Commit 86ae13b006e48959981248493efd3ff4b2828b3d
Committed by
Linus Torvalds
1 parent
03266d28ca
Exists in
master
and in
7 other branches
headers: Fix build after <linux/sched.h> removal
Commit d43c36dc6b357fa1806800f18aa30123c747a6d1 ("headers: remove sched.h from interrupt.h") left some build errors in some configurations due to drivers having depended on getting header files "accidentally". Signed-off-by: Ingo Molnar <mingo@elte.hu> [ Combined several one-liners from Ingo into one single patch - Linus ] Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 7 changed files with 7 additions and 0 deletions Inline Diff
drivers/char/genrtc.c
1 | /* | 1 | /* |
2 | * Real Time Clock interface for | 2 | * Real Time Clock interface for |
3 | * - q40 and other m68k machines, | 3 | * - q40 and other m68k machines, |
4 | * - HP PARISC machines | 4 | * - HP PARISC machines |
5 | * - PowerPC machines | 5 | * - PowerPC machines |
6 | * emulate some RTC irq capabilities in software | 6 | * emulate some RTC irq capabilities in software |
7 | * | 7 | * |
8 | * Copyright (C) 1999 Richard Zidlicky | 8 | * Copyright (C) 1999 Richard Zidlicky |
9 | * | 9 | * |
10 | * based on Paul Gortmaker's rtc.c device and | 10 | * based on Paul Gortmaker's rtc.c device and |
11 | * Sam Creasey Generic rtc driver | 11 | * Sam Creasey Generic rtc driver |
12 | * | 12 | * |
13 | * This driver allows use of the real time clock (built into | 13 | * This driver allows use of the real time clock (built into |
14 | * nearly all computers) from user space. It exports the /dev/rtc | 14 | * nearly all computers) from user space. It exports the /dev/rtc |
15 | * interface supporting various ioctl() and also the /proc/driver/rtc | 15 | * interface supporting various ioctl() and also the /proc/driver/rtc |
16 | * pseudo-file for status information. | 16 | * pseudo-file for status information. |
17 | * | 17 | * |
18 | * The ioctls can be used to set the interrupt behaviour where | 18 | * The ioctls can be used to set the interrupt behaviour where |
19 | * supported. | 19 | * supported. |
20 | * | 20 | * |
21 | * The /dev/rtc interface will block on reads until an interrupt | 21 | * The /dev/rtc interface will block on reads until an interrupt |
22 | * has been received. If a RTC interrupt has already happened, | 22 | * has been received. If a RTC interrupt has already happened, |
23 | * it will output an unsigned long and then block. The output value | 23 | * it will output an unsigned long and then block. The output value |
24 | * contains the interrupt status in the low byte and the number of | 24 | * contains the interrupt status in the low byte and the number of |
25 | * interrupts since the last read in the remaining high bytes. The | 25 | * interrupts since the last read in the remaining high bytes. The |
26 | * /dev/rtc interface can also be used with the select(2) call. | 26 | * /dev/rtc interface can also be used with the select(2) call. |
27 | * | 27 | * |
28 | * This program is free software; you can redistribute it and/or | 28 | * This program is free software; you can redistribute it and/or |
29 | * modify it under the terms of the GNU General Public License | 29 | * modify it under the terms of the GNU General Public License |
30 | * as published by the Free Software Foundation; either version | 30 | * as published by the Free Software Foundation; either version |
31 | * 2 of the License, or (at your option) any later version. | 31 | * 2 of the License, or (at your option) any later version. |
32 | * | 32 | * |
33 | 33 | ||
34 | * 1.01 fix for 2.3.X rz@linux-m68k.org | 34 | * 1.01 fix for 2.3.X rz@linux-m68k.org |
35 | * 1.02 merged with code from genrtc.c rz@linux-m68k.org | 35 | * 1.02 merged with code from genrtc.c rz@linux-m68k.org |
36 | * 1.03 make it more portable zippel@linux-m68k.org | 36 | * 1.03 make it more portable zippel@linux-m68k.org |
37 | * 1.04 removed useless timer code rz@linux-m68k.org | 37 | * 1.04 removed useless timer code rz@linux-m68k.org |
38 | * 1.05 portable RTC_UIE emulation rz@linux-m68k.org | 38 | * 1.05 portable RTC_UIE emulation rz@linux-m68k.org |
39 | * 1.06 set_rtc_time can return an error trini@kernel.crashing.org | 39 | * 1.06 set_rtc_time can return an error trini@kernel.crashing.org |
40 | * 1.07 ported to HP PARISC (hppa) Helge Deller <deller@gmx.de> | 40 | * 1.07 ported to HP PARISC (hppa) Helge Deller <deller@gmx.de> |
41 | */ | 41 | */ |
42 | 42 | ||
43 | #define RTC_VERSION "1.07" | 43 | #define RTC_VERSION "1.07" |
44 | 44 | ||
45 | #include <linux/module.h> | 45 | #include <linux/module.h> |
46 | #include <linux/sched.h> | ||
46 | #include <linux/errno.h> | 47 | #include <linux/errno.h> |
47 | #include <linux/miscdevice.h> | 48 | #include <linux/miscdevice.h> |
48 | #include <linux/fcntl.h> | 49 | #include <linux/fcntl.h> |
49 | 50 | ||
50 | #include <linux/rtc.h> | 51 | #include <linux/rtc.h> |
51 | #include <linux/init.h> | 52 | #include <linux/init.h> |
52 | #include <linux/poll.h> | 53 | #include <linux/poll.h> |
53 | #include <linux/proc_fs.h> | 54 | #include <linux/proc_fs.h> |
54 | #include <linux/smp_lock.h> | 55 | #include <linux/smp_lock.h> |
55 | #include <linux/workqueue.h> | 56 | #include <linux/workqueue.h> |
56 | 57 | ||
57 | #include <asm/uaccess.h> | 58 | #include <asm/uaccess.h> |
58 | #include <asm/system.h> | 59 | #include <asm/system.h> |
59 | #include <asm/rtc.h> | 60 | #include <asm/rtc.h> |
60 | 61 | ||
61 | /* | 62 | /* |
62 | * We sponge a minor off of the misc major. No need slurping | 63 | * We sponge a minor off of the misc major. No need slurping |
63 | * up another valuable major dev number for this. If you add | 64 | * up another valuable major dev number for this. If you add |
64 | * an ioctl, make sure you don't conflict with SPARC's RTC | 65 | * an ioctl, make sure you don't conflict with SPARC's RTC |
65 | * ioctls. | 66 | * ioctls. |
66 | */ | 67 | */ |
67 | 68 | ||
68 | static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait); | 69 | static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait); |
69 | 70 | ||
70 | /* | 71 | /* |
71 | * Bits in gen_rtc_status. | 72 | * Bits in gen_rtc_status. |
72 | */ | 73 | */ |
73 | 74 | ||
74 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ | 75 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ |
75 | 76 | ||
76 | static unsigned char gen_rtc_status; /* bitmapped status byte. */ | 77 | static unsigned char gen_rtc_status; /* bitmapped status byte. */ |
77 | static unsigned long gen_rtc_irq_data; /* our output to the world */ | 78 | static unsigned long gen_rtc_irq_data; /* our output to the world */ |
78 | 79 | ||
79 | /* months start at 0 now */ | 80 | /* months start at 0 now */ |
80 | static unsigned char days_in_mo[] = | 81 | static unsigned char days_in_mo[] = |
81 | {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | 82 | {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
82 | 83 | ||
83 | static int irq_active; | 84 | static int irq_active; |
84 | 85 | ||
85 | #ifdef CONFIG_GEN_RTC_X | 86 | #ifdef CONFIG_GEN_RTC_X |
86 | static struct work_struct genrtc_task; | 87 | static struct work_struct genrtc_task; |
87 | static struct timer_list timer_task; | 88 | static struct timer_list timer_task; |
88 | 89 | ||
89 | static unsigned int oldsecs; | 90 | static unsigned int oldsecs; |
90 | static int lostint; | 91 | static int lostint; |
91 | static unsigned long tt_exp; | 92 | static unsigned long tt_exp; |
92 | 93 | ||
93 | static void gen_rtc_timer(unsigned long data); | 94 | static void gen_rtc_timer(unsigned long data); |
94 | 95 | ||
95 | static volatile int stask_active; /* schedule_work */ | 96 | static volatile int stask_active; /* schedule_work */ |
96 | static volatile int ttask_active; /* timer_task */ | 97 | static volatile int ttask_active; /* timer_task */ |
97 | static int stop_rtc_timers; /* don't requeue tasks */ | 98 | static int stop_rtc_timers; /* don't requeue tasks */ |
98 | static DEFINE_SPINLOCK(gen_rtc_lock); | 99 | static DEFINE_SPINLOCK(gen_rtc_lock); |
99 | 100 | ||
100 | static void gen_rtc_interrupt(unsigned long arg); | 101 | static void gen_rtc_interrupt(unsigned long arg); |
101 | 102 | ||
102 | /* | 103 | /* |
103 | * Routine to poll RTC seconds field for change as often as possible, | 104 | * Routine to poll RTC seconds field for change as often as possible, |
104 | * after first RTC_UIE use timer to reduce polling | 105 | * after first RTC_UIE use timer to reduce polling |
105 | */ | 106 | */ |
106 | static void genrtc_troutine(struct work_struct *work) | 107 | static void genrtc_troutine(struct work_struct *work) |
107 | { | 108 | { |
108 | unsigned int tmp = get_rtc_ss(); | 109 | unsigned int tmp = get_rtc_ss(); |
109 | 110 | ||
110 | if (stop_rtc_timers) { | 111 | if (stop_rtc_timers) { |
111 | stask_active = 0; | 112 | stask_active = 0; |
112 | return; | 113 | return; |
113 | } | 114 | } |
114 | 115 | ||
115 | if (oldsecs != tmp){ | 116 | if (oldsecs != tmp){ |
116 | oldsecs = tmp; | 117 | oldsecs = tmp; |
117 | 118 | ||
118 | timer_task.function = gen_rtc_timer; | 119 | timer_task.function = gen_rtc_timer; |
119 | timer_task.expires = jiffies + HZ - (HZ/10); | 120 | timer_task.expires = jiffies + HZ - (HZ/10); |
120 | tt_exp=timer_task.expires; | 121 | tt_exp=timer_task.expires; |
121 | ttask_active=1; | 122 | ttask_active=1; |
122 | stask_active=0; | 123 | stask_active=0; |
123 | add_timer(&timer_task); | 124 | add_timer(&timer_task); |
124 | 125 | ||
125 | gen_rtc_interrupt(0); | 126 | gen_rtc_interrupt(0); |
126 | } else if (schedule_work(&genrtc_task) == 0) | 127 | } else if (schedule_work(&genrtc_task) == 0) |
127 | stask_active = 0; | 128 | stask_active = 0; |
128 | } | 129 | } |
129 | 130 | ||
130 | static void gen_rtc_timer(unsigned long data) | 131 | static void gen_rtc_timer(unsigned long data) |
131 | { | 132 | { |
132 | lostint = get_rtc_ss() - oldsecs ; | 133 | lostint = get_rtc_ss() - oldsecs ; |
133 | if (lostint<0) | 134 | if (lostint<0) |
134 | lostint = 60 - lostint; | 135 | lostint = 60 - lostint; |
135 | if (time_after(jiffies, tt_exp)) | 136 | if (time_after(jiffies, tt_exp)) |
136 | printk(KERN_INFO "genrtc: timer task delayed by %ld jiffies\n", | 137 | printk(KERN_INFO "genrtc: timer task delayed by %ld jiffies\n", |
137 | jiffies-tt_exp); | 138 | jiffies-tt_exp); |
138 | ttask_active=0; | 139 | ttask_active=0; |
139 | stask_active=1; | 140 | stask_active=1; |
140 | if ((schedule_work(&genrtc_task) == 0)) | 141 | if ((schedule_work(&genrtc_task) == 0)) |
141 | stask_active = 0; | 142 | stask_active = 0; |
142 | } | 143 | } |
143 | 144 | ||
144 | /* | 145 | /* |
145 | * call gen_rtc_interrupt function to signal an RTC_UIE, | 146 | * call gen_rtc_interrupt function to signal an RTC_UIE, |
146 | * arg is unused. | 147 | * arg is unused. |
147 | * Could be invoked either from a real interrupt handler or | 148 | * Could be invoked either from a real interrupt handler or |
148 | * from some routine that periodically (eg 100HZ) monitors | 149 | * from some routine that periodically (eg 100HZ) monitors |
149 | * whether RTC_SECS changed | 150 | * whether RTC_SECS changed |
150 | */ | 151 | */ |
151 | static void gen_rtc_interrupt(unsigned long arg) | 152 | static void gen_rtc_interrupt(unsigned long arg) |
152 | { | 153 | { |
153 | /* We store the status in the low byte and the number of | 154 | /* We store the status in the low byte and the number of |
154 | * interrupts received since the last read in the remainder | 155 | * interrupts received since the last read in the remainder |
155 | * of rtc_irq_data. */ | 156 | * of rtc_irq_data. */ |
156 | 157 | ||
157 | gen_rtc_irq_data += 0x100; | 158 | gen_rtc_irq_data += 0x100; |
158 | gen_rtc_irq_data &= ~0xff; | 159 | gen_rtc_irq_data &= ~0xff; |
159 | gen_rtc_irq_data |= RTC_UIE; | 160 | gen_rtc_irq_data |= RTC_UIE; |
160 | 161 | ||
161 | if (lostint){ | 162 | if (lostint){ |
162 | printk("genrtc: system delaying clock ticks?\n"); | 163 | printk("genrtc: system delaying clock ticks?\n"); |
163 | /* increment count so that userspace knows something is wrong */ | 164 | /* increment count so that userspace knows something is wrong */ |
164 | gen_rtc_irq_data += ((lostint-1)<<8); | 165 | gen_rtc_irq_data += ((lostint-1)<<8); |
165 | lostint = 0; | 166 | lostint = 0; |
166 | } | 167 | } |
167 | 168 | ||
168 | wake_up_interruptible(&gen_rtc_wait); | 169 | wake_up_interruptible(&gen_rtc_wait); |
169 | } | 170 | } |
170 | 171 | ||
171 | /* | 172 | /* |
172 | * Now all the various file operations that we export. | 173 | * Now all the various file operations that we export. |
173 | */ | 174 | */ |
174 | static ssize_t gen_rtc_read(struct file *file, char __user *buf, | 175 | static ssize_t gen_rtc_read(struct file *file, char __user *buf, |
175 | size_t count, loff_t *ppos) | 176 | size_t count, loff_t *ppos) |
176 | { | 177 | { |
177 | unsigned long data; | 178 | unsigned long data; |
178 | ssize_t retval; | 179 | ssize_t retval; |
179 | 180 | ||
180 | if (count != sizeof (unsigned int) && count != sizeof (unsigned long)) | 181 | if (count != sizeof (unsigned int) && count != sizeof (unsigned long)) |
181 | return -EINVAL; | 182 | return -EINVAL; |
182 | 183 | ||
183 | if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data) | 184 | if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data) |
184 | return -EAGAIN; | 185 | return -EAGAIN; |
185 | 186 | ||
186 | retval = wait_event_interruptible(gen_rtc_wait, | 187 | retval = wait_event_interruptible(gen_rtc_wait, |
187 | (data = xchg(&gen_rtc_irq_data, 0))); | 188 | (data = xchg(&gen_rtc_irq_data, 0))); |
188 | if (retval) | 189 | if (retval) |
189 | goto out; | 190 | goto out; |
190 | 191 | ||
191 | /* first test allows optimizer to nuke this case for 32-bit machines */ | 192 | /* first test allows optimizer to nuke this case for 32-bit machines */ |
192 | if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) { | 193 | if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) { |
193 | unsigned int uidata = data; | 194 | unsigned int uidata = data; |
194 | retval = put_user(uidata, (unsigned int __user *)buf) ?: | 195 | retval = put_user(uidata, (unsigned int __user *)buf) ?: |
195 | sizeof(unsigned int); | 196 | sizeof(unsigned int); |
196 | } | 197 | } |
197 | else { | 198 | else { |
198 | retval = put_user(data, (unsigned long __user *)buf) ?: | 199 | retval = put_user(data, (unsigned long __user *)buf) ?: |
199 | sizeof(unsigned long); | 200 | sizeof(unsigned long); |
200 | } | 201 | } |
201 | out: | 202 | out: |
202 | return retval; | 203 | return retval; |
203 | } | 204 | } |
204 | 205 | ||
205 | static unsigned int gen_rtc_poll(struct file *file, | 206 | static unsigned int gen_rtc_poll(struct file *file, |
206 | struct poll_table_struct *wait) | 207 | struct poll_table_struct *wait) |
207 | { | 208 | { |
208 | poll_wait(file, &gen_rtc_wait, wait); | 209 | poll_wait(file, &gen_rtc_wait, wait); |
209 | if (gen_rtc_irq_data != 0) | 210 | if (gen_rtc_irq_data != 0) |
210 | return POLLIN | POLLRDNORM; | 211 | return POLLIN | POLLRDNORM; |
211 | return 0; | 212 | return 0; |
212 | } | 213 | } |
213 | 214 | ||
214 | #endif | 215 | #endif |
215 | 216 | ||
216 | /* | 217 | /* |
217 | * Used to disable/enable interrupts, only RTC_UIE supported | 218 | * Used to disable/enable interrupts, only RTC_UIE supported |
218 | * We also clear out any old irq data after an ioctl() that | 219 | * We also clear out any old irq data after an ioctl() that |
219 | * meddles with the interrupt enable/disable bits. | 220 | * meddles with the interrupt enable/disable bits. |
220 | */ | 221 | */ |
221 | 222 | ||
222 | static inline void gen_clear_rtc_irq_bit(unsigned char bit) | 223 | static inline void gen_clear_rtc_irq_bit(unsigned char bit) |
223 | { | 224 | { |
224 | #ifdef CONFIG_GEN_RTC_X | 225 | #ifdef CONFIG_GEN_RTC_X |
225 | stop_rtc_timers = 1; | 226 | stop_rtc_timers = 1; |
226 | if (ttask_active){ | 227 | if (ttask_active){ |
227 | del_timer_sync(&timer_task); | 228 | del_timer_sync(&timer_task); |
228 | ttask_active = 0; | 229 | ttask_active = 0; |
229 | } | 230 | } |
230 | while (stask_active) | 231 | while (stask_active) |
231 | schedule(); | 232 | schedule(); |
232 | 233 | ||
233 | spin_lock(&gen_rtc_lock); | 234 | spin_lock(&gen_rtc_lock); |
234 | irq_active = 0; | 235 | irq_active = 0; |
235 | spin_unlock(&gen_rtc_lock); | 236 | spin_unlock(&gen_rtc_lock); |
236 | #endif | 237 | #endif |
237 | } | 238 | } |
238 | 239 | ||
239 | static inline int gen_set_rtc_irq_bit(unsigned char bit) | 240 | static inline int gen_set_rtc_irq_bit(unsigned char bit) |
240 | { | 241 | { |
241 | #ifdef CONFIG_GEN_RTC_X | 242 | #ifdef CONFIG_GEN_RTC_X |
242 | spin_lock(&gen_rtc_lock); | 243 | spin_lock(&gen_rtc_lock); |
243 | if ( !irq_active ) { | 244 | if ( !irq_active ) { |
244 | irq_active = 1; | 245 | irq_active = 1; |
245 | stop_rtc_timers = 0; | 246 | stop_rtc_timers = 0; |
246 | lostint = 0; | 247 | lostint = 0; |
247 | INIT_WORK(&genrtc_task, genrtc_troutine); | 248 | INIT_WORK(&genrtc_task, genrtc_troutine); |
248 | oldsecs = get_rtc_ss(); | 249 | oldsecs = get_rtc_ss(); |
249 | init_timer(&timer_task); | 250 | init_timer(&timer_task); |
250 | 251 | ||
251 | stask_active = 1; | 252 | stask_active = 1; |
252 | if (schedule_work(&genrtc_task) == 0){ | 253 | if (schedule_work(&genrtc_task) == 0){ |
253 | stask_active = 0; | 254 | stask_active = 0; |
254 | } | 255 | } |
255 | } | 256 | } |
256 | spin_unlock(&gen_rtc_lock); | 257 | spin_unlock(&gen_rtc_lock); |
257 | gen_rtc_irq_data = 0; | 258 | gen_rtc_irq_data = 0; |
258 | return 0; | 259 | return 0; |
259 | #else | 260 | #else |
260 | return -EINVAL; | 261 | return -EINVAL; |
261 | #endif | 262 | #endif |
262 | } | 263 | } |
263 | 264 | ||
264 | static int gen_rtc_ioctl(struct inode *inode, struct file *file, | 265 | static int gen_rtc_ioctl(struct inode *inode, struct file *file, |
265 | unsigned int cmd, unsigned long arg) | 266 | unsigned int cmd, unsigned long arg) |
266 | { | 267 | { |
267 | struct rtc_time wtime; | 268 | struct rtc_time wtime; |
268 | struct rtc_pll_info pll; | 269 | struct rtc_pll_info pll; |
269 | void __user *argp = (void __user *)arg; | 270 | void __user *argp = (void __user *)arg; |
270 | 271 | ||
271 | switch (cmd) { | 272 | switch (cmd) { |
272 | 273 | ||
273 | case RTC_PLL_GET: | 274 | case RTC_PLL_GET: |
274 | if (get_rtc_pll(&pll)) | 275 | if (get_rtc_pll(&pll)) |
275 | return -EINVAL; | 276 | return -EINVAL; |
276 | else | 277 | else |
277 | return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0; | 278 | return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0; |
278 | 279 | ||
279 | case RTC_PLL_SET: | 280 | case RTC_PLL_SET: |
280 | if (!capable(CAP_SYS_TIME)) | 281 | if (!capable(CAP_SYS_TIME)) |
281 | return -EACCES; | 282 | return -EACCES; |
282 | if (copy_from_user(&pll, argp, sizeof(pll))) | 283 | if (copy_from_user(&pll, argp, sizeof(pll))) |
283 | return -EFAULT; | 284 | return -EFAULT; |
284 | return set_rtc_pll(&pll); | 285 | return set_rtc_pll(&pll); |
285 | 286 | ||
286 | case RTC_UIE_OFF: /* disable ints from RTC updates. */ | 287 | case RTC_UIE_OFF: /* disable ints from RTC updates. */ |
287 | gen_clear_rtc_irq_bit(RTC_UIE); | 288 | gen_clear_rtc_irq_bit(RTC_UIE); |
288 | return 0; | 289 | return 0; |
289 | 290 | ||
290 | case RTC_UIE_ON: /* enable ints for RTC updates. */ | 291 | case RTC_UIE_ON: /* enable ints for RTC updates. */ |
291 | return gen_set_rtc_irq_bit(RTC_UIE); | 292 | return gen_set_rtc_irq_bit(RTC_UIE); |
292 | 293 | ||
293 | case RTC_RD_TIME: /* Read the time/date from RTC */ | 294 | case RTC_RD_TIME: /* Read the time/date from RTC */ |
294 | /* this doesn't get week-day, who cares */ | 295 | /* this doesn't get week-day, who cares */ |
295 | memset(&wtime, 0, sizeof(wtime)); | 296 | memset(&wtime, 0, sizeof(wtime)); |
296 | get_rtc_time(&wtime); | 297 | get_rtc_time(&wtime); |
297 | 298 | ||
298 | return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0; | 299 | return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0; |
299 | 300 | ||
300 | case RTC_SET_TIME: /* Set the RTC */ | 301 | case RTC_SET_TIME: /* Set the RTC */ |
301 | { | 302 | { |
302 | int year; | 303 | int year; |
303 | unsigned char leap_yr; | 304 | unsigned char leap_yr; |
304 | 305 | ||
305 | if (!capable(CAP_SYS_TIME)) | 306 | if (!capable(CAP_SYS_TIME)) |
306 | return -EACCES; | 307 | return -EACCES; |
307 | 308 | ||
308 | if (copy_from_user(&wtime, argp, sizeof(wtime))) | 309 | if (copy_from_user(&wtime, argp, sizeof(wtime))) |
309 | return -EFAULT; | 310 | return -EFAULT; |
310 | 311 | ||
311 | year = wtime.tm_year + 1900; | 312 | year = wtime.tm_year + 1900; |
312 | leap_yr = ((!(year % 4) && (year % 100)) || | 313 | leap_yr = ((!(year % 4) && (year % 100)) || |
313 | !(year % 400)); | 314 | !(year % 400)); |
314 | 315 | ||
315 | if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1)) | 316 | if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1)) |
316 | return -EINVAL; | 317 | return -EINVAL; |
317 | 318 | ||
318 | if (wtime.tm_mday < 0 || wtime.tm_mday > | 319 | if (wtime.tm_mday < 0 || wtime.tm_mday > |
319 | (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr))) | 320 | (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr))) |
320 | return -EINVAL; | 321 | return -EINVAL; |
321 | 322 | ||
322 | if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 || | 323 | if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 || |
323 | wtime.tm_min < 0 || wtime.tm_min >= 60 || | 324 | wtime.tm_min < 0 || wtime.tm_min >= 60 || |
324 | wtime.tm_sec < 0 || wtime.tm_sec >= 60) | 325 | wtime.tm_sec < 0 || wtime.tm_sec >= 60) |
325 | return -EINVAL; | 326 | return -EINVAL; |
326 | 327 | ||
327 | return set_rtc_time(&wtime); | 328 | return set_rtc_time(&wtime); |
328 | } | 329 | } |
329 | } | 330 | } |
330 | 331 | ||
331 | return -EINVAL; | 332 | return -EINVAL; |
332 | } | 333 | } |
333 | 334 | ||
334 | /* | 335 | /* |
335 | * We enforce only one user at a time here with the open/close. | 336 | * We enforce only one user at a time here with the open/close. |
336 | * Also clear the previous interrupt data on an open, and clean | 337 | * Also clear the previous interrupt data on an open, and clean |
337 | * up things on a close. | 338 | * up things on a close. |
338 | */ | 339 | */ |
339 | 340 | ||
340 | static int gen_rtc_open(struct inode *inode, struct file *file) | 341 | static int gen_rtc_open(struct inode *inode, struct file *file) |
341 | { | 342 | { |
342 | lock_kernel(); | 343 | lock_kernel(); |
343 | if (gen_rtc_status & RTC_IS_OPEN) { | 344 | if (gen_rtc_status & RTC_IS_OPEN) { |
344 | unlock_kernel(); | 345 | unlock_kernel(); |
345 | return -EBUSY; | 346 | return -EBUSY; |
346 | } | 347 | } |
347 | 348 | ||
348 | gen_rtc_status |= RTC_IS_OPEN; | 349 | gen_rtc_status |= RTC_IS_OPEN; |
349 | gen_rtc_irq_data = 0; | 350 | gen_rtc_irq_data = 0; |
350 | irq_active = 0; | 351 | irq_active = 0; |
351 | unlock_kernel(); | 352 | unlock_kernel(); |
352 | 353 | ||
353 | return 0; | 354 | return 0; |
354 | } | 355 | } |
355 | 356 | ||
356 | static int gen_rtc_release(struct inode *inode, struct file *file) | 357 | static int gen_rtc_release(struct inode *inode, struct file *file) |
357 | { | 358 | { |
358 | /* | 359 | /* |
359 | * Turn off all interrupts once the device is no longer | 360 | * Turn off all interrupts once the device is no longer |
360 | * in use and clear the data. | 361 | * in use and clear the data. |
361 | */ | 362 | */ |
362 | 363 | ||
363 | gen_clear_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE); | 364 | gen_clear_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE); |
364 | 365 | ||
365 | gen_rtc_status &= ~RTC_IS_OPEN; | 366 | gen_rtc_status &= ~RTC_IS_OPEN; |
366 | return 0; | 367 | return 0; |
367 | } | 368 | } |
368 | 369 | ||
369 | 370 | ||
370 | #ifdef CONFIG_PROC_FS | 371 | #ifdef CONFIG_PROC_FS |
371 | 372 | ||
372 | /* | 373 | /* |
373 | * Info exported via "/proc/driver/rtc". | 374 | * Info exported via "/proc/driver/rtc". |
374 | */ | 375 | */ |
375 | 376 | ||
376 | static int gen_rtc_proc_output(char *buf) | 377 | static int gen_rtc_proc_output(char *buf) |
377 | { | 378 | { |
378 | char *p; | 379 | char *p; |
379 | struct rtc_time tm; | 380 | struct rtc_time tm; |
380 | unsigned int flags; | 381 | unsigned int flags; |
381 | struct rtc_pll_info pll; | 382 | struct rtc_pll_info pll; |
382 | 383 | ||
383 | p = buf; | 384 | p = buf; |
384 | 385 | ||
385 | flags = get_rtc_time(&tm); | 386 | flags = get_rtc_time(&tm); |
386 | 387 | ||
387 | p += sprintf(p, | 388 | p += sprintf(p, |
388 | "rtc_time\t: %02d:%02d:%02d\n" | 389 | "rtc_time\t: %02d:%02d:%02d\n" |
389 | "rtc_date\t: %04d-%02d-%02d\n" | 390 | "rtc_date\t: %04d-%02d-%02d\n" |
390 | "rtc_epoch\t: %04u\n", | 391 | "rtc_epoch\t: %04u\n", |
391 | tm.tm_hour, tm.tm_min, tm.tm_sec, | 392 | tm.tm_hour, tm.tm_min, tm.tm_sec, |
392 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1900); | 393 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1900); |
393 | 394 | ||
394 | tm.tm_hour = tm.tm_min = tm.tm_sec = 0; | 395 | tm.tm_hour = tm.tm_min = tm.tm_sec = 0; |
395 | 396 | ||
396 | p += sprintf(p, "alarm\t\t: "); | 397 | p += sprintf(p, "alarm\t\t: "); |
397 | if (tm.tm_hour <= 24) | 398 | if (tm.tm_hour <= 24) |
398 | p += sprintf(p, "%02d:", tm.tm_hour); | 399 | p += sprintf(p, "%02d:", tm.tm_hour); |
399 | else | 400 | else |
400 | p += sprintf(p, "**:"); | 401 | p += sprintf(p, "**:"); |
401 | 402 | ||
402 | if (tm.tm_min <= 59) | 403 | if (tm.tm_min <= 59) |
403 | p += sprintf(p, "%02d:", tm.tm_min); | 404 | p += sprintf(p, "%02d:", tm.tm_min); |
404 | else | 405 | else |
405 | p += sprintf(p, "**:"); | 406 | p += sprintf(p, "**:"); |
406 | 407 | ||
407 | if (tm.tm_sec <= 59) | 408 | if (tm.tm_sec <= 59) |
408 | p += sprintf(p, "%02d\n", tm.tm_sec); | 409 | p += sprintf(p, "%02d\n", tm.tm_sec); |
409 | else | 410 | else |
410 | p += sprintf(p, "**\n"); | 411 | p += sprintf(p, "**\n"); |
411 | 412 | ||
412 | p += sprintf(p, | 413 | p += sprintf(p, |
413 | "DST_enable\t: %s\n" | 414 | "DST_enable\t: %s\n" |
414 | "BCD\t\t: %s\n" | 415 | "BCD\t\t: %s\n" |
415 | "24hr\t\t: %s\n" | 416 | "24hr\t\t: %s\n" |
416 | "square_wave\t: %s\n" | 417 | "square_wave\t: %s\n" |
417 | "alarm_IRQ\t: %s\n" | 418 | "alarm_IRQ\t: %s\n" |
418 | "update_IRQ\t: %s\n" | 419 | "update_IRQ\t: %s\n" |
419 | "periodic_IRQ\t: %s\n" | 420 | "periodic_IRQ\t: %s\n" |
420 | "periodic_freq\t: %ld\n" | 421 | "periodic_freq\t: %ld\n" |
421 | "batt_status\t: %s\n", | 422 | "batt_status\t: %s\n", |
422 | (flags & RTC_DST_EN) ? "yes" : "no", | 423 | (flags & RTC_DST_EN) ? "yes" : "no", |
423 | (flags & RTC_DM_BINARY) ? "no" : "yes", | 424 | (flags & RTC_DM_BINARY) ? "no" : "yes", |
424 | (flags & RTC_24H) ? "yes" : "no", | 425 | (flags & RTC_24H) ? "yes" : "no", |
425 | (flags & RTC_SQWE) ? "yes" : "no", | 426 | (flags & RTC_SQWE) ? "yes" : "no", |
426 | (flags & RTC_AIE) ? "yes" : "no", | 427 | (flags & RTC_AIE) ? "yes" : "no", |
427 | irq_active ? "yes" : "no", | 428 | irq_active ? "yes" : "no", |
428 | (flags & RTC_PIE) ? "yes" : "no", | 429 | (flags & RTC_PIE) ? "yes" : "no", |
429 | 0L /* freq */, | 430 | 0L /* freq */, |
430 | (flags & RTC_BATT_BAD) ? "bad" : "okay"); | 431 | (flags & RTC_BATT_BAD) ? "bad" : "okay"); |
431 | if (!get_rtc_pll(&pll)) | 432 | if (!get_rtc_pll(&pll)) |
432 | p += sprintf(p, | 433 | p += sprintf(p, |
433 | "PLL adjustment\t: %d\n" | 434 | "PLL adjustment\t: %d\n" |
434 | "PLL max +ve adjustment\t: %d\n" | 435 | "PLL max +ve adjustment\t: %d\n" |
435 | "PLL max -ve adjustment\t: %d\n" | 436 | "PLL max -ve adjustment\t: %d\n" |
436 | "PLL +ve adjustment factor\t: %d\n" | 437 | "PLL +ve adjustment factor\t: %d\n" |
437 | "PLL -ve adjustment factor\t: %d\n" | 438 | "PLL -ve adjustment factor\t: %d\n" |
438 | "PLL frequency\t: %ld\n", | 439 | "PLL frequency\t: %ld\n", |
439 | pll.pll_value, | 440 | pll.pll_value, |
440 | pll.pll_max, | 441 | pll.pll_max, |
441 | pll.pll_min, | 442 | pll.pll_min, |
442 | pll.pll_posmult, | 443 | pll.pll_posmult, |
443 | pll.pll_negmult, | 444 | pll.pll_negmult, |
444 | pll.pll_clock); | 445 | pll.pll_clock); |
445 | return p - buf; | 446 | return p - buf; |
446 | } | 447 | } |
447 | 448 | ||
448 | static int gen_rtc_read_proc(char *page, char **start, off_t off, | 449 | static int gen_rtc_read_proc(char *page, char **start, off_t off, |
449 | int count, int *eof, void *data) | 450 | int count, int *eof, void *data) |
450 | { | 451 | { |
451 | int len = gen_rtc_proc_output (page); | 452 | int len = gen_rtc_proc_output (page); |
452 | if (len <= off+count) *eof = 1; | 453 | if (len <= off+count) *eof = 1; |
453 | *start = page + off; | 454 | *start = page + off; |
454 | len -= off; | 455 | len -= off; |
455 | if (len>count) len = count; | 456 | if (len>count) len = count; |
456 | if (len<0) len = 0; | 457 | if (len<0) len = 0; |
457 | return len; | 458 | return len; |
458 | } | 459 | } |
459 | 460 | ||
460 | static int __init gen_rtc_proc_init(void) | 461 | static int __init gen_rtc_proc_init(void) |
461 | { | 462 | { |
462 | struct proc_dir_entry *r; | 463 | struct proc_dir_entry *r; |
463 | 464 | ||
464 | r = create_proc_read_entry("driver/rtc", 0, NULL, gen_rtc_read_proc, NULL); | 465 | r = create_proc_read_entry("driver/rtc", 0, NULL, gen_rtc_read_proc, NULL); |
465 | if (!r) | 466 | if (!r) |
466 | return -ENOMEM; | 467 | return -ENOMEM; |
467 | return 0; | 468 | return 0; |
468 | } | 469 | } |
469 | #else | 470 | #else |
470 | static inline int gen_rtc_proc_init(void) { return 0; } | 471 | static inline int gen_rtc_proc_init(void) { return 0; } |
471 | #endif /* CONFIG_PROC_FS */ | 472 | #endif /* CONFIG_PROC_FS */ |
472 | 473 | ||
473 | 474 | ||
474 | /* | 475 | /* |
475 | * The various file operations we support. | 476 | * The various file operations we support. |
476 | */ | 477 | */ |
477 | 478 | ||
478 | static const struct file_operations gen_rtc_fops = { | 479 | static const struct file_operations gen_rtc_fops = { |
479 | .owner = THIS_MODULE, | 480 | .owner = THIS_MODULE, |
480 | #ifdef CONFIG_GEN_RTC_X | 481 | #ifdef CONFIG_GEN_RTC_X |
481 | .read = gen_rtc_read, | 482 | .read = gen_rtc_read, |
482 | .poll = gen_rtc_poll, | 483 | .poll = gen_rtc_poll, |
483 | #endif | 484 | #endif |
484 | .ioctl = gen_rtc_ioctl, | 485 | .ioctl = gen_rtc_ioctl, |
485 | .open = gen_rtc_open, | 486 | .open = gen_rtc_open, |
486 | .release = gen_rtc_release, | 487 | .release = gen_rtc_release, |
487 | }; | 488 | }; |
488 | 489 | ||
489 | static struct miscdevice rtc_gen_dev = | 490 | static struct miscdevice rtc_gen_dev = |
490 | { | 491 | { |
491 | .minor = RTC_MINOR, | 492 | .minor = RTC_MINOR, |
492 | .name = "rtc", | 493 | .name = "rtc", |
493 | .fops = &gen_rtc_fops, | 494 | .fops = &gen_rtc_fops, |
494 | }; | 495 | }; |
495 | 496 | ||
496 | static int __init rtc_generic_init(void) | 497 | static int __init rtc_generic_init(void) |
497 | { | 498 | { |
498 | int retval; | 499 | int retval; |
499 | 500 | ||
500 | printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION); | 501 | printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION); |
501 | 502 | ||
502 | retval = misc_register(&rtc_gen_dev); | 503 | retval = misc_register(&rtc_gen_dev); |
503 | if (retval < 0) | 504 | if (retval < 0) |
504 | return retval; | 505 | return retval; |
505 | 506 | ||
506 | retval = gen_rtc_proc_init(); | 507 | retval = gen_rtc_proc_init(); |
507 | if (retval) { | 508 | if (retval) { |
508 | misc_deregister(&rtc_gen_dev); | 509 | misc_deregister(&rtc_gen_dev); |
509 | return retval; | 510 | return retval; |
510 | } | 511 | } |
511 | 512 | ||
512 | return 0; | 513 | return 0; |
513 | } | 514 | } |
514 | 515 | ||
515 | static void __exit rtc_generic_exit(void) | 516 | static void __exit rtc_generic_exit(void) |
516 | { | 517 | { |
517 | remove_proc_entry ("driver/rtc", NULL); | 518 | remove_proc_entry ("driver/rtc", NULL); |
518 | misc_deregister(&rtc_gen_dev); | 519 | misc_deregister(&rtc_gen_dev); |
519 | } | 520 | } |
520 | 521 | ||
521 | 522 | ||
522 | module_init(rtc_generic_init); | 523 | module_init(rtc_generic_init); |
523 | module_exit(rtc_generic_exit); | 524 | module_exit(rtc_generic_exit); |
524 | 525 | ||
525 | MODULE_AUTHOR("Richard Zidlicky"); | 526 | MODULE_AUTHOR("Richard Zidlicky"); |
526 | MODULE_LICENSE("GPL"); | 527 | MODULE_LICENSE("GPL"); |
527 | MODULE_ALIAS_MISCDEV(RTC_MINOR); | 528 | MODULE_ALIAS_MISCDEV(RTC_MINOR); |
528 | 529 |
drivers/char/rtc.c
1 | /* | 1 | /* |
2 | * Real Time Clock interface for Linux | 2 | * Real Time Clock interface for Linux |
3 | * | 3 | * |
4 | * Copyright (C) 1996 Paul Gortmaker | 4 | * Copyright (C) 1996 Paul Gortmaker |
5 | * | 5 | * |
6 | * This driver allows use of the real time clock (built into | 6 | * This driver allows use of the real time clock (built into |
7 | * nearly all computers) from user space. It exports the /dev/rtc | 7 | * nearly all computers) from user space. It exports the /dev/rtc |
8 | * interface supporting various ioctl() and also the | 8 | * interface supporting various ioctl() and also the |
9 | * /proc/driver/rtc pseudo-file for status information. | 9 | * /proc/driver/rtc pseudo-file for status information. |
10 | * | 10 | * |
11 | * The ioctls can be used to set the interrupt behaviour and | 11 | * The ioctls can be used to set the interrupt behaviour and |
12 | * generation rate from the RTC via IRQ 8. Then the /dev/rtc | 12 | * generation rate from the RTC via IRQ 8. Then the /dev/rtc |
13 | * interface can be used to make use of these timer interrupts, | 13 | * interface can be used to make use of these timer interrupts, |
14 | * be they interval or alarm based. | 14 | * be they interval or alarm based. |
15 | * | 15 | * |
16 | * The /dev/rtc interface will block on reads until an interrupt | 16 | * The /dev/rtc interface will block on reads until an interrupt |
17 | * has been received. If a RTC interrupt has already happened, | 17 | * has been received. If a RTC interrupt has already happened, |
18 | * it will output an unsigned long and then block. The output value | 18 | * it will output an unsigned long and then block. The output value |
19 | * contains the interrupt status in the low byte and the number of | 19 | * contains the interrupt status in the low byte and the number of |
20 | * interrupts since the last read in the remaining high bytes. The | 20 | * interrupts since the last read in the remaining high bytes. The |
21 | * /dev/rtc interface can also be used with the select(2) call. | 21 | * /dev/rtc interface can also be used with the select(2) call. |
22 | * | 22 | * |
23 | * This program is free software; you can redistribute it and/or | 23 | * This program is free software; you can redistribute it and/or |
24 | * modify it under the terms of the GNU General Public License | 24 | * modify it under the terms of the GNU General Public License |
25 | * as published by the Free Software Foundation; either version | 25 | * as published by the Free Software Foundation; either version |
26 | * 2 of the License, or (at your option) any later version. | 26 | * 2 of the License, or (at your option) any later version. |
27 | * | 27 | * |
28 | * Based on other minimal char device drivers, like Alan's | 28 | * Based on other minimal char device drivers, like Alan's |
29 | * watchdog, Ted's random, etc. etc. | 29 | * watchdog, Ted's random, etc. etc. |
30 | * | 30 | * |
31 | * 1.07 Paul Gortmaker. | 31 | * 1.07 Paul Gortmaker. |
32 | * 1.08 Miquel van Smoorenburg: disallow certain things on the | 32 | * 1.08 Miquel van Smoorenburg: disallow certain things on the |
33 | * DEC Alpha as the CMOS clock is also used for other things. | 33 | * DEC Alpha as the CMOS clock is also used for other things. |
34 | * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. | 34 | * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. |
35 | * 1.09a Pete Zaitcev: Sun SPARC | 35 | * 1.09a Pete Zaitcev: Sun SPARC |
36 | * 1.09b Jeff Garzik: Modularize, init cleanup | 36 | * 1.09b Jeff Garzik: Modularize, init cleanup |
37 | * 1.09c Jeff Garzik: SMP cleanup | 37 | * 1.09c Jeff Garzik: SMP cleanup |
38 | * 1.10 Paul Barton-Davis: add support for async I/O | 38 | * 1.10 Paul Barton-Davis: add support for async I/O |
39 | * 1.10a Andrea Arcangeli: Alpha updates | 39 | * 1.10a Andrea Arcangeli: Alpha updates |
40 | * 1.10b Andrew Morton: SMP lock fix | 40 | * 1.10b Andrew Morton: SMP lock fix |
41 | * 1.10c Cesar Barros: SMP locking fixes and cleanup | 41 | * 1.10c Cesar Barros: SMP locking fixes and cleanup |
42 | * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit | 42 | * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit |
43 | * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. | 43 | * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. |
44 | * 1.11 Takashi Iwai: Kernel access functions | 44 | * 1.11 Takashi Iwai: Kernel access functions |
45 | * rtc_register/rtc_unregister/rtc_control | 45 | * rtc_register/rtc_unregister/rtc_control |
46 | * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init | 46 | * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init |
47 | * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer | 47 | * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer |
48 | * CONFIG_HPET_EMULATE_RTC | 48 | * CONFIG_HPET_EMULATE_RTC |
49 | * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly. | 49 | * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly. |
50 | * 1.12ac Alan Cox: Allow read access to the day of week register | 50 | * 1.12ac Alan Cox: Allow read access to the day of week register |
51 | * 1.12b David John: Remove calls to the BKL. | 51 | * 1.12b David John: Remove calls to the BKL. |
52 | */ | 52 | */ |
53 | 53 | ||
54 | #define RTC_VERSION "1.12b" | 54 | #define RTC_VERSION "1.12b" |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with | 57 | * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with |
58 | * interrupts disabled. Due to the index-port/data-port (0x70/0x71) | 58 | * interrupts disabled. Due to the index-port/data-port (0x70/0x71) |
59 | * design of the RTC, we don't want two different things trying to | 59 | * design of the RTC, we don't want two different things trying to |
60 | * get to it at once. (e.g. the periodic 11 min sync from time.c vs. | 60 | * get to it at once. (e.g. the periodic 11 min sync from time.c vs. |
61 | * this driver.) | 61 | * this driver.) |
62 | */ | 62 | */ |
63 | 63 | ||
64 | #include <linux/interrupt.h> | 64 | #include <linux/interrupt.h> |
65 | #include <linux/module.h> | 65 | #include <linux/module.h> |
66 | #include <linux/kernel.h> | 66 | #include <linux/kernel.h> |
67 | #include <linux/types.h> | 67 | #include <linux/types.h> |
68 | #include <linux/miscdevice.h> | 68 | #include <linux/miscdevice.h> |
69 | #include <linux/ioport.h> | 69 | #include <linux/ioport.h> |
70 | #include <linux/fcntl.h> | 70 | #include <linux/fcntl.h> |
71 | #include <linux/mc146818rtc.h> | 71 | #include <linux/mc146818rtc.h> |
72 | #include <linux/init.h> | 72 | #include <linux/init.h> |
73 | #include <linux/poll.h> | 73 | #include <linux/poll.h> |
74 | #include <linux/proc_fs.h> | 74 | #include <linux/proc_fs.h> |
75 | #include <linux/seq_file.h> | 75 | #include <linux/seq_file.h> |
76 | #include <linux/spinlock.h> | 76 | #include <linux/spinlock.h> |
77 | #include <linux/sched.h> | ||
77 | #include <linux/sysctl.h> | 78 | #include <linux/sysctl.h> |
78 | #include <linux/wait.h> | 79 | #include <linux/wait.h> |
79 | #include <linux/bcd.h> | 80 | #include <linux/bcd.h> |
80 | #include <linux/delay.h> | 81 | #include <linux/delay.h> |
81 | #include <linux/uaccess.h> | 82 | #include <linux/uaccess.h> |
82 | 83 | ||
83 | #include <asm/current.h> | 84 | #include <asm/current.h> |
84 | #include <asm/system.h> | 85 | #include <asm/system.h> |
85 | 86 | ||
86 | #ifdef CONFIG_X86 | 87 | #ifdef CONFIG_X86 |
87 | #include <asm/hpet.h> | 88 | #include <asm/hpet.h> |
88 | #endif | 89 | #endif |
89 | 90 | ||
90 | #ifdef CONFIG_SPARC32 | 91 | #ifdef CONFIG_SPARC32 |
91 | #include <linux/of.h> | 92 | #include <linux/of.h> |
92 | #include <linux/of_device.h> | 93 | #include <linux/of_device.h> |
93 | #include <asm/io.h> | 94 | #include <asm/io.h> |
94 | 95 | ||
95 | static unsigned long rtc_port; | 96 | static unsigned long rtc_port; |
96 | static int rtc_irq; | 97 | static int rtc_irq; |
97 | #endif | 98 | #endif |
98 | 99 | ||
99 | #ifdef CONFIG_HPET_EMULATE_RTC | 100 | #ifdef CONFIG_HPET_EMULATE_RTC |
100 | #undef RTC_IRQ | 101 | #undef RTC_IRQ |
101 | #endif | 102 | #endif |
102 | 103 | ||
103 | #ifdef RTC_IRQ | 104 | #ifdef RTC_IRQ |
104 | static int rtc_has_irq = 1; | 105 | static int rtc_has_irq = 1; |
105 | #endif | 106 | #endif |
106 | 107 | ||
107 | #ifndef CONFIG_HPET_EMULATE_RTC | 108 | #ifndef CONFIG_HPET_EMULATE_RTC |
108 | #define is_hpet_enabled() 0 | 109 | #define is_hpet_enabled() 0 |
109 | #define hpet_set_alarm_time(hrs, min, sec) 0 | 110 | #define hpet_set_alarm_time(hrs, min, sec) 0 |
110 | #define hpet_set_periodic_freq(arg) 0 | 111 | #define hpet_set_periodic_freq(arg) 0 |
111 | #define hpet_mask_rtc_irq_bit(arg) 0 | 112 | #define hpet_mask_rtc_irq_bit(arg) 0 |
112 | #define hpet_set_rtc_irq_bit(arg) 0 | 113 | #define hpet_set_rtc_irq_bit(arg) 0 |
113 | #define hpet_rtc_timer_init() do { } while (0) | 114 | #define hpet_rtc_timer_init() do { } while (0) |
114 | #define hpet_rtc_dropped_irq() 0 | 115 | #define hpet_rtc_dropped_irq() 0 |
115 | #define hpet_register_irq_handler(h) ({ 0; }) | 116 | #define hpet_register_irq_handler(h) ({ 0; }) |
116 | #define hpet_unregister_irq_handler(h) ({ 0; }) | 117 | #define hpet_unregister_irq_handler(h) ({ 0; }) |
117 | #ifdef RTC_IRQ | 118 | #ifdef RTC_IRQ |
118 | static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) | 119 | static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) |
119 | { | 120 | { |
120 | return 0; | 121 | return 0; |
121 | } | 122 | } |
122 | #endif | 123 | #endif |
123 | #endif | 124 | #endif |
124 | 125 | ||
125 | /* | 126 | /* |
126 | * We sponge a minor off of the misc major. No need slurping | 127 | * We sponge a minor off of the misc major. No need slurping |
127 | * up another valuable major dev number for this. If you add | 128 | * up another valuable major dev number for this. If you add |
128 | * an ioctl, make sure you don't conflict with SPARC's RTC | 129 | * an ioctl, make sure you don't conflict with SPARC's RTC |
129 | * ioctls. | 130 | * ioctls. |
130 | */ | 131 | */ |
131 | 132 | ||
132 | static struct fasync_struct *rtc_async_queue; | 133 | static struct fasync_struct *rtc_async_queue; |
133 | 134 | ||
134 | static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); | 135 | static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); |
135 | 136 | ||
136 | #ifdef RTC_IRQ | 137 | #ifdef RTC_IRQ |
137 | static void rtc_dropped_irq(unsigned long data); | 138 | static void rtc_dropped_irq(unsigned long data); |
138 | 139 | ||
139 | static DEFINE_TIMER(rtc_irq_timer, rtc_dropped_irq, 0, 0); | 140 | static DEFINE_TIMER(rtc_irq_timer, rtc_dropped_irq, 0, 0); |
140 | #endif | 141 | #endif |
141 | 142 | ||
142 | static ssize_t rtc_read(struct file *file, char __user *buf, | 143 | static ssize_t rtc_read(struct file *file, char __user *buf, |
143 | size_t count, loff_t *ppos); | 144 | size_t count, loff_t *ppos); |
144 | 145 | ||
145 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | 146 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
146 | static void rtc_get_rtc_time(struct rtc_time *rtc_tm); | 147 | static void rtc_get_rtc_time(struct rtc_time *rtc_tm); |
147 | 148 | ||
148 | #ifdef RTC_IRQ | 149 | #ifdef RTC_IRQ |
149 | static unsigned int rtc_poll(struct file *file, poll_table *wait); | 150 | static unsigned int rtc_poll(struct file *file, poll_table *wait); |
150 | #endif | 151 | #endif |
151 | 152 | ||
152 | static void get_rtc_alm_time(struct rtc_time *alm_tm); | 153 | static void get_rtc_alm_time(struct rtc_time *alm_tm); |
153 | #ifdef RTC_IRQ | 154 | #ifdef RTC_IRQ |
154 | static void set_rtc_irq_bit_locked(unsigned char bit); | 155 | static void set_rtc_irq_bit_locked(unsigned char bit); |
155 | static void mask_rtc_irq_bit_locked(unsigned char bit); | 156 | static void mask_rtc_irq_bit_locked(unsigned char bit); |
156 | 157 | ||
157 | static inline void set_rtc_irq_bit(unsigned char bit) | 158 | static inline void set_rtc_irq_bit(unsigned char bit) |
158 | { | 159 | { |
159 | spin_lock_irq(&rtc_lock); | 160 | spin_lock_irq(&rtc_lock); |
160 | set_rtc_irq_bit_locked(bit); | 161 | set_rtc_irq_bit_locked(bit); |
161 | spin_unlock_irq(&rtc_lock); | 162 | spin_unlock_irq(&rtc_lock); |
162 | } | 163 | } |
163 | 164 | ||
164 | static void mask_rtc_irq_bit(unsigned char bit) | 165 | static void mask_rtc_irq_bit(unsigned char bit) |
165 | { | 166 | { |
166 | spin_lock_irq(&rtc_lock); | 167 | spin_lock_irq(&rtc_lock); |
167 | mask_rtc_irq_bit_locked(bit); | 168 | mask_rtc_irq_bit_locked(bit); |
168 | spin_unlock_irq(&rtc_lock); | 169 | spin_unlock_irq(&rtc_lock); |
169 | } | 170 | } |
170 | #endif | 171 | #endif |
171 | 172 | ||
172 | #ifdef CONFIG_PROC_FS | 173 | #ifdef CONFIG_PROC_FS |
173 | static int rtc_proc_open(struct inode *inode, struct file *file); | 174 | static int rtc_proc_open(struct inode *inode, struct file *file); |
174 | #endif | 175 | #endif |
175 | 176 | ||
176 | /* | 177 | /* |
177 | * Bits in rtc_status. (6 bits of room for future expansion) | 178 | * Bits in rtc_status. (6 bits of room for future expansion) |
178 | */ | 179 | */ |
179 | 180 | ||
180 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ | 181 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ |
181 | #define RTC_TIMER_ON 0x02 /* missed irq timer active */ | 182 | #define RTC_TIMER_ON 0x02 /* missed irq timer active */ |
182 | 183 | ||
183 | /* | 184 | /* |
184 | * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is | 185 | * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is |
185 | * protected by the spin lock rtc_lock. However, ioctl can still disable the | 186 | * protected by the spin lock rtc_lock. However, ioctl can still disable the |
186 | * timer in rtc_status and then with del_timer after the interrupt has read | 187 | * timer in rtc_status and then with del_timer after the interrupt has read |
187 | * rtc_status but before mod_timer is called, which would then reenable the | 188 | * rtc_status but before mod_timer is called, which would then reenable the |
188 | * timer (but you would need to have an awful timing before you'd trip on it) | 189 | * timer (but you would need to have an awful timing before you'd trip on it) |
189 | */ | 190 | */ |
190 | static unsigned long rtc_status; /* bitmapped status byte. */ | 191 | static unsigned long rtc_status; /* bitmapped status byte. */ |
191 | static unsigned long rtc_freq; /* Current periodic IRQ rate */ | 192 | static unsigned long rtc_freq; /* Current periodic IRQ rate */ |
192 | static unsigned long rtc_irq_data; /* our output to the world */ | 193 | static unsigned long rtc_irq_data; /* our output to the world */ |
193 | static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ | 194 | static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ |
194 | 195 | ||
195 | #ifdef RTC_IRQ | 196 | #ifdef RTC_IRQ |
196 | /* | 197 | /* |
197 | * rtc_task_lock nests inside rtc_lock. | 198 | * rtc_task_lock nests inside rtc_lock. |
198 | */ | 199 | */ |
199 | static DEFINE_SPINLOCK(rtc_task_lock); | 200 | static DEFINE_SPINLOCK(rtc_task_lock); |
200 | static rtc_task_t *rtc_callback; | 201 | static rtc_task_t *rtc_callback; |
201 | #endif | 202 | #endif |
202 | 203 | ||
203 | /* | 204 | /* |
204 | * If this driver ever becomes modularised, it will be really nice | 205 | * If this driver ever becomes modularised, it will be really nice |
205 | * to make the epoch retain its value across module reload... | 206 | * to make the epoch retain its value across module reload... |
206 | */ | 207 | */ |
207 | 208 | ||
208 | static unsigned long epoch = 1900; /* year corresponding to 0x00 */ | 209 | static unsigned long epoch = 1900; /* year corresponding to 0x00 */ |
209 | 210 | ||
210 | static const unsigned char days_in_mo[] = | 211 | static const unsigned char days_in_mo[] = |
211 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | 212 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
212 | 213 | ||
213 | /* | 214 | /* |
214 | * Returns true if a clock update is in progress | 215 | * Returns true if a clock update is in progress |
215 | */ | 216 | */ |
216 | static inline unsigned char rtc_is_updating(void) | 217 | static inline unsigned char rtc_is_updating(void) |
217 | { | 218 | { |
218 | unsigned long flags; | 219 | unsigned long flags; |
219 | unsigned char uip; | 220 | unsigned char uip; |
220 | 221 | ||
221 | spin_lock_irqsave(&rtc_lock, flags); | 222 | spin_lock_irqsave(&rtc_lock, flags); |
222 | uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); | 223 | uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); |
223 | spin_unlock_irqrestore(&rtc_lock, flags); | 224 | spin_unlock_irqrestore(&rtc_lock, flags); |
224 | return uip; | 225 | return uip; |
225 | } | 226 | } |
226 | 227 | ||
227 | #ifdef RTC_IRQ | 228 | #ifdef RTC_IRQ |
228 | /* | 229 | /* |
229 | * A very tiny interrupt handler. It runs with IRQF_DISABLED set, | 230 | * A very tiny interrupt handler. It runs with IRQF_DISABLED set, |
230 | * but there is possibility of conflicting with the set_rtc_mmss() | 231 | * but there is possibility of conflicting with the set_rtc_mmss() |
231 | * call (the rtc irq and the timer irq can easily run at the same | 232 | * call (the rtc irq and the timer irq can easily run at the same |
232 | * time in two different CPUs). So we need to serialize | 233 | * time in two different CPUs). So we need to serialize |
233 | * accesses to the chip with the rtc_lock spinlock that each | 234 | * accesses to the chip with the rtc_lock spinlock that each |
234 | * architecture should implement in the timer code. | 235 | * architecture should implement in the timer code. |
235 | * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) | 236 | * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) |
236 | */ | 237 | */ |
237 | 238 | ||
238 | static irqreturn_t rtc_interrupt(int irq, void *dev_id) | 239 | static irqreturn_t rtc_interrupt(int irq, void *dev_id) |
239 | { | 240 | { |
240 | /* | 241 | /* |
241 | * Can be an alarm interrupt, update complete interrupt, | 242 | * Can be an alarm interrupt, update complete interrupt, |
242 | * or a periodic interrupt. We store the status in the | 243 | * or a periodic interrupt. We store the status in the |
243 | * low byte and the number of interrupts received since | 244 | * low byte and the number of interrupts received since |
244 | * the last read in the remainder of rtc_irq_data. | 245 | * the last read in the remainder of rtc_irq_data. |
245 | */ | 246 | */ |
246 | 247 | ||
247 | spin_lock(&rtc_lock); | 248 | spin_lock(&rtc_lock); |
248 | rtc_irq_data += 0x100; | 249 | rtc_irq_data += 0x100; |
249 | rtc_irq_data &= ~0xff; | 250 | rtc_irq_data &= ~0xff; |
250 | if (is_hpet_enabled()) { | 251 | if (is_hpet_enabled()) { |
251 | /* | 252 | /* |
252 | * In this case it is HPET RTC interrupt handler | 253 | * In this case it is HPET RTC interrupt handler |
253 | * calling us, with the interrupt information | 254 | * calling us, with the interrupt information |
254 | * passed as arg1, instead of irq. | 255 | * passed as arg1, instead of irq. |
255 | */ | 256 | */ |
256 | rtc_irq_data |= (unsigned long)irq & 0xF0; | 257 | rtc_irq_data |= (unsigned long)irq & 0xF0; |
257 | } else { | 258 | } else { |
258 | rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); | 259 | rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); |
259 | } | 260 | } |
260 | 261 | ||
261 | if (rtc_status & RTC_TIMER_ON) | 262 | if (rtc_status & RTC_TIMER_ON) |
262 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); | 263 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); |
263 | 264 | ||
264 | spin_unlock(&rtc_lock); | 265 | spin_unlock(&rtc_lock); |
265 | 266 | ||
266 | /* Now do the rest of the actions */ | 267 | /* Now do the rest of the actions */ |
267 | spin_lock(&rtc_task_lock); | 268 | spin_lock(&rtc_task_lock); |
268 | if (rtc_callback) | 269 | if (rtc_callback) |
269 | rtc_callback->func(rtc_callback->private_data); | 270 | rtc_callback->func(rtc_callback->private_data); |
270 | spin_unlock(&rtc_task_lock); | 271 | spin_unlock(&rtc_task_lock); |
271 | wake_up_interruptible(&rtc_wait); | 272 | wake_up_interruptible(&rtc_wait); |
272 | 273 | ||
273 | kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); | 274 | kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); |
274 | 275 | ||
275 | return IRQ_HANDLED; | 276 | return IRQ_HANDLED; |
276 | } | 277 | } |
277 | #endif | 278 | #endif |
278 | 279 | ||
279 | /* | 280 | /* |
280 | * sysctl-tuning infrastructure. | 281 | * sysctl-tuning infrastructure. |
281 | */ | 282 | */ |
282 | static ctl_table rtc_table[] = { | 283 | static ctl_table rtc_table[] = { |
283 | { | 284 | { |
284 | .ctl_name = CTL_UNNUMBERED, | 285 | .ctl_name = CTL_UNNUMBERED, |
285 | .procname = "max-user-freq", | 286 | .procname = "max-user-freq", |
286 | .data = &rtc_max_user_freq, | 287 | .data = &rtc_max_user_freq, |
287 | .maxlen = sizeof(int), | 288 | .maxlen = sizeof(int), |
288 | .mode = 0644, | 289 | .mode = 0644, |
289 | .proc_handler = &proc_dointvec, | 290 | .proc_handler = &proc_dointvec, |
290 | }, | 291 | }, |
291 | { .ctl_name = 0 } | 292 | { .ctl_name = 0 } |
292 | }; | 293 | }; |
293 | 294 | ||
294 | static ctl_table rtc_root[] = { | 295 | static ctl_table rtc_root[] = { |
295 | { | 296 | { |
296 | .ctl_name = CTL_UNNUMBERED, | 297 | .ctl_name = CTL_UNNUMBERED, |
297 | .procname = "rtc", | 298 | .procname = "rtc", |
298 | .mode = 0555, | 299 | .mode = 0555, |
299 | .child = rtc_table, | 300 | .child = rtc_table, |
300 | }, | 301 | }, |
301 | { .ctl_name = 0 } | 302 | { .ctl_name = 0 } |
302 | }; | 303 | }; |
303 | 304 | ||
304 | static ctl_table dev_root[] = { | 305 | static ctl_table dev_root[] = { |
305 | { | 306 | { |
306 | .ctl_name = CTL_DEV, | 307 | .ctl_name = CTL_DEV, |
307 | .procname = "dev", | 308 | .procname = "dev", |
308 | .mode = 0555, | 309 | .mode = 0555, |
309 | .child = rtc_root, | 310 | .child = rtc_root, |
310 | }, | 311 | }, |
311 | { .ctl_name = 0 } | 312 | { .ctl_name = 0 } |
312 | }; | 313 | }; |
313 | 314 | ||
314 | static struct ctl_table_header *sysctl_header; | 315 | static struct ctl_table_header *sysctl_header; |
315 | 316 | ||
316 | static int __init init_sysctl(void) | 317 | static int __init init_sysctl(void) |
317 | { | 318 | { |
318 | sysctl_header = register_sysctl_table(dev_root); | 319 | sysctl_header = register_sysctl_table(dev_root); |
319 | return 0; | 320 | return 0; |
320 | } | 321 | } |
321 | 322 | ||
322 | static void __exit cleanup_sysctl(void) | 323 | static void __exit cleanup_sysctl(void) |
323 | { | 324 | { |
324 | unregister_sysctl_table(sysctl_header); | 325 | unregister_sysctl_table(sysctl_header); |
325 | } | 326 | } |
326 | 327 | ||
327 | /* | 328 | /* |
328 | * Now all the various file operations that we export. | 329 | * Now all the various file operations that we export. |
329 | */ | 330 | */ |
330 | 331 | ||
331 | static ssize_t rtc_read(struct file *file, char __user *buf, | 332 | static ssize_t rtc_read(struct file *file, char __user *buf, |
332 | size_t count, loff_t *ppos) | 333 | size_t count, loff_t *ppos) |
333 | { | 334 | { |
334 | #ifndef RTC_IRQ | 335 | #ifndef RTC_IRQ |
335 | return -EIO; | 336 | return -EIO; |
336 | #else | 337 | #else |
337 | DECLARE_WAITQUEUE(wait, current); | 338 | DECLARE_WAITQUEUE(wait, current); |
338 | unsigned long data; | 339 | unsigned long data; |
339 | ssize_t retval; | 340 | ssize_t retval; |
340 | 341 | ||
341 | if (rtc_has_irq == 0) | 342 | if (rtc_has_irq == 0) |
342 | return -EIO; | 343 | return -EIO; |
343 | 344 | ||
344 | /* | 345 | /* |
345 | * Historically this function used to assume that sizeof(unsigned long) | 346 | * Historically this function used to assume that sizeof(unsigned long) |
346 | * is the same in userspace and kernelspace. This lead to problems | 347 | * is the same in userspace and kernelspace. This lead to problems |
347 | * for configurations with multiple ABIs such a the MIPS o32 and 64 | 348 | * for configurations with multiple ABIs such a the MIPS o32 and 64 |
348 | * ABIs supported on the same kernel. So now we support read of both | 349 | * ABIs supported on the same kernel. So now we support read of both |
349 | * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the | 350 | * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the |
350 | * userspace ABI. | 351 | * userspace ABI. |
351 | */ | 352 | */ |
352 | if (count != sizeof(unsigned int) && count != sizeof(unsigned long)) | 353 | if (count != sizeof(unsigned int) && count != sizeof(unsigned long)) |
353 | return -EINVAL; | 354 | return -EINVAL; |
354 | 355 | ||
355 | add_wait_queue(&rtc_wait, &wait); | 356 | add_wait_queue(&rtc_wait, &wait); |
356 | 357 | ||
357 | do { | 358 | do { |
358 | /* First make it right. Then make it fast. Putting this whole | 359 | /* First make it right. Then make it fast. Putting this whole |
359 | * block within the parentheses of a while would be too | 360 | * block within the parentheses of a while would be too |
360 | * confusing. And no, xchg() is not the answer. */ | 361 | * confusing. And no, xchg() is not the answer. */ |
361 | 362 | ||
362 | __set_current_state(TASK_INTERRUPTIBLE); | 363 | __set_current_state(TASK_INTERRUPTIBLE); |
363 | 364 | ||
364 | spin_lock_irq(&rtc_lock); | 365 | spin_lock_irq(&rtc_lock); |
365 | data = rtc_irq_data; | 366 | data = rtc_irq_data; |
366 | rtc_irq_data = 0; | 367 | rtc_irq_data = 0; |
367 | spin_unlock_irq(&rtc_lock); | 368 | spin_unlock_irq(&rtc_lock); |
368 | 369 | ||
369 | if (data != 0) | 370 | if (data != 0) |
370 | break; | 371 | break; |
371 | 372 | ||
372 | if (file->f_flags & O_NONBLOCK) { | 373 | if (file->f_flags & O_NONBLOCK) { |
373 | retval = -EAGAIN; | 374 | retval = -EAGAIN; |
374 | goto out; | 375 | goto out; |
375 | } | 376 | } |
376 | if (signal_pending(current)) { | 377 | if (signal_pending(current)) { |
377 | retval = -ERESTARTSYS; | 378 | retval = -ERESTARTSYS; |
378 | goto out; | 379 | goto out; |
379 | } | 380 | } |
380 | schedule(); | 381 | schedule(); |
381 | } while (1); | 382 | } while (1); |
382 | 383 | ||
383 | if (count == sizeof(unsigned int)) { | 384 | if (count == sizeof(unsigned int)) { |
384 | retval = put_user(data, | 385 | retval = put_user(data, |
385 | (unsigned int __user *)buf) ?: sizeof(int); | 386 | (unsigned int __user *)buf) ?: sizeof(int); |
386 | } else { | 387 | } else { |
387 | retval = put_user(data, | 388 | retval = put_user(data, |
388 | (unsigned long __user *)buf) ?: sizeof(long); | 389 | (unsigned long __user *)buf) ?: sizeof(long); |
389 | } | 390 | } |
390 | if (!retval) | 391 | if (!retval) |
391 | retval = count; | 392 | retval = count; |
392 | out: | 393 | out: |
393 | __set_current_state(TASK_RUNNING); | 394 | __set_current_state(TASK_RUNNING); |
394 | remove_wait_queue(&rtc_wait, &wait); | 395 | remove_wait_queue(&rtc_wait, &wait); |
395 | 396 | ||
396 | return retval; | 397 | return retval; |
397 | #endif | 398 | #endif |
398 | } | 399 | } |
399 | 400 | ||
400 | static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) | 401 | static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) |
401 | { | 402 | { |
402 | struct rtc_time wtime; | 403 | struct rtc_time wtime; |
403 | 404 | ||
404 | #ifdef RTC_IRQ | 405 | #ifdef RTC_IRQ |
405 | if (rtc_has_irq == 0) { | 406 | if (rtc_has_irq == 0) { |
406 | switch (cmd) { | 407 | switch (cmd) { |
407 | case RTC_AIE_OFF: | 408 | case RTC_AIE_OFF: |
408 | case RTC_AIE_ON: | 409 | case RTC_AIE_ON: |
409 | case RTC_PIE_OFF: | 410 | case RTC_PIE_OFF: |
410 | case RTC_PIE_ON: | 411 | case RTC_PIE_ON: |
411 | case RTC_UIE_OFF: | 412 | case RTC_UIE_OFF: |
412 | case RTC_UIE_ON: | 413 | case RTC_UIE_ON: |
413 | case RTC_IRQP_READ: | 414 | case RTC_IRQP_READ: |
414 | case RTC_IRQP_SET: | 415 | case RTC_IRQP_SET: |
415 | return -EINVAL; | 416 | return -EINVAL; |
416 | }; | 417 | }; |
417 | } | 418 | } |
418 | #endif | 419 | #endif |
419 | 420 | ||
420 | switch (cmd) { | 421 | switch (cmd) { |
421 | #ifdef RTC_IRQ | 422 | #ifdef RTC_IRQ |
422 | case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ | 423 | case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ |
423 | { | 424 | { |
424 | mask_rtc_irq_bit(RTC_AIE); | 425 | mask_rtc_irq_bit(RTC_AIE); |
425 | return 0; | 426 | return 0; |
426 | } | 427 | } |
427 | case RTC_AIE_ON: /* Allow alarm interrupts. */ | 428 | case RTC_AIE_ON: /* Allow alarm interrupts. */ |
428 | { | 429 | { |
429 | set_rtc_irq_bit(RTC_AIE); | 430 | set_rtc_irq_bit(RTC_AIE); |
430 | return 0; | 431 | return 0; |
431 | } | 432 | } |
432 | case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ | 433 | case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ |
433 | { | 434 | { |
434 | /* can be called from isr via rtc_control() */ | 435 | /* can be called from isr via rtc_control() */ |
435 | unsigned long flags; | 436 | unsigned long flags; |
436 | 437 | ||
437 | spin_lock_irqsave(&rtc_lock, flags); | 438 | spin_lock_irqsave(&rtc_lock, flags); |
438 | mask_rtc_irq_bit_locked(RTC_PIE); | 439 | mask_rtc_irq_bit_locked(RTC_PIE); |
439 | if (rtc_status & RTC_TIMER_ON) { | 440 | if (rtc_status & RTC_TIMER_ON) { |
440 | rtc_status &= ~RTC_TIMER_ON; | 441 | rtc_status &= ~RTC_TIMER_ON; |
441 | del_timer(&rtc_irq_timer); | 442 | del_timer(&rtc_irq_timer); |
442 | } | 443 | } |
443 | spin_unlock_irqrestore(&rtc_lock, flags); | 444 | spin_unlock_irqrestore(&rtc_lock, flags); |
444 | 445 | ||
445 | return 0; | 446 | return 0; |
446 | } | 447 | } |
447 | case RTC_PIE_ON: /* Allow periodic ints */ | 448 | case RTC_PIE_ON: /* Allow periodic ints */ |
448 | { | 449 | { |
449 | /* can be called from isr via rtc_control() */ | 450 | /* can be called from isr via rtc_control() */ |
450 | unsigned long flags; | 451 | unsigned long flags; |
451 | 452 | ||
452 | /* | 453 | /* |
453 | * We don't really want Joe User enabling more | 454 | * We don't really want Joe User enabling more |
454 | * than 64Hz of interrupts on a multi-user machine. | 455 | * than 64Hz of interrupts on a multi-user machine. |
455 | */ | 456 | */ |
456 | if (!kernel && (rtc_freq > rtc_max_user_freq) && | 457 | if (!kernel && (rtc_freq > rtc_max_user_freq) && |
457 | (!capable(CAP_SYS_RESOURCE))) | 458 | (!capable(CAP_SYS_RESOURCE))) |
458 | return -EACCES; | 459 | return -EACCES; |
459 | 460 | ||
460 | spin_lock_irqsave(&rtc_lock, flags); | 461 | spin_lock_irqsave(&rtc_lock, flags); |
461 | if (!(rtc_status & RTC_TIMER_ON)) { | 462 | if (!(rtc_status & RTC_TIMER_ON)) { |
462 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + | 463 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + |
463 | 2*HZ/100); | 464 | 2*HZ/100); |
464 | rtc_status |= RTC_TIMER_ON; | 465 | rtc_status |= RTC_TIMER_ON; |
465 | } | 466 | } |
466 | set_rtc_irq_bit_locked(RTC_PIE); | 467 | set_rtc_irq_bit_locked(RTC_PIE); |
467 | spin_unlock_irqrestore(&rtc_lock, flags); | 468 | spin_unlock_irqrestore(&rtc_lock, flags); |
468 | 469 | ||
469 | return 0; | 470 | return 0; |
470 | } | 471 | } |
471 | case RTC_UIE_OFF: /* Mask ints from RTC updates. */ | 472 | case RTC_UIE_OFF: /* Mask ints from RTC updates. */ |
472 | { | 473 | { |
473 | mask_rtc_irq_bit(RTC_UIE); | 474 | mask_rtc_irq_bit(RTC_UIE); |
474 | return 0; | 475 | return 0; |
475 | } | 476 | } |
476 | case RTC_UIE_ON: /* Allow ints for RTC updates. */ | 477 | case RTC_UIE_ON: /* Allow ints for RTC updates. */ |
477 | { | 478 | { |
478 | set_rtc_irq_bit(RTC_UIE); | 479 | set_rtc_irq_bit(RTC_UIE); |
479 | return 0; | 480 | return 0; |
480 | } | 481 | } |
481 | #endif | 482 | #endif |
482 | case RTC_ALM_READ: /* Read the present alarm time */ | 483 | case RTC_ALM_READ: /* Read the present alarm time */ |
483 | { | 484 | { |
484 | /* | 485 | /* |
485 | * This returns a struct rtc_time. Reading >= 0xc0 | 486 | * This returns a struct rtc_time. Reading >= 0xc0 |
486 | * means "don't care" or "match all". Only the tm_hour, | 487 | * means "don't care" or "match all". Only the tm_hour, |
487 | * tm_min, and tm_sec values are filled in. | 488 | * tm_min, and tm_sec values are filled in. |
488 | */ | 489 | */ |
489 | memset(&wtime, 0, sizeof(struct rtc_time)); | 490 | memset(&wtime, 0, sizeof(struct rtc_time)); |
490 | get_rtc_alm_time(&wtime); | 491 | get_rtc_alm_time(&wtime); |
491 | break; | 492 | break; |
492 | } | 493 | } |
493 | case RTC_ALM_SET: /* Store a time into the alarm */ | 494 | case RTC_ALM_SET: /* Store a time into the alarm */ |
494 | { | 495 | { |
495 | /* | 496 | /* |
496 | * This expects a struct rtc_time. Writing 0xff means | 497 | * This expects a struct rtc_time. Writing 0xff means |
497 | * "don't care" or "match all". Only the tm_hour, | 498 | * "don't care" or "match all". Only the tm_hour, |
498 | * tm_min and tm_sec are used. | 499 | * tm_min and tm_sec are used. |
499 | */ | 500 | */ |
500 | unsigned char hrs, min, sec; | 501 | unsigned char hrs, min, sec; |
501 | struct rtc_time alm_tm; | 502 | struct rtc_time alm_tm; |
502 | 503 | ||
503 | if (copy_from_user(&alm_tm, (struct rtc_time __user *)arg, | 504 | if (copy_from_user(&alm_tm, (struct rtc_time __user *)arg, |
504 | sizeof(struct rtc_time))) | 505 | sizeof(struct rtc_time))) |
505 | return -EFAULT; | 506 | return -EFAULT; |
506 | 507 | ||
507 | hrs = alm_tm.tm_hour; | 508 | hrs = alm_tm.tm_hour; |
508 | min = alm_tm.tm_min; | 509 | min = alm_tm.tm_min; |
509 | sec = alm_tm.tm_sec; | 510 | sec = alm_tm.tm_sec; |
510 | 511 | ||
511 | spin_lock_irq(&rtc_lock); | 512 | spin_lock_irq(&rtc_lock); |
512 | if (hpet_set_alarm_time(hrs, min, sec)) { | 513 | if (hpet_set_alarm_time(hrs, min, sec)) { |
513 | /* | 514 | /* |
514 | * Fallthru and set alarm time in CMOS too, | 515 | * Fallthru and set alarm time in CMOS too, |
515 | * so that we will get proper value in RTC_ALM_READ | 516 | * so that we will get proper value in RTC_ALM_READ |
516 | */ | 517 | */ |
517 | } | 518 | } |
518 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || | 519 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || |
519 | RTC_ALWAYS_BCD) { | 520 | RTC_ALWAYS_BCD) { |
520 | if (sec < 60) | 521 | if (sec < 60) |
521 | sec = bin2bcd(sec); | 522 | sec = bin2bcd(sec); |
522 | else | 523 | else |
523 | sec = 0xff; | 524 | sec = 0xff; |
524 | 525 | ||
525 | if (min < 60) | 526 | if (min < 60) |
526 | min = bin2bcd(min); | 527 | min = bin2bcd(min); |
527 | else | 528 | else |
528 | min = 0xff; | 529 | min = 0xff; |
529 | 530 | ||
530 | if (hrs < 24) | 531 | if (hrs < 24) |
531 | hrs = bin2bcd(hrs); | 532 | hrs = bin2bcd(hrs); |
532 | else | 533 | else |
533 | hrs = 0xff; | 534 | hrs = 0xff; |
534 | } | 535 | } |
535 | CMOS_WRITE(hrs, RTC_HOURS_ALARM); | 536 | CMOS_WRITE(hrs, RTC_HOURS_ALARM); |
536 | CMOS_WRITE(min, RTC_MINUTES_ALARM); | 537 | CMOS_WRITE(min, RTC_MINUTES_ALARM); |
537 | CMOS_WRITE(sec, RTC_SECONDS_ALARM); | 538 | CMOS_WRITE(sec, RTC_SECONDS_ALARM); |
538 | spin_unlock_irq(&rtc_lock); | 539 | spin_unlock_irq(&rtc_lock); |
539 | 540 | ||
540 | return 0; | 541 | return 0; |
541 | } | 542 | } |
542 | case RTC_RD_TIME: /* Read the time/date from RTC */ | 543 | case RTC_RD_TIME: /* Read the time/date from RTC */ |
543 | { | 544 | { |
544 | memset(&wtime, 0, sizeof(struct rtc_time)); | 545 | memset(&wtime, 0, sizeof(struct rtc_time)); |
545 | rtc_get_rtc_time(&wtime); | 546 | rtc_get_rtc_time(&wtime); |
546 | break; | 547 | break; |
547 | } | 548 | } |
548 | case RTC_SET_TIME: /* Set the RTC */ | 549 | case RTC_SET_TIME: /* Set the RTC */ |
549 | { | 550 | { |
550 | struct rtc_time rtc_tm; | 551 | struct rtc_time rtc_tm; |
551 | unsigned char mon, day, hrs, min, sec, leap_yr; | 552 | unsigned char mon, day, hrs, min, sec, leap_yr; |
552 | unsigned char save_control, save_freq_select; | 553 | unsigned char save_control, save_freq_select; |
553 | unsigned int yrs; | 554 | unsigned int yrs; |
554 | #ifdef CONFIG_MACH_DECSTATION | 555 | #ifdef CONFIG_MACH_DECSTATION |
555 | unsigned int real_yrs; | 556 | unsigned int real_yrs; |
556 | #endif | 557 | #endif |
557 | 558 | ||
558 | if (!capable(CAP_SYS_TIME)) | 559 | if (!capable(CAP_SYS_TIME)) |
559 | return -EACCES; | 560 | return -EACCES; |
560 | 561 | ||
561 | if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg, | 562 | if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg, |
562 | sizeof(struct rtc_time))) | 563 | sizeof(struct rtc_time))) |
563 | return -EFAULT; | 564 | return -EFAULT; |
564 | 565 | ||
565 | yrs = rtc_tm.tm_year + 1900; | 566 | yrs = rtc_tm.tm_year + 1900; |
566 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ | 567 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ |
567 | day = rtc_tm.tm_mday; | 568 | day = rtc_tm.tm_mday; |
568 | hrs = rtc_tm.tm_hour; | 569 | hrs = rtc_tm.tm_hour; |
569 | min = rtc_tm.tm_min; | 570 | min = rtc_tm.tm_min; |
570 | sec = rtc_tm.tm_sec; | 571 | sec = rtc_tm.tm_sec; |
571 | 572 | ||
572 | if (yrs < 1970) | 573 | if (yrs < 1970) |
573 | return -EINVAL; | 574 | return -EINVAL; |
574 | 575 | ||
575 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); | 576 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); |
576 | 577 | ||
577 | if ((mon > 12) || (day == 0)) | 578 | if ((mon > 12) || (day == 0)) |
578 | return -EINVAL; | 579 | return -EINVAL; |
579 | 580 | ||
580 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) | 581 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) |
581 | return -EINVAL; | 582 | return -EINVAL; |
582 | 583 | ||
583 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) | 584 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) |
584 | return -EINVAL; | 585 | return -EINVAL; |
585 | 586 | ||
586 | yrs -= epoch; | 587 | yrs -= epoch; |
587 | if (yrs > 255) /* They are unsigned */ | 588 | if (yrs > 255) /* They are unsigned */ |
588 | return -EINVAL; | 589 | return -EINVAL; |
589 | 590 | ||
590 | spin_lock_irq(&rtc_lock); | 591 | spin_lock_irq(&rtc_lock); |
591 | #ifdef CONFIG_MACH_DECSTATION | 592 | #ifdef CONFIG_MACH_DECSTATION |
592 | real_yrs = yrs; | 593 | real_yrs = yrs; |
593 | yrs = 72; | 594 | yrs = 72; |
594 | 595 | ||
595 | /* | 596 | /* |
596 | * We want to keep the year set to 73 until March | 597 | * We want to keep the year set to 73 until March |
597 | * for non-leap years, so that Feb, 29th is handled | 598 | * for non-leap years, so that Feb, 29th is handled |
598 | * correctly. | 599 | * correctly. |
599 | */ | 600 | */ |
600 | if (!leap_yr && mon < 3) { | 601 | if (!leap_yr && mon < 3) { |
601 | real_yrs--; | 602 | real_yrs--; |
602 | yrs = 73; | 603 | yrs = 73; |
603 | } | 604 | } |
604 | #endif | 605 | #endif |
605 | /* These limits and adjustments are independent of | 606 | /* These limits and adjustments are independent of |
606 | * whether the chip is in binary mode or not. | 607 | * whether the chip is in binary mode or not. |
607 | */ | 608 | */ |
608 | if (yrs > 169) { | 609 | if (yrs > 169) { |
609 | spin_unlock_irq(&rtc_lock); | 610 | spin_unlock_irq(&rtc_lock); |
610 | return -EINVAL; | 611 | return -EINVAL; |
611 | } | 612 | } |
612 | if (yrs >= 100) | 613 | if (yrs >= 100) |
613 | yrs -= 100; | 614 | yrs -= 100; |
614 | 615 | ||
615 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) | 616 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) |
616 | || RTC_ALWAYS_BCD) { | 617 | || RTC_ALWAYS_BCD) { |
617 | sec = bin2bcd(sec); | 618 | sec = bin2bcd(sec); |
618 | min = bin2bcd(min); | 619 | min = bin2bcd(min); |
619 | hrs = bin2bcd(hrs); | 620 | hrs = bin2bcd(hrs); |
620 | day = bin2bcd(day); | 621 | day = bin2bcd(day); |
621 | mon = bin2bcd(mon); | 622 | mon = bin2bcd(mon); |
622 | yrs = bin2bcd(yrs); | 623 | yrs = bin2bcd(yrs); |
623 | } | 624 | } |
624 | 625 | ||
625 | save_control = CMOS_READ(RTC_CONTROL); | 626 | save_control = CMOS_READ(RTC_CONTROL); |
626 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | 627 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); |
627 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | 628 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); |
628 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | 629 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); |
629 | 630 | ||
630 | #ifdef CONFIG_MACH_DECSTATION | 631 | #ifdef CONFIG_MACH_DECSTATION |
631 | CMOS_WRITE(real_yrs, RTC_DEC_YEAR); | 632 | CMOS_WRITE(real_yrs, RTC_DEC_YEAR); |
632 | #endif | 633 | #endif |
633 | CMOS_WRITE(yrs, RTC_YEAR); | 634 | CMOS_WRITE(yrs, RTC_YEAR); |
634 | CMOS_WRITE(mon, RTC_MONTH); | 635 | CMOS_WRITE(mon, RTC_MONTH); |
635 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); | 636 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); |
636 | CMOS_WRITE(hrs, RTC_HOURS); | 637 | CMOS_WRITE(hrs, RTC_HOURS); |
637 | CMOS_WRITE(min, RTC_MINUTES); | 638 | CMOS_WRITE(min, RTC_MINUTES); |
638 | CMOS_WRITE(sec, RTC_SECONDS); | 639 | CMOS_WRITE(sec, RTC_SECONDS); |
639 | 640 | ||
640 | CMOS_WRITE(save_control, RTC_CONTROL); | 641 | CMOS_WRITE(save_control, RTC_CONTROL); |
641 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | 642 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); |
642 | 643 | ||
643 | spin_unlock_irq(&rtc_lock); | 644 | spin_unlock_irq(&rtc_lock); |
644 | return 0; | 645 | return 0; |
645 | } | 646 | } |
646 | #ifdef RTC_IRQ | 647 | #ifdef RTC_IRQ |
647 | case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ | 648 | case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ |
648 | { | 649 | { |
649 | return put_user(rtc_freq, (unsigned long __user *)arg); | 650 | return put_user(rtc_freq, (unsigned long __user *)arg); |
650 | } | 651 | } |
651 | case RTC_IRQP_SET: /* Set periodic IRQ rate. */ | 652 | case RTC_IRQP_SET: /* Set periodic IRQ rate. */ |
652 | { | 653 | { |
653 | int tmp = 0; | 654 | int tmp = 0; |
654 | unsigned char val; | 655 | unsigned char val; |
655 | /* can be called from isr via rtc_control() */ | 656 | /* can be called from isr via rtc_control() */ |
656 | unsigned long flags; | 657 | unsigned long flags; |
657 | 658 | ||
658 | /* | 659 | /* |
659 | * The max we can do is 8192Hz. | 660 | * The max we can do is 8192Hz. |
660 | */ | 661 | */ |
661 | if ((arg < 2) || (arg > 8192)) | 662 | if ((arg < 2) || (arg > 8192)) |
662 | return -EINVAL; | 663 | return -EINVAL; |
663 | /* | 664 | /* |
664 | * We don't really want Joe User generating more | 665 | * We don't really want Joe User generating more |
665 | * than 64Hz of interrupts on a multi-user machine. | 666 | * than 64Hz of interrupts on a multi-user machine. |
666 | */ | 667 | */ |
667 | if (!kernel && (arg > rtc_max_user_freq) && | 668 | if (!kernel && (arg > rtc_max_user_freq) && |
668 | !capable(CAP_SYS_RESOURCE)) | 669 | !capable(CAP_SYS_RESOURCE)) |
669 | return -EACCES; | 670 | return -EACCES; |
670 | 671 | ||
671 | while (arg > (1<<tmp)) | 672 | while (arg > (1<<tmp)) |
672 | tmp++; | 673 | tmp++; |
673 | 674 | ||
674 | /* | 675 | /* |
675 | * Check that the input was really a power of 2. | 676 | * Check that the input was really a power of 2. |
676 | */ | 677 | */ |
677 | if (arg != (1<<tmp)) | 678 | if (arg != (1<<tmp)) |
678 | return -EINVAL; | 679 | return -EINVAL; |
679 | 680 | ||
680 | rtc_freq = arg; | 681 | rtc_freq = arg; |
681 | 682 | ||
682 | spin_lock_irqsave(&rtc_lock, flags); | 683 | spin_lock_irqsave(&rtc_lock, flags); |
683 | if (hpet_set_periodic_freq(arg)) { | 684 | if (hpet_set_periodic_freq(arg)) { |
684 | spin_unlock_irqrestore(&rtc_lock, flags); | 685 | spin_unlock_irqrestore(&rtc_lock, flags); |
685 | return 0; | 686 | return 0; |
686 | } | 687 | } |
687 | 688 | ||
688 | val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; | 689 | val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; |
689 | val |= (16 - tmp); | 690 | val |= (16 - tmp); |
690 | CMOS_WRITE(val, RTC_FREQ_SELECT); | 691 | CMOS_WRITE(val, RTC_FREQ_SELECT); |
691 | spin_unlock_irqrestore(&rtc_lock, flags); | 692 | spin_unlock_irqrestore(&rtc_lock, flags); |
692 | return 0; | 693 | return 0; |
693 | } | 694 | } |
694 | #endif | 695 | #endif |
695 | case RTC_EPOCH_READ: /* Read the epoch. */ | 696 | case RTC_EPOCH_READ: /* Read the epoch. */ |
696 | { | 697 | { |
697 | return put_user(epoch, (unsigned long __user *)arg); | 698 | return put_user(epoch, (unsigned long __user *)arg); |
698 | } | 699 | } |
699 | case RTC_EPOCH_SET: /* Set the epoch. */ | 700 | case RTC_EPOCH_SET: /* Set the epoch. */ |
700 | { | 701 | { |
701 | /* | 702 | /* |
702 | * There were no RTC clocks before 1900. | 703 | * There were no RTC clocks before 1900. |
703 | */ | 704 | */ |
704 | if (arg < 1900) | 705 | if (arg < 1900) |
705 | return -EINVAL; | 706 | return -EINVAL; |
706 | 707 | ||
707 | if (!capable(CAP_SYS_TIME)) | 708 | if (!capable(CAP_SYS_TIME)) |
708 | return -EACCES; | 709 | return -EACCES; |
709 | 710 | ||
710 | epoch = arg; | 711 | epoch = arg; |
711 | return 0; | 712 | return 0; |
712 | } | 713 | } |
713 | default: | 714 | default: |
714 | return -ENOTTY; | 715 | return -ENOTTY; |
715 | } | 716 | } |
716 | return copy_to_user((void __user *)arg, | 717 | return copy_to_user((void __user *)arg, |
717 | &wtime, sizeof wtime) ? -EFAULT : 0; | 718 | &wtime, sizeof wtime) ? -EFAULT : 0; |
718 | } | 719 | } |
719 | 720 | ||
720 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 721 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
721 | { | 722 | { |
722 | long ret; | 723 | long ret; |
723 | ret = rtc_do_ioctl(cmd, arg, 0); | 724 | ret = rtc_do_ioctl(cmd, arg, 0); |
724 | return ret; | 725 | return ret; |
725 | } | 726 | } |
726 | 727 | ||
727 | /* | 728 | /* |
728 | * We enforce only one user at a time here with the open/close. | 729 | * We enforce only one user at a time here with the open/close. |
729 | * Also clear the previous interrupt data on an open, and clean | 730 | * Also clear the previous interrupt data on an open, and clean |
730 | * up things on a close. | 731 | * up things on a close. |
731 | */ | 732 | */ |
732 | static int rtc_open(struct inode *inode, struct file *file) | 733 | static int rtc_open(struct inode *inode, struct file *file) |
733 | { | 734 | { |
734 | spin_lock_irq(&rtc_lock); | 735 | spin_lock_irq(&rtc_lock); |
735 | 736 | ||
736 | if (rtc_status & RTC_IS_OPEN) | 737 | if (rtc_status & RTC_IS_OPEN) |
737 | goto out_busy; | 738 | goto out_busy; |
738 | 739 | ||
739 | rtc_status |= RTC_IS_OPEN; | 740 | rtc_status |= RTC_IS_OPEN; |
740 | 741 | ||
741 | rtc_irq_data = 0; | 742 | rtc_irq_data = 0; |
742 | spin_unlock_irq(&rtc_lock); | 743 | spin_unlock_irq(&rtc_lock); |
743 | return 0; | 744 | return 0; |
744 | 745 | ||
745 | out_busy: | 746 | out_busy: |
746 | spin_unlock_irq(&rtc_lock); | 747 | spin_unlock_irq(&rtc_lock); |
747 | return -EBUSY; | 748 | return -EBUSY; |
748 | } | 749 | } |
749 | 750 | ||
750 | static int rtc_fasync(int fd, struct file *filp, int on) | 751 | static int rtc_fasync(int fd, struct file *filp, int on) |
751 | { | 752 | { |
752 | return fasync_helper(fd, filp, on, &rtc_async_queue); | 753 | return fasync_helper(fd, filp, on, &rtc_async_queue); |
753 | } | 754 | } |
754 | 755 | ||
755 | static int rtc_release(struct inode *inode, struct file *file) | 756 | static int rtc_release(struct inode *inode, struct file *file) |
756 | { | 757 | { |
757 | #ifdef RTC_IRQ | 758 | #ifdef RTC_IRQ |
758 | unsigned char tmp; | 759 | unsigned char tmp; |
759 | 760 | ||
760 | if (rtc_has_irq == 0) | 761 | if (rtc_has_irq == 0) |
761 | goto no_irq; | 762 | goto no_irq; |
762 | 763 | ||
763 | /* | 764 | /* |
764 | * Turn off all interrupts once the device is no longer | 765 | * Turn off all interrupts once the device is no longer |
765 | * in use, and clear the data. | 766 | * in use, and clear the data. |
766 | */ | 767 | */ |
767 | 768 | ||
768 | spin_lock_irq(&rtc_lock); | 769 | spin_lock_irq(&rtc_lock); |
769 | if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { | 770 | if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { |
770 | tmp = CMOS_READ(RTC_CONTROL); | 771 | tmp = CMOS_READ(RTC_CONTROL); |
771 | tmp &= ~RTC_PIE; | 772 | tmp &= ~RTC_PIE; |
772 | tmp &= ~RTC_AIE; | 773 | tmp &= ~RTC_AIE; |
773 | tmp &= ~RTC_UIE; | 774 | tmp &= ~RTC_UIE; |
774 | CMOS_WRITE(tmp, RTC_CONTROL); | 775 | CMOS_WRITE(tmp, RTC_CONTROL); |
775 | CMOS_READ(RTC_INTR_FLAGS); | 776 | CMOS_READ(RTC_INTR_FLAGS); |
776 | } | 777 | } |
777 | if (rtc_status & RTC_TIMER_ON) { | 778 | if (rtc_status & RTC_TIMER_ON) { |
778 | rtc_status &= ~RTC_TIMER_ON; | 779 | rtc_status &= ~RTC_TIMER_ON; |
779 | del_timer(&rtc_irq_timer); | 780 | del_timer(&rtc_irq_timer); |
780 | } | 781 | } |
781 | spin_unlock_irq(&rtc_lock); | 782 | spin_unlock_irq(&rtc_lock); |
782 | 783 | ||
783 | no_irq: | 784 | no_irq: |
784 | #endif | 785 | #endif |
785 | 786 | ||
786 | spin_lock_irq(&rtc_lock); | 787 | spin_lock_irq(&rtc_lock); |
787 | rtc_irq_data = 0; | 788 | rtc_irq_data = 0; |
788 | rtc_status &= ~RTC_IS_OPEN; | 789 | rtc_status &= ~RTC_IS_OPEN; |
789 | spin_unlock_irq(&rtc_lock); | 790 | spin_unlock_irq(&rtc_lock); |
790 | 791 | ||
791 | return 0; | 792 | return 0; |
792 | } | 793 | } |
793 | 794 | ||
794 | #ifdef RTC_IRQ | 795 | #ifdef RTC_IRQ |
795 | static unsigned int rtc_poll(struct file *file, poll_table *wait) | 796 | static unsigned int rtc_poll(struct file *file, poll_table *wait) |
796 | { | 797 | { |
797 | unsigned long l; | 798 | unsigned long l; |
798 | 799 | ||
799 | if (rtc_has_irq == 0) | 800 | if (rtc_has_irq == 0) |
800 | return 0; | 801 | return 0; |
801 | 802 | ||
802 | poll_wait(file, &rtc_wait, wait); | 803 | poll_wait(file, &rtc_wait, wait); |
803 | 804 | ||
804 | spin_lock_irq(&rtc_lock); | 805 | spin_lock_irq(&rtc_lock); |
805 | l = rtc_irq_data; | 806 | l = rtc_irq_data; |
806 | spin_unlock_irq(&rtc_lock); | 807 | spin_unlock_irq(&rtc_lock); |
807 | 808 | ||
808 | if (l != 0) | 809 | if (l != 0) |
809 | return POLLIN | POLLRDNORM; | 810 | return POLLIN | POLLRDNORM; |
810 | return 0; | 811 | return 0; |
811 | } | 812 | } |
812 | #endif | 813 | #endif |
813 | 814 | ||
814 | int rtc_register(rtc_task_t *task) | 815 | int rtc_register(rtc_task_t *task) |
815 | { | 816 | { |
816 | #ifndef RTC_IRQ | 817 | #ifndef RTC_IRQ |
817 | return -EIO; | 818 | return -EIO; |
818 | #else | 819 | #else |
819 | if (task == NULL || task->func == NULL) | 820 | if (task == NULL || task->func == NULL) |
820 | return -EINVAL; | 821 | return -EINVAL; |
821 | spin_lock_irq(&rtc_lock); | 822 | spin_lock_irq(&rtc_lock); |
822 | if (rtc_status & RTC_IS_OPEN) { | 823 | if (rtc_status & RTC_IS_OPEN) { |
823 | spin_unlock_irq(&rtc_lock); | 824 | spin_unlock_irq(&rtc_lock); |
824 | return -EBUSY; | 825 | return -EBUSY; |
825 | } | 826 | } |
826 | spin_lock(&rtc_task_lock); | 827 | spin_lock(&rtc_task_lock); |
827 | if (rtc_callback) { | 828 | if (rtc_callback) { |
828 | spin_unlock(&rtc_task_lock); | 829 | spin_unlock(&rtc_task_lock); |
829 | spin_unlock_irq(&rtc_lock); | 830 | spin_unlock_irq(&rtc_lock); |
830 | return -EBUSY; | 831 | return -EBUSY; |
831 | } | 832 | } |
832 | rtc_status |= RTC_IS_OPEN; | 833 | rtc_status |= RTC_IS_OPEN; |
833 | rtc_callback = task; | 834 | rtc_callback = task; |
834 | spin_unlock(&rtc_task_lock); | 835 | spin_unlock(&rtc_task_lock); |
835 | spin_unlock_irq(&rtc_lock); | 836 | spin_unlock_irq(&rtc_lock); |
836 | return 0; | 837 | return 0; |
837 | #endif | 838 | #endif |
838 | } | 839 | } |
839 | EXPORT_SYMBOL(rtc_register); | 840 | EXPORT_SYMBOL(rtc_register); |
840 | 841 | ||
841 | int rtc_unregister(rtc_task_t *task) | 842 | int rtc_unregister(rtc_task_t *task) |
842 | { | 843 | { |
843 | #ifndef RTC_IRQ | 844 | #ifndef RTC_IRQ |
844 | return -EIO; | 845 | return -EIO; |
845 | #else | 846 | #else |
846 | unsigned char tmp; | 847 | unsigned char tmp; |
847 | 848 | ||
848 | spin_lock_irq(&rtc_lock); | 849 | spin_lock_irq(&rtc_lock); |
849 | spin_lock(&rtc_task_lock); | 850 | spin_lock(&rtc_task_lock); |
850 | if (rtc_callback != task) { | 851 | if (rtc_callback != task) { |
851 | spin_unlock(&rtc_task_lock); | 852 | spin_unlock(&rtc_task_lock); |
852 | spin_unlock_irq(&rtc_lock); | 853 | spin_unlock_irq(&rtc_lock); |
853 | return -ENXIO; | 854 | return -ENXIO; |
854 | } | 855 | } |
855 | rtc_callback = NULL; | 856 | rtc_callback = NULL; |
856 | 857 | ||
857 | /* disable controls */ | 858 | /* disable controls */ |
858 | if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { | 859 | if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { |
859 | tmp = CMOS_READ(RTC_CONTROL); | 860 | tmp = CMOS_READ(RTC_CONTROL); |
860 | tmp &= ~RTC_PIE; | 861 | tmp &= ~RTC_PIE; |
861 | tmp &= ~RTC_AIE; | 862 | tmp &= ~RTC_AIE; |
862 | tmp &= ~RTC_UIE; | 863 | tmp &= ~RTC_UIE; |
863 | CMOS_WRITE(tmp, RTC_CONTROL); | 864 | CMOS_WRITE(tmp, RTC_CONTROL); |
864 | CMOS_READ(RTC_INTR_FLAGS); | 865 | CMOS_READ(RTC_INTR_FLAGS); |
865 | } | 866 | } |
866 | if (rtc_status & RTC_TIMER_ON) { | 867 | if (rtc_status & RTC_TIMER_ON) { |
867 | rtc_status &= ~RTC_TIMER_ON; | 868 | rtc_status &= ~RTC_TIMER_ON; |
868 | del_timer(&rtc_irq_timer); | 869 | del_timer(&rtc_irq_timer); |
869 | } | 870 | } |
870 | rtc_status &= ~RTC_IS_OPEN; | 871 | rtc_status &= ~RTC_IS_OPEN; |
871 | spin_unlock(&rtc_task_lock); | 872 | spin_unlock(&rtc_task_lock); |
872 | spin_unlock_irq(&rtc_lock); | 873 | spin_unlock_irq(&rtc_lock); |
873 | return 0; | 874 | return 0; |
874 | #endif | 875 | #endif |
875 | } | 876 | } |
876 | EXPORT_SYMBOL(rtc_unregister); | 877 | EXPORT_SYMBOL(rtc_unregister); |
877 | 878 | ||
878 | int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) | 879 | int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) |
879 | { | 880 | { |
880 | #ifndef RTC_IRQ | 881 | #ifndef RTC_IRQ |
881 | return -EIO; | 882 | return -EIO; |
882 | #else | 883 | #else |
883 | unsigned long flags; | 884 | unsigned long flags; |
884 | if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET) | 885 | if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET) |
885 | return -EINVAL; | 886 | return -EINVAL; |
886 | spin_lock_irqsave(&rtc_task_lock, flags); | 887 | spin_lock_irqsave(&rtc_task_lock, flags); |
887 | if (rtc_callback != task) { | 888 | if (rtc_callback != task) { |
888 | spin_unlock_irqrestore(&rtc_task_lock, flags); | 889 | spin_unlock_irqrestore(&rtc_task_lock, flags); |
889 | return -ENXIO; | 890 | return -ENXIO; |
890 | } | 891 | } |
891 | spin_unlock_irqrestore(&rtc_task_lock, flags); | 892 | spin_unlock_irqrestore(&rtc_task_lock, flags); |
892 | return rtc_do_ioctl(cmd, arg, 1); | 893 | return rtc_do_ioctl(cmd, arg, 1); |
893 | #endif | 894 | #endif |
894 | } | 895 | } |
895 | EXPORT_SYMBOL(rtc_control); | 896 | EXPORT_SYMBOL(rtc_control); |
896 | 897 | ||
897 | /* | 898 | /* |
898 | * The various file operations we support. | 899 | * The various file operations we support. |
899 | */ | 900 | */ |
900 | 901 | ||
901 | static const struct file_operations rtc_fops = { | 902 | static const struct file_operations rtc_fops = { |
902 | .owner = THIS_MODULE, | 903 | .owner = THIS_MODULE, |
903 | .llseek = no_llseek, | 904 | .llseek = no_llseek, |
904 | .read = rtc_read, | 905 | .read = rtc_read, |
905 | #ifdef RTC_IRQ | 906 | #ifdef RTC_IRQ |
906 | .poll = rtc_poll, | 907 | .poll = rtc_poll, |
907 | #endif | 908 | #endif |
908 | .unlocked_ioctl = rtc_ioctl, | 909 | .unlocked_ioctl = rtc_ioctl, |
909 | .open = rtc_open, | 910 | .open = rtc_open, |
910 | .release = rtc_release, | 911 | .release = rtc_release, |
911 | .fasync = rtc_fasync, | 912 | .fasync = rtc_fasync, |
912 | }; | 913 | }; |
913 | 914 | ||
914 | static struct miscdevice rtc_dev = { | 915 | static struct miscdevice rtc_dev = { |
915 | .minor = RTC_MINOR, | 916 | .minor = RTC_MINOR, |
916 | .name = "rtc", | 917 | .name = "rtc", |
917 | .fops = &rtc_fops, | 918 | .fops = &rtc_fops, |
918 | }; | 919 | }; |
919 | 920 | ||
920 | #ifdef CONFIG_PROC_FS | 921 | #ifdef CONFIG_PROC_FS |
921 | static const struct file_operations rtc_proc_fops = { | 922 | static const struct file_operations rtc_proc_fops = { |
922 | .owner = THIS_MODULE, | 923 | .owner = THIS_MODULE, |
923 | .open = rtc_proc_open, | 924 | .open = rtc_proc_open, |
924 | .read = seq_read, | 925 | .read = seq_read, |
925 | .llseek = seq_lseek, | 926 | .llseek = seq_lseek, |
926 | .release = single_release, | 927 | .release = single_release, |
927 | }; | 928 | }; |
928 | #endif | 929 | #endif |
929 | 930 | ||
930 | static resource_size_t rtc_size; | 931 | static resource_size_t rtc_size; |
931 | 932 | ||
932 | static struct resource * __init rtc_request_region(resource_size_t size) | 933 | static struct resource * __init rtc_request_region(resource_size_t size) |
933 | { | 934 | { |
934 | struct resource *r; | 935 | struct resource *r; |
935 | 936 | ||
936 | if (RTC_IOMAPPED) | 937 | if (RTC_IOMAPPED) |
937 | r = request_region(RTC_PORT(0), size, "rtc"); | 938 | r = request_region(RTC_PORT(0), size, "rtc"); |
938 | else | 939 | else |
939 | r = request_mem_region(RTC_PORT(0), size, "rtc"); | 940 | r = request_mem_region(RTC_PORT(0), size, "rtc"); |
940 | 941 | ||
941 | if (r) | 942 | if (r) |
942 | rtc_size = size; | 943 | rtc_size = size; |
943 | 944 | ||
944 | return r; | 945 | return r; |
945 | } | 946 | } |
946 | 947 | ||
947 | static void rtc_release_region(void) | 948 | static void rtc_release_region(void) |
948 | { | 949 | { |
949 | if (RTC_IOMAPPED) | 950 | if (RTC_IOMAPPED) |
950 | release_region(RTC_PORT(0), rtc_size); | 951 | release_region(RTC_PORT(0), rtc_size); |
951 | else | 952 | else |
952 | release_mem_region(RTC_PORT(0), rtc_size); | 953 | release_mem_region(RTC_PORT(0), rtc_size); |
953 | } | 954 | } |
954 | 955 | ||
955 | static int __init rtc_init(void) | 956 | static int __init rtc_init(void) |
956 | { | 957 | { |
957 | #ifdef CONFIG_PROC_FS | 958 | #ifdef CONFIG_PROC_FS |
958 | struct proc_dir_entry *ent; | 959 | struct proc_dir_entry *ent; |
959 | #endif | 960 | #endif |
960 | #if defined(__alpha__) || defined(__mips__) | 961 | #if defined(__alpha__) || defined(__mips__) |
961 | unsigned int year, ctrl; | 962 | unsigned int year, ctrl; |
962 | char *guess = NULL; | 963 | char *guess = NULL; |
963 | #endif | 964 | #endif |
964 | #ifdef CONFIG_SPARC32 | 965 | #ifdef CONFIG_SPARC32 |
965 | struct device_node *ebus_dp; | 966 | struct device_node *ebus_dp; |
966 | struct of_device *op; | 967 | struct of_device *op; |
967 | #else | 968 | #else |
968 | void *r; | 969 | void *r; |
969 | #ifdef RTC_IRQ | 970 | #ifdef RTC_IRQ |
970 | irq_handler_t rtc_int_handler_ptr; | 971 | irq_handler_t rtc_int_handler_ptr; |
971 | #endif | 972 | #endif |
972 | #endif | 973 | #endif |
973 | 974 | ||
974 | #ifdef CONFIG_SPARC32 | 975 | #ifdef CONFIG_SPARC32 |
975 | for_each_node_by_name(ebus_dp, "ebus") { | 976 | for_each_node_by_name(ebus_dp, "ebus") { |
976 | struct device_node *dp; | 977 | struct device_node *dp; |
977 | for (dp = ebus_dp; dp; dp = dp->sibling) { | 978 | for (dp = ebus_dp; dp; dp = dp->sibling) { |
978 | if (!strcmp(dp->name, "rtc")) { | 979 | if (!strcmp(dp->name, "rtc")) { |
979 | op = of_find_device_by_node(dp); | 980 | op = of_find_device_by_node(dp); |
980 | if (op) { | 981 | if (op) { |
981 | rtc_port = op->resource[0].start; | 982 | rtc_port = op->resource[0].start; |
982 | rtc_irq = op->irqs[0]; | 983 | rtc_irq = op->irqs[0]; |
983 | goto found; | 984 | goto found; |
984 | } | 985 | } |
985 | } | 986 | } |
986 | } | 987 | } |
987 | } | 988 | } |
988 | rtc_has_irq = 0; | 989 | rtc_has_irq = 0; |
989 | printk(KERN_ERR "rtc_init: no PC rtc found\n"); | 990 | printk(KERN_ERR "rtc_init: no PC rtc found\n"); |
990 | return -EIO; | 991 | return -EIO; |
991 | 992 | ||
992 | found: | 993 | found: |
993 | if (!rtc_irq) { | 994 | if (!rtc_irq) { |
994 | rtc_has_irq = 0; | 995 | rtc_has_irq = 0; |
995 | goto no_irq; | 996 | goto no_irq; |
996 | } | 997 | } |
997 | 998 | ||
998 | /* | 999 | /* |
999 | * XXX Interrupt pin #7 in Espresso is shared between RTC and | 1000 | * XXX Interrupt pin #7 in Espresso is shared between RTC and |
1000 | * PCI Slot 2 INTA# (and some INTx# in Slot 1). | 1001 | * PCI Slot 2 INTA# (and some INTx# in Slot 1). |
1001 | */ | 1002 | */ |
1002 | if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", | 1003 | if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", |
1003 | (void *)&rtc_port)) { | 1004 | (void *)&rtc_port)) { |
1004 | rtc_has_irq = 0; | 1005 | rtc_has_irq = 0; |
1005 | printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); | 1006 | printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); |
1006 | return -EIO; | 1007 | return -EIO; |
1007 | } | 1008 | } |
1008 | no_irq: | 1009 | no_irq: |
1009 | #else | 1010 | #else |
1010 | r = rtc_request_region(RTC_IO_EXTENT); | 1011 | r = rtc_request_region(RTC_IO_EXTENT); |
1011 | 1012 | ||
1012 | /* | 1013 | /* |
1013 | * If we've already requested a smaller range (for example, because | 1014 | * If we've already requested a smaller range (for example, because |
1014 | * PNPBIOS or ACPI told us how the device is configured), the request | 1015 | * PNPBIOS or ACPI told us how the device is configured), the request |
1015 | * above might fail because it's too big. | 1016 | * above might fail because it's too big. |
1016 | * | 1017 | * |
1017 | * If so, request just the range we actually use. | 1018 | * If so, request just the range we actually use. |
1018 | */ | 1019 | */ |
1019 | if (!r) | 1020 | if (!r) |
1020 | r = rtc_request_region(RTC_IO_EXTENT_USED); | 1021 | r = rtc_request_region(RTC_IO_EXTENT_USED); |
1021 | if (!r) { | 1022 | if (!r) { |
1022 | #ifdef RTC_IRQ | 1023 | #ifdef RTC_IRQ |
1023 | rtc_has_irq = 0; | 1024 | rtc_has_irq = 0; |
1024 | #endif | 1025 | #endif |
1025 | printk(KERN_ERR "rtc: I/O resource %lx is not free.\n", | 1026 | printk(KERN_ERR "rtc: I/O resource %lx is not free.\n", |
1026 | (long)(RTC_PORT(0))); | 1027 | (long)(RTC_PORT(0))); |
1027 | return -EIO; | 1028 | return -EIO; |
1028 | } | 1029 | } |
1029 | 1030 | ||
1030 | #ifdef RTC_IRQ | 1031 | #ifdef RTC_IRQ |
1031 | if (is_hpet_enabled()) { | 1032 | if (is_hpet_enabled()) { |
1032 | int err; | 1033 | int err; |
1033 | 1034 | ||
1034 | rtc_int_handler_ptr = hpet_rtc_interrupt; | 1035 | rtc_int_handler_ptr = hpet_rtc_interrupt; |
1035 | err = hpet_register_irq_handler(rtc_interrupt); | 1036 | err = hpet_register_irq_handler(rtc_interrupt); |
1036 | if (err != 0) { | 1037 | if (err != 0) { |
1037 | printk(KERN_WARNING "hpet_register_irq_handler failed " | 1038 | printk(KERN_WARNING "hpet_register_irq_handler failed " |
1038 | "in rtc_init()."); | 1039 | "in rtc_init()."); |
1039 | return err; | 1040 | return err; |
1040 | } | 1041 | } |
1041 | } else { | 1042 | } else { |
1042 | rtc_int_handler_ptr = rtc_interrupt; | 1043 | rtc_int_handler_ptr = rtc_interrupt; |
1043 | } | 1044 | } |
1044 | 1045 | ||
1045 | if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, | 1046 | if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, |
1046 | "rtc", NULL)) { | 1047 | "rtc", NULL)) { |
1047 | /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ | 1048 | /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ |
1048 | rtc_has_irq = 0; | 1049 | rtc_has_irq = 0; |
1049 | printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); | 1050 | printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); |
1050 | rtc_release_region(); | 1051 | rtc_release_region(); |
1051 | 1052 | ||
1052 | return -EIO; | 1053 | return -EIO; |
1053 | } | 1054 | } |
1054 | hpet_rtc_timer_init(); | 1055 | hpet_rtc_timer_init(); |
1055 | 1056 | ||
1056 | #endif | 1057 | #endif |
1057 | 1058 | ||
1058 | #endif /* CONFIG_SPARC32 vs. others */ | 1059 | #endif /* CONFIG_SPARC32 vs. others */ |
1059 | 1060 | ||
1060 | if (misc_register(&rtc_dev)) { | 1061 | if (misc_register(&rtc_dev)) { |
1061 | #ifdef RTC_IRQ | 1062 | #ifdef RTC_IRQ |
1062 | free_irq(RTC_IRQ, NULL); | 1063 | free_irq(RTC_IRQ, NULL); |
1063 | hpet_unregister_irq_handler(rtc_interrupt); | 1064 | hpet_unregister_irq_handler(rtc_interrupt); |
1064 | rtc_has_irq = 0; | 1065 | rtc_has_irq = 0; |
1065 | #endif | 1066 | #endif |
1066 | rtc_release_region(); | 1067 | rtc_release_region(); |
1067 | return -ENODEV; | 1068 | return -ENODEV; |
1068 | } | 1069 | } |
1069 | 1070 | ||
1070 | #ifdef CONFIG_PROC_FS | 1071 | #ifdef CONFIG_PROC_FS |
1071 | ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops); | 1072 | ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops); |
1072 | if (!ent) | 1073 | if (!ent) |
1073 | printk(KERN_WARNING "rtc: Failed to register with procfs.\n"); | 1074 | printk(KERN_WARNING "rtc: Failed to register with procfs.\n"); |
1074 | #endif | 1075 | #endif |
1075 | 1076 | ||
1076 | #if defined(__alpha__) || defined(__mips__) | 1077 | #if defined(__alpha__) || defined(__mips__) |
1077 | rtc_freq = HZ; | 1078 | rtc_freq = HZ; |
1078 | 1079 | ||
1079 | /* Each operating system on an Alpha uses its own epoch. | 1080 | /* Each operating system on an Alpha uses its own epoch. |
1080 | Let's try to guess which one we are using now. */ | 1081 | Let's try to guess which one we are using now. */ |
1081 | 1082 | ||
1082 | if (rtc_is_updating() != 0) | 1083 | if (rtc_is_updating() != 0) |
1083 | msleep(20); | 1084 | msleep(20); |
1084 | 1085 | ||
1085 | spin_lock_irq(&rtc_lock); | 1086 | spin_lock_irq(&rtc_lock); |
1086 | year = CMOS_READ(RTC_YEAR); | 1087 | year = CMOS_READ(RTC_YEAR); |
1087 | ctrl = CMOS_READ(RTC_CONTROL); | 1088 | ctrl = CMOS_READ(RTC_CONTROL); |
1088 | spin_unlock_irq(&rtc_lock); | 1089 | spin_unlock_irq(&rtc_lock); |
1089 | 1090 | ||
1090 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | 1091 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) |
1091 | year = bcd2bin(year); /* This should never happen... */ | 1092 | year = bcd2bin(year); /* This should never happen... */ |
1092 | 1093 | ||
1093 | if (year < 20) { | 1094 | if (year < 20) { |
1094 | epoch = 2000; | 1095 | epoch = 2000; |
1095 | guess = "SRM (post-2000)"; | 1096 | guess = "SRM (post-2000)"; |
1096 | } else if (year >= 20 && year < 48) { | 1097 | } else if (year >= 20 && year < 48) { |
1097 | epoch = 1980; | 1098 | epoch = 1980; |
1098 | guess = "ARC console"; | 1099 | guess = "ARC console"; |
1099 | } else if (year >= 48 && year < 72) { | 1100 | } else if (year >= 48 && year < 72) { |
1100 | epoch = 1952; | 1101 | epoch = 1952; |
1101 | guess = "Digital UNIX"; | 1102 | guess = "Digital UNIX"; |
1102 | #if defined(__mips__) | 1103 | #if defined(__mips__) |
1103 | } else if (year >= 72 && year < 74) { | 1104 | } else if (year >= 72 && year < 74) { |
1104 | epoch = 2000; | 1105 | epoch = 2000; |
1105 | guess = "Digital DECstation"; | 1106 | guess = "Digital DECstation"; |
1106 | #else | 1107 | #else |
1107 | } else if (year >= 70) { | 1108 | } else if (year >= 70) { |
1108 | epoch = 1900; | 1109 | epoch = 1900; |
1109 | guess = "Standard PC (1900)"; | 1110 | guess = "Standard PC (1900)"; |
1110 | #endif | 1111 | #endif |
1111 | } | 1112 | } |
1112 | if (guess) | 1113 | if (guess) |
1113 | printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", | 1114 | printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", |
1114 | guess, epoch); | 1115 | guess, epoch); |
1115 | #endif | 1116 | #endif |
1116 | #ifdef RTC_IRQ | 1117 | #ifdef RTC_IRQ |
1117 | if (rtc_has_irq == 0) | 1118 | if (rtc_has_irq == 0) |
1118 | goto no_irq2; | 1119 | goto no_irq2; |
1119 | 1120 | ||
1120 | spin_lock_irq(&rtc_lock); | 1121 | spin_lock_irq(&rtc_lock); |
1121 | rtc_freq = 1024; | 1122 | rtc_freq = 1024; |
1122 | if (!hpet_set_periodic_freq(rtc_freq)) { | 1123 | if (!hpet_set_periodic_freq(rtc_freq)) { |
1123 | /* | 1124 | /* |
1124 | * Initialize periodic frequency to CMOS reset default, | 1125 | * Initialize periodic frequency to CMOS reset default, |
1125 | * which is 1024Hz | 1126 | * which is 1024Hz |
1126 | */ | 1127 | */ |
1127 | CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), | 1128 | CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), |
1128 | RTC_FREQ_SELECT); | 1129 | RTC_FREQ_SELECT); |
1129 | } | 1130 | } |
1130 | spin_unlock_irq(&rtc_lock); | 1131 | spin_unlock_irq(&rtc_lock); |
1131 | no_irq2: | 1132 | no_irq2: |
1132 | #endif | 1133 | #endif |
1133 | 1134 | ||
1134 | (void) init_sysctl(); | 1135 | (void) init_sysctl(); |
1135 | 1136 | ||
1136 | printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); | 1137 | printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); |
1137 | 1138 | ||
1138 | return 0; | 1139 | return 0; |
1139 | } | 1140 | } |
1140 | 1141 | ||
1141 | static void __exit rtc_exit(void) | 1142 | static void __exit rtc_exit(void) |
1142 | { | 1143 | { |
1143 | cleanup_sysctl(); | 1144 | cleanup_sysctl(); |
1144 | remove_proc_entry("driver/rtc", NULL); | 1145 | remove_proc_entry("driver/rtc", NULL); |
1145 | misc_deregister(&rtc_dev); | 1146 | misc_deregister(&rtc_dev); |
1146 | 1147 | ||
1147 | #ifdef CONFIG_SPARC32 | 1148 | #ifdef CONFIG_SPARC32 |
1148 | if (rtc_has_irq) | 1149 | if (rtc_has_irq) |
1149 | free_irq(rtc_irq, &rtc_port); | 1150 | free_irq(rtc_irq, &rtc_port); |
1150 | #else | 1151 | #else |
1151 | rtc_release_region(); | 1152 | rtc_release_region(); |
1152 | #ifdef RTC_IRQ | 1153 | #ifdef RTC_IRQ |
1153 | if (rtc_has_irq) { | 1154 | if (rtc_has_irq) { |
1154 | free_irq(RTC_IRQ, NULL); | 1155 | free_irq(RTC_IRQ, NULL); |
1155 | hpet_unregister_irq_handler(hpet_rtc_interrupt); | 1156 | hpet_unregister_irq_handler(hpet_rtc_interrupt); |
1156 | } | 1157 | } |
1157 | #endif | 1158 | #endif |
1158 | #endif /* CONFIG_SPARC32 */ | 1159 | #endif /* CONFIG_SPARC32 */ |
1159 | } | 1160 | } |
1160 | 1161 | ||
1161 | module_init(rtc_init); | 1162 | module_init(rtc_init); |
1162 | module_exit(rtc_exit); | 1163 | module_exit(rtc_exit); |
1163 | 1164 | ||
1164 | #ifdef RTC_IRQ | 1165 | #ifdef RTC_IRQ |
1165 | /* | 1166 | /* |
1166 | * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. | 1167 | * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. |
1167 | * (usually during an IDE disk interrupt, with IRQ unmasking off) | 1168 | * (usually during an IDE disk interrupt, with IRQ unmasking off) |
1168 | * Since the interrupt handler doesn't get called, the IRQ status | 1169 | * Since the interrupt handler doesn't get called, the IRQ status |
1169 | * byte doesn't get read, and the RTC stops generating interrupts. | 1170 | * byte doesn't get read, and the RTC stops generating interrupts. |
1170 | * A timer is set, and will call this function if/when that happens. | 1171 | * A timer is set, and will call this function if/when that happens. |
1171 | * To get it out of this stalled state, we just read the status. | 1172 | * To get it out of this stalled state, we just read the status. |
1172 | * At least a jiffy of interrupts (rtc_freq/HZ) will have been lost. | 1173 | * At least a jiffy of interrupts (rtc_freq/HZ) will have been lost. |
1173 | * (You *really* shouldn't be trying to use a non-realtime system | 1174 | * (You *really* shouldn't be trying to use a non-realtime system |
1174 | * for something that requires a steady > 1KHz signal anyways.) | 1175 | * for something that requires a steady > 1KHz signal anyways.) |
1175 | */ | 1176 | */ |
1176 | 1177 | ||
1177 | static void rtc_dropped_irq(unsigned long data) | 1178 | static void rtc_dropped_irq(unsigned long data) |
1178 | { | 1179 | { |
1179 | unsigned long freq; | 1180 | unsigned long freq; |
1180 | 1181 | ||
1181 | spin_lock_irq(&rtc_lock); | 1182 | spin_lock_irq(&rtc_lock); |
1182 | 1183 | ||
1183 | if (hpet_rtc_dropped_irq()) { | 1184 | if (hpet_rtc_dropped_irq()) { |
1184 | spin_unlock_irq(&rtc_lock); | 1185 | spin_unlock_irq(&rtc_lock); |
1185 | return; | 1186 | return; |
1186 | } | 1187 | } |
1187 | 1188 | ||
1188 | /* Just in case someone disabled the timer from behind our back... */ | 1189 | /* Just in case someone disabled the timer from behind our back... */ |
1189 | if (rtc_status & RTC_TIMER_ON) | 1190 | if (rtc_status & RTC_TIMER_ON) |
1190 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); | 1191 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); |
1191 | 1192 | ||
1192 | rtc_irq_data += ((rtc_freq/HZ)<<8); | 1193 | rtc_irq_data += ((rtc_freq/HZ)<<8); |
1193 | rtc_irq_data &= ~0xff; | 1194 | rtc_irq_data &= ~0xff; |
1194 | rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ | 1195 | rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ |
1195 | 1196 | ||
1196 | freq = rtc_freq; | 1197 | freq = rtc_freq; |
1197 | 1198 | ||
1198 | spin_unlock_irq(&rtc_lock); | 1199 | spin_unlock_irq(&rtc_lock); |
1199 | 1200 | ||
1200 | if (printk_ratelimit()) { | 1201 | if (printk_ratelimit()) { |
1201 | printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", | 1202 | printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", |
1202 | freq); | 1203 | freq); |
1203 | } | 1204 | } |
1204 | 1205 | ||
1205 | /* Now we have new data */ | 1206 | /* Now we have new data */ |
1206 | wake_up_interruptible(&rtc_wait); | 1207 | wake_up_interruptible(&rtc_wait); |
1207 | 1208 | ||
1208 | kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); | 1209 | kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); |
1209 | } | 1210 | } |
1210 | #endif | 1211 | #endif |
1211 | 1212 | ||
1212 | #ifdef CONFIG_PROC_FS | 1213 | #ifdef CONFIG_PROC_FS |
1213 | /* | 1214 | /* |
1214 | * Info exported via "/proc/driver/rtc". | 1215 | * Info exported via "/proc/driver/rtc". |
1215 | */ | 1216 | */ |
1216 | 1217 | ||
1217 | static int rtc_proc_show(struct seq_file *seq, void *v) | 1218 | static int rtc_proc_show(struct seq_file *seq, void *v) |
1218 | { | 1219 | { |
1219 | #define YN(bit) ((ctrl & bit) ? "yes" : "no") | 1220 | #define YN(bit) ((ctrl & bit) ? "yes" : "no") |
1220 | #define NY(bit) ((ctrl & bit) ? "no" : "yes") | 1221 | #define NY(bit) ((ctrl & bit) ? "no" : "yes") |
1221 | struct rtc_time tm; | 1222 | struct rtc_time tm; |
1222 | unsigned char batt, ctrl; | 1223 | unsigned char batt, ctrl; |
1223 | unsigned long freq; | 1224 | unsigned long freq; |
1224 | 1225 | ||
1225 | spin_lock_irq(&rtc_lock); | 1226 | spin_lock_irq(&rtc_lock); |
1226 | batt = CMOS_READ(RTC_VALID) & RTC_VRT; | 1227 | batt = CMOS_READ(RTC_VALID) & RTC_VRT; |
1227 | ctrl = CMOS_READ(RTC_CONTROL); | 1228 | ctrl = CMOS_READ(RTC_CONTROL); |
1228 | freq = rtc_freq; | 1229 | freq = rtc_freq; |
1229 | spin_unlock_irq(&rtc_lock); | 1230 | spin_unlock_irq(&rtc_lock); |
1230 | 1231 | ||
1231 | 1232 | ||
1232 | rtc_get_rtc_time(&tm); | 1233 | rtc_get_rtc_time(&tm); |
1233 | 1234 | ||
1234 | /* | 1235 | /* |
1235 | * There is no way to tell if the luser has the RTC set for local | 1236 | * There is no way to tell if the luser has the RTC set for local |
1236 | * time or for Universal Standard Time (GMT). Probably local though. | 1237 | * time or for Universal Standard Time (GMT). Probably local though. |
1237 | */ | 1238 | */ |
1238 | seq_printf(seq, | 1239 | seq_printf(seq, |
1239 | "rtc_time\t: %02d:%02d:%02d\n" | 1240 | "rtc_time\t: %02d:%02d:%02d\n" |
1240 | "rtc_date\t: %04d-%02d-%02d\n" | 1241 | "rtc_date\t: %04d-%02d-%02d\n" |
1241 | "rtc_epoch\t: %04lu\n", | 1242 | "rtc_epoch\t: %04lu\n", |
1242 | tm.tm_hour, tm.tm_min, tm.tm_sec, | 1243 | tm.tm_hour, tm.tm_min, tm.tm_sec, |
1243 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); | 1244 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); |
1244 | 1245 | ||
1245 | get_rtc_alm_time(&tm); | 1246 | get_rtc_alm_time(&tm); |
1246 | 1247 | ||
1247 | /* | 1248 | /* |
1248 | * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will | 1249 | * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will |
1249 | * match any value for that particular field. Values that are | 1250 | * match any value for that particular field. Values that are |
1250 | * greater than a valid time, but less than 0xc0 shouldn't appear. | 1251 | * greater than a valid time, but less than 0xc0 shouldn't appear. |
1251 | */ | 1252 | */ |
1252 | seq_puts(seq, "alarm\t\t: "); | 1253 | seq_puts(seq, "alarm\t\t: "); |
1253 | if (tm.tm_hour <= 24) | 1254 | if (tm.tm_hour <= 24) |
1254 | seq_printf(seq, "%02d:", tm.tm_hour); | 1255 | seq_printf(seq, "%02d:", tm.tm_hour); |
1255 | else | 1256 | else |
1256 | seq_puts(seq, "**:"); | 1257 | seq_puts(seq, "**:"); |
1257 | 1258 | ||
1258 | if (tm.tm_min <= 59) | 1259 | if (tm.tm_min <= 59) |
1259 | seq_printf(seq, "%02d:", tm.tm_min); | 1260 | seq_printf(seq, "%02d:", tm.tm_min); |
1260 | else | 1261 | else |
1261 | seq_puts(seq, "**:"); | 1262 | seq_puts(seq, "**:"); |
1262 | 1263 | ||
1263 | if (tm.tm_sec <= 59) | 1264 | if (tm.tm_sec <= 59) |
1264 | seq_printf(seq, "%02d\n", tm.tm_sec); | 1265 | seq_printf(seq, "%02d\n", tm.tm_sec); |
1265 | else | 1266 | else |
1266 | seq_puts(seq, "**\n"); | 1267 | seq_puts(seq, "**\n"); |
1267 | 1268 | ||
1268 | seq_printf(seq, | 1269 | seq_printf(seq, |
1269 | "DST_enable\t: %s\n" | 1270 | "DST_enable\t: %s\n" |
1270 | "BCD\t\t: %s\n" | 1271 | "BCD\t\t: %s\n" |
1271 | "24hr\t\t: %s\n" | 1272 | "24hr\t\t: %s\n" |
1272 | "square_wave\t: %s\n" | 1273 | "square_wave\t: %s\n" |
1273 | "alarm_IRQ\t: %s\n" | 1274 | "alarm_IRQ\t: %s\n" |
1274 | "update_IRQ\t: %s\n" | 1275 | "update_IRQ\t: %s\n" |
1275 | "periodic_IRQ\t: %s\n" | 1276 | "periodic_IRQ\t: %s\n" |
1276 | "periodic_freq\t: %ld\n" | 1277 | "periodic_freq\t: %ld\n" |
1277 | "batt_status\t: %s\n", | 1278 | "batt_status\t: %s\n", |
1278 | YN(RTC_DST_EN), | 1279 | YN(RTC_DST_EN), |
1279 | NY(RTC_DM_BINARY), | 1280 | NY(RTC_DM_BINARY), |
1280 | YN(RTC_24H), | 1281 | YN(RTC_24H), |
1281 | YN(RTC_SQWE), | 1282 | YN(RTC_SQWE), |
1282 | YN(RTC_AIE), | 1283 | YN(RTC_AIE), |
1283 | YN(RTC_UIE), | 1284 | YN(RTC_UIE), |
1284 | YN(RTC_PIE), | 1285 | YN(RTC_PIE), |
1285 | freq, | 1286 | freq, |
1286 | batt ? "okay" : "dead"); | 1287 | batt ? "okay" : "dead"); |
1287 | 1288 | ||
1288 | return 0; | 1289 | return 0; |
1289 | #undef YN | 1290 | #undef YN |
1290 | #undef NY | 1291 | #undef NY |
1291 | } | 1292 | } |
1292 | 1293 | ||
1293 | static int rtc_proc_open(struct inode *inode, struct file *file) | 1294 | static int rtc_proc_open(struct inode *inode, struct file *file) |
1294 | { | 1295 | { |
1295 | return single_open(file, rtc_proc_show, NULL); | 1296 | return single_open(file, rtc_proc_show, NULL); |
1296 | } | 1297 | } |
1297 | #endif | 1298 | #endif |
1298 | 1299 | ||
1299 | static void rtc_get_rtc_time(struct rtc_time *rtc_tm) | 1300 | static void rtc_get_rtc_time(struct rtc_time *rtc_tm) |
1300 | { | 1301 | { |
1301 | unsigned long uip_watchdog = jiffies, flags; | 1302 | unsigned long uip_watchdog = jiffies, flags; |
1302 | unsigned char ctrl; | 1303 | unsigned char ctrl; |
1303 | #ifdef CONFIG_MACH_DECSTATION | 1304 | #ifdef CONFIG_MACH_DECSTATION |
1304 | unsigned int real_year; | 1305 | unsigned int real_year; |
1305 | #endif | 1306 | #endif |
1306 | 1307 | ||
1307 | /* | 1308 | /* |
1308 | * read RTC once any update in progress is done. The update | 1309 | * read RTC once any update in progress is done. The update |
1309 | * can take just over 2ms. We wait 20ms. There is no need to | 1310 | * can take just over 2ms. We wait 20ms. There is no need to |
1310 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. | 1311 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. |
1311 | * If you need to know *exactly* when a second has started, enable | 1312 | * If you need to know *exactly* when a second has started, enable |
1312 | * periodic update complete interrupts, (via ioctl) and then | 1313 | * periodic update complete interrupts, (via ioctl) and then |
1313 | * immediately read /dev/rtc which will block until you get the IRQ. | 1314 | * immediately read /dev/rtc which will block until you get the IRQ. |
1314 | * Once the read clears, read the RTC time (again via ioctl). Easy. | 1315 | * Once the read clears, read the RTC time (again via ioctl). Easy. |
1315 | */ | 1316 | */ |
1316 | 1317 | ||
1317 | while (rtc_is_updating() != 0 && | 1318 | while (rtc_is_updating() != 0 && |
1318 | time_before(jiffies, uip_watchdog + 2*HZ/100)) | 1319 | time_before(jiffies, uip_watchdog + 2*HZ/100)) |
1319 | cpu_relax(); | 1320 | cpu_relax(); |
1320 | 1321 | ||
1321 | /* | 1322 | /* |
1322 | * Only the values that we read from the RTC are set. We leave | 1323 | * Only the values that we read from the RTC are set. We leave |
1323 | * tm_wday, tm_yday and tm_isdst untouched. Note that while the | 1324 | * tm_wday, tm_yday and tm_isdst untouched. Note that while the |
1324 | * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is | 1325 | * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is |
1325 | * only updated by the RTC when initially set to a non-zero value. | 1326 | * only updated by the RTC when initially set to a non-zero value. |
1326 | */ | 1327 | */ |
1327 | spin_lock_irqsave(&rtc_lock, flags); | 1328 | spin_lock_irqsave(&rtc_lock, flags); |
1328 | rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); | 1329 | rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); |
1329 | rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); | 1330 | rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); |
1330 | rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); | 1331 | rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); |
1331 | rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); | 1332 | rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); |
1332 | rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); | 1333 | rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); |
1333 | rtc_tm->tm_year = CMOS_READ(RTC_YEAR); | 1334 | rtc_tm->tm_year = CMOS_READ(RTC_YEAR); |
1334 | /* Only set from 2.6.16 onwards */ | 1335 | /* Only set from 2.6.16 onwards */ |
1335 | rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); | 1336 | rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); |
1336 | 1337 | ||
1337 | #ifdef CONFIG_MACH_DECSTATION | 1338 | #ifdef CONFIG_MACH_DECSTATION |
1338 | real_year = CMOS_READ(RTC_DEC_YEAR); | 1339 | real_year = CMOS_READ(RTC_DEC_YEAR); |
1339 | #endif | 1340 | #endif |
1340 | ctrl = CMOS_READ(RTC_CONTROL); | 1341 | ctrl = CMOS_READ(RTC_CONTROL); |
1341 | spin_unlock_irqrestore(&rtc_lock, flags); | 1342 | spin_unlock_irqrestore(&rtc_lock, flags); |
1342 | 1343 | ||
1343 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | 1344 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { |
1344 | rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); | 1345 | rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); |
1345 | rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); | 1346 | rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); |
1346 | rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); | 1347 | rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); |
1347 | rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); | 1348 | rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); |
1348 | rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); | 1349 | rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); |
1349 | rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); | 1350 | rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); |
1350 | rtc_tm->tm_wday = bcd2bin(rtc_tm->tm_wday); | 1351 | rtc_tm->tm_wday = bcd2bin(rtc_tm->tm_wday); |
1351 | } | 1352 | } |
1352 | 1353 | ||
1353 | #ifdef CONFIG_MACH_DECSTATION | 1354 | #ifdef CONFIG_MACH_DECSTATION |
1354 | rtc_tm->tm_year += real_year - 72; | 1355 | rtc_tm->tm_year += real_year - 72; |
1355 | #endif | 1356 | #endif |
1356 | 1357 | ||
1357 | /* | 1358 | /* |
1358 | * Account for differences between how the RTC uses the values | 1359 | * Account for differences between how the RTC uses the values |
1359 | * and how they are defined in a struct rtc_time; | 1360 | * and how they are defined in a struct rtc_time; |
1360 | */ | 1361 | */ |
1361 | rtc_tm->tm_year += epoch - 1900; | 1362 | rtc_tm->tm_year += epoch - 1900; |
1362 | if (rtc_tm->tm_year <= 69) | 1363 | if (rtc_tm->tm_year <= 69) |
1363 | rtc_tm->tm_year += 100; | 1364 | rtc_tm->tm_year += 100; |
1364 | 1365 | ||
1365 | rtc_tm->tm_mon--; | 1366 | rtc_tm->tm_mon--; |
1366 | } | 1367 | } |
1367 | 1368 | ||
1368 | static void get_rtc_alm_time(struct rtc_time *alm_tm) | 1369 | static void get_rtc_alm_time(struct rtc_time *alm_tm) |
1369 | { | 1370 | { |
1370 | unsigned char ctrl; | 1371 | unsigned char ctrl; |
1371 | 1372 | ||
1372 | /* | 1373 | /* |
1373 | * Only the values that we read from the RTC are set. That | 1374 | * Only the values that we read from the RTC are set. That |
1374 | * means only tm_hour, tm_min, and tm_sec. | 1375 | * means only tm_hour, tm_min, and tm_sec. |
1375 | */ | 1376 | */ |
1376 | spin_lock_irq(&rtc_lock); | 1377 | spin_lock_irq(&rtc_lock); |
1377 | alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM); | 1378 | alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM); |
1378 | alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM); | 1379 | alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM); |
1379 | alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM); | 1380 | alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM); |
1380 | ctrl = CMOS_READ(RTC_CONTROL); | 1381 | ctrl = CMOS_READ(RTC_CONTROL); |
1381 | spin_unlock_irq(&rtc_lock); | 1382 | spin_unlock_irq(&rtc_lock); |
1382 | 1383 | ||
1383 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | 1384 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { |
1384 | alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); | 1385 | alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); |
1385 | alm_tm->tm_min = bcd2bin(alm_tm->tm_min); | 1386 | alm_tm->tm_min = bcd2bin(alm_tm->tm_min); |
1386 | alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); | 1387 | alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); |
1387 | } | 1388 | } |
1388 | } | 1389 | } |
1389 | 1390 | ||
1390 | #ifdef RTC_IRQ | 1391 | #ifdef RTC_IRQ |
1391 | /* | 1392 | /* |
1392 | * Used to disable/enable interrupts for any one of UIE, AIE, PIE. | 1393 | * Used to disable/enable interrupts for any one of UIE, AIE, PIE. |
1393 | * Rumour has it that if you frob the interrupt enable/disable | 1394 | * Rumour has it that if you frob the interrupt enable/disable |
1394 | * bits in RTC_CONTROL, you should read RTC_INTR_FLAGS, to | 1395 | * bits in RTC_CONTROL, you should read RTC_INTR_FLAGS, to |
1395 | * ensure you actually start getting interrupts. Probably for | 1396 | * ensure you actually start getting interrupts. Probably for |
1396 | * compatibility with older/broken chipset RTC implementations. | 1397 | * compatibility with older/broken chipset RTC implementations. |
1397 | * We also clear out any old irq data after an ioctl() that | 1398 | * We also clear out any old irq data after an ioctl() that |
1398 | * meddles with the interrupt enable/disable bits. | 1399 | * meddles with the interrupt enable/disable bits. |
1399 | */ | 1400 | */ |
1400 | 1401 | ||
1401 | static void mask_rtc_irq_bit_locked(unsigned char bit) | 1402 | static void mask_rtc_irq_bit_locked(unsigned char bit) |
1402 | { | 1403 | { |
1403 | unsigned char val; | 1404 | unsigned char val; |
1404 | 1405 | ||
1405 | if (hpet_mask_rtc_irq_bit(bit)) | 1406 | if (hpet_mask_rtc_irq_bit(bit)) |
1406 | return; | 1407 | return; |
1407 | val = CMOS_READ(RTC_CONTROL); | 1408 | val = CMOS_READ(RTC_CONTROL); |
1408 | val &= ~bit; | 1409 | val &= ~bit; |
1409 | CMOS_WRITE(val, RTC_CONTROL); | 1410 | CMOS_WRITE(val, RTC_CONTROL); |
1410 | CMOS_READ(RTC_INTR_FLAGS); | 1411 | CMOS_READ(RTC_INTR_FLAGS); |
1411 | 1412 | ||
1412 | rtc_irq_data = 0; | 1413 | rtc_irq_data = 0; |
1413 | } | 1414 | } |
1414 | 1415 | ||
1415 | static void set_rtc_irq_bit_locked(unsigned char bit) | 1416 | static void set_rtc_irq_bit_locked(unsigned char bit) |
1416 | { | 1417 | { |
1417 | unsigned char val; | 1418 | unsigned char val; |
1418 | 1419 | ||
1419 | if (hpet_set_rtc_irq_bit(bit)) | 1420 | if (hpet_set_rtc_irq_bit(bit)) |
1420 | return; | 1421 | return; |
1421 | val = CMOS_READ(RTC_CONTROL); | 1422 | val = CMOS_READ(RTC_CONTROL); |
1422 | val |= bit; | 1423 | val |= bit; |
1423 | CMOS_WRITE(val, RTC_CONTROL); | 1424 | CMOS_WRITE(val, RTC_CONTROL); |
1424 | CMOS_READ(RTC_INTR_FLAGS); | 1425 | CMOS_READ(RTC_INTR_FLAGS); |
1425 | 1426 | ||
1426 | rtc_irq_data = 0; | 1427 | rtc_irq_data = 0; |
1427 | } | 1428 | } |
1428 | #endif | 1429 | #endif |
1429 | 1430 | ||
1430 | MODULE_AUTHOR("Paul Gortmaker"); | 1431 | MODULE_AUTHOR("Paul Gortmaker"); |
1431 | MODULE_LICENSE("GPL"); | 1432 | MODULE_LICENSE("GPL"); |
1432 | MODULE_ALIAS_MISCDEV(RTC_MINOR); | 1433 | MODULE_ALIAS_MISCDEV(RTC_MINOR); |
1433 | 1434 |
drivers/char/sonypi.c
1 | /* | 1 | /* |
2 | * Sony Programmable I/O Control Device driver for VAIO | 2 | * Sony Programmable I/O Control Device driver for VAIO |
3 | * | 3 | * |
4 | * Copyright (C) 2007 Mattia Dongili <malattia@linux.it> | 4 | * Copyright (C) 2007 Mattia Dongili <malattia@linux.it> |
5 | * | 5 | * |
6 | * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net> | 6 | * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net> |
7 | * | 7 | * |
8 | * Copyright (C) 2005 Narayanan R S <nars@kadamba.org> | 8 | * Copyright (C) 2005 Narayanan R S <nars@kadamba.org> |
9 | * | 9 | * |
10 | * Copyright (C) 2001-2002 Alcรดve <www.alcove.com> | 10 | * Copyright (C) 2001-2002 Alcรดve <www.alcove.com> |
11 | * | 11 | * |
12 | * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> | 12 | * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> |
13 | * | 13 | * |
14 | * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> | 14 | * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> |
15 | * | 15 | * |
16 | * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp> | 16 | * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp> |
17 | * | 17 | * |
18 | * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> | 18 | * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> |
19 | * | 19 | * |
20 | * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. | 20 | * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. |
21 | * | 21 | * |
22 | * This program is free software; you can redistribute it and/or modify | 22 | * This program is free software; you can redistribute it and/or modify |
23 | * it under the terms of the GNU General Public License as published by | 23 | * it under the terms of the GNU General Public License as published by |
24 | * the Free Software Foundation; either version 2 of the License, or | 24 | * the Free Software Foundation; either version 2 of the License, or |
25 | * (at your option) any later version. | 25 | * (at your option) any later version. |
26 | * | 26 | * |
27 | * This program is distributed in the hope that it will be useful, | 27 | * This program is distributed in the hope that it will be useful, |
28 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 28 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
29 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 29 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
30 | * GNU General Public License for more details. | 30 | * GNU General Public License for more details. |
31 | * | 31 | * |
32 | * You should have received a copy of the GNU General Public License | 32 | * You should have received a copy of the GNU General Public License |
33 | * along with this program; if not, write to the Free Software | 33 | * along with this program; if not, write to the Free Software |
34 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 34 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
35 | * | 35 | * |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <linux/module.h> | 38 | #include <linux/module.h> |
39 | #include <linux/sched.h> | ||
39 | #include <linux/input.h> | 40 | #include <linux/input.h> |
40 | #include <linux/pci.h> | 41 | #include <linux/pci.h> |
41 | #include <linux/init.h> | 42 | #include <linux/init.h> |
42 | #include <linux/interrupt.h> | 43 | #include <linux/interrupt.h> |
43 | #include <linux/miscdevice.h> | 44 | #include <linux/miscdevice.h> |
44 | #include <linux/poll.h> | 45 | #include <linux/poll.h> |
45 | #include <linux/delay.h> | 46 | #include <linux/delay.h> |
46 | #include <linux/wait.h> | 47 | #include <linux/wait.h> |
47 | #include <linux/acpi.h> | 48 | #include <linux/acpi.h> |
48 | #include <linux/dmi.h> | 49 | #include <linux/dmi.h> |
49 | #include <linux/err.h> | 50 | #include <linux/err.h> |
50 | #include <linux/kfifo.h> | 51 | #include <linux/kfifo.h> |
51 | #include <linux/platform_device.h> | 52 | #include <linux/platform_device.h> |
52 | #include <linux/smp_lock.h> | 53 | #include <linux/smp_lock.h> |
53 | 54 | ||
54 | #include <asm/uaccess.h> | 55 | #include <asm/uaccess.h> |
55 | #include <asm/io.h> | 56 | #include <asm/io.h> |
56 | #include <asm/system.h> | 57 | #include <asm/system.h> |
57 | 58 | ||
58 | #include <linux/sonypi.h> | 59 | #include <linux/sonypi.h> |
59 | 60 | ||
60 | #define SONYPI_DRIVER_VERSION "1.26" | 61 | #define SONYPI_DRIVER_VERSION "1.26" |
61 | 62 | ||
62 | MODULE_AUTHOR("Stelian Pop <stelian@popies.net>"); | 63 | MODULE_AUTHOR("Stelian Pop <stelian@popies.net>"); |
63 | MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver"); | 64 | MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver"); |
64 | MODULE_LICENSE("GPL"); | 65 | MODULE_LICENSE("GPL"); |
65 | MODULE_VERSION(SONYPI_DRIVER_VERSION); | 66 | MODULE_VERSION(SONYPI_DRIVER_VERSION); |
66 | 67 | ||
67 | static int minor = -1; | 68 | static int minor = -1; |
68 | module_param(minor, int, 0); | 69 | module_param(minor, int, 0); |
69 | MODULE_PARM_DESC(minor, | 70 | MODULE_PARM_DESC(minor, |
70 | "minor number of the misc device, default is -1 (automatic)"); | 71 | "minor number of the misc device, default is -1 (automatic)"); |
71 | 72 | ||
72 | static int verbose; /* = 0 */ | 73 | static int verbose; /* = 0 */ |
73 | module_param(verbose, int, 0644); | 74 | module_param(verbose, int, 0644); |
74 | MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)"); | 75 | MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)"); |
75 | 76 | ||
76 | static int fnkeyinit; /* = 0 */ | 77 | static int fnkeyinit; /* = 0 */ |
77 | module_param(fnkeyinit, int, 0444); | 78 | module_param(fnkeyinit, int, 0444); |
78 | MODULE_PARM_DESC(fnkeyinit, | 79 | MODULE_PARM_DESC(fnkeyinit, |
79 | "set this if your Fn keys do not generate any event"); | 80 | "set this if your Fn keys do not generate any event"); |
80 | 81 | ||
81 | static int camera; /* = 0 */ | 82 | static int camera; /* = 0 */ |
82 | module_param(camera, int, 0444); | 83 | module_param(camera, int, 0444); |
83 | MODULE_PARM_DESC(camera, | 84 | MODULE_PARM_DESC(camera, |
84 | "set this if you have a MotionEye camera (PictureBook series)"); | 85 | "set this if you have a MotionEye camera (PictureBook series)"); |
85 | 86 | ||
86 | static int compat; /* = 0 */ | 87 | static int compat; /* = 0 */ |
87 | module_param(compat, int, 0444); | 88 | module_param(compat, int, 0444); |
88 | MODULE_PARM_DESC(compat, | 89 | MODULE_PARM_DESC(compat, |
89 | "set this if you want to enable backward compatibility mode"); | 90 | "set this if you want to enable backward compatibility mode"); |
90 | 91 | ||
91 | static unsigned long mask = 0xffffffff; | 92 | static unsigned long mask = 0xffffffff; |
92 | module_param(mask, ulong, 0644); | 93 | module_param(mask, ulong, 0644); |
93 | MODULE_PARM_DESC(mask, | 94 | MODULE_PARM_DESC(mask, |
94 | "set this to the mask of event you want to enable (see doc)"); | 95 | "set this to the mask of event you want to enable (see doc)"); |
95 | 96 | ||
96 | static int useinput = 1; | 97 | static int useinput = 1; |
97 | module_param(useinput, int, 0444); | 98 | module_param(useinput, int, 0444); |
98 | MODULE_PARM_DESC(useinput, | 99 | MODULE_PARM_DESC(useinput, |
99 | "set this if you would like sonypi to feed events to the input subsystem"); | 100 | "set this if you would like sonypi to feed events to the input subsystem"); |
100 | 101 | ||
101 | static int check_ioport = 1; | 102 | static int check_ioport = 1; |
102 | module_param(check_ioport, int, 0444); | 103 | module_param(check_ioport, int, 0444); |
103 | MODULE_PARM_DESC(check_ioport, | 104 | MODULE_PARM_DESC(check_ioport, |
104 | "set this to 0 if you think the automatic ioport check for sony-laptop is wrong"); | 105 | "set this to 0 if you think the automatic ioport check for sony-laptop is wrong"); |
105 | 106 | ||
106 | #define SONYPI_DEVICE_MODEL_TYPE1 1 | 107 | #define SONYPI_DEVICE_MODEL_TYPE1 1 |
107 | #define SONYPI_DEVICE_MODEL_TYPE2 2 | 108 | #define SONYPI_DEVICE_MODEL_TYPE2 2 |
108 | #define SONYPI_DEVICE_MODEL_TYPE3 3 | 109 | #define SONYPI_DEVICE_MODEL_TYPE3 3 |
109 | 110 | ||
110 | /* type1 models use those */ | 111 | /* type1 models use those */ |
111 | #define SONYPI_IRQ_PORT 0x8034 | 112 | #define SONYPI_IRQ_PORT 0x8034 |
112 | #define SONYPI_IRQ_SHIFT 22 | 113 | #define SONYPI_IRQ_SHIFT 22 |
113 | #define SONYPI_TYPE1_BASE 0x50 | 114 | #define SONYPI_TYPE1_BASE 0x50 |
114 | #define SONYPI_G10A (SONYPI_TYPE1_BASE+0x14) | 115 | #define SONYPI_G10A (SONYPI_TYPE1_BASE+0x14) |
115 | #define SONYPI_TYPE1_REGION_SIZE 0x08 | 116 | #define SONYPI_TYPE1_REGION_SIZE 0x08 |
116 | #define SONYPI_TYPE1_EVTYPE_OFFSET 0x04 | 117 | #define SONYPI_TYPE1_EVTYPE_OFFSET 0x04 |
117 | 118 | ||
118 | /* type2 series specifics */ | 119 | /* type2 series specifics */ |
119 | #define SONYPI_SIRQ 0x9b | 120 | #define SONYPI_SIRQ 0x9b |
120 | #define SONYPI_SLOB 0x9c | 121 | #define SONYPI_SLOB 0x9c |
121 | #define SONYPI_SHIB 0x9d | 122 | #define SONYPI_SHIB 0x9d |
122 | #define SONYPI_TYPE2_REGION_SIZE 0x20 | 123 | #define SONYPI_TYPE2_REGION_SIZE 0x20 |
123 | #define SONYPI_TYPE2_EVTYPE_OFFSET 0x12 | 124 | #define SONYPI_TYPE2_EVTYPE_OFFSET 0x12 |
124 | 125 | ||
125 | /* type3 series specifics */ | 126 | /* type3 series specifics */ |
126 | #define SONYPI_TYPE3_BASE 0x40 | 127 | #define SONYPI_TYPE3_BASE 0x40 |
127 | #define SONYPI_TYPE3_GID2 (SONYPI_TYPE3_BASE+0x48) /* 16 bits */ | 128 | #define SONYPI_TYPE3_GID2 (SONYPI_TYPE3_BASE+0x48) /* 16 bits */ |
128 | #define SONYPI_TYPE3_MISC (SONYPI_TYPE3_BASE+0x6d) /* 8 bits */ | 129 | #define SONYPI_TYPE3_MISC (SONYPI_TYPE3_BASE+0x6d) /* 8 bits */ |
129 | #define SONYPI_TYPE3_REGION_SIZE 0x20 | 130 | #define SONYPI_TYPE3_REGION_SIZE 0x20 |
130 | #define SONYPI_TYPE3_EVTYPE_OFFSET 0x12 | 131 | #define SONYPI_TYPE3_EVTYPE_OFFSET 0x12 |
131 | 132 | ||
132 | /* battery / brightness addresses */ | 133 | /* battery / brightness addresses */ |
133 | #define SONYPI_BAT_FLAGS 0x81 | 134 | #define SONYPI_BAT_FLAGS 0x81 |
134 | #define SONYPI_LCD_LIGHT 0x96 | 135 | #define SONYPI_LCD_LIGHT 0x96 |
135 | #define SONYPI_BAT1_PCTRM 0xa0 | 136 | #define SONYPI_BAT1_PCTRM 0xa0 |
136 | #define SONYPI_BAT1_LEFT 0xa2 | 137 | #define SONYPI_BAT1_LEFT 0xa2 |
137 | #define SONYPI_BAT1_MAXRT 0xa4 | 138 | #define SONYPI_BAT1_MAXRT 0xa4 |
138 | #define SONYPI_BAT2_PCTRM 0xa8 | 139 | #define SONYPI_BAT2_PCTRM 0xa8 |
139 | #define SONYPI_BAT2_LEFT 0xaa | 140 | #define SONYPI_BAT2_LEFT 0xaa |
140 | #define SONYPI_BAT2_MAXRT 0xac | 141 | #define SONYPI_BAT2_MAXRT 0xac |
141 | #define SONYPI_BAT1_MAXTK 0xb0 | 142 | #define SONYPI_BAT1_MAXTK 0xb0 |
142 | #define SONYPI_BAT1_FULL 0xb2 | 143 | #define SONYPI_BAT1_FULL 0xb2 |
143 | #define SONYPI_BAT2_MAXTK 0xb8 | 144 | #define SONYPI_BAT2_MAXTK 0xb8 |
144 | #define SONYPI_BAT2_FULL 0xba | 145 | #define SONYPI_BAT2_FULL 0xba |
145 | 146 | ||
146 | /* FAN0 information (reverse engineered from ACPI tables) */ | 147 | /* FAN0 information (reverse engineered from ACPI tables) */ |
147 | #define SONYPI_FAN0_STATUS 0x93 | 148 | #define SONYPI_FAN0_STATUS 0x93 |
148 | #define SONYPI_TEMP_STATUS 0xC1 | 149 | #define SONYPI_TEMP_STATUS 0xC1 |
149 | 150 | ||
150 | /* ioports used for brightness and type2 events */ | 151 | /* ioports used for brightness and type2 events */ |
151 | #define SONYPI_DATA_IOPORT 0x62 | 152 | #define SONYPI_DATA_IOPORT 0x62 |
152 | #define SONYPI_CST_IOPORT 0x66 | 153 | #define SONYPI_CST_IOPORT 0x66 |
153 | 154 | ||
154 | /* The set of possible ioports */ | 155 | /* The set of possible ioports */ |
155 | struct sonypi_ioport_list { | 156 | struct sonypi_ioport_list { |
156 | u16 port1; | 157 | u16 port1; |
157 | u16 port2; | 158 | u16 port2; |
158 | }; | 159 | }; |
159 | 160 | ||
160 | static struct sonypi_ioport_list sonypi_type1_ioport_list[] = { | 161 | static struct sonypi_ioport_list sonypi_type1_ioport_list[] = { |
161 | { 0x10c0, 0x10c4 }, /* looks like the default on C1Vx */ | 162 | { 0x10c0, 0x10c4 }, /* looks like the default on C1Vx */ |
162 | { 0x1080, 0x1084 }, | 163 | { 0x1080, 0x1084 }, |
163 | { 0x1090, 0x1094 }, | 164 | { 0x1090, 0x1094 }, |
164 | { 0x10a0, 0x10a4 }, | 165 | { 0x10a0, 0x10a4 }, |
165 | { 0x10b0, 0x10b4 }, | 166 | { 0x10b0, 0x10b4 }, |
166 | { 0x0, 0x0 } | 167 | { 0x0, 0x0 } |
167 | }; | 168 | }; |
168 | 169 | ||
169 | static struct sonypi_ioport_list sonypi_type2_ioport_list[] = { | 170 | static struct sonypi_ioport_list sonypi_type2_ioport_list[] = { |
170 | { 0x1080, 0x1084 }, | 171 | { 0x1080, 0x1084 }, |
171 | { 0x10a0, 0x10a4 }, | 172 | { 0x10a0, 0x10a4 }, |
172 | { 0x10c0, 0x10c4 }, | 173 | { 0x10c0, 0x10c4 }, |
173 | { 0x10e0, 0x10e4 }, | 174 | { 0x10e0, 0x10e4 }, |
174 | { 0x0, 0x0 } | 175 | { 0x0, 0x0 } |
175 | }; | 176 | }; |
176 | 177 | ||
177 | /* same as in type 2 models */ | 178 | /* same as in type 2 models */ |
178 | static struct sonypi_ioport_list *sonypi_type3_ioport_list = | 179 | static struct sonypi_ioport_list *sonypi_type3_ioport_list = |
179 | sonypi_type2_ioport_list; | 180 | sonypi_type2_ioport_list; |
180 | 181 | ||
181 | /* The set of possible interrupts */ | 182 | /* The set of possible interrupts */ |
182 | struct sonypi_irq_list { | 183 | struct sonypi_irq_list { |
183 | u16 irq; | 184 | u16 irq; |
184 | u16 bits; | 185 | u16 bits; |
185 | }; | 186 | }; |
186 | 187 | ||
187 | static struct sonypi_irq_list sonypi_type1_irq_list[] = { | 188 | static struct sonypi_irq_list sonypi_type1_irq_list[] = { |
188 | { 11, 0x2 }, /* IRQ 11, GO22=0,GO23=1 in AML */ | 189 | { 11, 0x2 }, /* IRQ 11, GO22=0,GO23=1 in AML */ |
189 | { 10, 0x1 }, /* IRQ 10, GO22=1,GO23=0 in AML */ | 190 | { 10, 0x1 }, /* IRQ 10, GO22=1,GO23=0 in AML */ |
190 | { 5, 0x0 }, /* IRQ 5, GO22=0,GO23=0 in AML */ | 191 | { 5, 0x0 }, /* IRQ 5, GO22=0,GO23=0 in AML */ |
191 | { 0, 0x3 } /* no IRQ, GO22=1,GO23=1 in AML */ | 192 | { 0, 0x3 } /* no IRQ, GO22=1,GO23=1 in AML */ |
192 | }; | 193 | }; |
193 | 194 | ||
194 | static struct sonypi_irq_list sonypi_type2_irq_list[] = { | 195 | static struct sonypi_irq_list sonypi_type2_irq_list[] = { |
195 | { 11, 0x80 }, /* IRQ 11, 0x80 in SIRQ in AML */ | 196 | { 11, 0x80 }, /* IRQ 11, 0x80 in SIRQ in AML */ |
196 | { 10, 0x40 }, /* IRQ 10, 0x40 in SIRQ in AML */ | 197 | { 10, 0x40 }, /* IRQ 10, 0x40 in SIRQ in AML */ |
197 | { 9, 0x20 }, /* IRQ 9, 0x20 in SIRQ in AML */ | 198 | { 9, 0x20 }, /* IRQ 9, 0x20 in SIRQ in AML */ |
198 | { 6, 0x10 }, /* IRQ 6, 0x10 in SIRQ in AML */ | 199 | { 6, 0x10 }, /* IRQ 6, 0x10 in SIRQ in AML */ |
199 | { 0, 0x00 } /* no IRQ, 0x00 in SIRQ in AML */ | 200 | { 0, 0x00 } /* no IRQ, 0x00 in SIRQ in AML */ |
200 | }; | 201 | }; |
201 | 202 | ||
202 | /* same as in type2 models */ | 203 | /* same as in type2 models */ |
203 | static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list; | 204 | static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list; |
204 | 205 | ||
205 | #define SONYPI_CAMERA_BRIGHTNESS 0 | 206 | #define SONYPI_CAMERA_BRIGHTNESS 0 |
206 | #define SONYPI_CAMERA_CONTRAST 1 | 207 | #define SONYPI_CAMERA_CONTRAST 1 |
207 | #define SONYPI_CAMERA_HUE 2 | 208 | #define SONYPI_CAMERA_HUE 2 |
208 | #define SONYPI_CAMERA_COLOR 3 | 209 | #define SONYPI_CAMERA_COLOR 3 |
209 | #define SONYPI_CAMERA_SHARPNESS 4 | 210 | #define SONYPI_CAMERA_SHARPNESS 4 |
210 | 211 | ||
211 | #define SONYPI_CAMERA_PICTURE 5 | 212 | #define SONYPI_CAMERA_PICTURE 5 |
212 | #define SONYPI_CAMERA_EXPOSURE_MASK 0xC | 213 | #define SONYPI_CAMERA_EXPOSURE_MASK 0xC |
213 | #define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3 | 214 | #define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3 |
214 | #define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30 | 215 | #define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30 |
215 | #define SONYPI_CAMERA_MUTE_MASK 0x40 | 216 | #define SONYPI_CAMERA_MUTE_MASK 0x40 |
216 | 217 | ||
217 | /* the rest don't need a loop until not 0xff */ | 218 | /* the rest don't need a loop until not 0xff */ |
218 | #define SONYPI_CAMERA_AGC 6 | 219 | #define SONYPI_CAMERA_AGC 6 |
219 | #define SONYPI_CAMERA_AGC_MASK 0x30 | 220 | #define SONYPI_CAMERA_AGC_MASK 0x30 |
220 | #define SONYPI_CAMERA_SHUTTER_MASK 0x7 | 221 | #define SONYPI_CAMERA_SHUTTER_MASK 0x7 |
221 | 222 | ||
222 | #define SONYPI_CAMERA_SHUTDOWN_REQUEST 7 | 223 | #define SONYPI_CAMERA_SHUTDOWN_REQUEST 7 |
223 | #define SONYPI_CAMERA_CONTROL 0x10 | 224 | #define SONYPI_CAMERA_CONTROL 0x10 |
224 | 225 | ||
225 | #define SONYPI_CAMERA_STATUS 7 | 226 | #define SONYPI_CAMERA_STATUS 7 |
226 | #define SONYPI_CAMERA_STATUS_READY 0x2 | 227 | #define SONYPI_CAMERA_STATUS_READY 0x2 |
227 | #define SONYPI_CAMERA_STATUS_POSITION 0x4 | 228 | #define SONYPI_CAMERA_STATUS_POSITION 0x4 |
228 | 229 | ||
229 | #define SONYPI_DIRECTION_BACKWARDS 0x4 | 230 | #define SONYPI_DIRECTION_BACKWARDS 0x4 |
230 | 231 | ||
231 | #define SONYPI_CAMERA_REVISION 8 | 232 | #define SONYPI_CAMERA_REVISION 8 |
232 | #define SONYPI_CAMERA_ROMVERSION 9 | 233 | #define SONYPI_CAMERA_ROMVERSION 9 |
233 | 234 | ||
234 | /* Event masks */ | 235 | /* Event masks */ |
235 | #define SONYPI_JOGGER_MASK 0x00000001 | 236 | #define SONYPI_JOGGER_MASK 0x00000001 |
236 | #define SONYPI_CAPTURE_MASK 0x00000002 | 237 | #define SONYPI_CAPTURE_MASK 0x00000002 |
237 | #define SONYPI_FNKEY_MASK 0x00000004 | 238 | #define SONYPI_FNKEY_MASK 0x00000004 |
238 | #define SONYPI_BLUETOOTH_MASK 0x00000008 | 239 | #define SONYPI_BLUETOOTH_MASK 0x00000008 |
239 | #define SONYPI_PKEY_MASK 0x00000010 | 240 | #define SONYPI_PKEY_MASK 0x00000010 |
240 | #define SONYPI_BACK_MASK 0x00000020 | 241 | #define SONYPI_BACK_MASK 0x00000020 |
241 | #define SONYPI_HELP_MASK 0x00000040 | 242 | #define SONYPI_HELP_MASK 0x00000040 |
242 | #define SONYPI_LID_MASK 0x00000080 | 243 | #define SONYPI_LID_MASK 0x00000080 |
243 | #define SONYPI_ZOOM_MASK 0x00000100 | 244 | #define SONYPI_ZOOM_MASK 0x00000100 |
244 | #define SONYPI_THUMBPHRASE_MASK 0x00000200 | 245 | #define SONYPI_THUMBPHRASE_MASK 0x00000200 |
245 | #define SONYPI_MEYE_MASK 0x00000400 | 246 | #define SONYPI_MEYE_MASK 0x00000400 |
246 | #define SONYPI_MEMORYSTICK_MASK 0x00000800 | 247 | #define SONYPI_MEMORYSTICK_MASK 0x00000800 |
247 | #define SONYPI_BATTERY_MASK 0x00001000 | 248 | #define SONYPI_BATTERY_MASK 0x00001000 |
248 | #define SONYPI_WIRELESS_MASK 0x00002000 | 249 | #define SONYPI_WIRELESS_MASK 0x00002000 |
249 | 250 | ||
250 | struct sonypi_event { | 251 | struct sonypi_event { |
251 | u8 data; | 252 | u8 data; |
252 | u8 event; | 253 | u8 event; |
253 | }; | 254 | }; |
254 | 255 | ||
255 | /* The set of possible button release events */ | 256 | /* The set of possible button release events */ |
256 | static struct sonypi_event sonypi_releaseev[] = { | 257 | static struct sonypi_event sonypi_releaseev[] = { |
257 | { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED }, | 258 | { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED }, |
258 | { 0, 0 } | 259 | { 0, 0 } |
259 | }; | 260 | }; |
260 | 261 | ||
261 | /* The set of possible jogger events */ | 262 | /* The set of possible jogger events */ |
262 | static struct sonypi_event sonypi_joggerev[] = { | 263 | static struct sonypi_event sonypi_joggerev[] = { |
263 | { 0x1f, SONYPI_EVENT_JOGDIAL_UP }, | 264 | { 0x1f, SONYPI_EVENT_JOGDIAL_UP }, |
264 | { 0x01, SONYPI_EVENT_JOGDIAL_DOWN }, | 265 | { 0x01, SONYPI_EVENT_JOGDIAL_DOWN }, |
265 | { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED }, | 266 | { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED }, |
266 | { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED }, | 267 | { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED }, |
267 | { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP }, | 268 | { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP }, |
268 | { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN }, | 269 | { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN }, |
269 | { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED }, | 270 | { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED }, |
270 | { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED }, | 271 | { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED }, |
271 | { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP }, | 272 | { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP }, |
272 | { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN }, | 273 | { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN }, |
273 | { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED }, | 274 | { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED }, |
274 | { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED }, | 275 | { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED }, |
275 | { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED }, | 276 | { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED }, |
276 | { 0, 0 } | 277 | { 0, 0 } |
277 | }; | 278 | }; |
278 | 279 | ||
279 | /* The set of possible capture button events */ | 280 | /* The set of possible capture button events */ |
280 | static struct sonypi_event sonypi_captureev[] = { | 281 | static struct sonypi_event sonypi_captureev[] = { |
281 | { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED }, | 282 | { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED }, |
282 | { 0x07, SONYPI_EVENT_CAPTURE_PRESSED }, | 283 | { 0x07, SONYPI_EVENT_CAPTURE_PRESSED }, |
283 | { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED }, | 284 | { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED }, |
284 | { 0, 0 } | 285 | { 0, 0 } |
285 | }; | 286 | }; |
286 | 287 | ||
287 | /* The set of possible fnkeys events */ | 288 | /* The set of possible fnkeys events */ |
288 | static struct sonypi_event sonypi_fnkeyev[] = { | 289 | static struct sonypi_event sonypi_fnkeyev[] = { |
289 | { 0x10, SONYPI_EVENT_FNKEY_ESC }, | 290 | { 0x10, SONYPI_EVENT_FNKEY_ESC }, |
290 | { 0x11, SONYPI_EVENT_FNKEY_F1 }, | 291 | { 0x11, SONYPI_EVENT_FNKEY_F1 }, |
291 | { 0x12, SONYPI_EVENT_FNKEY_F2 }, | 292 | { 0x12, SONYPI_EVENT_FNKEY_F2 }, |
292 | { 0x13, SONYPI_EVENT_FNKEY_F3 }, | 293 | { 0x13, SONYPI_EVENT_FNKEY_F3 }, |
293 | { 0x14, SONYPI_EVENT_FNKEY_F4 }, | 294 | { 0x14, SONYPI_EVENT_FNKEY_F4 }, |
294 | { 0x15, SONYPI_EVENT_FNKEY_F5 }, | 295 | { 0x15, SONYPI_EVENT_FNKEY_F5 }, |
295 | { 0x16, SONYPI_EVENT_FNKEY_F6 }, | 296 | { 0x16, SONYPI_EVENT_FNKEY_F6 }, |
296 | { 0x17, SONYPI_EVENT_FNKEY_F7 }, | 297 | { 0x17, SONYPI_EVENT_FNKEY_F7 }, |
297 | { 0x18, SONYPI_EVENT_FNKEY_F8 }, | 298 | { 0x18, SONYPI_EVENT_FNKEY_F8 }, |
298 | { 0x19, SONYPI_EVENT_FNKEY_F9 }, | 299 | { 0x19, SONYPI_EVENT_FNKEY_F9 }, |
299 | { 0x1a, SONYPI_EVENT_FNKEY_F10 }, | 300 | { 0x1a, SONYPI_EVENT_FNKEY_F10 }, |
300 | { 0x1b, SONYPI_EVENT_FNKEY_F11 }, | 301 | { 0x1b, SONYPI_EVENT_FNKEY_F11 }, |
301 | { 0x1c, SONYPI_EVENT_FNKEY_F12 }, | 302 | { 0x1c, SONYPI_EVENT_FNKEY_F12 }, |
302 | { 0x1f, SONYPI_EVENT_FNKEY_RELEASED }, | 303 | { 0x1f, SONYPI_EVENT_FNKEY_RELEASED }, |
303 | { 0x21, SONYPI_EVENT_FNKEY_1 }, | 304 | { 0x21, SONYPI_EVENT_FNKEY_1 }, |
304 | { 0x22, SONYPI_EVENT_FNKEY_2 }, | 305 | { 0x22, SONYPI_EVENT_FNKEY_2 }, |
305 | { 0x31, SONYPI_EVENT_FNKEY_D }, | 306 | { 0x31, SONYPI_EVENT_FNKEY_D }, |
306 | { 0x32, SONYPI_EVENT_FNKEY_E }, | 307 | { 0x32, SONYPI_EVENT_FNKEY_E }, |
307 | { 0x33, SONYPI_EVENT_FNKEY_F }, | 308 | { 0x33, SONYPI_EVENT_FNKEY_F }, |
308 | { 0x34, SONYPI_EVENT_FNKEY_S }, | 309 | { 0x34, SONYPI_EVENT_FNKEY_S }, |
309 | { 0x35, SONYPI_EVENT_FNKEY_B }, | 310 | { 0x35, SONYPI_EVENT_FNKEY_B }, |
310 | { 0x36, SONYPI_EVENT_FNKEY_ONLY }, | 311 | { 0x36, SONYPI_EVENT_FNKEY_ONLY }, |
311 | { 0, 0 } | 312 | { 0, 0 } |
312 | }; | 313 | }; |
313 | 314 | ||
314 | /* The set of possible program key events */ | 315 | /* The set of possible program key events */ |
315 | static struct sonypi_event sonypi_pkeyev[] = { | 316 | static struct sonypi_event sonypi_pkeyev[] = { |
316 | { 0x01, SONYPI_EVENT_PKEY_P1 }, | 317 | { 0x01, SONYPI_EVENT_PKEY_P1 }, |
317 | { 0x02, SONYPI_EVENT_PKEY_P2 }, | 318 | { 0x02, SONYPI_EVENT_PKEY_P2 }, |
318 | { 0x04, SONYPI_EVENT_PKEY_P3 }, | 319 | { 0x04, SONYPI_EVENT_PKEY_P3 }, |
319 | { 0x5c, SONYPI_EVENT_PKEY_P1 }, | 320 | { 0x5c, SONYPI_EVENT_PKEY_P1 }, |
320 | { 0, 0 } | 321 | { 0, 0 } |
321 | }; | 322 | }; |
322 | 323 | ||
323 | /* The set of possible bluetooth events */ | 324 | /* The set of possible bluetooth events */ |
324 | static struct sonypi_event sonypi_blueev[] = { | 325 | static struct sonypi_event sonypi_blueev[] = { |
325 | { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED }, | 326 | { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED }, |
326 | { 0x59, SONYPI_EVENT_BLUETOOTH_ON }, | 327 | { 0x59, SONYPI_EVENT_BLUETOOTH_ON }, |
327 | { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF }, | 328 | { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF }, |
328 | { 0, 0 } | 329 | { 0, 0 } |
329 | }; | 330 | }; |
330 | 331 | ||
331 | /* The set of possible wireless events */ | 332 | /* The set of possible wireless events */ |
332 | static struct sonypi_event sonypi_wlessev[] = { | 333 | static struct sonypi_event sonypi_wlessev[] = { |
333 | { 0x59, SONYPI_EVENT_WIRELESS_ON }, | 334 | { 0x59, SONYPI_EVENT_WIRELESS_ON }, |
334 | { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, | 335 | { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, |
335 | { 0, 0 } | 336 | { 0, 0 } |
336 | }; | 337 | }; |
337 | 338 | ||
338 | /* The set of possible back button events */ | 339 | /* The set of possible back button events */ |
339 | static struct sonypi_event sonypi_backev[] = { | 340 | static struct sonypi_event sonypi_backev[] = { |
340 | { 0x20, SONYPI_EVENT_BACK_PRESSED }, | 341 | { 0x20, SONYPI_EVENT_BACK_PRESSED }, |
341 | { 0, 0 } | 342 | { 0, 0 } |
342 | }; | 343 | }; |
343 | 344 | ||
344 | /* The set of possible help button events */ | 345 | /* The set of possible help button events */ |
345 | static struct sonypi_event sonypi_helpev[] = { | 346 | static struct sonypi_event sonypi_helpev[] = { |
346 | { 0x3b, SONYPI_EVENT_HELP_PRESSED }, | 347 | { 0x3b, SONYPI_EVENT_HELP_PRESSED }, |
347 | { 0, 0 } | 348 | { 0, 0 } |
348 | }; | 349 | }; |
349 | 350 | ||
350 | 351 | ||
351 | /* The set of possible lid events */ | 352 | /* The set of possible lid events */ |
352 | static struct sonypi_event sonypi_lidev[] = { | 353 | static struct sonypi_event sonypi_lidev[] = { |
353 | { 0x51, SONYPI_EVENT_LID_CLOSED }, | 354 | { 0x51, SONYPI_EVENT_LID_CLOSED }, |
354 | { 0x50, SONYPI_EVENT_LID_OPENED }, | 355 | { 0x50, SONYPI_EVENT_LID_OPENED }, |
355 | { 0, 0 } | 356 | { 0, 0 } |
356 | }; | 357 | }; |
357 | 358 | ||
358 | /* The set of possible zoom events */ | 359 | /* The set of possible zoom events */ |
359 | static struct sonypi_event sonypi_zoomev[] = { | 360 | static struct sonypi_event sonypi_zoomev[] = { |
360 | { 0x39, SONYPI_EVENT_ZOOM_PRESSED }, | 361 | { 0x39, SONYPI_EVENT_ZOOM_PRESSED }, |
361 | { 0, 0 } | 362 | { 0, 0 } |
362 | }; | 363 | }; |
363 | 364 | ||
364 | /* The set of possible thumbphrase events */ | 365 | /* The set of possible thumbphrase events */ |
365 | static struct sonypi_event sonypi_thumbphraseev[] = { | 366 | static struct sonypi_event sonypi_thumbphraseev[] = { |
366 | { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED }, | 367 | { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED }, |
367 | { 0, 0 } | 368 | { 0, 0 } |
368 | }; | 369 | }; |
369 | 370 | ||
370 | /* The set of possible motioneye camera events */ | 371 | /* The set of possible motioneye camera events */ |
371 | static struct sonypi_event sonypi_meyeev[] = { | 372 | static struct sonypi_event sonypi_meyeev[] = { |
372 | { 0x00, SONYPI_EVENT_MEYE_FACE }, | 373 | { 0x00, SONYPI_EVENT_MEYE_FACE }, |
373 | { 0x01, SONYPI_EVENT_MEYE_OPPOSITE }, | 374 | { 0x01, SONYPI_EVENT_MEYE_OPPOSITE }, |
374 | { 0, 0 } | 375 | { 0, 0 } |
375 | }; | 376 | }; |
376 | 377 | ||
377 | /* The set of possible memorystick events */ | 378 | /* The set of possible memorystick events */ |
378 | static struct sonypi_event sonypi_memorystickev[] = { | 379 | static struct sonypi_event sonypi_memorystickev[] = { |
379 | { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT }, | 380 | { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT }, |
380 | { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT }, | 381 | { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT }, |
381 | { 0, 0 } | 382 | { 0, 0 } |
382 | }; | 383 | }; |
383 | 384 | ||
384 | /* The set of possible battery events */ | 385 | /* The set of possible battery events */ |
385 | static struct sonypi_event sonypi_batteryev[] = { | 386 | static struct sonypi_event sonypi_batteryev[] = { |
386 | { 0x20, SONYPI_EVENT_BATTERY_INSERT }, | 387 | { 0x20, SONYPI_EVENT_BATTERY_INSERT }, |
387 | { 0x30, SONYPI_EVENT_BATTERY_REMOVE }, | 388 | { 0x30, SONYPI_EVENT_BATTERY_REMOVE }, |
388 | { 0, 0 } | 389 | { 0, 0 } |
389 | }; | 390 | }; |
390 | 391 | ||
391 | static struct sonypi_eventtypes { | 392 | static struct sonypi_eventtypes { |
392 | int model; | 393 | int model; |
393 | u8 data; | 394 | u8 data; |
394 | unsigned long mask; | 395 | unsigned long mask; |
395 | struct sonypi_event * events; | 396 | struct sonypi_event * events; |
396 | } sonypi_eventtypes[] = { | 397 | } sonypi_eventtypes[] = { |
397 | { SONYPI_DEVICE_MODEL_TYPE1, 0, 0xffffffff, sonypi_releaseev }, | 398 | { SONYPI_DEVICE_MODEL_TYPE1, 0, 0xffffffff, sonypi_releaseev }, |
398 | { SONYPI_DEVICE_MODEL_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, | 399 | { SONYPI_DEVICE_MODEL_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, |
399 | { SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev }, | 400 | { SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev }, |
400 | { SONYPI_DEVICE_MODEL_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, | 401 | { SONYPI_DEVICE_MODEL_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, |
401 | { SONYPI_DEVICE_MODEL_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, | 402 | { SONYPI_DEVICE_MODEL_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, |
402 | { SONYPI_DEVICE_MODEL_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, | 403 | { SONYPI_DEVICE_MODEL_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, |
403 | { SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, | 404 | { SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, |
404 | { SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, | 405 | { SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, |
405 | { SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, | 406 | { SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, |
406 | { SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, | 407 | { SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, |
407 | 408 | ||
408 | { SONYPI_DEVICE_MODEL_TYPE2, 0, 0xffffffff, sonypi_releaseev }, | 409 | { SONYPI_DEVICE_MODEL_TYPE2, 0, 0xffffffff, sonypi_releaseev }, |
409 | { SONYPI_DEVICE_MODEL_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev }, | 410 | { SONYPI_DEVICE_MODEL_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev }, |
410 | { SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, | 411 | { SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, |
411 | { SONYPI_DEVICE_MODEL_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, | 412 | { SONYPI_DEVICE_MODEL_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, |
412 | { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, | 413 | { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, |
413 | { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, | 414 | { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, |
414 | { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, | 415 | { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, |
415 | { SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev }, | 416 | { SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev }, |
416 | { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev }, | 417 | { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev }, |
417 | { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, | 418 | { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, |
418 | { SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, | 419 | { SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, |
419 | { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, | 420 | { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, |
420 | { SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, | 421 | { SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, |
421 | { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, | 422 | { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, |
422 | 423 | ||
423 | { SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev }, | 424 | { SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev }, |
424 | { SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, | 425 | { SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, |
425 | { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, | 426 | { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, |
426 | { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, | 427 | { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, |
427 | { SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, | 428 | { SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, |
428 | { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, | 429 | { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, |
429 | { 0 } | 430 | { 0 } |
430 | }; | 431 | }; |
431 | 432 | ||
432 | #define SONYPI_BUF_SIZE 128 | 433 | #define SONYPI_BUF_SIZE 128 |
433 | 434 | ||
434 | /* Correspondance table between sonypi events and input layer events */ | 435 | /* Correspondance table between sonypi events and input layer events */ |
435 | static struct { | 436 | static struct { |
436 | int sonypiev; | 437 | int sonypiev; |
437 | int inputev; | 438 | int inputev; |
438 | } sonypi_inputkeys[] = { | 439 | } sonypi_inputkeys[] = { |
439 | { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA }, | 440 | { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA }, |
440 | { SONYPI_EVENT_FNKEY_ONLY, KEY_FN }, | 441 | { SONYPI_EVENT_FNKEY_ONLY, KEY_FN }, |
441 | { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC }, | 442 | { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC }, |
442 | { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 }, | 443 | { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 }, |
443 | { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 }, | 444 | { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 }, |
444 | { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 }, | 445 | { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 }, |
445 | { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 }, | 446 | { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 }, |
446 | { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 }, | 447 | { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 }, |
447 | { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 }, | 448 | { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 }, |
448 | { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 }, | 449 | { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 }, |
449 | { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 }, | 450 | { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 }, |
450 | { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 }, | 451 | { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 }, |
451 | { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 }, | 452 | { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 }, |
452 | { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 }, | 453 | { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 }, |
453 | { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 }, | 454 | { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 }, |
454 | { SONYPI_EVENT_FNKEY_1, KEY_FN_1 }, | 455 | { SONYPI_EVENT_FNKEY_1, KEY_FN_1 }, |
455 | { SONYPI_EVENT_FNKEY_2, KEY_FN_2 }, | 456 | { SONYPI_EVENT_FNKEY_2, KEY_FN_2 }, |
456 | { SONYPI_EVENT_FNKEY_D, KEY_FN_D }, | 457 | { SONYPI_EVENT_FNKEY_D, KEY_FN_D }, |
457 | { SONYPI_EVENT_FNKEY_E, KEY_FN_E }, | 458 | { SONYPI_EVENT_FNKEY_E, KEY_FN_E }, |
458 | { SONYPI_EVENT_FNKEY_F, KEY_FN_F }, | 459 | { SONYPI_EVENT_FNKEY_F, KEY_FN_F }, |
459 | { SONYPI_EVENT_FNKEY_S, KEY_FN_S }, | 460 | { SONYPI_EVENT_FNKEY_S, KEY_FN_S }, |
460 | { SONYPI_EVENT_FNKEY_B, KEY_FN_B }, | 461 | { SONYPI_EVENT_FNKEY_B, KEY_FN_B }, |
461 | { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE }, | 462 | { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE }, |
462 | { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE }, | 463 | { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE }, |
463 | { SONYPI_EVENT_PKEY_P1, KEY_PROG1 }, | 464 | { SONYPI_EVENT_PKEY_P1, KEY_PROG1 }, |
464 | { SONYPI_EVENT_PKEY_P2, KEY_PROG2 }, | 465 | { SONYPI_EVENT_PKEY_P2, KEY_PROG2 }, |
465 | { SONYPI_EVENT_PKEY_P3, KEY_PROG3 }, | 466 | { SONYPI_EVENT_PKEY_P3, KEY_PROG3 }, |
466 | { SONYPI_EVENT_BACK_PRESSED, KEY_BACK }, | 467 | { SONYPI_EVENT_BACK_PRESSED, KEY_BACK }, |
467 | { SONYPI_EVENT_HELP_PRESSED, KEY_HELP }, | 468 | { SONYPI_EVENT_HELP_PRESSED, KEY_HELP }, |
468 | { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM }, | 469 | { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM }, |
469 | { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB }, | 470 | { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB }, |
470 | { 0, 0 }, | 471 | { 0, 0 }, |
471 | }; | 472 | }; |
472 | 473 | ||
473 | struct sonypi_keypress { | 474 | struct sonypi_keypress { |
474 | struct input_dev *dev; | 475 | struct input_dev *dev; |
475 | int key; | 476 | int key; |
476 | }; | 477 | }; |
477 | 478 | ||
478 | static struct sonypi_device { | 479 | static struct sonypi_device { |
479 | struct pci_dev *dev; | 480 | struct pci_dev *dev; |
480 | u16 irq; | 481 | u16 irq; |
481 | u16 bits; | 482 | u16 bits; |
482 | u16 ioport1; | 483 | u16 ioport1; |
483 | u16 ioport2; | 484 | u16 ioport2; |
484 | u16 region_size; | 485 | u16 region_size; |
485 | u16 evtype_offset; | 486 | u16 evtype_offset; |
486 | int camera_power; | 487 | int camera_power; |
487 | int bluetooth_power; | 488 | int bluetooth_power; |
488 | struct mutex lock; | 489 | struct mutex lock; |
489 | struct kfifo *fifo; | 490 | struct kfifo *fifo; |
490 | spinlock_t fifo_lock; | 491 | spinlock_t fifo_lock; |
491 | wait_queue_head_t fifo_proc_list; | 492 | wait_queue_head_t fifo_proc_list; |
492 | struct fasync_struct *fifo_async; | 493 | struct fasync_struct *fifo_async; |
493 | int open_count; | 494 | int open_count; |
494 | int model; | 495 | int model; |
495 | struct input_dev *input_jog_dev; | 496 | struct input_dev *input_jog_dev; |
496 | struct input_dev *input_key_dev; | 497 | struct input_dev *input_key_dev; |
497 | struct work_struct input_work; | 498 | struct work_struct input_work; |
498 | struct kfifo *input_fifo; | 499 | struct kfifo *input_fifo; |
499 | spinlock_t input_fifo_lock; | 500 | spinlock_t input_fifo_lock; |
500 | } sonypi_device; | 501 | } sonypi_device; |
501 | 502 | ||
502 | #define ITERATIONS_LONG 10000 | 503 | #define ITERATIONS_LONG 10000 |
503 | #define ITERATIONS_SHORT 10 | 504 | #define ITERATIONS_SHORT 10 |
504 | 505 | ||
505 | #define wait_on_command(quiet, command, iterations) { \ | 506 | #define wait_on_command(quiet, command, iterations) { \ |
506 | unsigned int n = iterations; \ | 507 | unsigned int n = iterations; \ |
507 | while (--n && (command)) \ | 508 | while (--n && (command)) \ |
508 | udelay(1); \ | 509 | udelay(1); \ |
509 | if (!n && (verbose || !quiet)) \ | 510 | if (!n && (verbose || !quiet)) \ |
510 | printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __func__, __LINE__); \ | 511 | printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __func__, __LINE__); \ |
511 | } | 512 | } |
512 | 513 | ||
513 | #ifdef CONFIG_ACPI | 514 | #ifdef CONFIG_ACPI |
514 | #define SONYPI_ACPI_ACTIVE (!acpi_disabled) | 515 | #define SONYPI_ACPI_ACTIVE (!acpi_disabled) |
515 | #else | 516 | #else |
516 | #define SONYPI_ACPI_ACTIVE 0 | 517 | #define SONYPI_ACPI_ACTIVE 0 |
517 | #endif /* CONFIG_ACPI */ | 518 | #endif /* CONFIG_ACPI */ |
518 | 519 | ||
519 | #ifdef CONFIG_ACPI | 520 | #ifdef CONFIG_ACPI |
520 | static struct acpi_device *sonypi_acpi_device; | 521 | static struct acpi_device *sonypi_acpi_device; |
521 | static int acpi_driver_registered; | 522 | static int acpi_driver_registered; |
522 | #endif | 523 | #endif |
523 | 524 | ||
524 | static int sonypi_ec_write(u8 addr, u8 value) | 525 | static int sonypi_ec_write(u8 addr, u8 value) |
525 | { | 526 | { |
526 | #ifdef CONFIG_ACPI | 527 | #ifdef CONFIG_ACPI |
527 | if (SONYPI_ACPI_ACTIVE) | 528 | if (SONYPI_ACPI_ACTIVE) |
528 | return ec_write(addr, value); | 529 | return ec_write(addr, value); |
529 | #endif | 530 | #endif |
530 | wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG); | 531 | wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG); |
531 | outb_p(0x81, SONYPI_CST_IOPORT); | 532 | outb_p(0x81, SONYPI_CST_IOPORT); |
532 | wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); | 533 | wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); |
533 | outb_p(addr, SONYPI_DATA_IOPORT); | 534 | outb_p(addr, SONYPI_DATA_IOPORT); |
534 | wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); | 535 | wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); |
535 | outb_p(value, SONYPI_DATA_IOPORT); | 536 | outb_p(value, SONYPI_DATA_IOPORT); |
536 | wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); | 537 | wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); |
537 | return 0; | 538 | return 0; |
538 | } | 539 | } |
539 | 540 | ||
540 | static int sonypi_ec_read(u8 addr, u8 *value) | 541 | static int sonypi_ec_read(u8 addr, u8 *value) |
541 | { | 542 | { |
542 | #ifdef CONFIG_ACPI | 543 | #ifdef CONFIG_ACPI |
543 | if (SONYPI_ACPI_ACTIVE) | 544 | if (SONYPI_ACPI_ACTIVE) |
544 | return ec_read(addr, value); | 545 | return ec_read(addr, value); |
545 | #endif | 546 | #endif |
546 | wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG); | 547 | wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG); |
547 | outb_p(0x80, SONYPI_CST_IOPORT); | 548 | outb_p(0x80, SONYPI_CST_IOPORT); |
548 | wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); | 549 | wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); |
549 | outb_p(addr, SONYPI_DATA_IOPORT); | 550 | outb_p(addr, SONYPI_DATA_IOPORT); |
550 | wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); | 551 | wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); |
551 | *value = inb_p(SONYPI_DATA_IOPORT); | 552 | *value = inb_p(SONYPI_DATA_IOPORT); |
552 | return 0; | 553 | return 0; |
553 | } | 554 | } |
554 | 555 | ||
555 | static int ec_read16(u8 addr, u16 *value) | 556 | static int ec_read16(u8 addr, u16 *value) |
556 | { | 557 | { |
557 | u8 val_lb, val_hb; | 558 | u8 val_lb, val_hb; |
558 | if (sonypi_ec_read(addr, &val_lb)) | 559 | if (sonypi_ec_read(addr, &val_lb)) |
559 | return -1; | 560 | return -1; |
560 | if (sonypi_ec_read(addr + 1, &val_hb)) | 561 | if (sonypi_ec_read(addr + 1, &val_hb)) |
561 | return -1; | 562 | return -1; |
562 | *value = val_lb | (val_hb << 8); | 563 | *value = val_lb | (val_hb << 8); |
563 | return 0; | 564 | return 0; |
564 | } | 565 | } |
565 | 566 | ||
566 | /* Initializes the device - this comes from the AML code in the ACPI bios */ | 567 | /* Initializes the device - this comes from the AML code in the ACPI bios */ |
567 | static void sonypi_type1_srs(void) | 568 | static void sonypi_type1_srs(void) |
568 | { | 569 | { |
569 | u32 v; | 570 | u32 v; |
570 | 571 | ||
571 | pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); | 572 | pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); |
572 | v = (v & 0xFFFF0000) | ((u32) sonypi_device.ioport1); | 573 | v = (v & 0xFFFF0000) | ((u32) sonypi_device.ioport1); |
573 | pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); | 574 | pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); |
574 | 575 | ||
575 | pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); | 576 | pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); |
576 | v = (v & 0xFFF0FFFF) | | 577 | v = (v & 0xFFF0FFFF) | |
577 | (((u32) sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16); | 578 | (((u32) sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16); |
578 | pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); | 579 | pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); |
579 | 580 | ||
580 | v = inl(SONYPI_IRQ_PORT); | 581 | v = inl(SONYPI_IRQ_PORT); |
581 | v &= ~(((u32) 0x3) << SONYPI_IRQ_SHIFT); | 582 | v &= ~(((u32) 0x3) << SONYPI_IRQ_SHIFT); |
582 | v |= (((u32) sonypi_device.bits) << SONYPI_IRQ_SHIFT); | 583 | v |= (((u32) sonypi_device.bits) << SONYPI_IRQ_SHIFT); |
583 | outl(v, SONYPI_IRQ_PORT); | 584 | outl(v, SONYPI_IRQ_PORT); |
584 | 585 | ||
585 | pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); | 586 | pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); |
586 | v = (v & 0xFF1FFFFF) | 0x00C00000; | 587 | v = (v & 0xFF1FFFFF) | 0x00C00000; |
587 | pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); | 588 | pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); |
588 | } | 589 | } |
589 | 590 | ||
590 | static void sonypi_type2_srs(void) | 591 | static void sonypi_type2_srs(void) |
591 | { | 592 | { |
592 | if (sonypi_ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8)) | 593 | if (sonypi_ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8)) |
593 | printk(KERN_WARNING "ec_write failed\n"); | 594 | printk(KERN_WARNING "ec_write failed\n"); |
594 | if (sonypi_ec_write(SONYPI_SLOB, sonypi_device.ioport1 & 0x00FF)) | 595 | if (sonypi_ec_write(SONYPI_SLOB, sonypi_device.ioport1 & 0x00FF)) |
595 | printk(KERN_WARNING "ec_write failed\n"); | 596 | printk(KERN_WARNING "ec_write failed\n"); |
596 | if (sonypi_ec_write(SONYPI_SIRQ, sonypi_device.bits)) | 597 | if (sonypi_ec_write(SONYPI_SIRQ, sonypi_device.bits)) |
597 | printk(KERN_WARNING "ec_write failed\n"); | 598 | printk(KERN_WARNING "ec_write failed\n"); |
598 | udelay(10); | 599 | udelay(10); |
599 | } | 600 | } |
600 | 601 | ||
601 | static void sonypi_type3_srs(void) | 602 | static void sonypi_type3_srs(void) |
602 | { | 603 | { |
603 | u16 v16; | 604 | u16 v16; |
604 | u8 v8; | 605 | u8 v8; |
605 | 606 | ||
606 | /* This model type uses the same initialiazation of | 607 | /* This model type uses the same initialiazation of |
607 | * the embedded controller as the type2 models. */ | 608 | * the embedded controller as the type2 models. */ |
608 | sonypi_type2_srs(); | 609 | sonypi_type2_srs(); |
609 | 610 | ||
610 | /* Initialization of PCI config space of the LPC interface bridge. */ | 611 | /* Initialization of PCI config space of the LPC interface bridge. */ |
611 | v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01; | 612 | v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01; |
612 | pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16); | 613 | pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16); |
613 | pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8); | 614 | pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8); |
614 | v8 = (v8 & 0xCF) | 0x10; | 615 | v8 = (v8 & 0xCF) | 0x10; |
615 | pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8); | 616 | pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8); |
616 | } | 617 | } |
617 | 618 | ||
618 | /* Disables the device - this comes from the AML code in the ACPI bios */ | 619 | /* Disables the device - this comes from the AML code in the ACPI bios */ |
619 | static void sonypi_type1_dis(void) | 620 | static void sonypi_type1_dis(void) |
620 | { | 621 | { |
621 | u32 v; | 622 | u32 v; |
622 | 623 | ||
623 | pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); | 624 | pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); |
624 | v = v & 0xFF3FFFFF; | 625 | v = v & 0xFF3FFFFF; |
625 | pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); | 626 | pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); |
626 | 627 | ||
627 | v = inl(SONYPI_IRQ_PORT); | 628 | v = inl(SONYPI_IRQ_PORT); |
628 | v |= (0x3 << SONYPI_IRQ_SHIFT); | 629 | v |= (0x3 << SONYPI_IRQ_SHIFT); |
629 | outl(v, SONYPI_IRQ_PORT); | 630 | outl(v, SONYPI_IRQ_PORT); |
630 | } | 631 | } |
631 | 632 | ||
632 | static void sonypi_type2_dis(void) | 633 | static void sonypi_type2_dis(void) |
633 | { | 634 | { |
634 | if (sonypi_ec_write(SONYPI_SHIB, 0)) | 635 | if (sonypi_ec_write(SONYPI_SHIB, 0)) |
635 | printk(KERN_WARNING "ec_write failed\n"); | 636 | printk(KERN_WARNING "ec_write failed\n"); |
636 | if (sonypi_ec_write(SONYPI_SLOB, 0)) | 637 | if (sonypi_ec_write(SONYPI_SLOB, 0)) |
637 | printk(KERN_WARNING "ec_write failed\n"); | 638 | printk(KERN_WARNING "ec_write failed\n"); |
638 | if (sonypi_ec_write(SONYPI_SIRQ, 0)) | 639 | if (sonypi_ec_write(SONYPI_SIRQ, 0)) |
639 | printk(KERN_WARNING "ec_write failed\n"); | 640 | printk(KERN_WARNING "ec_write failed\n"); |
640 | } | 641 | } |
641 | 642 | ||
642 | static void sonypi_type3_dis(void) | 643 | static void sonypi_type3_dis(void) |
643 | { | 644 | { |
644 | sonypi_type2_dis(); | 645 | sonypi_type2_dis(); |
645 | udelay(10); | 646 | udelay(10); |
646 | pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0); | 647 | pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0); |
647 | } | 648 | } |
648 | 649 | ||
649 | static u8 sonypi_call1(u8 dev) | 650 | static u8 sonypi_call1(u8 dev) |
650 | { | 651 | { |
651 | u8 v1, v2; | 652 | u8 v1, v2; |
652 | 653 | ||
653 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); | 654 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); |
654 | outb(dev, sonypi_device.ioport2); | 655 | outb(dev, sonypi_device.ioport2); |
655 | v1 = inb_p(sonypi_device.ioport2); | 656 | v1 = inb_p(sonypi_device.ioport2); |
656 | v2 = inb_p(sonypi_device.ioport1); | 657 | v2 = inb_p(sonypi_device.ioport1); |
657 | return v2; | 658 | return v2; |
658 | } | 659 | } |
659 | 660 | ||
660 | static u8 sonypi_call2(u8 dev, u8 fn) | 661 | static u8 sonypi_call2(u8 dev, u8 fn) |
661 | { | 662 | { |
662 | u8 v1; | 663 | u8 v1; |
663 | 664 | ||
664 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); | 665 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); |
665 | outb(dev, sonypi_device.ioport2); | 666 | outb(dev, sonypi_device.ioport2); |
666 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); | 667 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); |
667 | outb(fn, sonypi_device.ioport1); | 668 | outb(fn, sonypi_device.ioport1); |
668 | v1 = inb_p(sonypi_device.ioport1); | 669 | v1 = inb_p(sonypi_device.ioport1); |
669 | return v1; | 670 | return v1; |
670 | } | 671 | } |
671 | 672 | ||
672 | static u8 sonypi_call3(u8 dev, u8 fn, u8 v) | 673 | static u8 sonypi_call3(u8 dev, u8 fn, u8 v) |
673 | { | 674 | { |
674 | u8 v1; | 675 | u8 v1; |
675 | 676 | ||
676 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); | 677 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); |
677 | outb(dev, sonypi_device.ioport2); | 678 | outb(dev, sonypi_device.ioport2); |
678 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); | 679 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); |
679 | outb(fn, sonypi_device.ioport1); | 680 | outb(fn, sonypi_device.ioport1); |
680 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); | 681 | wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); |
681 | outb(v, sonypi_device.ioport1); | 682 | outb(v, sonypi_device.ioport1); |
682 | v1 = inb_p(sonypi_device.ioport1); | 683 | v1 = inb_p(sonypi_device.ioport1); |
683 | return v1; | 684 | return v1; |
684 | } | 685 | } |
685 | 686 | ||
686 | #if 0 | 687 | #if 0 |
687 | /* Get brightness, hue etc. Unreliable... */ | 688 | /* Get brightness, hue etc. Unreliable... */ |
688 | static u8 sonypi_read(u8 fn) | 689 | static u8 sonypi_read(u8 fn) |
689 | { | 690 | { |
690 | u8 v1, v2; | 691 | u8 v1, v2; |
691 | int n = 100; | 692 | int n = 100; |
692 | 693 | ||
693 | while (n--) { | 694 | while (n--) { |
694 | v1 = sonypi_call2(0x8f, fn); | 695 | v1 = sonypi_call2(0x8f, fn); |
695 | v2 = sonypi_call2(0x8f, fn); | 696 | v2 = sonypi_call2(0x8f, fn); |
696 | if (v1 == v2 && v1 != 0xff) | 697 | if (v1 == v2 && v1 != 0xff) |
697 | return v1; | 698 | return v1; |
698 | } | 699 | } |
699 | return 0xff; | 700 | return 0xff; |
700 | } | 701 | } |
701 | #endif | 702 | #endif |
702 | 703 | ||
703 | /* Set brightness, hue etc */ | 704 | /* Set brightness, hue etc */ |
704 | static void sonypi_set(u8 fn, u8 v) | 705 | static void sonypi_set(u8 fn, u8 v) |
705 | { | 706 | { |
706 | wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT); | 707 | wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT); |
707 | } | 708 | } |
708 | 709 | ||
709 | /* Tests if the camera is ready */ | 710 | /* Tests if the camera is ready */ |
710 | static int sonypi_camera_ready(void) | 711 | static int sonypi_camera_ready(void) |
711 | { | 712 | { |
712 | u8 v; | 713 | u8 v; |
713 | 714 | ||
714 | v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS); | 715 | v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS); |
715 | return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY)); | 716 | return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY)); |
716 | } | 717 | } |
717 | 718 | ||
718 | /* Turns the camera off */ | 719 | /* Turns the camera off */ |
719 | static void sonypi_camera_off(void) | 720 | static void sonypi_camera_off(void) |
720 | { | 721 | { |
721 | sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK); | 722 | sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK); |
722 | 723 | ||
723 | if (!sonypi_device.camera_power) | 724 | if (!sonypi_device.camera_power) |
724 | return; | 725 | return; |
725 | 726 | ||
726 | sonypi_call2(0x91, 0); | 727 | sonypi_call2(0x91, 0); |
727 | sonypi_device.camera_power = 0; | 728 | sonypi_device.camera_power = 0; |
728 | } | 729 | } |
729 | 730 | ||
730 | /* Turns the camera on */ | 731 | /* Turns the camera on */ |
731 | static void sonypi_camera_on(void) | 732 | static void sonypi_camera_on(void) |
732 | { | 733 | { |
733 | int i, j; | 734 | int i, j; |
734 | 735 | ||
735 | if (sonypi_device.camera_power) | 736 | if (sonypi_device.camera_power) |
736 | return; | 737 | return; |
737 | 738 | ||
738 | for (j = 5; j > 0; j--) { | 739 | for (j = 5; j > 0; j--) { |
739 | 740 | ||
740 | while (sonypi_call2(0x91, 0x1)) | 741 | while (sonypi_call2(0x91, 0x1)) |
741 | msleep(10); | 742 | msleep(10); |
742 | sonypi_call1(0x93); | 743 | sonypi_call1(0x93); |
743 | 744 | ||
744 | for (i = 400; i > 0; i--) { | 745 | for (i = 400; i > 0; i--) { |
745 | if (sonypi_camera_ready()) | 746 | if (sonypi_camera_ready()) |
746 | break; | 747 | break; |
747 | msleep(10); | 748 | msleep(10); |
748 | } | 749 | } |
749 | if (i) | 750 | if (i) |
750 | break; | 751 | break; |
751 | } | 752 | } |
752 | 753 | ||
753 | if (j == 0) { | 754 | if (j == 0) { |
754 | printk(KERN_WARNING "sonypi: failed to power on camera\n"); | 755 | printk(KERN_WARNING "sonypi: failed to power on camera\n"); |
755 | return; | 756 | return; |
756 | } | 757 | } |
757 | 758 | ||
758 | sonypi_set(0x10, 0x5a); | 759 | sonypi_set(0x10, 0x5a); |
759 | sonypi_device.camera_power = 1; | 760 | sonypi_device.camera_power = 1; |
760 | } | 761 | } |
761 | 762 | ||
762 | /* sets the bluetooth subsystem power state */ | 763 | /* sets the bluetooth subsystem power state */ |
763 | static void sonypi_setbluetoothpower(u8 state) | 764 | static void sonypi_setbluetoothpower(u8 state) |
764 | { | 765 | { |
765 | state = !!state; | 766 | state = !!state; |
766 | 767 | ||
767 | if (sonypi_device.bluetooth_power == state) | 768 | if (sonypi_device.bluetooth_power == state) |
768 | return; | 769 | return; |
769 | 770 | ||
770 | sonypi_call2(0x96, state); | 771 | sonypi_call2(0x96, state); |
771 | sonypi_call1(0x82); | 772 | sonypi_call1(0x82); |
772 | sonypi_device.bluetooth_power = state; | 773 | sonypi_device.bluetooth_power = state; |
773 | } | 774 | } |
774 | 775 | ||
775 | static void input_keyrelease(struct work_struct *work) | 776 | static void input_keyrelease(struct work_struct *work) |
776 | { | 777 | { |
777 | struct sonypi_keypress kp; | 778 | struct sonypi_keypress kp; |
778 | 779 | ||
779 | while (kfifo_get(sonypi_device.input_fifo, (unsigned char *)&kp, | 780 | while (kfifo_get(sonypi_device.input_fifo, (unsigned char *)&kp, |
780 | sizeof(kp)) == sizeof(kp)) { | 781 | sizeof(kp)) == sizeof(kp)) { |
781 | msleep(10); | 782 | msleep(10); |
782 | input_report_key(kp.dev, kp.key, 0); | 783 | input_report_key(kp.dev, kp.key, 0); |
783 | input_sync(kp.dev); | 784 | input_sync(kp.dev); |
784 | } | 785 | } |
785 | } | 786 | } |
786 | 787 | ||
787 | static void sonypi_report_input_event(u8 event) | 788 | static void sonypi_report_input_event(u8 event) |
788 | { | 789 | { |
789 | struct input_dev *jog_dev = sonypi_device.input_jog_dev; | 790 | struct input_dev *jog_dev = sonypi_device.input_jog_dev; |
790 | struct input_dev *key_dev = sonypi_device.input_key_dev; | 791 | struct input_dev *key_dev = sonypi_device.input_key_dev; |
791 | struct sonypi_keypress kp = { NULL }; | 792 | struct sonypi_keypress kp = { NULL }; |
792 | int i; | 793 | int i; |
793 | 794 | ||
794 | switch (event) { | 795 | switch (event) { |
795 | case SONYPI_EVENT_JOGDIAL_UP: | 796 | case SONYPI_EVENT_JOGDIAL_UP: |
796 | case SONYPI_EVENT_JOGDIAL_UP_PRESSED: | 797 | case SONYPI_EVENT_JOGDIAL_UP_PRESSED: |
797 | input_report_rel(jog_dev, REL_WHEEL, 1); | 798 | input_report_rel(jog_dev, REL_WHEEL, 1); |
798 | input_sync(jog_dev); | 799 | input_sync(jog_dev); |
799 | break; | 800 | break; |
800 | 801 | ||
801 | case SONYPI_EVENT_JOGDIAL_DOWN: | 802 | case SONYPI_EVENT_JOGDIAL_DOWN: |
802 | case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED: | 803 | case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED: |
803 | input_report_rel(jog_dev, REL_WHEEL, -1); | 804 | input_report_rel(jog_dev, REL_WHEEL, -1); |
804 | input_sync(jog_dev); | 805 | input_sync(jog_dev); |
805 | break; | 806 | break; |
806 | 807 | ||
807 | case SONYPI_EVENT_JOGDIAL_PRESSED: | 808 | case SONYPI_EVENT_JOGDIAL_PRESSED: |
808 | kp.key = BTN_MIDDLE; | 809 | kp.key = BTN_MIDDLE; |
809 | kp.dev = jog_dev; | 810 | kp.dev = jog_dev; |
810 | break; | 811 | break; |
811 | 812 | ||
812 | case SONYPI_EVENT_FNKEY_RELEASED: | 813 | case SONYPI_EVENT_FNKEY_RELEASED: |
813 | /* Nothing, not all VAIOs generate this event */ | 814 | /* Nothing, not all VAIOs generate this event */ |
814 | break; | 815 | break; |
815 | 816 | ||
816 | default: | 817 | default: |
817 | for (i = 0; sonypi_inputkeys[i].sonypiev; i++) | 818 | for (i = 0; sonypi_inputkeys[i].sonypiev; i++) |
818 | if (event == sonypi_inputkeys[i].sonypiev) { | 819 | if (event == sonypi_inputkeys[i].sonypiev) { |
819 | kp.dev = key_dev; | 820 | kp.dev = key_dev; |
820 | kp.key = sonypi_inputkeys[i].inputev; | 821 | kp.key = sonypi_inputkeys[i].inputev; |
821 | break; | 822 | break; |
822 | } | 823 | } |
823 | break; | 824 | break; |
824 | } | 825 | } |
825 | 826 | ||
826 | if (kp.dev) { | 827 | if (kp.dev) { |
827 | input_report_key(kp.dev, kp.key, 1); | 828 | input_report_key(kp.dev, kp.key, 1); |
828 | input_sync(kp.dev); | 829 | input_sync(kp.dev); |
829 | kfifo_put(sonypi_device.input_fifo, | 830 | kfifo_put(sonypi_device.input_fifo, |
830 | (unsigned char *)&kp, sizeof(kp)); | 831 | (unsigned char *)&kp, sizeof(kp)); |
831 | schedule_work(&sonypi_device.input_work); | 832 | schedule_work(&sonypi_device.input_work); |
832 | } | 833 | } |
833 | } | 834 | } |
834 | 835 | ||
835 | /* Interrupt handler: some event is available */ | 836 | /* Interrupt handler: some event is available */ |
836 | static irqreturn_t sonypi_irq(int irq, void *dev_id) | 837 | static irqreturn_t sonypi_irq(int irq, void *dev_id) |
837 | { | 838 | { |
838 | u8 v1, v2, event = 0; | 839 | u8 v1, v2, event = 0; |
839 | int i, j; | 840 | int i, j; |
840 | 841 | ||
841 | v1 = inb_p(sonypi_device.ioport1); | 842 | v1 = inb_p(sonypi_device.ioport1); |
842 | v2 = inb_p(sonypi_device.ioport1 + sonypi_device.evtype_offset); | 843 | v2 = inb_p(sonypi_device.ioport1 + sonypi_device.evtype_offset); |
843 | 844 | ||
844 | for (i = 0; sonypi_eventtypes[i].model; i++) { | 845 | for (i = 0; sonypi_eventtypes[i].model; i++) { |
845 | if (sonypi_device.model != sonypi_eventtypes[i].model) | 846 | if (sonypi_device.model != sonypi_eventtypes[i].model) |
846 | continue; | 847 | continue; |
847 | if ((v2 & sonypi_eventtypes[i].data) != | 848 | if ((v2 & sonypi_eventtypes[i].data) != |
848 | sonypi_eventtypes[i].data) | 849 | sonypi_eventtypes[i].data) |
849 | continue; | 850 | continue; |
850 | if (!(mask & sonypi_eventtypes[i].mask)) | 851 | if (!(mask & sonypi_eventtypes[i].mask)) |
851 | continue; | 852 | continue; |
852 | for (j = 0; sonypi_eventtypes[i].events[j].event; j++) { | 853 | for (j = 0; sonypi_eventtypes[i].events[j].event; j++) { |
853 | if (v1 == sonypi_eventtypes[i].events[j].data) { | 854 | if (v1 == sonypi_eventtypes[i].events[j].data) { |
854 | event = sonypi_eventtypes[i].events[j].event; | 855 | event = sonypi_eventtypes[i].events[j].event; |
855 | goto found; | 856 | goto found; |
856 | } | 857 | } |
857 | } | 858 | } |
858 | } | 859 | } |
859 | 860 | ||
860 | if (verbose) | 861 | if (verbose) |
861 | printk(KERN_WARNING | 862 | printk(KERN_WARNING |
862 | "sonypi: unknown event port1=0x%02x,port2=0x%02x\n", | 863 | "sonypi: unknown event port1=0x%02x,port2=0x%02x\n", |
863 | v1, v2); | 864 | v1, v2); |
864 | /* We need to return IRQ_HANDLED here because there *are* | 865 | /* We need to return IRQ_HANDLED here because there *are* |
865 | * events belonging to the sonypi device we don't know about, | 866 | * events belonging to the sonypi device we don't know about, |
866 | * but we still don't want those to pollute the logs... */ | 867 | * but we still don't want those to pollute the logs... */ |
867 | return IRQ_HANDLED; | 868 | return IRQ_HANDLED; |
868 | 869 | ||
869 | found: | 870 | found: |
870 | if (verbose > 1) | 871 | if (verbose > 1) |
871 | printk(KERN_INFO | 872 | printk(KERN_INFO |
872 | "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2); | 873 | "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2); |
873 | 874 | ||
874 | if (useinput) | 875 | if (useinput) |
875 | sonypi_report_input_event(event); | 876 | sonypi_report_input_event(event); |
876 | 877 | ||
877 | #ifdef CONFIG_ACPI | 878 | #ifdef CONFIG_ACPI |
878 | if (sonypi_acpi_device) | 879 | if (sonypi_acpi_device) |
879 | acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event); | 880 | acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event); |
880 | #endif | 881 | #endif |
881 | 882 | ||
882 | kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event)); | 883 | kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event)); |
883 | kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN); | 884 | kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN); |
884 | wake_up_interruptible(&sonypi_device.fifo_proc_list); | 885 | wake_up_interruptible(&sonypi_device.fifo_proc_list); |
885 | 886 | ||
886 | return IRQ_HANDLED; | 887 | return IRQ_HANDLED; |
887 | } | 888 | } |
888 | 889 | ||
889 | static int sonypi_misc_fasync(int fd, struct file *filp, int on) | 890 | static int sonypi_misc_fasync(int fd, struct file *filp, int on) |
890 | { | 891 | { |
891 | return fasync_helper(fd, filp, on, &sonypi_device.fifo_async); | 892 | return fasync_helper(fd, filp, on, &sonypi_device.fifo_async); |
892 | } | 893 | } |
893 | 894 | ||
894 | static int sonypi_misc_release(struct inode *inode, struct file *file) | 895 | static int sonypi_misc_release(struct inode *inode, struct file *file) |
895 | { | 896 | { |
896 | mutex_lock(&sonypi_device.lock); | 897 | mutex_lock(&sonypi_device.lock); |
897 | sonypi_device.open_count--; | 898 | sonypi_device.open_count--; |
898 | mutex_unlock(&sonypi_device.lock); | 899 | mutex_unlock(&sonypi_device.lock); |
899 | return 0; | 900 | return 0; |
900 | } | 901 | } |
901 | 902 | ||
902 | static int sonypi_misc_open(struct inode *inode, struct file *file) | 903 | static int sonypi_misc_open(struct inode *inode, struct file *file) |
903 | { | 904 | { |
904 | lock_kernel(); | 905 | lock_kernel(); |
905 | mutex_lock(&sonypi_device.lock); | 906 | mutex_lock(&sonypi_device.lock); |
906 | /* Flush input queue on first open */ | 907 | /* Flush input queue on first open */ |
907 | if (!sonypi_device.open_count) | 908 | if (!sonypi_device.open_count) |
908 | kfifo_reset(sonypi_device.fifo); | 909 | kfifo_reset(sonypi_device.fifo); |
909 | sonypi_device.open_count++; | 910 | sonypi_device.open_count++; |
910 | mutex_unlock(&sonypi_device.lock); | 911 | mutex_unlock(&sonypi_device.lock); |
911 | unlock_kernel(); | 912 | unlock_kernel(); |
912 | return 0; | 913 | return 0; |
913 | } | 914 | } |
914 | 915 | ||
915 | static ssize_t sonypi_misc_read(struct file *file, char __user *buf, | 916 | static ssize_t sonypi_misc_read(struct file *file, char __user *buf, |
916 | size_t count, loff_t *pos) | 917 | size_t count, loff_t *pos) |
917 | { | 918 | { |
918 | ssize_t ret; | 919 | ssize_t ret; |
919 | unsigned char c; | 920 | unsigned char c; |
920 | 921 | ||
921 | if ((kfifo_len(sonypi_device.fifo) == 0) && | 922 | if ((kfifo_len(sonypi_device.fifo) == 0) && |
922 | (file->f_flags & O_NONBLOCK)) | 923 | (file->f_flags & O_NONBLOCK)) |
923 | return -EAGAIN; | 924 | return -EAGAIN; |
924 | 925 | ||
925 | ret = wait_event_interruptible(sonypi_device.fifo_proc_list, | 926 | ret = wait_event_interruptible(sonypi_device.fifo_proc_list, |
926 | kfifo_len(sonypi_device.fifo) != 0); | 927 | kfifo_len(sonypi_device.fifo) != 0); |
927 | if (ret) | 928 | if (ret) |
928 | return ret; | 929 | return ret; |
929 | 930 | ||
930 | while (ret < count && | 931 | while (ret < count && |
931 | (kfifo_get(sonypi_device.fifo, &c, sizeof(c)) == sizeof(c))) { | 932 | (kfifo_get(sonypi_device.fifo, &c, sizeof(c)) == sizeof(c))) { |
932 | if (put_user(c, buf++)) | 933 | if (put_user(c, buf++)) |
933 | return -EFAULT; | 934 | return -EFAULT; |
934 | ret++; | 935 | ret++; |
935 | } | 936 | } |
936 | 937 | ||
937 | if (ret > 0) { | 938 | if (ret > 0) { |
938 | struct inode *inode = file->f_path.dentry->d_inode; | 939 | struct inode *inode = file->f_path.dentry->d_inode; |
939 | inode->i_atime = current_fs_time(inode->i_sb); | 940 | inode->i_atime = current_fs_time(inode->i_sb); |
940 | } | 941 | } |
941 | 942 | ||
942 | return ret; | 943 | return ret; |
943 | } | 944 | } |
944 | 945 | ||
945 | static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) | 946 | static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) |
946 | { | 947 | { |
947 | poll_wait(file, &sonypi_device.fifo_proc_list, wait); | 948 | poll_wait(file, &sonypi_device.fifo_proc_list, wait); |
948 | if (kfifo_len(sonypi_device.fifo)) | 949 | if (kfifo_len(sonypi_device.fifo)) |
949 | return POLLIN | POLLRDNORM; | 950 | return POLLIN | POLLRDNORM; |
950 | return 0; | 951 | return 0; |
951 | } | 952 | } |
952 | 953 | ||
953 | static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, | 954 | static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, |
954 | unsigned int cmd, unsigned long arg) | 955 | unsigned int cmd, unsigned long arg) |
955 | { | 956 | { |
956 | int ret = 0; | 957 | int ret = 0; |
957 | void __user *argp = (void __user *)arg; | 958 | void __user *argp = (void __user *)arg; |
958 | u8 val8; | 959 | u8 val8; |
959 | u16 val16; | 960 | u16 val16; |
960 | 961 | ||
961 | mutex_lock(&sonypi_device.lock); | 962 | mutex_lock(&sonypi_device.lock); |
962 | switch (cmd) { | 963 | switch (cmd) { |
963 | case SONYPI_IOCGBRT: | 964 | case SONYPI_IOCGBRT: |
964 | if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) { | 965 | if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) { |
965 | ret = -EIO; | 966 | ret = -EIO; |
966 | break; | 967 | break; |
967 | } | 968 | } |
968 | if (copy_to_user(argp, &val8, sizeof(val8))) | 969 | if (copy_to_user(argp, &val8, sizeof(val8))) |
969 | ret = -EFAULT; | 970 | ret = -EFAULT; |
970 | break; | 971 | break; |
971 | case SONYPI_IOCSBRT: | 972 | case SONYPI_IOCSBRT: |
972 | if (copy_from_user(&val8, argp, sizeof(val8))) { | 973 | if (copy_from_user(&val8, argp, sizeof(val8))) { |
973 | ret = -EFAULT; | 974 | ret = -EFAULT; |
974 | break; | 975 | break; |
975 | } | 976 | } |
976 | if (sonypi_ec_write(SONYPI_LCD_LIGHT, val8)) | 977 | if (sonypi_ec_write(SONYPI_LCD_LIGHT, val8)) |
977 | ret = -EIO; | 978 | ret = -EIO; |
978 | break; | 979 | break; |
979 | case SONYPI_IOCGBAT1CAP: | 980 | case SONYPI_IOCGBAT1CAP: |
980 | if (ec_read16(SONYPI_BAT1_FULL, &val16)) { | 981 | if (ec_read16(SONYPI_BAT1_FULL, &val16)) { |
981 | ret = -EIO; | 982 | ret = -EIO; |
982 | break; | 983 | break; |
983 | } | 984 | } |
984 | if (copy_to_user(argp, &val16, sizeof(val16))) | 985 | if (copy_to_user(argp, &val16, sizeof(val16))) |
985 | ret = -EFAULT; | 986 | ret = -EFAULT; |
986 | break; | 987 | break; |
987 | case SONYPI_IOCGBAT1REM: | 988 | case SONYPI_IOCGBAT1REM: |
988 | if (ec_read16(SONYPI_BAT1_LEFT, &val16)) { | 989 | if (ec_read16(SONYPI_BAT1_LEFT, &val16)) { |
989 | ret = -EIO; | 990 | ret = -EIO; |
990 | break; | 991 | break; |
991 | } | 992 | } |
992 | if (copy_to_user(argp, &val16, sizeof(val16))) | 993 | if (copy_to_user(argp, &val16, sizeof(val16))) |
993 | ret = -EFAULT; | 994 | ret = -EFAULT; |
994 | break; | 995 | break; |
995 | case SONYPI_IOCGBAT2CAP: | 996 | case SONYPI_IOCGBAT2CAP: |
996 | if (ec_read16(SONYPI_BAT2_FULL, &val16)) { | 997 | if (ec_read16(SONYPI_BAT2_FULL, &val16)) { |
997 | ret = -EIO; | 998 | ret = -EIO; |
998 | break; | 999 | break; |
999 | } | 1000 | } |
1000 | if (copy_to_user(argp, &val16, sizeof(val16))) | 1001 | if (copy_to_user(argp, &val16, sizeof(val16))) |
1001 | ret = -EFAULT; | 1002 | ret = -EFAULT; |
1002 | break; | 1003 | break; |
1003 | case SONYPI_IOCGBAT2REM: | 1004 | case SONYPI_IOCGBAT2REM: |
1004 | if (ec_read16(SONYPI_BAT2_LEFT, &val16)) { | 1005 | if (ec_read16(SONYPI_BAT2_LEFT, &val16)) { |
1005 | ret = -EIO; | 1006 | ret = -EIO; |
1006 | break; | 1007 | break; |
1007 | } | 1008 | } |
1008 | if (copy_to_user(argp, &val16, sizeof(val16))) | 1009 | if (copy_to_user(argp, &val16, sizeof(val16))) |
1009 | ret = -EFAULT; | 1010 | ret = -EFAULT; |
1010 | break; | 1011 | break; |
1011 | case SONYPI_IOCGBATFLAGS: | 1012 | case SONYPI_IOCGBATFLAGS: |
1012 | if (sonypi_ec_read(SONYPI_BAT_FLAGS, &val8)) { | 1013 | if (sonypi_ec_read(SONYPI_BAT_FLAGS, &val8)) { |
1013 | ret = -EIO; | 1014 | ret = -EIO; |
1014 | break; | 1015 | break; |
1015 | } | 1016 | } |
1016 | val8 &= 0x07; | 1017 | val8 &= 0x07; |
1017 | if (copy_to_user(argp, &val8, sizeof(val8))) | 1018 | if (copy_to_user(argp, &val8, sizeof(val8))) |
1018 | ret = -EFAULT; | 1019 | ret = -EFAULT; |
1019 | break; | 1020 | break; |
1020 | case SONYPI_IOCGBLUE: | 1021 | case SONYPI_IOCGBLUE: |
1021 | val8 = sonypi_device.bluetooth_power; | 1022 | val8 = sonypi_device.bluetooth_power; |
1022 | if (copy_to_user(argp, &val8, sizeof(val8))) | 1023 | if (copy_to_user(argp, &val8, sizeof(val8))) |
1023 | ret = -EFAULT; | 1024 | ret = -EFAULT; |
1024 | break; | 1025 | break; |
1025 | case SONYPI_IOCSBLUE: | 1026 | case SONYPI_IOCSBLUE: |
1026 | if (copy_from_user(&val8, argp, sizeof(val8))) { | 1027 | if (copy_from_user(&val8, argp, sizeof(val8))) { |
1027 | ret = -EFAULT; | 1028 | ret = -EFAULT; |
1028 | break; | 1029 | break; |
1029 | } | 1030 | } |
1030 | sonypi_setbluetoothpower(val8); | 1031 | sonypi_setbluetoothpower(val8); |
1031 | break; | 1032 | break; |
1032 | /* FAN Controls */ | 1033 | /* FAN Controls */ |
1033 | case SONYPI_IOCGFAN: | 1034 | case SONYPI_IOCGFAN: |
1034 | if (sonypi_ec_read(SONYPI_FAN0_STATUS, &val8)) { | 1035 | if (sonypi_ec_read(SONYPI_FAN0_STATUS, &val8)) { |
1035 | ret = -EIO; | 1036 | ret = -EIO; |
1036 | break; | 1037 | break; |
1037 | } | 1038 | } |
1038 | if (copy_to_user(argp, &val8, sizeof(val8))) | 1039 | if (copy_to_user(argp, &val8, sizeof(val8))) |
1039 | ret = -EFAULT; | 1040 | ret = -EFAULT; |
1040 | break; | 1041 | break; |
1041 | case SONYPI_IOCSFAN: | 1042 | case SONYPI_IOCSFAN: |
1042 | if (copy_from_user(&val8, argp, sizeof(val8))) { | 1043 | if (copy_from_user(&val8, argp, sizeof(val8))) { |
1043 | ret = -EFAULT; | 1044 | ret = -EFAULT; |
1044 | break; | 1045 | break; |
1045 | } | 1046 | } |
1046 | if (sonypi_ec_write(SONYPI_FAN0_STATUS, val8)) | 1047 | if (sonypi_ec_write(SONYPI_FAN0_STATUS, val8)) |
1047 | ret = -EIO; | 1048 | ret = -EIO; |
1048 | break; | 1049 | break; |
1049 | /* GET Temperature (useful under APM) */ | 1050 | /* GET Temperature (useful under APM) */ |
1050 | case SONYPI_IOCGTEMP: | 1051 | case SONYPI_IOCGTEMP: |
1051 | if (sonypi_ec_read(SONYPI_TEMP_STATUS, &val8)) { | 1052 | if (sonypi_ec_read(SONYPI_TEMP_STATUS, &val8)) { |
1052 | ret = -EIO; | 1053 | ret = -EIO; |
1053 | break; | 1054 | break; |
1054 | } | 1055 | } |
1055 | if (copy_to_user(argp, &val8, sizeof(val8))) | 1056 | if (copy_to_user(argp, &val8, sizeof(val8))) |
1056 | ret = -EFAULT; | 1057 | ret = -EFAULT; |
1057 | break; | 1058 | break; |
1058 | default: | 1059 | default: |
1059 | ret = -EINVAL; | 1060 | ret = -EINVAL; |
1060 | } | 1061 | } |
1061 | mutex_unlock(&sonypi_device.lock); | 1062 | mutex_unlock(&sonypi_device.lock); |
1062 | return ret; | 1063 | return ret; |
1063 | } | 1064 | } |
1064 | 1065 | ||
1065 | static const struct file_operations sonypi_misc_fops = { | 1066 | static const struct file_operations sonypi_misc_fops = { |
1066 | .owner = THIS_MODULE, | 1067 | .owner = THIS_MODULE, |
1067 | .read = sonypi_misc_read, | 1068 | .read = sonypi_misc_read, |
1068 | .poll = sonypi_misc_poll, | 1069 | .poll = sonypi_misc_poll, |
1069 | .open = sonypi_misc_open, | 1070 | .open = sonypi_misc_open, |
1070 | .release = sonypi_misc_release, | 1071 | .release = sonypi_misc_release, |
1071 | .fasync = sonypi_misc_fasync, | 1072 | .fasync = sonypi_misc_fasync, |
1072 | .ioctl = sonypi_misc_ioctl, | 1073 | .ioctl = sonypi_misc_ioctl, |
1073 | }; | 1074 | }; |
1074 | 1075 | ||
1075 | static struct miscdevice sonypi_misc_device = { | 1076 | static struct miscdevice sonypi_misc_device = { |
1076 | .minor = MISC_DYNAMIC_MINOR, | 1077 | .minor = MISC_DYNAMIC_MINOR, |
1077 | .name = "sonypi", | 1078 | .name = "sonypi", |
1078 | .fops = &sonypi_misc_fops, | 1079 | .fops = &sonypi_misc_fops, |
1079 | }; | 1080 | }; |
1080 | 1081 | ||
1081 | static void sonypi_enable(unsigned int camera_on) | 1082 | static void sonypi_enable(unsigned int camera_on) |
1082 | { | 1083 | { |
1083 | switch (sonypi_device.model) { | 1084 | switch (sonypi_device.model) { |
1084 | case SONYPI_DEVICE_MODEL_TYPE1: | 1085 | case SONYPI_DEVICE_MODEL_TYPE1: |
1085 | sonypi_type1_srs(); | 1086 | sonypi_type1_srs(); |
1086 | break; | 1087 | break; |
1087 | case SONYPI_DEVICE_MODEL_TYPE2: | 1088 | case SONYPI_DEVICE_MODEL_TYPE2: |
1088 | sonypi_type2_srs(); | 1089 | sonypi_type2_srs(); |
1089 | break; | 1090 | break; |
1090 | case SONYPI_DEVICE_MODEL_TYPE3: | 1091 | case SONYPI_DEVICE_MODEL_TYPE3: |
1091 | sonypi_type3_srs(); | 1092 | sonypi_type3_srs(); |
1092 | break; | 1093 | break; |
1093 | } | 1094 | } |
1094 | 1095 | ||
1095 | sonypi_call1(0x82); | 1096 | sonypi_call1(0x82); |
1096 | sonypi_call2(0x81, 0xff); | 1097 | sonypi_call2(0x81, 0xff); |
1097 | sonypi_call1(compat ? 0x92 : 0x82); | 1098 | sonypi_call1(compat ? 0x92 : 0x82); |
1098 | 1099 | ||
1099 | /* Enable ACPI mode to get Fn key events */ | 1100 | /* Enable ACPI mode to get Fn key events */ |
1100 | if (!SONYPI_ACPI_ACTIVE && fnkeyinit) | 1101 | if (!SONYPI_ACPI_ACTIVE && fnkeyinit) |
1101 | outb(0xf0, 0xb2); | 1102 | outb(0xf0, 0xb2); |
1102 | 1103 | ||
1103 | if (camera && camera_on) | 1104 | if (camera && camera_on) |
1104 | sonypi_camera_on(); | 1105 | sonypi_camera_on(); |
1105 | } | 1106 | } |
1106 | 1107 | ||
1107 | static int sonypi_disable(void) | 1108 | static int sonypi_disable(void) |
1108 | { | 1109 | { |
1109 | sonypi_call2(0x81, 0); /* make sure we don't get any more events */ | 1110 | sonypi_call2(0x81, 0); /* make sure we don't get any more events */ |
1110 | if (camera) | 1111 | if (camera) |
1111 | sonypi_camera_off(); | 1112 | sonypi_camera_off(); |
1112 | 1113 | ||
1113 | /* disable ACPI mode */ | 1114 | /* disable ACPI mode */ |
1114 | if (!SONYPI_ACPI_ACTIVE && fnkeyinit) | 1115 | if (!SONYPI_ACPI_ACTIVE && fnkeyinit) |
1115 | outb(0xf1, 0xb2); | 1116 | outb(0xf1, 0xb2); |
1116 | 1117 | ||
1117 | switch (sonypi_device.model) { | 1118 | switch (sonypi_device.model) { |
1118 | case SONYPI_DEVICE_MODEL_TYPE1: | 1119 | case SONYPI_DEVICE_MODEL_TYPE1: |
1119 | sonypi_type1_dis(); | 1120 | sonypi_type1_dis(); |
1120 | break; | 1121 | break; |
1121 | case SONYPI_DEVICE_MODEL_TYPE2: | 1122 | case SONYPI_DEVICE_MODEL_TYPE2: |
1122 | sonypi_type2_dis(); | 1123 | sonypi_type2_dis(); |
1123 | break; | 1124 | break; |
1124 | case SONYPI_DEVICE_MODEL_TYPE3: | 1125 | case SONYPI_DEVICE_MODEL_TYPE3: |
1125 | sonypi_type3_dis(); | 1126 | sonypi_type3_dis(); |
1126 | break; | 1127 | break; |
1127 | } | 1128 | } |
1128 | 1129 | ||
1129 | return 0; | 1130 | return 0; |
1130 | } | 1131 | } |
1131 | 1132 | ||
1132 | #ifdef CONFIG_ACPI | 1133 | #ifdef CONFIG_ACPI |
1133 | static int sonypi_acpi_add(struct acpi_device *device) | 1134 | static int sonypi_acpi_add(struct acpi_device *device) |
1134 | { | 1135 | { |
1135 | sonypi_acpi_device = device; | 1136 | sonypi_acpi_device = device; |
1136 | strcpy(acpi_device_name(device), "Sony laptop hotkeys"); | 1137 | strcpy(acpi_device_name(device), "Sony laptop hotkeys"); |
1137 | strcpy(acpi_device_class(device), "sony/hotkey"); | 1138 | strcpy(acpi_device_class(device), "sony/hotkey"); |
1138 | return 0; | 1139 | return 0; |
1139 | } | 1140 | } |
1140 | 1141 | ||
1141 | static int sonypi_acpi_remove(struct acpi_device *device, int type) | 1142 | static int sonypi_acpi_remove(struct acpi_device *device, int type) |
1142 | { | 1143 | { |
1143 | sonypi_acpi_device = NULL; | 1144 | sonypi_acpi_device = NULL; |
1144 | return 0; | 1145 | return 0; |
1145 | } | 1146 | } |
1146 | 1147 | ||
1147 | static const struct acpi_device_id sonypi_device_ids[] = { | 1148 | static const struct acpi_device_id sonypi_device_ids[] = { |
1148 | {"SNY6001", 0}, | 1149 | {"SNY6001", 0}, |
1149 | {"", 0}, | 1150 | {"", 0}, |
1150 | }; | 1151 | }; |
1151 | 1152 | ||
1152 | static struct acpi_driver sonypi_acpi_driver = { | 1153 | static struct acpi_driver sonypi_acpi_driver = { |
1153 | .name = "sonypi", | 1154 | .name = "sonypi", |
1154 | .class = "hkey", | 1155 | .class = "hkey", |
1155 | .ids = sonypi_device_ids, | 1156 | .ids = sonypi_device_ids, |
1156 | .ops = { | 1157 | .ops = { |
1157 | .add = sonypi_acpi_add, | 1158 | .add = sonypi_acpi_add, |
1158 | .remove = sonypi_acpi_remove, | 1159 | .remove = sonypi_acpi_remove, |
1159 | }, | 1160 | }, |
1160 | }; | 1161 | }; |
1161 | #endif | 1162 | #endif |
1162 | 1163 | ||
1163 | static int __devinit sonypi_create_input_devices(struct platform_device *pdev) | 1164 | static int __devinit sonypi_create_input_devices(struct platform_device *pdev) |
1164 | { | 1165 | { |
1165 | struct input_dev *jog_dev; | 1166 | struct input_dev *jog_dev; |
1166 | struct input_dev *key_dev; | 1167 | struct input_dev *key_dev; |
1167 | int i; | 1168 | int i; |
1168 | int error; | 1169 | int error; |
1169 | 1170 | ||
1170 | sonypi_device.input_jog_dev = jog_dev = input_allocate_device(); | 1171 | sonypi_device.input_jog_dev = jog_dev = input_allocate_device(); |
1171 | if (!jog_dev) | 1172 | if (!jog_dev) |
1172 | return -ENOMEM; | 1173 | return -ENOMEM; |
1173 | 1174 | ||
1174 | jog_dev->name = "Sony Vaio Jogdial"; | 1175 | jog_dev->name = "Sony Vaio Jogdial"; |
1175 | jog_dev->id.bustype = BUS_ISA; | 1176 | jog_dev->id.bustype = BUS_ISA; |
1176 | jog_dev->id.vendor = PCI_VENDOR_ID_SONY; | 1177 | jog_dev->id.vendor = PCI_VENDOR_ID_SONY; |
1177 | jog_dev->dev.parent = &pdev->dev; | 1178 | jog_dev->dev.parent = &pdev->dev; |
1178 | 1179 | ||
1179 | jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); | 1180 | jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); |
1180 | jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE); | 1181 | jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE); |
1181 | jog_dev->relbit[0] = BIT_MASK(REL_WHEEL); | 1182 | jog_dev->relbit[0] = BIT_MASK(REL_WHEEL); |
1182 | 1183 | ||
1183 | sonypi_device.input_key_dev = key_dev = input_allocate_device(); | 1184 | sonypi_device.input_key_dev = key_dev = input_allocate_device(); |
1184 | if (!key_dev) { | 1185 | if (!key_dev) { |
1185 | error = -ENOMEM; | 1186 | error = -ENOMEM; |
1186 | goto err_free_jogdev; | 1187 | goto err_free_jogdev; |
1187 | } | 1188 | } |
1188 | 1189 | ||
1189 | key_dev->name = "Sony Vaio Keys"; | 1190 | key_dev->name = "Sony Vaio Keys"; |
1190 | key_dev->id.bustype = BUS_ISA; | 1191 | key_dev->id.bustype = BUS_ISA; |
1191 | key_dev->id.vendor = PCI_VENDOR_ID_SONY; | 1192 | key_dev->id.vendor = PCI_VENDOR_ID_SONY; |
1192 | key_dev->dev.parent = &pdev->dev; | 1193 | key_dev->dev.parent = &pdev->dev; |
1193 | 1194 | ||
1194 | /* Initialize the Input Drivers: special keys */ | 1195 | /* Initialize the Input Drivers: special keys */ |
1195 | key_dev->evbit[0] = BIT_MASK(EV_KEY); | 1196 | key_dev->evbit[0] = BIT_MASK(EV_KEY); |
1196 | for (i = 0; sonypi_inputkeys[i].sonypiev; i++) | 1197 | for (i = 0; sonypi_inputkeys[i].sonypiev; i++) |
1197 | if (sonypi_inputkeys[i].inputev) | 1198 | if (sonypi_inputkeys[i].inputev) |
1198 | set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit); | 1199 | set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit); |
1199 | 1200 | ||
1200 | error = input_register_device(jog_dev); | 1201 | error = input_register_device(jog_dev); |
1201 | if (error) | 1202 | if (error) |
1202 | goto err_free_keydev; | 1203 | goto err_free_keydev; |
1203 | 1204 | ||
1204 | error = input_register_device(key_dev); | 1205 | error = input_register_device(key_dev); |
1205 | if (error) | 1206 | if (error) |
1206 | goto err_unregister_jogdev; | 1207 | goto err_unregister_jogdev; |
1207 | 1208 | ||
1208 | return 0; | 1209 | return 0; |
1209 | 1210 | ||
1210 | err_unregister_jogdev: | 1211 | err_unregister_jogdev: |
1211 | input_unregister_device(jog_dev); | 1212 | input_unregister_device(jog_dev); |
1212 | /* Set to NULL so we don't free it again below */ | 1213 | /* Set to NULL so we don't free it again below */ |
1213 | jog_dev = NULL; | 1214 | jog_dev = NULL; |
1214 | err_free_keydev: | 1215 | err_free_keydev: |
1215 | input_free_device(key_dev); | 1216 | input_free_device(key_dev); |
1216 | sonypi_device.input_key_dev = NULL; | 1217 | sonypi_device.input_key_dev = NULL; |
1217 | err_free_jogdev: | 1218 | err_free_jogdev: |
1218 | input_free_device(jog_dev); | 1219 | input_free_device(jog_dev); |
1219 | sonypi_device.input_jog_dev = NULL; | 1220 | sonypi_device.input_jog_dev = NULL; |
1220 | 1221 | ||
1221 | return error; | 1222 | return error; |
1222 | } | 1223 | } |
1223 | 1224 | ||
1224 | static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, | 1225 | static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, |
1225 | const struct sonypi_ioport_list *ioport_list) | 1226 | const struct sonypi_ioport_list *ioport_list) |
1226 | { | 1227 | { |
1227 | /* try to detect if sony-laptop is being used and thus | 1228 | /* try to detect if sony-laptop is being used and thus |
1228 | * has already requested one of the known ioports. | 1229 | * has already requested one of the known ioports. |
1229 | * As in the deprecated check_region this is racy has we have | 1230 | * As in the deprecated check_region this is racy has we have |
1230 | * multiple ioports available and one of them can be requested | 1231 | * multiple ioports available and one of them can be requested |
1231 | * between this check and the subsequent request. Anyway, as an | 1232 | * between this check and the subsequent request. Anyway, as an |
1232 | * attempt to be some more user-friendly as we currently are, | 1233 | * attempt to be some more user-friendly as we currently are, |
1233 | * this is enough. | 1234 | * this is enough. |
1234 | */ | 1235 | */ |
1235 | const struct sonypi_ioport_list *check = ioport_list; | 1236 | const struct sonypi_ioport_list *check = ioport_list; |
1236 | while (check_ioport && check->port1) { | 1237 | while (check_ioport && check->port1) { |
1237 | if (!request_region(check->port1, | 1238 | if (!request_region(check->port1, |
1238 | sonypi_device.region_size, | 1239 | sonypi_device.region_size, |
1239 | "Sony Programable I/O Device Check")) { | 1240 | "Sony Programable I/O Device Check")) { |
1240 | printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? " | 1241 | printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? " |
1241 | "if not use check_ioport=0\n", | 1242 | "if not use check_ioport=0\n", |
1242 | check->port1); | 1243 | check->port1); |
1243 | return -EBUSY; | 1244 | return -EBUSY; |
1244 | } | 1245 | } |
1245 | release_region(check->port1, sonypi_device.region_size); | 1246 | release_region(check->port1, sonypi_device.region_size); |
1246 | check++; | 1247 | check++; |
1247 | } | 1248 | } |
1248 | 1249 | ||
1249 | while (ioport_list->port1) { | 1250 | while (ioport_list->port1) { |
1250 | 1251 | ||
1251 | if (request_region(ioport_list->port1, | 1252 | if (request_region(ioport_list->port1, |
1252 | sonypi_device.region_size, | 1253 | sonypi_device.region_size, |
1253 | "Sony Programable I/O Device")) { | 1254 | "Sony Programable I/O Device")) { |
1254 | dev->ioport1 = ioport_list->port1; | 1255 | dev->ioport1 = ioport_list->port1; |
1255 | dev->ioport2 = ioport_list->port2; | 1256 | dev->ioport2 = ioport_list->port2; |
1256 | return 0; | 1257 | return 0; |
1257 | } | 1258 | } |
1258 | ioport_list++; | 1259 | ioport_list++; |
1259 | } | 1260 | } |
1260 | 1261 | ||
1261 | return -EBUSY; | 1262 | return -EBUSY; |
1262 | } | 1263 | } |
1263 | 1264 | ||
1264 | static int __devinit sonypi_setup_irq(struct sonypi_device *dev, | 1265 | static int __devinit sonypi_setup_irq(struct sonypi_device *dev, |
1265 | const struct sonypi_irq_list *irq_list) | 1266 | const struct sonypi_irq_list *irq_list) |
1266 | { | 1267 | { |
1267 | while (irq_list->irq) { | 1268 | while (irq_list->irq) { |
1268 | 1269 | ||
1269 | if (!request_irq(irq_list->irq, sonypi_irq, | 1270 | if (!request_irq(irq_list->irq, sonypi_irq, |
1270 | IRQF_SHARED, "sonypi", sonypi_irq)) { | 1271 | IRQF_SHARED, "sonypi", sonypi_irq)) { |
1271 | dev->irq = irq_list->irq; | 1272 | dev->irq = irq_list->irq; |
1272 | dev->bits = irq_list->bits; | 1273 | dev->bits = irq_list->bits; |
1273 | return 0; | 1274 | return 0; |
1274 | } | 1275 | } |
1275 | irq_list++; | 1276 | irq_list++; |
1276 | } | 1277 | } |
1277 | 1278 | ||
1278 | return -EBUSY; | 1279 | return -EBUSY; |
1279 | } | 1280 | } |
1280 | 1281 | ||
1281 | static void __devinit sonypi_display_info(void) | 1282 | static void __devinit sonypi_display_info(void) |
1282 | { | 1283 | { |
1283 | printk(KERN_INFO "sonypi: detected type%d model, " | 1284 | printk(KERN_INFO "sonypi: detected type%d model, " |
1284 | "verbose = %d, fnkeyinit = %s, camera = %s, " | 1285 | "verbose = %d, fnkeyinit = %s, camera = %s, " |
1285 | "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", | 1286 | "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", |
1286 | sonypi_device.model, | 1287 | sonypi_device.model, |
1287 | verbose, | 1288 | verbose, |
1288 | fnkeyinit ? "on" : "off", | 1289 | fnkeyinit ? "on" : "off", |
1289 | camera ? "on" : "off", | 1290 | camera ? "on" : "off", |
1290 | compat ? "on" : "off", | 1291 | compat ? "on" : "off", |
1291 | mask, | 1292 | mask, |
1292 | useinput ? "on" : "off", | 1293 | useinput ? "on" : "off", |
1293 | SONYPI_ACPI_ACTIVE ? "on" : "off"); | 1294 | SONYPI_ACPI_ACTIVE ? "on" : "off"); |
1294 | printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n", | 1295 | printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n", |
1295 | sonypi_device.irq, | 1296 | sonypi_device.irq, |
1296 | sonypi_device.ioport1, sonypi_device.ioport2); | 1297 | sonypi_device.ioport1, sonypi_device.ioport2); |
1297 | 1298 | ||
1298 | if (minor == -1) | 1299 | if (minor == -1) |
1299 | printk(KERN_INFO "sonypi: device allocated minor is %d\n", | 1300 | printk(KERN_INFO "sonypi: device allocated minor is %d\n", |
1300 | sonypi_misc_device.minor); | 1301 | sonypi_misc_device.minor); |
1301 | } | 1302 | } |
1302 | 1303 | ||
1303 | static int __devinit sonypi_probe(struct platform_device *dev) | 1304 | static int __devinit sonypi_probe(struct platform_device *dev) |
1304 | { | 1305 | { |
1305 | const struct sonypi_ioport_list *ioport_list; | 1306 | const struct sonypi_ioport_list *ioport_list; |
1306 | const struct sonypi_irq_list *irq_list; | 1307 | const struct sonypi_irq_list *irq_list; |
1307 | struct pci_dev *pcidev; | 1308 | struct pci_dev *pcidev; |
1308 | int error; | 1309 | int error; |
1309 | 1310 | ||
1310 | printk(KERN_WARNING "sonypi: please try the sony-laptop module instead " | 1311 | printk(KERN_WARNING "sonypi: please try the sony-laptop module instead " |
1311 | "and report failures, see also " | 1312 | "and report failures, see also " |
1312 | "http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n"); | 1313 | "http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n"); |
1313 | 1314 | ||
1314 | spin_lock_init(&sonypi_device.fifo_lock); | 1315 | spin_lock_init(&sonypi_device.fifo_lock); |
1315 | sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, | 1316 | sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, |
1316 | &sonypi_device.fifo_lock); | 1317 | &sonypi_device.fifo_lock); |
1317 | if (IS_ERR(sonypi_device.fifo)) { | 1318 | if (IS_ERR(sonypi_device.fifo)) { |
1318 | printk(KERN_ERR "sonypi: kfifo_alloc failed\n"); | 1319 | printk(KERN_ERR "sonypi: kfifo_alloc failed\n"); |
1319 | return PTR_ERR(sonypi_device.fifo); | 1320 | return PTR_ERR(sonypi_device.fifo); |
1320 | } | 1321 | } |
1321 | 1322 | ||
1322 | init_waitqueue_head(&sonypi_device.fifo_proc_list); | 1323 | init_waitqueue_head(&sonypi_device.fifo_proc_list); |
1323 | mutex_init(&sonypi_device.lock); | 1324 | mutex_init(&sonypi_device.lock); |
1324 | sonypi_device.bluetooth_power = -1; | 1325 | sonypi_device.bluetooth_power = -1; |
1325 | 1326 | ||
1326 | if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, | 1327 | if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, |
1327 | PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) | 1328 | PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) |
1328 | sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1; | 1329 | sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1; |
1329 | else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, | 1330 | else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, |
1330 | PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) | 1331 | PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) |
1331 | sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; | 1332 | sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; |
1332 | else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, | 1333 | else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, |
1333 | PCI_DEVICE_ID_INTEL_ICH7_1, NULL))) | 1334 | PCI_DEVICE_ID_INTEL_ICH7_1, NULL))) |
1334 | sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; | 1335 | sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; |
1335 | else | 1336 | else |
1336 | sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; | 1337 | sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; |
1337 | 1338 | ||
1338 | if (pcidev && pci_enable_device(pcidev)) { | 1339 | if (pcidev && pci_enable_device(pcidev)) { |
1339 | printk(KERN_ERR "sonypi: pci_enable_device failed\n"); | 1340 | printk(KERN_ERR "sonypi: pci_enable_device failed\n"); |
1340 | error = -EIO; | 1341 | error = -EIO; |
1341 | goto err_put_pcidev; | 1342 | goto err_put_pcidev; |
1342 | } | 1343 | } |
1343 | 1344 | ||
1344 | sonypi_device.dev = pcidev; | 1345 | sonypi_device.dev = pcidev; |
1345 | 1346 | ||
1346 | if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) { | 1347 | if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) { |
1347 | ioport_list = sonypi_type1_ioport_list; | 1348 | ioport_list = sonypi_type1_ioport_list; |
1348 | sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE; | 1349 | sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE; |
1349 | sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET; | 1350 | sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET; |
1350 | irq_list = sonypi_type1_irq_list; | 1351 | irq_list = sonypi_type1_irq_list; |
1351 | } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { | 1352 | } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { |
1352 | ioport_list = sonypi_type2_ioport_list; | 1353 | ioport_list = sonypi_type2_ioport_list; |
1353 | sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE; | 1354 | sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE; |
1354 | sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET; | 1355 | sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET; |
1355 | irq_list = sonypi_type2_irq_list; | 1356 | irq_list = sonypi_type2_irq_list; |
1356 | } else { | 1357 | } else { |
1357 | ioport_list = sonypi_type3_ioport_list; | 1358 | ioport_list = sonypi_type3_ioport_list; |
1358 | sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE; | 1359 | sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE; |
1359 | sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET; | 1360 | sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET; |
1360 | irq_list = sonypi_type3_irq_list; | 1361 | irq_list = sonypi_type3_irq_list; |
1361 | } | 1362 | } |
1362 | 1363 | ||
1363 | error = sonypi_setup_ioports(&sonypi_device, ioport_list); | 1364 | error = sonypi_setup_ioports(&sonypi_device, ioport_list); |
1364 | if (error) { | 1365 | if (error) { |
1365 | printk(KERN_ERR "sonypi: failed to request ioports\n"); | 1366 | printk(KERN_ERR "sonypi: failed to request ioports\n"); |
1366 | goto err_disable_pcidev; | 1367 | goto err_disable_pcidev; |
1367 | } | 1368 | } |
1368 | 1369 | ||
1369 | error = sonypi_setup_irq(&sonypi_device, irq_list); | 1370 | error = sonypi_setup_irq(&sonypi_device, irq_list); |
1370 | if (error) { | 1371 | if (error) { |
1371 | printk(KERN_ERR "sonypi: request_irq failed\n"); | 1372 | printk(KERN_ERR "sonypi: request_irq failed\n"); |
1372 | goto err_free_ioports; | 1373 | goto err_free_ioports; |
1373 | } | 1374 | } |
1374 | 1375 | ||
1375 | if (minor != -1) | 1376 | if (minor != -1) |
1376 | sonypi_misc_device.minor = minor; | 1377 | sonypi_misc_device.minor = minor; |
1377 | error = misc_register(&sonypi_misc_device); | 1378 | error = misc_register(&sonypi_misc_device); |
1378 | if (error) { | 1379 | if (error) { |
1379 | printk(KERN_ERR "sonypi: misc_register failed\n"); | 1380 | printk(KERN_ERR "sonypi: misc_register failed\n"); |
1380 | goto err_free_irq; | 1381 | goto err_free_irq; |
1381 | } | 1382 | } |
1382 | 1383 | ||
1383 | sonypi_display_info(); | 1384 | sonypi_display_info(); |
1384 | 1385 | ||
1385 | if (useinput) { | 1386 | if (useinput) { |
1386 | 1387 | ||
1387 | error = sonypi_create_input_devices(dev); | 1388 | error = sonypi_create_input_devices(dev); |
1388 | if (error) { | 1389 | if (error) { |
1389 | printk(KERN_ERR | 1390 | printk(KERN_ERR |
1390 | "sonypi: failed to create input devices\n"); | 1391 | "sonypi: failed to create input devices\n"); |
1391 | goto err_miscdev_unregister; | 1392 | goto err_miscdev_unregister; |
1392 | } | 1393 | } |
1393 | 1394 | ||
1394 | spin_lock_init(&sonypi_device.input_fifo_lock); | 1395 | spin_lock_init(&sonypi_device.input_fifo_lock); |
1395 | sonypi_device.input_fifo = | 1396 | sonypi_device.input_fifo = |
1396 | kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, | 1397 | kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, |
1397 | &sonypi_device.input_fifo_lock); | 1398 | &sonypi_device.input_fifo_lock); |
1398 | if (IS_ERR(sonypi_device.input_fifo)) { | 1399 | if (IS_ERR(sonypi_device.input_fifo)) { |
1399 | printk(KERN_ERR "sonypi: kfifo_alloc failed\n"); | 1400 | printk(KERN_ERR "sonypi: kfifo_alloc failed\n"); |
1400 | error = PTR_ERR(sonypi_device.input_fifo); | 1401 | error = PTR_ERR(sonypi_device.input_fifo); |
1401 | goto err_inpdev_unregister; | 1402 | goto err_inpdev_unregister; |
1402 | } | 1403 | } |
1403 | 1404 | ||
1404 | INIT_WORK(&sonypi_device.input_work, input_keyrelease); | 1405 | INIT_WORK(&sonypi_device.input_work, input_keyrelease); |
1405 | } | 1406 | } |
1406 | 1407 | ||
1407 | sonypi_enable(0); | 1408 | sonypi_enable(0); |
1408 | 1409 | ||
1409 | return 0; | 1410 | return 0; |
1410 | 1411 | ||
1411 | err_inpdev_unregister: | 1412 | err_inpdev_unregister: |
1412 | input_unregister_device(sonypi_device.input_key_dev); | 1413 | input_unregister_device(sonypi_device.input_key_dev); |
1413 | input_unregister_device(sonypi_device.input_jog_dev); | 1414 | input_unregister_device(sonypi_device.input_jog_dev); |
1414 | err_miscdev_unregister: | 1415 | err_miscdev_unregister: |
1415 | misc_deregister(&sonypi_misc_device); | 1416 | misc_deregister(&sonypi_misc_device); |
1416 | err_free_irq: | 1417 | err_free_irq: |
1417 | free_irq(sonypi_device.irq, sonypi_irq); | 1418 | free_irq(sonypi_device.irq, sonypi_irq); |
1418 | err_free_ioports: | 1419 | err_free_ioports: |
1419 | release_region(sonypi_device.ioport1, sonypi_device.region_size); | 1420 | release_region(sonypi_device.ioport1, sonypi_device.region_size); |
1420 | err_disable_pcidev: | 1421 | err_disable_pcidev: |
1421 | if (pcidev) | 1422 | if (pcidev) |
1422 | pci_disable_device(pcidev); | 1423 | pci_disable_device(pcidev); |
1423 | err_put_pcidev: | 1424 | err_put_pcidev: |
1424 | pci_dev_put(pcidev); | 1425 | pci_dev_put(pcidev); |
1425 | kfifo_free(sonypi_device.fifo); | 1426 | kfifo_free(sonypi_device.fifo); |
1426 | 1427 | ||
1427 | return error; | 1428 | return error; |
1428 | } | 1429 | } |
1429 | 1430 | ||
1430 | static int __devexit sonypi_remove(struct platform_device *dev) | 1431 | static int __devexit sonypi_remove(struct platform_device *dev) |
1431 | { | 1432 | { |
1432 | sonypi_disable(); | 1433 | sonypi_disable(); |
1433 | 1434 | ||
1434 | synchronize_irq(sonypi_device.irq); | 1435 | synchronize_irq(sonypi_device.irq); |
1435 | flush_scheduled_work(); | 1436 | flush_scheduled_work(); |
1436 | 1437 | ||
1437 | if (useinput) { | 1438 | if (useinput) { |
1438 | input_unregister_device(sonypi_device.input_key_dev); | 1439 | input_unregister_device(sonypi_device.input_key_dev); |
1439 | input_unregister_device(sonypi_device.input_jog_dev); | 1440 | input_unregister_device(sonypi_device.input_jog_dev); |
1440 | kfifo_free(sonypi_device.input_fifo); | 1441 | kfifo_free(sonypi_device.input_fifo); |
1441 | } | 1442 | } |
1442 | 1443 | ||
1443 | misc_deregister(&sonypi_misc_device); | 1444 | misc_deregister(&sonypi_misc_device); |
1444 | 1445 | ||
1445 | free_irq(sonypi_device.irq, sonypi_irq); | 1446 | free_irq(sonypi_device.irq, sonypi_irq); |
1446 | release_region(sonypi_device.ioport1, sonypi_device.region_size); | 1447 | release_region(sonypi_device.ioport1, sonypi_device.region_size); |
1447 | 1448 | ||
1448 | if (sonypi_device.dev) { | 1449 | if (sonypi_device.dev) { |
1449 | pci_disable_device(sonypi_device.dev); | 1450 | pci_disable_device(sonypi_device.dev); |
1450 | pci_dev_put(sonypi_device.dev); | 1451 | pci_dev_put(sonypi_device.dev); |
1451 | } | 1452 | } |
1452 | 1453 | ||
1453 | kfifo_free(sonypi_device.fifo); | 1454 | kfifo_free(sonypi_device.fifo); |
1454 | 1455 | ||
1455 | return 0; | 1456 | return 0; |
1456 | } | 1457 | } |
1457 | 1458 | ||
1458 | #ifdef CONFIG_PM | 1459 | #ifdef CONFIG_PM |
1459 | static int old_camera_power; | 1460 | static int old_camera_power; |
1460 | 1461 | ||
1461 | static int sonypi_suspend(struct platform_device *dev, pm_message_t state) | 1462 | static int sonypi_suspend(struct platform_device *dev, pm_message_t state) |
1462 | { | 1463 | { |
1463 | old_camera_power = sonypi_device.camera_power; | 1464 | old_camera_power = sonypi_device.camera_power; |
1464 | sonypi_disable(); | 1465 | sonypi_disable(); |
1465 | 1466 | ||
1466 | return 0; | 1467 | return 0; |
1467 | } | 1468 | } |
1468 | 1469 | ||
1469 | static int sonypi_resume(struct platform_device *dev) | 1470 | static int sonypi_resume(struct platform_device *dev) |
1470 | { | 1471 | { |
1471 | sonypi_enable(old_camera_power); | 1472 | sonypi_enable(old_camera_power); |
1472 | return 0; | 1473 | return 0; |
1473 | } | 1474 | } |
1474 | #else | 1475 | #else |
1475 | #define sonypi_suspend NULL | 1476 | #define sonypi_suspend NULL |
1476 | #define sonypi_resume NULL | 1477 | #define sonypi_resume NULL |
1477 | #endif | 1478 | #endif |
1478 | 1479 | ||
1479 | static void sonypi_shutdown(struct platform_device *dev) | 1480 | static void sonypi_shutdown(struct platform_device *dev) |
1480 | { | 1481 | { |
1481 | sonypi_disable(); | 1482 | sonypi_disable(); |
1482 | } | 1483 | } |
1483 | 1484 | ||
1484 | static struct platform_driver sonypi_driver = { | 1485 | static struct platform_driver sonypi_driver = { |
1485 | .driver = { | 1486 | .driver = { |
1486 | .name = "sonypi", | 1487 | .name = "sonypi", |
1487 | .owner = THIS_MODULE, | 1488 | .owner = THIS_MODULE, |
1488 | }, | 1489 | }, |
1489 | .probe = sonypi_probe, | 1490 | .probe = sonypi_probe, |
1490 | .remove = __devexit_p(sonypi_remove), | 1491 | .remove = __devexit_p(sonypi_remove), |
1491 | .shutdown = sonypi_shutdown, | 1492 | .shutdown = sonypi_shutdown, |
1492 | .suspend = sonypi_suspend, | 1493 | .suspend = sonypi_suspend, |
1493 | .resume = sonypi_resume, | 1494 | .resume = sonypi_resume, |
1494 | }; | 1495 | }; |
1495 | 1496 | ||
1496 | static struct platform_device *sonypi_platform_device; | 1497 | static struct platform_device *sonypi_platform_device; |
1497 | 1498 | ||
1498 | static struct dmi_system_id __initdata sonypi_dmi_table[] = { | 1499 | static struct dmi_system_id __initdata sonypi_dmi_table[] = { |
1499 | { | 1500 | { |
1500 | .ident = "Sony Vaio", | 1501 | .ident = "Sony Vaio", |
1501 | .matches = { | 1502 | .matches = { |
1502 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | 1503 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
1503 | DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"), | 1504 | DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"), |
1504 | }, | 1505 | }, |
1505 | }, | 1506 | }, |
1506 | { | 1507 | { |
1507 | .ident = "Sony Vaio", | 1508 | .ident = "Sony Vaio", |
1508 | .matches = { | 1509 | .matches = { |
1509 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | 1510 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
1510 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"), | 1511 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"), |
1511 | }, | 1512 | }, |
1512 | }, | 1513 | }, |
1513 | { } | 1514 | { } |
1514 | }; | 1515 | }; |
1515 | 1516 | ||
1516 | static int __init sonypi_init(void) | 1517 | static int __init sonypi_init(void) |
1517 | { | 1518 | { |
1518 | int error; | 1519 | int error; |
1519 | 1520 | ||
1520 | printk(KERN_INFO | 1521 | printk(KERN_INFO |
1521 | "sonypi: Sony Programmable I/O Controller Driver v%s.\n", | 1522 | "sonypi: Sony Programmable I/O Controller Driver v%s.\n", |
1522 | SONYPI_DRIVER_VERSION); | 1523 | SONYPI_DRIVER_VERSION); |
1523 | 1524 | ||
1524 | if (!dmi_check_system(sonypi_dmi_table)) | 1525 | if (!dmi_check_system(sonypi_dmi_table)) |
1525 | return -ENODEV; | 1526 | return -ENODEV; |
1526 | 1527 | ||
1527 | error = platform_driver_register(&sonypi_driver); | 1528 | error = platform_driver_register(&sonypi_driver); |
1528 | if (error) | 1529 | if (error) |
1529 | return error; | 1530 | return error; |
1530 | 1531 | ||
1531 | sonypi_platform_device = platform_device_alloc("sonypi", -1); | 1532 | sonypi_platform_device = platform_device_alloc("sonypi", -1); |
1532 | if (!sonypi_platform_device) { | 1533 | if (!sonypi_platform_device) { |
1533 | error = -ENOMEM; | 1534 | error = -ENOMEM; |
1534 | goto err_driver_unregister; | 1535 | goto err_driver_unregister; |
1535 | } | 1536 | } |
1536 | 1537 | ||
1537 | error = platform_device_add(sonypi_platform_device); | 1538 | error = platform_device_add(sonypi_platform_device); |
1538 | if (error) | 1539 | if (error) |
1539 | goto err_free_device; | 1540 | goto err_free_device; |
1540 | 1541 | ||
1541 | #ifdef CONFIG_ACPI | 1542 | #ifdef CONFIG_ACPI |
1542 | if (acpi_bus_register_driver(&sonypi_acpi_driver) >= 0) | 1543 | if (acpi_bus_register_driver(&sonypi_acpi_driver) >= 0) |
1543 | acpi_driver_registered = 1; | 1544 | acpi_driver_registered = 1; |
1544 | #endif | 1545 | #endif |
1545 | 1546 | ||
1546 | return 0; | 1547 | return 0; |
1547 | 1548 | ||
1548 | err_free_device: | 1549 | err_free_device: |
1549 | platform_device_put(sonypi_platform_device); | 1550 | platform_device_put(sonypi_platform_device); |
1550 | err_driver_unregister: | 1551 | err_driver_unregister: |
1551 | platform_driver_unregister(&sonypi_driver); | 1552 | platform_driver_unregister(&sonypi_driver); |
1552 | return error; | 1553 | return error; |
1553 | } | 1554 | } |
1554 | 1555 | ||
1555 | static void __exit sonypi_exit(void) | 1556 | static void __exit sonypi_exit(void) |
1556 | { | 1557 | { |
1557 | #ifdef CONFIG_ACPI | 1558 | #ifdef CONFIG_ACPI |
1558 | if (acpi_driver_registered) | 1559 | if (acpi_driver_registered) |
1559 | acpi_bus_unregister_driver(&sonypi_acpi_driver); | 1560 | acpi_bus_unregister_driver(&sonypi_acpi_driver); |
1560 | #endif | 1561 | #endif |
1561 | platform_device_unregister(sonypi_platform_device); | 1562 | platform_device_unregister(sonypi_platform_device); |
1562 | platform_driver_unregister(&sonypi_driver); | 1563 | platform_driver_unregister(&sonypi_driver); |
1563 | printk(KERN_INFO "sonypi: removed.\n"); | 1564 | printk(KERN_INFO "sonypi: removed.\n"); |
1564 | } | 1565 | } |
1565 | 1566 | ||
1566 | module_init(sonypi_init); | 1567 | module_init(sonypi_init); |
1567 | module_exit(sonypi_exit); | 1568 | module_exit(sonypi_exit); |
1568 | 1569 |
drivers/net/wan/c101.c
1 | /* | 1 | /* |
2 | * Moxa C101 synchronous serial card driver for Linux | 2 | * Moxa C101 synchronous serial card driver for Linux |
3 | * | 3 | * |
4 | * Copyright (C) 2000-2003 Krzysztof Halasa <khc@pm.waw.pl> | 4 | * Copyright (C) 2000-2003 Krzysztof Halasa <khc@pm.waw.pl> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of version 2 of the GNU General Public License | 7 | * under the terms of version 2 of the GNU General Public License |
8 | * as published by the Free Software Foundation. | 8 | * as published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/> | 10 | * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/> |
11 | * | 11 | * |
12 | * Sources of information: | 12 | * Sources of information: |
13 | * Hitachi HD64570 SCA User's Manual | 13 | * Hitachi HD64570 SCA User's Manual |
14 | * Moxa C101 User's Manual | 14 | * Moxa C101 User's Manual |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/capability.h> | ||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <linux/types.h> | 21 | #include <linux/types.h> |
21 | #include <linux/string.h> | 22 | #include <linux/string.h> |
22 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
23 | #include <linux/init.h> | 24 | #include <linux/init.h> |
24 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
25 | #include <linux/netdevice.h> | 26 | #include <linux/netdevice.h> |
26 | #include <linux/hdlc.h> | 27 | #include <linux/hdlc.h> |
27 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
28 | #include <asm/io.h> | 29 | #include <asm/io.h> |
29 | 30 | ||
30 | #include "hd64570.h" | 31 | #include "hd64570.h" |
31 | 32 | ||
32 | 33 | ||
33 | static const char* version = "Moxa C101 driver version: 1.15"; | 34 | static const char* version = "Moxa C101 driver version: 1.15"; |
34 | static const char* devname = "C101"; | 35 | static const char* devname = "C101"; |
35 | 36 | ||
36 | #undef DEBUG_PKT | 37 | #undef DEBUG_PKT |
37 | #define DEBUG_RINGS | 38 | #define DEBUG_RINGS |
38 | 39 | ||
39 | #define C101_PAGE 0x1D00 | 40 | #define C101_PAGE 0x1D00 |
40 | #define C101_DTR 0x1E00 | 41 | #define C101_DTR 0x1E00 |
41 | #define C101_SCA 0x1F00 | 42 | #define C101_SCA 0x1F00 |
42 | #define C101_WINDOW_SIZE 0x2000 | 43 | #define C101_WINDOW_SIZE 0x2000 |
43 | #define C101_MAPPED_RAM_SIZE 0x4000 | 44 | #define C101_MAPPED_RAM_SIZE 0x4000 |
44 | 45 | ||
45 | #define RAM_SIZE (256 * 1024) | 46 | #define RAM_SIZE (256 * 1024) |
46 | #define TX_RING_BUFFERS 10 | 47 | #define TX_RING_BUFFERS 10 |
47 | #define RX_RING_BUFFERS ((RAM_SIZE - C101_WINDOW_SIZE) / \ | 48 | #define RX_RING_BUFFERS ((RAM_SIZE - C101_WINDOW_SIZE) / \ |
48 | (sizeof(pkt_desc) + HDLC_MAX_MRU) - TX_RING_BUFFERS) | 49 | (sizeof(pkt_desc) + HDLC_MAX_MRU) - TX_RING_BUFFERS) |
49 | 50 | ||
50 | #define CLOCK_BASE 9830400 /* 9.8304 MHz */ | 51 | #define CLOCK_BASE 9830400 /* 9.8304 MHz */ |
51 | #define PAGE0_ALWAYS_MAPPED | 52 | #define PAGE0_ALWAYS_MAPPED |
52 | 53 | ||
53 | static char *hw; /* pointer to hw=xxx command line string */ | 54 | static char *hw; /* pointer to hw=xxx command line string */ |
54 | 55 | ||
55 | 56 | ||
56 | typedef struct card_s { | 57 | typedef struct card_s { |
57 | struct net_device *dev; | 58 | struct net_device *dev; |
58 | spinlock_t lock; /* TX lock */ | 59 | spinlock_t lock; /* TX lock */ |
59 | u8 __iomem *win0base; /* ISA window base address */ | 60 | u8 __iomem *win0base; /* ISA window base address */ |
60 | u32 phy_winbase; /* ISA physical base address */ | 61 | u32 phy_winbase; /* ISA physical base address */ |
61 | sync_serial_settings settings; | 62 | sync_serial_settings settings; |
62 | int rxpart; /* partial frame received, next frame invalid*/ | 63 | int rxpart; /* partial frame received, next frame invalid*/ |
63 | unsigned short encoding; | 64 | unsigned short encoding; |
64 | unsigned short parity; | 65 | unsigned short parity; |
65 | u16 rx_ring_buffers; /* number of buffers in a ring */ | 66 | u16 rx_ring_buffers; /* number of buffers in a ring */ |
66 | u16 tx_ring_buffers; | 67 | u16 tx_ring_buffers; |
67 | u16 buff_offset; /* offset of first buffer of first channel */ | 68 | u16 buff_offset; /* offset of first buffer of first channel */ |
68 | u16 rxin; /* rx ring buffer 'in' pointer */ | 69 | u16 rxin; /* rx ring buffer 'in' pointer */ |
69 | u16 txin; /* tx ring buffer 'in' and 'last' pointers */ | 70 | u16 txin; /* tx ring buffer 'in' and 'last' pointers */ |
70 | u16 txlast; | 71 | u16 txlast; |
71 | u8 rxs, txs, tmc; /* SCA registers */ | 72 | u8 rxs, txs, tmc; /* SCA registers */ |
72 | u8 irq; /* IRQ (3-15) */ | 73 | u8 irq; /* IRQ (3-15) */ |
73 | u8 page; | 74 | u8 page; |
74 | 75 | ||
75 | struct card_s *next_card; | 76 | struct card_s *next_card; |
76 | }card_t; | 77 | }card_t; |
77 | 78 | ||
78 | typedef card_t port_t; | 79 | typedef card_t port_t; |
79 | 80 | ||
80 | static card_t *first_card; | 81 | static card_t *first_card; |
81 | static card_t **new_card = &first_card; | 82 | static card_t **new_card = &first_card; |
82 | 83 | ||
83 | 84 | ||
84 | #define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg)) | 85 | #define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg)) |
85 | #define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg)) | 86 | #define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg)) |
86 | #define sca_inw(reg, card) readw((card)->win0base + C101_SCA + (reg)) | 87 | #define sca_inw(reg, card) readw((card)->win0base + C101_SCA + (reg)) |
87 | 88 | ||
88 | /* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */ | 89 | /* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */ |
89 | #define sca_outw(value, reg, card) do { \ | 90 | #define sca_outw(value, reg, card) do { \ |
90 | writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \ | 91 | writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \ |
91 | writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\ | 92 | writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\ |
92 | } while(0) | 93 | } while(0) |
93 | 94 | ||
94 | #define port_to_card(port) (port) | 95 | #define port_to_card(port) (port) |
95 | #define log_node(port) (0) | 96 | #define log_node(port) (0) |
96 | #define phy_node(port) (0) | 97 | #define phy_node(port) (0) |
97 | #define winsize(card) (C101_WINDOW_SIZE) | 98 | #define winsize(card) (C101_WINDOW_SIZE) |
98 | #define win0base(card) ((card)->win0base) | 99 | #define win0base(card) ((card)->win0base) |
99 | #define winbase(card) ((card)->win0base + 0x2000) | 100 | #define winbase(card) ((card)->win0base + 0x2000) |
100 | #define get_port(card, port) (card) | 101 | #define get_port(card, port) (card) |
101 | static void sca_msci_intr(port_t *port); | 102 | static void sca_msci_intr(port_t *port); |
102 | 103 | ||
103 | 104 | ||
104 | static inline u8 sca_get_page(card_t *card) | 105 | static inline u8 sca_get_page(card_t *card) |
105 | { | 106 | { |
106 | return card->page; | 107 | return card->page; |
107 | } | 108 | } |
108 | 109 | ||
109 | static inline void openwin(card_t *card, u8 page) | 110 | static inline void openwin(card_t *card, u8 page) |
110 | { | 111 | { |
111 | card->page = page; | 112 | card->page = page; |
112 | writeb(page, card->win0base + C101_PAGE); | 113 | writeb(page, card->win0base + C101_PAGE); |
113 | } | 114 | } |
114 | 115 | ||
115 | 116 | ||
116 | #include "hd64570.c" | 117 | #include "hd64570.c" |
117 | 118 | ||
118 | 119 | ||
119 | static inline void set_carrier(port_t *port) | 120 | static inline void set_carrier(port_t *port) |
120 | { | 121 | { |
121 | if (!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD)) | 122 | if (!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD)) |
122 | netif_carrier_on(port_to_dev(port)); | 123 | netif_carrier_on(port_to_dev(port)); |
123 | else | 124 | else |
124 | netif_carrier_off(port_to_dev(port)); | 125 | netif_carrier_off(port_to_dev(port)); |
125 | } | 126 | } |
126 | 127 | ||
127 | 128 | ||
128 | static void sca_msci_intr(port_t *port) | 129 | static void sca_msci_intr(port_t *port) |
129 | { | 130 | { |
130 | u8 stat = sca_in(MSCI0_OFFSET + ST1, port); /* read MSCI ST1 status */ | 131 | u8 stat = sca_in(MSCI0_OFFSET + ST1, port); /* read MSCI ST1 status */ |
131 | 132 | ||
132 | /* Reset MSCI TX underrun and CDCD (ignored) status bit */ | 133 | /* Reset MSCI TX underrun and CDCD (ignored) status bit */ |
133 | sca_out(stat & (ST1_UDRN | ST1_CDCD), MSCI0_OFFSET + ST1, port); | 134 | sca_out(stat & (ST1_UDRN | ST1_CDCD), MSCI0_OFFSET + ST1, port); |
134 | 135 | ||
135 | if (stat & ST1_UDRN) { | 136 | if (stat & ST1_UDRN) { |
136 | /* TX Underrun error detected */ | 137 | /* TX Underrun error detected */ |
137 | port_to_dev(port)->stats.tx_errors++; | 138 | port_to_dev(port)->stats.tx_errors++; |
138 | port_to_dev(port)->stats.tx_fifo_errors++; | 139 | port_to_dev(port)->stats.tx_fifo_errors++; |
139 | } | 140 | } |
140 | 141 | ||
141 | stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI1 ST1 status */ | 142 | stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI1 ST1 status */ |
142 | /* Reset MSCI CDCD status bit - uses ch#2 DCD input */ | 143 | /* Reset MSCI CDCD status bit - uses ch#2 DCD input */ |
143 | sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, port); | 144 | sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, port); |
144 | 145 | ||
145 | if (stat & ST1_CDCD) | 146 | if (stat & ST1_CDCD) |
146 | set_carrier(port); | 147 | set_carrier(port); |
147 | } | 148 | } |
148 | 149 | ||
149 | 150 | ||
150 | static void c101_set_iface(port_t *port) | 151 | static void c101_set_iface(port_t *port) |
151 | { | 152 | { |
152 | u8 rxs = port->rxs & CLK_BRG_MASK; | 153 | u8 rxs = port->rxs & CLK_BRG_MASK; |
153 | u8 txs = port->txs & CLK_BRG_MASK; | 154 | u8 txs = port->txs & CLK_BRG_MASK; |
154 | 155 | ||
155 | switch(port->settings.clock_type) { | 156 | switch(port->settings.clock_type) { |
156 | case CLOCK_INT: | 157 | case CLOCK_INT: |
157 | rxs |= CLK_BRG_RX; /* TX clock */ | 158 | rxs |= CLK_BRG_RX; /* TX clock */ |
158 | txs |= CLK_RXCLK_TX; /* BRG output */ | 159 | txs |= CLK_RXCLK_TX; /* BRG output */ |
159 | break; | 160 | break; |
160 | 161 | ||
161 | case CLOCK_TXINT: | 162 | case CLOCK_TXINT: |
162 | rxs |= CLK_LINE_RX; /* RXC input */ | 163 | rxs |= CLK_LINE_RX; /* RXC input */ |
163 | txs |= CLK_BRG_TX; /* BRG output */ | 164 | txs |= CLK_BRG_TX; /* BRG output */ |
164 | break; | 165 | break; |
165 | 166 | ||
166 | case CLOCK_TXFROMRX: | 167 | case CLOCK_TXFROMRX: |
167 | rxs |= CLK_LINE_RX; /* RXC input */ | 168 | rxs |= CLK_LINE_RX; /* RXC input */ |
168 | txs |= CLK_RXCLK_TX; /* RX clock */ | 169 | txs |= CLK_RXCLK_TX; /* RX clock */ |
169 | break; | 170 | break; |
170 | 171 | ||
171 | default: /* EXTernal clock */ | 172 | default: /* EXTernal clock */ |
172 | rxs |= CLK_LINE_RX; /* RXC input */ | 173 | rxs |= CLK_LINE_RX; /* RXC input */ |
173 | txs |= CLK_LINE_TX; /* TXC input */ | 174 | txs |= CLK_LINE_TX; /* TXC input */ |
174 | } | 175 | } |
175 | 176 | ||
176 | port->rxs = rxs; | 177 | port->rxs = rxs; |
177 | port->txs = txs; | 178 | port->txs = txs; |
178 | sca_out(rxs, MSCI1_OFFSET + RXS, port); | 179 | sca_out(rxs, MSCI1_OFFSET + RXS, port); |
179 | sca_out(txs, MSCI1_OFFSET + TXS, port); | 180 | sca_out(txs, MSCI1_OFFSET + TXS, port); |
180 | sca_set_port(port); | 181 | sca_set_port(port); |
181 | } | 182 | } |
182 | 183 | ||
183 | 184 | ||
184 | static int c101_open(struct net_device *dev) | 185 | static int c101_open(struct net_device *dev) |
185 | { | 186 | { |
186 | port_t *port = dev_to_port(dev); | 187 | port_t *port = dev_to_port(dev); |
187 | int result; | 188 | int result; |
188 | 189 | ||
189 | result = hdlc_open(dev); | 190 | result = hdlc_open(dev); |
190 | if (result) | 191 | if (result) |
191 | return result; | 192 | return result; |
192 | 193 | ||
193 | writeb(1, port->win0base + C101_DTR); | 194 | writeb(1, port->win0base + C101_DTR); |
194 | sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ | 195 | sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ |
195 | sca_open(dev); | 196 | sca_open(dev); |
196 | /* DCD is connected to port 2 !@#$%^& - disable MSCI0 CDCD interrupt */ | 197 | /* DCD is connected to port 2 !@#$%^& - disable MSCI0 CDCD interrupt */ |
197 | sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port); | 198 | sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port); |
198 | sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port); | 199 | sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port); |
199 | 200 | ||
200 | set_carrier(port); | 201 | set_carrier(port); |
201 | 202 | ||
202 | /* enable MSCI1 CDCD interrupt */ | 203 | /* enable MSCI1 CDCD interrupt */ |
203 | sca_out(IE1_CDCD, MSCI1_OFFSET + IE1, port); | 204 | sca_out(IE1_CDCD, MSCI1_OFFSET + IE1, port); |
204 | sca_out(IE0_RXINTA, MSCI1_OFFSET + IE0, port); | 205 | sca_out(IE0_RXINTA, MSCI1_OFFSET + IE0, port); |
205 | sca_out(0x48, IER0, port); /* TXINT #0 and RXINT #1 */ | 206 | sca_out(0x48, IER0, port); /* TXINT #0 and RXINT #1 */ |
206 | c101_set_iface(port); | 207 | c101_set_iface(port); |
207 | return 0; | 208 | return 0; |
208 | } | 209 | } |
209 | 210 | ||
210 | 211 | ||
211 | static int c101_close(struct net_device *dev) | 212 | static int c101_close(struct net_device *dev) |
212 | { | 213 | { |
213 | port_t *port = dev_to_port(dev); | 214 | port_t *port = dev_to_port(dev); |
214 | 215 | ||
215 | sca_close(dev); | 216 | sca_close(dev); |
216 | writeb(0, port->win0base + C101_DTR); | 217 | writeb(0, port->win0base + C101_DTR); |
217 | sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port); | 218 | sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port); |
218 | hdlc_close(dev); | 219 | hdlc_close(dev); |
219 | return 0; | 220 | return 0; |
220 | } | 221 | } |
221 | 222 | ||
222 | 223 | ||
223 | static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 224 | static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
224 | { | 225 | { |
225 | const size_t size = sizeof(sync_serial_settings); | 226 | const size_t size = sizeof(sync_serial_settings); |
226 | sync_serial_settings new_line; | 227 | sync_serial_settings new_line; |
227 | sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; | 228 | sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; |
228 | port_t *port = dev_to_port(dev); | 229 | port_t *port = dev_to_port(dev); |
229 | 230 | ||
230 | #ifdef DEBUG_RINGS | 231 | #ifdef DEBUG_RINGS |
231 | if (cmd == SIOCDEVPRIVATE) { | 232 | if (cmd == SIOCDEVPRIVATE) { |
232 | sca_dump_rings(dev); | 233 | sca_dump_rings(dev); |
233 | printk(KERN_DEBUG "MSCI1: ST: %02x %02x %02x %02x\n", | 234 | printk(KERN_DEBUG "MSCI1: ST: %02x %02x %02x %02x\n", |
234 | sca_in(MSCI1_OFFSET + ST0, port), | 235 | sca_in(MSCI1_OFFSET + ST0, port), |
235 | sca_in(MSCI1_OFFSET + ST1, port), | 236 | sca_in(MSCI1_OFFSET + ST1, port), |
236 | sca_in(MSCI1_OFFSET + ST2, port), | 237 | sca_in(MSCI1_OFFSET + ST2, port), |
237 | sca_in(MSCI1_OFFSET + ST3, port)); | 238 | sca_in(MSCI1_OFFSET + ST3, port)); |
238 | return 0; | 239 | return 0; |
239 | } | 240 | } |
240 | #endif | 241 | #endif |
241 | if (cmd != SIOCWANDEV) | 242 | if (cmd != SIOCWANDEV) |
242 | return hdlc_ioctl(dev, ifr, cmd); | 243 | return hdlc_ioctl(dev, ifr, cmd); |
243 | 244 | ||
244 | switch(ifr->ifr_settings.type) { | 245 | switch(ifr->ifr_settings.type) { |
245 | case IF_GET_IFACE: | 246 | case IF_GET_IFACE: |
246 | ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; | 247 | ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; |
247 | if (ifr->ifr_settings.size < size) { | 248 | if (ifr->ifr_settings.size < size) { |
248 | ifr->ifr_settings.size = size; /* data size wanted */ | 249 | ifr->ifr_settings.size = size; /* data size wanted */ |
249 | return -ENOBUFS; | 250 | return -ENOBUFS; |
250 | } | 251 | } |
251 | if (copy_to_user(line, &port->settings, size)) | 252 | if (copy_to_user(line, &port->settings, size)) |
252 | return -EFAULT; | 253 | return -EFAULT; |
253 | return 0; | 254 | return 0; |
254 | 255 | ||
255 | case IF_IFACE_SYNC_SERIAL: | 256 | case IF_IFACE_SYNC_SERIAL: |
256 | if(!capable(CAP_NET_ADMIN)) | 257 | if(!capable(CAP_NET_ADMIN)) |
257 | return -EPERM; | 258 | return -EPERM; |
258 | 259 | ||
259 | if (copy_from_user(&new_line, line, size)) | 260 | if (copy_from_user(&new_line, line, size)) |
260 | return -EFAULT; | 261 | return -EFAULT; |
261 | 262 | ||
262 | if (new_line.clock_type != CLOCK_EXT && | 263 | if (new_line.clock_type != CLOCK_EXT && |
263 | new_line.clock_type != CLOCK_TXFROMRX && | 264 | new_line.clock_type != CLOCK_TXFROMRX && |
264 | new_line.clock_type != CLOCK_INT && | 265 | new_line.clock_type != CLOCK_INT && |
265 | new_line.clock_type != CLOCK_TXINT) | 266 | new_line.clock_type != CLOCK_TXINT) |
266 | return -EINVAL; /* No such clock setting */ | 267 | return -EINVAL; /* No such clock setting */ |
267 | 268 | ||
268 | if (new_line.loopback != 0 && new_line.loopback != 1) | 269 | if (new_line.loopback != 0 && new_line.loopback != 1) |
269 | return -EINVAL; | 270 | return -EINVAL; |
270 | 271 | ||
271 | memcpy(&port->settings, &new_line, size); /* Update settings */ | 272 | memcpy(&port->settings, &new_line, size); /* Update settings */ |
272 | c101_set_iface(port); | 273 | c101_set_iface(port); |
273 | return 0; | 274 | return 0; |
274 | 275 | ||
275 | default: | 276 | default: |
276 | return hdlc_ioctl(dev, ifr, cmd); | 277 | return hdlc_ioctl(dev, ifr, cmd); |
277 | } | 278 | } |
278 | } | 279 | } |
279 | 280 | ||
280 | 281 | ||
281 | 282 | ||
282 | static void c101_destroy_card(card_t *card) | 283 | static void c101_destroy_card(card_t *card) |
283 | { | 284 | { |
284 | readb(card->win0base + C101_PAGE); /* Resets SCA? */ | 285 | readb(card->win0base + C101_PAGE); /* Resets SCA? */ |
285 | 286 | ||
286 | if (card->irq) | 287 | if (card->irq) |
287 | free_irq(card->irq, card); | 288 | free_irq(card->irq, card); |
288 | 289 | ||
289 | if (card->win0base) { | 290 | if (card->win0base) { |
290 | iounmap(card->win0base); | 291 | iounmap(card->win0base); |
291 | release_mem_region(card->phy_winbase, C101_MAPPED_RAM_SIZE); | 292 | release_mem_region(card->phy_winbase, C101_MAPPED_RAM_SIZE); |
292 | } | 293 | } |
293 | 294 | ||
294 | free_netdev(card->dev); | 295 | free_netdev(card->dev); |
295 | 296 | ||
296 | kfree(card); | 297 | kfree(card); |
297 | } | 298 | } |
298 | 299 | ||
299 | static const struct net_device_ops c101_ops = { | 300 | static const struct net_device_ops c101_ops = { |
300 | .ndo_open = c101_open, | 301 | .ndo_open = c101_open, |
301 | .ndo_stop = c101_close, | 302 | .ndo_stop = c101_close, |
302 | .ndo_change_mtu = hdlc_change_mtu, | 303 | .ndo_change_mtu = hdlc_change_mtu, |
303 | .ndo_start_xmit = hdlc_start_xmit, | 304 | .ndo_start_xmit = hdlc_start_xmit, |
304 | .ndo_do_ioctl = c101_ioctl, | 305 | .ndo_do_ioctl = c101_ioctl, |
305 | }; | 306 | }; |
306 | 307 | ||
307 | static int __init c101_run(unsigned long irq, unsigned long winbase) | 308 | static int __init c101_run(unsigned long irq, unsigned long winbase) |
308 | { | 309 | { |
309 | struct net_device *dev; | 310 | struct net_device *dev; |
310 | hdlc_device *hdlc; | 311 | hdlc_device *hdlc; |
311 | card_t *card; | 312 | card_t *card; |
312 | int result; | 313 | int result; |
313 | 314 | ||
314 | if (irq<3 || irq>15 || irq == 6) /* FIXME */ { | 315 | if (irq<3 || irq>15 || irq == 6) /* FIXME */ { |
315 | printk(KERN_ERR "c101: invalid IRQ value\n"); | 316 | printk(KERN_ERR "c101: invalid IRQ value\n"); |
316 | return -ENODEV; | 317 | return -ENODEV; |
317 | } | 318 | } |
318 | 319 | ||
319 | if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) !=0) { | 320 | if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) !=0) { |
320 | printk(KERN_ERR "c101: invalid RAM value\n"); | 321 | printk(KERN_ERR "c101: invalid RAM value\n"); |
321 | return -ENODEV; | 322 | return -ENODEV; |
322 | } | 323 | } |
323 | 324 | ||
324 | card = kzalloc(sizeof(card_t), GFP_KERNEL); | 325 | card = kzalloc(sizeof(card_t), GFP_KERNEL); |
325 | if (card == NULL) { | 326 | if (card == NULL) { |
326 | printk(KERN_ERR "c101: unable to allocate memory\n"); | 327 | printk(KERN_ERR "c101: unable to allocate memory\n"); |
327 | return -ENOBUFS; | 328 | return -ENOBUFS; |
328 | } | 329 | } |
329 | 330 | ||
330 | card->dev = alloc_hdlcdev(card); | 331 | card->dev = alloc_hdlcdev(card); |
331 | if (!card->dev) { | 332 | if (!card->dev) { |
332 | printk(KERN_ERR "c101: unable to allocate memory\n"); | 333 | printk(KERN_ERR "c101: unable to allocate memory\n"); |
333 | kfree(card); | 334 | kfree(card); |
334 | return -ENOBUFS; | 335 | return -ENOBUFS; |
335 | } | 336 | } |
336 | 337 | ||
337 | if (request_irq(irq, sca_intr, 0, devname, card)) { | 338 | if (request_irq(irq, sca_intr, 0, devname, card)) { |
338 | printk(KERN_ERR "c101: could not allocate IRQ\n"); | 339 | printk(KERN_ERR "c101: could not allocate IRQ\n"); |
339 | c101_destroy_card(card); | 340 | c101_destroy_card(card); |
340 | return -EBUSY; | 341 | return -EBUSY; |
341 | } | 342 | } |
342 | card->irq = irq; | 343 | card->irq = irq; |
343 | 344 | ||
344 | if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) { | 345 | if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) { |
345 | printk(KERN_ERR "c101: could not request RAM window\n"); | 346 | printk(KERN_ERR "c101: could not request RAM window\n"); |
346 | c101_destroy_card(card); | 347 | c101_destroy_card(card); |
347 | return -EBUSY; | 348 | return -EBUSY; |
348 | } | 349 | } |
349 | card->phy_winbase = winbase; | 350 | card->phy_winbase = winbase; |
350 | card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE); | 351 | card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE); |
351 | if (!card->win0base) { | 352 | if (!card->win0base) { |
352 | printk(KERN_ERR "c101: could not map I/O address\n"); | 353 | printk(KERN_ERR "c101: could not map I/O address\n"); |
353 | c101_destroy_card(card); | 354 | c101_destroy_card(card); |
354 | return -EFAULT; | 355 | return -EFAULT; |
355 | } | 356 | } |
356 | 357 | ||
357 | card->tx_ring_buffers = TX_RING_BUFFERS; | 358 | card->tx_ring_buffers = TX_RING_BUFFERS; |
358 | card->rx_ring_buffers = RX_RING_BUFFERS; | 359 | card->rx_ring_buffers = RX_RING_BUFFERS; |
359 | card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ | 360 | card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ |
360 | 361 | ||
361 | readb(card->win0base + C101_PAGE); /* Resets SCA? */ | 362 | readb(card->win0base + C101_PAGE); /* Resets SCA? */ |
362 | udelay(100); | 363 | udelay(100); |
363 | writeb(0, card->win0base + C101_PAGE); | 364 | writeb(0, card->win0base + C101_PAGE); |
364 | writeb(0, card->win0base + C101_DTR); /* Power-up for RAM? */ | 365 | writeb(0, card->win0base + C101_DTR); /* Power-up for RAM? */ |
365 | 366 | ||
366 | sca_init(card, 0); | 367 | sca_init(card, 0); |
367 | 368 | ||
368 | dev = port_to_dev(card); | 369 | dev = port_to_dev(card); |
369 | hdlc = dev_to_hdlc(dev); | 370 | hdlc = dev_to_hdlc(dev); |
370 | 371 | ||
371 | spin_lock_init(&card->lock); | 372 | spin_lock_init(&card->lock); |
372 | dev->irq = irq; | 373 | dev->irq = irq; |
373 | dev->mem_start = winbase; | 374 | dev->mem_start = winbase; |
374 | dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1; | 375 | dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1; |
375 | dev->tx_queue_len = 50; | 376 | dev->tx_queue_len = 50; |
376 | dev->netdev_ops = &c101_ops; | 377 | dev->netdev_ops = &c101_ops; |
377 | hdlc->attach = sca_attach; | 378 | hdlc->attach = sca_attach; |
378 | hdlc->xmit = sca_xmit; | 379 | hdlc->xmit = sca_xmit; |
379 | card->settings.clock_type = CLOCK_EXT; | 380 | card->settings.clock_type = CLOCK_EXT; |
380 | 381 | ||
381 | result = register_hdlc_device(dev); | 382 | result = register_hdlc_device(dev); |
382 | if (result) { | 383 | if (result) { |
383 | printk(KERN_WARNING "c101: unable to register hdlc device\n"); | 384 | printk(KERN_WARNING "c101: unable to register hdlc device\n"); |
384 | c101_destroy_card(card); | 385 | c101_destroy_card(card); |
385 | return result; | 386 | return result; |
386 | } | 387 | } |
387 | 388 | ||
388 | sca_init_port(card); /* Set up C101 memory */ | 389 | sca_init_port(card); /* Set up C101 memory */ |
389 | set_carrier(card); | 390 | set_carrier(card); |
390 | 391 | ||
391 | printk(KERN_INFO "%s: Moxa C101 on IRQ%u," | 392 | printk(KERN_INFO "%s: Moxa C101 on IRQ%u," |
392 | " using %u TX + %u RX packets rings\n", | 393 | " using %u TX + %u RX packets rings\n", |
393 | dev->name, card->irq, | 394 | dev->name, card->irq, |
394 | card->tx_ring_buffers, card->rx_ring_buffers); | 395 | card->tx_ring_buffers, card->rx_ring_buffers); |
395 | 396 | ||
396 | *new_card = card; | 397 | *new_card = card; |
397 | new_card = &card->next_card; | 398 | new_card = &card->next_card; |
398 | return 0; | 399 | return 0; |
399 | } | 400 | } |
400 | 401 | ||
401 | 402 | ||
402 | 403 | ||
403 | static int __init c101_init(void) | 404 | static int __init c101_init(void) |
404 | { | 405 | { |
405 | if (hw == NULL) { | 406 | if (hw == NULL) { |
406 | #ifdef MODULE | 407 | #ifdef MODULE |
407 | printk(KERN_INFO "c101: no card initialized\n"); | 408 | printk(KERN_INFO "c101: no card initialized\n"); |
408 | #endif | 409 | #endif |
409 | return -EINVAL; /* no parameters specified, abort */ | 410 | return -EINVAL; /* no parameters specified, abort */ |
410 | } | 411 | } |
411 | 412 | ||
412 | printk(KERN_INFO "%s\n", version); | 413 | printk(KERN_INFO "%s\n", version); |
413 | 414 | ||
414 | do { | 415 | do { |
415 | unsigned long irq, ram; | 416 | unsigned long irq, ram; |
416 | 417 | ||
417 | irq = simple_strtoul(hw, &hw, 0); | 418 | irq = simple_strtoul(hw, &hw, 0); |
418 | 419 | ||
419 | if (*hw++ != ',') | 420 | if (*hw++ != ',') |
420 | break; | 421 | break; |
421 | ram = simple_strtoul(hw, &hw, 0); | 422 | ram = simple_strtoul(hw, &hw, 0); |
422 | 423 | ||
423 | if (*hw == ':' || *hw == '\x0') | 424 | if (*hw == ':' || *hw == '\x0') |
424 | c101_run(irq, ram); | 425 | c101_run(irq, ram); |
425 | 426 | ||
426 | if (*hw == '\x0') | 427 | if (*hw == '\x0') |
427 | return first_card ? 0 : -EINVAL; | 428 | return first_card ? 0 : -EINVAL; |
428 | }while(*hw++ == ':'); | 429 | }while(*hw++ == ':'); |
429 | 430 | ||
430 | printk(KERN_ERR "c101: invalid hardware parameters\n"); | 431 | printk(KERN_ERR "c101: invalid hardware parameters\n"); |
431 | return first_card ? 0 : -EINVAL; | 432 | return first_card ? 0 : -EINVAL; |
432 | } | 433 | } |
433 | 434 | ||
434 | 435 | ||
435 | static void __exit c101_cleanup(void) | 436 | static void __exit c101_cleanup(void) |
436 | { | 437 | { |
437 | card_t *card = first_card; | 438 | card_t *card = first_card; |
438 | 439 | ||
439 | while (card) { | 440 | while (card) { |
440 | card_t *ptr = card; | 441 | card_t *ptr = card; |
441 | card = card->next_card; | 442 | card = card->next_card; |
442 | unregister_hdlc_device(port_to_dev(ptr)); | 443 | unregister_hdlc_device(port_to_dev(ptr)); |
443 | c101_destroy_card(ptr); | 444 | c101_destroy_card(ptr); |
444 | } | 445 | } |
445 | } | 446 | } |
446 | 447 | ||
447 | 448 | ||
448 | module_init(c101_init); | 449 | module_init(c101_init); |
449 | module_exit(c101_cleanup); | 450 | module_exit(c101_cleanup); |
450 | 451 | ||
451 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); | 452 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
452 | MODULE_DESCRIPTION("Moxa C101 serial port driver"); | 453 | MODULE_DESCRIPTION("Moxa C101 serial port driver"); |
453 | MODULE_LICENSE("GPL v2"); | 454 | MODULE_LICENSE("GPL v2"); |
454 | module_param(hw, charp, 0444); | 455 | module_param(hw, charp, 0444); |
455 | MODULE_PARM_DESC(hw, "irq,ram:irq,..."); | 456 | MODULE_PARM_DESC(hw, "irq,ram:irq,..."); |
456 | 457 |
drivers/net/wan/n2.c
1 | /* | 1 | /* |
2 | * SDL Inc. RISCom/N2 synchronous serial card driver for Linux | 2 | * SDL Inc. RISCom/N2 synchronous serial card driver for Linux |
3 | * | 3 | * |
4 | * Copyright (C) 1998-2003 Krzysztof Halasa <khc@pm.waw.pl> | 4 | * Copyright (C) 1998-2003 Krzysztof Halasa <khc@pm.waw.pl> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of version 2 of the GNU General Public License | 7 | * under the terms of version 2 of the GNU General Public License |
8 | * as published by the Free Software Foundation. | 8 | * as published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/> | 10 | * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/> |
11 | * | 11 | * |
12 | * Note: integrated CSU/DSU/DDS are not supported by this driver | 12 | * Note: integrated CSU/DSU/DDS are not supported by this driver |
13 | * | 13 | * |
14 | * Sources of information: | 14 | * Sources of information: |
15 | * Hitachi HD64570 SCA User's Manual | 15 | * Hitachi HD64570 SCA User's Manual |
16 | * SDL Inc. PPP/HDLC/CISCO driver | 16 | * SDL Inc. PPP/HDLC/CISCO driver |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/capability.h> | ||
21 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
22 | #include <linux/types.h> | 23 | #include <linux/types.h> |
23 | #include <linux/fcntl.h> | 24 | #include <linux/fcntl.h> |
24 | #include <linux/in.h> | 25 | #include <linux/in.h> |
25 | #include <linux/string.h> | 26 | #include <linux/string.h> |
26 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
27 | #include <linux/init.h> | 28 | #include <linux/init.h> |
28 | #include <linux/ioport.h> | 29 | #include <linux/ioport.h> |
29 | #include <linux/moduleparam.h> | 30 | #include <linux/moduleparam.h> |
30 | #include <linux/netdevice.h> | 31 | #include <linux/netdevice.h> |
31 | #include <linux/hdlc.h> | 32 | #include <linux/hdlc.h> |
32 | #include <asm/io.h> | 33 | #include <asm/io.h> |
33 | #include "hd64570.h" | 34 | #include "hd64570.h" |
34 | 35 | ||
35 | 36 | ||
36 | static const char* version = "SDL RISCom/N2 driver version: 1.15"; | 37 | static const char* version = "SDL RISCom/N2 driver version: 1.15"; |
37 | static const char* devname = "RISCom/N2"; | 38 | static const char* devname = "RISCom/N2"; |
38 | 39 | ||
39 | #undef DEBUG_PKT | 40 | #undef DEBUG_PKT |
40 | #define DEBUG_RINGS | 41 | #define DEBUG_RINGS |
41 | 42 | ||
42 | #define USE_WINDOWSIZE 16384 | 43 | #define USE_WINDOWSIZE 16384 |
43 | #define USE_BUS16BITS 1 | 44 | #define USE_BUS16BITS 1 |
44 | #define CLOCK_BASE 9830400 /* 9.8304 MHz */ | 45 | #define CLOCK_BASE 9830400 /* 9.8304 MHz */ |
45 | #define MAX_PAGES 16 /* 16 RAM pages at max */ | 46 | #define MAX_PAGES 16 /* 16 RAM pages at max */ |
46 | #define MAX_RAM_SIZE 0x80000 /* 512 KB */ | 47 | #define MAX_RAM_SIZE 0x80000 /* 512 KB */ |
47 | #if MAX_RAM_SIZE > MAX_PAGES * USE_WINDOWSIZE | 48 | #if MAX_RAM_SIZE > MAX_PAGES * USE_WINDOWSIZE |
48 | #undef MAX_RAM_SIZE | 49 | #undef MAX_RAM_SIZE |
49 | #define MAX_RAM_SIZE (MAX_PAGES * USE_WINDOWSIZE) | 50 | #define MAX_RAM_SIZE (MAX_PAGES * USE_WINDOWSIZE) |
50 | #endif | 51 | #endif |
51 | #define N2_IOPORTS 0x10 | 52 | #define N2_IOPORTS 0x10 |
52 | #define NEED_DETECT_RAM | 53 | #define NEED_DETECT_RAM |
53 | #define NEED_SCA_MSCI_INTR | 54 | #define NEED_SCA_MSCI_INTR |
54 | #define MAX_TX_BUFFERS 10 | 55 | #define MAX_TX_BUFFERS 10 |
55 | 56 | ||
56 | static char *hw; /* pointer to hw=xxx command line string */ | 57 | static char *hw; /* pointer to hw=xxx command line string */ |
57 | 58 | ||
58 | /* RISCom/N2 Board Registers */ | 59 | /* RISCom/N2 Board Registers */ |
59 | 60 | ||
60 | /* PC Control Register */ | 61 | /* PC Control Register */ |
61 | #define N2_PCR 0 | 62 | #define N2_PCR 0 |
62 | #define PCR_RUNSCA 1 /* Run 64570 */ | 63 | #define PCR_RUNSCA 1 /* Run 64570 */ |
63 | #define PCR_VPM 2 /* Enable VPM - needed if using RAM above 1 MB */ | 64 | #define PCR_VPM 2 /* Enable VPM - needed if using RAM above 1 MB */ |
64 | #define PCR_ENWIN 4 /* Open window */ | 65 | #define PCR_ENWIN 4 /* Open window */ |
65 | #define PCR_BUS16 8 /* 16-bit bus */ | 66 | #define PCR_BUS16 8 /* 16-bit bus */ |
66 | 67 | ||
67 | 68 | ||
68 | /* Memory Base Address Register */ | 69 | /* Memory Base Address Register */ |
69 | #define N2_BAR 2 | 70 | #define N2_BAR 2 |
70 | 71 | ||
71 | 72 | ||
72 | /* Page Scan Register */ | 73 | /* Page Scan Register */ |
73 | #define N2_PSR 4 | 74 | #define N2_PSR 4 |
74 | #define WIN16K 0x00 | 75 | #define WIN16K 0x00 |
75 | #define WIN32K 0x20 | 76 | #define WIN32K 0x20 |
76 | #define WIN64K 0x40 | 77 | #define WIN64K 0x40 |
77 | #define PSR_WINBITS 0x60 | 78 | #define PSR_WINBITS 0x60 |
78 | #define PSR_DMAEN 0x80 | 79 | #define PSR_DMAEN 0x80 |
79 | #define PSR_PAGEBITS 0x0F | 80 | #define PSR_PAGEBITS 0x0F |
80 | 81 | ||
81 | 82 | ||
82 | /* Modem Control Reg */ | 83 | /* Modem Control Reg */ |
83 | #define N2_MCR 6 | 84 | #define N2_MCR 6 |
84 | #define CLOCK_OUT_PORT1 0x80 | 85 | #define CLOCK_OUT_PORT1 0x80 |
85 | #define CLOCK_OUT_PORT0 0x40 | 86 | #define CLOCK_OUT_PORT0 0x40 |
86 | #define TX422_PORT1 0x20 | 87 | #define TX422_PORT1 0x20 |
87 | #define TX422_PORT0 0x10 | 88 | #define TX422_PORT0 0x10 |
88 | #define DSR_PORT1 0x08 | 89 | #define DSR_PORT1 0x08 |
89 | #define DSR_PORT0 0x04 | 90 | #define DSR_PORT0 0x04 |
90 | #define DTR_PORT1 0x02 | 91 | #define DTR_PORT1 0x02 |
91 | #define DTR_PORT0 0x01 | 92 | #define DTR_PORT0 0x01 |
92 | 93 | ||
93 | 94 | ||
94 | typedef struct port_s { | 95 | typedef struct port_s { |
95 | struct net_device *dev; | 96 | struct net_device *dev; |
96 | struct card_s *card; | 97 | struct card_s *card; |
97 | spinlock_t lock; /* TX lock */ | 98 | spinlock_t lock; /* TX lock */ |
98 | sync_serial_settings settings; | 99 | sync_serial_settings settings; |
99 | int valid; /* port enabled */ | 100 | int valid; /* port enabled */ |
100 | int rxpart; /* partial frame received, next frame invalid*/ | 101 | int rxpart; /* partial frame received, next frame invalid*/ |
101 | unsigned short encoding; | 102 | unsigned short encoding; |
102 | unsigned short parity; | 103 | unsigned short parity; |
103 | u16 rxin; /* rx ring buffer 'in' pointer */ | 104 | u16 rxin; /* rx ring buffer 'in' pointer */ |
104 | u16 txin; /* tx ring buffer 'in' and 'last' pointers */ | 105 | u16 txin; /* tx ring buffer 'in' and 'last' pointers */ |
105 | u16 txlast; | 106 | u16 txlast; |
106 | u8 rxs, txs, tmc; /* SCA registers */ | 107 | u8 rxs, txs, tmc; /* SCA registers */ |
107 | u8 phy_node; /* physical port # - 0 or 1 */ | 108 | u8 phy_node; /* physical port # - 0 or 1 */ |
108 | u8 log_node; /* logical port # */ | 109 | u8 log_node; /* logical port # */ |
109 | }port_t; | 110 | }port_t; |
110 | 111 | ||
111 | 112 | ||
112 | 113 | ||
113 | typedef struct card_s { | 114 | typedef struct card_s { |
114 | u8 __iomem *winbase; /* ISA window base address */ | 115 | u8 __iomem *winbase; /* ISA window base address */ |
115 | u32 phy_winbase; /* ISA physical base address */ | 116 | u32 phy_winbase; /* ISA physical base address */ |
116 | u32 ram_size; /* number of bytes */ | 117 | u32 ram_size; /* number of bytes */ |
117 | u16 io; /* IO Base address */ | 118 | u16 io; /* IO Base address */ |
118 | u16 buff_offset; /* offset of first buffer of first channel */ | 119 | u16 buff_offset; /* offset of first buffer of first channel */ |
119 | u16 rx_ring_buffers; /* number of buffers in a ring */ | 120 | u16 rx_ring_buffers; /* number of buffers in a ring */ |
120 | u16 tx_ring_buffers; | 121 | u16 tx_ring_buffers; |
121 | u8 irq; /* IRQ (3-15) */ | 122 | u8 irq; /* IRQ (3-15) */ |
122 | 123 | ||
123 | port_t ports[2]; | 124 | port_t ports[2]; |
124 | struct card_s *next_card; | 125 | struct card_s *next_card; |
125 | }card_t; | 126 | }card_t; |
126 | 127 | ||
127 | 128 | ||
128 | static card_t *first_card; | 129 | static card_t *first_card; |
129 | static card_t **new_card = &first_card; | 130 | static card_t **new_card = &first_card; |
130 | 131 | ||
131 | 132 | ||
132 | #define sca_reg(reg, card) (0x8000 | (card)->io | \ | 133 | #define sca_reg(reg, card) (0x8000 | (card)->io | \ |
133 | ((reg) & 0x0F) | (((reg) & 0xF0) << 6)) | 134 | ((reg) & 0x0F) | (((reg) & 0xF0) << 6)) |
134 | #define sca_in(reg, card) inb(sca_reg(reg, card)) | 135 | #define sca_in(reg, card) inb(sca_reg(reg, card)) |
135 | #define sca_out(value, reg, card) outb(value, sca_reg(reg, card)) | 136 | #define sca_out(value, reg, card) outb(value, sca_reg(reg, card)) |
136 | #define sca_inw(reg, card) inw(sca_reg(reg, card)) | 137 | #define sca_inw(reg, card) inw(sca_reg(reg, card)) |
137 | #define sca_outw(value, reg, card) outw(value, sca_reg(reg, card)) | 138 | #define sca_outw(value, reg, card) outw(value, sca_reg(reg, card)) |
138 | 139 | ||
139 | #define port_to_card(port) ((port)->card) | 140 | #define port_to_card(port) ((port)->card) |
140 | #define log_node(port) ((port)->log_node) | 141 | #define log_node(port) ((port)->log_node) |
141 | #define phy_node(port) ((port)->phy_node) | 142 | #define phy_node(port) ((port)->phy_node) |
142 | #define winsize(card) (USE_WINDOWSIZE) | 143 | #define winsize(card) (USE_WINDOWSIZE) |
143 | #define winbase(card) ((card)->winbase) | 144 | #define winbase(card) ((card)->winbase) |
144 | #define get_port(card, port) ((card)->ports[port].valid ? \ | 145 | #define get_port(card, port) ((card)->ports[port].valid ? \ |
145 | &(card)->ports[port] : NULL) | 146 | &(card)->ports[port] : NULL) |
146 | 147 | ||
147 | 148 | ||
148 | static __inline__ u8 sca_get_page(card_t *card) | 149 | static __inline__ u8 sca_get_page(card_t *card) |
149 | { | 150 | { |
150 | return inb(card->io + N2_PSR) & PSR_PAGEBITS; | 151 | return inb(card->io + N2_PSR) & PSR_PAGEBITS; |
151 | } | 152 | } |
152 | 153 | ||
153 | 154 | ||
154 | static __inline__ void openwin(card_t *card, u8 page) | 155 | static __inline__ void openwin(card_t *card, u8 page) |
155 | { | 156 | { |
156 | u8 psr = inb(card->io + N2_PSR); | 157 | u8 psr = inb(card->io + N2_PSR); |
157 | outb((psr & ~PSR_PAGEBITS) | page, card->io + N2_PSR); | 158 | outb((psr & ~PSR_PAGEBITS) | page, card->io + N2_PSR); |
158 | } | 159 | } |
159 | 160 | ||
160 | 161 | ||
161 | #include "hd64570.c" | 162 | #include "hd64570.c" |
162 | 163 | ||
163 | 164 | ||
164 | static void n2_set_iface(port_t *port) | 165 | static void n2_set_iface(port_t *port) |
165 | { | 166 | { |
166 | card_t *card = port->card; | 167 | card_t *card = port->card; |
167 | int io = card->io; | 168 | int io = card->io; |
168 | u8 mcr = inb(io + N2_MCR); | 169 | u8 mcr = inb(io + N2_MCR); |
169 | u8 msci = get_msci(port); | 170 | u8 msci = get_msci(port); |
170 | u8 rxs = port->rxs & CLK_BRG_MASK; | 171 | u8 rxs = port->rxs & CLK_BRG_MASK; |
171 | u8 txs = port->txs & CLK_BRG_MASK; | 172 | u8 txs = port->txs & CLK_BRG_MASK; |
172 | 173 | ||
173 | switch(port->settings.clock_type) { | 174 | switch(port->settings.clock_type) { |
174 | case CLOCK_INT: | 175 | case CLOCK_INT: |
175 | mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; | 176 | mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; |
176 | rxs |= CLK_BRG_RX; /* BRG output */ | 177 | rxs |= CLK_BRG_RX; /* BRG output */ |
177 | txs |= CLK_RXCLK_TX; /* RX clock */ | 178 | txs |= CLK_RXCLK_TX; /* RX clock */ |
178 | break; | 179 | break; |
179 | 180 | ||
180 | case CLOCK_TXINT: | 181 | case CLOCK_TXINT: |
181 | mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; | 182 | mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; |
182 | rxs |= CLK_LINE_RX; /* RXC input */ | 183 | rxs |= CLK_LINE_RX; /* RXC input */ |
183 | txs |= CLK_BRG_TX; /* BRG output */ | 184 | txs |= CLK_BRG_TX; /* BRG output */ |
184 | break; | 185 | break; |
185 | 186 | ||
186 | case CLOCK_TXFROMRX: | 187 | case CLOCK_TXFROMRX: |
187 | mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; | 188 | mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; |
188 | rxs |= CLK_LINE_RX; /* RXC input */ | 189 | rxs |= CLK_LINE_RX; /* RXC input */ |
189 | txs |= CLK_RXCLK_TX; /* RX clock */ | 190 | txs |= CLK_RXCLK_TX; /* RX clock */ |
190 | break; | 191 | break; |
191 | 192 | ||
192 | default: /* Clock EXTernal */ | 193 | default: /* Clock EXTernal */ |
193 | mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0; | 194 | mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0; |
194 | rxs |= CLK_LINE_RX; /* RXC input */ | 195 | rxs |= CLK_LINE_RX; /* RXC input */ |
195 | txs |= CLK_LINE_TX; /* TXC input */ | 196 | txs |= CLK_LINE_TX; /* TXC input */ |
196 | } | 197 | } |
197 | 198 | ||
198 | outb(mcr, io + N2_MCR); | 199 | outb(mcr, io + N2_MCR); |
199 | port->rxs = rxs; | 200 | port->rxs = rxs; |
200 | port->txs = txs; | 201 | port->txs = txs; |
201 | sca_out(rxs, msci + RXS, card); | 202 | sca_out(rxs, msci + RXS, card); |
202 | sca_out(txs, msci + TXS, card); | 203 | sca_out(txs, msci + TXS, card); |
203 | sca_set_port(port); | 204 | sca_set_port(port); |
204 | } | 205 | } |
205 | 206 | ||
206 | 207 | ||
207 | 208 | ||
208 | static int n2_open(struct net_device *dev) | 209 | static int n2_open(struct net_device *dev) |
209 | { | 210 | { |
210 | port_t *port = dev_to_port(dev); | 211 | port_t *port = dev_to_port(dev); |
211 | int io = port->card->io; | 212 | int io = port->card->io; |
212 | u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1:TX422_PORT0); | 213 | u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1:TX422_PORT0); |
213 | int result; | 214 | int result; |
214 | 215 | ||
215 | result = hdlc_open(dev); | 216 | result = hdlc_open(dev); |
216 | if (result) | 217 | if (result) |
217 | return result; | 218 | return result; |
218 | 219 | ||
219 | mcr &= port->phy_node ? ~DTR_PORT1 : ~DTR_PORT0; /* set DTR ON */ | 220 | mcr &= port->phy_node ? ~DTR_PORT1 : ~DTR_PORT0; /* set DTR ON */ |
220 | outb(mcr, io + N2_MCR); | 221 | outb(mcr, io + N2_MCR); |
221 | 222 | ||
222 | outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */ | 223 | outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */ |
223 | outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */ | 224 | outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */ |
224 | sca_open(dev); | 225 | sca_open(dev); |
225 | n2_set_iface(port); | 226 | n2_set_iface(port); |
226 | return 0; | 227 | return 0; |
227 | } | 228 | } |
228 | 229 | ||
229 | 230 | ||
230 | 231 | ||
231 | static int n2_close(struct net_device *dev) | 232 | static int n2_close(struct net_device *dev) |
232 | { | 233 | { |
233 | port_t *port = dev_to_port(dev); | 234 | port_t *port = dev_to_port(dev); |
234 | int io = port->card->io; | 235 | int io = port->card->io; |
235 | u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0); | 236 | u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0); |
236 | 237 | ||
237 | sca_close(dev); | 238 | sca_close(dev); |
238 | mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */ | 239 | mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */ |
239 | outb(mcr, io + N2_MCR); | 240 | outb(mcr, io + N2_MCR); |
240 | hdlc_close(dev); | 241 | hdlc_close(dev); |
241 | return 0; | 242 | return 0; |
242 | } | 243 | } |
243 | 244 | ||
244 | 245 | ||
245 | 246 | ||
246 | static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 247 | static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
247 | { | 248 | { |
248 | const size_t size = sizeof(sync_serial_settings); | 249 | const size_t size = sizeof(sync_serial_settings); |
249 | sync_serial_settings new_line; | 250 | sync_serial_settings new_line; |
250 | sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; | 251 | sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; |
251 | port_t *port = dev_to_port(dev); | 252 | port_t *port = dev_to_port(dev); |
252 | 253 | ||
253 | #ifdef DEBUG_RINGS | 254 | #ifdef DEBUG_RINGS |
254 | if (cmd == SIOCDEVPRIVATE) { | 255 | if (cmd == SIOCDEVPRIVATE) { |
255 | sca_dump_rings(dev); | 256 | sca_dump_rings(dev); |
256 | return 0; | 257 | return 0; |
257 | } | 258 | } |
258 | #endif | 259 | #endif |
259 | if (cmd != SIOCWANDEV) | 260 | if (cmd != SIOCWANDEV) |
260 | return hdlc_ioctl(dev, ifr, cmd); | 261 | return hdlc_ioctl(dev, ifr, cmd); |
261 | 262 | ||
262 | switch(ifr->ifr_settings.type) { | 263 | switch(ifr->ifr_settings.type) { |
263 | case IF_GET_IFACE: | 264 | case IF_GET_IFACE: |
264 | ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; | 265 | ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; |
265 | if (ifr->ifr_settings.size < size) { | 266 | if (ifr->ifr_settings.size < size) { |
266 | ifr->ifr_settings.size = size; /* data size wanted */ | 267 | ifr->ifr_settings.size = size; /* data size wanted */ |
267 | return -ENOBUFS; | 268 | return -ENOBUFS; |
268 | } | 269 | } |
269 | if (copy_to_user(line, &port->settings, size)) | 270 | if (copy_to_user(line, &port->settings, size)) |
270 | return -EFAULT; | 271 | return -EFAULT; |
271 | return 0; | 272 | return 0; |
272 | 273 | ||
273 | case IF_IFACE_SYNC_SERIAL: | 274 | case IF_IFACE_SYNC_SERIAL: |
274 | if(!capable(CAP_NET_ADMIN)) | 275 | if(!capable(CAP_NET_ADMIN)) |
275 | return -EPERM; | 276 | return -EPERM; |
276 | 277 | ||
277 | if (copy_from_user(&new_line, line, size)) | 278 | if (copy_from_user(&new_line, line, size)) |
278 | return -EFAULT; | 279 | return -EFAULT; |
279 | 280 | ||
280 | if (new_line.clock_type != CLOCK_EXT && | 281 | if (new_line.clock_type != CLOCK_EXT && |
281 | new_line.clock_type != CLOCK_TXFROMRX && | 282 | new_line.clock_type != CLOCK_TXFROMRX && |
282 | new_line.clock_type != CLOCK_INT && | 283 | new_line.clock_type != CLOCK_INT && |
283 | new_line.clock_type != CLOCK_TXINT) | 284 | new_line.clock_type != CLOCK_TXINT) |
284 | return -EINVAL; /* No such clock setting */ | 285 | return -EINVAL; /* No such clock setting */ |
285 | 286 | ||
286 | if (new_line.loopback != 0 && new_line.loopback != 1) | 287 | if (new_line.loopback != 0 && new_line.loopback != 1) |
287 | return -EINVAL; | 288 | return -EINVAL; |
288 | 289 | ||
289 | memcpy(&port->settings, &new_line, size); /* Update settings */ | 290 | memcpy(&port->settings, &new_line, size); /* Update settings */ |
290 | n2_set_iface(port); | 291 | n2_set_iface(port); |
291 | return 0; | 292 | return 0; |
292 | 293 | ||
293 | default: | 294 | default: |
294 | return hdlc_ioctl(dev, ifr, cmd); | 295 | return hdlc_ioctl(dev, ifr, cmd); |
295 | } | 296 | } |
296 | } | 297 | } |
297 | 298 | ||
298 | 299 | ||
299 | 300 | ||
300 | static void n2_destroy_card(card_t *card) | 301 | static void n2_destroy_card(card_t *card) |
301 | { | 302 | { |
302 | int cnt; | 303 | int cnt; |
303 | 304 | ||
304 | for (cnt = 0; cnt < 2; cnt++) | 305 | for (cnt = 0; cnt < 2; cnt++) |
305 | if (card->ports[cnt].card) { | 306 | if (card->ports[cnt].card) { |
306 | struct net_device *dev = port_to_dev(&card->ports[cnt]); | 307 | struct net_device *dev = port_to_dev(&card->ports[cnt]); |
307 | unregister_hdlc_device(dev); | 308 | unregister_hdlc_device(dev); |
308 | } | 309 | } |
309 | 310 | ||
310 | if (card->irq) | 311 | if (card->irq) |
311 | free_irq(card->irq, card); | 312 | free_irq(card->irq, card); |
312 | 313 | ||
313 | if (card->winbase) { | 314 | if (card->winbase) { |
314 | iounmap(card->winbase); | 315 | iounmap(card->winbase); |
315 | release_mem_region(card->phy_winbase, USE_WINDOWSIZE); | 316 | release_mem_region(card->phy_winbase, USE_WINDOWSIZE); |
316 | } | 317 | } |
317 | 318 | ||
318 | if (card->io) | 319 | if (card->io) |
319 | release_region(card->io, N2_IOPORTS); | 320 | release_region(card->io, N2_IOPORTS); |
320 | if (card->ports[0].dev) | 321 | if (card->ports[0].dev) |
321 | free_netdev(card->ports[0].dev); | 322 | free_netdev(card->ports[0].dev); |
322 | if (card->ports[1].dev) | 323 | if (card->ports[1].dev) |
323 | free_netdev(card->ports[1].dev); | 324 | free_netdev(card->ports[1].dev); |
324 | kfree(card); | 325 | kfree(card); |
325 | } | 326 | } |
326 | 327 | ||
327 | static const struct net_device_ops n2_ops = { | 328 | static const struct net_device_ops n2_ops = { |
328 | .ndo_open = n2_open, | 329 | .ndo_open = n2_open, |
329 | .ndo_stop = n2_close, | 330 | .ndo_stop = n2_close, |
330 | .ndo_change_mtu = hdlc_change_mtu, | 331 | .ndo_change_mtu = hdlc_change_mtu, |
331 | .ndo_start_xmit = hdlc_start_xmit, | 332 | .ndo_start_xmit = hdlc_start_xmit, |
332 | .ndo_do_ioctl = n2_ioctl, | 333 | .ndo_do_ioctl = n2_ioctl, |
333 | }; | 334 | }; |
334 | 335 | ||
335 | static int __init n2_run(unsigned long io, unsigned long irq, | 336 | static int __init n2_run(unsigned long io, unsigned long irq, |
336 | unsigned long winbase, long valid0, long valid1) | 337 | unsigned long winbase, long valid0, long valid1) |
337 | { | 338 | { |
338 | card_t *card; | 339 | card_t *card; |
339 | u8 cnt, pcr; | 340 | u8 cnt, pcr; |
340 | int i; | 341 | int i; |
341 | 342 | ||
342 | if (io < 0x200 || io > 0x3FF || (io % N2_IOPORTS) != 0) { | 343 | if (io < 0x200 || io > 0x3FF || (io % N2_IOPORTS) != 0) { |
343 | printk(KERN_ERR "n2: invalid I/O port value\n"); | 344 | printk(KERN_ERR "n2: invalid I/O port value\n"); |
344 | return -ENODEV; | 345 | return -ENODEV; |
345 | } | 346 | } |
346 | 347 | ||
347 | if (irq < 3 || irq > 15 || irq == 6) /* FIXME */ { | 348 | if (irq < 3 || irq > 15 || irq == 6) /* FIXME */ { |
348 | printk(KERN_ERR "n2: invalid IRQ value\n"); | 349 | printk(KERN_ERR "n2: invalid IRQ value\n"); |
349 | return -ENODEV; | 350 | return -ENODEV; |
350 | } | 351 | } |
351 | 352 | ||
352 | if (winbase < 0xA0000 || winbase > 0xFFFFF || (winbase & 0xFFF) != 0) { | 353 | if (winbase < 0xA0000 || winbase > 0xFFFFF || (winbase & 0xFFF) != 0) { |
353 | printk(KERN_ERR "n2: invalid RAM value\n"); | 354 | printk(KERN_ERR "n2: invalid RAM value\n"); |
354 | return -ENODEV; | 355 | return -ENODEV; |
355 | } | 356 | } |
356 | 357 | ||
357 | card = kzalloc(sizeof(card_t), GFP_KERNEL); | 358 | card = kzalloc(sizeof(card_t), GFP_KERNEL); |
358 | if (card == NULL) { | 359 | if (card == NULL) { |
359 | printk(KERN_ERR "n2: unable to allocate memory\n"); | 360 | printk(KERN_ERR "n2: unable to allocate memory\n"); |
360 | return -ENOBUFS; | 361 | return -ENOBUFS; |
361 | } | 362 | } |
362 | 363 | ||
363 | card->ports[0].dev = alloc_hdlcdev(&card->ports[0]); | 364 | card->ports[0].dev = alloc_hdlcdev(&card->ports[0]); |
364 | card->ports[1].dev = alloc_hdlcdev(&card->ports[1]); | 365 | card->ports[1].dev = alloc_hdlcdev(&card->ports[1]); |
365 | if (!card->ports[0].dev || !card->ports[1].dev) { | 366 | if (!card->ports[0].dev || !card->ports[1].dev) { |
366 | printk(KERN_ERR "n2: unable to allocate memory\n"); | 367 | printk(KERN_ERR "n2: unable to allocate memory\n"); |
367 | n2_destroy_card(card); | 368 | n2_destroy_card(card); |
368 | return -ENOMEM; | 369 | return -ENOMEM; |
369 | } | 370 | } |
370 | 371 | ||
371 | if (!request_region(io, N2_IOPORTS, devname)) { | 372 | if (!request_region(io, N2_IOPORTS, devname)) { |
372 | printk(KERN_ERR "n2: I/O port region in use\n"); | 373 | printk(KERN_ERR "n2: I/O port region in use\n"); |
373 | n2_destroy_card(card); | 374 | n2_destroy_card(card); |
374 | return -EBUSY; | 375 | return -EBUSY; |
375 | } | 376 | } |
376 | card->io = io; | 377 | card->io = io; |
377 | 378 | ||
378 | if (request_irq(irq, &sca_intr, 0, devname, card)) { | 379 | if (request_irq(irq, &sca_intr, 0, devname, card)) { |
379 | printk(KERN_ERR "n2: could not allocate IRQ\n"); | 380 | printk(KERN_ERR "n2: could not allocate IRQ\n"); |
380 | n2_destroy_card(card); | 381 | n2_destroy_card(card); |
381 | return(-EBUSY); | 382 | return(-EBUSY); |
382 | } | 383 | } |
383 | card->irq = irq; | 384 | card->irq = irq; |
384 | 385 | ||
385 | if (!request_mem_region(winbase, USE_WINDOWSIZE, devname)) { | 386 | if (!request_mem_region(winbase, USE_WINDOWSIZE, devname)) { |
386 | printk(KERN_ERR "n2: could not request RAM window\n"); | 387 | printk(KERN_ERR "n2: could not request RAM window\n"); |
387 | n2_destroy_card(card); | 388 | n2_destroy_card(card); |
388 | return(-EBUSY); | 389 | return(-EBUSY); |
389 | } | 390 | } |
390 | card->phy_winbase = winbase; | 391 | card->phy_winbase = winbase; |
391 | card->winbase = ioremap(winbase, USE_WINDOWSIZE); | 392 | card->winbase = ioremap(winbase, USE_WINDOWSIZE); |
392 | if (!card->winbase) { | 393 | if (!card->winbase) { |
393 | printk(KERN_ERR "n2: ioremap() failed\n"); | 394 | printk(KERN_ERR "n2: ioremap() failed\n"); |
394 | n2_destroy_card(card); | 395 | n2_destroy_card(card); |
395 | return -EFAULT; | 396 | return -EFAULT; |
396 | } | 397 | } |
397 | 398 | ||
398 | outb(0, io + N2_PCR); | 399 | outb(0, io + N2_PCR); |
399 | outb(winbase >> 12, io + N2_BAR); | 400 | outb(winbase >> 12, io + N2_BAR); |
400 | 401 | ||
401 | switch (USE_WINDOWSIZE) { | 402 | switch (USE_WINDOWSIZE) { |
402 | case 16384: | 403 | case 16384: |
403 | outb(WIN16K, io + N2_PSR); | 404 | outb(WIN16K, io + N2_PSR); |
404 | break; | 405 | break; |
405 | 406 | ||
406 | case 32768: | 407 | case 32768: |
407 | outb(WIN32K, io + N2_PSR); | 408 | outb(WIN32K, io + N2_PSR); |
408 | break; | 409 | break; |
409 | 410 | ||
410 | case 65536: | 411 | case 65536: |
411 | outb(WIN64K, io + N2_PSR); | 412 | outb(WIN64K, io + N2_PSR); |
412 | break; | 413 | break; |
413 | 414 | ||
414 | default: | 415 | default: |
415 | printk(KERN_ERR "n2: invalid window size\n"); | 416 | printk(KERN_ERR "n2: invalid window size\n"); |
416 | n2_destroy_card(card); | 417 | n2_destroy_card(card); |
417 | return -ENODEV; | 418 | return -ENODEV; |
418 | } | 419 | } |
419 | 420 | ||
420 | pcr = PCR_ENWIN | PCR_VPM | (USE_BUS16BITS ? PCR_BUS16 : 0); | 421 | pcr = PCR_ENWIN | PCR_VPM | (USE_BUS16BITS ? PCR_BUS16 : 0); |
421 | outb(pcr, io + N2_PCR); | 422 | outb(pcr, io + N2_PCR); |
422 | 423 | ||
423 | card->ram_size = sca_detect_ram(card, card->winbase, MAX_RAM_SIZE); | 424 | card->ram_size = sca_detect_ram(card, card->winbase, MAX_RAM_SIZE); |
424 | 425 | ||
425 | /* number of TX + RX buffers for one port */ | 426 | /* number of TX + RX buffers for one port */ |
426 | i = card->ram_size / ((valid0 + valid1) * (sizeof(pkt_desc) + | 427 | i = card->ram_size / ((valid0 + valid1) * (sizeof(pkt_desc) + |
427 | HDLC_MAX_MRU)); | 428 | HDLC_MAX_MRU)); |
428 | 429 | ||
429 | card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS); | 430 | card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS); |
430 | card->rx_ring_buffers = i - card->tx_ring_buffers; | 431 | card->rx_ring_buffers = i - card->tx_ring_buffers; |
431 | 432 | ||
432 | card->buff_offset = (valid0 + valid1) * sizeof(pkt_desc) * | 433 | card->buff_offset = (valid0 + valid1) * sizeof(pkt_desc) * |
433 | (card->tx_ring_buffers + card->rx_ring_buffers); | 434 | (card->tx_ring_buffers + card->rx_ring_buffers); |
434 | 435 | ||
435 | printk(KERN_INFO "n2: RISCom/N2 %u KB RAM, IRQ%u, " | 436 | printk(KERN_INFO "n2: RISCom/N2 %u KB RAM, IRQ%u, " |
436 | "using %u TX + %u RX packets rings\n", card->ram_size / 1024, | 437 | "using %u TX + %u RX packets rings\n", card->ram_size / 1024, |
437 | card->irq, card->tx_ring_buffers, card->rx_ring_buffers); | 438 | card->irq, card->tx_ring_buffers, card->rx_ring_buffers); |
438 | 439 | ||
439 | if (card->tx_ring_buffers < 1) { | 440 | if (card->tx_ring_buffers < 1) { |
440 | printk(KERN_ERR "n2: RAM test failed\n"); | 441 | printk(KERN_ERR "n2: RAM test failed\n"); |
441 | n2_destroy_card(card); | 442 | n2_destroy_card(card); |
442 | return -EIO; | 443 | return -EIO; |
443 | } | 444 | } |
444 | 445 | ||
445 | pcr |= PCR_RUNSCA; /* run SCA */ | 446 | pcr |= PCR_RUNSCA; /* run SCA */ |
446 | outb(pcr, io + N2_PCR); | 447 | outb(pcr, io + N2_PCR); |
447 | outb(0, io + N2_MCR); | 448 | outb(0, io + N2_MCR); |
448 | 449 | ||
449 | sca_init(card, 0); | 450 | sca_init(card, 0); |
450 | for (cnt = 0; cnt < 2; cnt++) { | 451 | for (cnt = 0; cnt < 2; cnt++) { |
451 | port_t *port = &card->ports[cnt]; | 452 | port_t *port = &card->ports[cnt]; |
452 | struct net_device *dev = port_to_dev(port); | 453 | struct net_device *dev = port_to_dev(port); |
453 | hdlc_device *hdlc = dev_to_hdlc(dev); | 454 | hdlc_device *hdlc = dev_to_hdlc(dev); |
454 | 455 | ||
455 | if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1)) | 456 | if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1)) |
456 | continue; | 457 | continue; |
457 | 458 | ||
458 | port->phy_node = cnt; | 459 | port->phy_node = cnt; |
459 | port->valid = 1; | 460 | port->valid = 1; |
460 | 461 | ||
461 | if ((cnt == 1) && valid0) | 462 | if ((cnt == 1) && valid0) |
462 | port->log_node = 1; | 463 | port->log_node = 1; |
463 | 464 | ||
464 | spin_lock_init(&port->lock); | 465 | spin_lock_init(&port->lock); |
465 | dev->irq = irq; | 466 | dev->irq = irq; |
466 | dev->mem_start = winbase; | 467 | dev->mem_start = winbase; |
467 | dev->mem_end = winbase + USE_WINDOWSIZE - 1; | 468 | dev->mem_end = winbase + USE_WINDOWSIZE - 1; |
468 | dev->tx_queue_len = 50; | 469 | dev->tx_queue_len = 50; |
469 | dev->netdev_ops = &n2_ops; | 470 | dev->netdev_ops = &n2_ops; |
470 | hdlc->attach = sca_attach; | 471 | hdlc->attach = sca_attach; |
471 | hdlc->xmit = sca_xmit; | 472 | hdlc->xmit = sca_xmit; |
472 | port->settings.clock_type = CLOCK_EXT; | 473 | port->settings.clock_type = CLOCK_EXT; |
473 | port->card = card; | 474 | port->card = card; |
474 | 475 | ||
475 | if (register_hdlc_device(dev)) { | 476 | if (register_hdlc_device(dev)) { |
476 | printk(KERN_WARNING "n2: unable to register hdlc " | 477 | printk(KERN_WARNING "n2: unable to register hdlc " |
477 | "device\n"); | 478 | "device\n"); |
478 | port->card = NULL; | 479 | port->card = NULL; |
479 | n2_destroy_card(card); | 480 | n2_destroy_card(card); |
480 | return -ENOBUFS; | 481 | return -ENOBUFS; |
481 | } | 482 | } |
482 | sca_init_port(port); /* Set up SCA memory */ | 483 | sca_init_port(port); /* Set up SCA memory */ |
483 | 484 | ||
484 | printk(KERN_INFO "%s: RISCom/N2 node %d\n", | 485 | printk(KERN_INFO "%s: RISCom/N2 node %d\n", |
485 | dev->name, port->phy_node); | 486 | dev->name, port->phy_node); |
486 | } | 487 | } |
487 | 488 | ||
488 | *new_card = card; | 489 | *new_card = card; |
489 | new_card = &card->next_card; | 490 | new_card = &card->next_card; |
490 | 491 | ||
491 | return 0; | 492 | return 0; |
492 | } | 493 | } |
493 | 494 | ||
494 | 495 | ||
495 | 496 | ||
496 | static int __init n2_init(void) | 497 | static int __init n2_init(void) |
497 | { | 498 | { |
498 | if (hw==NULL) { | 499 | if (hw==NULL) { |
499 | #ifdef MODULE | 500 | #ifdef MODULE |
500 | printk(KERN_INFO "n2: no card initialized\n"); | 501 | printk(KERN_INFO "n2: no card initialized\n"); |
501 | #endif | 502 | #endif |
502 | return -EINVAL; /* no parameters specified, abort */ | 503 | return -EINVAL; /* no parameters specified, abort */ |
503 | } | 504 | } |
504 | 505 | ||
505 | printk(KERN_INFO "%s\n", version); | 506 | printk(KERN_INFO "%s\n", version); |
506 | 507 | ||
507 | do { | 508 | do { |
508 | unsigned long io, irq, ram; | 509 | unsigned long io, irq, ram; |
509 | long valid[2] = { 0, 0 }; /* Default = both ports disabled */ | 510 | long valid[2] = { 0, 0 }; /* Default = both ports disabled */ |
510 | 511 | ||
511 | io = simple_strtoul(hw, &hw, 0); | 512 | io = simple_strtoul(hw, &hw, 0); |
512 | 513 | ||
513 | if (*hw++ != ',') | 514 | if (*hw++ != ',') |
514 | break; | 515 | break; |
515 | irq = simple_strtoul(hw, &hw, 0); | 516 | irq = simple_strtoul(hw, &hw, 0); |
516 | 517 | ||
517 | if (*hw++ != ',') | 518 | if (*hw++ != ',') |
518 | break; | 519 | break; |
519 | ram = simple_strtoul(hw, &hw, 0); | 520 | ram = simple_strtoul(hw, &hw, 0); |
520 | 521 | ||
521 | if (*hw++ != ',') | 522 | if (*hw++ != ',') |
522 | break; | 523 | break; |
523 | while(1) { | 524 | while(1) { |
524 | if (*hw == '0' && !valid[0]) | 525 | if (*hw == '0' && !valid[0]) |
525 | valid[0] = 1; /* Port 0 enabled */ | 526 | valid[0] = 1; /* Port 0 enabled */ |
526 | else if (*hw == '1' && !valid[1]) | 527 | else if (*hw == '1' && !valid[1]) |
527 | valid[1] = 1; /* Port 1 enabled */ | 528 | valid[1] = 1; /* Port 1 enabled */ |
528 | else | 529 | else |
529 | break; | 530 | break; |
530 | hw++; | 531 | hw++; |
531 | } | 532 | } |
532 | 533 | ||
533 | if (!valid[0] && !valid[1]) | 534 | if (!valid[0] && !valid[1]) |
534 | break; /* at least one port must be used */ | 535 | break; /* at least one port must be used */ |
535 | 536 | ||
536 | if (*hw == ':' || *hw == '\x0') | 537 | if (*hw == ':' || *hw == '\x0') |
537 | n2_run(io, irq, ram, valid[0], valid[1]); | 538 | n2_run(io, irq, ram, valid[0], valid[1]); |
538 | 539 | ||
539 | if (*hw == '\x0') | 540 | if (*hw == '\x0') |
540 | return first_card ? 0 : -EINVAL; | 541 | return first_card ? 0 : -EINVAL; |
541 | }while(*hw++ == ':'); | 542 | }while(*hw++ == ':'); |
542 | 543 | ||
543 | printk(KERN_ERR "n2: invalid hardware parameters\n"); | 544 | printk(KERN_ERR "n2: invalid hardware parameters\n"); |
544 | return first_card ? 0 : -EINVAL; | 545 | return first_card ? 0 : -EINVAL; |
545 | } | 546 | } |
546 | 547 | ||
547 | 548 | ||
548 | static void __exit n2_cleanup(void) | 549 | static void __exit n2_cleanup(void) |
549 | { | 550 | { |
550 | card_t *card = first_card; | 551 | card_t *card = first_card; |
551 | 552 | ||
552 | while (card) { | 553 | while (card) { |
553 | card_t *ptr = card; | 554 | card_t *ptr = card; |
554 | card = card->next_card; | 555 | card = card->next_card; |
555 | n2_destroy_card(ptr); | 556 | n2_destroy_card(ptr); |
556 | } | 557 | } |
557 | } | 558 | } |
558 | 559 | ||
559 | 560 | ||
560 | module_init(n2_init); | 561 | module_init(n2_init); |
561 | module_exit(n2_cleanup); | 562 | module_exit(n2_cleanup); |
562 | 563 | ||
563 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); | 564 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
564 | MODULE_DESCRIPTION("RISCom/N2 serial port driver"); | 565 | MODULE_DESCRIPTION("RISCom/N2 serial port driver"); |
565 | MODULE_LICENSE("GPL v2"); | 566 | MODULE_LICENSE("GPL v2"); |
566 | module_param(hw, charp, 0444); | 567 | module_param(hw, charp, 0444); |
567 | MODULE_PARM_DESC(hw, "io,irq,ram,ports:io,irq,..."); | 568 | MODULE_PARM_DESC(hw, "io,irq,ram,ports:io,irq,..."); |
568 | 569 |
drivers/net/wan/pci200syn.c
1 | /* | 1 | /* |
2 | * Goramo PCI200SYN synchronous serial card driver for Linux | 2 | * Goramo PCI200SYN synchronous serial card driver for Linux |
3 | * | 3 | * |
4 | * Copyright (C) 2002-2008 Krzysztof Halasa <khc@pm.waw.pl> | 4 | * Copyright (C) 2002-2008 Krzysztof Halasa <khc@pm.waw.pl> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of version 2 of the GNU General Public License | 7 | * under the terms of version 2 of the GNU General Public License |
8 | * as published by the Free Software Foundation. | 8 | * as published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/> | 10 | * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/> |
11 | * | 11 | * |
12 | * Sources of information: | 12 | * Sources of information: |
13 | * Hitachi HD64572 SCA-II User's Manual | 13 | * Hitachi HD64572 SCA-II User's Manual |
14 | * PLX Technology Inc. PCI9052 Data Book | 14 | * PLX Technology Inc. PCI9052 Data Book |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/capability.h> | ||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <linux/types.h> | 21 | #include <linux/types.h> |
21 | #include <linux/fcntl.h> | 22 | #include <linux/fcntl.h> |
22 | #include <linux/in.h> | 23 | #include <linux/in.h> |
23 | #include <linux/string.h> | 24 | #include <linux/string.h> |
24 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
25 | #include <linux/init.h> | 26 | #include <linux/init.h> |
26 | #include <linux/ioport.h> | 27 | #include <linux/ioport.h> |
27 | #include <linux/moduleparam.h> | 28 | #include <linux/moduleparam.h> |
28 | #include <linux/netdevice.h> | 29 | #include <linux/netdevice.h> |
29 | #include <linux/hdlc.h> | 30 | #include <linux/hdlc.h> |
30 | #include <linux/pci.h> | 31 | #include <linux/pci.h> |
31 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
32 | #include <asm/io.h> | 33 | #include <asm/io.h> |
33 | 34 | ||
34 | #include "hd64572.h" | 35 | #include "hd64572.h" |
35 | 36 | ||
36 | #undef DEBUG_PKT | 37 | #undef DEBUG_PKT |
37 | #define DEBUG_RINGS | 38 | #define DEBUG_RINGS |
38 | 39 | ||
39 | #define PCI200SYN_PLX_SIZE 0x80 /* PLX control window size (128b) */ | 40 | #define PCI200SYN_PLX_SIZE 0x80 /* PLX control window size (128b) */ |
40 | #define PCI200SYN_SCA_SIZE 0x400 /* SCA window size (1Kb) */ | 41 | #define PCI200SYN_SCA_SIZE 0x400 /* SCA window size (1Kb) */ |
41 | #define MAX_TX_BUFFERS 10 | 42 | #define MAX_TX_BUFFERS 10 |
42 | 43 | ||
43 | static int pci_clock_freq = 33000000; | 44 | static int pci_clock_freq = 33000000; |
44 | #define CLOCK_BASE pci_clock_freq | 45 | #define CLOCK_BASE pci_clock_freq |
45 | 46 | ||
46 | /* | 47 | /* |
47 | * PLX PCI9052 local configuration and shared runtime registers. | 48 | * PLX PCI9052 local configuration and shared runtime registers. |
48 | * This structure can be used to access 9052 registers (memory mapped). | 49 | * This structure can be used to access 9052 registers (memory mapped). |
49 | */ | 50 | */ |
50 | typedef struct { | 51 | typedef struct { |
51 | u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */ | 52 | u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */ |
52 | u32 loc_rom_range; /* 10h : Local ROM Range */ | 53 | u32 loc_rom_range; /* 10h : Local ROM Range */ |
53 | u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */ | 54 | u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */ |
54 | u32 loc_rom_base; /* 24h : Local ROM Base */ | 55 | u32 loc_rom_base; /* 24h : Local ROM Base */ |
55 | u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */ | 56 | u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */ |
56 | u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */ | 57 | u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */ |
57 | u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */ | 58 | u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */ |
58 | u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */ | 59 | u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */ |
59 | u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */ | 60 | u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */ |
60 | }plx9052; | 61 | }plx9052; |
61 | 62 | ||
62 | 63 | ||
63 | 64 | ||
64 | typedef struct port_s { | 65 | typedef struct port_s { |
65 | struct napi_struct napi; | 66 | struct napi_struct napi; |
66 | struct net_device *netdev; | 67 | struct net_device *netdev; |
67 | struct card_s *card; | 68 | struct card_s *card; |
68 | spinlock_t lock; /* TX lock */ | 69 | spinlock_t lock; /* TX lock */ |
69 | sync_serial_settings settings; | 70 | sync_serial_settings settings; |
70 | int rxpart; /* partial frame received, next frame invalid*/ | 71 | int rxpart; /* partial frame received, next frame invalid*/ |
71 | unsigned short encoding; | 72 | unsigned short encoding; |
72 | unsigned short parity; | 73 | unsigned short parity; |
73 | u16 rxin; /* rx ring buffer 'in' pointer */ | 74 | u16 rxin; /* rx ring buffer 'in' pointer */ |
74 | u16 txin; /* tx ring buffer 'in' and 'last' pointers */ | 75 | u16 txin; /* tx ring buffer 'in' and 'last' pointers */ |
75 | u16 txlast; | 76 | u16 txlast; |
76 | u8 rxs, txs, tmc; /* SCA registers */ | 77 | u8 rxs, txs, tmc; /* SCA registers */ |
77 | u8 chan; /* physical port # - 0 or 1 */ | 78 | u8 chan; /* physical port # - 0 or 1 */ |
78 | }port_t; | 79 | }port_t; |
79 | 80 | ||
80 | 81 | ||
81 | 82 | ||
82 | typedef struct card_s { | 83 | typedef struct card_s { |
83 | u8 __iomem *rambase; /* buffer memory base (virtual) */ | 84 | u8 __iomem *rambase; /* buffer memory base (virtual) */ |
84 | u8 __iomem *scabase; /* SCA memory base (virtual) */ | 85 | u8 __iomem *scabase; /* SCA memory base (virtual) */ |
85 | plx9052 __iomem *plxbase;/* PLX registers memory base (virtual) */ | 86 | plx9052 __iomem *plxbase;/* PLX registers memory base (virtual) */ |
86 | u16 rx_ring_buffers; /* number of buffers in a ring */ | 87 | u16 rx_ring_buffers; /* number of buffers in a ring */ |
87 | u16 tx_ring_buffers; | 88 | u16 tx_ring_buffers; |
88 | u16 buff_offset; /* offset of first buffer of first channel */ | 89 | u16 buff_offset; /* offset of first buffer of first channel */ |
89 | u8 irq; /* interrupt request level */ | 90 | u8 irq; /* interrupt request level */ |
90 | 91 | ||
91 | port_t ports[2]; | 92 | port_t ports[2]; |
92 | }card_t; | 93 | }card_t; |
93 | 94 | ||
94 | 95 | ||
95 | #define get_port(card, port) (&card->ports[port]) | 96 | #define get_port(card, port) (&card->ports[port]) |
96 | #define sca_flush(card) (sca_in(IER0, card)); | 97 | #define sca_flush(card) (sca_in(IER0, card)); |
97 | 98 | ||
98 | static inline void new_memcpy_toio(char __iomem *dest, char *src, int length) | 99 | static inline void new_memcpy_toio(char __iomem *dest, char *src, int length) |
99 | { | 100 | { |
100 | int len; | 101 | int len; |
101 | do { | 102 | do { |
102 | len = length > 256 ? 256 : length; | 103 | len = length > 256 ? 256 : length; |
103 | memcpy_toio(dest, src, len); | 104 | memcpy_toio(dest, src, len); |
104 | dest += len; | 105 | dest += len; |
105 | src += len; | 106 | src += len; |
106 | length -= len; | 107 | length -= len; |
107 | readb(dest); | 108 | readb(dest); |
108 | } while (len); | 109 | } while (len); |
109 | } | 110 | } |
110 | 111 | ||
111 | #undef memcpy_toio | 112 | #undef memcpy_toio |
112 | #define memcpy_toio new_memcpy_toio | 113 | #define memcpy_toio new_memcpy_toio |
113 | 114 | ||
114 | #include "hd64572.c" | 115 | #include "hd64572.c" |
115 | 116 | ||
116 | 117 | ||
117 | static void pci200_set_iface(port_t *port) | 118 | static void pci200_set_iface(port_t *port) |
118 | { | 119 | { |
119 | card_t *card = port->card; | 120 | card_t *card = port->card; |
120 | u16 msci = get_msci(port); | 121 | u16 msci = get_msci(port); |
121 | u8 rxs = port->rxs & CLK_BRG_MASK; | 122 | u8 rxs = port->rxs & CLK_BRG_MASK; |
122 | u8 txs = port->txs & CLK_BRG_MASK; | 123 | u8 txs = port->txs & CLK_BRG_MASK; |
123 | 124 | ||
124 | sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, | 125 | sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, |
125 | port->card); | 126 | port->card); |
126 | switch(port->settings.clock_type) { | 127 | switch(port->settings.clock_type) { |
127 | case CLOCK_INT: | 128 | case CLOCK_INT: |
128 | rxs |= CLK_BRG; /* BRG output */ | 129 | rxs |= CLK_BRG; /* BRG output */ |
129 | txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ | 130 | txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ |
130 | break; | 131 | break; |
131 | 132 | ||
132 | case CLOCK_TXINT: | 133 | case CLOCK_TXINT: |
133 | rxs |= CLK_LINE; /* RXC input */ | 134 | rxs |= CLK_LINE; /* RXC input */ |
134 | txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */ | 135 | txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */ |
135 | break; | 136 | break; |
136 | 137 | ||
137 | case CLOCK_TXFROMRX: | 138 | case CLOCK_TXFROMRX: |
138 | rxs |= CLK_LINE; /* RXC input */ | 139 | rxs |= CLK_LINE; /* RXC input */ |
139 | txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ | 140 | txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ |
140 | break; | 141 | break; |
141 | 142 | ||
142 | default: /* EXTernal clock */ | 143 | default: /* EXTernal clock */ |
143 | rxs |= CLK_LINE; /* RXC input */ | 144 | rxs |= CLK_LINE; /* RXC input */ |
144 | txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */ | 145 | txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */ |
145 | break; | 146 | break; |
146 | } | 147 | } |
147 | 148 | ||
148 | port->rxs = rxs; | 149 | port->rxs = rxs; |
149 | port->txs = txs; | 150 | port->txs = txs; |
150 | sca_out(rxs, msci + RXS, card); | 151 | sca_out(rxs, msci + RXS, card); |
151 | sca_out(txs, msci + TXS, card); | 152 | sca_out(txs, msci + TXS, card); |
152 | sca_set_port(port); | 153 | sca_set_port(port); |
153 | } | 154 | } |
154 | 155 | ||
155 | 156 | ||
156 | 157 | ||
157 | static int pci200_open(struct net_device *dev) | 158 | static int pci200_open(struct net_device *dev) |
158 | { | 159 | { |
159 | port_t *port = dev_to_port(dev); | 160 | port_t *port = dev_to_port(dev); |
160 | 161 | ||
161 | int result = hdlc_open(dev); | 162 | int result = hdlc_open(dev); |
162 | if (result) | 163 | if (result) |
163 | return result; | 164 | return result; |
164 | 165 | ||
165 | sca_open(dev); | 166 | sca_open(dev); |
166 | pci200_set_iface(port); | 167 | pci200_set_iface(port); |
167 | sca_flush(port->card); | 168 | sca_flush(port->card); |
168 | return 0; | 169 | return 0; |
169 | } | 170 | } |
170 | 171 | ||
171 | 172 | ||
172 | 173 | ||
173 | static int pci200_close(struct net_device *dev) | 174 | static int pci200_close(struct net_device *dev) |
174 | { | 175 | { |
175 | sca_close(dev); | 176 | sca_close(dev); |
176 | sca_flush(dev_to_port(dev)->card); | 177 | sca_flush(dev_to_port(dev)->card); |
177 | hdlc_close(dev); | 178 | hdlc_close(dev); |
178 | return 0; | 179 | return 0; |
179 | } | 180 | } |
180 | 181 | ||
181 | 182 | ||
182 | 183 | ||
183 | static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 184 | static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
184 | { | 185 | { |
185 | const size_t size = sizeof(sync_serial_settings); | 186 | const size_t size = sizeof(sync_serial_settings); |
186 | sync_serial_settings new_line; | 187 | sync_serial_settings new_line; |
187 | sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; | 188 | sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; |
188 | port_t *port = dev_to_port(dev); | 189 | port_t *port = dev_to_port(dev); |
189 | 190 | ||
190 | #ifdef DEBUG_RINGS | 191 | #ifdef DEBUG_RINGS |
191 | if (cmd == SIOCDEVPRIVATE) { | 192 | if (cmd == SIOCDEVPRIVATE) { |
192 | sca_dump_rings(dev); | 193 | sca_dump_rings(dev); |
193 | return 0; | 194 | return 0; |
194 | } | 195 | } |
195 | #endif | 196 | #endif |
196 | if (cmd != SIOCWANDEV) | 197 | if (cmd != SIOCWANDEV) |
197 | return hdlc_ioctl(dev, ifr, cmd); | 198 | return hdlc_ioctl(dev, ifr, cmd); |
198 | 199 | ||
199 | switch(ifr->ifr_settings.type) { | 200 | switch(ifr->ifr_settings.type) { |
200 | case IF_GET_IFACE: | 201 | case IF_GET_IFACE: |
201 | ifr->ifr_settings.type = IF_IFACE_V35; | 202 | ifr->ifr_settings.type = IF_IFACE_V35; |
202 | if (ifr->ifr_settings.size < size) { | 203 | if (ifr->ifr_settings.size < size) { |
203 | ifr->ifr_settings.size = size; /* data size wanted */ | 204 | ifr->ifr_settings.size = size; /* data size wanted */ |
204 | return -ENOBUFS; | 205 | return -ENOBUFS; |
205 | } | 206 | } |
206 | if (copy_to_user(line, &port->settings, size)) | 207 | if (copy_to_user(line, &port->settings, size)) |
207 | return -EFAULT; | 208 | return -EFAULT; |
208 | return 0; | 209 | return 0; |
209 | 210 | ||
210 | case IF_IFACE_V35: | 211 | case IF_IFACE_V35: |
211 | case IF_IFACE_SYNC_SERIAL: | 212 | case IF_IFACE_SYNC_SERIAL: |
212 | if (!capable(CAP_NET_ADMIN)) | 213 | if (!capable(CAP_NET_ADMIN)) |
213 | return -EPERM; | 214 | return -EPERM; |
214 | 215 | ||
215 | if (copy_from_user(&new_line, line, size)) | 216 | if (copy_from_user(&new_line, line, size)) |
216 | return -EFAULT; | 217 | return -EFAULT; |
217 | 218 | ||
218 | if (new_line.clock_type != CLOCK_EXT && | 219 | if (new_line.clock_type != CLOCK_EXT && |
219 | new_line.clock_type != CLOCK_TXFROMRX && | 220 | new_line.clock_type != CLOCK_TXFROMRX && |
220 | new_line.clock_type != CLOCK_INT && | 221 | new_line.clock_type != CLOCK_INT && |
221 | new_line.clock_type != CLOCK_TXINT) | 222 | new_line.clock_type != CLOCK_TXINT) |
222 | return -EINVAL; /* No such clock setting */ | 223 | return -EINVAL; /* No such clock setting */ |
223 | 224 | ||
224 | if (new_line.loopback != 0 && new_line.loopback != 1) | 225 | if (new_line.loopback != 0 && new_line.loopback != 1) |
225 | return -EINVAL; | 226 | return -EINVAL; |
226 | 227 | ||
227 | memcpy(&port->settings, &new_line, size); /* Update settings */ | 228 | memcpy(&port->settings, &new_line, size); /* Update settings */ |
228 | pci200_set_iface(port); | 229 | pci200_set_iface(port); |
229 | sca_flush(port->card); | 230 | sca_flush(port->card); |
230 | return 0; | 231 | return 0; |
231 | 232 | ||
232 | default: | 233 | default: |
233 | return hdlc_ioctl(dev, ifr, cmd); | 234 | return hdlc_ioctl(dev, ifr, cmd); |
234 | } | 235 | } |
235 | } | 236 | } |
236 | 237 | ||
237 | 238 | ||
238 | 239 | ||
239 | static void pci200_pci_remove_one(struct pci_dev *pdev) | 240 | static void pci200_pci_remove_one(struct pci_dev *pdev) |
240 | { | 241 | { |
241 | int i; | 242 | int i; |
242 | card_t *card = pci_get_drvdata(pdev); | 243 | card_t *card = pci_get_drvdata(pdev); |
243 | 244 | ||
244 | for (i = 0; i < 2; i++) | 245 | for (i = 0; i < 2; i++) |
245 | if (card->ports[i].card) | 246 | if (card->ports[i].card) |
246 | unregister_hdlc_device(card->ports[i].netdev); | 247 | unregister_hdlc_device(card->ports[i].netdev); |
247 | 248 | ||
248 | if (card->irq) | 249 | if (card->irq) |
249 | free_irq(card->irq, card); | 250 | free_irq(card->irq, card); |
250 | 251 | ||
251 | if (card->rambase) | 252 | if (card->rambase) |
252 | iounmap(card->rambase); | 253 | iounmap(card->rambase); |
253 | if (card->scabase) | 254 | if (card->scabase) |
254 | iounmap(card->scabase); | 255 | iounmap(card->scabase); |
255 | if (card->plxbase) | 256 | if (card->plxbase) |
256 | iounmap(card->plxbase); | 257 | iounmap(card->plxbase); |
257 | 258 | ||
258 | pci_release_regions(pdev); | 259 | pci_release_regions(pdev); |
259 | pci_disable_device(pdev); | 260 | pci_disable_device(pdev); |
260 | pci_set_drvdata(pdev, NULL); | 261 | pci_set_drvdata(pdev, NULL); |
261 | if (card->ports[0].netdev) | 262 | if (card->ports[0].netdev) |
262 | free_netdev(card->ports[0].netdev); | 263 | free_netdev(card->ports[0].netdev); |
263 | if (card->ports[1].netdev) | 264 | if (card->ports[1].netdev) |
264 | free_netdev(card->ports[1].netdev); | 265 | free_netdev(card->ports[1].netdev); |
265 | kfree(card); | 266 | kfree(card); |
266 | } | 267 | } |
267 | 268 | ||
268 | static const struct net_device_ops pci200_ops = { | 269 | static const struct net_device_ops pci200_ops = { |
269 | .ndo_open = pci200_open, | 270 | .ndo_open = pci200_open, |
270 | .ndo_stop = pci200_close, | 271 | .ndo_stop = pci200_close, |
271 | .ndo_change_mtu = hdlc_change_mtu, | 272 | .ndo_change_mtu = hdlc_change_mtu, |
272 | .ndo_start_xmit = hdlc_start_xmit, | 273 | .ndo_start_xmit = hdlc_start_xmit, |
273 | .ndo_do_ioctl = pci200_ioctl, | 274 | .ndo_do_ioctl = pci200_ioctl, |
274 | }; | 275 | }; |
275 | 276 | ||
276 | static int __devinit pci200_pci_init_one(struct pci_dev *pdev, | 277 | static int __devinit pci200_pci_init_one(struct pci_dev *pdev, |
277 | const struct pci_device_id *ent) | 278 | const struct pci_device_id *ent) |
278 | { | 279 | { |
279 | card_t *card; | 280 | card_t *card; |
280 | u32 __iomem *p; | 281 | u32 __iomem *p; |
281 | int i; | 282 | int i; |
282 | u32 ramsize; | 283 | u32 ramsize; |
283 | u32 ramphys; /* buffer memory base */ | 284 | u32 ramphys; /* buffer memory base */ |
284 | u32 scaphys; /* SCA memory base */ | 285 | u32 scaphys; /* SCA memory base */ |
285 | u32 plxphys; /* PLX registers memory base */ | 286 | u32 plxphys; /* PLX registers memory base */ |
286 | 287 | ||
287 | i = pci_enable_device(pdev); | 288 | i = pci_enable_device(pdev); |
288 | if (i) | 289 | if (i) |
289 | return i; | 290 | return i; |
290 | 291 | ||
291 | i = pci_request_regions(pdev, "PCI200SYN"); | 292 | i = pci_request_regions(pdev, "PCI200SYN"); |
292 | if (i) { | 293 | if (i) { |
293 | pci_disable_device(pdev); | 294 | pci_disable_device(pdev); |
294 | return i; | 295 | return i; |
295 | } | 296 | } |
296 | 297 | ||
297 | card = kzalloc(sizeof(card_t), GFP_KERNEL); | 298 | card = kzalloc(sizeof(card_t), GFP_KERNEL); |
298 | if (card == NULL) { | 299 | if (card == NULL) { |
299 | printk(KERN_ERR "pci200syn: unable to allocate memory\n"); | 300 | printk(KERN_ERR "pci200syn: unable to allocate memory\n"); |
300 | pci_release_regions(pdev); | 301 | pci_release_regions(pdev); |
301 | pci_disable_device(pdev); | 302 | pci_disable_device(pdev); |
302 | return -ENOBUFS; | 303 | return -ENOBUFS; |
303 | } | 304 | } |
304 | pci_set_drvdata(pdev, card); | 305 | pci_set_drvdata(pdev, card); |
305 | card->ports[0].netdev = alloc_hdlcdev(&card->ports[0]); | 306 | card->ports[0].netdev = alloc_hdlcdev(&card->ports[0]); |
306 | card->ports[1].netdev = alloc_hdlcdev(&card->ports[1]); | 307 | card->ports[1].netdev = alloc_hdlcdev(&card->ports[1]); |
307 | if (!card->ports[0].netdev || !card->ports[1].netdev) { | 308 | if (!card->ports[0].netdev || !card->ports[1].netdev) { |
308 | printk(KERN_ERR "pci200syn: unable to allocate memory\n"); | 309 | printk(KERN_ERR "pci200syn: unable to allocate memory\n"); |
309 | pci200_pci_remove_one(pdev); | 310 | pci200_pci_remove_one(pdev); |
310 | return -ENOMEM; | 311 | return -ENOMEM; |
311 | } | 312 | } |
312 | 313 | ||
313 | if (pci_resource_len(pdev, 0) != PCI200SYN_PLX_SIZE || | 314 | if (pci_resource_len(pdev, 0) != PCI200SYN_PLX_SIZE || |
314 | pci_resource_len(pdev, 2) != PCI200SYN_SCA_SIZE || | 315 | pci_resource_len(pdev, 2) != PCI200SYN_SCA_SIZE || |
315 | pci_resource_len(pdev, 3) < 16384) { | 316 | pci_resource_len(pdev, 3) < 16384) { |
316 | printk(KERN_ERR "pci200syn: invalid card EEPROM parameters\n"); | 317 | printk(KERN_ERR "pci200syn: invalid card EEPROM parameters\n"); |
317 | pci200_pci_remove_one(pdev); | 318 | pci200_pci_remove_one(pdev); |
318 | return -EFAULT; | 319 | return -EFAULT; |
319 | } | 320 | } |
320 | 321 | ||
321 | plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK; | 322 | plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK; |
322 | card->plxbase = ioremap(plxphys, PCI200SYN_PLX_SIZE); | 323 | card->plxbase = ioremap(plxphys, PCI200SYN_PLX_SIZE); |
323 | 324 | ||
324 | scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK; | 325 | scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK; |
325 | card->scabase = ioremap(scaphys, PCI200SYN_SCA_SIZE); | 326 | card->scabase = ioremap(scaphys, PCI200SYN_SCA_SIZE); |
326 | 327 | ||
327 | ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK; | 328 | ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK; |
328 | card->rambase = pci_ioremap_bar(pdev, 3); | 329 | card->rambase = pci_ioremap_bar(pdev, 3); |
329 | 330 | ||
330 | if (card->plxbase == NULL || | 331 | if (card->plxbase == NULL || |
331 | card->scabase == NULL || | 332 | card->scabase == NULL || |
332 | card->rambase == NULL) { | 333 | card->rambase == NULL) { |
333 | printk(KERN_ERR "pci200syn: ioremap() failed\n"); | 334 | printk(KERN_ERR "pci200syn: ioremap() failed\n"); |
334 | pci200_pci_remove_one(pdev); | 335 | pci200_pci_remove_one(pdev); |
335 | return -EFAULT; | 336 | return -EFAULT; |
336 | } | 337 | } |
337 | 338 | ||
338 | /* Reset PLX */ | 339 | /* Reset PLX */ |
339 | p = &card->plxbase->init_ctrl; | 340 | p = &card->plxbase->init_ctrl; |
340 | writel(readl(p) | 0x40000000, p); | 341 | writel(readl(p) | 0x40000000, p); |
341 | readl(p); /* Flush the write - do not use sca_flush */ | 342 | readl(p); /* Flush the write - do not use sca_flush */ |
342 | udelay(1); | 343 | udelay(1); |
343 | 344 | ||
344 | writel(readl(p) & ~0x40000000, p); | 345 | writel(readl(p) & ~0x40000000, p); |
345 | readl(p); /* Flush the write - do not use sca_flush */ | 346 | readl(p); /* Flush the write - do not use sca_flush */ |
346 | udelay(1); | 347 | udelay(1); |
347 | 348 | ||
348 | ramsize = sca_detect_ram(card, card->rambase, | 349 | ramsize = sca_detect_ram(card, card->rambase, |
349 | pci_resource_len(pdev, 3)); | 350 | pci_resource_len(pdev, 3)); |
350 | 351 | ||
351 | /* number of TX + RX buffers for one port - this is dual port card */ | 352 | /* number of TX + RX buffers for one port - this is dual port card */ |
352 | i = ramsize / (2 * (sizeof(pkt_desc) + HDLC_MAX_MRU)); | 353 | i = ramsize / (2 * (sizeof(pkt_desc) + HDLC_MAX_MRU)); |
353 | card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS); | 354 | card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS); |
354 | card->rx_ring_buffers = i - card->tx_ring_buffers; | 355 | card->rx_ring_buffers = i - card->tx_ring_buffers; |
355 | 356 | ||
356 | card->buff_offset = 2 * sizeof(pkt_desc) * (card->tx_ring_buffers + | 357 | card->buff_offset = 2 * sizeof(pkt_desc) * (card->tx_ring_buffers + |
357 | card->rx_ring_buffers); | 358 | card->rx_ring_buffers); |
358 | 359 | ||
359 | printk(KERN_INFO "pci200syn: %u KB RAM at 0x%x, IRQ%u, using %u TX +" | 360 | printk(KERN_INFO "pci200syn: %u KB RAM at 0x%x, IRQ%u, using %u TX +" |
360 | " %u RX packets rings\n", ramsize / 1024, ramphys, | 361 | " %u RX packets rings\n", ramsize / 1024, ramphys, |
361 | pdev->irq, card->tx_ring_buffers, card->rx_ring_buffers); | 362 | pdev->irq, card->tx_ring_buffers, card->rx_ring_buffers); |
362 | 363 | ||
363 | if (card->tx_ring_buffers < 1) { | 364 | if (card->tx_ring_buffers < 1) { |
364 | printk(KERN_ERR "pci200syn: RAM test failed\n"); | 365 | printk(KERN_ERR "pci200syn: RAM test failed\n"); |
365 | pci200_pci_remove_one(pdev); | 366 | pci200_pci_remove_one(pdev); |
366 | return -EFAULT; | 367 | return -EFAULT; |
367 | } | 368 | } |
368 | 369 | ||
369 | /* Enable interrupts on the PCI bridge */ | 370 | /* Enable interrupts on the PCI bridge */ |
370 | p = &card->plxbase->intr_ctrl_stat; | 371 | p = &card->plxbase->intr_ctrl_stat; |
371 | writew(readw(p) | 0x0040, p); | 372 | writew(readw(p) | 0x0040, p); |
372 | 373 | ||
373 | /* Allocate IRQ */ | 374 | /* Allocate IRQ */ |
374 | if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, "pci200syn", card)) { | 375 | if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, "pci200syn", card)) { |
375 | printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n", | 376 | printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n", |
376 | pdev->irq); | 377 | pdev->irq); |
377 | pci200_pci_remove_one(pdev); | 378 | pci200_pci_remove_one(pdev); |
378 | return -EBUSY; | 379 | return -EBUSY; |
379 | } | 380 | } |
380 | card->irq = pdev->irq; | 381 | card->irq = pdev->irq; |
381 | 382 | ||
382 | sca_init(card, 0); | 383 | sca_init(card, 0); |
383 | 384 | ||
384 | for (i = 0; i < 2; i++) { | 385 | for (i = 0; i < 2; i++) { |
385 | port_t *port = &card->ports[i]; | 386 | port_t *port = &card->ports[i]; |
386 | struct net_device *dev = port->netdev; | 387 | struct net_device *dev = port->netdev; |
387 | hdlc_device *hdlc = dev_to_hdlc(dev); | 388 | hdlc_device *hdlc = dev_to_hdlc(dev); |
388 | port->chan = i; | 389 | port->chan = i; |
389 | 390 | ||
390 | spin_lock_init(&port->lock); | 391 | spin_lock_init(&port->lock); |
391 | dev->irq = card->irq; | 392 | dev->irq = card->irq; |
392 | dev->mem_start = ramphys; | 393 | dev->mem_start = ramphys; |
393 | dev->mem_end = ramphys + ramsize - 1; | 394 | dev->mem_end = ramphys + ramsize - 1; |
394 | dev->tx_queue_len = 50; | 395 | dev->tx_queue_len = 50; |
395 | dev->netdev_ops = &pci200_ops; | 396 | dev->netdev_ops = &pci200_ops; |
396 | hdlc->attach = sca_attach; | 397 | hdlc->attach = sca_attach; |
397 | hdlc->xmit = sca_xmit; | 398 | hdlc->xmit = sca_xmit; |
398 | port->settings.clock_type = CLOCK_EXT; | 399 | port->settings.clock_type = CLOCK_EXT; |
399 | port->card = card; | 400 | port->card = card; |
400 | sca_init_port(port); | 401 | sca_init_port(port); |
401 | if (register_hdlc_device(dev)) { | 402 | if (register_hdlc_device(dev)) { |
402 | printk(KERN_ERR "pci200syn: unable to register hdlc " | 403 | printk(KERN_ERR "pci200syn: unable to register hdlc " |
403 | "device\n"); | 404 | "device\n"); |
404 | port->card = NULL; | 405 | port->card = NULL; |
405 | pci200_pci_remove_one(pdev); | 406 | pci200_pci_remove_one(pdev); |
406 | return -ENOBUFS; | 407 | return -ENOBUFS; |
407 | } | 408 | } |
408 | 409 | ||
409 | printk(KERN_INFO "%s: PCI200SYN channel %d\n", | 410 | printk(KERN_INFO "%s: PCI200SYN channel %d\n", |
410 | dev->name, port->chan); | 411 | dev->name, port->chan); |
411 | } | 412 | } |
412 | 413 | ||
413 | sca_flush(card); | 414 | sca_flush(card); |
414 | return 0; | 415 | return 0; |
415 | } | 416 | } |
416 | 417 | ||
417 | 418 | ||
418 | 419 | ||
419 | static struct pci_device_id pci200_pci_tbl[] __devinitdata = { | 420 | static struct pci_device_id pci200_pci_tbl[] __devinitdata = { |
420 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX, | 421 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX, |
421 | PCI_DEVICE_ID_PLX_PCI200SYN, 0, 0, 0 }, | 422 | PCI_DEVICE_ID_PLX_PCI200SYN, 0, 0, 0 }, |
422 | { 0, } | 423 | { 0, } |
423 | }; | 424 | }; |
424 | 425 | ||
425 | 426 | ||
426 | static struct pci_driver pci200_pci_driver = { | 427 | static struct pci_driver pci200_pci_driver = { |
427 | .name = "PCI200SYN", | 428 | .name = "PCI200SYN", |
428 | .id_table = pci200_pci_tbl, | 429 | .id_table = pci200_pci_tbl, |
429 | .probe = pci200_pci_init_one, | 430 | .probe = pci200_pci_init_one, |
430 | .remove = pci200_pci_remove_one, | 431 | .remove = pci200_pci_remove_one, |
431 | }; | 432 | }; |
432 | 433 | ||
433 | 434 | ||
434 | static int __init pci200_init_module(void) | 435 | static int __init pci200_init_module(void) |
435 | { | 436 | { |
436 | if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) { | 437 | if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) { |
437 | printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n"); | 438 | printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n"); |
438 | return -EINVAL; | 439 | return -EINVAL; |
439 | } | 440 | } |
440 | return pci_register_driver(&pci200_pci_driver); | 441 | return pci_register_driver(&pci200_pci_driver); |
441 | } | 442 | } |
442 | 443 | ||
443 | 444 | ||
444 | 445 | ||
445 | static void __exit pci200_cleanup_module(void) | 446 | static void __exit pci200_cleanup_module(void) |
446 | { | 447 | { |
447 | pci_unregister_driver(&pci200_pci_driver); | 448 | pci_unregister_driver(&pci200_pci_driver); |
448 | } | 449 | } |
449 | 450 | ||
450 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); | 451 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
451 | MODULE_DESCRIPTION("Goramo PCI200SYN serial port driver"); | 452 | MODULE_DESCRIPTION("Goramo PCI200SYN serial port driver"); |
452 | MODULE_LICENSE("GPL v2"); | 453 | MODULE_LICENSE("GPL v2"); |
453 | MODULE_DEVICE_TABLE(pci, pci200_pci_tbl); | 454 | MODULE_DEVICE_TABLE(pci, pci200_pci_tbl); |
454 | module_param(pci_clock_freq, int, 0444); | 455 | module_param(pci_clock_freq, int, 0444); |
455 | MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz"); | 456 | MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz"); |
456 | module_init(pci200_init_module); | 457 | module_init(pci200_init_module); |
457 | module_exit(pci200_cleanup_module); | 458 | module_exit(pci200_cleanup_module); |
458 | 459 |
drivers/pci/hotplug/cpqphp.h
1 | /* | 1 | /* |
2 | * Compaq Hot Plug Controller Driver | 2 | * Compaq Hot Plug Controller Driver |
3 | * | 3 | * |
4 | * Copyright (C) 1995,2001 Compaq Computer Corporation | 4 | * Copyright (C) 1995,2001 Compaq Computer Corporation |
5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) | 5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) |
6 | * Copyright (C) 2001 IBM | 6 | * Copyright (C) 2001 IBM |
7 | * | 7 | * |
8 | * All rights reserved. | 8 | * All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or (at | 12 | * the Free Software Foundation; either version 2 of the License, or (at |
13 | * your option) any later version. | 13 | * your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, but | 15 | * This program is distributed in the hope that it will be useful, but |
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | 17 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or |
18 | * NON INFRINGEMENT. See the GNU General Public License for more | 18 | * NON INFRINGEMENT. See the GNU General Public License for more |
19 | * details. | 19 | * details. |
20 | * | 20 | * |
21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
22 | * along with this program; if not, write to the Free Software | 22 | * along with this program; if not, write to the Free Software |
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | * | 24 | * |
25 | * Send feedback to <greg@kroah.com> | 25 | * Send feedback to <greg@kroah.com> |
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | #ifndef _CPQPHP_H | 28 | #ifndef _CPQPHP_H |
29 | #define _CPQPHP_H | 29 | #define _CPQPHP_H |
30 | 30 | ||
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <asm/io.h> /* for read? and write? functions */ | 32 | #include <asm/io.h> /* for read? and write? functions */ |
33 | #include <linux/delay.h> /* for delays */ | 33 | #include <linux/delay.h> /* for delays */ |
34 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
35 | #include <linux/sched.h> /* for signal_pending() */ | ||
35 | 36 | ||
36 | #define MY_NAME "cpqphp" | 37 | #define MY_NAME "cpqphp" |
37 | 38 | ||
38 | #define dbg(fmt, arg...) do { if (cpqhp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) | 39 | #define dbg(fmt, arg...) do { if (cpqhp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) |
39 | #define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) | 40 | #define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) |
40 | #define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) | 41 | #define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) |
41 | #define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) | 42 | #define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) |
42 | 43 | ||
43 | 44 | ||
44 | 45 | ||
45 | struct smbios_system_slot { | 46 | struct smbios_system_slot { |
46 | u8 type; | 47 | u8 type; |
47 | u8 length; | 48 | u8 length; |
48 | u16 handle; | 49 | u16 handle; |
49 | u8 name_string_num; | 50 | u8 name_string_num; |
50 | u8 slot_type; | 51 | u8 slot_type; |
51 | u8 slot_width; | 52 | u8 slot_width; |
52 | u8 slot_current_usage; | 53 | u8 slot_current_usage; |
53 | u8 slot_length; | 54 | u8 slot_length; |
54 | u16 slot_number; | 55 | u16 slot_number; |
55 | u8 properties1; | 56 | u8 properties1; |
56 | u8 properties2; | 57 | u8 properties2; |
57 | } __attribute__ ((packed)); | 58 | } __attribute__ ((packed)); |
58 | 59 | ||
59 | /* offsets to the smbios generic type based on the above structure layout */ | 60 | /* offsets to the smbios generic type based on the above structure layout */ |
60 | enum smbios_system_slot_offsets { | 61 | enum smbios_system_slot_offsets { |
61 | SMBIOS_SLOT_GENERIC_TYPE = offsetof(struct smbios_system_slot, type), | 62 | SMBIOS_SLOT_GENERIC_TYPE = offsetof(struct smbios_system_slot, type), |
62 | SMBIOS_SLOT_GENERIC_LENGTH = offsetof(struct smbios_system_slot, length), | 63 | SMBIOS_SLOT_GENERIC_LENGTH = offsetof(struct smbios_system_slot, length), |
63 | SMBIOS_SLOT_GENERIC_HANDLE = offsetof(struct smbios_system_slot, handle), | 64 | SMBIOS_SLOT_GENERIC_HANDLE = offsetof(struct smbios_system_slot, handle), |
64 | SMBIOS_SLOT_NAME_STRING_NUM = offsetof(struct smbios_system_slot, name_string_num), | 65 | SMBIOS_SLOT_NAME_STRING_NUM = offsetof(struct smbios_system_slot, name_string_num), |
65 | SMBIOS_SLOT_TYPE = offsetof(struct smbios_system_slot, slot_type), | 66 | SMBIOS_SLOT_TYPE = offsetof(struct smbios_system_slot, slot_type), |
66 | SMBIOS_SLOT_WIDTH = offsetof(struct smbios_system_slot, slot_width), | 67 | SMBIOS_SLOT_WIDTH = offsetof(struct smbios_system_slot, slot_width), |
67 | SMBIOS_SLOT_CURRENT_USAGE = offsetof(struct smbios_system_slot, slot_current_usage), | 68 | SMBIOS_SLOT_CURRENT_USAGE = offsetof(struct smbios_system_slot, slot_current_usage), |
68 | SMBIOS_SLOT_LENGTH = offsetof(struct smbios_system_slot, slot_length), | 69 | SMBIOS_SLOT_LENGTH = offsetof(struct smbios_system_slot, slot_length), |
69 | SMBIOS_SLOT_NUMBER = offsetof(struct smbios_system_slot, slot_number), | 70 | SMBIOS_SLOT_NUMBER = offsetof(struct smbios_system_slot, slot_number), |
70 | SMBIOS_SLOT_PROPERTIES1 = offsetof(struct smbios_system_slot, properties1), | 71 | SMBIOS_SLOT_PROPERTIES1 = offsetof(struct smbios_system_slot, properties1), |
71 | SMBIOS_SLOT_PROPERTIES2 = offsetof(struct smbios_system_slot, properties2), | 72 | SMBIOS_SLOT_PROPERTIES2 = offsetof(struct smbios_system_slot, properties2), |
72 | }; | 73 | }; |
73 | 74 | ||
74 | struct smbios_generic { | 75 | struct smbios_generic { |
75 | u8 type; | 76 | u8 type; |
76 | u8 length; | 77 | u8 length; |
77 | u16 handle; | 78 | u16 handle; |
78 | } __attribute__ ((packed)); | 79 | } __attribute__ ((packed)); |
79 | 80 | ||
80 | /* offsets to the smbios generic type based on the above structure layout */ | 81 | /* offsets to the smbios generic type based on the above structure layout */ |
81 | enum smbios_generic_offsets { | 82 | enum smbios_generic_offsets { |
82 | SMBIOS_GENERIC_TYPE = offsetof(struct smbios_generic, type), | 83 | SMBIOS_GENERIC_TYPE = offsetof(struct smbios_generic, type), |
83 | SMBIOS_GENERIC_LENGTH = offsetof(struct smbios_generic, length), | 84 | SMBIOS_GENERIC_LENGTH = offsetof(struct smbios_generic, length), |
84 | SMBIOS_GENERIC_HANDLE = offsetof(struct smbios_generic, handle), | 85 | SMBIOS_GENERIC_HANDLE = offsetof(struct smbios_generic, handle), |
85 | }; | 86 | }; |
86 | 87 | ||
87 | struct smbios_entry_point { | 88 | struct smbios_entry_point { |
88 | char anchor[4]; | 89 | char anchor[4]; |
89 | u8 ep_checksum; | 90 | u8 ep_checksum; |
90 | u8 ep_length; | 91 | u8 ep_length; |
91 | u8 major_version; | 92 | u8 major_version; |
92 | u8 minor_version; | 93 | u8 minor_version; |
93 | u16 max_size_entry; | 94 | u16 max_size_entry; |
94 | u8 ep_rev; | 95 | u8 ep_rev; |
95 | u8 reserved[5]; | 96 | u8 reserved[5]; |
96 | char int_anchor[5]; | 97 | char int_anchor[5]; |
97 | u8 int_checksum; | 98 | u8 int_checksum; |
98 | u16 st_length; | 99 | u16 st_length; |
99 | u32 st_address; | 100 | u32 st_address; |
100 | u16 number_of_entrys; | 101 | u16 number_of_entrys; |
101 | u8 bcd_rev; | 102 | u8 bcd_rev; |
102 | } __attribute__ ((packed)); | 103 | } __attribute__ ((packed)); |
103 | 104 | ||
104 | /* offsets to the smbios entry point based on the above structure layout */ | 105 | /* offsets to the smbios entry point based on the above structure layout */ |
105 | enum smbios_entry_point_offsets { | 106 | enum smbios_entry_point_offsets { |
106 | ANCHOR = offsetof(struct smbios_entry_point, anchor[0]), | 107 | ANCHOR = offsetof(struct smbios_entry_point, anchor[0]), |
107 | EP_CHECKSUM = offsetof(struct smbios_entry_point, ep_checksum), | 108 | EP_CHECKSUM = offsetof(struct smbios_entry_point, ep_checksum), |
108 | EP_LENGTH = offsetof(struct smbios_entry_point, ep_length), | 109 | EP_LENGTH = offsetof(struct smbios_entry_point, ep_length), |
109 | MAJOR_VERSION = offsetof(struct smbios_entry_point, major_version), | 110 | MAJOR_VERSION = offsetof(struct smbios_entry_point, major_version), |
110 | MINOR_VERSION = offsetof(struct smbios_entry_point, minor_version), | 111 | MINOR_VERSION = offsetof(struct smbios_entry_point, minor_version), |
111 | MAX_SIZE_ENTRY = offsetof(struct smbios_entry_point, max_size_entry), | 112 | MAX_SIZE_ENTRY = offsetof(struct smbios_entry_point, max_size_entry), |
112 | EP_REV = offsetof(struct smbios_entry_point, ep_rev), | 113 | EP_REV = offsetof(struct smbios_entry_point, ep_rev), |
113 | INT_ANCHOR = offsetof(struct smbios_entry_point, int_anchor[0]), | 114 | INT_ANCHOR = offsetof(struct smbios_entry_point, int_anchor[0]), |
114 | INT_CHECKSUM = offsetof(struct smbios_entry_point, int_checksum), | 115 | INT_CHECKSUM = offsetof(struct smbios_entry_point, int_checksum), |
115 | ST_LENGTH = offsetof(struct smbios_entry_point, st_length), | 116 | ST_LENGTH = offsetof(struct smbios_entry_point, st_length), |
116 | ST_ADDRESS = offsetof(struct smbios_entry_point, st_address), | 117 | ST_ADDRESS = offsetof(struct smbios_entry_point, st_address), |
117 | NUMBER_OF_ENTRYS = offsetof(struct smbios_entry_point, number_of_entrys), | 118 | NUMBER_OF_ENTRYS = offsetof(struct smbios_entry_point, number_of_entrys), |
118 | BCD_REV = offsetof(struct smbios_entry_point, bcd_rev), | 119 | BCD_REV = offsetof(struct smbios_entry_point, bcd_rev), |
119 | }; | 120 | }; |
120 | 121 | ||
121 | struct ctrl_reg { /* offset */ | 122 | struct ctrl_reg { /* offset */ |
122 | u8 slot_RST; /* 0x00 */ | 123 | u8 slot_RST; /* 0x00 */ |
123 | u8 slot_enable; /* 0x01 */ | 124 | u8 slot_enable; /* 0x01 */ |
124 | u16 misc; /* 0x02 */ | 125 | u16 misc; /* 0x02 */ |
125 | u32 led_control; /* 0x04 */ | 126 | u32 led_control; /* 0x04 */ |
126 | u32 int_input_clear; /* 0x08 */ | 127 | u32 int_input_clear; /* 0x08 */ |
127 | u32 int_mask; /* 0x0a */ | 128 | u32 int_mask; /* 0x0a */ |
128 | u8 reserved0; /* 0x10 */ | 129 | u8 reserved0; /* 0x10 */ |
129 | u8 reserved1; /* 0x11 */ | 130 | u8 reserved1; /* 0x11 */ |
130 | u8 reserved2; /* 0x12 */ | 131 | u8 reserved2; /* 0x12 */ |
131 | u8 gen_output_AB; /* 0x13 */ | 132 | u8 gen_output_AB; /* 0x13 */ |
132 | u32 non_int_input; /* 0x14 */ | 133 | u32 non_int_input; /* 0x14 */ |
133 | u32 reserved3; /* 0x18 */ | 134 | u32 reserved3; /* 0x18 */ |
134 | u32 reserved4; /* 0x1a */ | 135 | u32 reserved4; /* 0x1a */ |
135 | u32 reserved5; /* 0x20 */ | 136 | u32 reserved5; /* 0x20 */ |
136 | u8 reserved6; /* 0x24 */ | 137 | u8 reserved6; /* 0x24 */ |
137 | u8 reserved7; /* 0x25 */ | 138 | u8 reserved7; /* 0x25 */ |
138 | u16 reserved8; /* 0x26 */ | 139 | u16 reserved8; /* 0x26 */ |
139 | u8 slot_mask; /* 0x28 */ | 140 | u8 slot_mask; /* 0x28 */ |
140 | u8 reserved9; /* 0x29 */ | 141 | u8 reserved9; /* 0x29 */ |
141 | u8 reserved10; /* 0x2a */ | 142 | u8 reserved10; /* 0x2a */ |
142 | u8 reserved11; /* 0x2b */ | 143 | u8 reserved11; /* 0x2b */ |
143 | u8 slot_SERR; /* 0x2c */ | 144 | u8 slot_SERR; /* 0x2c */ |
144 | u8 slot_power; /* 0x2d */ | 145 | u8 slot_power; /* 0x2d */ |
145 | u8 reserved12; /* 0x2e */ | 146 | u8 reserved12; /* 0x2e */ |
146 | u8 reserved13; /* 0x2f */ | 147 | u8 reserved13; /* 0x2f */ |
147 | u8 next_curr_freq; /* 0x30 */ | 148 | u8 next_curr_freq; /* 0x30 */ |
148 | u8 reset_freq_mode; /* 0x31 */ | 149 | u8 reset_freq_mode; /* 0x31 */ |
149 | } __attribute__ ((packed)); | 150 | } __attribute__ ((packed)); |
150 | 151 | ||
151 | /* offsets to the controller registers based on the above structure layout */ | 152 | /* offsets to the controller registers based on the above structure layout */ |
152 | enum ctrl_offsets { | 153 | enum ctrl_offsets { |
153 | SLOT_RST = offsetof(struct ctrl_reg, slot_RST), | 154 | SLOT_RST = offsetof(struct ctrl_reg, slot_RST), |
154 | SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), | 155 | SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), |
155 | MISC = offsetof(struct ctrl_reg, misc), | 156 | MISC = offsetof(struct ctrl_reg, misc), |
156 | LED_CONTROL = offsetof(struct ctrl_reg, led_control), | 157 | LED_CONTROL = offsetof(struct ctrl_reg, led_control), |
157 | INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), | 158 | INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), |
158 | INT_MASK = offsetof(struct ctrl_reg, int_mask), | 159 | INT_MASK = offsetof(struct ctrl_reg, int_mask), |
159 | CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), | 160 | CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), |
160 | CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), | 161 | CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), |
161 | CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), | 162 | CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), |
162 | GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), | 163 | GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), |
163 | NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), | 164 | NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), |
164 | CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), | 165 | CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), |
165 | CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), | 166 | CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), |
166 | CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), | 167 | CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), |
167 | CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), | 168 | CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), |
168 | CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), | 169 | CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), |
169 | CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), | 170 | CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), |
170 | SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), | 171 | SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), |
171 | CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), | 172 | CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), |
172 | CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), | 173 | CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), |
173 | CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), | 174 | CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), |
174 | SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), | 175 | SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), |
175 | SLOT_POWER = offsetof(struct ctrl_reg, slot_power), | 176 | SLOT_POWER = offsetof(struct ctrl_reg, slot_power), |
176 | NEXT_CURR_FREQ = offsetof(struct ctrl_reg, next_curr_freq), | 177 | NEXT_CURR_FREQ = offsetof(struct ctrl_reg, next_curr_freq), |
177 | RESET_FREQ_MODE = offsetof(struct ctrl_reg, reset_freq_mode), | 178 | RESET_FREQ_MODE = offsetof(struct ctrl_reg, reset_freq_mode), |
178 | }; | 179 | }; |
179 | 180 | ||
180 | struct hrt { | 181 | struct hrt { |
181 | char sig0; | 182 | char sig0; |
182 | char sig1; | 183 | char sig1; |
183 | char sig2; | 184 | char sig2; |
184 | char sig3; | 185 | char sig3; |
185 | u16 unused_IRQ; | 186 | u16 unused_IRQ; |
186 | u16 PCIIRQ; | 187 | u16 PCIIRQ; |
187 | u8 number_of_entries; | 188 | u8 number_of_entries; |
188 | u8 revision; | 189 | u8 revision; |
189 | u16 reserved1; | 190 | u16 reserved1; |
190 | u32 reserved2; | 191 | u32 reserved2; |
191 | } __attribute__ ((packed)); | 192 | } __attribute__ ((packed)); |
192 | 193 | ||
193 | /* offsets to the hotplug resource table registers based on the above | 194 | /* offsets to the hotplug resource table registers based on the above |
194 | * structure layout | 195 | * structure layout |
195 | */ | 196 | */ |
196 | enum hrt_offsets { | 197 | enum hrt_offsets { |
197 | SIG0 = offsetof(struct hrt, sig0), | 198 | SIG0 = offsetof(struct hrt, sig0), |
198 | SIG1 = offsetof(struct hrt, sig1), | 199 | SIG1 = offsetof(struct hrt, sig1), |
199 | SIG2 = offsetof(struct hrt, sig2), | 200 | SIG2 = offsetof(struct hrt, sig2), |
200 | SIG3 = offsetof(struct hrt, sig3), | 201 | SIG3 = offsetof(struct hrt, sig3), |
201 | UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), | 202 | UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), |
202 | PCIIRQ = offsetof(struct hrt, PCIIRQ), | 203 | PCIIRQ = offsetof(struct hrt, PCIIRQ), |
203 | NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), | 204 | NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), |
204 | REVISION = offsetof(struct hrt, revision), | 205 | REVISION = offsetof(struct hrt, revision), |
205 | HRT_RESERVED1 = offsetof(struct hrt, reserved1), | 206 | HRT_RESERVED1 = offsetof(struct hrt, reserved1), |
206 | HRT_RESERVED2 = offsetof(struct hrt, reserved2), | 207 | HRT_RESERVED2 = offsetof(struct hrt, reserved2), |
207 | }; | 208 | }; |
208 | 209 | ||
209 | struct slot_rt { | 210 | struct slot_rt { |
210 | u8 dev_func; | 211 | u8 dev_func; |
211 | u8 primary_bus; | 212 | u8 primary_bus; |
212 | u8 secondary_bus; | 213 | u8 secondary_bus; |
213 | u8 max_bus; | 214 | u8 max_bus; |
214 | u16 io_base; | 215 | u16 io_base; |
215 | u16 io_length; | 216 | u16 io_length; |
216 | u16 mem_base; | 217 | u16 mem_base; |
217 | u16 mem_length; | 218 | u16 mem_length; |
218 | u16 pre_mem_base; | 219 | u16 pre_mem_base; |
219 | u16 pre_mem_length; | 220 | u16 pre_mem_length; |
220 | } __attribute__ ((packed)); | 221 | } __attribute__ ((packed)); |
221 | 222 | ||
222 | /* offsets to the hotplug slot resource table registers based on the above | 223 | /* offsets to the hotplug slot resource table registers based on the above |
223 | * structure layout | 224 | * structure layout |
224 | */ | 225 | */ |
225 | enum slot_rt_offsets { | 226 | enum slot_rt_offsets { |
226 | DEV_FUNC = offsetof(struct slot_rt, dev_func), | 227 | DEV_FUNC = offsetof(struct slot_rt, dev_func), |
227 | PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), | 228 | PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), |
228 | SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), | 229 | SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), |
229 | MAX_BUS = offsetof(struct slot_rt, max_bus), | 230 | MAX_BUS = offsetof(struct slot_rt, max_bus), |
230 | IO_BASE = offsetof(struct slot_rt, io_base), | 231 | IO_BASE = offsetof(struct slot_rt, io_base), |
231 | IO_LENGTH = offsetof(struct slot_rt, io_length), | 232 | IO_LENGTH = offsetof(struct slot_rt, io_length), |
232 | MEM_BASE = offsetof(struct slot_rt, mem_base), | 233 | MEM_BASE = offsetof(struct slot_rt, mem_base), |
233 | MEM_LENGTH = offsetof(struct slot_rt, mem_length), | 234 | MEM_LENGTH = offsetof(struct slot_rt, mem_length), |
234 | PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), | 235 | PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), |
235 | PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), | 236 | PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), |
236 | }; | 237 | }; |
237 | 238 | ||
238 | struct pci_func { | 239 | struct pci_func { |
239 | struct pci_func *next; | 240 | struct pci_func *next; |
240 | u8 bus; | 241 | u8 bus; |
241 | u8 device; | 242 | u8 device; |
242 | u8 function; | 243 | u8 function; |
243 | u8 is_a_board; | 244 | u8 is_a_board; |
244 | u16 status; | 245 | u16 status; |
245 | u8 configured; | 246 | u8 configured; |
246 | u8 switch_save; | 247 | u8 switch_save; |
247 | u8 presence_save; | 248 | u8 presence_save; |
248 | u32 base_length[0x06]; | 249 | u32 base_length[0x06]; |
249 | u8 base_type[0x06]; | 250 | u8 base_type[0x06]; |
250 | u16 reserved2; | 251 | u16 reserved2; |
251 | u32 config_space[0x20]; | 252 | u32 config_space[0x20]; |
252 | struct pci_resource *mem_head; | 253 | struct pci_resource *mem_head; |
253 | struct pci_resource *p_mem_head; | 254 | struct pci_resource *p_mem_head; |
254 | struct pci_resource *io_head; | 255 | struct pci_resource *io_head; |
255 | struct pci_resource *bus_head; | 256 | struct pci_resource *bus_head; |
256 | struct timer_list *p_task_event; | 257 | struct timer_list *p_task_event; |
257 | struct pci_dev* pci_dev; | 258 | struct pci_dev* pci_dev; |
258 | }; | 259 | }; |
259 | 260 | ||
260 | struct slot { | 261 | struct slot { |
261 | struct slot *next; | 262 | struct slot *next; |
262 | u8 bus; | 263 | u8 bus; |
263 | u8 device; | 264 | u8 device; |
264 | u8 number; | 265 | u8 number; |
265 | u8 is_a_board; | 266 | u8 is_a_board; |
266 | u8 configured; | 267 | u8 configured; |
267 | u8 state; | 268 | u8 state; |
268 | u8 switch_save; | 269 | u8 switch_save; |
269 | u8 presence_save; | 270 | u8 presence_save; |
270 | u32 capabilities; | 271 | u32 capabilities; |
271 | u16 reserved2; | 272 | u16 reserved2; |
272 | struct timer_list task_event; | 273 | struct timer_list task_event; |
273 | u8 hp_slot; | 274 | u8 hp_slot; |
274 | struct controller *ctrl; | 275 | struct controller *ctrl; |
275 | void __iomem *p_sm_slot; | 276 | void __iomem *p_sm_slot; |
276 | struct hotplug_slot *hotplug_slot; | 277 | struct hotplug_slot *hotplug_slot; |
277 | }; | 278 | }; |
278 | 279 | ||
279 | struct pci_resource { | 280 | struct pci_resource { |
280 | struct pci_resource * next; | 281 | struct pci_resource * next; |
281 | u32 base; | 282 | u32 base; |
282 | u32 length; | 283 | u32 length; |
283 | }; | 284 | }; |
284 | 285 | ||
285 | struct event_info { | 286 | struct event_info { |
286 | u32 event_type; | 287 | u32 event_type; |
287 | u8 hp_slot; | 288 | u8 hp_slot; |
288 | }; | 289 | }; |
289 | 290 | ||
290 | struct controller { | 291 | struct controller { |
291 | struct controller *next; | 292 | struct controller *next; |
292 | u32 ctrl_int_comp; | 293 | u32 ctrl_int_comp; |
293 | struct mutex crit_sect; /* critical section mutex */ | 294 | struct mutex crit_sect; /* critical section mutex */ |
294 | void __iomem *hpc_reg; /* cookie for our pci controller location */ | 295 | void __iomem *hpc_reg; /* cookie for our pci controller location */ |
295 | struct pci_resource *mem_head; | 296 | struct pci_resource *mem_head; |
296 | struct pci_resource *p_mem_head; | 297 | struct pci_resource *p_mem_head; |
297 | struct pci_resource *io_head; | 298 | struct pci_resource *io_head; |
298 | struct pci_resource *bus_head; | 299 | struct pci_resource *bus_head; |
299 | struct pci_dev *pci_dev; | 300 | struct pci_dev *pci_dev; |
300 | struct pci_bus *pci_bus; | 301 | struct pci_bus *pci_bus; |
301 | struct event_info event_queue[10]; | 302 | struct event_info event_queue[10]; |
302 | struct slot *slot; | 303 | struct slot *slot; |
303 | u8 next_event; | 304 | u8 next_event; |
304 | u8 interrupt; | 305 | u8 interrupt; |
305 | u8 cfgspc_irq; | 306 | u8 cfgspc_irq; |
306 | u8 bus; /* bus number for the pci hotplug controller */ | 307 | u8 bus; /* bus number for the pci hotplug controller */ |
307 | u8 rev; | 308 | u8 rev; |
308 | u8 slot_device_offset; | 309 | u8 slot_device_offset; |
309 | u8 first_slot; | 310 | u8 first_slot; |
310 | u8 add_support; | 311 | u8 add_support; |
311 | u8 push_flag; | 312 | u8 push_flag; |
312 | enum pci_bus_speed speed; | 313 | enum pci_bus_speed speed; |
313 | enum pci_bus_speed speed_capability; | 314 | enum pci_bus_speed speed_capability; |
314 | u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */ | 315 | u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */ |
315 | u8 slot_switch_type; /* 0 = no switch, 1 = switch present */ | 316 | u8 slot_switch_type; /* 0 = no switch, 1 = switch present */ |
316 | u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */ | 317 | u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */ |
317 | u8 alternate_base_address; /* 0 = not supported, 1 = supported */ | 318 | u8 alternate_base_address; /* 0 = not supported, 1 = supported */ |
318 | u8 pci_config_space; /* Index/data access to working registers 0 = not supported, 1 = supported */ | 319 | u8 pci_config_space; /* Index/data access to working registers 0 = not supported, 1 = supported */ |
319 | u8 pcix_speed_capability; /* PCI-X */ | 320 | u8 pcix_speed_capability; /* PCI-X */ |
320 | u8 pcix_support; /* PCI-X */ | 321 | u8 pcix_support; /* PCI-X */ |
321 | u16 vendor_id; | 322 | u16 vendor_id; |
322 | struct work_struct int_task_event; | 323 | struct work_struct int_task_event; |
323 | wait_queue_head_t queue; /* sleep & wake process */ | 324 | wait_queue_head_t queue; /* sleep & wake process */ |
324 | struct dentry *dentry; /* debugfs dentry */ | 325 | struct dentry *dentry; /* debugfs dentry */ |
325 | }; | 326 | }; |
326 | 327 | ||
327 | struct irq_mapping { | 328 | struct irq_mapping { |
328 | u8 barber_pole; | 329 | u8 barber_pole; |
329 | u8 valid_INT; | 330 | u8 valid_INT; |
330 | u8 interrupt[4]; | 331 | u8 interrupt[4]; |
331 | }; | 332 | }; |
332 | 333 | ||
333 | struct resource_lists { | 334 | struct resource_lists { |
334 | struct pci_resource *mem_head; | 335 | struct pci_resource *mem_head; |
335 | struct pci_resource *p_mem_head; | 336 | struct pci_resource *p_mem_head; |
336 | struct pci_resource *io_head; | 337 | struct pci_resource *io_head; |
337 | struct pci_resource *bus_head; | 338 | struct pci_resource *bus_head; |
338 | struct irq_mapping *irqs; | 339 | struct irq_mapping *irqs; |
339 | }; | 340 | }; |
340 | 341 | ||
341 | #define ROM_PHY_ADDR 0x0F0000 | 342 | #define ROM_PHY_ADDR 0x0F0000 |
342 | #define ROM_PHY_LEN 0x00ffff | 343 | #define ROM_PHY_LEN 0x00ffff |
343 | 344 | ||
344 | #define PCI_HPC_ID 0xA0F7 | 345 | #define PCI_HPC_ID 0xA0F7 |
345 | #define PCI_SUB_HPC_ID 0xA2F7 | 346 | #define PCI_SUB_HPC_ID 0xA2F7 |
346 | #define PCI_SUB_HPC_ID2 0xA2F8 | 347 | #define PCI_SUB_HPC_ID2 0xA2F8 |
347 | #define PCI_SUB_HPC_ID3 0xA2F9 | 348 | #define PCI_SUB_HPC_ID3 0xA2F9 |
348 | #define PCI_SUB_HPC_ID_INTC 0xA2FA | 349 | #define PCI_SUB_HPC_ID_INTC 0xA2FA |
349 | #define PCI_SUB_HPC_ID4 0xA2FD | 350 | #define PCI_SUB_HPC_ID4 0xA2FD |
350 | 351 | ||
351 | #define INT_BUTTON_IGNORE 0 | 352 | #define INT_BUTTON_IGNORE 0 |
352 | #define INT_PRESENCE_ON 1 | 353 | #define INT_PRESENCE_ON 1 |
353 | #define INT_PRESENCE_OFF 2 | 354 | #define INT_PRESENCE_OFF 2 |
354 | #define INT_SWITCH_CLOSE 3 | 355 | #define INT_SWITCH_CLOSE 3 |
355 | #define INT_SWITCH_OPEN 4 | 356 | #define INT_SWITCH_OPEN 4 |
356 | #define INT_POWER_FAULT 5 | 357 | #define INT_POWER_FAULT 5 |
357 | #define INT_POWER_FAULT_CLEAR 6 | 358 | #define INT_POWER_FAULT_CLEAR 6 |
358 | #define INT_BUTTON_PRESS 7 | 359 | #define INT_BUTTON_PRESS 7 |
359 | #define INT_BUTTON_RELEASE 8 | 360 | #define INT_BUTTON_RELEASE 8 |
360 | #define INT_BUTTON_CANCEL 9 | 361 | #define INT_BUTTON_CANCEL 9 |
361 | 362 | ||
362 | #define STATIC_STATE 0 | 363 | #define STATIC_STATE 0 |
363 | #define BLINKINGON_STATE 1 | 364 | #define BLINKINGON_STATE 1 |
364 | #define BLINKINGOFF_STATE 2 | 365 | #define BLINKINGOFF_STATE 2 |
365 | #define POWERON_STATE 3 | 366 | #define POWERON_STATE 3 |
366 | #define POWEROFF_STATE 4 | 367 | #define POWEROFF_STATE 4 |
367 | 368 | ||
368 | #define PCISLOT_INTERLOCK_CLOSED 0x00000001 | 369 | #define PCISLOT_INTERLOCK_CLOSED 0x00000001 |
369 | #define PCISLOT_ADAPTER_PRESENT 0x00000002 | 370 | #define PCISLOT_ADAPTER_PRESENT 0x00000002 |
370 | #define PCISLOT_POWERED 0x00000004 | 371 | #define PCISLOT_POWERED 0x00000004 |
371 | #define PCISLOT_66_MHZ_OPERATION 0x00000008 | 372 | #define PCISLOT_66_MHZ_OPERATION 0x00000008 |
372 | #define PCISLOT_64_BIT_OPERATION 0x00000010 | 373 | #define PCISLOT_64_BIT_OPERATION 0x00000010 |
373 | #define PCISLOT_REPLACE_SUPPORTED 0x00000020 | 374 | #define PCISLOT_REPLACE_SUPPORTED 0x00000020 |
374 | #define PCISLOT_ADD_SUPPORTED 0x00000040 | 375 | #define PCISLOT_ADD_SUPPORTED 0x00000040 |
375 | #define PCISLOT_INTERLOCK_SUPPORTED 0x00000080 | 376 | #define PCISLOT_INTERLOCK_SUPPORTED 0x00000080 |
376 | #define PCISLOT_66_MHZ_SUPPORTED 0x00000100 | 377 | #define PCISLOT_66_MHZ_SUPPORTED 0x00000100 |
377 | #define PCISLOT_64_BIT_SUPPORTED 0x00000200 | 378 | #define PCISLOT_64_BIT_SUPPORTED 0x00000200 |
378 | 379 | ||
379 | #define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 | 380 | #define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 |
380 | 381 | ||
381 | #define INTERLOCK_OPEN 0x00000002 | 382 | #define INTERLOCK_OPEN 0x00000002 |
382 | #define ADD_NOT_SUPPORTED 0x00000003 | 383 | #define ADD_NOT_SUPPORTED 0x00000003 |
383 | #define CARD_FUNCTIONING 0x00000005 | 384 | #define CARD_FUNCTIONING 0x00000005 |
384 | #define ADAPTER_NOT_SAME 0x00000006 | 385 | #define ADAPTER_NOT_SAME 0x00000006 |
385 | #define NO_ADAPTER_PRESENT 0x00000009 | 386 | #define NO_ADAPTER_PRESENT 0x00000009 |
386 | #define NOT_ENOUGH_RESOURCES 0x0000000B | 387 | #define NOT_ENOUGH_RESOURCES 0x0000000B |
387 | #define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C | 388 | #define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C |
388 | #define POWER_FAILURE 0x0000000E | 389 | #define POWER_FAILURE 0x0000000E |
389 | 390 | ||
390 | #define REMOVE_NOT_SUPPORTED 0x00000003 | 391 | #define REMOVE_NOT_SUPPORTED 0x00000003 |
391 | 392 | ||
392 | 393 | ||
393 | /* | 394 | /* |
394 | * error Messages | 395 | * error Messages |
395 | */ | 396 | */ |
396 | #define msg_initialization_err "Initialization failure, error=%d\n" | 397 | #define msg_initialization_err "Initialization failure, error=%d\n" |
397 | #define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" | 398 | #define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" |
398 | #define msg_HPC_non_compaq_or_intel "The PCI hot plug controller is not supported by this driver.\n" | 399 | #define msg_HPC_non_compaq_or_intel "The PCI hot plug controller is not supported by this driver.\n" |
399 | #define msg_HPC_not_supported "this system is not supported by this version of cpqphpd. Upgrade to a newer version of cpqphpd\n" | 400 | #define msg_HPC_not_supported "this system is not supported by this version of cpqphpd. Upgrade to a newer version of cpqphpd\n" |
400 | #define msg_unable_to_save "unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" | 401 | #define msg_unable_to_save "unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" |
401 | #define msg_button_on "PCI slot #%d - powering on due to button press.\n" | 402 | #define msg_button_on "PCI slot #%d - powering on due to button press.\n" |
402 | #define msg_button_off "PCI slot #%d - powering off due to button press.\n" | 403 | #define msg_button_off "PCI slot #%d - powering off due to button press.\n" |
403 | #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" | 404 | #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" |
404 | #define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" | 405 | #define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" |
405 | 406 | ||
406 | 407 | ||
407 | /* debugfs functions for the hotplug controller info */ | 408 | /* debugfs functions for the hotplug controller info */ |
408 | extern void cpqhp_initialize_debugfs(void); | 409 | extern void cpqhp_initialize_debugfs(void); |
409 | extern void cpqhp_shutdown_debugfs(void); | 410 | extern void cpqhp_shutdown_debugfs(void); |
410 | extern void cpqhp_create_debugfs_files(struct controller *ctrl); | 411 | extern void cpqhp_create_debugfs_files(struct controller *ctrl); |
411 | extern void cpqhp_remove_debugfs_files(struct controller *ctrl); | 412 | extern void cpqhp_remove_debugfs_files(struct controller *ctrl); |
412 | 413 | ||
413 | /* controller functions */ | 414 | /* controller functions */ |
414 | extern void cpqhp_pushbutton_thread(unsigned long event_pointer); | 415 | extern void cpqhp_pushbutton_thread(unsigned long event_pointer); |
415 | extern irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data); | 416 | extern irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data); |
416 | extern int cpqhp_find_available_resources(struct controller *ctrl, | 417 | extern int cpqhp_find_available_resources(struct controller *ctrl, |
417 | void __iomem *rom_start); | 418 | void __iomem *rom_start); |
418 | extern int cpqhp_event_start_thread(void); | 419 | extern int cpqhp_event_start_thread(void); |
419 | extern void cpqhp_event_stop_thread(void); | 420 | extern void cpqhp_event_stop_thread(void); |
420 | extern struct pci_func *cpqhp_slot_create(unsigned char busnumber); | 421 | extern struct pci_func *cpqhp_slot_create(unsigned char busnumber); |
421 | extern struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device, | 422 | extern struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device, |
422 | unsigned char index); | 423 | unsigned char index); |
423 | extern int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func); | 424 | extern int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func); |
424 | extern int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func); | 425 | extern int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func); |
425 | extern int cpqhp_hardware_test(struct controller *ctrl, int test_num); | 426 | extern int cpqhp_hardware_test(struct controller *ctrl, int test_num); |
426 | 427 | ||
427 | /* resource functions */ | 428 | /* resource functions */ |
428 | extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); | 429 | extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); |
429 | 430 | ||
430 | /* pci functions */ | 431 | /* pci functions */ |
431 | extern int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); | 432 | extern int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); |
432 | extern int cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, | 433 | extern int cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, |
433 | u8 slot); | 434 | u8 slot); |
434 | extern int cpqhp_save_config(struct controller *ctrl, int busnumber, | 435 | extern int cpqhp_save_config(struct controller *ctrl, int busnumber, |
435 | int is_hot_plug); | 436 | int is_hot_plug); |
436 | extern int cpqhp_save_base_addr_length(struct controller *ctrl, | 437 | extern int cpqhp_save_base_addr_length(struct controller *ctrl, |
437 | struct pci_func *func); | 438 | struct pci_func *func); |
438 | extern int cpqhp_save_used_resources(struct controller *ctrl, | 439 | extern int cpqhp_save_used_resources(struct controller *ctrl, |
439 | struct pci_func *func); | 440 | struct pci_func *func); |
440 | extern int cpqhp_configure_board(struct controller *ctrl, | 441 | extern int cpqhp_configure_board(struct controller *ctrl, |
441 | struct pci_func *func); | 442 | struct pci_func *func); |
442 | extern int cpqhp_save_slot_config(struct controller *ctrl, | 443 | extern int cpqhp_save_slot_config(struct controller *ctrl, |
443 | struct pci_func *new_slot); | 444 | struct pci_func *new_slot); |
444 | extern int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func); | 445 | extern int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func); |
445 | extern void cpqhp_destroy_board_resources(struct pci_func *func); | 446 | extern void cpqhp_destroy_board_resources(struct pci_func *func); |
446 | extern int cpqhp_return_board_resources (struct pci_func *func, | 447 | extern int cpqhp_return_board_resources (struct pci_func *func, |
447 | struct resource_lists *resources); | 448 | struct resource_lists *resources); |
448 | extern void cpqhp_destroy_resource_list(struct resource_lists *resources); | 449 | extern void cpqhp_destroy_resource_list(struct resource_lists *resources); |
449 | extern int cpqhp_configure_device(struct controller *ctrl, | 450 | extern int cpqhp_configure_device(struct controller *ctrl, |
450 | struct pci_func *func); | 451 | struct pci_func *func); |
451 | extern int cpqhp_unconfigure_device(struct pci_func *func); | 452 | extern int cpqhp_unconfigure_device(struct pci_func *func); |
452 | 453 | ||
453 | /* Global variables */ | 454 | /* Global variables */ |
454 | extern int cpqhp_debug; | 455 | extern int cpqhp_debug; |
455 | extern int cpqhp_legacy_mode; | 456 | extern int cpqhp_legacy_mode; |
456 | extern struct controller *cpqhp_ctrl_list; | 457 | extern struct controller *cpqhp_ctrl_list; |
457 | extern struct pci_func *cpqhp_slot_list[256]; | 458 | extern struct pci_func *cpqhp_slot_list[256]; |
458 | extern struct irq_routing_table *cpqhp_routing_table; | 459 | extern struct irq_routing_table *cpqhp_routing_table; |
459 | 460 | ||
460 | /* these can be gotten rid of, but for debugging they are purty */ | 461 | /* these can be gotten rid of, but for debugging they are purty */ |
461 | extern u8 cpqhp_nic_irq; | 462 | extern u8 cpqhp_nic_irq; |
462 | extern u8 cpqhp_disk_irq; | 463 | extern u8 cpqhp_disk_irq; |
463 | 464 | ||
464 | 465 | ||
465 | /* inline functions */ | 466 | /* inline functions */ |
466 | 467 | ||
467 | static inline const char *slot_name(struct slot *slot) | 468 | static inline const char *slot_name(struct slot *slot) |
468 | { | 469 | { |
469 | return hotplug_slot_name(slot->hotplug_slot); | 470 | return hotplug_slot_name(slot->hotplug_slot); |
470 | } | 471 | } |
471 | 472 | ||
472 | /* | 473 | /* |
473 | * return_resource | 474 | * return_resource |
474 | * | 475 | * |
475 | * Puts node back in the resource list pointed to by head | 476 | * Puts node back in the resource list pointed to by head |
476 | */ | 477 | */ |
477 | static inline void return_resource(struct pci_resource **head, | 478 | static inline void return_resource(struct pci_resource **head, |
478 | struct pci_resource *node) | 479 | struct pci_resource *node) |
479 | { | 480 | { |
480 | if (!node || !head) | 481 | if (!node || !head) |
481 | return; | 482 | return; |
482 | node->next = *head; | 483 | node->next = *head; |
483 | *head = node; | 484 | *head = node; |
484 | } | 485 | } |
485 | 486 | ||
486 | static inline void set_SOGO(struct controller *ctrl) | 487 | static inline void set_SOGO(struct controller *ctrl) |
487 | { | 488 | { |
488 | u16 misc; | 489 | u16 misc; |
489 | 490 | ||
490 | misc = readw(ctrl->hpc_reg + MISC); | 491 | misc = readw(ctrl->hpc_reg + MISC); |
491 | misc = (misc | 0x0001) & 0xFFFB; | 492 | misc = (misc | 0x0001) & 0xFFFB; |
492 | writew(misc, ctrl->hpc_reg + MISC); | 493 | writew(misc, ctrl->hpc_reg + MISC); |
493 | } | 494 | } |
494 | 495 | ||
495 | 496 | ||
496 | static inline void amber_LED_on(struct controller *ctrl, u8 slot) | 497 | static inline void amber_LED_on(struct controller *ctrl, u8 slot) |
497 | { | 498 | { |
498 | u32 led_control; | 499 | u32 led_control; |
499 | 500 | ||
500 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); | 501 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); |
501 | led_control |= (0x01010000L << slot); | 502 | led_control |= (0x01010000L << slot); |
502 | writel(led_control, ctrl->hpc_reg + LED_CONTROL); | 503 | writel(led_control, ctrl->hpc_reg + LED_CONTROL); |
503 | } | 504 | } |
504 | 505 | ||
505 | 506 | ||
506 | static inline void amber_LED_off(struct controller *ctrl, u8 slot) | 507 | static inline void amber_LED_off(struct controller *ctrl, u8 slot) |
507 | { | 508 | { |
508 | u32 led_control; | 509 | u32 led_control; |
509 | 510 | ||
510 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); | 511 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); |
511 | led_control &= ~(0x01010000L << slot); | 512 | led_control &= ~(0x01010000L << slot); |
512 | writel(led_control, ctrl->hpc_reg + LED_CONTROL); | 513 | writel(led_control, ctrl->hpc_reg + LED_CONTROL); |
513 | } | 514 | } |
514 | 515 | ||
515 | 516 | ||
516 | static inline int read_amber_LED(struct controller *ctrl, u8 slot) | 517 | static inline int read_amber_LED(struct controller *ctrl, u8 slot) |
517 | { | 518 | { |
518 | u32 led_control; | 519 | u32 led_control; |
519 | 520 | ||
520 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); | 521 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); |
521 | led_control &= (0x01010000L << slot); | 522 | led_control &= (0x01010000L << slot); |
522 | 523 | ||
523 | return led_control ? 1 : 0; | 524 | return led_control ? 1 : 0; |
524 | } | 525 | } |
525 | 526 | ||
526 | 527 | ||
527 | static inline void green_LED_on(struct controller *ctrl, u8 slot) | 528 | static inline void green_LED_on(struct controller *ctrl, u8 slot) |
528 | { | 529 | { |
529 | u32 led_control; | 530 | u32 led_control; |
530 | 531 | ||
531 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); | 532 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); |
532 | led_control |= 0x0101L << slot; | 533 | led_control |= 0x0101L << slot; |
533 | writel(led_control, ctrl->hpc_reg + LED_CONTROL); | 534 | writel(led_control, ctrl->hpc_reg + LED_CONTROL); |
534 | } | 535 | } |
535 | 536 | ||
536 | static inline void green_LED_off(struct controller *ctrl, u8 slot) | 537 | static inline void green_LED_off(struct controller *ctrl, u8 slot) |
537 | { | 538 | { |
538 | u32 led_control; | 539 | u32 led_control; |
539 | 540 | ||
540 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); | 541 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); |
541 | led_control &= ~(0x0101L << slot); | 542 | led_control &= ~(0x0101L << slot); |
542 | writel(led_control, ctrl->hpc_reg + LED_CONTROL); | 543 | writel(led_control, ctrl->hpc_reg + LED_CONTROL); |
543 | } | 544 | } |
544 | 545 | ||
545 | 546 | ||
546 | static inline void green_LED_blink(struct controller *ctrl, u8 slot) | 547 | static inline void green_LED_blink(struct controller *ctrl, u8 slot) |
547 | { | 548 | { |
548 | u32 led_control; | 549 | u32 led_control; |
549 | 550 | ||
550 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); | 551 | led_control = readl(ctrl->hpc_reg + LED_CONTROL); |
551 | led_control &= ~(0x0101L << slot); | 552 | led_control &= ~(0x0101L << slot); |
552 | led_control |= (0x0001L << slot); | 553 | led_control |= (0x0001L << slot); |
553 | writel(led_control, ctrl->hpc_reg + LED_CONTROL); | 554 | writel(led_control, ctrl->hpc_reg + LED_CONTROL); |
554 | } | 555 | } |
555 | 556 | ||
556 | 557 | ||
557 | static inline void slot_disable(struct controller *ctrl, u8 slot) | 558 | static inline void slot_disable(struct controller *ctrl, u8 slot) |
558 | { | 559 | { |
559 | u8 slot_enable; | 560 | u8 slot_enable; |
560 | 561 | ||
561 | slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); | 562 | slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); |
562 | slot_enable &= ~(0x01 << slot); | 563 | slot_enable &= ~(0x01 << slot); |
563 | writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); | 564 | writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); |
564 | } | 565 | } |
565 | 566 | ||
566 | 567 | ||
567 | static inline void slot_enable(struct controller *ctrl, u8 slot) | 568 | static inline void slot_enable(struct controller *ctrl, u8 slot) |
568 | { | 569 | { |
569 | u8 slot_enable; | 570 | u8 slot_enable; |
570 | 571 | ||
571 | slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); | 572 | slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); |
572 | slot_enable |= (0x01 << slot); | 573 | slot_enable |= (0x01 << slot); |
573 | writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); | 574 | writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); |
574 | } | 575 | } |
575 | 576 | ||
576 | 577 | ||
577 | static inline u8 is_slot_enabled(struct controller *ctrl, u8 slot) | 578 | static inline u8 is_slot_enabled(struct controller *ctrl, u8 slot) |
578 | { | 579 | { |
579 | u8 slot_enable; | 580 | u8 slot_enable; |
580 | 581 | ||
581 | slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); | 582 | slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); |
582 | slot_enable &= (0x01 << slot); | 583 | slot_enable &= (0x01 << slot); |
583 | return slot_enable ? 1 : 0; | 584 | return slot_enable ? 1 : 0; |
584 | } | 585 | } |
585 | 586 | ||
586 | 587 | ||
587 | static inline u8 read_slot_enable(struct controller *ctrl) | 588 | static inline u8 read_slot_enable(struct controller *ctrl) |
588 | { | 589 | { |
589 | return readb(ctrl->hpc_reg + SLOT_ENABLE); | 590 | return readb(ctrl->hpc_reg + SLOT_ENABLE); |
590 | } | 591 | } |
591 | 592 | ||
592 | 593 | ||
593 | /** | 594 | /** |
594 | * get_controller_speed - find the current frequency/mode of controller. | 595 | * get_controller_speed - find the current frequency/mode of controller. |
595 | * | 596 | * |
596 | * @ctrl: controller to get frequency/mode for. | 597 | * @ctrl: controller to get frequency/mode for. |
597 | * | 598 | * |
598 | * Returns controller speed. | 599 | * Returns controller speed. |
599 | */ | 600 | */ |
600 | static inline u8 get_controller_speed(struct controller *ctrl) | 601 | static inline u8 get_controller_speed(struct controller *ctrl) |
601 | { | 602 | { |
602 | u8 curr_freq; | 603 | u8 curr_freq; |
603 | u16 misc; | 604 | u16 misc; |
604 | 605 | ||
605 | if (ctrl->pcix_support) { | 606 | if (ctrl->pcix_support) { |
606 | curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ); | 607 | curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ); |
607 | if ((curr_freq & 0xB0) == 0xB0) | 608 | if ((curr_freq & 0xB0) == 0xB0) |
608 | return PCI_SPEED_133MHz_PCIX; | 609 | return PCI_SPEED_133MHz_PCIX; |
609 | if ((curr_freq & 0xA0) == 0xA0) | 610 | if ((curr_freq & 0xA0) == 0xA0) |
610 | return PCI_SPEED_100MHz_PCIX; | 611 | return PCI_SPEED_100MHz_PCIX; |
611 | if ((curr_freq & 0x90) == 0x90) | 612 | if ((curr_freq & 0x90) == 0x90) |
612 | return PCI_SPEED_66MHz_PCIX; | 613 | return PCI_SPEED_66MHz_PCIX; |
613 | if (curr_freq & 0x10) | 614 | if (curr_freq & 0x10) |
614 | return PCI_SPEED_66MHz; | 615 | return PCI_SPEED_66MHz; |
615 | 616 | ||
616 | return PCI_SPEED_33MHz; | 617 | return PCI_SPEED_33MHz; |
617 | } | 618 | } |
618 | 619 | ||
619 | misc = readw(ctrl->hpc_reg + MISC); | 620 | misc = readw(ctrl->hpc_reg + MISC); |
620 | return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; | 621 | return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; |
621 | } | 622 | } |
622 | 623 | ||
623 | 624 | ||
624 | /** | 625 | /** |
625 | * get_adapter_speed - find the max supported frequency/mode of adapter. | 626 | * get_adapter_speed - find the max supported frequency/mode of adapter. |
626 | * | 627 | * |
627 | * @ctrl: hotplug controller. | 628 | * @ctrl: hotplug controller. |
628 | * @hp_slot: hotplug slot where adapter is installed. | 629 | * @hp_slot: hotplug slot where adapter is installed. |
629 | * | 630 | * |
630 | * Returns adapter speed. | 631 | * Returns adapter speed. |
631 | */ | 632 | */ |
632 | static inline u8 get_adapter_speed(struct controller *ctrl, u8 hp_slot) | 633 | static inline u8 get_adapter_speed(struct controller *ctrl, u8 hp_slot) |
633 | { | 634 | { |
634 | u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT); | 635 | u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT); |
635 | dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword); | 636 | dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword); |
636 | if (ctrl->pcix_support) { | 637 | if (ctrl->pcix_support) { |
637 | if (temp_dword & (0x10000 << hp_slot)) | 638 | if (temp_dword & (0x10000 << hp_slot)) |
638 | return PCI_SPEED_133MHz_PCIX; | 639 | return PCI_SPEED_133MHz_PCIX; |
639 | if (temp_dword & (0x100 << hp_slot)) | 640 | if (temp_dword & (0x100 << hp_slot)) |
640 | return PCI_SPEED_66MHz_PCIX; | 641 | return PCI_SPEED_66MHz_PCIX; |
641 | } | 642 | } |
642 | 643 | ||
643 | if (temp_dword & (0x01 << hp_slot)) | 644 | if (temp_dword & (0x01 << hp_slot)) |
644 | return PCI_SPEED_66MHz; | 645 | return PCI_SPEED_66MHz; |
645 | 646 | ||
646 | return PCI_SPEED_33MHz; | 647 | return PCI_SPEED_33MHz; |
647 | } | 648 | } |
648 | 649 | ||
649 | static inline void enable_slot_power(struct controller *ctrl, u8 slot) | 650 | static inline void enable_slot_power(struct controller *ctrl, u8 slot) |
650 | { | 651 | { |
651 | u8 slot_power; | 652 | u8 slot_power; |
652 | 653 | ||
653 | slot_power = readb(ctrl->hpc_reg + SLOT_POWER); | 654 | slot_power = readb(ctrl->hpc_reg + SLOT_POWER); |
654 | slot_power |= (0x01 << slot); | 655 | slot_power |= (0x01 << slot); |
655 | writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); | 656 | writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); |
656 | } | 657 | } |
657 | 658 | ||
658 | static inline void disable_slot_power(struct controller *ctrl, u8 slot) | 659 | static inline void disable_slot_power(struct controller *ctrl, u8 slot) |
659 | { | 660 | { |
660 | u8 slot_power; | 661 | u8 slot_power; |
661 | 662 | ||
662 | slot_power = readb(ctrl->hpc_reg + SLOT_POWER); | 663 | slot_power = readb(ctrl->hpc_reg + SLOT_POWER); |
663 | slot_power &= ~(0x01 << slot); | 664 | slot_power &= ~(0x01 << slot); |
664 | writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); | 665 | writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); |
665 | } | 666 | } |
666 | 667 | ||
667 | 668 | ||
668 | static inline int cpq_get_attention_status(struct controller *ctrl, struct slot *slot) | 669 | static inline int cpq_get_attention_status(struct controller *ctrl, struct slot *slot) |
669 | { | 670 | { |
670 | u8 hp_slot; | 671 | u8 hp_slot; |
671 | 672 | ||
672 | hp_slot = slot->device - ctrl->slot_device_offset; | 673 | hp_slot = slot->device - ctrl->slot_device_offset; |
673 | 674 | ||
674 | return read_amber_LED(ctrl, hp_slot); | 675 | return read_amber_LED(ctrl, hp_slot); |
675 | } | 676 | } |
676 | 677 | ||
677 | 678 | ||
678 | static inline int get_slot_enabled(struct controller *ctrl, struct slot *slot) | 679 | static inline int get_slot_enabled(struct controller *ctrl, struct slot *slot) |
679 | { | 680 | { |
680 | u8 hp_slot; | 681 | u8 hp_slot; |
681 | 682 | ||
682 | hp_slot = slot->device - ctrl->slot_device_offset; | 683 | hp_slot = slot->device - ctrl->slot_device_offset; |
683 | 684 | ||
684 | return is_slot_enabled(ctrl, hp_slot); | 685 | return is_slot_enabled(ctrl, hp_slot); |
685 | } | 686 | } |
686 | 687 | ||
687 | 688 | ||
688 | static inline int cpq_get_latch_status(struct controller *ctrl, | 689 | static inline int cpq_get_latch_status(struct controller *ctrl, |
689 | struct slot *slot) | 690 | struct slot *slot) |
690 | { | 691 | { |
691 | u32 status; | 692 | u32 status; |
692 | u8 hp_slot; | 693 | u8 hp_slot; |
693 | 694 | ||
694 | hp_slot = slot->device - ctrl->slot_device_offset; | 695 | hp_slot = slot->device - ctrl->slot_device_offset; |
695 | dbg("%s: slot->device = %d, ctrl->slot_device_offset = %d \n", | 696 | dbg("%s: slot->device = %d, ctrl->slot_device_offset = %d \n", |
696 | __func__, slot->device, ctrl->slot_device_offset); | 697 | __func__, slot->device, ctrl->slot_device_offset); |
697 | 698 | ||
698 | status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)); | 699 | status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)); |
699 | 700 | ||
700 | return(status == 0) ? 1 : 0; | 701 | return(status == 0) ? 1 : 0; |
701 | } | 702 | } |
702 | 703 | ||
703 | 704 | ||
704 | static inline int get_presence_status(struct controller *ctrl, | 705 | static inline int get_presence_status(struct controller *ctrl, |
705 | struct slot *slot) | 706 | struct slot *slot) |
706 | { | 707 | { |
707 | int presence_save = 0; | 708 | int presence_save = 0; |
708 | u8 hp_slot; | 709 | u8 hp_slot; |
709 | u32 tempdword; | 710 | u32 tempdword; |
710 | 711 | ||
711 | hp_slot = slot->device - ctrl->slot_device_offset; | 712 | hp_slot = slot->device - ctrl->slot_device_offset; |
712 | 713 | ||
713 | tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); | 714 | tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); |
714 | presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) | 715 | presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) |
715 | >> hp_slot) & 0x02; | 716 | >> hp_slot) & 0x02; |
716 | 717 | ||
717 | return presence_save; | 718 | return presence_save; |
718 | } | 719 | } |
719 | 720 | ||
720 | static inline int wait_for_ctrl_irq(struct controller *ctrl) | 721 | static inline int wait_for_ctrl_irq(struct controller *ctrl) |
721 | { | 722 | { |
722 | DECLARE_WAITQUEUE(wait, current); | 723 | DECLARE_WAITQUEUE(wait, current); |
723 | int retval = 0; | 724 | int retval = 0; |
724 | 725 | ||
725 | dbg("%s - start\n", __func__); | 726 | dbg("%s - start\n", __func__); |
726 | add_wait_queue(&ctrl->queue, &wait); | 727 | add_wait_queue(&ctrl->queue, &wait); |
727 | /* Sleep for up to 1 second to wait for the LED to change. */ | 728 | /* Sleep for up to 1 second to wait for the LED to change. */ |
728 | msleep_interruptible(1000); | 729 | msleep_interruptible(1000); |
729 | remove_wait_queue(&ctrl->queue, &wait); | 730 | remove_wait_queue(&ctrl->queue, &wait); |
730 | if (signal_pending(current)) | 731 | if (signal_pending(current)) |
731 | retval = -EINTR; | 732 | retval = -EINTR; |
732 | 733 | ||
733 | dbg("%s - end\n", __func__); | 734 | dbg("%s - end\n", __func__); |
734 | return retval; | 735 | return retval; |
735 | } | 736 | } |
736 | 737 | ||
737 | #include <asm/pci_x86.h> | 738 | #include <asm/pci_x86.h> |
738 | static inline int cpqhp_routing_table_length(void) | 739 | static inline int cpqhp_routing_table_length(void) |
739 | { | 740 | { |
740 | BUG_ON(cpqhp_routing_table == NULL); | 741 | BUG_ON(cpqhp_routing_table == NULL); |
741 | return ((cpqhp_routing_table->size - sizeof(struct irq_routing_table)) / | 742 | return ((cpqhp_routing_table->size - sizeof(struct irq_routing_table)) / |
742 | sizeof(struct irq_info)); | 743 | sizeof(struct irq_info)); |
743 | } | 744 | } |
744 | 745 | ||
745 | #endif | 746 | #endif |
746 | 747 |