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 @@ static int __init rtc_init(void) } 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 @@ static int __init rtc_init(void) 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); diff --git a/include/asm-mips/mach-dec/mc146818rtc.h b/include/asm-mips/mach-dec/mc146818rtc.h index 6d37a5675803..6724e99e43e1 100644 --- a/include/asm-mips/mach-dec/mc146818rtc.h +++ b/include/asm-mips/mach-dec/mc146818rtc.h @@ -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 diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h index bbc93ae217e1..432b2fa24929 100644 --- a/include/linux/mc146818rtc.h +++ b/include/linux/mc146818rtc.h @@ -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 ? */ + +#define RTC_IO_EXTENT 0x8 +#define RTC_IOMAPPED 1 /* Default to I/O mapping. */ + +#endif /* ARCH_RTC_LOCATION */ + #endif /* _MC146818RTC_H */