[PATCH] char/rtc: Handle memory-mapped chips properly
authorMaciej W. Rozycki <macro@linux-mips.org>
Mon, 10 Jul 2006 11:45:30 +0000 (04:45 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 10 Jul 2006 20:24:25 +0000 (13:24 -0700)
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>
drivers/char/rtc.c
include/asm-mips/mach-dec/mc146818rtc.h
include/linux/mc146818rtc.h

index cc7bd1a3095b799fba093bee386bcdfe805529fb..6ccc364c08df58076402a482232d4819708b6fac 100644 (file)
  *      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);
index 6d37a5675803172091bda06d505a7718d3ddcede..6724e99e43e1f293a6fe6ae053abd58c5bd2412b 100644 (file)
@@ -19,6 +19,8 @@
 
 extern volatile u8 *dec_rtc_base;
 
+#define ARCH_RTC_LOCATION
+
 #define RTC_PORT(x)    CPHYSADDR((long)dec_rtc_base)
 #define RTC_IO_EXTENT  dec_kn_slot_size
 #define RTC_IOMAPPED   0
index bbc93ae217e1c48390bb5352d6e76a59e5efb5d4..432b2fa249290343702eabfbc8c031d84a697e39 100644 (file)
@@ -89,4 +89,11 @@ extern spinlock_t rtc_lock;          /* serialize CMOS RAM access */
 # define RTC_VRT 0x80          /* valid RAM and time */
 /**********************************************************************/
 
+#ifndef ARCH_RTC_LOCATION      /* Override by <asm/mc146818rtc.h>? */
+
+#define RTC_IO_EXTENT  0x8
+#define RTC_IOMAPPED   1       /* Default to I/O mapping. */
+
+#endif /* ARCH_RTC_LOCATION */
+
 #endif /* _MC146818RTC_H */