Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.21 273 lines 7.1 kB view raw
1/* $Id: rtc.c,v 1.28 2001/10/08 22:19:51 davem Exp $ 2 * 3 * Linux/SPARC Real Time Clock Driver 4 * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) 5 * 6 * This is a little driver that lets a user-level program access 7 * the SPARC Mostek real time clock chip. It is no use unless you 8 * use the modified clock utility. 9 * 10 * Get the modified clock utility from: 11 * ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c 12 */ 13 14#include <linux/module.h> 15#include <linux/types.h> 16#include <linux/errno.h> 17#include <linux/miscdevice.h> 18#include <linux/slab.h> 19#include <linux/fcntl.h> 20#include <linux/poll.h> 21#include <linux/init.h> 22#include <linux/smp_lock.h> 23#include <asm/io.h> 24#include <asm/mostek.h> 25#include <asm/system.h> 26#include <asm/uaccess.h> 27#include <asm/rtc.h> 28 29static int rtc_busy = 0; 30 31/* This is the structure layout used by drivers/char/rtc.c, we 32 * support that driver's ioctls so that things are less messy in 33 * userspace. 34 */ 35struct rtc_time_generic { 36 int tm_sec; 37 int tm_min; 38 int tm_hour; 39 int tm_mday; 40 int tm_mon; 41 int tm_year; 42 int tm_wday; 43 int tm_yday; 44 int tm_isdst; 45}; 46#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ 47#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ 48#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ 49#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ 50#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ 51#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ 52#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */ 53#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */ 54#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time_generic) /* Read RTC time */ 55#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time_generic) /* Set RTC time */ 56#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */ 57#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */ 58#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ 59#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ 60#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ 61#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ 62#define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/ 63#define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/ 64#define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ 65#define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ 66 67/* Retrieve the current date and time from the real time clock. */ 68static void get_rtc_time(struct rtc_time *t) 69{ 70 void __iomem *regs = mstk48t02_regs; 71 u8 tmp; 72 73 spin_lock_irq(&mostek_lock); 74 75 tmp = mostek_read(regs + MOSTEK_CREG); 76 tmp |= MSTK_CREG_READ; 77 mostek_write(regs + MOSTEK_CREG, tmp); 78 79 t->sec = MSTK_REG_SEC(regs); 80 t->min = MSTK_REG_MIN(regs); 81 t->hour = MSTK_REG_HOUR(regs); 82 t->dow = MSTK_REG_DOW(regs); 83 t->dom = MSTK_REG_DOM(regs); 84 t->month = MSTK_REG_MONTH(regs); 85 t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) ); 86 87 tmp = mostek_read(regs + MOSTEK_CREG); 88 tmp &= ~MSTK_CREG_READ; 89 mostek_write(regs + MOSTEK_CREG, tmp); 90 91 spin_unlock_irq(&mostek_lock); 92} 93 94/* Set the current date and time inthe real time clock. */ 95void set_rtc_time(struct rtc_time *t) 96{ 97 void __iomem *regs = mstk48t02_regs; 98 u8 tmp; 99 100 spin_lock_irq(&mostek_lock); 101 102 tmp = mostek_read(regs + MOSTEK_CREG); 103 tmp |= MSTK_CREG_WRITE; 104 mostek_write(regs + MOSTEK_CREG, tmp); 105 106 MSTK_SET_REG_SEC(regs,t->sec); 107 MSTK_SET_REG_MIN(regs,t->min); 108 MSTK_SET_REG_HOUR(regs,t->hour); 109 MSTK_SET_REG_DOW(regs,t->dow); 110 MSTK_SET_REG_DOM(regs,t->dom); 111 MSTK_SET_REG_MONTH(regs,t->month); 112 MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO); 113 114 tmp = mostek_read(regs + MOSTEK_CREG); 115 tmp &= ~MSTK_CREG_WRITE; 116 mostek_write(regs + MOSTEK_CREG, tmp); 117 118 spin_unlock_irq(&mostek_lock); 119} 120 121static int put_rtc_time_generic(void __user *argp, struct rtc_time *tm) 122{ 123 struct rtc_time_generic __user *utm = argp; 124 125 if (__put_user(tm->sec, &utm->tm_sec) || 126 __put_user(tm->min, &utm->tm_min) || 127 __put_user(tm->hour, &utm->tm_hour) || 128 __put_user(tm->dom, &utm->tm_mday) || 129 __put_user(tm->month, &utm->tm_mon) || 130 __put_user(tm->year, &utm->tm_year) || 131 __put_user(tm->dow, &utm->tm_wday) || 132 __put_user(0, &utm->tm_yday) || 133 __put_user(0, &utm->tm_isdst)) 134 return -EFAULT; 135 136 return 0; 137} 138 139static int get_rtc_time_generic(struct rtc_time *tm, void __user *argp) 140{ 141 struct rtc_time_generic __user *utm = argp; 142 143 if (__get_user(tm->sec, &utm->tm_sec) || 144 __get_user(tm->min, &utm->tm_min) || 145 __get_user(tm->hour, &utm->tm_hour) || 146 __get_user(tm->dom, &utm->tm_mday) || 147 __get_user(tm->month, &utm->tm_mon) || 148 __get_user(tm->year, &utm->tm_year) || 149 __get_user(tm->dow, &utm->tm_wday)) 150 return -EFAULT; 151 152 return 0; 153} 154 155static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 156 unsigned long arg) 157{ 158 struct rtc_time rtc_tm; 159 void __user *argp = (void __user *)arg; 160 161 switch (cmd) { 162 /* No interrupt support, return an error 163 * compatible with drivers/char/rtc.c 164 */ 165 case RTC_AIE_OFF: 166 case RTC_AIE_ON: 167 case RTC_PIE_OFF: 168 case RTC_PIE_ON: 169 case RTC_UIE_OFF: 170 case RTC_UIE_ON: 171 case RTC_IRQP_READ: 172 case RTC_IRQP_SET: 173 case RTC_EPOCH_SET: 174 case RTC_EPOCH_READ: 175 return -EINVAL; 176 177 case RTCGET: 178 case RTC_RD_TIME: 179 memset(&rtc_tm, 0, sizeof(struct rtc_time)); 180 get_rtc_time(&rtc_tm); 181 182 if (cmd == RTCGET) { 183 if (copy_to_user(argp, &rtc_tm, 184 sizeof(struct rtc_time))) 185 return -EFAULT; 186 } else if (put_rtc_time_generic(argp, &rtc_tm)) 187 return -EFAULT; 188 189 return 0; 190 191 192 case RTCSET: 193 case RTC_SET_TIME: 194 if (!capable(CAP_SYS_TIME)) 195 return -EPERM; 196 197 if (cmd == RTCSET) { 198 if (copy_from_user(&rtc_tm, argp, 199 sizeof(struct rtc_time))) 200 return -EFAULT; 201 } else if (get_rtc_time_generic(&rtc_tm, argp)) 202 return -EFAULT; 203 204 set_rtc_time(&rtc_tm); 205 206 return 0; 207 208 default: 209 return -EINVAL; 210 } 211} 212 213static int rtc_open(struct inode *inode, struct file *file) 214{ 215 int ret; 216 217 spin_lock_irq(&mostek_lock); 218 if (rtc_busy) { 219 ret = -EBUSY; 220 } else { 221 rtc_busy = 1; 222 ret = 0; 223 } 224 spin_unlock_irq(&mostek_lock); 225 226 return ret; 227} 228 229static int rtc_release(struct inode *inode, struct file *file) 230{ 231 rtc_busy = 0; 232 233 return 0; 234} 235 236static const struct file_operations rtc_fops = { 237 .owner = THIS_MODULE, 238 .llseek = no_llseek, 239 .ioctl = rtc_ioctl, 240 .open = rtc_open, 241 .release = rtc_release, 242}; 243 244static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; 245 246static int __init rtc_sun_init(void) 247{ 248 int error; 249 250 /* It is possible we are being driven by some other RTC chip 251 * and thus another RTC driver is handling things. 252 */ 253 if (!mstk48t02_regs) 254 return -ENODEV; 255 256 error = misc_register(&rtc_dev); 257 if (error) { 258 printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n"); 259 return error; 260 } 261 printk("rtc_sun_init: Registered Mostek RTC driver.\n"); 262 263 return 0; 264} 265 266static void __exit rtc_sun_cleanup(void) 267{ 268 misc_deregister(&rtc_dev); 269} 270 271module_init(rtc_sun_init); 272module_exit(rtc_sun_cleanup); 273MODULE_LICENSE("GPL");