1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <linux/config.h>
35#include <linux/module.h>
36#include <linux/input.h>
37#include <linux/pci.h>
38#include <linux/sched.h>
39#include <linux/init.h>
40#include <linux/interrupt.h>
41#include <linux/miscdevice.h>
42#include <linux/poll.h>
43#include <linux/delay.h>
44#include <linux/wait.h>
45#include <linux/acpi.h>
46
47#include <asm/uaccess.h>
48#include <asm/io.h>
49#include <asm/system.h>
50
51#include "sonypi.h"
52#include <linux/sonypi.h>
53
54static struct sonypi_device sonypi_device;
55static int minor = -1;
56static int verbose;
57static int fnkeyinit;
58static int camera;
59static int compat;
60static int useinput = 1;
61static unsigned long mask = 0xffffffff;
62
63
64static inline void sonypi_initq(void) {
65 sonypi_device.queue.head = sonypi_device.queue.tail = 0;
66 sonypi_device.queue.len = 0;
67 sonypi_device.queue.s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
68 init_waitqueue_head(&sonypi_device.queue.proc_list);
69}
70
71
72static inline unsigned char sonypi_pullq(void) {
73 unsigned char result;
74 unsigned long flags;
75
76 spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
77 if (!sonypi_device.queue.len) {
78 spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
79 return 0;
80 }
81 result = sonypi_device.queue.buf[sonypi_device.queue.head];
82 sonypi_device.queue.head++;
83 sonypi_device.queue.head &= (SONYPI_BUF_SIZE - 1);
84 sonypi_device.queue.len--;
85 spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
86 return result;
87}
88
89
90static inline void sonypi_pushq(unsigned char event) {
91 unsigned long flags;
92
93 spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
94 if (sonypi_device.queue.len == SONYPI_BUF_SIZE) {
95
96 sonypi_device.queue.head++;
97 sonypi_device.queue.head &= (SONYPI_BUF_SIZE - 1);
98 sonypi_device.queue.len--;
99 }
100 sonypi_device.queue.buf[sonypi_device.queue.tail] = event;
101 sonypi_device.queue.tail++;
102 sonypi_device.queue.tail &= (SONYPI_BUF_SIZE - 1);
103 sonypi_device.queue.len++;
104
105 kill_fasync(&sonypi_device.queue.fasync, SIGIO, POLL_IN);
106 wake_up_interruptible(&sonypi_device.queue.proc_list);
107 spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
108}
109
110
111static inline int sonypi_emptyq(void) {
112 int result;
113 unsigned long flags;
114
115 spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
116 result = (sonypi_device.queue.len == 0);
117 spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
118 return result;
119}
120
121static int ec_read16(u8 addr, u16 *value) {
122 u8 val_lb, val_hb;
123 if (sonypi_ec_read(addr, &val_lb))
124 return -1;
125 if (sonypi_ec_read(addr + 1, &val_hb))
126 return -1;
127 *value = val_lb | (val_hb << 8);
128 return 0;
129}
130
131
132static void sonypi_type1_srs(void) {
133 u32 v;
134
135 pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
136 v = (v & 0xFFFF0000) | ((u32)sonypi_device.ioport1);
137 pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
138
139 pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
140 v = (v & 0xFFF0FFFF) |
141 (((u32)sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16);
142 pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
143
144 v = inl(SONYPI_IRQ_PORT);
145 v &= ~(((u32)0x3) << SONYPI_IRQ_SHIFT);
146 v |= (((u32)sonypi_device.bits) << SONYPI_IRQ_SHIFT);
147 outl(v, SONYPI_IRQ_PORT);
148
149 pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
150 v = (v & 0xFF1FFFFF) | 0x00C00000;
151 pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
152}
153
154static void sonypi_type2_srs(void) {
155 if (sonypi_ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8))
156 printk(KERN_WARNING "ec_write failed\n");
157 if (sonypi_ec_write(SONYPI_SLOB, sonypi_device.ioport1 & 0x00FF))
158 printk(KERN_WARNING "ec_write failed\n");
159 if (sonypi_ec_write(SONYPI_SIRQ, sonypi_device.bits))
160 printk(KERN_WARNING "ec_write failed\n");
161 udelay(10);
162}
163
164
165static void sonypi_type1_dis(void) {
166 u32 v;
167
168 pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
169 v = v & 0xFF3FFFFF;
170 pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
171
172 v = inl(SONYPI_IRQ_PORT);
173 v |= (0x3 << SONYPI_IRQ_SHIFT);
174 outl(v, SONYPI_IRQ_PORT);
175}
176
177static void sonypi_type2_dis(void) {
178 if (sonypi_ec_write(SONYPI_SHIB, 0))
179 printk(KERN_WARNING "ec_write failed\n");
180 if (sonypi_ec_write(SONYPI_SLOB, 0))
181 printk(KERN_WARNING "ec_write failed\n");
182 if (sonypi_ec_write(SONYPI_SIRQ, 0))
183 printk(KERN_WARNING "ec_write failed\n");
184}
185
186static u8 sonypi_call1(u8 dev) {
187 u8 v1, v2;
188
189 wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
190 outb(dev, sonypi_device.ioport2);
191 v1 = inb_p(sonypi_device.ioport2);
192 v2 = inb_p(sonypi_device.ioport1);
193 return v2;
194}
195
196static u8 sonypi_call2(u8 dev, u8 fn) {
197 u8 v1;
198
199 wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
200 outb(dev, sonypi_device.ioport2);
201 wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
202 outb(fn, sonypi_device.ioport1);
203 v1 = inb_p(sonypi_device.ioport1);
204 return v1;
205}
206
207static u8 sonypi_call3(u8 dev, u8 fn, u8 v) {
208 u8 v1;
209
210 wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
211 outb(dev, sonypi_device.ioport2);
212 wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
213 outb(fn, sonypi_device.ioport1);
214 wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
215 outb(v, sonypi_device.ioport1);
216 v1 = inb_p(sonypi_device.ioport1);
217 return v1;
218}
219
220static u8 sonypi_read(u8 fn) {
221 u8 v1, v2;
222 int n = 100;
223
224 while (n--) {
225 v1 = sonypi_call2(0x8f, fn);
226 v2 = sonypi_call2(0x8f, fn);
227 if (v1 == v2 && v1 != 0xff)
228 return v1;
229 }
230 return 0xff;
231}
232
233
234static void sonypi_set(u8 fn, u8 v) {
235
236 wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT);
237}
238
239
240static int sonypi_camera_ready(void) {
241 u8 v;
242
243 v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS);
244 return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
245}
246
247
248static void sonypi_camera_off(void) {
249
250 sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK);
251
252 if (!sonypi_device.camera_power)
253 return;
254
255 sonypi_call2(0x91, 0);
256 sonypi_device.camera_power = 0;
257}
258
259
260static void sonypi_camera_on(void) {
261 int i, j;
262
263 if (sonypi_device.camera_power)
264 return;
265
266 for (j = 5; j > 0; j--) {
267
268 while (sonypi_call2(0x91, 0x1)) {
269 set_current_state(TASK_UNINTERRUPTIBLE);
270 schedule_timeout(1);
271 }
272 sonypi_call1(0x93);
273
274 for (i = 400; i > 0; i--) {
275 if (sonypi_camera_ready())
276 break;
277 set_current_state(TASK_UNINTERRUPTIBLE);
278 schedule_timeout(1);
279 }
280 if (i)
281 break;
282 }
283
284 if (j == 0) {
285 printk(KERN_WARNING "sonypi: failed to power on camera\n");
286 return;
287 }
288
289 sonypi_set(0x10, 0x5a);
290 sonypi_device.camera_power = 1;
291}
292
293
294static void sonypi_setbluetoothpower(u8 state) {
295
296 state = !!state;
297 if (sonypi_device.bluetooth_power == state)
298 return;
299
300 sonypi_call2(0x96, state);
301 sonypi_call1(0x82);
302 sonypi_device.bluetooth_power = state;
303}
304
305
306static irqreturn_t sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
307 u8 v1, v2, event = 0;
308 int i, j;
309
310 v1 = inb_p(sonypi_device.ioport1);
311 v2 = inb_p(sonypi_device.ioport1 + sonypi_device.evtype_offset);
312
313 for (i = 0; sonypi_eventtypes[i].model; i++) {
314 if (sonypi_device.model != sonypi_eventtypes[i].model)
315 continue;
316 if ((v2 & sonypi_eventtypes[i].data) != sonypi_eventtypes[i].data)
317 continue;
318 if (! (mask & sonypi_eventtypes[i].mask))
319 continue;
320 for (j = 0; sonypi_eventtypes[i].events[j].event; j++) {
321 if (v1 == sonypi_eventtypes[i].events[j].data) {
322 event = sonypi_eventtypes[i].events[j].event;
323 goto found;
324 }
325 }
326 }
327
328 if (verbose)
329 printk(KERN_WARNING
330 "sonypi: unknown event port1=0x%02x,port2=0x%02x\n",v1,v2);
331
332
333
334 return IRQ_HANDLED;
335
336found:
337 if (verbose > 1)
338 printk(KERN_INFO
339 "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2);
340
341#ifdef SONYPI_USE_INPUT
342 if (useinput) {
343 struct input_dev *jog_dev = &sonypi_device.jog_dev;
344 if (event == SONYPI_EVENT_JOGDIAL_PRESSED)
345 input_report_key(jog_dev, BTN_MIDDLE, 1);
346 else if (event == SONYPI_EVENT_ANYBUTTON_RELEASED)
347 input_report_key(jog_dev, BTN_MIDDLE, 0);
348 else if ((event == SONYPI_EVENT_JOGDIAL_UP) ||
349 (event == SONYPI_EVENT_JOGDIAL_UP_PRESSED))
350 input_report_rel(jog_dev, REL_WHEEL, 1);
351 else if ((event == SONYPI_EVENT_JOGDIAL_DOWN) ||
352 (event == SONYPI_EVENT_JOGDIAL_DOWN_PRESSED))
353 input_report_rel(jog_dev, REL_WHEEL, -1);
354 }
355#endif
356 sonypi_pushq(event);
357 return IRQ_HANDLED;
358}
359
360
361u8 sonypi_camera_command(int command, u8 value) {
362 u8 ret = 0;
363
364 if (!camera)
365 return 0;
366
367 down(&sonypi_device.lock);
368
369 switch(command) {
370 case SONYPI_COMMAND_GETCAMERA:
371 ret = sonypi_camera_ready();
372 break;
373 case SONYPI_COMMAND_SETCAMERA:
374 if (value)
375 sonypi_camera_on();
376 else
377 sonypi_camera_off();
378 break;
379 case SONYPI_COMMAND_GETCAMERABRIGHTNESS:
380 ret = sonypi_read(SONYPI_CAMERA_BRIGHTNESS);
381 break;
382 case SONYPI_COMMAND_SETCAMERABRIGHTNESS:
383 sonypi_set(SONYPI_CAMERA_BRIGHTNESS, value);
384 break;
385 case SONYPI_COMMAND_GETCAMERACONTRAST:
386 ret = sonypi_read(SONYPI_CAMERA_CONTRAST);
387 break;
388 case SONYPI_COMMAND_SETCAMERACONTRAST:
389 sonypi_set(SONYPI_CAMERA_CONTRAST, value);
390 break;
391 case SONYPI_COMMAND_GETCAMERAHUE:
392 ret = sonypi_read(SONYPI_CAMERA_HUE);
393 break;
394 case SONYPI_COMMAND_SETCAMERAHUE:
395 sonypi_set(SONYPI_CAMERA_HUE, value);
396 break;
397 case SONYPI_COMMAND_GETCAMERACOLOR:
398 ret = sonypi_read(SONYPI_CAMERA_COLOR);
399 break;
400 case SONYPI_COMMAND_SETCAMERACOLOR:
401 sonypi_set(SONYPI_CAMERA_COLOR, value);
402 break;
403 case SONYPI_COMMAND_GETCAMERASHARPNESS:
404 ret = sonypi_read(SONYPI_CAMERA_SHARPNESS);
405 break;
406 case SONYPI_COMMAND_SETCAMERASHARPNESS:
407 sonypi_set(SONYPI_CAMERA_SHARPNESS, value);
408 break;
409 case SONYPI_COMMAND_GETCAMERAPICTURE:
410 ret = sonypi_read(SONYPI_CAMERA_PICTURE);
411 break;
412 case SONYPI_COMMAND_SETCAMERAPICTURE:
413 sonypi_set(SONYPI_CAMERA_PICTURE, value);
414 break;
415 case SONYPI_COMMAND_GETCAMERAAGC:
416 ret = sonypi_read(SONYPI_CAMERA_AGC);
417 break;
418 case SONYPI_COMMAND_SETCAMERAAGC:
419 sonypi_set(SONYPI_CAMERA_AGC, value);
420 break;
421 case SONYPI_COMMAND_GETCAMERADIRECTION:
422 ret = sonypi_read(SONYPI_CAMERA_STATUS);
423 ret &= SONYPI_DIRECTION_BACKWARDS;
424 break;
425 case SONYPI_COMMAND_GETCAMERAROMVERSION:
426 ret = sonypi_read(SONYPI_CAMERA_ROMVERSION);
427 break;
428 case SONYPI_COMMAND_GETCAMERAREVISION:
429 ret = sonypi_read(SONYPI_CAMERA_REVISION);
430 break;
431 }
432 up(&sonypi_device.lock);
433 return ret;
434}
435
436static int sonypi_misc_fasync(int fd, struct file *filp, int on) {
437 int retval;
438
439 retval = fasync_helper(fd, filp, on, &sonypi_device.queue.fasync);
440 if (retval < 0)
441 return retval;
442 return 0;
443}
444
445static int sonypi_misc_release(struct inode * inode, struct file * file) {
446 sonypi_misc_fasync(-1, file, 0);
447 down(&sonypi_device.lock);
448 sonypi_device.open_count--;
449 up(&sonypi_device.lock);
450 return 0;
451}
452
453static int sonypi_misc_open(struct inode * inode, struct file * file) {
454 down(&sonypi_device.lock);
455
456 if (!sonypi_device.open_count)
457 sonypi_initq();
458 sonypi_device.open_count++;
459 up(&sonypi_device.lock);
460 return 0;
461}
462
463static ssize_t sonypi_misc_read(struct file * file, char * buf,
464 size_t count, loff_t *pos) {
465 DECLARE_WAITQUEUE(wait, current);
466 ssize_t i = count;
467 unsigned char c;
468
469 if (sonypi_emptyq()) {
470 if (file->f_flags & O_NONBLOCK)
471 return -EAGAIN;
472 add_wait_queue(&sonypi_device.queue.proc_list, &wait);
473repeat:
474 set_current_state(TASK_INTERRUPTIBLE);
475 if (sonypi_emptyq() && !signal_pending(current)) {
476 schedule();
477 goto repeat;
478 }
479 current->state = TASK_RUNNING;
480 remove_wait_queue(&sonypi_device.queue.proc_list, &wait);
481 }
482 while (i > 0 && !sonypi_emptyq()) {
483 c = sonypi_pullq();
484 put_user(c, buf++);
485 i--;
486 }
487 if (count - i) {
488 file->f_dentry->d_inode->i_atime = CURRENT_TIME;
489 return count-i;
490 }
491 if (signal_pending(current))
492 return -ERESTARTSYS;
493 return 0;
494}
495
496static unsigned int sonypi_misc_poll(struct file *file, poll_table * wait) {
497 poll_wait(file, &sonypi_device.queue.proc_list, wait);
498 if (!sonypi_emptyq())
499 return POLLIN | POLLRDNORM;
500 return 0;
501}
502
503static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
504 unsigned int cmd, unsigned long arg) {
505 int ret = 0;
506 u8 val8;
507 u16 val16;
508
509 down(&sonypi_device.lock);
510 switch (cmd) {
511 case SONYPI_IOCGBRT:
512 if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) {
513 ret = -EIO;
514 break;
515 }
516 if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
517 ret = -EFAULT;
518 break;
519 case SONYPI_IOCSBRT:
520 if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
521 ret = -EFAULT;
522 break;
523 }
524 if (sonypi_ec_write(SONYPI_LCD_LIGHT, val8))
525 ret = -EIO;
526 break;
527 case SONYPI_IOCGBAT1CAP:
528 if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
529 ret = -EIO;
530 break;
531 }
532 if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
533 ret = -EFAULT;
534 break;
535 case SONYPI_IOCGBAT1REM:
536 if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
537 ret = -EIO;
538 break;
539 }
540 if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
541 ret = -EFAULT;
542 break;
543 case SONYPI_IOCGBAT2CAP:
544 if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
545 ret = -EIO;
546 break;
547 }
548 if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
549 ret = -EFAULT;
550 break;
551 case SONYPI_IOCGBAT2REM:
552 if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
553 ret = -EIO;
554 break;
555 }
556 if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
557 ret = -EFAULT;
558 break;
559 case SONYPI_IOCGBATFLAGS:
560 if (sonypi_ec_read(SONYPI_BAT_FLAGS, &val8)) {
561 ret = -EIO;
562 break;
563 }
564 val8 &= 0x07;
565 if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
566 ret = -EFAULT;
567 break;
568 case SONYPI_IOCGBLUE:
569 val8 = sonypi_device.bluetooth_power;
570 if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
571 ret = -EFAULT;
572 break;
573 case SONYPI_IOCSBLUE:
574 if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
575 ret = -EFAULT;
576 break;
577 }
578 sonypi_setbluetoothpower(val8);
579 break;
580 default:
581 ret = -EINVAL;
582 }
583 up(&sonypi_device.lock);
584 return ret;
585}
586
587static struct file_operations sonypi_misc_fops = {
588 .owner = THIS_MODULE,
589 .read = sonypi_misc_read,
590 .poll = sonypi_misc_poll,
591 .open = sonypi_misc_open,
592 .release = sonypi_misc_release,
593 .fasync = sonypi_misc_fasync,
594 .ioctl = sonypi_misc_ioctl,
595};
596
597struct miscdevice sonypi_misc_device = {
598 -1, "sonypi", &sonypi_misc_fops
599};
600
601#ifdef CONFIG_PM
602static int sonypi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) {
603 static int old_camera_power;
604
605 switch (rqst) {
606 case PM_SUSPEND:
607 sonypi_call2(0x81, 0);
608 if (camera) {
609 old_camera_power = sonypi_device.camera_power;
610 sonypi_camera_off();
611 }
612 if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
613 sonypi_type2_dis();
614 else
615 sonypi_type1_dis();
616
617 if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
618 outb(0xf1, 0xb2);
619 break;
620 case PM_RESUME:
621
622 if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
623 outb(0xf0, 0xb2);
624 if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
625 sonypi_type2_srs();
626 else
627 sonypi_type1_srs();
628 sonypi_call1(0x82);
629 sonypi_call2(0x81, 0xff);
630 if (compat)
631 sonypi_call1(0x92);
632 else
633 sonypi_call1(0x82);
634 if (camera && old_camera_power)
635 sonypi_camera_on();
636 break;
637 }
638 return 0;
639}
640#endif
641
642static int __devinit sonypi_probe(struct pci_dev *pcidev) {
643 int i, ret;
644 struct sonypi_ioport_list *ioport_list;
645 struct sonypi_irq_list *irq_list;
646
647 sonypi_device.dev = pcidev;
648 if (pcidev)
649 sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
650 else
651 sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
652 sonypi_initq();
653 init_MUTEX(&sonypi_device.lock);
654 sonypi_device.bluetooth_power = 0;
655
656 if (pcidev && pci_enable_device(pcidev)) {
657 printk(KERN_ERR "sonypi: pci_enable_device failed\n");
658 ret = -EIO;
659 goto out1;
660 }
661
662 sonypi_misc_device.minor = (minor == -1) ?
663 MISC_DYNAMIC_MINOR : minor;
664 if ((ret = misc_register(&sonypi_misc_device))) {
665 printk(KERN_ERR "sonypi: misc_register failed\n");
666 goto out1;
667 }
668
669 if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
670 ioport_list = sonypi_type2_ioport_list;
671 sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
672 sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET;
673 irq_list = sonypi_type2_irq_list;
674 }
675 else {
676 ioport_list = sonypi_type1_ioport_list;
677 sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
678 sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
679 irq_list = sonypi_type1_irq_list;
680 }
681
682 for (i = 0; ioport_list[i].port1; i++) {
683 if (request_region(ioport_list[i].port1,
684 sonypi_device.region_size,
685 "Sony Programable I/O Device")) {
686
687 sonypi_device.ioport1 = ioport_list[i].port1;
688 sonypi_device.ioport2 = ioport_list[i].port2;
689 break;
690 }
691 }
692 if (!sonypi_device.ioport1) {
693 printk(KERN_ERR "sonypi: request_region failed\n");
694 ret = -ENODEV;
695 goto out2;
696 }
697
698 for (i = 0; irq_list[i].irq; i++) {
699
700 sonypi_device.irq = irq_list[i].irq;
701 sonypi_device.bits = irq_list[i].bits;
702
703
704 if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
705 sonypi_type2_srs();
706 else
707 sonypi_type1_srs();
708
709 sonypi_call1(0x82);
710 sonypi_call2(0x81, 0xff);
711 if (compat)
712 sonypi_call1(0x92);
713 else
714 sonypi_call1(0x82);
715
716
717 if (!request_irq(sonypi_device.irq, sonypi_irq,
718 SA_SHIRQ, "sonypi", sonypi_irq))
719 break;
720
721
722 if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
723 sonypi_type2_dis();
724 else
725 sonypi_type1_dis();
726 }
727
728 if (!irq_list[i].irq) {
729 printk(KERN_ERR "sonypi: request_irq failed\n");
730 ret = -ENODEV;
731 goto out3;
732 }
733
734
735 if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
736 outb(0xf0, 0xb2);
737
738 printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver v%d.%d.\n",
739 SONYPI_DRIVER_MAJORVERSION,
740 SONYPI_DRIVER_MINORVERSION);
741 printk(KERN_INFO "sonypi: detected %s model, "
742 "verbose = %d, fnkeyinit = %s, camera = %s, "
743 "compat = %s, mask = 0x%08lx, useinput = %s\n",
744 (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
745 "type1" : "type2",
746 verbose,
747 fnkeyinit ? "on" : "off",
748 camera ? "on" : "off",
749 compat ? "on" : "off",
750 mask,
751 useinput ? "on" : "off");
752 printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
753 sonypi_device.irq,
754 sonypi_device.ioport1, sonypi_device.ioport2);
755 if (minor == -1)
756 printk(KERN_INFO "sonypi: device allocated minor is %d\n",
757 sonypi_misc_device.minor);
758
759#ifdef SONYPI_USE_INPUT
760 if (useinput) {
761
762 sonypi_device.jog_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
763 sonypi_device.jog_dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
764 sonypi_device.jog_dev.relbit[0] = BIT(REL_WHEEL);
765 sonypi_device.jog_dev.name = (char *) kmalloc(
766 sizeof(SONYPI_INPUTNAME), GFP_KERNEL);
767 sprintf(sonypi_device.jog_dev.name, SONYPI_INPUTNAME);
768 sonypi_device.jog_dev.idbus = BUS_ISA;
769 sonypi_device.jog_dev.idvendor = PCI_VENDOR_ID_SONY;
770
771 input_register_device(&sonypi_device.jog_dev);
772 printk(KERN_INFO "%s installed at input event device #%d.\n",
773 sonypi_device.jog_dev.name,
774 sonypi_device.jog_dev.number);
775 }
776#endif
777
778#ifdef CONFIG_PM
779 sonypi_device.pm = pm_register(PM_PCI_DEV, 0, sonypi_pm_callback);
780#endif
781
782 return 0;
783
784out3:
785 release_region(sonypi_device.ioport1, sonypi_device.region_size);
786out2:
787 misc_deregister(&sonypi_misc_device);
788out1:
789 return ret;
790}
791
792static void __devexit sonypi_remove(void) {
793
794#ifdef CONFIG_PM
795 pm_unregister(sonypi_device.pm);
796#endif
797
798 sonypi_call2(0x81, 0);
799
800#ifdef SONYPI_USE_INPUT
801 if (useinput) {
802 input_unregister_device(&sonypi_device.jog_dev);
803 kfree(sonypi_device.jog_dev.name);
804 }
805#endif
806
807 if (camera)
808 sonypi_camera_off();
809 if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
810 sonypi_type2_dis();
811 else
812 sonypi_type1_dis();
813
814 if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
815 outb(0xf1, 0xb2);
816 free_irq(sonypi_device.irq, sonypi_irq);
817 release_region(sonypi_device.ioport1, sonypi_device.region_size);
818 misc_deregister(&sonypi_misc_device);
819 printk(KERN_INFO "sonypi: removed.\n");
820}
821
822static int __init sonypi_init_module(void) {
823 struct pci_dev *pcidev = NULL;
824
825 if (is_sony_vaio_laptop) {
826 pcidev = pci_find_device(PCI_VENDOR_ID_INTEL,
827 PCI_DEVICE_ID_INTEL_82371AB_3,
828 NULL);
829 return sonypi_probe(pcidev);
830 }
831 else
832 return -ENODEV;
833}
834
835static void __exit sonypi_cleanup_module(void) {
836 sonypi_remove();
837}
838
839#ifndef MODULE
840static int __init sonypi_setup(char *str) {
841 int ints[8];
842
843 str = get_options(str, ARRAY_SIZE(ints), ints);
844 if (ints[0] <= 0)
845 goto out;
846 minor = ints[1];
847 if (ints[0] == 1)
848 goto out;
849 verbose = ints[2];
850 if (ints[0] == 2)
851 goto out;
852 fnkeyinit = ints[3];
853 if (ints[0] == 3)
854 goto out;
855 camera = ints[4];
856 if (ints[0] == 4)
857 goto out;
858 compat = ints[5];
859 if (ints[0] == 5)
860 goto out;
861 mask = ints[6];
862 if (ints[0] == 6)
863 goto out;
864 useinput = ints[7];
865out:
866 return 1;
867}
868
869__setup("sonypi=", sonypi_setup);
870#endif
871
872
873module_init(sonypi_init_module);
874module_exit(sonypi_cleanup_module);
875
876MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
877MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
878MODULE_LICENSE("GPL");
879
880
881MODULE_PARM(minor,"i");
882MODULE_PARM_DESC(minor, "minor number of the misc device, default is -1 (automatic)");
883MODULE_PARM(verbose,"i");
884MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
885MODULE_PARM(fnkeyinit,"i");
886MODULE_PARM_DESC(fnkeyinit, "set this if your Fn keys do not generate any event");
887MODULE_PARM(camera,"i");
888MODULE_PARM_DESC(camera, "set this if you have a MotionEye camera (PictureBook series)");
889MODULE_PARM(compat,"i");
890MODULE_PARM_DESC(compat, "set this if you want to enable backward compatibility mode");
891MODULE_PARM(mask, "i");
892MODULE_PARM_DESC(mask, "set this to the mask of event you want to enable (see doc)");
893MODULE_PARM(useinput, "i");
894MODULE_PARM_DESC(useinput, "if you have a jogdial, set this if you would like it to use the modern Linux Input Driver system");
895
896EXPORT_SYMBOL(sonypi_camera_command);
897