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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
46
47#include <linux/kernel.h>
48#include <linux/module.h>
49#include <linux/moduleparam.h>
50#include <linux/init.h>
51#include <linux/types.h>
52#include <linux/backlight.h>
53#include <linux/platform_device.h>
54#include <linux/err.h>
55#include <linux/dmi.h>
56#include <linux/pci.h>
57#include <linux/interrupt.h>
58#include <linux/delay.h>
59#include <linux/input.h>
60#include <linux/kfifo.h>
61#include <linux/workqueue.h>
62#include <linux/acpi.h>
63#include <linux/slab.h>
64#include <acpi/acpi_drivers.h>
65#include <acpi/acpi_bus.h>
66#include <asm/uaccess.h>
67#include <linux/sonypi.h>
68#include <linux/sony-laptop.h>
69#include <linux/rfkill.h>
70#ifdef CONFIG_SONYPI_COMPAT
71#include <linux/poll.h>
72#include <linux/miscdevice.h>
73#endif
74
75#define dprintk(fmt, ...) \
76do { \
77 if (debug) \
78 pr_warn(fmt, ##__VA_ARGS__); \
79} while (0)
80
81#define SONY_LAPTOP_DRIVER_VERSION "0.6"
82
83#define SONY_NC_CLASS "sony-nc"
84#define SONY_NC_HID "SNY5001"
85#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver"
86
87#define SONY_PIC_CLASS "sony-pic"
88#define SONY_PIC_HID "SNY6001"
89#define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver"
90
91MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
92MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
93MODULE_LICENSE("GPL");
94MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION);
95
96static int debug;
97module_param(debug, int, 0);
98MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
99 "the development of this driver");
100
101static int no_spic;
102module_param(no_spic, int, 0444);
103MODULE_PARM_DESC(no_spic,
104 "set this if you don't want to enable the SPIC device");
105
106static int compat;
107module_param(compat, int, 0444);
108MODULE_PARM_DESC(compat,
109 "set this if you want to enable backward compatibility mode");
110
111static unsigned long mask = 0xffffffff;
112module_param(mask, ulong, 0644);
113MODULE_PARM_DESC(mask,
114 "set this to the mask of event you want to enable (see doc)");
115
116static int camera;
117module_param(camera, int, 0444);
118MODULE_PARM_DESC(camera,
119 "set this to 1 to enable Motion Eye camera controls "
120 "(only use it if you have a C1VE or C1VN model)");
121
122#ifdef CONFIG_SONYPI_COMPAT
123static int minor = -1;
124module_param(minor, int, 0);
125MODULE_PARM_DESC(minor,
126 "minor number of the misc device for the SPIC compatibility code, "
127 "default is -1 (automatic)");
128#endif
129
130static int kbd_backlight;
131module_param(kbd_backlight, int, 0444);
132MODULE_PARM_DESC(kbd_backlight,
133 "set this to 0 to disable keyboard backlight, "
134 "1 to enable it (default: 0)");
135
136static int kbd_backlight_timeout;
137module_param(kbd_backlight_timeout, int, 0444);
138MODULE_PARM_DESC(kbd_backlight_timeout,
139 "set this to 0 to set the default 10 seconds timeout, "
140 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
141 "(default: 0)");
142
143static void sony_nc_kbd_backlight_resume(void);
144
145enum sony_nc_rfkill {
146 SONY_WIFI,
147 SONY_BLUETOOTH,
148 SONY_WWAN,
149 SONY_WIMAX,
150 N_SONY_RFKILL,
151};
152
153static int sony_rfkill_handle;
154static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
155static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
156static void sony_nc_rfkill_update(void);
157
158
159
160#define SONY_LAPTOP_BUF_SIZE 128
161struct sony_laptop_input_s {
162 atomic_t users;
163 struct input_dev *jog_dev;
164 struct input_dev *key_dev;
165 struct kfifo fifo;
166 spinlock_t fifo_lock;
167 struct timer_list release_key_timer;
168};
169
170static struct sony_laptop_input_s sony_laptop_input = {
171 .users = ATOMIC_INIT(0),
172};
173
174struct sony_laptop_keypress {
175 struct input_dev *dev;
176 int key;
177};
178
179
180
181
182static int sony_laptop_input_index[] = {
183 -1,
184 -1,
185 -1,
186 -1,
187 -1,
188 -1,
189 -1,
190 0,
191 1,
192 2,
193 3,
194 4,
195 5,
196 6,
197 7,
198 8,
199 9,
200 10,
201 11,
202 12,
203 13,
204 14,
205 15,
206 16,
207 17,
208 18,
209 19,
210 20,
211 21,
212 22,
213 23,
214 24,
215 25,
216 26,
217 27,
218 28,
219 -1,
220 -1,
221 29,
222 30,
223 31,
224 32,
225 33,
226 34,
227 35,
228 36,
229 37,
230 38,
231 39,
232 40,
233 41,
234 42,
235 43,
236 44,
237 45,
238 46,
239 -1,
240 -1,
241 -1,
242 -1,
243 47,
244 48,
245 49,
246 50,
247 51,
248 52,
249 53,
250 54,
251 55,
252 56,
253 57,
254 -1,
255 58,
256 59,
257};
258
259static int sony_laptop_input_keycode_map[] = {
260 KEY_CAMERA,
261 KEY_RESERVED,
262 KEY_RESERVED,
263 KEY_RESERVED,
264 KEY_FN_ESC,
265 KEY_FN_F1,
266 KEY_FN_F2,
267 KEY_FN_F3,
268 KEY_FN_F4,
269 KEY_FN_F5,
270 KEY_FN_F6,
271 KEY_FN_F7,
272 KEY_FN_F8,
273 KEY_FN_F9,
274 KEY_FN_F10,
275 KEY_FN_F11,
276 KEY_FN_F12,
277 KEY_FN_F1,
278 KEY_FN_F2,
279 KEY_FN_D,
280 KEY_FN_E,
281 KEY_FN_F,
282 KEY_FN_S,
283 KEY_FN_B,
284 KEY_BLUETOOTH,
285 KEY_PROG1,
286 KEY_PROG2,
287 KEY_PROG3,
288 KEY_BACK,
289 KEY_BLUETOOTH,
290 KEY_BLUETOOTH,
291 KEY_HELP,
292 KEY_FN,
293 KEY_RESERVED,
294 KEY_RESERVED,
295 KEY_RESERVED,
296 KEY_RESERVED,
297 KEY_RESERVED,
298 KEY_RESERVED,
299 KEY_RESERVED,
300 KEY_RESERVED,
301 KEY_ZOOM,
302 BTN_THUMB,
303 KEY_RESERVED,
304 KEY_RESERVED,
305 KEY_RESERVED,
306 KEY_RESERVED,
307 KEY_WLAN,
308 KEY_WLAN,
309 KEY_ZOOMIN,
310 KEY_ZOOMOUT,
311 KEY_EJECTCD,
312 KEY_F13,
313 KEY_PROG4,
314 KEY_F14,
315 KEY_F15,
316 KEY_VOLUMEUP,
317 KEY_VOLUMEDOWN,
318 KEY_MEDIA,
319 KEY_VENDOR,
320};
321
322
323static void do_sony_laptop_release_key(unsigned long unused)
324{
325 struct sony_laptop_keypress kp;
326 unsigned long flags;
327
328 spin_lock_irqsave(&sony_laptop_input.fifo_lock, flags);
329
330 if (kfifo_out(&sony_laptop_input.fifo,
331 (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
332 input_report_key(kp.dev, kp.key, 0);
333 input_sync(kp.dev);
334 }
335
336
337 if (kfifo_len(&sony_laptop_input.fifo) != 0)
338 mod_timer(&sony_laptop_input.release_key_timer,
339 jiffies + msecs_to_jiffies(10));
340
341 spin_unlock_irqrestore(&sony_laptop_input.fifo_lock, flags);
342}
343
344
345static void sony_laptop_report_input_event(u8 event)
346{
347 struct input_dev *jog_dev = sony_laptop_input.jog_dev;
348 struct input_dev *key_dev = sony_laptop_input.key_dev;
349 struct sony_laptop_keypress kp = { NULL };
350
351 if (event == SONYPI_EVENT_FNKEY_RELEASED ||
352 event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
353
354 return;
355 }
356
357
358 switch (event) {
359
360 case SONYPI_EVENT_JOGDIAL_UP:
361 case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
362 input_report_rel(jog_dev, REL_WHEEL, 1);
363 input_sync(jog_dev);
364 return;
365
366 case SONYPI_EVENT_JOGDIAL_DOWN:
367 case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
368 input_report_rel(jog_dev, REL_WHEEL, -1);
369 input_sync(jog_dev);
370 return;
371
372
373 case SONYPI_EVENT_JOGDIAL_PRESSED:
374 kp.key = BTN_MIDDLE;
375 kp.dev = jog_dev;
376 break;
377
378 default:
379 if (event >= ARRAY_SIZE(sony_laptop_input_index)) {
380 dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
381 break;
382 }
383 if (sony_laptop_input_index[event] != -1) {
384 kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
385 if (kp.key != KEY_UNKNOWN)
386 kp.dev = key_dev;
387 }
388 break;
389 }
390
391 if (kp.dev) {
392 input_report_key(kp.dev, kp.key, 1);
393
394 input_event(kp.dev, EV_MSC, MSC_SCAN, event);
395 input_sync(kp.dev);
396
397
398 kfifo_in_locked(&sony_laptop_input.fifo,
399 (unsigned char *)&kp, sizeof(kp),
400 &sony_laptop_input.fifo_lock);
401 mod_timer(&sony_laptop_input.release_key_timer,
402 jiffies + msecs_to_jiffies(10));
403 } else
404 dprintk("unknown input event %.2x\n", event);
405}
406
407static int sony_laptop_setup_input(struct acpi_device *acpi_device)
408{
409 struct input_dev *jog_dev;
410 struct input_dev *key_dev;
411 int i;
412 int error;
413
414
415 if (atomic_add_return(1, &sony_laptop_input.users) > 1)
416 return 0;
417
418
419 spin_lock_init(&sony_laptop_input.fifo_lock);
420 error = kfifo_alloc(&sony_laptop_input.fifo,
421 SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
422 if (error) {
423 pr_err("kfifo_alloc failed\n");
424 goto err_dec_users;
425 }
426
427 setup_timer(&sony_laptop_input.release_key_timer,
428 do_sony_laptop_release_key, 0);
429
430
431 key_dev = input_allocate_device();
432 if (!key_dev) {
433 error = -ENOMEM;
434 goto err_free_kfifo;
435 }
436
437 key_dev->name = "Sony Vaio Keys";
438 key_dev->id.bustype = BUS_ISA;
439 key_dev->id.vendor = PCI_VENDOR_ID_SONY;
440 key_dev->dev.parent = &acpi_device->dev;
441
442
443 input_set_capability(key_dev, EV_MSC, MSC_SCAN);
444
445 __set_bit(EV_KEY, key_dev->evbit);
446 key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
447 key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
448 key_dev->keycode = &sony_laptop_input_keycode_map;
449 for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++)
450 __set_bit(sony_laptop_input_keycode_map[i], key_dev->keybit);
451 __clear_bit(KEY_RESERVED, key_dev->keybit);
452
453 error = input_register_device(key_dev);
454 if (error)
455 goto err_free_keydev;
456
457 sony_laptop_input.key_dev = key_dev;
458
459
460 jog_dev = input_allocate_device();
461 if (!jog_dev) {
462 error = -ENOMEM;
463 goto err_unregister_keydev;
464 }
465
466 jog_dev->name = "Sony Vaio Jogdial";
467 jog_dev->id.bustype = BUS_ISA;
468 jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
469 key_dev->dev.parent = &acpi_device->dev;
470
471 input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
472 input_set_capability(jog_dev, EV_REL, REL_WHEEL);
473
474 error = input_register_device(jog_dev);
475 if (error)
476 goto err_free_jogdev;
477
478 sony_laptop_input.jog_dev = jog_dev;
479
480 return 0;
481
482err_free_jogdev:
483 input_free_device(jog_dev);
484
485err_unregister_keydev:
486 input_unregister_device(key_dev);
487
488 key_dev = NULL;
489
490err_free_keydev:
491 input_free_device(key_dev);
492
493err_free_kfifo:
494 kfifo_free(&sony_laptop_input.fifo);
495
496err_dec_users:
497 atomic_dec(&sony_laptop_input.users);
498 return error;
499}
500
501static void sony_laptop_remove_input(void)
502{
503 struct sony_laptop_keypress kp = { NULL };
504
505
506 if (!atomic_dec_and_test(&sony_laptop_input.users))
507 return;
508
509 del_timer_sync(&sony_laptop_input.release_key_timer);
510
511
512
513
514
515 while (kfifo_out(&sony_laptop_input.fifo,
516 (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
517 input_report_key(kp.dev, kp.key, 0);
518 input_sync(kp.dev);
519 }
520
521
522 input_unregister_device(sony_laptop_input.key_dev);
523 sony_laptop_input.key_dev = NULL;
524
525 if (sony_laptop_input.jog_dev) {
526 input_unregister_device(sony_laptop_input.jog_dev);
527 sony_laptop_input.jog_dev = NULL;
528 }
529
530 kfifo_free(&sony_laptop_input.fifo);
531}
532
533
534
535static atomic_t sony_pf_users = ATOMIC_INIT(0);
536static struct platform_driver sony_pf_driver = {
537 .driver = {
538 .name = "sony-laptop",
539 .owner = THIS_MODULE,
540 }
541};
542static struct platform_device *sony_pf_device;
543
544static int sony_pf_add(void)
545{
546 int ret = 0;
547
548
549 if (atomic_add_return(1, &sony_pf_users) > 1)
550 return 0;
551
552 ret = platform_driver_register(&sony_pf_driver);
553 if (ret)
554 goto out;
555
556 sony_pf_device = platform_device_alloc("sony-laptop", -1);
557 if (!sony_pf_device) {
558 ret = -ENOMEM;
559 goto out_platform_registered;
560 }
561
562 ret = platform_device_add(sony_pf_device);
563 if (ret)
564 goto out_platform_alloced;
565
566 return 0;
567
568 out_platform_alloced:
569 platform_device_put(sony_pf_device);
570 sony_pf_device = NULL;
571 out_platform_registered:
572 platform_driver_unregister(&sony_pf_driver);
573 out:
574 atomic_dec(&sony_pf_users);
575 return ret;
576}
577
578static void sony_pf_remove(void)
579{
580
581 if (!atomic_dec_and_test(&sony_pf_users))
582 return;
583
584 platform_device_unregister(sony_pf_device);
585 platform_driver_unregister(&sony_pf_driver);
586}
587
588
589
590
591
592#define SONY_MAX_BRIGHTNESS 8
593
594#define SNC_VALIDATE_IN 0
595#define SNC_VALIDATE_OUT 1
596
597static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
598 char *);
599static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
600 const char *, size_t);
601static int boolean_validate(const int, const int);
602static int brightness_default_validate(const int, const int);
603
604struct sony_nc_value {
605 char *name;
606 char **acpiget;
607 char **acpiset;
608 int (*validate)(const int, const int);
609 int value;
610 int valid;
611 int debug;
612 struct device_attribute devattr;
613};
614
615#define SNC_HANDLE_NAMES(_name, _values...) \
616 static char *snc_##_name[] = { _values, NULL }
617
618#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
619 { \
620 .name = __stringify(_name), \
621 .acpiget = _getters, \
622 .acpiset = _setters, \
623 .validate = _validate, \
624 .debug = _debug, \
625 .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
626 }
627
628#define SNC_HANDLE_NULL { .name = NULL }
629
630SNC_HANDLE_NAMES(fnkey_get, "GHKE");
631
632SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
633SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
634
635SNC_HANDLE_NAMES(cdpower_get, "GCDP");
636SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
637
638SNC_HANDLE_NAMES(audiopower_get, "GAZP");
639SNC_HANDLE_NAMES(audiopower_set, "AZPW");
640
641SNC_HANDLE_NAMES(lanpower_get, "GLNP");
642SNC_HANDLE_NAMES(lanpower_set, "LNPW");
643
644SNC_HANDLE_NAMES(lidstate_get, "GLID");
645
646SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
647SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
648
649SNC_HANDLE_NAMES(gainbass_get, "GMGB");
650SNC_HANDLE_NAMES(gainbass_set, "CMGB");
651
652SNC_HANDLE_NAMES(PID_get, "GPID");
653
654SNC_HANDLE_NAMES(CTR_get, "GCTR");
655SNC_HANDLE_NAMES(CTR_set, "SCTR");
656
657SNC_HANDLE_NAMES(PCR_get, "GPCR");
658SNC_HANDLE_NAMES(PCR_set, "SPCR");
659
660SNC_HANDLE_NAMES(CMI_get, "GCMI");
661SNC_HANDLE_NAMES(CMI_set, "SCMI");
662
663static struct sony_nc_value sony_nc_values[] = {
664 SNC_HANDLE(brightness_default, snc_brightness_def_get,
665 snc_brightness_def_set, brightness_default_validate, 0),
666 SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
667 SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
668 SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
669 boolean_validate, 0),
670 SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
671 boolean_validate, 1),
672 SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
673 boolean_validate, 0),
674 SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
675 boolean_validate, 0),
676 SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
677 boolean_validate, 0),
678
679 SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
680 SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
681 SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
682 SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
683 SNC_HANDLE_NULL
684};
685
686static acpi_handle sony_nc_acpi_handle;
687static struct acpi_device *sony_nc_acpi_device = NULL;
688
689
690
691
692static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
693{
694 struct acpi_buffer output;
695 union acpi_object out_obj;
696 acpi_status status;
697
698 output.length = sizeof(out_obj);
699 output.pointer = &out_obj;
700
701 status = acpi_evaluate_object(handle, name, NULL, &output);
702 if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) {
703 *result = out_obj.integer.value;
704 return 0;
705 }
706
707 pr_warn("acpi_callreadfunc failed\n");
708
709 return -1;
710}
711
712static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
713 int *result)
714{
715 struct acpi_object_list params;
716 union acpi_object in_obj;
717 struct acpi_buffer output;
718 union acpi_object out_obj;
719 acpi_status status;
720
721 params.count = 1;
722 params.pointer = &in_obj;
723 in_obj.type = ACPI_TYPE_INTEGER;
724 in_obj.integer.value = value;
725
726 output.length = sizeof(out_obj);
727 output.pointer = &out_obj;
728
729 status = acpi_evaluate_object(handle, name, ¶ms, &output);
730 if (status == AE_OK) {
731 if (result != NULL) {
732 if (out_obj.type != ACPI_TYPE_INTEGER) {
733 pr_warn("acpi_evaluate_object bad return type\n");
734 return -1;
735 }
736 *result = out_obj.integer.value;
737 }
738 return 0;
739 }
740
741 pr_warn("acpi_evaluate_object failed\n");
742
743 return -1;
744}
745
746struct sony_nc_handles {
747 u16 cap[0x10];
748 struct device_attribute devattr;
749};
750
751static struct sony_nc_handles *handles;
752
753static ssize_t sony_nc_handles_show(struct device *dev,
754 struct device_attribute *attr, char *buffer)
755{
756 ssize_t len = 0;
757 int i;
758
759 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
760 len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
761 handles->cap[i]);
762 }
763 len += snprintf(buffer + len, PAGE_SIZE - len, "\n");
764
765 return len;
766}
767
768static int sony_nc_handles_setup(struct platform_device *pd)
769{
770 int i;
771 int result;
772
773 handles = kzalloc(sizeof(*handles), GFP_KERNEL);
774 if (!handles)
775 return -ENOMEM;
776
777 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
778 if (!acpi_callsetfunc(sony_nc_acpi_handle,
779 "SN00", i + 0x20, &result)) {
780 dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
781 result, i);
782 handles->cap[i] = result;
783 }
784 }
785
786 if (debug) {
787 sysfs_attr_init(&handles->devattr.attr);
788 handles->devattr.attr.name = "handles";
789 handles->devattr.attr.mode = S_IRUGO;
790 handles->devattr.show = sony_nc_handles_show;
791
792
793 if (device_create_file(&pd->dev, &handles->devattr)) {
794 kfree(handles);
795 handles = NULL;
796 return -1;
797 }
798 }
799
800 return 0;
801}
802
803static int sony_nc_handles_cleanup(struct platform_device *pd)
804{
805 if (handles) {
806 if (debug)
807 device_remove_file(&pd->dev, &handles->devattr);
808 kfree(handles);
809 handles = NULL;
810 }
811 return 0;
812}
813
814static int sony_find_snc_handle(int handle)
815{
816 int i;
817
818
819 if (!handles)
820 return -1;
821
822 for (i = 0; i < 0x10; i++) {
823 if (handles->cap[i] == handle) {
824 dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
825 handle, i);
826 return i;
827 }
828 }
829 dprintk("handle 0x%.4x not found\n", handle);
830 return -1;
831}
832
833static int sony_call_snc_handle(int handle, int argument, int *result)
834{
835 int ret = 0;
836 int offset = sony_find_snc_handle(handle);
837
838 if (offset < 0)
839 return -1;
840
841 ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument,
842 result);
843 dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument,
844 *result);
845 return ret;
846}
847
848
849
850
851
852
853
854
855
856
857static int brightness_default_validate(const int direction, const int value)
858{
859 switch (direction) {
860 case SNC_VALIDATE_OUT:
861 return value - 1;
862 case SNC_VALIDATE_IN:
863 if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
864 return value + 1;
865 }
866 return -EINVAL;
867}
868
869
870
871
872
873
874static int boolean_validate(const int direction, const int value)
875{
876 if (direction == SNC_VALIDATE_IN) {
877 if (value != 0 && value != 1)
878 return -EINVAL;
879 }
880 return value;
881}
882
883
884
885
886static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
887 char *buffer)
888{
889 int value;
890 struct sony_nc_value *item =
891 container_of(attr, struct sony_nc_value, devattr);
892
893 if (!*item->acpiget)
894 return -EIO;
895
896 if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0)
897 return -EIO;
898
899 if (item->validate)
900 value = item->validate(SNC_VALIDATE_OUT, value);
901
902 return snprintf(buffer, PAGE_SIZE, "%d\n", value);
903}
904
905static ssize_t sony_nc_sysfs_store(struct device *dev,
906 struct device_attribute *attr,
907 const char *buffer, size_t count)
908{
909 int value;
910 struct sony_nc_value *item =
911 container_of(attr, struct sony_nc_value, devattr);
912
913 if (!item->acpiset)
914 return -EIO;
915
916 if (count > 31)
917 return -EINVAL;
918
919 value = simple_strtoul(buffer, NULL, 10);
920
921 if (item->validate)
922 value = item->validate(SNC_VALIDATE_IN, value);
923
924 if (value < 0)
925 return value;
926
927 if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0)
928 return -EIO;
929 item->value = value;
930 item->valid = 1;
931 return count;
932}
933
934
935
936
937
938struct sony_backlight_props {
939 struct backlight_device *dev;
940 int handle;
941 u8 offset;
942 u8 maxlvl;
943};
944struct sony_backlight_props sony_bl_props;
945
946static int sony_backlight_update_status(struct backlight_device *bd)
947{
948 return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
949 bd->props.brightness + 1, NULL);
950}
951
952static int sony_backlight_get_brightness(struct backlight_device *bd)
953{
954 int value;
955
956 if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
957 return 0;
958
959 return value - 1;
960}
961
962static int sony_nc_get_brightness_ng(struct backlight_device *bd)
963{
964 int result;
965 struct sony_backlight_props *sdev =
966 (struct sony_backlight_props *)bl_get_data(bd);
967
968 sony_call_snc_handle(sdev->handle, 0x0200, &result);
969
970 return (result & 0xff) - sdev->offset;
971}
972
973static int sony_nc_update_status_ng(struct backlight_device *bd)
974{
975 int value, result;
976 struct sony_backlight_props *sdev =
977 (struct sony_backlight_props *)bl_get_data(bd);
978
979 value = bd->props.brightness + sdev->offset;
980 if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result))
981 return -EIO;
982
983 return value;
984}
985
986static const struct backlight_ops sony_backlight_ops = {
987 .options = BL_CORE_SUSPENDRESUME,
988 .update_status = sony_backlight_update_status,
989 .get_brightness = sony_backlight_get_brightness,
990};
991static const struct backlight_ops sony_backlight_ng_ops = {
992 .options = BL_CORE_SUSPENDRESUME,
993 .update_status = sony_nc_update_status_ng,
994 .get_brightness = sony_nc_get_brightness_ng,
995};
996
997
998
999
1000struct sony_nc_event {
1001 u8 data;
1002 u8 event;
1003};
1004
1005static struct sony_nc_event sony_100_events[] = {
1006 { 0x90, SONYPI_EVENT_PKEY_P1 },
1007 { 0x10, SONYPI_EVENT_ANYBUTTON_RELEASED },
1008 { 0x91, SONYPI_EVENT_PKEY_P2 },
1009 { 0x11, SONYPI_EVENT_ANYBUTTON_RELEASED },
1010 { 0x81, SONYPI_EVENT_FNKEY_F1 },
1011 { 0x01, SONYPI_EVENT_FNKEY_RELEASED },
1012 { 0x82, SONYPI_EVENT_FNKEY_F2 },
1013 { 0x02, SONYPI_EVENT_FNKEY_RELEASED },
1014 { 0x83, SONYPI_EVENT_FNKEY_F3 },
1015 { 0x03, SONYPI_EVENT_FNKEY_RELEASED },
1016 { 0x84, SONYPI_EVENT_FNKEY_F4 },
1017 { 0x04, SONYPI_EVENT_FNKEY_RELEASED },
1018 { 0x85, SONYPI_EVENT_FNKEY_F5 },
1019 { 0x05, SONYPI_EVENT_FNKEY_RELEASED },
1020 { 0x86, SONYPI_EVENT_FNKEY_F6 },
1021 { 0x06, SONYPI_EVENT_FNKEY_RELEASED },
1022 { 0x87, SONYPI_EVENT_FNKEY_F7 },
1023 { 0x07, SONYPI_EVENT_FNKEY_RELEASED },
1024 { 0x89, SONYPI_EVENT_FNKEY_F9 },
1025 { 0x09, SONYPI_EVENT_FNKEY_RELEASED },
1026 { 0x8A, SONYPI_EVENT_FNKEY_F10 },
1027 { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
1028 { 0x8C, SONYPI_EVENT_FNKEY_F12 },
1029 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
1030 { 0x9d, SONYPI_EVENT_ZOOM_PRESSED },
1031 { 0x1d, SONYPI_EVENT_ANYBUTTON_RELEASED },
1032 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
1033 { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED },
1034 { 0xa1, SONYPI_EVENT_MEDIA_PRESSED },
1035 { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED },
1036 { 0xa4, SONYPI_EVENT_CD_EJECT_PRESSED },
1037 { 0x24, SONYPI_EVENT_ANYBUTTON_RELEASED },
1038 { 0xa5, SONYPI_EVENT_VENDOR_PRESSED },
1039 { 0x25, SONYPI_EVENT_ANYBUTTON_RELEASED },
1040 { 0xa6, SONYPI_EVENT_HELP_PRESSED },
1041 { 0x26, SONYPI_EVENT_ANYBUTTON_RELEASED },
1042 { 0, 0 },
1043};
1044
1045static struct sony_nc_event sony_127_events[] = {
1046 { 0x81, SONYPI_EVENT_MODEKEY_PRESSED },
1047 { 0x01, SONYPI_EVENT_ANYBUTTON_RELEASED },
1048 { 0x82, SONYPI_EVENT_PKEY_P1 },
1049 { 0x02, SONYPI_EVENT_ANYBUTTON_RELEASED },
1050 { 0x83, SONYPI_EVENT_PKEY_P2 },
1051 { 0x03, SONYPI_EVENT_ANYBUTTON_RELEASED },
1052 { 0x84, SONYPI_EVENT_PKEY_P3 },
1053 { 0x04, SONYPI_EVENT_ANYBUTTON_RELEASED },
1054 { 0x85, SONYPI_EVENT_PKEY_P4 },
1055 { 0x05, SONYPI_EVENT_ANYBUTTON_RELEASED },
1056 { 0x86, SONYPI_EVENT_PKEY_P5 },
1057 { 0x06, SONYPI_EVENT_ANYBUTTON_RELEASED },
1058 { 0x87, SONYPI_EVENT_SETTINGKEY_PRESSED },
1059 { 0x07, SONYPI_EVENT_ANYBUTTON_RELEASED },
1060 { 0, 0 },
1061};
1062
1063
1064
1065
1066static void sony_nc_notify(struct acpi_device *device, u32 event)
1067{
1068 u32 ev = event;
1069
1070 if (ev >= 0x90) {
1071
1072 int result;
1073 int key_handle = 0;
1074 ev -= 0x90;
1075
1076 if (sony_find_snc_handle(0x100) == ev)
1077 key_handle = 0x100;
1078 if (sony_find_snc_handle(0x127) == ev)
1079 key_handle = 0x127;
1080
1081 if (key_handle) {
1082 struct sony_nc_event *key_event;
1083
1084 if (sony_call_snc_handle(key_handle, 0x200, &result)) {
1085 dprintk("sony_nc_notify, unable to decode"
1086 " event 0x%.2x 0x%.2x\n", key_handle,
1087 ev);
1088
1089 ev = event;
1090 } else {
1091 ev = result & 0xFF;
1092
1093 if (key_handle == 0x100)
1094 key_event = sony_100_events;
1095 else
1096 key_event = sony_127_events;
1097
1098 for (; key_event->data; key_event++) {
1099 if (key_event->data == ev) {
1100 ev = key_event->event;
1101 break;
1102 }
1103 }
1104
1105 if (!key_event->data)
1106 pr_info("Unknown event: 0x%x 0x%x\n",
1107 key_handle, ev);
1108 else
1109 sony_laptop_report_input_event(ev);
1110 }
1111 } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) {
1112 sony_nc_rfkill_update();
1113 return;
1114 }
1115 } else
1116 sony_laptop_report_input_event(ev);
1117
1118 dprintk("sony_nc_notify, event: 0x%.2x\n", ev);
1119 acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev);
1120}
1121
1122static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
1123 void *context, void **return_value)
1124{
1125 struct acpi_device_info *info;
1126
1127 if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
1128 pr_warn("method: name: %4.4s, args %X\n",
1129 (char *)&info->name, info->param_count);
1130
1131 kfree(info);
1132 }
1133
1134 return AE_OK;
1135}
1136
1137
1138
1139
1140static int sony_nc_function_setup(struct acpi_device *device)
1141{
1142 int result;
1143
1144
1145 acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result);
1146
1147
1148 sony_call_snc_handle(0x0100, 0, &result);
1149 sony_call_snc_handle(0x0101, 0, &result);
1150 sony_call_snc_handle(0x0102, 0x100, &result);
1151 sony_call_snc_handle(0x0127, 0, &result);
1152
1153 return 0;
1154}
1155
1156static int sony_nc_resume(struct acpi_device *device)
1157{
1158 struct sony_nc_value *item;
1159 acpi_handle handle;
1160
1161 for (item = sony_nc_values; item->name; item++) {
1162 int ret;
1163
1164 if (!item->valid)
1165 continue;
1166 ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
1167 item->value, NULL);
1168 if (ret < 0) {
1169 pr_err("%s: %d\n", __func__, ret);
1170 break;
1171 }
1172 }
1173
1174 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
1175 &handle))) {
1176 if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL))
1177 dprintk("ECON Method failed\n");
1178 }
1179
1180 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
1181 &handle))) {
1182 dprintk("Doing SNC setup\n");
1183 sony_nc_function_setup(device);
1184 }
1185
1186
1187 sony_nc_rfkill_update();
1188
1189
1190 sony_nc_kbd_backlight_resume();
1191
1192 return 0;
1193}
1194
1195static void sony_nc_rfkill_cleanup(void)
1196{
1197 int i;
1198
1199 for (i = 0; i < N_SONY_RFKILL; i++) {
1200 if (sony_rfkill_devices[i]) {
1201 rfkill_unregister(sony_rfkill_devices[i]);
1202 rfkill_destroy(sony_rfkill_devices[i]);
1203 }
1204 }
1205}
1206
1207static int sony_nc_rfkill_set(void *data, bool blocked)
1208{
1209 int result;
1210 int argument = sony_rfkill_address[(long) data] + 0x100;
1211
1212 if (!blocked)
1213 argument |= 0xff0000;
1214
1215 return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1216}
1217
1218static const struct rfkill_ops sony_rfkill_ops = {
1219 .set_block = sony_nc_rfkill_set,
1220};
1221
1222static int sony_nc_setup_rfkill(struct acpi_device *device,
1223 enum sony_nc_rfkill nc_type)
1224{
1225 int err = 0;
1226 struct rfkill *rfk;
1227 enum rfkill_type type;
1228 const char *name;
1229 int result;
1230 bool hwblock;
1231
1232 switch (nc_type) {
1233 case SONY_WIFI:
1234 type = RFKILL_TYPE_WLAN;
1235 name = "sony-wifi";
1236 break;
1237 case SONY_BLUETOOTH:
1238 type = RFKILL_TYPE_BLUETOOTH;
1239 name = "sony-bluetooth";
1240 break;
1241 case SONY_WWAN:
1242 type = RFKILL_TYPE_WWAN;
1243 name = "sony-wwan";
1244 break;
1245 case SONY_WIMAX:
1246 type = RFKILL_TYPE_WIMAX;
1247 name = "sony-wimax";
1248 break;
1249 default:
1250 return -EINVAL;
1251 }
1252
1253 rfk = rfkill_alloc(name, &device->dev, type,
1254 &sony_rfkill_ops, (void *)nc_type);
1255 if (!rfk)
1256 return -ENOMEM;
1257
1258 sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1259 hwblock = !(result & 0x1);
1260 rfkill_set_hw_state(rfk, hwblock);
1261
1262 err = rfkill_register(rfk);
1263 if (err) {
1264 rfkill_destroy(rfk);
1265 return err;
1266 }
1267 sony_rfkill_devices[nc_type] = rfk;
1268 return err;
1269}
1270
1271static void sony_nc_rfkill_update(void)
1272{
1273 enum sony_nc_rfkill i;
1274 int result;
1275 bool hwblock;
1276
1277 sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1278 hwblock = !(result & 0x1);
1279
1280 for (i = 0; i < N_SONY_RFKILL; i++) {
1281 int argument = sony_rfkill_address[i];
1282
1283 if (!sony_rfkill_devices[i])
1284 continue;
1285
1286 if (hwblock) {
1287 if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) {
1288
1289 }
1290 continue;
1291 }
1292
1293 sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1294 rfkill_set_states(sony_rfkill_devices[i],
1295 !(result & 0xf), false);
1296 }
1297}
1298
1299static void sony_nc_rfkill_setup(struct acpi_device *device)
1300{
1301 int offset;
1302 u8 dev_code, i;
1303 acpi_status status;
1304 struct acpi_object_list params;
1305 union acpi_object in_obj;
1306 union acpi_object *device_enum;
1307 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1308
1309 offset = sony_find_snc_handle(0x124);
1310 if (offset == -1) {
1311 offset = sony_find_snc_handle(0x135);
1312 if (offset == -1)
1313 return;
1314 else
1315 sony_rfkill_handle = 0x135;
1316 } else
1317 sony_rfkill_handle = 0x124;
1318 dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle);
1319
1320
1321
1322
1323 params.count = 1;
1324 params.pointer = &in_obj;
1325 in_obj.type = ACPI_TYPE_INTEGER;
1326 in_obj.integer.value = offset;
1327 status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms,
1328 &buffer);
1329 if (ACPI_FAILURE(status)) {
1330 dprintk("Radio device enumeration failed\n");
1331 return;
1332 }
1333
1334 device_enum = (union acpi_object *) buffer.pointer;
1335 if (!device_enum) {
1336 pr_err("No SN06 return object\n");
1337 goto out_no_enum;
1338 }
1339 if (device_enum->type != ACPI_TYPE_BUFFER) {
1340 pr_err("Invalid SN06 return object 0x%.2x\n",
1341 device_enum->type);
1342 goto out_no_enum;
1343 }
1344
1345
1346
1347
1348 for (i = 0; i < device_enum->buffer.length; i++) {
1349
1350 dev_code = *(device_enum->buffer.pointer + i);
1351 if (dev_code == 0xff)
1352 break;
1353
1354 dprintk("Radio devices, looking at 0x%.2x\n", dev_code);
1355
1356 if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI])
1357 sony_nc_setup_rfkill(device, SONY_WIFI);
1358
1359 if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
1360 sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
1361
1362 if ((0xf0 & dev_code) == 0x20 &&
1363 !sony_rfkill_devices[SONY_WWAN])
1364 sony_nc_setup_rfkill(device, SONY_WWAN);
1365
1366 if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
1367 sony_nc_setup_rfkill(device, SONY_WIMAX);
1368 }
1369
1370out_no_enum:
1371 kfree(buffer.pointer);
1372 return;
1373}
1374
1375
1376#define KBDBL_HANDLER 0x137
1377#define KBDBL_PRESENT 0xB00
1378#define SET_MODE 0xC00
1379#define SET_STATE 0xD00
1380#define SET_TIMEOUT 0xE00
1381
1382struct kbd_backlight {
1383 int mode;
1384 int timeout;
1385 struct device_attribute mode_attr;
1386 struct device_attribute timeout_attr;
1387};
1388
1389static struct kbd_backlight *kbdbl_handle;
1390
1391static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1392{
1393 int result;
1394
1395 if (value > 1)
1396 return -EINVAL;
1397
1398 if (sony_call_snc_handle(KBDBL_HANDLER,
1399 (value << 0x10) | SET_MODE, &result))
1400 return -EIO;
1401
1402
1403 sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE,
1404 &result);
1405
1406 kbdbl_handle->mode = value;
1407
1408 return 0;
1409}
1410
1411static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
1412 struct device_attribute *attr,
1413 const char *buffer, size_t count)
1414{
1415 int ret = 0;
1416 unsigned long value;
1417
1418 if (count > 31)
1419 return -EINVAL;
1420
1421 if (strict_strtoul(buffer, 10, &value))
1422 return -EINVAL;
1423
1424 ret = __sony_nc_kbd_backlight_mode_set(value);
1425 if (ret < 0)
1426 return ret;
1427
1428 return count;
1429}
1430
1431static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
1432 struct device_attribute *attr, char *buffer)
1433{
1434 ssize_t count = 0;
1435 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode);
1436 return count;
1437}
1438
1439static int __sony_nc_kbd_backlight_timeout_set(u8 value)
1440{
1441 int result;
1442
1443 if (value > 3)
1444 return -EINVAL;
1445
1446 if (sony_call_snc_handle(KBDBL_HANDLER,
1447 (value << 0x10) | SET_TIMEOUT, &result))
1448 return -EIO;
1449
1450 kbdbl_handle->timeout = value;
1451
1452 return 0;
1453}
1454
1455static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
1456 struct device_attribute *attr,
1457 const char *buffer, size_t count)
1458{
1459 int ret = 0;
1460 unsigned long value;
1461
1462 if (count > 31)
1463 return -EINVAL;
1464
1465 if (strict_strtoul(buffer, 10, &value))
1466 return -EINVAL;
1467
1468 ret = __sony_nc_kbd_backlight_timeout_set(value);
1469 if (ret < 0)
1470 return ret;
1471
1472 return count;
1473}
1474
1475static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
1476 struct device_attribute *attr, char *buffer)
1477{
1478 ssize_t count = 0;
1479 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout);
1480 return count;
1481}
1482
1483static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
1484{
1485 int result;
1486
1487 if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result))
1488 return 0;
1489 if (!(result & 0x02))
1490 return 0;
1491
1492 kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
1493 if (!kbdbl_handle)
1494 return -ENOMEM;
1495
1496 sysfs_attr_init(&kbdbl_handle->mode_attr.attr);
1497 kbdbl_handle->mode_attr.attr.name = "kbd_backlight";
1498 kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
1499 kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show;
1500 kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store;
1501
1502 sysfs_attr_init(&kbdbl_handle->timeout_attr.attr);
1503 kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout";
1504 kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
1505 kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
1506 kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
1507
1508 if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr))
1509 goto outkzalloc;
1510
1511 if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr))
1512 goto outmode;
1513
1514 __sony_nc_kbd_backlight_mode_set(kbd_backlight);
1515 __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
1516
1517 return 0;
1518
1519outmode:
1520 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
1521outkzalloc:
1522 kfree(kbdbl_handle);
1523 kbdbl_handle = NULL;
1524 return -1;
1525}
1526
1527static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
1528{
1529 if (kbdbl_handle) {
1530 int result;
1531
1532 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
1533 device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
1534
1535
1536 sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result);
1537 sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result);
1538
1539 kfree(kbdbl_handle);
1540 }
1541 return 0;
1542}
1543
1544static void sony_nc_kbd_backlight_resume(void)
1545{
1546 int ignore = 0;
1547
1548 if (!kbdbl_handle)
1549 return;
1550
1551 if (kbdbl_handle->mode == 0)
1552 sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore);
1553
1554 if (kbdbl_handle->timeout != 0)
1555 sony_call_snc_handle(KBDBL_HANDLER,
1556 (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT,
1557 &ignore);
1558}
1559
1560static void sony_nc_backlight_ng_read_limits(int handle,
1561 struct sony_backlight_props *props)
1562{
1563 int offset;
1564 acpi_status status;
1565 u8 brlvl, i;
1566 u8 min = 0xff, max = 0x00;
1567 struct acpi_object_list params;
1568 union acpi_object in_obj;
1569 union acpi_object *lvl_enum;
1570 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1571
1572 props->handle = handle;
1573 props->offset = 0;
1574 props->maxlvl = 0xff;
1575
1576 offset = sony_find_snc_handle(handle);
1577 if (offset < 0)
1578 return;
1579
1580
1581
1582
1583 params.count = 1;
1584 params.pointer = &in_obj;
1585 in_obj.type = ACPI_TYPE_INTEGER;
1586 in_obj.integer.value = offset;
1587 status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms,
1588 &buffer);
1589 if (ACPI_FAILURE(status))
1590 return;
1591
1592 lvl_enum = (union acpi_object *) buffer.pointer;
1593 if (!lvl_enum) {
1594 pr_err("No SN06 return object.");
1595 return;
1596 }
1597 if (lvl_enum->type != ACPI_TYPE_BUFFER) {
1598 pr_err("Invalid SN06 return object 0x%.2x\n",
1599 lvl_enum->type);
1600 goto out_invalid;
1601 }
1602
1603
1604
1605
1606 for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) {
1607
1608 brlvl = *(lvl_enum->buffer.pointer + i);
1609 dprintk("Brightness level: %d\n", brlvl);
1610
1611 if (!brlvl)
1612 break;
1613
1614 if (brlvl > max)
1615 max = brlvl;
1616 if (brlvl < min)
1617 min = brlvl;
1618 }
1619 props->offset = min;
1620 props->maxlvl = max;
1621 dprintk("Brightness levels: min=%d max=%d\n", props->offset,
1622 props->maxlvl);
1623
1624out_invalid:
1625 kfree(buffer.pointer);
1626 return;
1627}
1628
1629static void sony_nc_backlight_setup(void)
1630{
1631 acpi_handle unused;
1632 int max_brightness = 0;
1633 const struct backlight_ops *ops = NULL;
1634 struct backlight_properties props;
1635
1636 if (sony_find_snc_handle(0x12f) != -1) {
1637 ops = &sony_backlight_ng_ops;
1638 sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
1639 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
1640
1641 } else if (sony_find_snc_handle(0x137) != -1) {
1642 ops = &sony_backlight_ng_ops;
1643 sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
1644 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
1645
1646 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
1647 &unused))) {
1648 ops = &sony_backlight_ops;
1649 max_brightness = SONY_MAX_BRIGHTNESS - 1;
1650
1651 } else
1652 return;
1653
1654 memset(&props, 0, sizeof(struct backlight_properties));
1655 props.type = BACKLIGHT_PLATFORM;
1656 props.max_brightness = max_brightness;
1657 sony_bl_props.dev = backlight_device_register("sony", NULL,
1658 &sony_bl_props,
1659 ops, &props);
1660
1661 if (IS_ERR(sony_bl_props.dev)) {
1662 pr_warn("unable to register backlight device\n");
1663 sony_bl_props.dev = NULL;
1664 } else
1665 sony_bl_props.dev->props.brightness =
1666 ops->get_brightness(sony_bl_props.dev);
1667}
1668
1669static void sony_nc_backlight_cleanup(void)
1670{
1671 if (sony_bl_props.dev)
1672 backlight_device_unregister(sony_bl_props.dev);
1673}
1674
1675static int sony_nc_add(struct acpi_device *device)
1676{
1677 acpi_status status;
1678 int result = 0;
1679 acpi_handle handle;
1680 struct sony_nc_value *item;
1681
1682 pr_info("%s v%s\n", SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
1683
1684 sony_nc_acpi_device = device;
1685 strcpy(acpi_device_class(device), "sony/hotkey");
1686
1687 sony_nc_acpi_handle = device->handle;
1688
1689
1690 result = acpi_bus_get_status(device);
1691
1692 if (!result && !device->status.present) {
1693 dprintk("Device not present\n");
1694 result = -ENODEV;
1695 goto outwalk;
1696 }
1697
1698 result = sony_pf_add();
1699 if (result)
1700 goto outpresent;
1701
1702 if (debug) {
1703 status = acpi_walk_namespace(ACPI_TYPE_METHOD,
1704 sony_nc_acpi_handle, 1, sony_walk_callback,
1705 NULL, NULL, NULL);
1706 if (ACPI_FAILURE(status)) {
1707 pr_warn("unable to walk acpi resources\n");
1708 result = -ENODEV;
1709 goto outpresent;
1710 }
1711 }
1712
1713 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
1714 &handle))) {
1715 if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL))
1716 dprintk("ECON Method failed\n");
1717 }
1718
1719 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
1720 &handle))) {
1721 dprintk("Doing SNC setup\n");
1722 result = sony_nc_handles_setup(sony_pf_device);
1723 if (result)
1724 goto outpresent;
1725 result = sony_nc_kbd_backlight_setup(sony_pf_device);
1726 if (result)
1727 goto outsnc;
1728 sony_nc_function_setup(device);
1729 sony_nc_rfkill_setup(device);
1730 }
1731
1732
1733 result = sony_laptop_setup_input(device);
1734 if (result) {
1735 pr_err("Unable to create input devices\n");
1736 goto outkbdbacklight;
1737 }
1738
1739 if (acpi_video_backlight_support()) {
1740 pr_info("brightness ignored, must be controlled by ACPI video driver\n");
1741 } else {
1742 sony_nc_backlight_setup();
1743 }
1744
1745
1746 for (item = sony_nc_values; item->name; ++item) {
1747
1748 if (!debug && item->debug)
1749 continue;
1750
1751
1752 for (; item->acpiget && *item->acpiget; ++item->acpiget) {
1753 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
1754 *item->acpiget,
1755 &handle))) {
1756 dprintk("Found %s getter: %s\n",
1757 item->name, *item->acpiget);
1758 item->devattr.attr.mode |= S_IRUGO;
1759 break;
1760 }
1761 }
1762
1763
1764 for (; item->acpiset && *item->acpiset; ++item->acpiset) {
1765 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
1766 *item->acpiset,
1767 &handle))) {
1768 dprintk("Found %s setter: %s\n",
1769 item->name, *item->acpiset);
1770 item->devattr.attr.mode |= S_IWUSR;
1771 break;
1772 }
1773 }
1774
1775 if (item->devattr.attr.mode != 0) {
1776 result =
1777 device_create_file(&sony_pf_device->dev,
1778 &item->devattr);
1779 if (result)
1780 goto out_sysfs;
1781 }
1782 }
1783
1784 return 0;
1785
1786 out_sysfs:
1787 for (item = sony_nc_values; item->name; ++item) {
1788 device_remove_file(&sony_pf_device->dev, &item->devattr);
1789 }
1790 sony_nc_backlight_cleanup();
1791
1792 sony_laptop_remove_input();
1793
1794 outkbdbacklight:
1795 sony_nc_kbd_backlight_cleanup(sony_pf_device);
1796
1797 outsnc:
1798 sony_nc_handles_cleanup(sony_pf_device);
1799
1800 outpresent:
1801 sony_pf_remove();
1802
1803 outwalk:
1804 sony_nc_rfkill_cleanup();
1805 return result;
1806}
1807
1808static int sony_nc_remove(struct acpi_device *device, int type)
1809{
1810 struct sony_nc_value *item;
1811
1812 sony_nc_backlight_cleanup();
1813
1814 sony_nc_acpi_device = NULL;
1815
1816 for (item = sony_nc_values; item->name; ++item) {
1817 device_remove_file(&sony_pf_device->dev, &item->devattr);
1818 }
1819
1820 sony_nc_kbd_backlight_cleanup(sony_pf_device);
1821 sony_nc_handles_cleanup(sony_pf_device);
1822 sony_pf_remove();
1823 sony_laptop_remove_input();
1824 sony_nc_rfkill_cleanup();
1825 dprintk(SONY_NC_DRIVER_NAME " removed.\n");
1826
1827 return 0;
1828}
1829
1830static const struct acpi_device_id sony_device_ids[] = {
1831 {SONY_NC_HID, 0},
1832 {SONY_PIC_HID, 0},
1833 {"", 0},
1834};
1835MODULE_DEVICE_TABLE(acpi, sony_device_ids);
1836
1837static const struct acpi_device_id sony_nc_device_ids[] = {
1838 {SONY_NC_HID, 0},
1839 {"", 0},
1840};
1841
1842static struct acpi_driver sony_nc_driver = {
1843 .name = SONY_NC_DRIVER_NAME,
1844 .class = SONY_NC_CLASS,
1845 .ids = sony_nc_device_ids,
1846 .owner = THIS_MODULE,
1847 .ops = {
1848 .add = sony_nc_add,
1849 .remove = sony_nc_remove,
1850 .resume = sony_nc_resume,
1851 .notify = sony_nc_notify,
1852 },
1853};
1854
1855
1856
1857#define SONYPI_DEVICE_TYPE1 0x00000001
1858#define SONYPI_DEVICE_TYPE2 0x00000002
1859#define SONYPI_DEVICE_TYPE3 0x00000004
1860
1861#define SONYPI_TYPE1_OFFSET 0x04
1862#define SONYPI_TYPE2_OFFSET 0x12
1863#define SONYPI_TYPE3_OFFSET 0x12
1864
1865struct sony_pic_ioport {
1866 struct acpi_resource_io io1;
1867 struct acpi_resource_io io2;
1868 struct list_head list;
1869};
1870
1871struct sony_pic_irq {
1872 struct acpi_resource_irq irq;
1873 struct list_head list;
1874};
1875
1876struct sonypi_eventtypes {
1877 u8 data;
1878 unsigned long mask;
1879 struct sonypi_event *events;
1880};
1881
1882struct sony_pic_dev {
1883 struct acpi_device *acpi_dev;
1884 struct sony_pic_irq *cur_irq;
1885 struct sony_pic_ioport *cur_ioport;
1886 struct list_head interrupts;
1887 struct list_head ioports;
1888 struct mutex lock;
1889 struct sonypi_eventtypes *event_types;
1890 int (*handle_irq)(const u8, const u8);
1891 int model;
1892 u16 evport_offset;
1893 u8 camera_power;
1894 u8 bluetooth_power;
1895 u8 wwan_power;
1896};
1897
1898static struct sony_pic_dev spic_dev = {
1899 .interrupts = LIST_HEAD_INIT(spic_dev.interrupts),
1900 .ioports = LIST_HEAD_INIT(spic_dev.ioports),
1901};
1902
1903static int spic_drv_registered;
1904
1905
1906#define SONYPI_JOGGER_MASK 0x00000001
1907#define SONYPI_CAPTURE_MASK 0x00000002
1908#define SONYPI_FNKEY_MASK 0x00000004
1909#define SONYPI_BLUETOOTH_MASK 0x00000008
1910#define SONYPI_PKEY_MASK 0x00000010
1911#define SONYPI_BACK_MASK 0x00000020
1912#define SONYPI_HELP_MASK 0x00000040
1913#define SONYPI_LID_MASK 0x00000080
1914#define SONYPI_ZOOM_MASK 0x00000100
1915#define SONYPI_THUMBPHRASE_MASK 0x00000200
1916#define SONYPI_MEYE_MASK 0x00000400
1917#define SONYPI_MEMORYSTICK_MASK 0x00000800
1918#define SONYPI_BATTERY_MASK 0x00001000
1919#define SONYPI_WIRELESS_MASK 0x00002000
1920
1921struct sonypi_event {
1922 u8 data;
1923 u8 event;
1924};
1925
1926
1927static struct sonypi_event sonypi_releaseev[] = {
1928 { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
1929 { 0, 0 }
1930};
1931
1932
1933static struct sonypi_event sonypi_joggerev[] = {
1934 { 0x1f, SONYPI_EVENT_JOGDIAL_UP },
1935 { 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
1936 { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
1937 { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
1938 { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
1939 { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
1940 { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
1941 { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
1942 { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
1943 { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
1944 { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
1945 { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
1946 { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
1947 { 0, 0 }
1948};
1949
1950
1951static struct sonypi_event sonypi_captureev[] = {
1952 { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
1953 { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
1954 { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
1955 { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
1956 { 0, 0 }
1957};
1958
1959
1960static struct sonypi_event sonypi_fnkeyev[] = {
1961 { 0x10, SONYPI_EVENT_FNKEY_ESC },
1962 { 0x11, SONYPI_EVENT_FNKEY_F1 },
1963 { 0x12, SONYPI_EVENT_FNKEY_F2 },
1964 { 0x13, SONYPI_EVENT_FNKEY_F3 },
1965 { 0x14, SONYPI_EVENT_FNKEY_F4 },
1966 { 0x15, SONYPI_EVENT_FNKEY_F5 },
1967 { 0x16, SONYPI_EVENT_FNKEY_F6 },
1968 { 0x17, SONYPI_EVENT_FNKEY_F7 },
1969 { 0x18, SONYPI_EVENT_FNKEY_F8 },
1970 { 0x19, SONYPI_EVENT_FNKEY_F9 },
1971 { 0x1a, SONYPI_EVENT_FNKEY_F10 },
1972 { 0x1b, SONYPI_EVENT_FNKEY_F11 },
1973 { 0x1c, SONYPI_EVENT_FNKEY_F12 },
1974 { 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
1975 { 0x21, SONYPI_EVENT_FNKEY_1 },
1976 { 0x22, SONYPI_EVENT_FNKEY_2 },
1977 { 0x31, SONYPI_EVENT_FNKEY_D },
1978 { 0x32, SONYPI_EVENT_FNKEY_E },
1979 { 0x33, SONYPI_EVENT_FNKEY_F },
1980 { 0x34, SONYPI_EVENT_FNKEY_S },
1981 { 0x35, SONYPI_EVENT_FNKEY_B },
1982 { 0x36, SONYPI_EVENT_FNKEY_ONLY },
1983 { 0, 0 }
1984};
1985
1986
1987static struct sonypi_event sonypi_pkeyev[] = {
1988 { 0x01, SONYPI_EVENT_PKEY_P1 },
1989 { 0x02, SONYPI_EVENT_PKEY_P2 },
1990 { 0x04, SONYPI_EVENT_PKEY_P3 },
1991 { 0x20, SONYPI_EVENT_PKEY_P1 },
1992 { 0, 0 }
1993};
1994
1995
1996static struct sonypi_event sonypi_blueev[] = {
1997 { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
1998 { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
1999 { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
2000 { 0, 0 }
2001};
2002
2003
2004static struct sonypi_event sonypi_wlessev[] = {
2005 { 0x59, SONYPI_EVENT_IGNORE },
2006 { 0x5a, SONYPI_EVENT_IGNORE },
2007 { 0, 0 }
2008};
2009
2010
2011static struct sonypi_event sonypi_backev[] = {
2012 { 0x20, SONYPI_EVENT_BACK_PRESSED },
2013 { 0, 0 }
2014};
2015
2016
2017static struct sonypi_event sonypi_helpev[] = {
2018 { 0x3b, SONYPI_EVENT_HELP_PRESSED },
2019 { 0, 0 }
2020};
2021
2022
2023
2024static struct sonypi_event sonypi_lidev[] = {
2025 { 0x51, SONYPI_EVENT_LID_CLOSED },
2026 { 0x50, SONYPI_EVENT_LID_OPENED },
2027 { 0, 0 }
2028};
2029
2030
2031static struct sonypi_event sonypi_zoomev[] = {
2032 { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
2033 { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
2034 { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
2035 { 0x04, SONYPI_EVENT_ZOOM_PRESSED },
2036 { 0, 0 }
2037};
2038
2039
2040static struct sonypi_event sonypi_thumbphraseev[] = {
2041 { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
2042 { 0, 0 }
2043};
2044
2045
2046static struct sonypi_event sonypi_meyeev[] = {
2047 { 0x00, SONYPI_EVENT_MEYE_FACE },
2048 { 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
2049 { 0, 0 }
2050};
2051
2052
2053static struct sonypi_event sonypi_memorystickev[] = {
2054 { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
2055 { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
2056 { 0, 0 }
2057};
2058
2059
2060static struct sonypi_event sonypi_batteryev[] = {
2061 { 0x20, SONYPI_EVENT_BATTERY_INSERT },
2062 { 0x30, SONYPI_EVENT_BATTERY_REMOVE },
2063 { 0, 0 }
2064};
2065
2066
2067static struct sonypi_event sonypi_volumeev[] = {
2068 { 0x01, SONYPI_EVENT_VOLUME_INC_PRESSED },
2069 { 0x02, SONYPI_EVENT_VOLUME_DEC_PRESSED },
2070 { 0, 0 }
2071};
2072
2073
2074static struct sonypi_event sonypi_brightnessev[] = {
2075 { 0x80, SONYPI_EVENT_BRIGHTNESS_PRESSED },
2076 { 0, 0 }
2077};
2078
2079static struct sonypi_eventtypes type1_events[] = {
2080 { 0, 0xffffffff, sonypi_releaseev },
2081 { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
2082 { 0x30, SONYPI_LID_MASK, sonypi_lidev },
2083 { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
2084 { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
2085 { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
2086 { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
2087 { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
2088 { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
2089 { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
2090 { 0 },
2091};
2092static struct sonypi_eventtypes type2_events[] = {
2093 { 0, 0xffffffff, sonypi_releaseev },
2094 { 0x38, SONYPI_LID_MASK, sonypi_lidev },
2095 { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
2096 { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
2097 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
2098 { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
2099 { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
2100 { 0x11, SONYPI_BACK_MASK, sonypi_backev },
2101 { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
2102 { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
2103 { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
2104 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
2105 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
2106 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
2107 { 0 },
2108};
2109static struct sonypi_eventtypes type3_events[] = {
2110 { 0, 0xffffffff, sonypi_releaseev },
2111 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
2112 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
2113 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
2114 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
2115 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
2116 { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
2117 { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
2118 { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
2119 { 0x05, SONYPI_PKEY_MASK, sonypi_volumeev },
2120 { 0x05, SONYPI_PKEY_MASK, sonypi_brightnessev },
2121 { 0 },
2122};
2123
2124
2125#define ITERATIONS_LONG 10000
2126#define ITERATIONS_SHORT 10
2127#define wait_on_command(command, iterations) { \
2128 unsigned int n = iterations; \
2129 while (--n && (command)) \
2130 udelay(1); \
2131 if (!n) \
2132 dprintk("command failed at %s : %s (line %d)\n", \
2133 __FILE__, __func__, __LINE__); \
2134}
2135
2136static u8 sony_pic_call1(u8 dev)
2137{
2138 u8 v1, v2;
2139
2140 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
2141 ITERATIONS_LONG);
2142 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
2143 v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
2144 v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
2145 dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
2146 return v2;
2147}
2148
2149static u8 sony_pic_call2(u8 dev, u8 fn)
2150{
2151 u8 v1;
2152
2153 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
2154 ITERATIONS_LONG);
2155 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
2156 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
2157 ITERATIONS_LONG);
2158 outb(fn, spic_dev.cur_ioport->io1.minimum);
2159 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
2160 dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
2161 return v1;
2162}
2163
2164static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
2165{
2166 u8 v1;
2167
2168 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
2169 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
2170 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
2171 outb(fn, spic_dev.cur_ioport->io1.minimum);
2172 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
2173 outb(v, spic_dev.cur_ioport->io1.minimum);
2174 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
2175 dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
2176 dev, fn, v, v1);
2177 return v1;
2178}
2179
2180
2181
2182
2183static int type3_handle_irq(const u8 data_mask, const u8 ev)
2184{
2185
2186
2187
2188
2189
2190
2191
2192 if (data_mask == 0x31) {
2193 if (ev == 0x5c || ev == 0x5f)
2194 sony_pic_call1(0xA0);
2195 else if (ev == 0x61)
2196 sony_pic_call1(0xB3);
2197 return 0;
2198 }
2199 return 1;
2200}
2201
2202static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
2203{
2204 struct pci_dev *pcidev;
2205
2206 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
2207 PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
2208 if (pcidev) {
2209 dev->model = SONYPI_DEVICE_TYPE1;
2210 dev->evport_offset = SONYPI_TYPE1_OFFSET;
2211 dev->event_types = type1_events;
2212 goto out;
2213 }
2214
2215 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
2216 PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
2217 if (pcidev) {
2218 dev->model = SONYPI_DEVICE_TYPE2;
2219 dev->evport_offset = SONYPI_TYPE2_OFFSET;
2220 dev->event_types = type2_events;
2221 goto out;
2222 }
2223
2224 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
2225 PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
2226 if (pcidev) {
2227 dev->model = SONYPI_DEVICE_TYPE3;
2228 dev->handle_irq = type3_handle_irq;
2229 dev->evport_offset = SONYPI_TYPE3_OFFSET;
2230 dev->event_types = type3_events;
2231 goto out;
2232 }
2233
2234 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
2235 PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
2236 if (pcidev) {
2237 dev->model = SONYPI_DEVICE_TYPE3;
2238 dev->handle_irq = type3_handle_irq;
2239 dev->evport_offset = SONYPI_TYPE3_OFFSET;
2240 dev->event_types = type3_events;
2241 goto out;
2242 }
2243
2244 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
2245 PCI_DEVICE_ID_INTEL_ICH9_1, NULL);
2246 if (pcidev) {
2247 dev->model = SONYPI_DEVICE_TYPE3;
2248 dev->handle_irq = type3_handle_irq;
2249 dev->evport_offset = SONYPI_TYPE3_OFFSET;
2250 dev->event_types = type3_events;
2251 goto out;
2252 }
2253
2254
2255 dev->model = SONYPI_DEVICE_TYPE2;
2256 dev->evport_offset = SONYPI_TYPE2_OFFSET;
2257 dev->event_types = type2_events;
2258
2259out:
2260 if (pcidev)
2261 pci_dev_put(pcidev);
2262
2263 pr_info("detected Type%d model\n",
2264 dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
2265 dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
2266}
2267
2268
2269#define SONYPI_CAMERA_PICTURE 5
2270#define SONYPI_CAMERA_CONTROL 0x10
2271
2272#define SONYPI_CAMERA_BRIGHTNESS 0
2273#define SONYPI_CAMERA_CONTRAST 1
2274#define SONYPI_CAMERA_HUE 2
2275#define SONYPI_CAMERA_COLOR 3
2276#define SONYPI_CAMERA_SHARPNESS 4
2277
2278#define SONYPI_CAMERA_EXPOSURE_MASK 0xC
2279#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3
2280#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30
2281#define SONYPI_CAMERA_MUTE_MASK 0x40
2282
2283
2284#define SONYPI_CAMERA_AGC 6
2285#define SONYPI_CAMERA_AGC_MASK 0x30
2286#define SONYPI_CAMERA_SHUTTER_MASK 0x7
2287
2288#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7
2289#define SONYPI_CAMERA_CONTROL 0x10
2290
2291#define SONYPI_CAMERA_STATUS 7
2292#define SONYPI_CAMERA_STATUS_READY 0x2
2293#define SONYPI_CAMERA_STATUS_POSITION 0x4
2294
2295#define SONYPI_DIRECTION_BACKWARDS 0x4
2296
2297#define SONYPI_CAMERA_REVISION 8
2298#define SONYPI_CAMERA_ROMVERSION 9
2299
2300static int __sony_pic_camera_ready(void)
2301{
2302 u8 v;
2303
2304 v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
2305 return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
2306}
2307
2308static int __sony_pic_camera_off(void)
2309{
2310 if (!camera) {
2311 pr_warn("camera control not enabled\n");
2312 return -ENODEV;
2313 }
2314
2315 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
2316 SONYPI_CAMERA_MUTE_MASK),
2317 ITERATIONS_SHORT);
2318
2319 if (spic_dev.camera_power) {
2320 sony_pic_call2(0x91, 0);
2321 spic_dev.camera_power = 0;
2322 }
2323 return 0;
2324}
2325
2326static int __sony_pic_camera_on(void)
2327{
2328 int i, j, x;
2329
2330 if (!camera) {
2331 pr_warn("camera control not enabled\n");
2332 return -ENODEV;
2333 }
2334
2335 if (spic_dev.camera_power)
2336 return 0;
2337
2338 for (j = 5; j > 0; j--) {
2339
2340 for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
2341 msleep(10);
2342 sony_pic_call1(0x93);
2343
2344 for (i = 400; i > 0; i--) {
2345 if (__sony_pic_camera_ready())
2346 break;
2347 msleep(10);
2348 }
2349 if (i)
2350 break;
2351 }
2352
2353 if (j == 0) {
2354 pr_warn("failed to power on camera\n");
2355 return -ENODEV;
2356 }
2357
2358 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
2359 0x5a),
2360 ITERATIONS_SHORT);
2361
2362 spic_dev.camera_power = 1;
2363 return 0;
2364}
2365
2366
2367int sony_pic_camera_command(int command, u8 value)
2368{
2369 if (!camera)
2370 return -EIO;
2371
2372 mutex_lock(&spic_dev.lock);
2373
2374 switch (command) {
2375 case SONY_PIC_COMMAND_SETCAMERA:
2376 if (value)
2377 __sony_pic_camera_on();
2378 else
2379 __sony_pic_camera_off();
2380 break;
2381 case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
2382 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
2383 ITERATIONS_SHORT);
2384 break;
2385 case SONY_PIC_COMMAND_SETCAMERACONTRAST:
2386 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
2387 ITERATIONS_SHORT);
2388 break;
2389 case SONY_PIC_COMMAND_SETCAMERAHUE:
2390 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
2391 ITERATIONS_SHORT);
2392 break;
2393 case SONY_PIC_COMMAND_SETCAMERACOLOR:
2394 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
2395 ITERATIONS_SHORT);
2396 break;
2397 case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
2398 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
2399 ITERATIONS_SHORT);
2400 break;
2401 case SONY_PIC_COMMAND_SETCAMERAPICTURE:
2402 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
2403 ITERATIONS_SHORT);
2404 break;
2405 case SONY_PIC_COMMAND_SETCAMERAAGC:
2406 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
2407 ITERATIONS_SHORT);
2408 break;
2409 default:
2410 pr_err("sony_pic_camera_command invalid: %d\n", command);
2411 break;
2412 }
2413 mutex_unlock(&spic_dev.lock);
2414 return 0;
2415}
2416EXPORT_SYMBOL(sony_pic_camera_command);
2417
2418
2419static void __sony_pic_set_wwanpower(u8 state)
2420{
2421 state = !!state;
2422 if (spic_dev.wwan_power == state)
2423 return;
2424 sony_pic_call2(0xB0, state);
2425 sony_pic_call1(0x82);
2426 spic_dev.wwan_power = state;
2427}
2428
2429static ssize_t sony_pic_wwanpower_store(struct device *dev,
2430 struct device_attribute *attr,
2431 const char *buffer, size_t count)
2432{
2433 unsigned long value;
2434 if (count > 31)
2435 return -EINVAL;
2436
2437 value = simple_strtoul(buffer, NULL, 10);
2438 mutex_lock(&spic_dev.lock);
2439 __sony_pic_set_wwanpower(value);
2440 mutex_unlock(&spic_dev.lock);
2441
2442 return count;
2443}
2444
2445static ssize_t sony_pic_wwanpower_show(struct device *dev,
2446 struct device_attribute *attr, char *buffer)
2447{
2448 ssize_t count;
2449 mutex_lock(&spic_dev.lock);
2450 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
2451 mutex_unlock(&spic_dev.lock);
2452 return count;
2453}
2454
2455
2456static void __sony_pic_set_bluetoothpower(u8 state)
2457{
2458 state = !!state;
2459 if (spic_dev.bluetooth_power == state)
2460 return;
2461 sony_pic_call2(0x96, state);
2462 sony_pic_call1(0x82);
2463 spic_dev.bluetooth_power = state;
2464}
2465
2466static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
2467 struct device_attribute *attr,
2468 const char *buffer, size_t count)
2469{
2470 unsigned long value;
2471 if (count > 31)
2472 return -EINVAL;
2473
2474 value = simple_strtoul(buffer, NULL, 10);
2475 mutex_lock(&spic_dev.lock);
2476 __sony_pic_set_bluetoothpower(value);
2477 mutex_unlock(&spic_dev.lock);
2478
2479 return count;
2480}
2481
2482static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
2483 struct device_attribute *attr, char *buffer)
2484{
2485 ssize_t count = 0;
2486 mutex_lock(&spic_dev.lock);
2487 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
2488 mutex_unlock(&spic_dev.lock);
2489 return count;
2490}
2491
2492
2493
2494#define SONY_PIC_FAN0_STATUS 0x93
2495static int sony_pic_set_fanspeed(unsigned long value)
2496{
2497 return ec_write(SONY_PIC_FAN0_STATUS, value);
2498}
2499
2500static int sony_pic_get_fanspeed(u8 *value)
2501{
2502 return ec_read(SONY_PIC_FAN0_STATUS, value);
2503}
2504
2505static ssize_t sony_pic_fanspeed_store(struct device *dev,
2506 struct device_attribute *attr,
2507 const char *buffer, size_t count)
2508{
2509 unsigned long value;
2510 if (count > 31)
2511 return -EINVAL;
2512
2513 value = simple_strtoul(buffer, NULL, 10);
2514 if (sony_pic_set_fanspeed(value))
2515 return -EIO;
2516
2517 return count;
2518}
2519
2520static ssize_t sony_pic_fanspeed_show(struct device *dev,
2521 struct device_attribute *attr, char *buffer)
2522{
2523 u8 value = 0;
2524 if (sony_pic_get_fanspeed(&value))
2525 return -EIO;
2526
2527 return snprintf(buffer, PAGE_SIZE, "%d\n", value);
2528}
2529
2530#define SPIC_ATTR(_name, _mode) \
2531struct device_attribute spic_attr_##_name = __ATTR(_name, \
2532 _mode, sony_pic_## _name ##_show, \
2533 sony_pic_## _name ##_store)
2534
2535static SPIC_ATTR(bluetoothpower, 0644);
2536static SPIC_ATTR(wwanpower, 0644);
2537static SPIC_ATTR(fanspeed, 0644);
2538
2539static struct attribute *spic_attributes[] = {
2540 &spic_attr_bluetoothpower.attr,
2541 &spic_attr_wwanpower.attr,
2542 &spic_attr_fanspeed.attr,
2543 NULL
2544};
2545
2546static struct attribute_group spic_attribute_group = {
2547 .attrs = spic_attributes
2548};
2549
2550
2551#ifdef CONFIG_SONYPI_COMPAT
2552
2553
2554#define SONYPI_BAT_FLAGS 0x81
2555#define SONYPI_LCD_LIGHT 0x96
2556#define SONYPI_BAT1_PCTRM 0xa0
2557#define SONYPI_BAT1_LEFT 0xa2
2558#define SONYPI_BAT1_MAXRT 0xa4
2559#define SONYPI_BAT2_PCTRM 0xa8
2560#define SONYPI_BAT2_LEFT 0xaa
2561#define SONYPI_BAT2_MAXRT 0xac
2562#define SONYPI_BAT1_MAXTK 0xb0
2563#define SONYPI_BAT1_FULL 0xb2
2564#define SONYPI_BAT2_MAXTK 0xb8
2565#define SONYPI_BAT2_FULL 0xba
2566#define SONYPI_TEMP_STATUS 0xC1
2567
2568struct sonypi_compat_s {
2569 struct fasync_struct *fifo_async;
2570 struct kfifo fifo;
2571 spinlock_t fifo_lock;
2572 wait_queue_head_t fifo_proc_list;
2573 atomic_t open_count;
2574};
2575static struct sonypi_compat_s sonypi_compat = {
2576 .open_count = ATOMIC_INIT(0),
2577};
2578
2579static int sonypi_misc_fasync(int fd, struct file *filp, int on)
2580{
2581 return fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
2582}
2583
2584static int sonypi_misc_release(struct inode *inode, struct file *file)
2585{
2586 atomic_dec(&sonypi_compat.open_count);
2587 return 0;
2588}
2589
2590static int sonypi_misc_open(struct inode *inode, struct file *file)
2591{
2592
2593 unsigned long flags;
2594
2595 spin_lock_irqsave(&sonypi_compat.fifo_lock, flags);
2596
2597 if (atomic_inc_return(&sonypi_compat.open_count) == 1)
2598 kfifo_reset(&sonypi_compat.fifo);
2599
2600 spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags);
2601
2602 return 0;
2603}
2604
2605static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
2606 size_t count, loff_t *pos)
2607{
2608 ssize_t ret;
2609 unsigned char c;
2610
2611 if ((kfifo_len(&sonypi_compat.fifo) == 0) &&
2612 (file->f_flags & O_NONBLOCK))
2613 return -EAGAIN;
2614
2615 ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
2616 kfifo_len(&sonypi_compat.fifo) != 0);
2617 if (ret)
2618 return ret;
2619
2620 while (ret < count &&
2621 (kfifo_out_locked(&sonypi_compat.fifo, &c, sizeof(c),
2622 &sonypi_compat.fifo_lock) == sizeof(c))) {
2623 if (put_user(c, buf++))
2624 return -EFAULT;
2625 ret++;
2626 }
2627
2628 if (ret > 0) {
2629 struct inode *inode = file->f_path.dentry->d_inode;
2630 inode->i_atime = current_fs_time(inode->i_sb);
2631 }
2632
2633 return ret;
2634}
2635
2636static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
2637{
2638 poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
2639 if (kfifo_len(&sonypi_compat.fifo))
2640 return POLLIN | POLLRDNORM;
2641 return 0;
2642}
2643
2644static int ec_read16(u8 addr, u16 *value)
2645{
2646 u8 val_lb, val_hb;
2647 if (ec_read(addr, &val_lb))
2648 return -1;
2649 if (ec_read(addr + 1, &val_hb))
2650 return -1;
2651 *value = val_lb | (val_hb << 8);
2652 return 0;
2653}
2654
2655static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
2656 unsigned long arg)
2657{
2658 int ret = 0;
2659 void __user *argp = (void __user *)arg;
2660 u8 val8;
2661 u16 val16;
2662 int value;
2663
2664 mutex_lock(&spic_dev.lock);
2665 switch (cmd) {
2666 case SONYPI_IOCGBRT:
2667 if (sony_bl_props.dev == NULL) {
2668 ret = -EIO;
2669 break;
2670 }
2671 if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) {
2672 ret = -EIO;
2673 break;
2674 }
2675 val8 = ((value & 0xff) - 1) << 5;
2676 if (copy_to_user(argp, &val8, sizeof(val8)))
2677 ret = -EFAULT;
2678 break;
2679 case SONYPI_IOCSBRT:
2680 if (sony_bl_props.dev == NULL) {
2681 ret = -EIO;
2682 break;
2683 }
2684 if (copy_from_user(&val8, argp, sizeof(val8))) {
2685 ret = -EFAULT;
2686 break;
2687 }
2688 if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
2689 (val8 >> 5) + 1, NULL)) {
2690 ret = -EIO;
2691 break;
2692 }
2693
2694 sony_bl_props.dev->props.brightness =
2695 sony_backlight_get_brightness(sony_bl_props.dev);
2696 break;
2697 case SONYPI_IOCGBAT1CAP:
2698 if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
2699 ret = -EIO;
2700 break;
2701 }
2702 if (copy_to_user(argp, &val16, sizeof(val16)))
2703 ret = -EFAULT;
2704 break;
2705 case SONYPI_IOCGBAT1REM:
2706 if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
2707 ret = -EIO;
2708 break;
2709 }
2710 if (copy_to_user(argp, &val16, sizeof(val16)))
2711 ret = -EFAULT;
2712 break;
2713 case SONYPI_IOCGBAT2CAP:
2714 if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
2715 ret = -EIO;
2716 break;
2717 }
2718 if (copy_to_user(argp, &val16, sizeof(val16)))
2719 ret = -EFAULT;
2720 break;
2721 case SONYPI_IOCGBAT2REM:
2722 if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
2723 ret = -EIO;
2724 break;
2725 }
2726 if (copy_to_user(argp, &val16, sizeof(val16)))
2727 ret = -EFAULT;
2728 break;
2729 case SONYPI_IOCGBATFLAGS:
2730 if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
2731 ret = -EIO;
2732 break;
2733 }
2734 val8 &= 0x07;
2735 if (copy_to_user(argp, &val8, sizeof(val8)))
2736 ret = -EFAULT;
2737 break;
2738 case SONYPI_IOCGBLUE:
2739 val8 = spic_dev.bluetooth_power;
2740 if (copy_to_user(argp, &val8, sizeof(val8)))
2741 ret = -EFAULT;
2742 break;
2743 case SONYPI_IOCSBLUE:
2744 if (copy_from_user(&val8, argp, sizeof(val8))) {
2745 ret = -EFAULT;
2746 break;
2747 }
2748 __sony_pic_set_bluetoothpower(val8);
2749 break;
2750
2751 case SONYPI_IOCGFAN:
2752 if (sony_pic_get_fanspeed(&val8)) {
2753 ret = -EIO;
2754 break;
2755 }
2756 if (copy_to_user(argp, &val8, sizeof(val8)))
2757 ret = -EFAULT;
2758 break;
2759 case SONYPI_IOCSFAN:
2760 if (copy_from_user(&val8, argp, sizeof(val8))) {
2761 ret = -EFAULT;
2762 break;
2763 }
2764 if (sony_pic_set_fanspeed(val8))
2765 ret = -EIO;
2766 break;
2767
2768 case SONYPI_IOCGTEMP:
2769 if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
2770 ret = -EIO;
2771 break;
2772 }
2773 if (copy_to_user(argp, &val8, sizeof(val8)))
2774 ret = -EFAULT;
2775 break;
2776 default:
2777 ret = -EINVAL;
2778 }
2779 mutex_unlock(&spic_dev.lock);
2780 return ret;
2781}
2782
2783static const struct file_operations sonypi_misc_fops = {
2784 .owner = THIS_MODULE,
2785 .read = sonypi_misc_read,
2786 .poll = sonypi_misc_poll,
2787 .open = sonypi_misc_open,
2788 .release = sonypi_misc_release,
2789 .fasync = sonypi_misc_fasync,
2790 .unlocked_ioctl = sonypi_misc_ioctl,
2791 .llseek = noop_llseek,
2792};
2793
2794static struct miscdevice sonypi_misc_device = {
2795 .minor = MISC_DYNAMIC_MINOR,
2796 .name = "sonypi",
2797 .fops = &sonypi_misc_fops,
2798};
2799
2800static void sonypi_compat_report_event(u8 event)
2801{
2802 kfifo_in_locked(&sonypi_compat.fifo, (unsigned char *)&event,
2803 sizeof(event), &sonypi_compat.fifo_lock);
2804 kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
2805 wake_up_interruptible(&sonypi_compat.fifo_proc_list);
2806}
2807
2808static int sonypi_compat_init(void)
2809{
2810 int error;
2811
2812 spin_lock_init(&sonypi_compat.fifo_lock);
2813 error =
2814 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
2815 if (error) {
2816 pr_err("kfifo_alloc failed\n");
2817 return error;
2818 }
2819
2820 init_waitqueue_head(&sonypi_compat.fifo_proc_list);
2821
2822 if (minor != -1)
2823 sonypi_misc_device.minor = minor;
2824 error = misc_register(&sonypi_misc_device);
2825 if (error) {
2826 pr_err("misc_register failed\n");
2827 goto err_free_kfifo;
2828 }
2829 if (minor == -1)
2830 pr_info("device allocated minor is %d\n",
2831 sonypi_misc_device.minor);
2832
2833 return 0;
2834
2835err_free_kfifo:
2836 kfifo_free(&sonypi_compat.fifo);
2837 return error;
2838}
2839
2840static void sonypi_compat_exit(void)
2841{
2842 misc_deregister(&sonypi_misc_device);
2843 kfifo_free(&sonypi_compat.fifo);
2844}
2845#else
2846static int sonypi_compat_init(void) { return 0; }
2847static void sonypi_compat_exit(void) { }
2848static void sonypi_compat_report_event(u8 event) { }
2849#endif
2850
2851
2852
2853
2854static acpi_status
2855sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
2856{
2857 u32 i;
2858 struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
2859
2860 switch (resource->type) {
2861 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
2862 {
2863
2864 struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
2865 if (!ioport)
2866 return AE_ERROR;
2867
2868 list_add(&ioport->list, &dev->ioports);
2869 return AE_OK;
2870 }
2871
2872 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
2873
2874 return AE_OK;
2875
2876 case ACPI_RESOURCE_TYPE_IRQ:
2877 {
2878 struct acpi_resource_irq *p = &resource->data.irq;
2879 struct sony_pic_irq *interrupt = NULL;
2880 if (!p || !p->interrupt_count) {
2881
2882
2883
2884
2885 dprintk("Blank IRQ resource\n");
2886 return AE_OK;
2887 }
2888 for (i = 0; i < p->interrupt_count; i++) {
2889 if (!p->interrupts[i]) {
2890 pr_warn("Invalid IRQ %d\n",
2891 p->interrupts[i]);
2892 continue;
2893 }
2894 interrupt = kzalloc(sizeof(*interrupt),
2895 GFP_KERNEL);
2896 if (!interrupt)
2897 return AE_ERROR;
2898
2899 list_add(&interrupt->list, &dev->interrupts);
2900 interrupt->irq.triggering = p->triggering;
2901 interrupt->irq.polarity = p->polarity;
2902 interrupt->irq.sharable = p->sharable;
2903 interrupt->irq.interrupt_count = 1;
2904 interrupt->irq.interrupts[0] = p->interrupts[i];
2905 }
2906 return AE_OK;
2907 }
2908 case ACPI_RESOURCE_TYPE_IO:
2909 {
2910 struct acpi_resource_io *io = &resource->data.io;
2911 struct sony_pic_ioport *ioport =
2912 list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
2913 if (!io) {
2914 dprintk("Blank IO resource\n");
2915 return AE_OK;
2916 }
2917
2918 if (!ioport->io1.minimum) {
2919 memcpy(&ioport->io1, io, sizeof(*io));
2920 dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
2921 ioport->io1.address_length);
2922 }
2923 else if (!ioport->io2.minimum) {
2924 memcpy(&ioport->io2, io, sizeof(*io));
2925 dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
2926 ioport->io2.address_length);
2927 }
2928 else {
2929 pr_err("Unknown SPIC Type, more than 2 IO Ports\n");
2930 return AE_ERROR;
2931 }
2932 return AE_OK;
2933 }
2934 default:
2935 dprintk("Resource %d isn't an IRQ nor an IO port\n",
2936 resource->type);
2937
2938 case ACPI_RESOURCE_TYPE_END_TAG:
2939 return AE_OK;
2940 }
2941 return AE_CTRL_TERMINATE;
2942}
2943
2944static int sony_pic_possible_resources(struct acpi_device *device)
2945{
2946 int result = 0;
2947 acpi_status status = AE_OK;
2948
2949 if (!device)
2950 return -EINVAL;
2951
2952
2953
2954 dprintk("Evaluating _STA\n");
2955 result = acpi_bus_get_status(device);
2956 if (result) {
2957 pr_warn("Unable to read status\n");
2958 goto end;
2959 }
2960
2961 if (!device->status.enabled)
2962 dprintk("Device disabled\n");
2963 else
2964 dprintk("Device enabled\n");
2965
2966
2967
2968
2969 dprintk("Evaluating %s\n", METHOD_NAME__PRS);
2970 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
2971 sony_pic_read_possible_resource, &spic_dev);
2972 if (ACPI_FAILURE(status)) {
2973 pr_warn("Failure evaluating %s\n", METHOD_NAME__PRS);
2974 result = -ENODEV;
2975 }
2976end:
2977 return result;
2978}
2979
2980
2981
2982
2983static int sony_pic_disable(struct acpi_device *device)
2984{
2985 acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL,
2986 NULL);
2987
2988 if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND)
2989 return -ENXIO;
2990
2991 dprintk("Device disabled\n");
2992 return 0;
2993}
2994
2995
2996
2997
2998
2999
3000
3001static int sony_pic_enable(struct acpi_device *device,
3002 struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
3003{
3004 acpi_status status;
3005 int result = 0;
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017 struct {
3018 struct acpi_resource res1;
3019 struct acpi_resource res2;
3020 struct acpi_resource res3;
3021 struct acpi_resource res4;
3022 } *resource;
3023 struct acpi_buffer buffer = { 0, NULL };
3024
3025 if (!ioport || !irq)
3026 return -EINVAL;
3027
3028
3029 resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
3030 if (!resource)
3031 return -ENOMEM;
3032
3033 buffer.length = sizeof(*resource) + 1;
3034 buffer.pointer = resource;
3035
3036
3037 if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
3038
3039
3040 resource->res1.type = ACPI_RESOURCE_TYPE_IO;
3041 resource->res1.length = sizeof(struct acpi_resource);
3042 memcpy(&resource->res1.data.io, &ioport->io1,
3043 sizeof(struct acpi_resource_io));
3044
3045 resource->res2.type = ACPI_RESOURCE_TYPE_IO;
3046 resource->res2.length = sizeof(struct acpi_resource);
3047 memcpy(&resource->res2.data.io, &ioport->io2,
3048 sizeof(struct acpi_resource_io));
3049
3050
3051 resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
3052 resource->res3.length = sizeof(struct acpi_resource);
3053 memcpy(&resource->res3.data.irq, &irq->irq,
3054 sizeof(struct acpi_resource_irq));
3055
3056 resource->res3.data.irq.sharable = ACPI_SHARED;
3057
3058 resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
3059
3060 }
3061
3062 else {
3063
3064 resource->res1.type = ACPI_RESOURCE_TYPE_IO;
3065 resource->res1.length = sizeof(struct acpi_resource);
3066 memcpy(&resource->res1.data.io, &ioport->io1,
3067 sizeof(struct acpi_resource_io));
3068
3069
3070 resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
3071 resource->res2.length = sizeof(struct acpi_resource);
3072 memcpy(&resource->res2.data.irq, &irq->irq,
3073 sizeof(struct acpi_resource_irq));
3074
3075 resource->res2.data.irq.sharable = ACPI_SHARED;
3076
3077 resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
3078 }
3079
3080
3081 dprintk("Evaluating _SRS\n");
3082 status = acpi_set_current_resources(device->handle, &buffer);
3083
3084
3085 if (ACPI_FAILURE(status)) {
3086 pr_err("Error evaluating _SRS\n");
3087 result = -ENODEV;
3088 goto end;
3089 }
3090
3091
3092 sony_pic_call1(0x82);
3093 sony_pic_call2(0x81, 0xff);
3094 sony_pic_call1(compat ? 0x92 : 0x82);
3095
3096end:
3097 kfree(resource);
3098 return result;
3099}
3100
3101
3102
3103
3104
3105
3106static irqreturn_t sony_pic_irq(int irq, void *dev_id)
3107{
3108 int i, j;
3109 u8 ev = 0;
3110 u8 data_mask = 0;
3111 u8 device_event = 0;
3112
3113 struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
3114
3115 ev = inb_p(dev->cur_ioport->io1.minimum);
3116 if (dev->cur_ioport->io2.minimum)
3117 data_mask = inb_p(dev->cur_ioport->io2.minimum);
3118 else
3119 data_mask = inb_p(dev->cur_ioport->io1.minimum +
3120 dev->evport_offset);
3121
3122 dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
3123 ev, data_mask, dev->cur_ioport->io1.minimum,
3124 dev->evport_offset);
3125
3126 if (ev == 0x00 || ev == 0xff)
3127 return IRQ_HANDLED;
3128
3129 for (i = 0; dev->event_types[i].mask; i++) {
3130
3131 if ((data_mask & dev->event_types[i].data) !=
3132 dev->event_types[i].data)
3133 continue;
3134
3135 if (!(mask & dev->event_types[i].mask))
3136 continue;
3137
3138 for (j = 0; dev->event_types[i].events[j].event; j++) {
3139 if (ev == dev->event_types[i].events[j].data) {
3140 device_event =
3141 dev->event_types[i].events[j].event;
3142
3143 if (!device_event)
3144 return IRQ_HANDLED;
3145 goto found;
3146 }
3147 }
3148 }
3149
3150
3151
3152 if (dev->handle_irq && dev->handle_irq(data_mask, ev) == 0)
3153 return IRQ_HANDLED;
3154
3155 dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
3156 ev, data_mask, dev->cur_ioport->io1.minimum,
3157 dev->evport_offset);
3158 return IRQ_HANDLED;
3159
3160found:
3161 sony_laptop_report_input_event(device_event);
3162 acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
3163 sonypi_compat_report_event(device_event);
3164 return IRQ_HANDLED;
3165}
3166
3167
3168
3169
3170
3171
3172static int sony_pic_remove(struct acpi_device *device, int type)
3173{
3174 struct sony_pic_ioport *io, *tmp_io;
3175 struct sony_pic_irq *irq, *tmp_irq;
3176
3177 if (sony_pic_disable(device)) {
3178 pr_err("Couldn't disable device\n");
3179 return -ENXIO;
3180 }
3181
3182 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
3183 release_region(spic_dev.cur_ioport->io1.minimum,
3184 spic_dev.cur_ioport->io1.address_length);
3185 if (spic_dev.cur_ioport->io2.minimum)
3186 release_region(spic_dev.cur_ioport->io2.minimum,
3187 spic_dev.cur_ioport->io2.address_length);
3188
3189 sonypi_compat_exit();
3190
3191 sony_laptop_remove_input();
3192
3193
3194 sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
3195 sony_pf_remove();
3196
3197 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
3198 list_del(&io->list);
3199 kfree(io);
3200 }
3201 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
3202 list_del(&irq->list);
3203 kfree(irq);
3204 }
3205 spic_dev.cur_ioport = NULL;
3206 spic_dev.cur_irq = NULL;
3207
3208 dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
3209 return 0;
3210}
3211
3212static int sony_pic_add(struct acpi_device *device)
3213{
3214 int result;
3215 struct sony_pic_ioport *io, *tmp_io;
3216 struct sony_pic_irq *irq, *tmp_irq;
3217
3218 pr_info("%s v%s\n", SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
3219
3220 spic_dev.acpi_dev = device;
3221 strcpy(acpi_device_class(device), "sony/hotkey");
3222 sony_pic_detect_device_type(&spic_dev);
3223 mutex_init(&spic_dev.lock);
3224
3225
3226 result = sony_pic_possible_resources(device);
3227 if (result) {
3228 pr_err("Unable to read possible resources\n");
3229 goto err_free_resources;
3230 }
3231
3232
3233 result = sony_laptop_setup_input(device);
3234 if (result) {
3235 pr_err("Unable to create input devices\n");
3236 goto err_free_resources;
3237 }
3238
3239 if (sonypi_compat_init())
3240 goto err_remove_input;
3241
3242
3243 list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
3244 if (request_region(io->io1.minimum, io->io1.address_length,
3245 "Sony Programmable I/O Device")) {
3246 dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
3247 io->io1.minimum, io->io1.maximum,
3248 io->io1.address_length);
3249
3250 if (io->io2.minimum) {
3251 if (request_region(io->io2.minimum,
3252 io->io2.address_length,
3253 "Sony Programmable I/O Device")) {
3254 dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
3255 io->io2.minimum, io->io2.maximum,
3256 io->io2.address_length);
3257 spic_dev.cur_ioport = io;
3258 break;
3259 }
3260 else {
3261 dprintk("Unable to get I/O port2: "
3262 "0x%.4x (0x%.4x) + 0x%.2x\n",
3263 io->io2.minimum, io->io2.maximum,
3264 io->io2.address_length);
3265 release_region(io->io1.minimum,
3266 io->io1.address_length);
3267 }
3268 }
3269 else {
3270 spic_dev.cur_ioport = io;
3271 break;
3272 }
3273 }
3274 }
3275 if (!spic_dev.cur_ioport) {
3276 pr_err("Failed to request_region\n");
3277 result = -ENODEV;
3278 goto err_remove_compat;
3279 }
3280
3281
3282 list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
3283 if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
3284 0, "sony-laptop", &spic_dev)) {
3285 dprintk("IRQ: %d - triggering: %d - "
3286 "polarity: %d - shr: %d\n",
3287 irq->irq.interrupts[0],
3288 irq->irq.triggering,
3289 irq->irq.polarity,
3290 irq->irq.sharable);
3291 spic_dev.cur_irq = irq;
3292 break;
3293 }
3294 }
3295 if (!spic_dev.cur_irq) {
3296 pr_err("Failed to request_irq\n");
3297 result = -ENODEV;
3298 goto err_release_region;
3299 }
3300
3301
3302 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
3303 if (result) {
3304 pr_err("Couldn't enable device\n");
3305 goto err_free_irq;
3306 }
3307
3308 spic_dev.bluetooth_power = -1;
3309
3310 result = sony_pf_add();
3311 if (result)
3312 goto err_disable_device;
3313
3314 result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
3315 if (result)
3316 goto err_remove_pf;
3317
3318 return 0;
3319
3320err_remove_pf:
3321 sony_pf_remove();
3322
3323err_disable_device:
3324 sony_pic_disable(device);
3325
3326err_free_irq:
3327 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
3328
3329err_release_region:
3330 release_region(spic_dev.cur_ioport->io1.minimum,
3331 spic_dev.cur_ioport->io1.address_length);
3332 if (spic_dev.cur_ioport->io2.minimum)
3333 release_region(spic_dev.cur_ioport->io2.minimum,
3334 spic_dev.cur_ioport->io2.address_length);
3335
3336err_remove_compat:
3337 sonypi_compat_exit();
3338
3339err_remove_input:
3340 sony_laptop_remove_input();
3341
3342err_free_resources:
3343 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
3344 list_del(&io->list);
3345 kfree(io);
3346 }
3347 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
3348 list_del(&irq->list);
3349 kfree(irq);
3350 }
3351 spic_dev.cur_ioport = NULL;
3352 spic_dev.cur_irq = NULL;
3353
3354 return result;
3355}
3356
3357static int sony_pic_suspend(struct acpi_device *device, pm_message_t state)
3358{
3359 if (sony_pic_disable(device))
3360 return -ENXIO;
3361 return 0;
3362}
3363
3364static int sony_pic_resume(struct acpi_device *device)
3365{
3366 sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
3367 return 0;
3368}
3369
3370static const struct acpi_device_id sony_pic_device_ids[] = {
3371 {SONY_PIC_HID, 0},
3372 {"", 0},
3373};
3374
3375static struct acpi_driver sony_pic_driver = {
3376 .name = SONY_PIC_DRIVER_NAME,
3377 .class = SONY_PIC_CLASS,
3378 .ids = sony_pic_device_ids,
3379 .owner = THIS_MODULE,
3380 .ops = {
3381 .add = sony_pic_add,
3382 .remove = sony_pic_remove,
3383 .suspend = sony_pic_suspend,
3384 .resume = sony_pic_resume,
3385 },
3386};
3387
3388static struct dmi_system_id __initdata sonypi_dmi_table[] = {
3389 {
3390 .ident = "Sony Vaio",
3391 .matches = {
3392 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
3393 DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
3394 },
3395 },
3396 {
3397 .ident = "Sony Vaio",
3398 .matches = {
3399 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
3400 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
3401 },
3402 },
3403 { }
3404};
3405
3406static int __init sony_laptop_init(void)
3407{
3408 int result;
3409
3410 if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
3411 result = acpi_bus_register_driver(&sony_pic_driver);
3412 if (result) {
3413 pr_err("Unable to register SPIC driver\n");
3414 goto out;
3415 }
3416 spic_drv_registered = 1;
3417 }
3418
3419 result = acpi_bus_register_driver(&sony_nc_driver);
3420 if (result) {
3421 pr_err("Unable to register SNC driver\n");
3422 goto out_unregister_pic;
3423 }
3424
3425 return 0;
3426
3427out_unregister_pic:
3428 if (spic_drv_registered)
3429 acpi_bus_unregister_driver(&sony_pic_driver);
3430out:
3431 return result;
3432}
3433
3434static void __exit sony_laptop_exit(void)
3435{
3436 acpi_bus_unregister_driver(&sony_nc_driver);
3437 if (spic_drv_registered)
3438 acpi_bus_unregister_driver(&sony_pic_driver);
3439}
3440
3441module_init(sony_laptop_init);
3442module_exit(sony_laptop_exit);
3443