From 15b9b00ca341b40dd79cb8999e12a6f1fadab342 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 26 Jul 2005 03:32:46 -0700 Subject: [PATCH] [PATCH] ARM: OMAP: RTC cleanups The big win here is a shrink of runtime code size, but again there's the usual MODULE_ALIAS_MISCDEV and sparse stuff and more traditional coding style. RTC driver cleanups: - Various "sparse" fixes - Reduce some pointless code duplication - Add a MODULE_ALIAS_MISCDEV (supports KMOD) - Style and other code cleanups Object code shrinks by almost 800 bytes. Signed-off-by: David Brownell Signed-off-by: Tony Lindgren --- drivers/char/omap-rtc.c | 420 ++++++++++++++++------------------------ 1 file changed, 165 insertions(+), 255 deletions(-) diff --git a/drivers/char/omap-rtc.c b/drivers/char/omap-rtc.c index 84cba75051a..5c28e783b01 100644 --- a/drivers/char/omap-rtc.c +++ b/drivers/char/omap-rtc.c @@ -37,8 +37,6 @@ * - changed the return value of the interrupt handler */ -#define RTC_VERSION "1.0" - /* * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with * interrupts disabled. @@ -56,16 +54,17 @@ #include #include #include -#include - +#include #include #include +#include #include #include #include #include #include + #include "omap-rtc.h" extern spinlock_t rtc_lock; @@ -76,46 +75,16 @@ extern spinlock_t rtc_lock; #define CMOS_READ(addr) omap_readb(addr) #define CMOS_WRITE(val, addr) omap_writeb(val, addr) - -/* Local BCD/BIN conversion macros: */ -#ifdef BCD_TO_BIN -#undef BCD_TO_BIN -#endif -#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) - -#ifdef BIN_TO_BCD -#undef BIN_TO_BCD -#endif -#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) - - -/* - * We sponge a minor off of the misc major. No need slurping - * up another valuable major dev number for this. If you add - * an ioctl, make sure you don't conflict with SPARC's RTC - * ioctls. - */ - static struct fasync_struct *rtc_async_queue; static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); -static ssize_t rtc_read(struct file *file, char *buf, - size_t count, loff_t *ppos); - -static int rtc_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); - -static unsigned int rtc_poll(struct file *file, poll_table *wait); - static void get_rtc_time (struct rtc_time *rtc_tm); static void get_rtc_alm_time (struct rtc_time *alm_tm); static void set_rtc_irq_bit(unsigned char bit); static void mask_rtc_irq_bit(unsigned char bit); -static inline unsigned char rtc_is_updating(void); - static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); @@ -178,7 +147,7 @@ static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) * 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) { DECLARE_WAITQUEUE(wait, current); @@ -212,7 +181,7 @@ static ssize_t rtc_read(struct file *file, char *buf, } spin_unlock_irq (&rtc_lock); - retval = put_user(data, (unsigned long *)buf); + retval = put_user(data, (unsigned long __user *)buf); if (!retval) retval = sizeof(unsigned long); out: @@ -222,34 +191,74 @@ static ssize_t rtc_read(struct file *file, char *buf, return retval; } +/* convert from userspace struct to hardware BCD-encoded version, + * or return error code + */ +static int utm2bcd(struct rtc_time __user *arg, struct rtc_time *tm) +{ + unsigned char leap_yr; + + if (copy_from_user(tm, arg, sizeof(struct rtc_time))) + return -EFAULT; + + tm->tm_year += 1900; + tm->tm_mon++; + + if (tm->tm_year < 1970) + return -EINVAL; + + leap_yr = (!(tm->tm_year % 4) && (tm->tm_year % 100)) + || !(tm->tm_year % 400); + + if ((tm->tm_mon > 12) || (tm->tm_mday == 0)) + return -EINVAL; + + if (tm->tm_mday > (days_in_mo[tm->tm_mon] + ((tm->tm_mon == 2) && leap_yr))) + return -EINVAL; + + if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60)) + return -EINVAL; + + if ((tm->tm_year -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + if (tm->tm_year > 169) + return -EINVAL; + + if (tm->tm_year >= 100) + tm->tm_year -= 100; + + BIN_TO_BCD(tm->tm_sec); + BIN_TO_BCD(tm->tm_min); + BIN_TO_BCD(tm->tm_hour); + BIN_TO_BCD(tm->tm_mday); + BIN_TO_BCD(tm->tm_mon); + BIN_TO_BCD(tm->tm_year); + + return 0; +} + static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time wtime; + int status = 0; + u8 save_control; switch (cmd) { case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ - { mask_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_ALARM); - return 0; - } + break; case RTC_AIE_ON: /* Allow alarm interrupts. */ - { set_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_ALARM); - return 0; - } + break; case RTC_UIE_OFF: /* Mask ints from RTC updates. */ - { mask_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_TIMER); - return 0; - } + break; case RTC_UIE_ON: /* Allow ints for RTC updates. */ - { set_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_TIMER); - return 0; - } + break; case RTC_ALM_READ: /* Read the present alarm time */ - { /* * This returns a struct rtc_time. Reading >= 0xc0 * means "don't care" or "match all". Only the tm_hour, @@ -257,167 +266,73 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, */ memset(&wtime, 0, sizeof(struct rtc_time)); get_rtc_alm_time(&wtime); - break; - } + goto return_wtime; case RTC_ALM_SET: /* Store a time into the alarm */ - { - struct rtc_time alm_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned int yrs; - - if (copy_from_user(&alm_tm, (struct rtc_time*)arg, - sizeof(struct rtc_time))) - return -EFAULT; - - yrs = alm_tm.tm_year + 1900; - mon = alm_tm.tm_mon + 1; - day = alm_tm.tm_mday; - hrs = alm_tm.tm_hour; - min = alm_tm.tm_min; - sec = alm_tm.tm_sec; - - if (yrs < 1970) - return -EINVAL; - - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - - if ((mon > 12) || (day == 0)) - return -EINVAL; - - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - - if ((yrs -= epoch) > 255) /* They are unsigned */ - return -EINVAL; - - if (yrs > 169) { - return -EINVAL; - } - - if (yrs >= 100) - yrs -= 100; - - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); + status = utm2bcd((void __user *)arg, &wtime); + if (status != 0) + return status; spin_lock_irq(&rtc_lock); - CMOS_WRITE(yrs, OMAP_RTC_ALARM_YEARS_REG); - CMOS_WRITE(mon, OMAP_RTC_ALARM_MONTHS_REG); - CMOS_WRITE(day, OMAP_RTC_ALARM_DAYS_REG); - CMOS_WRITE(hrs, OMAP_RTC_ALARM_HOURS_REG); - CMOS_WRITE(min, OMAP_RTC_ALARM_MINUTES_REG); - CMOS_WRITE(sec, OMAP_RTC_ALARM_SECONDS_REG); + CMOS_WRITE(wtime.tm_year, OMAP_RTC_ALARM_YEARS_REG); + CMOS_WRITE(wtime.tm_mon, OMAP_RTC_ALARM_MONTHS_REG); + CMOS_WRITE(wtime.tm_mday, OMAP_RTC_ALARM_DAYS_REG); + CMOS_WRITE(wtime.tm_hour, OMAP_RTC_ALARM_HOURS_REG); + CMOS_WRITE(wtime.tm_min, OMAP_RTC_ALARM_MINUTES_REG); + CMOS_WRITE(wtime.tm_sec, OMAP_RTC_ALARM_SECONDS_REG); spin_unlock_irq(&rtc_lock); - return 0; - } + break; case RTC_RD_TIME: /* Read the time/date from RTC */ - { memset(&wtime, 0, sizeof(struct rtc_time)); get_rtc_time(&wtime); - break; - } + goto return_wtime; case RTC_SET_TIME: /* Set the RTC */ - { - struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned char save_control; - unsigned int yrs; - if (!capable(CAP_SYS_TIME)) return -EACCES; - if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, - sizeof(struct rtc_time))) - return -EFAULT; - - yrs = rtc_tm.tm_year + 1900; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; - - if (yrs < 1970) - return -EINVAL; - - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - - if ((mon > 12) || (day == 0)) - return -EINVAL; - - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - - if ((yrs -= epoch) > 255) /* They are unsigned */ - return -EINVAL; - - if (yrs > 169) { - return -EINVAL; - } - - if (yrs >= 100) - yrs -= 100; - - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); + status = utm2bcd((void __user *)arg, &wtime); + if (status != 0) + return status; spin_lock_irq(&rtc_lock); save_control = CMOS_READ(OMAP_RTC_CTRL_REG); CMOS_WRITE((save_control & ~OMAP_RTC_CTRL_STOP), OMAP_RTC_CTRL_REG); - CMOS_WRITE(yrs, OMAP_RTC_YEARS_REG); - CMOS_WRITE(mon, OMAP_RTC_MONTHS_REG); - CMOS_WRITE(day, OMAP_RTC_DAYS_REG); - CMOS_WRITE(hrs, OMAP_RTC_HOURS_REG); - CMOS_WRITE(min, OMAP_RTC_MINUTES_REG); - CMOS_WRITE(sec, OMAP_RTC_SECONDS_REG); + CMOS_WRITE(wtime.tm_year, OMAP_RTC_YEARS_REG); + CMOS_WRITE(wtime.tm_mon, OMAP_RTC_MONTHS_REG); + CMOS_WRITE(wtime.tm_mday, OMAP_RTC_DAYS_REG); + CMOS_WRITE(wtime.tm_hour, OMAP_RTC_HOURS_REG); + CMOS_WRITE(wtime.tm_min, OMAP_RTC_MINUTES_REG); + CMOS_WRITE(wtime.tm_sec, OMAP_RTC_SECONDS_REG); CMOS_WRITE((save_control | OMAP_RTC_CTRL_STOP), OMAP_RTC_CTRL_REG); spin_unlock_irq(&rtc_lock); - return 0; - } + break; case RTC_EPOCH_READ: /* Read the epoch. */ - { - return put_user (epoch, (unsigned long *)arg); - } + status = put_user (epoch, (unsigned long __user *)arg); + break; case RTC_EPOCH_SET: /* Set the epoch. */ - { + if (!capable(CAP_SYS_TIME)) + return -EACCES; + /* * There were no RTC clocks before 1900. */ if (arg < 1900) - return -EINVAL; - - if (!capable(CAP_SYS_TIME)) - return -EACCES; - - epoch = arg; - return 0; - } + status = -EINVAL; + else + epoch = arg; + break; default: -#if !defined(CONFIG_ARCH_OMAP) - return -ENOTTY; -#else - return -EINVAL; -#endif + status = -ENOTTY; } - return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; + return status; + +return_wtime: + return copy_to_user((void __user *)arg, &wtime, sizeof wtime) + ? -EFAULT + : 0; } /* @@ -432,7 +347,7 @@ static int rtc_open(struct inode *inode, struct file *file) { spin_lock_irq (&rtc_lock); - if(rtc_status & RTC_IS_OPEN) + if (rtc_status & RTC_IS_OPEN) goto out_busy; rtc_status |= RTC_IS_OPEN; @@ -446,8 +361,7 @@ out_busy: return -EBUSY; } -static int rtc_fasync (int fd, struct file *filp, int on) - +static int rtc_fasync(int fd, struct file *filp, int on) { return fasync_helper (fd, filp, on, &rtc_async_queue); } @@ -504,74 +418,76 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait) */ static struct file_operations rtc_fops = { - owner: THIS_MODULE, - llseek: no_llseek, - read: rtc_read, - poll: rtc_poll, - ioctl: rtc_ioctl, - open: rtc_open, - release: rtc_release, - fasync: rtc_fasync, + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = rtc_read, + .poll = rtc_poll, + .ioctl = rtc_ioctl, + .open = rtc_open, + .release = rtc_release, + .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, }; static int __init rtc_init(void) { if (!request_region(OMAP_RTC_VIRT_BASE, OMAP_RTC_SIZE, rtc_dev.name)) { - printk(KERN_ERR "%s: RTC I/O port %d is not free.\n", + pr_debug("%s: RTC registers at %x are not free.\n", rtc_dev.name, OMAP_RTC_VIRT_BASE); - return -EIO; + return -EBUSY; } if (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_POWER_UP) { - printk(KERN_WARNING "%s: RTC power up reset detected.\n", + pr_info("%s: RTC power up reset detected.\n", rtc_dev.name); /* Clear OMAP_RTC_STATUS_POWER_UP */ CMOS_WRITE(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG); } if (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_ALARM) { - printk(KERN_WARNING "%s: Clearing RTC ALARM interrupt.\n", + pr_debug("%s: Clearing RTC ALARM interrupt.\n", rtc_dev.name); /* Clear OMAP_RTC_STATUS_ALARM */ CMOS_WRITE(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG); } - if (!(CMOS_READ(OMAP_RTC_CTRL_REG) & OMAP_RTC_CTRL_STOP)) { - printk(KERN_INFO "%s: Enabling RTC.\n", rtc_dev.name); - CMOS_WRITE(OMAP_RTC_CTRL_STOP, OMAP_RTC_CTRL_REG); - } - if (request_irq(INT_RTC_TIMER, rtc_interrupt, SA_INTERRUPT, rtc_dev.name, NULL)) { - printk(KERN_ERR "%s: RTC timer interrupt IRQ%d is not free.\n", + pr_debug("%s: RTC timer interrupt IRQ%d is not free.\n", rtc_dev.name, INT_RTC_TIMER); - release_region(OMAP_RTC_VIRT_BASE, OMAP_RTC_SIZE); - return -EIO; + goto fail; } if (request_irq(INT_RTC_ALARM, rtc_interrupt, SA_INTERRUPT, - "omap-rtc alarm", NULL)) { - printk(KERN_ERR "%s: RTC alarm interrupt IRQ%d is not free.\n", + rtc_dev.name, NULL)) { + pr_debug("%s: RTC alarm interrupt IRQ%d is not free.\n", rtc_dev.name, INT_RTC_ALARM); - release_region(OMAP_RTC_VIRT_BASE, OMAP_RTC_SIZE); - return -EIO; + free_irq(INT_RTC_TIMER, NULL); + goto fail; } + /* On boards with split power, RTC_ON_NOFF resets all but the RTC */ + if (!(CMOS_READ(OMAP_RTC_CTRL_REG) & OMAP_RTC_CTRL_STOP)) { + pr_info("%s: Enabling RTC.\n", rtc_dev.name); + CMOS_WRITE(OMAP_RTC_CTRL_STOP, OMAP_RTC_CTRL_REG); + } else + pr_info("%s: RTC already running.\n", rtc_dev.name); + spin_lock_init(&rtc_lock); misc_register(&rtc_dev); - create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); - - printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); + create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL); return 0; + +fail: + release_region(OMAP_RTC_VIRT_BASE, OMAP_RTC_SIZE); + return -EIO; } static void __exit rtc_exit (void) @@ -592,7 +508,6 @@ static void __exit rtc_exit (void) static int rtc_proc_output (char *buf) { #define YN(value) ((value) ? "yes" : "no") -#define NY(value) ((value) ? "no" : "yes") char *p; struct rtc_time tm; @@ -640,25 +555,27 @@ static int rtc_proc_output (char *buf) return p - buf; #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; + + if (len <= off+count) + *eof = 1; *start = page + off; len -= off; - if (len>count) len = count; - if (len<0) len = 0; + 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) { unsigned char uip; @@ -669,6 +586,26 @@ static inline unsigned char rtc_is_updating(void) return uip; } +static void bcd2tm(struct rtc_time *tm) +{ + BCD_TO_BIN(tm->tm_sec); + BCD_TO_BIN(tm->tm_min); + BCD_TO_BIN(tm->tm_hour); + BCD_TO_BIN(tm->tm_mday); + BCD_TO_BIN(tm->tm_mon); + BCD_TO_BIN(tm->tm_year); + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if ((tm->tm_year += (epoch - 1900)) <= 69) + tm->tm_year += 100; + + tm->tm_mon--; +} + + static void get_rtc_time(struct rtc_time *rtc_tm) { unsigned char ctrl; @@ -708,21 +645,7 @@ static void get_rtc_time(struct rtc_time *rtc_tm) ctrl = CMOS_READ(OMAP_RTC_CTRL_REG); spin_unlock_irq(&rtc_lock); - BCD_TO_BIN(rtc_tm->tm_sec); - BCD_TO_BIN(rtc_tm->tm_min); - BCD_TO_BIN(rtc_tm->tm_hour); - BCD_TO_BIN(rtc_tm->tm_mday); - BCD_TO_BIN(rtc_tm->tm_mon); - BCD_TO_BIN(rtc_tm->tm_year); - - /* - * Account for differences between how the RTC uses the values - * and how they are defined in a struct rtc_time; - */ - if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) - rtc_tm->tm_year += 100; - - rtc_tm->tm_mon--; + bcd2tm(rtc_tm); } static void get_rtc_alm_time(struct rtc_time *alm_tm) @@ -739,21 +662,7 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm) ctrl = CMOS_READ(OMAP_RTC_CTRL_REG); spin_unlock_irq(&rtc_lock); - BCD_TO_BIN(alm_tm->tm_sec); - BCD_TO_BIN(alm_tm->tm_min); - BCD_TO_BIN(alm_tm->tm_hour); - BCD_TO_BIN(alm_tm->tm_mday); - BCD_TO_BIN(alm_tm->tm_mon); - BCD_TO_BIN(alm_tm->tm_year); - - /* - * Account for differences between how the RTC uses the values - * and how they are defined in a struct rtc_time; - */ - if ((alm_tm->tm_year += (epoch - 1900)) <= 69) - alm_tm->tm_year += 100; - - alm_tm->tm_mon--; + bcd2tm(alm_tm); } /* @@ -784,8 +693,9 @@ static void set_rtc_irq_bit(unsigned char bit) spin_unlock_irq(&rtc_lock); } -MODULE_AUTHOR("George G. Davis"); -MODULE_LICENSE("GPL"); - module_init(rtc_init); module_exit(rtc_exit); + +MODULE_AUTHOR("George G. Davis (and others)"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(RTC_MINOR); -- 2.41.1