X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Frtc.c;h=664f36c98e6acc4f257759aaff8c5586f48653e2;hb=refs%2Fheads%2Fvserver;hp=fddefbb11508448d9ef9e4de49824aa6be1af9ba;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index fddefbb11..664f36c98 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -35,23 +35,22 @@ * 1.09a Pete Zaitcev: Sun SPARC * 1.09b Jeff Garzik: Modularize, init cleanup * 1.09c Jeff Garzik: SMP cleanup - * 1.10 Paul Barton-Davis: add support for async I/O + * 1.10 Paul Barton-Davis: add support for async I/O * 1.10a Andrea Arcangeli: Alpha updates * 1.10b Andrew Morton: SMP lock fix * 1.10c Cesar Barros: SMP locking fixes and cleanup * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. - * 1.11 Takashi Iwai: Kernel access functions + * 1.11 Takashi Iwai: Kernel access functions * rtc_register/rtc_unregister/rtc_control * 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.12" - -#define RTC_IO_EXTENT 0x8 +#define RTC_VERSION "1.12ac" /* * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with @@ -61,7 +60,6 @@ * this driver.) */ -#include #include #include #include @@ -73,10 +71,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -97,7 +97,11 @@ static unsigned long rtc_port; static int rtc_irq = PCI_IRQ_NONE; #endif -#if RTC_IRQ +#ifdef CONFIG_HPET_RTC_IRQ +#undef RTC_IRQ +#endif + +#ifdef RTC_IRQ static int rtc_has_irq = 1; #endif @@ -109,9 +113,14 @@ static int rtc_has_irq = 1; #define hpet_set_rtc_irq_bit(arg) 0 #define hpet_rtc_timer_init() do { } while (0) #define hpet_rtc_dropped_irq() 0 -static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) {return 0;} +#ifdef RTC_IRQ +static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) +{ + return 0; +} +#endif #else -extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); #endif /* @@ -125,32 +134,45 @@ static struct fasync_struct *rtc_async_queue; static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); -#if RTC_IRQ +#ifdef RTC_IRQ static struct timer_list rtc_irq_timer; #endif -static ssize_t rtc_read(struct file *file, char *buf, +static ssize_t rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -#if RTC_IRQ +#ifdef RTC_IRQ static unsigned int rtc_poll(struct file *file, poll_table *wait); #endif static void get_rtc_alm_time (struct rtc_time *alm_tm); -#if RTC_IRQ +#ifdef RTC_IRQ static void rtc_dropped_irq(unsigned long data); -static void set_rtc_irq_bit(unsigned char bit); -static void mask_rtc_irq_bit(unsigned char bit); -#endif +static void set_rtc_irq_bit_locked(unsigned char bit); +static void mask_rtc_irq_bit_locked(unsigned char bit); -static inline unsigned char rtc_is_updating(void); +static inline void set_rtc_irq_bit(unsigned char bit) +{ + spin_lock_irq(&rtc_lock); + set_rtc_irq_bit_locked(bit); + spin_unlock_irq(&rtc_lock); +} -static int rtc_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data); +static void mask_rtc_irq_bit(unsigned char bit) +{ + spin_lock_irq(&rtc_lock); + mask_rtc_irq_bit_locked(bit); + spin_unlock_irq(&rtc_lock); +} +#endif + +#ifdef CONFIG_PROC_FS +static int rtc_proc_open(struct inode *inode, struct file *file); +#endif /* * Bits in rtc_status. (6 bits of room for future expansion) @@ -171,11 +193,11 @@ static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ static unsigned long rtc_irq_data = 0; /* our output to the world */ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ -#if RTC_IRQ +#ifdef RTC_IRQ /* * rtc_task_lock nests inside rtc_lock. */ -static spinlock_t rtc_task_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(rtc_task_lock); static rtc_task_t *rtc_callback = NULL; #endif @@ -189,9 +211,23 @@ static unsigned long epoch = 1900; /* year corresponding to 0x00 */ static const unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -#if RTC_IRQ /* - * A very tiny interrupt handler. It runs with SA_INTERRUPT set, + * Returns true if a clock update is in progress + */ +static inline unsigned char rtc_is_updating(void) +{ + unsigned long flags; + unsigned char uip; + + spin_lock_irqsave(&rtc_lock, flags); + uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + spin_unlock_irqrestore(&rtc_lock, flags); + return uip; +} + +#ifdef RTC_IRQ +/* + * A very tiny interrupt handler. It runs with IRQF_DISABLED set, * but there is possibility of conflicting with the set_rtc_mmss() * call (the rtc irq and the timer irq can easily run at the same * time in two different CPUs). So we need to serialize @@ -200,7 +236,7 @@ static const unsigned char days_in_mo[] = * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) */ -irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t rtc_interrupt(int irq, void *dev_id) { /* * Can be an alarm interrupt, update complete interrupt, @@ -295,10 +331,10 @@ static void __exit cleanup_sysctl(void) * Now all the various file operations that we export. */ -static ssize_t rtc_read(struct file *file, char *buf, +static ssize_t rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { -#if !RTC_IRQ +#ifndef RTC_IRQ return -EIO; #else DECLARE_WAITQUEUE(wait, current); @@ -308,7 +344,15 @@ static ssize_t rtc_read(struct file *file, char *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); @@ -339,10 +383,12 @@ static ssize_t rtc_read(struct file *file, char *buf, schedule(); } while (1); - if (count < sizeof(unsigned long)) - retval = put_user(data, (unsigned int *)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 *)buf) ?: sizeof(long); + 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); @@ -355,7 +401,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) { struct rtc_time wtime; -#if RTC_IRQ +#ifdef RTC_IRQ if (rtc_has_irq == 0) { switch (cmd) { case RTC_AIE_OFF: @@ -372,7 +418,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) #endif switch (cmd) { -#if RTC_IRQ +#ifdef RTC_IRQ case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ { mask_rtc_irq_bit(RTC_AIE); @@ -385,18 +431,19 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) } case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ { - mask_rtc_irq_bit(RTC_PIE); + unsigned long flags; /* can be called from isr via rtc_control() */ + spin_lock_irqsave (&rtc_lock, flags); + mask_rtc_irq_bit_locked(RTC_PIE); if (rtc_status & RTC_TIMER_ON) { - spin_lock_irq (&rtc_lock); rtc_status &= ~RTC_TIMER_ON; del_timer(&rtc_irq_timer); - spin_unlock_irq (&rtc_lock); } + spin_unlock_irqrestore (&rtc_lock, flags); return 0; } case RTC_PIE_ON: /* Allow periodic ints */ { - + unsigned long flags; /* can be called from isr via rtc_control() */ /* * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. @@ -405,14 +452,14 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) (!capable(CAP_SYS_RESOURCE))) return -EACCES; + spin_lock_irqsave (&rtc_lock, flags); if (!(rtc_status & RTC_TIMER_ON)) { - spin_lock_irq (&rtc_lock); rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; add_timer(&rtc_irq_timer); rtc_status |= RTC_TIMER_ON; - spin_unlock_irq (&rtc_lock); } - set_rtc_irq_bit(RTC_PIE); + set_rtc_irq_bit_locked(RTC_PIE); + spin_unlock_irqrestore (&rtc_lock, flags); return 0; } case RTC_UIE_OFF: /* Mask ints from RTC updates. */ @@ -447,7 +494,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) unsigned char hrs, min, sec; struct rtc_time alm_tm; - if (copy_from_user(&alm_tm, (struct rtc_time*)arg, + if (copy_from_user(&alm_tm, (struct rtc_time __user *)arg, sizeof(struct rtc_time))) return -EFAULT; @@ -493,14 +540,14 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) unsigned char mon, day, hrs, min, sec, leap_yr; unsigned char save_control, save_freq_select; unsigned int yrs; -#ifdef CONFIG_DECSTATION +#ifdef CONFIG_MACH_DECSTATION unsigned int real_yrs; #endif if (!capable(CAP_SYS_TIME)) return -EACCES; - if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, + if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg, sizeof(struct rtc_time))) return -EFAULT; @@ -529,7 +576,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) return -EINVAL; spin_lock_irq(&rtc_lock); -#ifdef CONFIG_DECSTATION +#ifdef CONFIG_MACH_DECSTATION real_yrs = yrs; yrs = 72; @@ -568,7 +615,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) save_freq_select = CMOS_READ(RTC_FREQ_SELECT); CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); -#ifdef CONFIG_DECSTATION +#ifdef CONFIG_MACH_DECSTATION CMOS_WRITE(real_yrs, RTC_DEC_YEAR); #endif CMOS_WRITE(yrs, RTC_YEAR); @@ -584,15 +631,16 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) spin_unlock_irq(&rtc_lock); return 0; } -#if RTC_IRQ +#ifdef RTC_IRQ case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ { - return put_user(rtc_freq, (unsigned long *)arg); + return put_user(rtc_freq, (unsigned long __user *)arg); } case RTC_IRQP_SET: /* Set periodic IRQ rate. */ { int tmp = 0; unsigned char val; + unsigned long flags; /* can be called from isr via rtc_control() */ /* * The max we can do is 8192Hz. @@ -615,9 +663,9 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) if (arg != (1<func == NULL) @@ -789,7 +837,7 @@ int rtc_register(rtc_task_t *task) int rtc_unregister(rtc_task_t *task) { -#if !RTC_IRQ +#ifndef RTC_IRQ return -EIO; #else unsigned char tmp; @@ -825,15 +873,18 @@ int rtc_unregister(rtc_task_t *task) int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) { -#if !RTC_IRQ +#ifndef RTC_IRQ return -EIO; #else - spin_lock_irq(&rtc_task_lock); + unsigned long flags; + if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET) + return -EINVAL; + spin_lock_irqsave(&rtc_task_lock, flags); if (rtc_callback != task) { - spin_unlock_irq(&rtc_task_lock); + spin_unlock_irqrestore(&rtc_task_lock, flags); return -ENXIO; } - spin_unlock_irq(&rtc_task_lock); + spin_unlock_irqrestore(&rtc_task_lock, flags); return rtc_do_ioctl(cmd, arg, 1); #endif } @@ -843,11 +894,11 @@ int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) * The various file operations we support. */ -static struct file_operations rtc_fops = { +static const struct file_operations rtc_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = rtc_read, -#if RTC_IRQ +#ifdef RTC_IRQ .poll = rtc_poll, #endif .ioctl = rtc_ioctl, @@ -856,22 +907,29 @@ static struct file_operations rtc_fops = { .fasync = rtc_fasync, }; -static struct miscdevice rtc_dev= -{ - RTC_MINOR, - "rtc", - &rtc_fops +static struct miscdevice rtc_dev = { + .minor = RTC_MINOR, + .name = "rtc", + .fops = &rtc_fops, }; -#if RTC_IRQ -static irqreturn_t (*rtc_int_handler_ptr)(int irq, void *dev_id, struct pt_regs *regs); +#ifdef CONFIG_PROC_FS +static const struct file_operations rtc_proc_fops = { + .owner = THIS_MODULE, + .open = rtc_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif static int __init rtc_init(void) { +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *ent; +#endif #if defined(__alpha__) || defined(__mips__) unsigned int year, ctrl; - unsigned long uip_watchdog; char *guess = NULL; #endif #ifdef __sparc__ @@ -881,12 +939,17 @@ static int __init rtc_init(void) struct sparc_isa_bridge *isa_br; struct sparc_isa_device *isa_dev; #endif +#else + void *r; +#ifdef RTC_IRQ + irq_handler_t rtc_int_handler_ptr; +#endif #endif #ifdef __sparc__ for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if(strcmp(edev->prom_name, "rtc") == 0) { + if(strcmp(edev->prom_node->name, "rtc") == 0) { rtc_port = edev->resource[0].start; rtc_irq = edev->irqs[0]; goto found; @@ -896,7 +959,7 @@ static int __init rtc_init(void) #ifdef __sparc_v9__ for_each_isa(isa_br) { for_each_isadev(isa_dev, isa_br) { - if (strcmp(isa_dev->prom_name, "rtc") == 0) { + if (strcmp(isa_dev->prom_node->name, "rtc") == 0) { rtc_port = isa_dev->resource.start; rtc_irq = isa_dev->irq; goto found; @@ -904,6 +967,7 @@ static int __init rtc_init(void) } } #endif + rtc_has_irq = 0; printk(KERN_ERR "rtc_init: no PC rtc found\n"); return -EIO; @@ -915,35 +979,43 @@ found: /* * XXX Interrupt pin #7 in Espresso is shared between RTC and - * PCI Slot 2 INTA# (and some INTx# in Slot 1). SA_INTERRUPT here - * is asking for trouble with add-on boards. Change to SA_SHIRQ. + * PCI Slot 2 INTA# (and some INTx# in Slot 1). */ - if (request_irq(rtc_irq, rtc_interrupt, SA_INTERRUPT, "rtc", (void *)&rtc_port)) { - /* - * Standard way for sparc to print irq's is to use - * __irq_itoa(). I think for EBus it's ok to use %d. - */ + if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) { + rtc_has_irq = 0; printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); return -EIO; } 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) { +#ifdef RTC_IRQ + rtc_has_irq = 0; +#endif + printk(KERN_ERR "rtc: I/O resource %lx is not free.\n", + (long)(RTC_PORT(0))); return -EIO; } -#if RTC_IRQ +#ifdef RTC_IRQ if (is_hpet_enabled()) { rtc_int_handler_ptr = hpet_rtc_interrupt; } else { rtc_int_handler_ptr = rtc_interrupt; } - if(request_irq(RTC_IRQ, rtc_int_handler_ptr, SA_INTERRUPT, "rtc", NULL)) { + 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. */ + rtc_has_irq = 0; 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(); @@ -953,20 +1025,21 @@ no_irq: #endif /* __sparc__ vs. others */ if (misc_register(&rtc_dev)) { -#if RTC_IRQ +#ifdef RTC_IRQ free_irq(RTC_IRQ, NULL); + rtc_has_irq = 0; #endif release_region(RTC_PORT(0), RTC_IO_EXTENT); return -ENODEV; } - if (create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL) == NULL) { -#if RTC_IRQ - free_irq(RTC_IRQ, NULL); + +#ifdef CONFIG_PROC_FS + ent = create_proc_entry("driver/rtc", 0, NULL); + if (ent) + ent->proc_fops = &rtc_proc_fops; + else + printk(KERN_WARNING "rtc: Failed to register with procfs.\n"); #endif - release_region(RTC_PORT(0), RTC_IO_EXTENT); - misc_deregister(&rtc_dev); - return -ENOMEM; - } #if defined(__alpha__) || defined(__mips__) rtc_freq = HZ; @@ -974,12 +1047,8 @@ no_irq: /* Each operating system on an Alpha uses its own epoch. Let's try to guess which one we are using now. */ - uip_watchdog = jiffies; if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) { - barrier(); - cpu_relax(); - } + msleep(20); spin_lock_irq(&rtc_lock); year = CMOS_READ(RTC_YEAR); @@ -1011,7 +1080,7 @@ no_irq: if (guess) printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch); #endif -#if RTC_IRQ +#ifdef RTC_IRQ if (rtc_has_irq == 0) goto no_irq2; @@ -1044,8 +1113,11 @@ 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_IRQ + 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); #endif @@ -1055,7 +1127,7 @@ static void __exit rtc_exit (void) module_init(rtc_init); module_exit(rtc_exit); -#if RTC_IRQ +#ifdef RTC_IRQ /* * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. * (usually during an IDE disk interrupt, with IRQ unmasking off) @@ -1100,15 +1172,15 @@ static void rtc_dropped_irq(unsigned long data) } #endif +#ifdef CONFIG_PROC_FS /* * Info exported via "/proc/driver/rtc". */ -static int rtc_proc_output (char *buf) +static int rtc_proc_show(struct seq_file *seq, void *v) { #define YN(bit) ((ctrl & bit) ? "yes" : "no") #define NY(bit) ((ctrl & bit) ? "no" : "yes") - char *p; struct rtc_time tm; unsigned char batt, ctrl; unsigned long freq; @@ -1119,7 +1191,6 @@ static int rtc_proc_output (char *buf) freq = rtc_freq; spin_unlock_irq(&rtc_lock); - p = buf; rtc_get_rtc_time(&tm); @@ -1127,12 +1198,12 @@ static int rtc_proc_output (char *buf) * There is no way to tell if the luser has the RTC set for local * time or for Universal Standard Time (GMT). Probably local though. */ - p += sprintf(p, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n" - "rtc_epoch\t: %04lu\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + seq_printf(seq, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); get_rtc_alm_time(&tm); @@ -1141,84 +1212,64 @@ static int rtc_proc_output (char *buf) * match any value for that particular field. Values that are * greater than a valid time, but less than 0xc0 shouldn't appear. */ - p += sprintf(p, "alarm\t\t: "); + seq_puts(seq, "alarm\t\t: "); if (tm.tm_hour <= 24) - p += sprintf(p, "%02d:", tm.tm_hour); + seq_printf(seq, "%02d:", tm.tm_hour); else - p += sprintf(p, "**:"); + seq_puts(seq, "**:"); if (tm.tm_min <= 59) - p += sprintf(p, "%02d:", tm.tm_min); + seq_printf(seq, "%02d:", tm.tm_min); else - p += sprintf(p, "**:"); + seq_puts(seq, "**:"); if (tm.tm_sec <= 59) - p += sprintf(p, "%02d\n", tm.tm_sec); + seq_printf(seq, "%02d\n", tm.tm_sec); else - p += sprintf(p, "**\n"); - - p += sprintf(p, - "DST_enable\t: %s\n" - "BCD\t\t: %s\n" - "24hr\t\t: %s\n" - "square_wave\t: %s\n" - "alarm_IRQ\t: %s\n" - "update_IRQ\t: %s\n" - "periodic_IRQ\t: %s\n" - "periodic_freq\t: %ld\n" - "batt_status\t: %s\n", - YN(RTC_DST_EN), - NY(RTC_DM_BINARY), - YN(RTC_24H), - YN(RTC_SQWE), - YN(RTC_AIE), - YN(RTC_UIE), - YN(RTC_PIE), - freq, - batt ? "okay" : "dead"); - - return p - buf; + seq_puts(seq, "**\n"); + + seq_printf(seq, + "DST_enable\t: %s\n" + "BCD\t\t: %s\n" + "24hr\t\t: %s\n" + "square_wave\t: %s\n" + "alarm_IRQ\t: %s\n" + "update_IRQ\t: %s\n" + "periodic_IRQ\t: %s\n" + "periodic_freq\t: %ld\n" + "batt_status\t: %s\n", + YN(RTC_DST_EN), + NY(RTC_DM_BINARY), + YN(RTC_24H), + YN(RTC_SQWE), + YN(RTC_AIE), + YN(RTC_UIE), + YN(RTC_PIE), + freq, + batt ? "okay" : "dead"); + + return 0; #undef YN #undef NY } -static int rtc_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = rtc_proc_output (page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - return len; -} - -/* - * Returns true if a clock update is in progress - */ -/* FIXME shouldn't this be above rtc_init to make it fully inlined? */ -static inline unsigned char rtc_is_updating(void) +static int rtc_proc_open(struct inode *inode, struct file *file) { - unsigned char uip; - - spin_lock_irq(&rtc_lock); - uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); - spin_unlock_irq(&rtc_lock); - return uip; + return single_open(file, rtc_proc_show, NULL); } +#endif void rtc_get_rtc_time(struct rtc_time *rtc_tm) { - unsigned long uip_watchdog = jiffies; + unsigned long uip_watchdog = jiffies, flags; unsigned char ctrl; -#ifdef CONFIG_DECSTATION +#ifdef CONFIG_MACH_DECSTATION unsigned int real_year; #endif /* * read RTC once any update in progress is done. The update - * can take just over 2ms. We wait 10 to 20ms. There is no need to + * can take just over 2ms. We wait 20ms. There is no need to * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. * If you need to know *exactly* when a second has started, enable * periodic update complete interrupts, (via ioctl) and then @@ -1226,30 +1277,30 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) * Once the read clears, read the RTC time (again via ioctl). Easy. */ - if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) { - barrier(); - cpu_relax(); - } + while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100) + cpu_relax(); /* * Only the values that we read from the RTC are set. We leave - * tm_wday, tm_yday and tm_isdst untouched. Even though the - * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated - * by the RTC when initially set to a non-zero value. + * tm_wday, tm_yday and tm_isdst untouched. Note that while the + * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is + * only updated by the RTC when initially set to a non-zero value. */ - spin_lock_irq(&rtc_lock); + spin_lock_irqsave(&rtc_lock, flags); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); rtc_tm->tm_year = CMOS_READ(RTC_YEAR); -#ifdef CONFIG_DECSTATION + /* Only set from 2.6.16 onwards */ + rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); + +#ifdef CONFIG_MACH_DECSTATION real_year = CMOS_READ(RTC_DEC_YEAR); #endif ctrl = CMOS_READ(RTC_CONTROL); - spin_unlock_irq(&rtc_lock); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -1259,9 +1310,10 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) BCD_TO_BIN(rtc_tm->tm_mday); BCD_TO_BIN(rtc_tm->tm_mon); BCD_TO_BIN(rtc_tm->tm_year); + BCD_TO_BIN(rtc_tm->tm_wday); } -#ifdef CONFIG_DECSTATION +#ifdef CONFIG_MACH_DECSTATION rtc_tm->tm_year += real_year - 72; #endif @@ -1298,7 +1350,7 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm) } } -#if RTC_IRQ +#ifdef RTC_IRQ /* * Used to disable/enable interrupts for any one of UIE, AIE, PIE. * Rumour has it that if you frob the interrupt enable/disable @@ -1309,40 +1361,32 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm) * meddles with the interrupt enable/disable bits. */ -static void mask_rtc_irq_bit(unsigned char bit) +static void mask_rtc_irq_bit_locked(unsigned char bit) { unsigned char val; - spin_lock_irq(&rtc_lock); - if (hpet_mask_rtc_irq_bit(bit)) { - spin_unlock_irq(&rtc_lock); + if (hpet_mask_rtc_irq_bit(bit)) return; - } val = CMOS_READ(RTC_CONTROL); val &= ~bit; CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); rtc_irq_data = 0; - spin_unlock_irq(&rtc_lock); } -static void set_rtc_irq_bit(unsigned char bit) +static void set_rtc_irq_bit_locked(unsigned char bit) { unsigned char val; - spin_lock_irq(&rtc_lock); - if (hpet_set_rtc_irq_bit(bit)) { - spin_unlock_irq(&rtc_lock); + if (hpet_set_rtc_irq_bit(bit)) return; - } val = CMOS_READ(RTC_CONTROL); val |= bit; CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); rtc_irq_data = 0; - spin_unlock_irq(&rtc_lock); } #endif