94c0fa52 |
1 | /* |
2 | * arch/sh/boards/landisk/landisk_pwb.c -- driver for the Power control switch. |
3 | * |
4 | * This driver will also support the I-O DATA Device, Inc. LANDISK Board. |
5 | * |
6 | * This file is subject to the terms and conditions of the GNU General Public |
7 | * License. See the file "COPYING" in the main directory of this archive |
8 | * for more details. |
9 | * |
10 | * Copylight (C) 2002 Atom Create Engineering Co., Ltd. |
11 | * |
12 | * LED control drive function added by kogiidena |
13 | */ |
94c0fa52 |
14 | #include <linux/module.h> |
15 | #include <linux/errno.h> |
16 | #include <linux/signal.h> |
17 | #include <linux/major.h> |
18 | #include <linux/poll.h> |
19 | #include <linux/init.h> |
20 | #include <linux/delay.h> |
21 | #include <linux/sched.h> |
22 | #include <linux/timer.h> |
23 | #include <linux/interrupt.h> |
24 | |
25 | #include <asm/system.h> |
26 | #include <asm/io.h> |
27 | #include <asm/irq.h> |
28 | #include <asm/uaccess.h> |
29 | #include <asm/landisk/iodata_landisk.h> |
30 | |
31 | #define SHUTDOWN_BTN_MINOR 1 /* Shutdown button device minor no. */ |
32 | #define LED_MINOR 21 /* LED minor no. */ |
33 | #define BTN_MINOR 22 /* BUTTON minor no. */ |
34 | #define GIO_MINOR 40 /* GIO minor no. */ |
35 | |
36 | static int openCnt; |
37 | static int openCntLED; |
38 | static int openCntGio; |
39 | static int openCntBtn; |
40 | static int landisk_btn; |
41 | static int landisk_btnctrlpid; |
42 | /* |
43 | * Functions prototypes |
44 | */ |
45 | |
46 | static int gio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, |
47 | unsigned long arg); |
48 | |
49 | static int swdrv_open(struct inode *inode, struct file *filp) |
50 | { |
51 | int minor; |
52 | |
53 | minor = MINOR(inode->i_rdev); |
54 | filp->private_data = (void *)minor; |
55 | |
56 | if (minor == SHUTDOWN_BTN_MINOR) { |
57 | if (openCnt > 0) { |
58 | return -EALREADY; |
59 | } else { |
60 | openCnt++; |
61 | return 0; |
62 | } |
63 | } else if (minor == LED_MINOR) { |
64 | if (openCntLED > 0) { |
65 | return -EALREADY; |
66 | } else { |
67 | openCntLED++; |
68 | return 0; |
69 | } |
70 | } else if (minor == BTN_MINOR) { |
71 | if (openCntBtn > 0) { |
72 | return -EALREADY; |
73 | } else { |
74 | openCntBtn++; |
75 | return 0; |
76 | } |
77 | } else if (minor == GIO_MINOR) { |
78 | if (openCntGio > 0) { |
79 | return -EALREADY; |
80 | } else { |
81 | openCntGio++; |
82 | return 0; |
83 | } |
84 | } |
85 | return -ENOENT; |
86 | |
87 | } |
88 | |
89 | static int swdrv_close(struct inode *inode, struct file *filp) |
90 | { |
91 | int minor; |
92 | |
93 | minor = MINOR(inode->i_rdev); |
94 | if (minor == SHUTDOWN_BTN_MINOR) { |
95 | openCnt--; |
96 | } else if (minor == LED_MINOR) { |
97 | openCntLED--; |
98 | } else if (minor == BTN_MINOR) { |
99 | openCntBtn--; |
100 | } else if (minor == GIO_MINOR) { |
101 | openCntGio--; |
102 | } |
103 | return 0; |
104 | } |
105 | |
106 | static int swdrv_read(struct file *filp, char *buff, size_t count, |
107 | loff_t * ppos) |
108 | { |
109 | int minor; |
110 | minor = (int)(filp->private_data); |
111 | |
112 | if (!access_ok(VERIFY_WRITE, (void *)buff, count)) |
113 | return -EFAULT; |
114 | |
115 | if (minor == SHUTDOWN_BTN_MINOR) { |
116 | if (landisk_btn & 0x10) { |
117 | put_user(1, buff); |
118 | return 1; |
119 | } else { |
120 | return 0; |
121 | } |
122 | } |
123 | return 0; |
124 | } |
125 | |
126 | static int swdrv_write(struct file *filp, const char *buff, size_t count, |
127 | loff_t * ppos) |
128 | { |
129 | int minor; |
130 | minor = (int)(filp->private_data); |
131 | |
132 | if (minor == SHUTDOWN_BTN_MINOR) { |
133 | return count; |
134 | } |
135 | return count; |
136 | } |
137 | |
138 | static irqreturn_t sw_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
139 | { |
140 | landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS))); |
141 | disable_irq(IRQ_BUTTON); |
142 | disable_irq(IRQ_POWER); |
143 | ctrl_outb(0x00, PA_PWRINT_CLR); |
144 | |
145 | if (landisk_btnctrlpid != 0) { |
146 | kill_proc(landisk_btnctrlpid, SIGUSR1, 1); |
147 | landisk_btnctrlpid = 0; |
148 | } |
149 | |
150 | return IRQ_HANDLED; |
151 | } |
152 | |
153 | static struct file_operations swdrv_fops = { |
154 | .read = swdrv_read, /* read */ |
155 | .write = swdrv_write, /* write */ |
156 | .open = swdrv_open, /* open */ |
157 | .release = swdrv_close, /* release */ |
158 | .ioctl = gio_ioctl, /* ioctl */ |
159 | |
160 | }; |
161 | |
162 | static char banner[] __initdata = |
163 | KERN_INFO "LANDISK and USL-5P Button, LED and GIO driver initialized\n"; |
164 | |
165 | int __init swdrv_init(void) |
166 | { |
167 | int error; |
168 | |
169 | printk("%s", banner); |
170 | |
171 | openCnt = 0; |
172 | openCntLED = 0; |
173 | openCntBtn = 0; |
174 | openCntGio = 0; |
175 | landisk_btn = 0; |
176 | landisk_btnctrlpid = 0; |
177 | |
178 | if ((error = register_chrdev(SHUTDOWN_BTN_MAJOR, "swdrv", &swdrv_fops))) { |
179 | printk(KERN_ERR |
180 | "Button, LED and GIO driver:Couldn't register driver, error=%d\n", |
181 | error); |
182 | return 1; |
183 | } |
184 | |
185 | if (request_irq(IRQ_POWER, sw_interrupt, 0, "SHUTDOWNSWITCH", NULL)) { |
186 | printk(KERN_ERR "Unable to get IRQ 11.\n"); |
187 | return 1; |
188 | } |
189 | if (request_irq(IRQ_BUTTON, sw_interrupt, 0, "USL-5P BUTTON", NULL)) { |
190 | printk(KERN_ERR "Unable to get IRQ 12.\n"); |
191 | return 1; |
192 | } |
193 | ctrl_outb(0x00, PA_PWRINT_CLR); |
194 | |
195 | return 0; |
196 | } |
197 | |
198 | module_init(swdrv_init); |
199 | |
200 | /* |
201 | * gio driver |
202 | * |
203 | */ |
204 | |
205 | #include <asm/landisk/gio.h> |
206 | |
207 | static int gio_ioctl(struct inode *inode, struct file *filp, |
208 | unsigned int cmd, unsigned long arg) |
209 | { |
210 | int minor; |
211 | unsigned int data, mask; |
212 | static unsigned int addr = 0; |
213 | |
214 | minor = (int)(filp->private_data); |
215 | |
216 | /* access control */ |
217 | if (minor == GIO_MINOR) { |
218 | ; |
219 | } else if (minor == LED_MINOR) { |
220 | if (((cmd & 0x0ff) >= 9) && ((cmd & 0x0ff) < 20)) { |
221 | ; |
222 | } else { |
223 | return -EINVAL; |
224 | } |
225 | } else if (minor == BTN_MINOR) { |
226 | if (((cmd & 0x0ff) >= 20) && ((cmd & 0x0ff) < 30)) { |
227 | ; |
228 | } else { |
229 | return -EINVAL; |
230 | } |
231 | } else { |
232 | return -EINVAL; |
233 | } |
234 | |
235 | if (cmd & 0x01) { /* write */ |
236 | if (copy_from_user(&data, (int *)arg, sizeof(int))) { |
237 | return -EFAULT; |
238 | } |
239 | } |
240 | |
241 | switch (cmd) { |
242 | case GIODRV_IOCSGIOSETADDR: /* addres set */ |
243 | addr = data; |
244 | break; |
245 | |
246 | case GIODRV_IOCSGIODATA1: /* write byte */ |
247 | ctrl_outb((unsigned char)(0x0ff & data), addr); |
248 | break; |
249 | |
250 | case GIODRV_IOCSGIODATA2: /* write word */ |
251 | if (addr & 0x01) { |
252 | return -EFAULT; |
253 | } |
254 | ctrl_outw((unsigned short int)(0x0ffff & data), addr); |
255 | break; |
256 | |
257 | case GIODRV_IOCSGIODATA4: /* write long */ |
258 | if (addr & 0x03) { |
259 | return -EFAULT; |
260 | } |
261 | ctrl_outl(data, addr); |
262 | break; |
263 | |
264 | case GIODRV_IOCGGIODATA1: /* read byte */ |
265 | data = ctrl_inb(addr); |
266 | break; |
267 | |
268 | case GIODRV_IOCGGIODATA2: /* read word */ |
269 | if (addr & 0x01) { |
270 | return -EFAULT; |
271 | } |
272 | data = ctrl_inw(addr); |
273 | break; |
274 | |
275 | case GIODRV_IOCGGIODATA4: /* read long */ |
276 | if (addr & 0x03) { |
277 | return -EFAULT; |
278 | } |
279 | data = ctrl_inl(addr); |
280 | break; |
281 | case GIODRV_IOCSGIO_LED: /* write */ |
282 | mask = ((data & 0x00ffffff) << 8) |
283 | | ((data & 0x0000ffff) << 16) |
284 | | ((data & 0x000000ff) << 24); |
285 | landisk_ledparam = data & (~mask); |
286 | if (landisk_arch == 0) { /* arch == landisk */ |
287 | landisk_ledparam &= 0x03030303; |
288 | mask = (~(landisk_ledparam >> 22)) & 0x000c; |
289 | landisk_ledparam |= mask; |
290 | } else { /* arch == usl-5p */ |
291 | mask = (landisk_ledparam >> 24) & 0x0001; |
292 | landisk_ledparam |= mask; |
293 | landisk_ledparam &= 0x007f7f7f; |
294 | } |
295 | landisk_ledparam |= 0x80; |
296 | break; |
297 | case GIODRV_IOCGGIO_LED: /* read */ |
298 | data = landisk_ledparam; |
299 | if (landisk_arch == 0) { /* arch == landisk */ |
300 | data &= 0x03030303; |
301 | } else { /* arch == usl-5p */ |
302 | ; |
303 | } |
304 | data &= (~0x080); |
305 | break; |
306 | case GIODRV_IOCSGIO_BUZZER: /* write */ |
307 | landisk_buzzerparam = data; |
308 | landisk_ledparam |= 0x80; |
309 | break; |
310 | case GIODRV_IOCGGIO_LANDISK: /* read */ |
311 | data = landisk_arch & 0x01; |
312 | break; |
313 | case GIODRV_IOCGGIO_BTN: /* read */ |
314 | data = (0x0ff & ctrl_inb(PA_PWRINT_CLR)); |
315 | data <<= 8; |
316 | data |= (0x0ff & ctrl_inb(PA_IMASK)); |
317 | data <<= 8; |
318 | data |= (0x0ff & landisk_btn); |
319 | data <<= 8; |
320 | data |= (0x0ff & (~ctrl_inb(PA_STATUS))); |
321 | break; |
322 | case GIODRV_IOCSGIO_BTNPID: /* write */ |
323 | landisk_btnctrlpid = data; |
324 | landisk_btn = 0; |
325 | if (irq_desc[IRQ_BUTTON].depth) { |
326 | enable_irq(IRQ_BUTTON); |
327 | } |
328 | if (irq_desc[IRQ_POWER].depth) { |
329 | enable_irq(IRQ_POWER); |
330 | } |
331 | break; |
332 | case GIODRV_IOCGGIO_BTNPID: /* read */ |
333 | data = landisk_btnctrlpid; |
334 | break; |
335 | default: |
336 | return -EFAULT; |
337 | break; |
338 | } |
339 | |
340 | if ((cmd & 0x01) == 0) { /* read */ |
341 | if (copy_to_user((int *)arg, &data, sizeof(int))) { |
342 | return -EFAULT; |
343 | } |
344 | } |
345 | return 0; |
346 | } |