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
35
36
37
38
39
40
41
42
43
44
45#include <linux/kernel.h>
46#include <linux/module.h>
47#include <linux/moduleparam.h>
48#include <linux/init.h>
49#include <linux/smp_lock.h>
50#include <linux/types.h>
51#include <linux/backlight.h>
52#include <linux/platform_device.h>
53#include <linux/err.h>
54#include <linux/dmi.h>
55#include <linux/pci.h>
56#include <linux/interrupt.h>
57#include <linux/delay.h>
58#include <linux/input.h>
59#include <linux/kfifo.h>
60#include <linux/workqueue.h>
61#include <linux/acpi.h>
62#include <acpi/acpi_drivers.h>
63#include <acpi/acpi_bus.h>
64#include <asm/uaccess.h>
65#include <linux/sonypi.h>
66#include <linux/sony-laptop.h>
67#ifdef CONFIG_SONYPI_COMPAT
68#include <linux/poll.h>
69#include <linux/miscdevice.h>
70#endif
71
72#define DRV_PFX "sony-laptop: "
73#define dprintk(msg...) do { \
74 if (debug) printk(KERN_WARNING DRV_PFX msg); \
75} while (0)
76
77#define SONY_LAPTOP_DRIVER_VERSION "0.6"
78
79#define SONY_NC_CLASS "sony-nc"
80#define SONY_NC_HID "SNY5001"
81#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver"
82
83#define SONY_PIC_CLASS "sony-pic"
84#define SONY_PIC_HID "SNY6001"
85#define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver"
86
87MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
88MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
89MODULE_LICENSE("GPL");
90MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION);
91
92static int debug;
93module_param(debug, int, 0);
94MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
95 "the development of this driver");
96
97static int no_spic;
98module_param(no_spic, int, 0444);
99MODULE_PARM_DESC(no_spic,
100 "set this if you don't want to enable the SPIC device");
101
102static int compat;
103module_param(compat, int, 0444);
104MODULE_PARM_DESC(compat,
105 "set this if you want to enable backward compatibility mode");
106
107static unsigned long mask = 0xffffffff;
108module_param(mask, ulong, 0644);
109MODULE_PARM_DESC(mask,
110 "set this to the mask of event you want to enable (see doc)");
111
112static int camera;
113module_param(camera, int, 0444);
114MODULE_PARM_DESC(camera,
115 "set this to 1 to enable Motion Eye camera controls "
116 "(only use it if you have a C1VE or C1VN model)");
117
118#ifdef CONFIG_SONYPI_COMPAT
119static int minor = -1;
120module_param(minor, int, 0);
121MODULE_PARM_DESC(minor,
122 "minor number of the misc device for the SPIC compatibility code, "
123 "default is -1 (automatic)");
124#endif
125
126
127
128#define SONY_LAPTOP_BUF_SIZE 128
129struct sony_laptop_input_s {
130 atomic_t users;
131 struct input_dev *jog_dev;
132 struct input_dev *key_dev;
133 struct kfifo *fifo;
134 spinlock_t fifo_lock;
135 struct workqueue_struct *wq;
136};
137static struct sony_laptop_input_s sony_laptop_input = {
138 .users = ATOMIC_INIT(0),
139};
140
141struct sony_laptop_keypress {
142 struct input_dev *dev;
143 int key;
144};
145
146
147
148
149static int sony_laptop_input_index[] = {
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 0,
158 1,
159 2,
160 3,
161 4,
162 5,
163 6,
164 7,
165 8,
166 9,
167 10,
168 11,
169 12,
170 13,
171 14,
172 15,
173 16,
174 17,
175 18,
176 19,
177 20,
178 21,
179 22,
180 23,
181 24,
182 25,
183 26,
184 27,
185 28,
186 -1,
187 -1,
188 29,
189 30,
190 31,
191 32,
192 33,
193 34,
194 35,
195 36,
196 37,
197 38,
198 39,
199 40,
200 41,
201 42,
202 43,
203 44,
204 45,
205 46,
206 -1,
207 -1,
208 -1,
209 -1,
210 47,
211 48,
212 49,
213 50,
214};
215
216static int sony_laptop_input_keycode_map[] = {
217 KEY_CAMERA,
218 KEY_RESERVED,
219 KEY_RESERVED,
220 KEY_RESERVED,
221 KEY_FN_ESC,
222 KEY_FN_F1,
223 KEY_FN_F2,
224 KEY_FN_F3,
225 KEY_FN_F4,
226 KEY_FN_F5,
227 KEY_FN_F6,
228 KEY_FN_F7,
229 KEY_FN_F8,
230 KEY_FN_F9,
231 KEY_FN_F10,
232 KEY_FN_F11,
233 KEY_FN_F12,
234 KEY_FN_F1,
235 KEY_FN_F2,
236 KEY_FN_D,
237 KEY_FN_E,
238 KEY_FN_F,
239 KEY_FN_S,
240 KEY_FN_B,
241 KEY_BLUETOOTH,
242 KEY_PROG1,
243 KEY_PROG2,
244 KEY_PROG3,
245 KEY_BACK,
246 KEY_BLUETOOTH,
247 KEY_BLUETOOTH,
248 KEY_HELP,
249 KEY_FN,
250 KEY_RESERVED,
251 KEY_RESERVED,
252 KEY_RESERVED,
253 KEY_RESERVED,
254 KEY_RESERVED,
255 KEY_RESERVED,
256 KEY_RESERVED,
257 KEY_RESERVED,
258 KEY_ZOOM,
259 BTN_THUMB,
260 KEY_RESERVED,
261 KEY_RESERVED,
262 KEY_RESERVED,
263 KEY_RESERVED,
264 KEY_WLAN,
265 KEY_WLAN,
266 KEY_ZOOMIN,
267 KEY_ZOOMOUT
268};
269
270
271static void do_sony_laptop_release_key(struct work_struct *work)
272{
273 struct sony_laptop_keypress kp;
274
275 while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
276 sizeof(kp)) == sizeof(kp)) {
277 msleep(10);
278 input_report_key(kp.dev, kp.key, 0);
279 input_sync(kp.dev);
280 }
281}
282static DECLARE_WORK(sony_laptop_release_key_work,
283 do_sony_laptop_release_key);
284
285
286static void sony_laptop_report_input_event(u8 event)
287{
288 struct input_dev *jog_dev = sony_laptop_input.jog_dev;
289 struct input_dev *key_dev = sony_laptop_input.key_dev;
290 struct sony_laptop_keypress kp = { NULL };
291
292 if (event == SONYPI_EVENT_FNKEY_RELEASED) {
293
294 return;
295 }
296
297
298 switch (event) {
299
300 case SONYPI_EVENT_JOGDIAL_UP:
301 case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
302 input_report_rel(jog_dev, REL_WHEEL, 1);
303 input_sync(jog_dev);
304 return;
305
306 case SONYPI_EVENT_JOGDIAL_DOWN:
307 case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
308 input_report_rel(jog_dev, REL_WHEEL, -1);
309 input_sync(jog_dev);
310 return;
311
312
313 case SONYPI_EVENT_JOGDIAL_PRESSED:
314 kp.key = BTN_MIDDLE;
315 kp.dev = jog_dev;
316 break;
317
318 default:
319 if (event >= ARRAY_SIZE(sony_laptop_input_index)) {
320 dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
321 break;
322 }
323 if (sony_laptop_input_index[event] != -1) {
324 kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
325 if (kp.key != KEY_UNKNOWN)
326 kp.dev = key_dev;
327 }
328 break;
329 }
330
331 if (kp.dev) {
332 input_report_key(kp.dev, kp.key, 1);
333
334 input_event(kp.dev, EV_MSC, MSC_SCAN, event);
335 input_sync(kp.dev);
336 kfifo_put(sony_laptop_input.fifo,
337 (unsigned char *)&kp, sizeof(kp));
338
339 if (!work_pending(&sony_laptop_release_key_work))
340 queue_work(sony_laptop_input.wq,
341 &sony_laptop_release_key_work);
342 } else
343 dprintk("unknown input event %.2x\n", event);
344}
345
346static int sony_laptop_setup_input(struct acpi_device *acpi_device)
347{
348 struct input_dev *jog_dev;
349 struct input_dev *key_dev;
350 int i;
351 int error;
352
353
354 if (atomic_add_return(1, &sony_laptop_input.users) > 1)
355 return 0;
356
357
358 spin_lock_init(&sony_laptop_input.fifo_lock);
359 sony_laptop_input.fifo =
360 kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
361 &sony_laptop_input.fifo_lock);
362 if (IS_ERR(sony_laptop_input.fifo)) {
363 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
364 error = PTR_ERR(sony_laptop_input.fifo);
365 goto err_dec_users;
366 }
367
368
369 sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");
370 if (!sony_laptop_input.wq) {
371 printk(KERN_ERR DRV_PFX
372 "Unabe to create workqueue.\n");
373 error = -ENXIO;
374 goto err_free_kfifo;
375 }
376
377
378 key_dev = input_allocate_device();
379 if (!key_dev) {
380 error = -ENOMEM;
381 goto err_destroy_wq;
382 }
383
384 key_dev->name = "Sony Vaio Keys";
385 key_dev->id.bustype = BUS_ISA;
386 key_dev->id.vendor = PCI_VENDOR_ID_SONY;
387 key_dev->dev.parent = &acpi_device->dev;
388
389
390 set_bit(EV_KEY, key_dev->evbit);
391 set_bit(EV_MSC, key_dev->evbit);
392 set_bit(MSC_SCAN, key_dev->mscbit);
393 key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
394 key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
395 key_dev->keycode = &sony_laptop_input_keycode_map;
396 for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) {
397 if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) {
398 set_bit(sony_laptop_input_keycode_map[i],
399 key_dev->keybit);
400 }
401 }
402
403 error = input_register_device(key_dev);
404 if (error)
405 goto err_free_keydev;
406
407 sony_laptop_input.key_dev = key_dev;
408
409
410 jog_dev = input_allocate_device();
411 if (!jog_dev) {
412 error = -ENOMEM;
413 goto err_unregister_keydev;
414 }
415
416 jog_dev->name = "Sony Vaio Jogdial";
417 jog_dev->id.bustype = BUS_ISA;
418 jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
419 key_dev->dev.parent = &acpi_device->dev;
420
421 jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
422 jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
423 jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
424
425 error = input_register_device(jog_dev);
426 if (error)
427 goto err_free_jogdev;
428
429 sony_laptop_input.jog_dev = jog_dev;
430
431 return 0;
432
433err_free_jogdev:
434 input_free_device(jog_dev);
435
436err_unregister_keydev:
437 input_unregister_device(key_dev);
438
439 key_dev = NULL;
440
441err_free_keydev:
442 input_free_device(key_dev);
443
444err_destroy_wq:
445 destroy_workqueue(sony_laptop_input.wq);
446
447err_free_kfifo:
448 kfifo_free(sony_laptop_input.fifo);
449
450err_dec_users:
451 atomic_dec(&sony_laptop_input.users);
452 return error;
453}
454
455static void sony_laptop_remove_input(void)
456{
457
458 if (!atomic_dec_and_test(&sony_laptop_input.users))
459 return;
460
461
462 flush_workqueue(sony_laptop_input.wq);
463
464
465 input_unregister_device(sony_laptop_input.key_dev);
466 sony_laptop_input.key_dev = NULL;
467
468 if (sony_laptop_input.jog_dev) {
469 input_unregister_device(sony_laptop_input.jog_dev);
470 sony_laptop_input.jog_dev = NULL;
471 }
472
473 destroy_workqueue(sony_laptop_input.wq);
474 kfifo_free(sony_laptop_input.fifo);
475}
476
477
478
479static atomic_t sony_pf_users = ATOMIC_INIT(0);
480static struct platform_driver sony_pf_driver = {
481 .driver = {
482 .name = "sony-laptop",
483 .owner = THIS_MODULE,
484 }
485};
486static struct platform_device *sony_pf_device;
487
488static int sony_pf_add(void)
489{
490 int ret = 0;
491
492
493 if (atomic_add_return(1, &sony_pf_users) > 1)
494 return 0;
495
496 ret = platform_driver_register(&sony_pf_driver);
497 if (ret)
498 goto out;
499
500 sony_pf_device = platform_device_alloc("sony-laptop", -1);
501 if (!sony_pf_device) {
502 ret = -ENOMEM;
503 goto out_platform_registered;
504 }
505
506 ret = platform_device_add(sony_pf_device);
507 if (ret)
508 goto out_platform_alloced;
509
510 return 0;
511
512 out_platform_alloced:
513 platform_device_put(sony_pf_device);
514 sony_pf_device = NULL;
515 out_platform_registered:
516 platform_driver_unregister(&sony_pf_driver);
517 out:
518 atomic_dec(&sony_pf_users);
519 return ret;
520}
521
522static void sony_pf_remove(void)
523{
524
525 if (!atomic_dec_and_test(&sony_pf_users))
526 return;
527
528 platform_device_del(sony_pf_device);
529 platform_device_put(sony_pf_device);
530 platform_driver_unregister(&sony_pf_driver);
531}
532
533
534
535
536
537#define SONY_MAX_BRIGHTNESS 8
538
539#define SNC_VALIDATE_IN 0
540#define SNC_VALIDATE_OUT 1
541
542static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
543 char *);
544static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
545 const char *, size_t);
546static int boolean_validate(const int, const int);
547static int brightness_default_validate(const int, const int);
548
549struct sony_nc_value {
550 char *name;
551 char **acpiget;
552 char **acpiset;
553 int (*validate)(const int, const int);
554 int value;
555 int valid;
556 int debug;
557 struct device_attribute devattr;
558};
559
560#define SNC_HANDLE_NAMES(_name, _values...) \
561 static char *snc_##_name[] = { _values, NULL }
562
563#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
564 { \
565 .name = __stringify(_name), \
566 .acpiget = _getters, \
567 .acpiset = _setters, \
568 .validate = _validate, \
569 .debug = _debug, \
570 .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
571 }
572
573#define SNC_HANDLE_NULL { .name = NULL }
574
575SNC_HANDLE_NAMES(fnkey_get, "GHKE");
576
577SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
578SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
579
580SNC_HANDLE_NAMES(cdpower_get, "GCDP");
581SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
582
583SNC_HANDLE_NAMES(audiopower_get, "GAZP");
584SNC_HANDLE_NAMES(audiopower_set, "AZPW");
585
586SNC_HANDLE_NAMES(lanpower_get, "GLNP");
587SNC_HANDLE_NAMES(lanpower_set, "LNPW");
588
589SNC_HANDLE_NAMES(lidstate_get, "GLID");
590
591SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
592SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
593
594SNC_HANDLE_NAMES(gainbass_get, "GMGB");
595SNC_HANDLE_NAMES(gainbass_set, "CMGB");
596
597SNC_HANDLE_NAMES(PID_get, "GPID");
598
599SNC_HANDLE_NAMES(CTR_get, "GCTR");
600SNC_HANDLE_NAMES(CTR_set, "SCTR");
601
602SNC_HANDLE_NAMES(PCR_get, "GPCR");
603SNC_HANDLE_NAMES(PCR_set, "SPCR");
604
605SNC_HANDLE_NAMES(CMI_get, "GCMI");
606SNC_HANDLE_NAMES(CMI_set, "SCMI");
607
608static struct sony_nc_value sony_nc_values[] = {
609 SNC_HANDLE(brightness_default, snc_brightness_def_get,
610 snc_brightness_def_set, brightness_default_validate, 0),
611 SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
612 SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
613 SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
614 boolean_validate, 0),
615 SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
616 boolean_validate, 1),
617 SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
618 boolean_validate, 0),
619 SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
620 boolean_validate, 0),
621 SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
622 boolean_validate, 0),
623
624 SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
625 SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
626 SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
627 SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
628 SNC_HANDLE_NULL
629};
630
631static acpi_handle sony_nc_acpi_handle;
632static struct acpi_device *sony_nc_acpi_device = NULL;
633
634
635
636
637static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
638{
639 struct acpi_buffer output;
640 union acpi_object out_obj;
641 acpi_status status;
642
643 output.length = sizeof(out_obj);
644 output.pointer = &out_obj;
645
646 status = acpi_evaluate_object(handle, name, NULL, &output);
647 if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) {
648 *result = out_obj.integer.value;
649 return 0;
650 }
651
652 printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n");
653
654 return -1;
655}
656
657static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
658 int *result)
659{
660 struct acpi_object_list params;
661 union acpi_object in_obj;
662 struct acpi_buffer output;
663 union acpi_object out_obj;
664 acpi_status status;
665
666 params.count = 1;
667 params.pointer = &in_obj;
668 in_obj.type = ACPI_TYPE_INTEGER;
669 in_obj.integer.value = value;
670
671 output.length = sizeof(out_obj);
672 output.pointer = &out_obj;
673
674 status = acpi_evaluate_object(handle, name, ¶ms, &output);
675 if (status == AE_OK) {
676 if (result != NULL) {
677 if (out_obj.type != ACPI_TYPE_INTEGER) {
678 printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad "
679 "return type\n");
680 return -1;
681 }
682 *result = out_obj.integer.value;
683 }
684 return 0;
685 }
686
687 printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n");
688
689 return -1;
690}
691
692
693
694
695
696
697
698
699
700
701static int brightness_default_validate(const int direction, const int value)
702{
703 switch (direction) {
704 case SNC_VALIDATE_OUT:
705 return value - 1;
706 case SNC_VALIDATE_IN:
707 if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
708 return value + 1;
709 }
710 return -EINVAL;
711}
712
713
714
715
716
717
718static int boolean_validate(const int direction, const int value)
719{
720 if (direction == SNC_VALIDATE_IN) {
721 if (value != 0 && value != 1)
722 return -EINVAL;
723 }
724 return value;
725}
726
727
728
729
730static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
731 char *buffer)
732{
733 int value;
734 struct sony_nc_value *item =
735 container_of(attr, struct sony_nc_value, devattr);
736
737 if (!*item->acpiget)
738 return -EIO;
739
740 if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0)
741 return -EIO;
742
743 if (item->validate)
744 value = item->validate(SNC_VALIDATE_OUT, value);
745
746 return snprintf(buffer, PAGE_SIZE, "%d\n", value);
747}
748
749static ssize_t sony_nc_sysfs_store(struct device *dev,
750 struct device_attribute *attr,
751 const char *buffer, size_t count)
752{
753 int value;
754 struct sony_nc_value *item =
755 container_of(attr, struct sony_nc_value, devattr);
756
757 if (!item->acpiset)
758 return -EIO;
759
760 if (count > 31)
761 return -EINVAL;
762
763 value = simple_strtoul(buffer, NULL, 10);
764
765 if (item->validate)
766 value = item->validate(SNC_VALIDATE_IN, value);
767
768 if (value < 0)
769 return value;
770
771 if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0)
772 return -EIO;
773 item->value = value;
774 item->valid = 1;
775 return count;
776}
777
778
779
780
781
782static int sony_backlight_update_status(struct backlight_device *bd)
783{
784 return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
785 bd->props.brightness + 1, NULL);
786}
787
788static int sony_backlight_get_brightness(struct backlight_device *bd)
789{
790 int value;
791
792 if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
793 return 0;
794
795 return value - 1;
796}
797
798static struct backlight_device *sony_backlight_device;
799static struct backlight_ops sony_backlight_ops = {
800 .update_status = sony_backlight_update_status,
801 .get_brightness = sony_backlight_get_brightness,
802};
803
804
805
806
807struct sony_nc_event {
808 u8 data;
809 u8 event;
810};
811
812static struct sony_nc_event *sony_nc_events;
813
814
815
816
817static int sony_nc_C_enable(const struct dmi_system_id *id)
818{
819 int result = 0;
820
821 printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident);
822
823 sony_nc_events = id->driver_data;
824
825 if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0
826 || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0
827 || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0
828 || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0
829 || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0
830 || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) {
831 printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some "
832 "functionalities may be missing\n");
833 return 1;
834 }
835 return 0;
836}
837
838static struct sony_nc_event sony_C_events[] = {
839 { 0x81, SONYPI_EVENT_FNKEY_F1 },
840 { 0x01, SONYPI_EVENT_FNKEY_RELEASED },
841 { 0x85, SONYPI_EVENT_FNKEY_F5 },
842 { 0x05, SONYPI_EVENT_FNKEY_RELEASED },
843 { 0x86, SONYPI_EVENT_FNKEY_F6 },
844 { 0x06, SONYPI_EVENT_FNKEY_RELEASED },
845 { 0x87, SONYPI_EVENT_FNKEY_F7 },
846 { 0x07, SONYPI_EVENT_FNKEY_RELEASED },
847 { 0x8A, SONYPI_EVENT_FNKEY_F10 },
848 { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
849 { 0x8C, SONYPI_EVENT_FNKEY_F12 },
850 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
851 { 0, 0 },
852};
853
854
855static const struct dmi_system_id sony_nc_ids[] = {
856 {
857 .ident = "Sony Vaio FE Series",
858 .callback = sony_nc_C_enable,
859 .driver_data = sony_C_events,
860 .matches = {
861 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
862 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"),
863 },
864 },
865 {
866 .ident = "Sony Vaio FZ Series",
867 .callback = sony_nc_C_enable,
868 .driver_data = sony_C_events,
869 .matches = {
870 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
871 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ"),
872 },
873 },
874 {
875 .ident = "Sony Vaio C Series",
876 .callback = sony_nc_C_enable,
877 .driver_data = sony_C_events,
878 .matches = {
879 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
880 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
881 },
882 },
883 {
884 .ident = "Sony Vaio N Series",
885 .callback = sony_nc_C_enable,
886 .driver_data = sony_C_events,
887 .matches = {
888 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
889 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-N"),
890 },
891 },
892 { }
893};
894
895
896
897
898static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
899{
900 struct sony_nc_event *evmap;
901 u32 ev = event;
902 int result;
903
904 if (ev == 0x92) {
905
906
907
908
909
910
911
912
913
914
915
916 if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0)
917 dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev);
918 else
919 ev = result & 0xFF;
920 }
921
922 if (sony_nc_events)
923 for (evmap = sony_nc_events; evmap->event; evmap++) {
924 if (evmap->data == ev) {
925 ev = evmap->event;
926 break;
927 }
928 }
929
930 dprintk("sony_acpi_notify, event: 0x%.2x\n", ev);
931 sony_laptop_report_input_event(ev);
932 acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev);
933}
934
935static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
936 void *context, void **return_value)
937{
938 struct acpi_namespace_node *node;
939 union acpi_operand_object *operand;
940
941 node = (struct acpi_namespace_node *)handle;
942 operand = (union acpi_operand_object *)node->object;
943
944 printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
945 (u32) operand->method.param_count);
946
947 return AE_OK;
948}
949
950
951
952
953static int sony_nc_resume(struct acpi_device *device)
954{
955 struct sony_nc_value *item;
956
957 for (item = sony_nc_values; item->name; item++) {
958 int ret;
959
960 if (!item->valid)
961 continue;
962 ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
963 item->value, NULL);
964 if (ret < 0) {
965 printk("%s: %d\n", __func__, ret);
966 break;
967 }
968 }
969
970
971 if (sony_backlight_device &&
972 !sony_backlight_update_status(sony_backlight_device))
973 printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n");
974
975
976 dmi_check_system(sony_nc_ids);
977
978 return 0;
979}
980
981static int sony_nc_add(struct acpi_device *device)
982{
983 acpi_status status;
984 int result = 0;
985 acpi_handle handle;
986 struct sony_nc_value *item;
987
988 printk(KERN_INFO DRV_PFX "%s v%s.\n",
989 SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
990
991 sony_nc_acpi_device = device;
992 strcpy(acpi_device_class(device), "sony/hotkey");
993
994 sony_nc_acpi_handle = device->handle;
995
996
997 result = acpi_bus_get_status(device);
998
999 if (!result && !device->status.present) {
1000 dprintk("Device not present\n");
1001 result = -ENODEV;
1002 goto outwalk;
1003 }
1004
1005 if (debug) {
1006 status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
1007 1, sony_walk_callback, NULL, NULL);
1008 if (ACPI_FAILURE(status)) {
1009 printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n");
1010 result = -ENODEV;
1011 goto outwalk;
1012 }
1013 }
1014
1015
1016
1017 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) {
1018 dprintk("Invoking _INI\n");
1019 if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI,
1020 NULL, NULL)))
1021 dprintk("_INI Method failed\n");
1022 }
1023
1024
1025 result = sony_laptop_setup_input(device);
1026 if (result) {
1027 printk(KERN_ERR DRV_PFX
1028 "Unabe to create input devices.\n");
1029 goto outwalk;
1030 }
1031
1032 status = acpi_install_notify_handler(sony_nc_acpi_handle,
1033 ACPI_DEVICE_NOTIFY,
1034 sony_acpi_notify, NULL);
1035 if (ACPI_FAILURE(status)) {
1036 printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status);
1037 result = -ENODEV;
1038 goto outinput;
1039 }
1040
1041 if (acpi_video_backlight_support()) {
1042 printk(KERN_INFO DRV_PFX "brightness ignored, must be "
1043 "controlled by ACPI video driver\n");
1044 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
1045 &handle))) {
1046 sony_backlight_device = backlight_device_register("sony", NULL,
1047 NULL,
1048 &sony_backlight_ops);
1049
1050 if (IS_ERR(sony_backlight_device)) {
1051 printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
1052 sony_backlight_device = NULL;
1053 } else {
1054 sony_backlight_device->props.brightness =
1055 sony_backlight_get_brightness
1056 (sony_backlight_device);
1057 sony_backlight_device->props.max_brightness =
1058 SONY_MAX_BRIGHTNESS - 1;
1059 }
1060
1061 }
1062
1063
1064 dmi_check_system(sony_nc_ids);
1065
1066 result = sony_pf_add();
1067 if (result)
1068 goto outbacklight;
1069
1070
1071 for (item = sony_nc_values; item->name; ++item) {
1072
1073 if (!debug && item->debug)
1074 continue;
1075
1076
1077 for (; item->acpiget && *item->acpiget; ++item->acpiget) {
1078 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
1079 *item->acpiget,
1080 &handle))) {
1081 dprintk("Found %s getter: %s\n",
1082 item->name, *item->acpiget);
1083 item->devattr.attr.mode |= S_IRUGO;
1084 break;
1085 }
1086 }
1087
1088
1089 for (; item->acpiset && *item->acpiset; ++item->acpiset) {
1090 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
1091 *item->acpiset,
1092 &handle))) {
1093 dprintk("Found %s setter: %s\n",
1094 item->name, *item->acpiset);
1095 item->devattr.attr.mode |= S_IWUSR;
1096 break;
1097 }
1098 }
1099
1100 if (item->devattr.attr.mode != 0) {
1101 result =
1102 device_create_file(&sony_pf_device->dev,
1103 &item->devattr);
1104 if (result)
1105 goto out_sysfs;
1106 }
1107 }
1108
1109 return 0;
1110
1111 out_sysfs:
1112 for (item = sony_nc_values; item->name; ++item) {
1113 device_remove_file(&sony_pf_device->dev, &item->devattr);
1114 }
1115 sony_pf_remove();
1116
1117 outbacklight:
1118 if (sony_backlight_device)
1119 backlight_device_unregister(sony_backlight_device);
1120
1121 status = acpi_remove_notify_handler(sony_nc_acpi_handle,
1122 ACPI_DEVICE_NOTIFY,
1123 sony_acpi_notify);
1124 if (ACPI_FAILURE(status))
1125 printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
1126
1127 outinput:
1128 sony_laptop_remove_input();
1129
1130 outwalk:
1131 return result;
1132}
1133
1134static int sony_nc_remove(struct acpi_device *device, int type)
1135{
1136 acpi_status status;
1137 struct sony_nc_value *item;
1138
1139 if (sony_backlight_device)
1140 backlight_device_unregister(sony_backlight_device);
1141
1142 sony_nc_acpi_device = NULL;
1143
1144 status = acpi_remove_notify_handler(sony_nc_acpi_handle,
1145 ACPI_DEVICE_NOTIFY,
1146 sony_acpi_notify);
1147 if (ACPI_FAILURE(status))
1148 printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
1149
1150 for (item = sony_nc_values; item->name; ++item) {
1151 device_remove_file(&sony_pf_device->dev, &item->devattr);
1152 }
1153
1154 sony_pf_remove();
1155 sony_laptop_remove_input();
1156 dprintk(SONY_NC_DRIVER_NAME " removed.\n");
1157
1158 return 0;
1159}
1160
1161static const struct acpi_device_id sony_device_ids[] = {
1162 {SONY_NC_HID, 0},
1163 {SONY_PIC_HID, 0},
1164 {"", 0},
1165};
1166MODULE_DEVICE_TABLE(acpi, sony_device_ids);
1167
1168static const struct acpi_device_id sony_nc_device_ids[] = {
1169 {SONY_NC_HID, 0},
1170 {"", 0},
1171};
1172
1173static struct acpi_driver sony_nc_driver = {
1174 .name = SONY_NC_DRIVER_NAME,
1175 .class = SONY_NC_CLASS,
1176 .ids = sony_nc_device_ids,
1177 .owner = THIS_MODULE,
1178 .ops = {
1179 .add = sony_nc_add,
1180 .remove = sony_nc_remove,
1181 .resume = sony_nc_resume,
1182 },
1183};
1184
1185
1186
1187#define SONYPI_DEVICE_TYPE1 0x00000001
1188#define SONYPI_DEVICE_TYPE2 0x00000002
1189#define SONYPI_DEVICE_TYPE3 0x00000004
1190#define SONYPI_DEVICE_TYPE4 0x00000008
1191
1192#define SONYPI_TYPE1_OFFSET 0x04
1193#define SONYPI_TYPE2_OFFSET 0x12
1194#define SONYPI_TYPE3_OFFSET 0x12
1195#define SONYPI_TYPE4_OFFSET 0x12
1196
1197struct sony_pic_ioport {
1198 struct acpi_resource_io io1;
1199 struct acpi_resource_io io2;
1200 struct list_head list;
1201};
1202
1203struct sony_pic_irq {
1204 struct acpi_resource_irq irq;
1205 struct list_head list;
1206};
1207
1208struct sonypi_eventtypes {
1209 u8 data;
1210 unsigned long mask;
1211 struct sonypi_event *events;
1212};
1213
1214struct device_ctrl {
1215 int model;
1216 int (*handle_irq)(const u8, const u8);
1217 u16 evport_offset;
1218 u8 has_camera;
1219 u8 has_bluetooth;
1220 u8 has_wwan;
1221 struct sonypi_eventtypes *event_types;
1222};
1223
1224struct sony_pic_dev {
1225 struct device_ctrl *control;
1226 struct acpi_device *acpi_dev;
1227 struct sony_pic_irq *cur_irq;
1228 struct sony_pic_ioport *cur_ioport;
1229 struct list_head interrupts;
1230 struct list_head ioports;
1231 struct mutex lock;
1232 u8 camera_power;
1233 u8 bluetooth_power;
1234 u8 wwan_power;
1235};
1236
1237static struct sony_pic_dev spic_dev = {
1238 .interrupts = LIST_HEAD_INIT(spic_dev.interrupts),
1239 .ioports = LIST_HEAD_INIT(spic_dev.ioports),
1240};
1241
1242
1243#define SONYPI_JOGGER_MASK 0x00000001
1244#define SONYPI_CAPTURE_MASK 0x00000002
1245#define SONYPI_FNKEY_MASK 0x00000004
1246#define SONYPI_BLUETOOTH_MASK 0x00000008
1247#define SONYPI_PKEY_MASK 0x00000010
1248#define SONYPI_BACK_MASK 0x00000020
1249#define SONYPI_HELP_MASK 0x00000040
1250#define SONYPI_LID_MASK 0x00000080
1251#define SONYPI_ZOOM_MASK 0x00000100
1252#define SONYPI_THUMBPHRASE_MASK 0x00000200
1253#define SONYPI_MEYE_MASK 0x00000400
1254#define SONYPI_MEMORYSTICK_MASK 0x00000800
1255#define SONYPI_BATTERY_MASK 0x00001000
1256#define SONYPI_WIRELESS_MASK 0x00002000
1257
1258struct sonypi_event {
1259 u8 data;
1260 u8 event;
1261};
1262
1263
1264static struct sonypi_event sonypi_releaseev[] = {
1265 { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
1266 { 0, 0 }
1267};
1268
1269
1270static struct sonypi_event sonypi_joggerev[] = {
1271 { 0x1f, SONYPI_EVENT_JOGDIAL_UP },
1272 { 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
1273 { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
1274 { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
1275 { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
1276 { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
1277 { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
1278 { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
1279 { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
1280 { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
1281 { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
1282 { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
1283 { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
1284 { 0, 0 }
1285};
1286
1287
1288static struct sonypi_event sonypi_captureev[] = {
1289 { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
1290 { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
1291 { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
1292 { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
1293 { 0, 0 }
1294};
1295
1296
1297static struct sonypi_event sonypi_fnkeyev[] = {
1298 { 0x10, SONYPI_EVENT_FNKEY_ESC },
1299 { 0x11, SONYPI_EVENT_FNKEY_F1 },
1300 { 0x12, SONYPI_EVENT_FNKEY_F2 },
1301 { 0x13, SONYPI_EVENT_FNKEY_F3 },
1302 { 0x14, SONYPI_EVENT_FNKEY_F4 },
1303 { 0x15, SONYPI_EVENT_FNKEY_F5 },
1304 { 0x16, SONYPI_EVENT_FNKEY_F6 },
1305 { 0x17, SONYPI_EVENT_FNKEY_F7 },
1306 { 0x18, SONYPI_EVENT_FNKEY_F8 },
1307 { 0x19, SONYPI_EVENT_FNKEY_F9 },
1308 { 0x1a, SONYPI_EVENT_FNKEY_F10 },
1309 { 0x1b, SONYPI_EVENT_FNKEY_F11 },
1310 { 0x1c, SONYPI_EVENT_FNKEY_F12 },
1311 { 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
1312 { 0x21, SONYPI_EVENT_FNKEY_1 },
1313 { 0x22, SONYPI_EVENT_FNKEY_2 },
1314 { 0x31, SONYPI_EVENT_FNKEY_D },
1315 { 0x32, SONYPI_EVENT_FNKEY_E },
1316 { 0x33, SONYPI_EVENT_FNKEY_F },
1317 { 0x34, SONYPI_EVENT_FNKEY_S },
1318 { 0x35, SONYPI_EVENT_FNKEY_B },
1319 { 0x36, SONYPI_EVENT_FNKEY_ONLY },
1320 { 0, 0 }
1321};
1322
1323
1324static struct sonypi_event sonypi_pkeyev[] = {
1325 { 0x01, SONYPI_EVENT_PKEY_P1 },
1326 { 0x02, SONYPI_EVENT_PKEY_P2 },
1327 { 0x04, SONYPI_EVENT_PKEY_P3 },
1328 { 0, 0 }
1329};
1330
1331
1332static struct sonypi_event sonypi_blueev[] = {
1333 { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
1334 { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
1335 { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
1336 { 0, 0 }
1337};
1338
1339
1340static struct sonypi_event sonypi_wlessev[] = {
1341 { 0x59, SONYPI_EVENT_WIRELESS_ON },
1342 { 0x5a, SONYPI_EVENT_WIRELESS_OFF },
1343 { 0, 0 }
1344};
1345
1346
1347static struct sonypi_event sonypi_backev[] = {
1348 { 0x20, SONYPI_EVENT_BACK_PRESSED },
1349 { 0, 0 }
1350};
1351
1352
1353static struct sonypi_event sonypi_helpev[] = {
1354 { 0x3b, SONYPI_EVENT_HELP_PRESSED },
1355 { 0, 0 }
1356};
1357
1358
1359
1360static struct sonypi_event sonypi_lidev[] = {
1361 { 0x51, SONYPI_EVENT_LID_CLOSED },
1362 { 0x50, SONYPI_EVENT_LID_OPENED },
1363 { 0, 0 }
1364};
1365
1366
1367static struct sonypi_event sonypi_zoomev[] = {
1368 { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
1369 { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
1370 { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
1371 { 0, 0 }
1372};
1373
1374
1375static struct sonypi_event sonypi_thumbphraseev[] = {
1376 { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
1377 { 0, 0 }
1378};
1379
1380
1381static struct sonypi_event sonypi_meyeev[] = {
1382 { 0x00, SONYPI_EVENT_MEYE_FACE },
1383 { 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
1384 { 0, 0 }
1385};
1386
1387
1388static struct sonypi_event sonypi_memorystickev[] = {
1389 { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
1390 { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
1391 { 0, 0 }
1392};
1393
1394
1395static struct sonypi_event sonypi_batteryev[] = {
1396 { 0x20, SONYPI_EVENT_BATTERY_INSERT },
1397 { 0x30, SONYPI_EVENT_BATTERY_REMOVE },
1398 { 0, 0 }
1399};
1400
1401static struct sonypi_eventtypes type1_events[] = {
1402 { 0, 0xffffffff, sonypi_releaseev },
1403 { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
1404 { 0x30, SONYPI_LID_MASK, sonypi_lidev },
1405 { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
1406 { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
1407 { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1408 { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
1409 { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
1410 { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1411 { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
1412 { 0 },
1413};
1414static struct sonypi_eventtypes type2_events[] = {
1415 { 0, 0xffffffff, sonypi_releaseev },
1416 { 0x38, SONYPI_LID_MASK, sonypi_lidev },
1417 { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
1418 { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
1419 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1420 { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
1421 { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
1422 { 0x11, SONYPI_BACK_MASK, sonypi_backev },
1423 { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
1424 { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
1425 { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
1426 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1427 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1428 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
1429 { 0 },
1430};
1431static struct sonypi_eventtypes type3_events[] = {
1432 { 0, 0xffffffff, sonypi_releaseev },
1433 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1434 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
1435 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1436 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1437 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
1438 { 0 },
1439};
1440static struct sonypi_eventtypes type4_events[] = {
1441 { 0, 0xffffffff, sonypi_releaseev },
1442 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1443 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
1444 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1445 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1446 { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
1447 { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
1448 { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
1449 { 0 },
1450};
1451
1452
1453#define ITERATIONS_LONG 10000
1454#define ITERATIONS_SHORT 10
1455#define wait_on_command(command, iterations) { \
1456 unsigned int n = iterations; \
1457 while (--n && (command)) \
1458 udelay(1); \
1459 if (!n) \
1460 dprintk("command failed at %s : %s (line %d)\n", \
1461 __FILE__, __func__, __LINE__); \
1462}
1463
1464static u8 sony_pic_call1(u8 dev)
1465{
1466 u8 v1, v2;
1467
1468 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
1469 ITERATIONS_LONG);
1470 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
1471 v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
1472 v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
1473 dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
1474 return v2;
1475}
1476
1477static u8 sony_pic_call2(u8 dev, u8 fn)
1478{
1479 u8 v1;
1480
1481 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
1482 ITERATIONS_LONG);
1483 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
1484 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
1485 ITERATIONS_LONG);
1486 outb(fn, spic_dev.cur_ioport->io1.minimum);
1487 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
1488 dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
1489 return v1;
1490}
1491
1492static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
1493{
1494 u8 v1;
1495
1496 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
1497 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
1498 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
1499 outb(fn, spic_dev.cur_ioport->io1.minimum);
1500 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
1501 outb(v, spic_dev.cur_ioport->io1.minimum);
1502 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
1503 dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
1504 dev, fn, v, v1);
1505 return v1;
1506}
1507
1508
1509
1510
1511static int type4_handle_irq(const u8 data_mask, const u8 ev)
1512{
1513
1514
1515
1516
1517
1518
1519
1520 if (data_mask == 0x31) {
1521 if (ev == 0x5c || ev == 0x5f)
1522 sony_pic_call1(0xA0);
1523 else if (ev == 0x61)
1524 sony_pic_call1(0xB3);
1525 return 0;
1526 }
1527 return 1;
1528}
1529
1530static struct device_ctrl spic_types[] = {
1531 {
1532 .model = SONYPI_DEVICE_TYPE1,
1533 .handle_irq = NULL,
1534 .evport_offset = SONYPI_TYPE1_OFFSET,
1535 .event_types = type1_events,
1536 },
1537 {
1538 .model = SONYPI_DEVICE_TYPE2,
1539 .handle_irq = NULL,
1540 .evport_offset = SONYPI_TYPE2_OFFSET,
1541 .event_types = type2_events,
1542 },
1543 {
1544 .model = SONYPI_DEVICE_TYPE3,
1545 .handle_irq = NULL,
1546 .evport_offset = SONYPI_TYPE3_OFFSET,
1547 .event_types = type3_events,
1548 },
1549 {
1550 .model = SONYPI_DEVICE_TYPE4,
1551 .handle_irq = type4_handle_irq,
1552 .evport_offset = SONYPI_TYPE4_OFFSET,
1553 .event_types = type4_events,
1554 },
1555};
1556
1557static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
1558{
1559 struct pci_dev *pcidev;
1560
1561 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1562 PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
1563 if (pcidev) {
1564 dev->control = &spic_types[0];
1565 goto out;
1566 }
1567
1568 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1569 PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
1570 if (pcidev) {
1571 dev->control = &spic_types[2];
1572 goto out;
1573 }
1574
1575 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1576 PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
1577 if (pcidev) {
1578 dev->control = &spic_types[3];
1579 goto out;
1580 }
1581
1582 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1583 PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
1584 if (pcidev) {
1585 dev->control = &spic_types[3];
1586 goto out;
1587 }
1588
1589
1590 dev->control = &spic_types[1];
1591
1592out:
1593 if (pcidev)
1594 pci_dev_put(pcidev);
1595
1596 printk(KERN_INFO DRV_PFX "detected Type%d model\n",
1597 dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 :
1598 dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 :
1599 dev->control->model == SONYPI_DEVICE_TYPE3 ? 3 : 4);
1600}
1601
1602
1603#define SONYPI_CAMERA_PICTURE 5
1604#define SONYPI_CAMERA_CONTROL 0x10
1605
1606#define SONYPI_CAMERA_BRIGHTNESS 0
1607#define SONYPI_CAMERA_CONTRAST 1
1608#define SONYPI_CAMERA_HUE 2
1609#define SONYPI_CAMERA_COLOR 3
1610#define SONYPI_CAMERA_SHARPNESS 4
1611
1612#define SONYPI_CAMERA_EXPOSURE_MASK 0xC
1613#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3
1614#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30
1615#define SONYPI_CAMERA_MUTE_MASK 0x40
1616
1617
1618#define SONYPI_CAMERA_AGC 6
1619#define SONYPI_CAMERA_AGC_MASK 0x30
1620#define SONYPI_CAMERA_SHUTTER_MASK 0x7
1621
1622#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7
1623#define SONYPI_CAMERA_CONTROL 0x10
1624
1625#define SONYPI_CAMERA_STATUS 7
1626#define SONYPI_CAMERA_STATUS_READY 0x2
1627#define SONYPI_CAMERA_STATUS_POSITION 0x4
1628
1629#define SONYPI_DIRECTION_BACKWARDS 0x4
1630
1631#define SONYPI_CAMERA_REVISION 8
1632#define SONYPI_CAMERA_ROMVERSION 9
1633
1634static int __sony_pic_camera_ready(void)
1635{
1636 u8 v;
1637
1638 v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
1639 return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
1640}
1641
1642static int __sony_pic_camera_off(void)
1643{
1644 if (!camera) {
1645 printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
1646 return -ENODEV;
1647 }
1648
1649 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
1650 SONYPI_CAMERA_MUTE_MASK),
1651 ITERATIONS_SHORT);
1652
1653 if (spic_dev.camera_power) {
1654 sony_pic_call2(0x91, 0);
1655 spic_dev.camera_power = 0;
1656 }
1657 return 0;
1658}
1659
1660static int __sony_pic_camera_on(void)
1661{
1662 int i, j, x;
1663
1664 if (!camera) {
1665 printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
1666 return -ENODEV;
1667 }
1668
1669 if (spic_dev.camera_power)
1670 return 0;
1671
1672 for (j = 5; j > 0; j--) {
1673
1674 for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
1675 msleep(10);
1676 sony_pic_call1(0x93);
1677
1678 for (i = 400; i > 0; i--) {
1679 if (__sony_pic_camera_ready())
1680 break;
1681 msleep(10);
1682 }
1683 if (i)
1684 break;
1685 }
1686
1687 if (j == 0) {
1688 printk(KERN_WARNING DRV_PFX "failed to power on camera\n");
1689 return -ENODEV;
1690 }
1691
1692 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
1693 0x5a),
1694 ITERATIONS_SHORT);
1695
1696 spic_dev.camera_power = 1;
1697 return 0;
1698}
1699
1700
1701int sony_pic_camera_command(int command, u8 value)
1702{
1703 if (!camera)
1704 return -EIO;
1705
1706 mutex_lock(&spic_dev.lock);
1707
1708 switch (command) {
1709 case SONY_PIC_COMMAND_SETCAMERA:
1710 if (value)
1711 __sony_pic_camera_on();
1712 else
1713 __sony_pic_camera_off();
1714 break;
1715 case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
1716 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
1717 ITERATIONS_SHORT);
1718 break;
1719 case SONY_PIC_COMMAND_SETCAMERACONTRAST:
1720 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
1721 ITERATIONS_SHORT);
1722 break;
1723 case SONY_PIC_COMMAND_SETCAMERAHUE:
1724 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
1725 ITERATIONS_SHORT);
1726 break;
1727 case SONY_PIC_COMMAND_SETCAMERACOLOR:
1728 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
1729 ITERATIONS_SHORT);
1730 break;
1731 case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
1732 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
1733 ITERATIONS_SHORT);
1734 break;
1735 case SONY_PIC_COMMAND_SETCAMERAPICTURE:
1736 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
1737 ITERATIONS_SHORT);
1738 break;
1739 case SONY_PIC_COMMAND_SETCAMERAAGC:
1740 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
1741 ITERATIONS_SHORT);
1742 break;
1743 default:
1744 printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n",
1745 command);
1746 break;
1747 }
1748 mutex_unlock(&spic_dev.lock);
1749 return 0;
1750}
1751EXPORT_SYMBOL(sony_pic_camera_command);
1752
1753
1754static void sony_pic_set_wwanpower(u8 state)
1755{
1756 state = !!state;
1757 mutex_lock(&spic_dev.lock);
1758 if (spic_dev.wwan_power == state) {
1759 mutex_unlock(&spic_dev.lock);
1760 return;
1761 }
1762 sony_pic_call2(0xB0, state);
1763 spic_dev.wwan_power = state;
1764 mutex_unlock(&spic_dev.lock);
1765}
1766
1767static ssize_t sony_pic_wwanpower_store(struct device *dev,
1768 struct device_attribute *attr,
1769 const char *buffer, size_t count)
1770{
1771 unsigned long value;
1772 if (count > 31)
1773 return -EINVAL;
1774
1775 value = simple_strtoul(buffer, NULL, 10);
1776 sony_pic_set_wwanpower(value);
1777
1778 return count;
1779}
1780
1781static ssize_t sony_pic_wwanpower_show(struct device *dev,
1782 struct device_attribute *attr, char *buffer)
1783{
1784 ssize_t count;
1785 mutex_lock(&spic_dev.lock);
1786 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
1787 mutex_unlock(&spic_dev.lock);
1788 return count;
1789}
1790
1791
1792static void __sony_pic_set_bluetoothpower(u8 state)
1793{
1794 state = !!state;
1795 if (spic_dev.bluetooth_power == state)
1796 return;
1797 sony_pic_call2(0x96, state);
1798 sony_pic_call1(0x82);
1799 spic_dev.bluetooth_power = state;
1800}
1801
1802static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
1803 struct device_attribute *attr,
1804 const char *buffer, size_t count)
1805{
1806 unsigned long value;
1807 if (count > 31)
1808 return -EINVAL;
1809
1810 value = simple_strtoul(buffer, NULL, 10);
1811 mutex_lock(&spic_dev.lock);
1812 __sony_pic_set_bluetoothpower(value);
1813 mutex_unlock(&spic_dev.lock);
1814
1815 return count;
1816}
1817
1818static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
1819 struct device_attribute *attr, char *buffer)
1820{
1821 ssize_t count = 0;
1822 mutex_lock(&spic_dev.lock);
1823 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
1824 mutex_unlock(&spic_dev.lock);
1825 return count;
1826}
1827
1828
1829
1830#define SONY_PIC_FAN0_STATUS 0x93
1831static int sony_pic_set_fanspeed(unsigned long value)
1832{
1833 return ec_write(SONY_PIC_FAN0_STATUS, value);
1834}
1835
1836static int sony_pic_get_fanspeed(u8 *value)
1837{
1838 return ec_read(SONY_PIC_FAN0_STATUS, value);
1839}
1840
1841static ssize_t sony_pic_fanspeed_store(struct device *dev,
1842 struct device_attribute *attr,
1843 const char *buffer, size_t count)
1844{
1845 unsigned long value;
1846 if (count > 31)
1847 return -EINVAL;
1848
1849 value = simple_strtoul(buffer, NULL, 10);
1850 if (sony_pic_set_fanspeed(value))
1851 return -EIO;
1852
1853 return count;
1854}
1855
1856static ssize_t sony_pic_fanspeed_show(struct device *dev,
1857 struct device_attribute *attr, char *buffer)
1858{
1859 u8 value = 0;
1860 if (sony_pic_get_fanspeed(&value))
1861 return -EIO;
1862
1863 return snprintf(buffer, PAGE_SIZE, "%d\n", value);
1864}
1865
1866#define SPIC_ATTR(_name, _mode) \
1867struct device_attribute spic_attr_##_name = __ATTR(_name, \
1868 _mode, sony_pic_## _name ##_show, \
1869 sony_pic_## _name ##_store)
1870
1871static SPIC_ATTR(bluetoothpower, 0644);
1872static SPIC_ATTR(wwanpower, 0644);
1873static SPIC_ATTR(fanspeed, 0644);
1874
1875static struct attribute *spic_attributes[] = {
1876 &spic_attr_bluetoothpower.attr,
1877 &spic_attr_wwanpower.attr,
1878 &spic_attr_fanspeed.attr,
1879 NULL
1880};
1881
1882static struct attribute_group spic_attribute_group = {
1883 .attrs = spic_attributes
1884};
1885
1886
1887#ifdef CONFIG_SONYPI_COMPAT
1888
1889
1890#define SONYPI_BAT_FLAGS 0x81
1891#define SONYPI_LCD_LIGHT 0x96
1892#define SONYPI_BAT1_PCTRM 0xa0
1893#define SONYPI_BAT1_LEFT 0xa2
1894#define SONYPI_BAT1_MAXRT 0xa4
1895#define SONYPI_BAT2_PCTRM 0xa8
1896#define SONYPI_BAT2_LEFT 0xaa
1897#define SONYPI_BAT2_MAXRT 0xac
1898#define SONYPI_BAT1_MAXTK 0xb0
1899#define SONYPI_BAT1_FULL 0xb2
1900#define SONYPI_BAT2_MAXTK 0xb8
1901#define SONYPI_BAT2_FULL 0xba
1902#define SONYPI_TEMP_STATUS 0xC1
1903
1904struct sonypi_compat_s {
1905 struct fasync_struct *fifo_async;
1906 struct kfifo *fifo;
1907 spinlock_t fifo_lock;
1908 wait_queue_head_t fifo_proc_list;
1909 atomic_t open_count;
1910};
1911static struct sonypi_compat_s sonypi_compat = {
1912 .open_count = ATOMIC_INIT(0),
1913};
1914
1915static int sonypi_misc_fasync(int fd, struct file *filp, int on)
1916{
1917 int retval;
1918
1919 retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
1920 if (retval < 0)
1921 return retval;
1922 return 0;
1923}
1924
1925static int sonypi_misc_release(struct inode *inode, struct file *file)
1926{
1927 atomic_dec(&sonypi_compat.open_count);
1928 return 0;
1929}
1930
1931static int sonypi_misc_open(struct inode *inode, struct file *file)
1932{
1933
1934 lock_kernel();
1935 if (atomic_inc_return(&sonypi_compat.open_count) == 1)
1936 kfifo_reset(sonypi_compat.fifo);
1937 unlock_kernel();
1938 return 0;
1939}
1940
1941static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
1942 size_t count, loff_t *pos)
1943{
1944 ssize_t ret;
1945 unsigned char c;
1946
1947 if ((kfifo_len(sonypi_compat.fifo) == 0) &&
1948 (file->f_flags & O_NONBLOCK))
1949 return -EAGAIN;
1950
1951 ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
1952 kfifo_len(sonypi_compat.fifo) != 0);
1953 if (ret)
1954 return ret;
1955
1956 while (ret < count &&
1957 (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) {
1958 if (put_user(c, buf++))
1959 return -EFAULT;
1960 ret++;
1961 }
1962
1963 if (ret > 0) {
1964 struct inode *inode = file->f_path.dentry->d_inode;
1965 inode->i_atime = current_fs_time(inode->i_sb);
1966 }
1967
1968 return ret;
1969}
1970
1971static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
1972{
1973 poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
1974 if (kfifo_len(sonypi_compat.fifo))
1975 return POLLIN | POLLRDNORM;
1976 return 0;
1977}
1978
1979static int ec_read16(u8 addr, u16 *value)
1980{
1981 u8 val_lb, val_hb;
1982 if (ec_read(addr, &val_lb))
1983 return -1;
1984 if (ec_read(addr + 1, &val_hb))
1985 return -1;
1986 *value = val_lb | (val_hb << 8);
1987 return 0;
1988}
1989
1990static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
1991 unsigned int cmd, unsigned long arg)
1992{
1993 int ret = 0;
1994 void __user *argp = (void __user *)arg;
1995 u8 val8;
1996 u16 val16;
1997 int value;
1998
1999 mutex_lock(&spic_dev.lock);
2000 switch (cmd) {
2001 case SONYPI_IOCGBRT:
2002 if (sony_backlight_device == NULL) {
2003 ret = -EIO;
2004 break;
2005 }
2006 if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) {
2007 ret = -EIO;
2008 break;
2009 }
2010 val8 = ((value & 0xff) - 1) << 5;
2011 if (copy_to_user(argp, &val8, sizeof(val8)))
2012 ret = -EFAULT;
2013 break;
2014 case SONYPI_IOCSBRT:
2015 if (sony_backlight_device == NULL) {
2016 ret = -EIO;
2017 break;
2018 }
2019 if (copy_from_user(&val8, argp, sizeof(val8))) {
2020 ret = -EFAULT;
2021 break;
2022 }
2023 if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
2024 (val8 >> 5) + 1, NULL)) {
2025 ret = -EIO;
2026 break;
2027 }
2028
2029 sony_backlight_device->props.brightness =
2030 sony_backlight_get_brightness(sony_backlight_device);
2031 break;
2032 case SONYPI_IOCGBAT1CAP:
2033 if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
2034 ret = -EIO;
2035 break;
2036 }
2037 if (copy_to_user(argp, &val16, sizeof(val16)))
2038 ret = -EFAULT;
2039 break;
2040 case SONYPI_IOCGBAT1REM:
2041 if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
2042 ret = -EIO;
2043 break;
2044 }
2045 if (copy_to_user(argp, &val16, sizeof(val16)))
2046 ret = -EFAULT;
2047 break;
2048 case SONYPI_IOCGBAT2CAP:
2049 if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
2050 ret = -EIO;
2051 break;
2052 }
2053 if (copy_to_user(argp, &val16, sizeof(val16)))
2054 ret = -EFAULT;
2055 break;
2056 case SONYPI_IOCGBAT2REM:
2057 if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
2058 ret = -EIO;
2059 break;
2060 }
2061 if (copy_to_user(argp, &val16, sizeof(val16)))
2062 ret = -EFAULT;
2063 break;
2064 case SONYPI_IOCGBATFLAGS:
2065 if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
2066 ret = -EIO;
2067 break;
2068 }
2069 val8 &= 0x07;
2070 if (copy_to_user(argp, &val8, sizeof(val8)))
2071 ret = -EFAULT;
2072 break;
2073 case SONYPI_IOCGBLUE:
2074 val8 = spic_dev.bluetooth_power;
2075 if (copy_to_user(argp, &val8, sizeof(val8)))
2076 ret = -EFAULT;
2077 break;
2078 case SONYPI_IOCSBLUE:
2079 if (copy_from_user(&val8, argp, sizeof(val8))) {
2080 ret = -EFAULT;
2081 break;
2082 }
2083 __sony_pic_set_bluetoothpower(val8);
2084 break;
2085
2086 case SONYPI_IOCGFAN:
2087 if (sony_pic_get_fanspeed(&val8)) {
2088 ret = -EIO;
2089 break;
2090 }
2091 if (copy_to_user(argp, &val8, sizeof(val8)))
2092 ret = -EFAULT;
2093 break;
2094 case SONYPI_IOCSFAN:
2095 if (copy_from_user(&val8, argp, sizeof(val8))) {
2096 ret = -EFAULT;
2097 break;
2098 }
2099 if (sony_pic_set_fanspeed(val8))
2100 ret = -EIO;
2101 break;
2102
2103 case SONYPI_IOCGTEMP:
2104 if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
2105 ret = -EIO;
2106 break;
2107 }
2108 if (copy_to_user(argp, &val8, sizeof(val8)))
2109 ret = -EFAULT;
2110 break;
2111 default:
2112 ret = -EINVAL;
2113 }
2114 mutex_unlock(&spic_dev.lock);
2115 return ret;
2116}
2117
2118static const struct file_operations sonypi_misc_fops = {
2119 .owner = THIS_MODULE,
2120 .read = sonypi_misc_read,
2121 .poll = sonypi_misc_poll,
2122 .open = sonypi_misc_open,
2123 .release = sonypi_misc_release,
2124 .fasync = sonypi_misc_fasync,
2125 .ioctl = sonypi_misc_ioctl,
2126};
2127
2128static struct miscdevice sonypi_misc_device = {
2129 .minor = MISC_DYNAMIC_MINOR,
2130 .name = "sonypi",
2131 .fops = &sonypi_misc_fops,
2132};
2133
2134static void sonypi_compat_report_event(u8 event)
2135{
2136 kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));
2137 kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
2138 wake_up_interruptible(&sonypi_compat.fifo_proc_list);
2139}
2140
2141static int sonypi_compat_init(void)
2142{
2143 int error;
2144
2145 spin_lock_init(&sonypi_compat.fifo_lock);
2146 sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
2147 &sonypi_compat.fifo_lock);
2148 if (IS_ERR(sonypi_compat.fifo)) {
2149 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
2150 return PTR_ERR(sonypi_compat.fifo);
2151 }
2152
2153 init_waitqueue_head(&sonypi_compat.fifo_proc_list);
2154
2155 if (minor != -1)
2156 sonypi_misc_device.minor = minor;
2157 error = misc_register(&sonypi_misc_device);
2158 if (error) {
2159 printk(KERN_ERR DRV_PFX "misc_register failed\n");
2160 goto err_free_kfifo;
2161 }
2162 if (minor == -1)
2163 printk(KERN_INFO DRV_PFX "device allocated minor is %d\n",
2164 sonypi_misc_device.minor);
2165
2166 return 0;
2167
2168err_free_kfifo:
2169 kfifo_free(sonypi_compat.fifo);
2170 return error;
2171}
2172
2173static void sonypi_compat_exit(void)
2174{
2175 misc_deregister(&sonypi_misc_device);
2176 kfifo_free(sonypi_compat.fifo);
2177}
2178#else
2179static int sonypi_compat_init(void) { return 0; }
2180static void sonypi_compat_exit(void) { }
2181static void sonypi_compat_report_event(u8 event) { }
2182#endif
2183
2184
2185
2186
2187static acpi_status
2188sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
2189{
2190 u32 i;
2191 struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
2192
2193 switch (resource->type) {
2194 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
2195 {
2196
2197 struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
2198 if (!ioport)
2199 return AE_ERROR;
2200
2201 list_add(&ioport->list, &dev->ioports);
2202 return AE_OK;
2203 }
2204
2205 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
2206
2207 return AE_OK;
2208
2209 case ACPI_RESOURCE_TYPE_IRQ:
2210 {
2211 struct acpi_resource_irq *p = &resource->data.irq;
2212 struct sony_pic_irq *interrupt = NULL;
2213 if (!p || !p->interrupt_count) {
2214
2215
2216
2217
2218 dprintk("Blank IRQ resource\n");
2219 return AE_OK;
2220 }
2221 for (i = 0; i < p->interrupt_count; i++) {
2222 if (!p->interrupts[i]) {
2223 printk(KERN_WARNING DRV_PFX
2224 "Invalid IRQ %d\n",
2225 p->interrupts[i]);
2226 continue;
2227 }
2228 interrupt = kzalloc(sizeof(*interrupt),
2229 GFP_KERNEL);
2230 if (!interrupt)
2231 return AE_ERROR;
2232
2233 list_add(&interrupt->list, &dev->interrupts);
2234 interrupt->irq.triggering = p->triggering;
2235 interrupt->irq.polarity = p->polarity;
2236 interrupt->irq.sharable = p->sharable;
2237 interrupt->irq.interrupt_count = 1;
2238 interrupt->irq.interrupts[0] = p->interrupts[i];
2239 }
2240 return AE_OK;
2241 }
2242 case ACPI_RESOURCE_TYPE_IO:
2243 {
2244 struct acpi_resource_io *io = &resource->data.io;
2245 struct sony_pic_ioport *ioport =
2246 list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
2247 if (!io) {
2248 dprintk("Blank IO resource\n");
2249 return AE_OK;
2250 }
2251
2252 if (!ioport->io1.minimum) {
2253 memcpy(&ioport->io1, io, sizeof(*io));
2254 dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
2255 ioport->io1.address_length);
2256 }
2257 else if (!ioport->io2.minimum) {
2258 memcpy(&ioport->io2, io, sizeof(*io));
2259 dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
2260 ioport->io2.address_length);
2261 }
2262 else {
2263 printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
2264 return AE_ERROR;
2265 }
2266 return AE_OK;
2267 }
2268 default:
2269 dprintk("Resource %d isn't an IRQ nor an IO port\n",
2270 resource->type);
2271
2272 case ACPI_RESOURCE_TYPE_END_TAG:
2273 return AE_OK;
2274 }
2275 return AE_CTRL_TERMINATE;
2276}
2277
2278static int sony_pic_possible_resources(struct acpi_device *device)
2279{
2280 int result = 0;
2281 acpi_status status = AE_OK;
2282
2283 if (!device)
2284 return -EINVAL;
2285
2286
2287
2288 dprintk("Evaluating _STA\n");
2289 result = acpi_bus_get_status(device);
2290 if (result) {
2291 printk(KERN_WARNING DRV_PFX "Unable to read status\n");
2292 goto end;
2293 }
2294
2295 if (!device->status.enabled)
2296 dprintk("Device disabled\n");
2297 else
2298 dprintk("Device enabled\n");
2299
2300
2301
2302
2303 dprintk("Evaluating %s\n", METHOD_NAME__PRS);
2304 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
2305 sony_pic_read_possible_resource, &spic_dev);
2306 if (ACPI_FAILURE(status)) {
2307 printk(KERN_WARNING DRV_PFX
2308 "Failure evaluating %s\n",
2309 METHOD_NAME__PRS);
2310 result = -ENODEV;
2311 }
2312end:
2313 return result;
2314}
2315
2316
2317
2318
2319static int sony_pic_disable(struct acpi_device *device)
2320{
2321 acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL,
2322 NULL);
2323
2324 if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND)
2325 return -ENXIO;
2326
2327 dprintk("Device disabled\n");
2328 return 0;
2329}
2330
2331
2332
2333
2334
2335
2336
2337static int sony_pic_enable(struct acpi_device *device,
2338 struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
2339{
2340 acpi_status status;
2341 int result = 0;
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353 struct {
2354 struct acpi_resource res1;
2355 struct acpi_resource res2;
2356 struct acpi_resource res3;
2357 struct acpi_resource res4;
2358 } *resource;
2359 struct acpi_buffer buffer = { 0, NULL };
2360
2361 if (!ioport || !irq)
2362 return -EINVAL;
2363
2364
2365 resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
2366 if (!resource)
2367 return -ENOMEM;
2368
2369 buffer.length = sizeof(*resource) + 1;
2370 buffer.pointer = resource;
2371
2372
2373 if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) {
2374
2375
2376 resource->res1.type = ACPI_RESOURCE_TYPE_IO;
2377 resource->res1.length = sizeof(struct acpi_resource);
2378 memcpy(&resource->res1.data.io, &ioport->io1,
2379 sizeof(struct acpi_resource_io));
2380
2381 resource->res2.type = ACPI_RESOURCE_TYPE_IO;
2382 resource->res2.length = sizeof(struct acpi_resource);
2383 memcpy(&resource->res2.data.io, &ioport->io2,
2384 sizeof(struct acpi_resource_io));
2385
2386
2387 resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
2388 resource->res3.length = sizeof(struct acpi_resource);
2389 memcpy(&resource->res3.data.irq, &irq->irq,
2390 sizeof(struct acpi_resource_irq));
2391
2392 resource->res3.data.irq.sharable = ACPI_SHARED;
2393
2394 resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
2395
2396 }
2397
2398 else {
2399
2400 resource->res1.type = ACPI_RESOURCE_TYPE_IO;
2401 resource->res1.length = sizeof(struct acpi_resource);
2402 memcpy(&resource->res1.data.io, &ioport->io1,
2403 sizeof(struct acpi_resource_io));
2404
2405
2406 resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
2407 resource->res2.length = sizeof(struct acpi_resource);
2408 memcpy(&resource->res2.data.irq, &irq->irq,
2409 sizeof(struct acpi_resource_irq));
2410
2411 resource->res2.data.irq.sharable = ACPI_SHARED;
2412
2413 resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
2414 }
2415
2416
2417 dprintk("Evaluating _SRS\n");
2418 status = acpi_set_current_resources(device->handle, &buffer);
2419
2420
2421 if (ACPI_FAILURE(status)) {
2422 printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n");
2423 result = -ENODEV;
2424 goto end;
2425 }
2426
2427
2428 sony_pic_call1(0x82);
2429 sony_pic_call2(0x81, 0xff);
2430 sony_pic_call1(compat ? 0x92 : 0x82);
2431
2432end:
2433 kfree(resource);
2434 return result;
2435}
2436
2437
2438
2439
2440
2441
2442static irqreturn_t sony_pic_irq(int irq, void *dev_id)
2443{
2444 int i, j;
2445 u8 ev = 0;
2446 u8 data_mask = 0;
2447 u8 device_event = 0;
2448
2449 struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
2450
2451 ev = inb_p(dev->cur_ioport->io1.minimum);
2452 if (dev->cur_ioport->io2.minimum)
2453 data_mask = inb_p(dev->cur_ioport->io2.minimum);
2454 else
2455 data_mask = inb_p(dev->cur_ioport->io1.minimum +
2456 dev->control->evport_offset);
2457
2458 dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
2459 ev, data_mask, dev->cur_ioport->io1.minimum,
2460 dev->control->evport_offset);
2461
2462 if (ev == 0x00 || ev == 0xff)
2463 return IRQ_HANDLED;
2464
2465 for (i = 0; dev->control->event_types[i].mask; i++) {
2466
2467 if ((data_mask & dev->control->event_types[i].data) !=
2468 dev->control->event_types[i].data)
2469 continue;
2470
2471 if (!(mask & dev->control->event_types[i].mask))
2472 continue;
2473
2474 for (j = 0; dev->control->event_types[i].events[j].event; j++) {
2475 if (ev == dev->control->event_types[i].events[j].data) {
2476 device_event =
2477 dev->control->
2478 event_types[i].events[j].event;
2479 goto found;
2480 }
2481 }
2482 }
2483
2484
2485
2486 if (dev->control->handle_irq &&
2487 dev->control->handle_irq(data_mask, ev) == 0)
2488 return IRQ_HANDLED;
2489
2490 dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
2491 ev, data_mask, dev->cur_ioport->io1.minimum,
2492 dev->control->evport_offset);
2493 return IRQ_HANDLED;
2494
2495found:
2496 sony_laptop_report_input_event(device_event);
2497 acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
2498 sonypi_compat_report_event(device_event);
2499
2500 return IRQ_HANDLED;
2501}
2502
2503
2504
2505
2506
2507
2508static int sony_pic_remove(struct acpi_device *device, int type)
2509{
2510 struct sony_pic_ioport *io, *tmp_io;
2511 struct sony_pic_irq *irq, *tmp_irq;
2512
2513 if (sony_pic_disable(device)) {
2514 printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");
2515 return -ENXIO;
2516 }
2517
2518 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
2519 release_region(spic_dev.cur_ioport->io1.minimum,
2520 spic_dev.cur_ioport->io1.address_length);
2521 if (spic_dev.cur_ioport->io2.minimum)
2522 release_region(spic_dev.cur_ioport->io2.minimum,
2523 spic_dev.cur_ioport->io2.address_length);
2524
2525 sonypi_compat_exit();
2526
2527 sony_laptop_remove_input();
2528
2529
2530 sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
2531 sony_pf_remove();
2532
2533 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
2534 list_del(&io->list);
2535 kfree(io);
2536 }
2537 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
2538 list_del(&irq->list);
2539 kfree(irq);
2540 }
2541 spic_dev.cur_ioport = NULL;
2542 spic_dev.cur_irq = NULL;
2543
2544 dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
2545 return 0;
2546}
2547
2548static int sony_pic_add(struct acpi_device *device)
2549{
2550 int result;
2551 struct sony_pic_ioport *io, *tmp_io;
2552 struct sony_pic_irq *irq, *tmp_irq;
2553
2554 printk(KERN_INFO DRV_PFX "%s v%s.\n",
2555 SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
2556
2557 spic_dev.acpi_dev = device;
2558 strcpy(acpi_device_class(device), "sony/hotkey");
2559 sony_pic_detect_device_type(&spic_dev);
2560 mutex_init(&spic_dev.lock);
2561
2562
2563 result = sony_pic_possible_resources(device);
2564 if (result) {
2565 printk(KERN_ERR DRV_PFX
2566 "Unabe to read possible resources.\n");
2567 goto err_free_resources;
2568 }
2569
2570
2571 result = sony_laptop_setup_input(device);
2572 if (result) {
2573 printk(KERN_ERR DRV_PFX
2574 "Unabe to create input devices.\n");
2575 goto err_free_resources;
2576 }
2577
2578 if (sonypi_compat_init())
2579 goto err_remove_input;
2580
2581
2582 list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
2583 if (request_region(io->io1.minimum, io->io1.address_length,
2584 "Sony Programable I/O Device")) {
2585 dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
2586 io->io1.minimum, io->io1.maximum,
2587 io->io1.address_length);
2588
2589 if (io->io2.minimum) {
2590 if (request_region(io->io2.minimum,
2591 io->io2.address_length,
2592 "Sony Programable I/O Device")) {
2593 dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
2594 io->io2.minimum, io->io2.maximum,
2595 io->io2.address_length);
2596 spic_dev.cur_ioport = io;
2597 break;
2598 }
2599 else {
2600 dprintk("Unable to get I/O port2: "
2601 "0x%.4x (0x%.4x) + 0x%.2x\n",
2602 io->io2.minimum, io->io2.maximum,
2603 io->io2.address_length);
2604 release_region(io->io1.minimum,
2605 io->io1.address_length);
2606 }
2607 }
2608 else {
2609 spic_dev.cur_ioport = io;
2610 break;
2611 }
2612 }
2613 }
2614 if (!spic_dev.cur_ioport) {
2615 printk(KERN_ERR DRV_PFX "Failed to request_region.\n");
2616 result = -ENODEV;
2617 goto err_remove_compat;
2618 }
2619
2620
2621 list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
2622 if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
2623 IRQF_SHARED, "sony-laptop", &spic_dev)) {
2624 dprintk("IRQ: %d - triggering: %d - "
2625 "polarity: %d - shr: %d\n",
2626 irq->irq.interrupts[0],
2627 irq->irq.triggering,
2628 irq->irq.polarity,
2629 irq->irq.sharable);
2630 spic_dev.cur_irq = irq;
2631 break;
2632 }
2633 }
2634 if (!spic_dev.cur_irq) {
2635 printk(KERN_ERR DRV_PFX "Failed to request_irq.\n");
2636 result = -ENODEV;
2637 goto err_release_region;
2638 }
2639
2640
2641 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
2642 if (result) {
2643 printk(KERN_ERR DRV_PFX "Couldn't enable device.\n");
2644 goto err_free_irq;
2645 }
2646
2647 spic_dev.bluetooth_power = -1;
2648
2649 result = sony_pf_add();
2650 if (result)
2651 goto err_disable_device;
2652
2653 result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
2654 if (result)
2655 goto err_remove_pf;
2656
2657 return 0;
2658
2659err_remove_pf:
2660 sony_pf_remove();
2661
2662err_disable_device:
2663 sony_pic_disable(device);
2664
2665err_free_irq:
2666 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
2667
2668err_release_region:
2669 release_region(spic_dev.cur_ioport->io1.minimum,
2670 spic_dev.cur_ioport->io1.address_length);
2671 if (spic_dev.cur_ioport->io2.minimum)
2672 release_region(spic_dev.cur_ioport->io2.minimum,
2673 spic_dev.cur_ioport->io2.address_length);
2674
2675err_remove_compat:
2676 sonypi_compat_exit();
2677
2678err_remove_input:
2679 sony_laptop_remove_input();
2680
2681err_free_resources:
2682 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
2683 list_del(&io->list);
2684 kfree(io);
2685 }
2686 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
2687 list_del(&irq->list);
2688 kfree(irq);
2689 }
2690 spic_dev.cur_ioport = NULL;
2691 spic_dev.cur_irq = NULL;
2692
2693 return result;
2694}
2695
2696static int sony_pic_suspend(struct acpi_device *device, pm_message_t state)
2697{
2698 if (sony_pic_disable(device))
2699 return -ENXIO;
2700 return 0;
2701}
2702
2703static int sony_pic_resume(struct acpi_device *device)
2704{
2705 sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
2706 return 0;
2707}
2708
2709static const struct acpi_device_id sony_pic_device_ids[] = {
2710 {SONY_PIC_HID, 0},
2711 {"", 0},
2712};
2713
2714static struct acpi_driver sony_pic_driver = {
2715 .name = SONY_PIC_DRIVER_NAME,
2716 .class = SONY_PIC_CLASS,
2717 .ids = sony_pic_device_ids,
2718 .owner = THIS_MODULE,
2719 .ops = {
2720 .add = sony_pic_add,
2721 .remove = sony_pic_remove,
2722 .suspend = sony_pic_suspend,
2723 .resume = sony_pic_resume,
2724 },
2725};
2726
2727static struct dmi_system_id __initdata sonypi_dmi_table[] = {
2728 {
2729 .ident = "Sony Vaio",
2730 .matches = {
2731 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
2732 DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
2733 },
2734 },
2735 {
2736 .ident = "Sony Vaio",
2737 .matches = {
2738 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
2739 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
2740 },
2741 },
2742 { }
2743};
2744
2745static int __init sony_laptop_init(void)
2746{
2747 int result;
2748
2749 if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
2750 result = acpi_bus_register_driver(&sony_pic_driver);
2751 if (result) {
2752 printk(KERN_ERR DRV_PFX
2753 "Unable to register SPIC driver.");
2754 goto out;
2755 }
2756 }
2757
2758 result = acpi_bus_register_driver(&sony_nc_driver);
2759 if (result) {
2760 printk(KERN_ERR DRV_PFX "Unable to register SNC driver.");
2761 goto out_unregister_pic;
2762 }
2763
2764 return 0;
2765
2766out_unregister_pic:
2767 if (!no_spic)
2768 acpi_bus_unregister_driver(&sony_pic_driver);
2769out:
2770 return result;
2771}
2772
2773static void __exit sony_laptop_exit(void)
2774{
2775 acpi_bus_unregister_driver(&sony_nc_driver);
2776 if (!no_spic)
2777 acpi_bus_unregister_driver(&sony_pic_driver);
2778}
2779
2780module_init(sony_laptop_init);
2781module_exit(sony_laptop_exit);