aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sbus/char/rtc.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2005-04-22 00:42:34 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-04-22 00:42:34 -0400
commitb4bca26c0160f48b4eb04f21d31a229832732013 (patch)
treeb4a6d736fcb8664753066df3e6a93ed24c0f409b /drivers/sbus/char/rtc.c
parentd7be828e03969ea7f922f299acb8daa0d8ce7006 (diff)
[SPARC]: Provide generic ioctls in Sparc RTC driver.
Provide support for drivers/char/rtc.c ioctls in the Mostek rtc driver as well as the Sparc specific RTCGET and RTCSET. This allows userspace to be much less messy. Currently util-linux and other spots jump through hoops trying various ioctl variants until it hits the right one whatever driver actually being used supports. Eventually all of this should move over to the genrtc.c driver, but not today... While we are here, fix up the register types for sparse. Thanks to Frans Pop for helping point out this issue. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/sbus/char/rtc.c')
-rw-r--r--drivers/sbus/char/rtc.c103
1 files changed, 99 insertions, 4 deletions
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
index bf3273eb1c8b..49d1cd99d5ac 100644
--- a/drivers/sbus/char/rtc.c
+++ b/drivers/sbus/char/rtc.c
@@ -28,6 +28,42 @@
28 28
29static int rtc_busy = 0; 29static int rtc_busy = 0;
30 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
31/* Retrieve the current date and time from the real time clock. */ 67/* Retrieve the current date and time from the real time clock. */
32static void get_rtc_time(struct rtc_time *t) 68static void get_rtc_time(struct rtc_time *t)
33{ 69{
@@ -82,29 +118,87 @@ void set_rtc_time(struct rtc_time *t)
82 spin_unlock_irq(&mostek_lock); 118 spin_unlock_irq(&mostek_lock);
83} 119}
84 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
85static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 155static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
86 unsigned long arg) 156 unsigned long arg)
87{ 157{
88 struct rtc_time rtc_tm; 158 struct rtc_time rtc_tm;
89 void __user *argp = (void __user *)arg; 159 void __user *argp = (void __user *)arg;
90 160
91 switch (cmd) 161 switch (cmd) {
92 { 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
93 case RTCGET: 177 case RTCGET:
178 case RTC_RD_TIME:
94 memset(&rtc_tm, 0, sizeof(struct rtc_time)); 179 memset(&rtc_tm, 0, sizeof(struct rtc_time));
95 get_rtc_time(&rtc_tm); 180 get_rtc_time(&rtc_tm);
96 181
97 if (copy_to_user(argp, &rtc_tm, sizeof(struct rtc_time))) 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))
98 return -EFAULT; 187 return -EFAULT;
99 188
100 return 0; 189 return 0;
101 190
102 191
103 case RTCSET: 192 case RTCSET:
193 case RTC_SET_TIME:
104 if (!capable(CAP_SYS_TIME)) 194 if (!capable(CAP_SYS_TIME))
105 return -EPERM; 195 return -EPERM;
106 196
107 if (copy_from_user(&rtc_tm, argp, sizeof(struct rtc_time))) 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))
108 return -EFAULT; 202 return -EFAULT;
109 203
110 set_rtc_time(&rtc_tm); 204 set_rtc_time(&rtc_tm);
@@ -164,6 +258,7 @@ static int __init rtc_sun_init(void)
164 printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n"); 258 printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n");
165 return error; 259 return error;
166 } 260 }
261 printk("rtc_sun_init: Registered Mostek RTC driver.\n");
167 262
168 return 0; 263 return 0;
169} 264}