summary refs log tree commit diff
path: root/drivers/char/rtc.c
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2006-07-10 04:45:30 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-10 13:24:25 -0700
commit38e0e8c0550eaed1af48ec5ad9ddb8a25e8b04ae (patch)
treef38daa22e42969c8eabccfd73dc298dcaec99821 /drivers/char/rtc.c
parent06c67befeeb16f2995c11b0e04a348103ddbfab1 (diff)
downloadlinux-38e0e8c0550eaed1af48ec5ad9ddb8a25e8b04ae.tar.gz
[PATCH] char/rtc: Handle memory-mapped chips properly
Handle memory-mapped chips properly, needed for example on DECstations.
This support was in Linux 2.4 but for some reason got lost in 2.6.  This
patch is taken directly from the linux-mips repository.

[akpm@osdl.org: cleanup]
Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Signed-off-by: Martin Michlmayr <tbm@cyrius.com>
Cc: Paul Gortmaker <penguin@muskoka.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/rtc.c')
-rw-r--r--drivers/char/rtc.c41
1 files changed, 32 insertions, 9 deletions
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index cc7bd1a3095b..6ccc364c08df 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -46,13 +46,12 @@
  *      1.11a   Daniele Bellucci: Audit create_proc_read_entry in rtc_init
  *	1.12	Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
  *		CONFIG_HPET_EMULATE_RTC
+ *	1.12a	Maciej W. Rozycki: Handle memory-mapped chips properly.
  *	1.12ac	Alan Cox: Allow read access to the day of week register
  */
 
 #define RTC_VERSION		"1.12ac"
 
-#define RTC_IO_EXTENT	0x8
-
 /*
  *	Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
  *	interrupts disabled. Due to the index-port/data-port (0x70/0x71)
@@ -337,7 +336,15 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
 	if (rtc_has_irq == 0)
 		return -EIO;
 
-	if (count < sizeof(unsigned))
+	/*
+	 * Historically this function used to assume that sizeof(unsigned long)
+	 * is the same in userspace and kernelspace.  This lead to problems
+	 * for configurations with multiple ABIs such a the MIPS o32 and 64
+	 * ABIs supported on the same kernel.  So now we support read of both
+	 * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the
+	 * userspace ABI.
+	 */
+	if (count != sizeof(unsigned int) && count !=  sizeof(unsigned long))
 		return -EINVAL;
 
 	add_wait_queue(&rtc_wait, &wait);
@@ -368,10 +375,12 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
 		schedule();
 	} while (1);
 
-	if (count < sizeof(unsigned long))
-		retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int); 
+	if (count == sizeof(unsigned int))
+		retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int);
 	else
 		retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long);
+	if (!retval)
+		retval = count;
  out:
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&rtc_wait, &wait);
@@ -923,6 +932,9 @@ static int __init rtc_init(void)
 	struct sparc_isa_device *isa_dev;
 #endif
 #endif
+#ifndef __sparc__
+	void *r;
+#endif
 
 #ifdef __sparc__
 	for_each_ebus(ebus) {
@@ -964,8 +976,13 @@ found:
 	}
 no_irq:
 #else
-	if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc")) {
-		printk(KERN_ERR "rtc: I/O port %d is not free.\n", RTC_PORT (0));
+	if (RTC_IOMAPPED)
+		r = request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+	else
+		r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+	if (!r) {
+		printk(KERN_ERR "rtc: I/O resource %lx is not free.\n",
+		       (long)(RTC_PORT(0)));
 		return -EIO;
 	}
 
@@ -979,7 +996,10 @@ no_irq:
 	if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) {
 		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
 		printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
-		release_region(RTC_PORT(0), RTC_IO_EXTENT);
+		if (RTC_IOMAPPED)
+			release_region(RTC_PORT(0), RTC_IO_EXTENT);
+		else
+			release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
 		return -EIO;
 	}
 	hpet_rtc_timer_init();
@@ -1079,7 +1099,10 @@ static void __exit rtc_exit (void)
 	if (rtc_has_irq)
 		free_irq (rtc_irq, &rtc_port);
 #else
-	release_region (RTC_PORT (0), RTC_IO_EXTENT);
+	if (RTC_IOMAPPED)
+		release_region(RTC_PORT(0), RTC_IO_EXTENT);
+	else
+		release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
 #ifdef RTC_IRQ
 	if (rtc_has_irq)
 		free_irq (RTC_IRQ, NULL);