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