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 <linux/sonypi.h>
65#include <linux/sony-laptop.h>
66#include <linux/rfkill.h>
67#ifdef CONFIG_SONYPI_COMPAT
68#include <linux/poll.h>
69#include <linux/miscdevice.h>
70#endif
71#include <asm/uaccess.h>
72
73#define dprintk(fmt, ...) \
74do { \
75 if (debug) \
76 pr_warn(fmt, ##__VA_ARGS__); \
77} while (0)
78
79#define SONY_NC_CLASS "sony-nc"
80#define SONY_NC_HID "SNY5001"
81#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver"
82
83#define SONY_PIC_CLASS "sony-pic"
84#define SONY_PIC_HID "SNY6001"
85#define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver"
86
87MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
88MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
89MODULE_LICENSE("GPL");
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
125static int kbd_backlight = -1;
126module_param(kbd_backlight, int, 0444);
127MODULE_PARM_DESC(kbd_backlight,
128 "set this to 0 to disable keyboard backlight, "
129 "1 to enable it with automatic control and 2 to have it always "
130 "on (default: no change from current value)");
131
132static int kbd_backlight_timeout = -1;
133module_param(kbd_backlight_timeout, int, 0444);
134MODULE_PARM_DESC(kbd_backlight_timeout,
135 "meaningful values vary from 0 to 3 and their meaning depends "
136 "on the model (default: no change from current value)");
137
138#ifdef CONFIG_PM_SLEEP
139static void sony_nc_thermal_resume(void);
140#endif
141static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
142 unsigned int handle);
143static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd,
144 unsigned int handle);
145
146static int sony_nc_battery_care_setup(struct platform_device *pd,
147 unsigned int handle);
148static void sony_nc_battery_care_cleanup(struct platform_device *pd);
149
150static int sony_nc_thermal_setup(struct platform_device *pd);
151static void sony_nc_thermal_cleanup(struct platform_device *pd);
152
153static int sony_nc_lid_resume_setup(struct platform_device *pd,
154 unsigned int handle);
155static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
156
157static int sony_nc_gfx_switch_setup(struct platform_device *pd,
158 unsigned int handle);
159static void sony_nc_gfx_switch_cleanup(struct platform_device *pd);
160static int __sony_nc_gfx_switch_status_get(void);
161
162static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
163static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
164
165static int sony_nc_lowbatt_setup(struct platform_device *pd);
166static void sony_nc_lowbatt_cleanup(struct platform_device *pd);
167
168static int sony_nc_fanspeed_setup(struct platform_device *pd);
169static void sony_nc_fanspeed_cleanup(struct platform_device *pd);
170
171static int sony_nc_usb_charge_setup(struct platform_device *pd);
172static void sony_nc_usb_charge_cleanup(struct platform_device *pd);
173
174static int sony_nc_panelid_setup(struct platform_device *pd);
175static void sony_nc_panelid_cleanup(struct platform_device *pd);
176
177static int sony_nc_smart_conn_setup(struct platform_device *pd);
178static void sony_nc_smart_conn_cleanup(struct platform_device *pd);
179
180static int sony_nc_touchpad_setup(struct platform_device *pd,
181 unsigned int handle);
182static void sony_nc_touchpad_cleanup(struct platform_device *pd);
183
184enum sony_nc_rfkill {
185 SONY_WIFI,
186 SONY_BLUETOOTH,
187 SONY_WWAN,
188 SONY_WIMAX,
189 N_SONY_RFKILL,
190};
191
192static int sony_rfkill_handle;
193static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
194static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
195static int sony_nc_rfkill_setup(struct acpi_device *device,
196 unsigned int handle);
197static void sony_nc_rfkill_cleanup(void);
198static void sony_nc_rfkill_update(void);
199
200
201
202#define SONY_LAPTOP_BUF_SIZE 128
203struct sony_laptop_input_s {
204 atomic_t users;
205 struct input_dev *jog_dev;
206 struct input_dev *key_dev;
207 struct kfifo fifo;
208 spinlock_t fifo_lock;
209 struct timer_list release_key_timer;
210};
211
212static struct sony_laptop_input_s sony_laptop_input = {
213 .users = ATOMIC_INIT(0),
214};
215
216struct sony_laptop_keypress {
217 struct input_dev *dev;
218 int key;
219};
220
221
222
223
224static int sony_laptop_input_index[] = {
225 -1,
226 -1,
227 -1,
228 -1,
229 -1,
230 -1,
231 -1,
232 0,
233 1,
234 2,
235 3,
236 4,
237 5,
238 6,
239 7,
240 8,
241 9,
242 10,
243 11,
244 12,
245 13,
246 14,
247 15,
248 16,
249 17,
250 18,
251 19,
252 20,
253 21,
254 22,
255 23,
256 24,
257 25,
258 26,
259 27,
260 28,
261 -1,
262 -1,
263 29,
264 30,
265 31,
266 32,
267 33,
268 34,
269 35,
270 36,
271 37,
272 38,
273 39,
274 40,
275 41,
276 42,
277 43,
278 44,
279 45,
280 46,
281 -1,
282 -1,
283 -1,
284 -1,
285 47,
286 48,
287 49,
288 50,
289 51,
290 52,
291 53,
292 54,
293 55,
294 56,
295 57,
296 -1,
297 58,
298 59,
299};
300
301static int sony_laptop_input_keycode_map[] = {
302 KEY_CAMERA,
303 KEY_RESERVED,
304 KEY_RESERVED,
305 KEY_RESERVED,
306 KEY_FN_ESC,
307 KEY_FN_F1,
308 KEY_FN_F2,
309 KEY_FN_F3,
310 KEY_FN_F4,
311 KEY_FN_F5,
312 KEY_FN_F6,
313 KEY_FN_F7,
314 KEY_FN_F8,
315 KEY_FN_F9,
316 KEY_FN_F10,
317 KEY_FN_F11,
318 KEY_FN_F12,
319 KEY_FN_1,
320 KEY_FN_2,
321 KEY_FN_D,
322 KEY_FN_E,
323 KEY_FN_F,
324 KEY_FN_S,
325 KEY_FN_B,
326 KEY_BLUETOOTH,
327 KEY_PROG1,
328 KEY_PROG2,
329 KEY_PROG3,
330 KEY_BACK,
331 KEY_BLUETOOTH,
332 KEY_BLUETOOTH,
333 KEY_HELP,
334 KEY_FN,
335 KEY_RESERVED,
336 KEY_RESERVED,
337 KEY_RESERVED,
338 KEY_RESERVED,
339 KEY_RESERVED,
340 KEY_RESERVED,
341 KEY_RESERVED,
342 KEY_RESERVED,
343 KEY_ZOOM,
344 BTN_THUMB,
345 KEY_RESERVED,
346 KEY_RESERVED,
347 KEY_RESERVED,
348 KEY_RESERVED,
349 KEY_WLAN,
350 KEY_WLAN,
351 KEY_ZOOMIN,
352 KEY_ZOOMOUT,
353 KEY_EJECTCD,
354 KEY_F13,
355 KEY_PROG4,
356 KEY_F14,
357 KEY_F15,
358 KEY_VOLUMEUP,
359 KEY_VOLUMEDOWN,
360 KEY_MEDIA,
361 KEY_VENDOR,
362};
363
364
365static void do_sony_laptop_release_key(unsigned long unused)
366{
367 struct sony_laptop_keypress kp;
368 unsigned long flags;
369
370 spin_lock_irqsave(&sony_laptop_input.fifo_lock, flags);
371
372 if (kfifo_out(&sony_laptop_input.fifo,
373 (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
374 input_report_key(kp.dev, kp.key, 0);
375 input_sync(kp.dev);
376 }
377
378
379 if (kfifo_len(&sony_laptop_input.fifo) != 0)
380 mod_timer(&sony_laptop_input.release_key_timer,
381 jiffies + msecs_to_jiffies(10));
382
383 spin_unlock_irqrestore(&sony_laptop_input.fifo_lock, flags);
384}
385
386
387static void sony_laptop_report_input_event(u8 event)
388{
389 struct input_dev *jog_dev = sony_laptop_input.jog_dev;
390 struct input_dev *key_dev = sony_laptop_input.key_dev;
391 struct sony_laptop_keypress kp = { NULL };
392 int scancode = -1;
393
394 if (event == SONYPI_EVENT_FNKEY_RELEASED ||
395 event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
396
397 return;
398 }
399
400
401 switch (event) {
402
403 case SONYPI_EVENT_JOGDIAL_UP:
404 case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
405 input_report_rel(jog_dev, REL_WHEEL, 1);
406 input_sync(jog_dev);
407 return;
408
409 case SONYPI_EVENT_JOGDIAL_DOWN:
410 case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
411 input_report_rel(jog_dev, REL_WHEEL, -1);
412 input_sync(jog_dev);
413 return;
414
415
416 case SONYPI_EVENT_JOGDIAL_PRESSED:
417 kp.key = BTN_MIDDLE;
418 kp.dev = jog_dev;
419 break;
420
421 default:
422 if (event >= ARRAY_SIZE(sony_laptop_input_index)) {
423 dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
424 break;
425 }
426 if ((scancode = sony_laptop_input_index[event]) != -1) {
427 kp.key = sony_laptop_input_keycode_map[scancode];
428 if (kp.key != KEY_UNKNOWN)
429 kp.dev = key_dev;
430 }
431 break;
432 }
433
434 if (kp.dev) {
435
436
437 if (scancode != -1)
438 input_event(kp.dev, EV_MSC, MSC_SCAN, scancode);
439 input_report_key(kp.dev, kp.key, 1);
440 input_sync(kp.dev);
441
442
443 kfifo_in_locked(&sony_laptop_input.fifo,
444 (unsigned char *)&kp, sizeof(kp),
445 &sony_laptop_input.fifo_lock);
446 mod_timer(&sony_laptop_input.release_key_timer,
447 jiffies + msecs_to_jiffies(10));
448 } else
449 dprintk("unknown input event %.2x\n", event);
450}
451
452static int sony_laptop_setup_input(struct acpi_device *acpi_device)
453{
454 struct input_dev *jog_dev;
455 struct input_dev *key_dev;
456 int i;
457 int error;
458
459
460 if (atomic_add_return(1, &sony_laptop_input.users) > 1)
461 return 0;
462
463
464 spin_lock_init(&sony_laptop_input.fifo_lock);
465 error = kfifo_alloc(&sony_laptop_input.fifo,
466 SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
467 if (error) {
468 pr_err("kfifo_alloc failed\n");
469 goto err_dec_users;
470 }
471
472 setup_timer(&sony_laptop_input.release_key_timer,
473 do_sony_laptop_release_key, 0);
474
475
476 key_dev = input_allocate_device();
477 if (!key_dev) {
478 error = -ENOMEM;
479 goto err_free_kfifo;
480 }
481
482 key_dev->name = "Sony Vaio Keys";
483 key_dev->id.bustype = BUS_ISA;
484 key_dev->id.vendor = PCI_VENDOR_ID_SONY;
485 key_dev->dev.parent = &acpi_device->dev;
486
487
488 input_set_capability(key_dev, EV_MSC, MSC_SCAN);
489
490 __set_bit(EV_KEY, key_dev->evbit);
491 key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
492 key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
493 key_dev->keycode = &sony_laptop_input_keycode_map;
494 for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++)
495 __set_bit(sony_laptop_input_keycode_map[i], key_dev->keybit);
496 __clear_bit(KEY_RESERVED, key_dev->keybit);
497
498 error = input_register_device(key_dev);
499 if (error)
500 goto err_free_keydev;
501
502 sony_laptop_input.key_dev = key_dev;
503
504
505 jog_dev = input_allocate_device();
506 if (!jog_dev) {
507 error = -ENOMEM;
508 goto err_unregister_keydev;
509 }
510
511 jog_dev->name = "Sony Vaio Jogdial";
512 jog_dev->id.bustype = BUS_ISA;
513 jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
514 jog_dev->dev.parent = &acpi_device->dev;
515
516 input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
517 input_set_capability(jog_dev, EV_REL, REL_WHEEL);
518
519 error = input_register_device(jog_dev);
520 if (error)
521 goto err_free_jogdev;
522
523 sony_laptop_input.jog_dev = jog_dev;
524
525 return 0;
526
527err_free_jogdev:
528 input_free_device(jog_dev);
529
530err_unregister_keydev:
531 input_unregister_device(key_dev);
532
533 key_dev = NULL;
534
535err_free_keydev:
536 input_free_device(key_dev);
537
538err_free_kfifo:
539 kfifo_free(&sony_laptop_input.fifo);
540
541err_dec_users:
542 atomic_dec(&sony_laptop_input.users);
543 return error;
544}
545
546static void sony_laptop_remove_input(void)
547{
548 struct sony_laptop_keypress kp = { NULL };
549
550
551 if (!atomic_dec_and_test(&sony_laptop_input.users))
552 return;
553
554 del_timer_sync(&sony_laptop_input.release_key_timer);
555
556
557
558
559
560 while (kfifo_out(&sony_laptop_input.fifo,
561 (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
562 input_report_key(kp.dev, kp.key, 0);
563 input_sync(kp.dev);
564 }
565
566
567 input_unregister_device(sony_laptop_input.key_dev);
568 sony_laptop_input.key_dev = NULL;
569
570 if (sony_laptop_input.jog_dev) {
571 input_unregister_device(sony_laptop_input.jog_dev);
572 sony_laptop_input.jog_dev = NULL;
573 }
574
575 kfifo_free(&sony_laptop_input.fifo);
576}
577
578
579
580static atomic_t sony_pf_users = ATOMIC_INIT(0);
581static struct platform_driver sony_pf_driver = {
582 .driver = {
583 .name = "sony-laptop",
584 .owner = THIS_MODULE,
585 }
586};
587static struct platform_device *sony_pf_device;
588
589static int sony_pf_add(void)
590{
591 int ret = 0;
592
593
594 if (atomic_add_return(1, &sony_pf_users) > 1)
595 return 0;
596
597 ret = platform_driver_register(&sony_pf_driver);
598 if (ret)
599 goto out;
600
601 sony_pf_device = platform_device_alloc("sony-laptop", -1);
602 if (!sony_pf_device) {
603 ret = -ENOMEM;
604 goto out_platform_registered;
605 }
606
607 ret = platform_device_add(sony_pf_device);
608 if (ret)
609 goto out_platform_alloced;
610
611 return 0;
612
613 out_platform_alloced:
614 platform_device_put(sony_pf_device);
615 sony_pf_device = NULL;
616 out_platform_registered:
617 platform_driver_unregister(&sony_pf_driver);
618 out:
619 atomic_dec(&sony_pf_users);
620 return ret;
621}
622
623static void sony_pf_remove(void)
624{
625
626 if (!atomic_dec_and_test(&sony_pf_users))
627 return;
628
629 platform_device_unregister(sony_pf_device);
630 platform_driver_unregister(&sony_pf_driver);
631}
632
633
634
635
636
637#define SONY_MAX_BRIGHTNESS 8
638
639#define SNC_VALIDATE_IN 0
640#define SNC_VALIDATE_OUT 1
641
642static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
643 char *);
644static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
645 const char *, size_t);
646static int boolean_validate(const int, const int);
647static int brightness_default_validate(const int, const int);
648
649struct sony_nc_value {
650 char *name;
651 char **acpiget;
652 char **acpiset;
653 int (*validate)(const int, const int);
654 int value;
655 int valid;
656 int debug;
657 struct device_attribute devattr;
658};
659
660#define SNC_HANDLE_NAMES(_name, _values...) \
661 static char *snc_##_name[] = { _values, NULL }
662
663#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
664 { \
665 .name = __stringify(_name), \
666 .acpiget = _getters, \
667 .acpiset = _setters, \
668 .validate = _validate, \
669 .debug = _debug, \
670 .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
671 }
672
673#define SNC_HANDLE_NULL { .name = NULL }
674
675SNC_HANDLE_NAMES(fnkey_get, "GHKE");
676
677SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
678SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
679
680SNC_HANDLE_NAMES(cdpower_get, "GCDP");
681SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
682
683SNC_HANDLE_NAMES(audiopower_get, "GAZP");
684SNC_HANDLE_NAMES(audiopower_set, "AZPW");
685
686SNC_HANDLE_NAMES(lanpower_get, "GLNP");
687SNC_HANDLE_NAMES(lanpower_set, "LNPW");
688
689SNC_HANDLE_NAMES(lidstate_get, "GLID");
690
691SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
692SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
693
694SNC_HANDLE_NAMES(gainbass_get, "GMGB");
695SNC_HANDLE_NAMES(gainbass_set, "CMGB");
696
697SNC_HANDLE_NAMES(PID_get, "GPID");
698
699SNC_HANDLE_NAMES(CTR_get, "GCTR");
700SNC_HANDLE_NAMES(CTR_set, "SCTR");
701
702SNC_HANDLE_NAMES(PCR_get, "GPCR");
703SNC_HANDLE_NAMES(PCR_set, "SPCR");
704
705SNC_HANDLE_NAMES(CMI_get, "GCMI");
706SNC_HANDLE_NAMES(CMI_set, "SCMI");
707
708static struct sony_nc_value sony_nc_values[] = {
709 SNC_HANDLE(brightness_default, snc_brightness_def_get,
710 snc_brightness_def_set, brightness_default_validate, 0),
711 SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
712 SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
713 SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
714 boolean_validate, 0),
715 SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
716 boolean_validate, 1),
717 SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
718 boolean_validate, 0),
719 SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
720 boolean_validate, 0),
721 SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
722 boolean_validate, 0),
723
724 SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
725 SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
726 SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
727 SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
728 SNC_HANDLE_NULL
729};
730
731static acpi_handle sony_nc_acpi_handle;
732static struct acpi_device *sony_nc_acpi_device = NULL;
733
734
735
736
737
738
739static union acpi_object *__call_snc_method(acpi_handle handle, char *method,
740 u64 *value)
741{
742 union acpi_object *result = NULL;
743 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
744 acpi_status status;
745
746 if (value) {
747 struct acpi_object_list params;
748 union acpi_object in;
749 in.type = ACPI_TYPE_INTEGER;
750 in.integer.value = *value;
751 params.count = 1;
752 params.pointer = ∈
753 status = acpi_evaluate_object(handle, method, ¶ms, &output);
754 dprintk("__call_snc_method: [%s:0x%.8x%.8x]\n", method,
755 (unsigned int)(*value >> 32),
756 (unsigned int)*value & 0xffffffff);
757 } else {
758 status = acpi_evaluate_object(handle, method, NULL, &output);
759 dprintk("__call_snc_method: [%s]\n", method);
760 }
761
762 if (ACPI_FAILURE(status)) {
763 pr_err("Failed to evaluate [%s]\n", method);
764 return NULL;
765 }
766
767 result = (union acpi_object *) output.pointer;
768 if (!result)
769 dprintk("No return object [%s]\n", method);
770
771 return result;
772}
773
774static int sony_nc_int_call(acpi_handle handle, char *name, int *value,
775 int *result)
776{
777 union acpi_object *object = NULL;
778 if (value) {
779 u64 v = *value;
780 object = __call_snc_method(handle, name, &v);
781 } else
782 object = __call_snc_method(handle, name, NULL);
783
784 if (!object)
785 return -EINVAL;
786
787 if (object->type != ACPI_TYPE_INTEGER) {
788 pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
789 ACPI_TYPE_INTEGER, object->type);
790 kfree(object);
791 return -EINVAL;
792 }
793
794 if (result)
795 *result = object->integer.value;
796
797 kfree(object);
798 return 0;
799}
800
801#define MIN(a, b) (a > b ? b : a)
802static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
803 void *buffer, size_t buflen)
804{
805 int ret = 0;
806 size_t len;
807 union acpi_object *object = __call_snc_method(handle, name, value);
808
809 if (!object)
810 return -EINVAL;
811
812 if (object->type == ACPI_TYPE_BUFFER) {
813 len = MIN(buflen, object->buffer.length);
814 memcpy(buffer, object->buffer.pointer, len);
815
816 } else if (object->type == ACPI_TYPE_INTEGER) {
817 len = MIN(buflen, sizeof(object->integer.value));
818 memcpy(buffer, &object->integer.value, len);
819
820 } else {
821 pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
822 ACPI_TYPE_BUFFER, object->type);
823 ret = -EINVAL;
824 }
825
826 kfree(object);
827 return ret;
828}
829
830struct sony_nc_handles {
831 u16 cap[0x10];
832 struct device_attribute devattr;
833};
834
835static struct sony_nc_handles *handles;
836
837static ssize_t sony_nc_handles_show(struct device *dev,
838 struct device_attribute *attr, char *buffer)
839{
840 ssize_t len = 0;
841 int i;
842
843 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
844 len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
845 handles->cap[i]);
846 }
847 len += snprintf(buffer + len, PAGE_SIZE - len, "\n");
848
849 return len;
850}
851
852static int sony_nc_handles_setup(struct platform_device *pd)
853{
854 int i, r, result, arg;
855
856 handles = kzalloc(sizeof(*handles), GFP_KERNEL);
857 if (!handles)
858 return -ENOMEM;
859
860 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
861 arg = i + 0x20;
862 r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg,
863 &result);
864 if (!r) {
865 dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
866 result, i);
867 handles->cap[i] = result;
868 }
869 }
870
871 if (debug) {
872 sysfs_attr_init(&handles->devattr.attr);
873 handles->devattr.attr.name = "handles";
874 handles->devattr.attr.mode = S_IRUGO;
875 handles->devattr.show = sony_nc_handles_show;
876
877
878 if (device_create_file(&pd->dev, &handles->devattr)) {
879 kfree(handles);
880 handles = NULL;
881 return -1;
882 }
883 }
884
885 return 0;
886}
887
888static int sony_nc_handles_cleanup(struct platform_device *pd)
889{
890 if (handles) {
891 if (debug)
892 device_remove_file(&pd->dev, &handles->devattr);
893 kfree(handles);
894 handles = NULL;
895 }
896 return 0;
897}
898
899static int sony_find_snc_handle(int handle)
900{
901 int i;
902
903
904 if (!handles || !handle)
905 return -EINVAL;
906
907 for (i = 0; i < 0x10; i++) {
908 if (handles->cap[i] == handle) {
909 dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
910 handle, i);
911 return i;
912 }
913 }
914 dprintk("handle 0x%.4x not found\n", handle);
915 return -EINVAL;
916}
917
918static int sony_call_snc_handle(int handle, int argument, int *result)
919{
920 int arg, ret = 0;
921 int offset = sony_find_snc_handle(handle);
922
923 if (offset < 0)
924 return offset;
925
926 arg = offset | argument;
927 ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result);
928 dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result);
929 return ret;
930}
931
932
933
934
935
936
937
938
939
940
941static int brightness_default_validate(const int direction, const int value)
942{
943 switch (direction) {
944 case SNC_VALIDATE_OUT:
945 return value - 1;
946 case SNC_VALIDATE_IN:
947 if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
948 return value + 1;
949 }
950 return -EINVAL;
951}
952
953
954
955
956
957
958static int boolean_validate(const int direction, const int value)
959{
960 if (direction == SNC_VALIDATE_IN) {
961 if (value != 0 && value != 1)
962 return -EINVAL;
963 }
964 return value;
965}
966
967
968
969
970static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
971 char *buffer)
972{
973 int value, ret = 0;
974 struct sony_nc_value *item =
975 container_of(attr, struct sony_nc_value, devattr);
976
977 if (!*item->acpiget)
978 return -EIO;
979
980 ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiget, NULL,
981 &value);
982 if (ret < 0)
983 return -EIO;
984
985 if (item->validate)
986 value = item->validate(SNC_VALIDATE_OUT, value);
987
988 return snprintf(buffer, PAGE_SIZE, "%d\n", value);
989}
990
991static ssize_t sony_nc_sysfs_store(struct device *dev,
992 struct device_attribute *attr,
993 const char *buffer, size_t count)
994{
995 int value;
996 int ret = 0;
997 struct sony_nc_value *item =
998 container_of(attr, struct sony_nc_value, devattr);
999
1000 if (!item->acpiset)
1001 return -EIO;
1002
1003 if (count > 31)
1004 return -EINVAL;
1005
1006 if (kstrtoint(buffer, 10, &value))
1007 return -EINVAL;
1008
1009 if (item->validate)
1010 value = item->validate(SNC_VALIDATE_IN, value);
1011
1012 if (value < 0)
1013 return value;
1014
1015 ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
1016 &value, NULL);
1017 if (ret < 0)
1018 return -EIO;
1019
1020 item->value = value;
1021 item->valid = 1;
1022 return count;
1023}
1024
1025
1026
1027
1028
1029struct sony_backlight_props {
1030 struct backlight_device *dev;
1031 int handle;
1032 int cmd_base;
1033 u8 offset;
1034 u8 maxlvl;
1035};
1036struct sony_backlight_props sony_bl_props;
1037
1038static int sony_backlight_update_status(struct backlight_device *bd)
1039{
1040 int arg = bd->props.brightness + 1;
1041 return sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &arg, NULL);
1042}
1043
1044static int sony_backlight_get_brightness(struct backlight_device *bd)
1045{
1046 int value;
1047
1048 if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, &value))
1049 return 0;
1050
1051 return value - 1;
1052}
1053
1054static int sony_nc_get_brightness_ng(struct backlight_device *bd)
1055{
1056 int result;
1057 struct sony_backlight_props *sdev =
1058 (struct sony_backlight_props *)bl_get_data(bd);
1059
1060 sony_call_snc_handle(sdev->handle, sdev->cmd_base + 0x100, &result);
1061
1062 return (result & 0xff) - sdev->offset;
1063}
1064
1065static int sony_nc_update_status_ng(struct backlight_device *bd)
1066{
1067 int value, result;
1068 struct sony_backlight_props *sdev =
1069 (struct sony_backlight_props *)bl_get_data(bd);
1070
1071 value = bd->props.brightness + sdev->offset;
1072 if (sony_call_snc_handle(sdev->handle, sdev->cmd_base | (value << 0x10),
1073 &result))
1074 return -EIO;
1075
1076 return value;
1077}
1078
1079static const struct backlight_ops sony_backlight_ops = {
1080 .options = BL_CORE_SUSPENDRESUME,
1081 .update_status = sony_backlight_update_status,
1082 .get_brightness = sony_backlight_get_brightness,
1083};
1084static const struct backlight_ops sony_backlight_ng_ops = {
1085 .options = BL_CORE_SUSPENDRESUME,
1086 .update_status = sony_nc_update_status_ng,
1087 .get_brightness = sony_nc_get_brightness_ng,
1088};
1089
1090
1091
1092
1093struct sony_nc_event {
1094 u8 data;
1095 u8 event;
1096};
1097
1098static struct sony_nc_event sony_100_events[] = {
1099 { 0x90, SONYPI_EVENT_PKEY_P1 },
1100 { 0x10, SONYPI_EVENT_ANYBUTTON_RELEASED },
1101 { 0x91, SONYPI_EVENT_PKEY_P2 },
1102 { 0x11, SONYPI_EVENT_ANYBUTTON_RELEASED },
1103 { 0x81, SONYPI_EVENT_FNKEY_F1 },
1104 { 0x01, SONYPI_EVENT_FNKEY_RELEASED },
1105 { 0x82, SONYPI_EVENT_FNKEY_F2 },
1106 { 0x02, SONYPI_EVENT_FNKEY_RELEASED },
1107 { 0x83, SONYPI_EVENT_FNKEY_F3 },
1108 { 0x03, SONYPI_EVENT_FNKEY_RELEASED },
1109 { 0x84, SONYPI_EVENT_FNKEY_F4 },
1110 { 0x04, SONYPI_EVENT_FNKEY_RELEASED },
1111 { 0x85, SONYPI_EVENT_FNKEY_F5 },
1112 { 0x05, SONYPI_EVENT_FNKEY_RELEASED },
1113 { 0x86, SONYPI_EVENT_FNKEY_F6 },
1114 { 0x06, SONYPI_EVENT_FNKEY_RELEASED },
1115 { 0x87, SONYPI_EVENT_FNKEY_F7 },
1116 { 0x07, SONYPI_EVENT_FNKEY_RELEASED },
1117 { 0x88, SONYPI_EVENT_FNKEY_F8 },
1118 { 0x08, SONYPI_EVENT_FNKEY_RELEASED },
1119 { 0x89, SONYPI_EVENT_FNKEY_F9 },
1120 { 0x09, SONYPI_EVENT_FNKEY_RELEASED },
1121 { 0x8A, SONYPI_EVENT_FNKEY_F10 },
1122 { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
1123 { 0x8B, SONYPI_EVENT_FNKEY_F11 },
1124 { 0x0B, SONYPI_EVENT_FNKEY_RELEASED },
1125 { 0x8C, SONYPI_EVENT_FNKEY_F12 },
1126 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
1127 { 0x9d, SONYPI_EVENT_ZOOM_PRESSED },
1128 { 0x1d, SONYPI_EVENT_ANYBUTTON_RELEASED },
1129 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
1130 { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED },
1131 { 0xa1, SONYPI_EVENT_MEDIA_PRESSED },
1132 { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED },
1133 { 0xa4, SONYPI_EVENT_CD_EJECT_PRESSED },
1134 { 0x24, SONYPI_EVENT_ANYBUTTON_RELEASED },
1135 { 0xa5, SONYPI_EVENT_VENDOR_PRESSED },
1136 { 0x25, SONYPI_EVENT_ANYBUTTON_RELEASED },
1137 { 0xa6, SONYPI_EVENT_HELP_PRESSED },
1138 { 0x26, SONYPI_EVENT_ANYBUTTON_RELEASED },
1139 { 0xa8, SONYPI_EVENT_FNKEY_1 },
1140 { 0x28, SONYPI_EVENT_ANYBUTTON_RELEASED },
1141 { 0, 0 },
1142};
1143
1144static struct sony_nc_event sony_127_events[] = {
1145 { 0x81, SONYPI_EVENT_MODEKEY_PRESSED },
1146 { 0x01, SONYPI_EVENT_ANYBUTTON_RELEASED },
1147 { 0x82, SONYPI_EVENT_PKEY_P1 },
1148 { 0x02, SONYPI_EVENT_ANYBUTTON_RELEASED },
1149 { 0x83, SONYPI_EVENT_PKEY_P2 },
1150 { 0x03, SONYPI_EVENT_ANYBUTTON_RELEASED },
1151 { 0x84, SONYPI_EVENT_PKEY_P3 },
1152 { 0x04, SONYPI_EVENT_ANYBUTTON_RELEASED },
1153 { 0x85, SONYPI_EVENT_PKEY_P4 },
1154 { 0x05, SONYPI_EVENT_ANYBUTTON_RELEASED },
1155 { 0x86, SONYPI_EVENT_PKEY_P5 },
1156 { 0x06, SONYPI_EVENT_ANYBUTTON_RELEASED },
1157 { 0x87, SONYPI_EVENT_SETTINGKEY_PRESSED },
1158 { 0x07, SONYPI_EVENT_ANYBUTTON_RELEASED },
1159 { 0, 0 },
1160};
1161
1162static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
1163{
1164 int ret = -EINVAL;
1165 unsigned int result = 0;
1166 struct sony_nc_event *key_event;
1167
1168 if (sony_call_snc_handle(handle, 0x200, &result)) {
1169 dprintk("Unable to decode event 0x%.2x 0x%.2x\n", handle,
1170 event);
1171 return -EINVAL;
1172 }
1173
1174 result &= 0xFF;
1175
1176 if (handle == 0x0100)
1177 key_event = sony_100_events;
1178 else
1179 key_event = sony_127_events;
1180
1181 for (; key_event->data; key_event++) {
1182 if (key_event->data == result) {
1183 ret = key_event->event;
1184 break;
1185 }
1186 }
1187
1188 if (!key_event->data)
1189 pr_info("Unknown hotkey 0x%.2x/0x%.2x (handle 0x%.2x)\n",
1190 event, result, handle);
1191
1192 return ret;
1193}
1194
1195
1196
1197
1198enum event_types {
1199 HOTKEY = 1,
1200 KILLSWITCH,
1201 GFX_SWITCH
1202};
1203static void sony_nc_notify(struct acpi_device *device, u32 event)
1204{
1205 u32 real_ev = event;
1206 u8 ev_type = 0;
1207 dprintk("sony_nc_notify, event: 0x%.2x\n", event);
1208
1209 if (event >= 0x90) {
1210 unsigned int result = 0;
1211 unsigned int arg = 0;
1212 unsigned int handle = 0;
1213 unsigned int offset = event - 0x90;
1214
1215 if (offset >= ARRAY_SIZE(handles->cap)) {
1216 pr_err("Event 0x%x outside of capabilities list\n",
1217 event);
1218 return;
1219 }
1220 handle = handles->cap[offset];
1221
1222
1223 switch (handle) {
1224
1225 case 0x0100:
1226 case 0x0127:
1227 ev_type = HOTKEY;
1228 real_ev = sony_nc_hotkeys_decode(event, handle);
1229
1230 if (real_ev > 0)
1231 sony_laptop_report_input_event(real_ev);
1232 else
1233
1234 real_ev = event;
1235
1236 break;
1237
1238
1239 case 0x0124:
1240 case 0x0135:
1241
1242
1243
1244
1245
1246
1247 ev_type = KILLSWITCH;
1248 sony_call_snc_handle(handle, 0x0100, &result);
1249 real_ev = result & 0x03;
1250
1251
1252 if (real_ev == 1)
1253 sony_nc_rfkill_update();
1254
1255 break;
1256
1257 case 0x0128:
1258 case 0x0146:
1259
1260 sony_call_snc_handle(handle, 0x0000, &result);
1261 dprintk("GFX switch event received (reason: %s)\n",
1262 (result == 0x1) ? "switch change" :
1263 (result == 0x2) ? "output switch" :
1264 (result == 0x3) ? "output switch" :
1265 "");
1266
1267 ev_type = GFX_SWITCH;
1268 real_ev = __sony_nc_gfx_switch_status_get();
1269 break;
1270
1271 case 0x015B:
1272
1273 ev_type = GFX_SWITCH;
1274 real_ev = __sony_nc_gfx_switch_status_get();
1275 break;
1276 default:
1277 dprintk("Unknown event 0x%x for handle 0x%x\n",
1278 event, handle);
1279 break;
1280 }
1281
1282
1283 arg = 1 << offset;
1284 sony_nc_int_call(sony_nc_acpi_handle, "SN05", &arg, &result);
1285
1286 } else {
1287
1288 ev_type = HOTKEY;
1289 sony_laptop_report_input_event(real_ev);
1290 }
1291 acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class,
1292 dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev);
1293}
1294
1295static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
1296 void *context, void **return_value)
1297{
1298 struct acpi_device_info *info;
1299
1300 if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
1301 pr_warn("method: name: %4.4s, args %X\n",
1302 (char *)&info->name, info->param_count);
1303
1304 kfree(info);
1305 }
1306
1307 return AE_OK;
1308}
1309
1310
1311
1312
1313static void sony_nc_function_setup(struct acpi_device *device,
1314 struct platform_device *pf_device)
1315{
1316 unsigned int i, result, bitmask, arg;
1317
1318 if (!handles)
1319 return;
1320
1321
1322 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1323 unsigned int handle = handles->cap[i];
1324
1325 if (!handle)
1326 continue;
1327
1328 dprintk("setting up handle 0x%.4x\n", handle);
1329
1330 switch (handle) {
1331 case 0x0100:
1332 case 0x0101:
1333 case 0x0127:
1334
1335 sony_call_snc_handle(handle, 0, &result);
1336 break;
1337 case 0x0102:
1338
1339 sony_call_snc_handle(handle, 0x100, &result);
1340 break;
1341 case 0x0105:
1342 case 0x0148:
1343
1344 result = sony_nc_touchpad_setup(pf_device, handle);
1345 if (result)
1346 pr_err("couldn't set up touchpad control function (%d)\n",
1347 result);
1348 break;
1349 case 0x0115:
1350 case 0x0136:
1351 case 0x013f:
1352 result = sony_nc_battery_care_setup(pf_device, handle);
1353 if (result)
1354 pr_err("couldn't set up battery care function (%d)\n",
1355 result);
1356 break;
1357 case 0x0119:
1358 case 0x015D:
1359 result = sony_nc_lid_resume_setup(pf_device, handle);
1360 if (result)
1361 pr_err("couldn't set up lid resume function (%d)\n",
1362 result);
1363 break;
1364 case 0x0122:
1365 result = sony_nc_thermal_setup(pf_device);
1366 if (result)
1367 pr_err("couldn't set up thermal profile function (%d)\n",
1368 result);
1369 break;
1370 case 0x0128:
1371 case 0x0146:
1372 case 0x015B:
1373 result = sony_nc_gfx_switch_setup(pf_device, handle);
1374 if (result)
1375 pr_err("couldn't set up GFX Switch status (%d)\n",
1376 result);
1377 break;
1378 case 0x0131:
1379 result = sony_nc_highspeed_charging_setup(pf_device);
1380 if (result)
1381 pr_err("couldn't set up high speed charging function (%d)\n",
1382 result);
1383 break;
1384 case 0x0124:
1385 case 0x0135:
1386 result = sony_nc_rfkill_setup(device, handle);
1387 if (result)
1388 pr_err("couldn't set up rfkill support (%d)\n",
1389 result);
1390 break;
1391 case 0x0137:
1392 case 0x0143:
1393 case 0x014b:
1394 case 0x014c:
1395 case 0x0163:
1396 result = sony_nc_kbd_backlight_setup(pf_device, handle);
1397 if (result)
1398 pr_err("couldn't set up keyboard backlight function (%d)\n",
1399 result);
1400 break;
1401 case 0x0121:
1402 result = sony_nc_lowbatt_setup(pf_device);
1403 if (result)
1404 pr_err("couldn't set up low battery function (%d)\n",
1405 result);
1406 break;
1407 case 0x0149:
1408 result = sony_nc_fanspeed_setup(pf_device);
1409 if (result)
1410 pr_err("couldn't set up fan speed function (%d)\n",
1411 result);
1412 break;
1413 case 0x0155:
1414 result = sony_nc_usb_charge_setup(pf_device);
1415 if (result)
1416 pr_err("couldn't set up USB charge support (%d)\n",
1417 result);
1418 break;
1419 case 0x011D:
1420 result = sony_nc_panelid_setup(pf_device);
1421 if (result)
1422 pr_err("couldn't set up panel ID function (%d)\n",
1423 result);
1424 break;
1425 case 0x0168:
1426 result = sony_nc_smart_conn_setup(pf_device);
1427 if (result)
1428 pr_err("couldn't set up smart connect support (%d)\n",
1429 result);
1430 break;
1431 default:
1432 continue;
1433 }
1434 }
1435
1436
1437 arg = 0x10;
1438 if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
1439 sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
1440 &result);
1441}
1442
1443static void sony_nc_function_cleanup(struct platform_device *pd)
1444{
1445 unsigned int i, result, bitmask, handle;
1446
1447
1448 sony_nc_int_call(sony_nc_acpi_handle, "SN01", NULL, &bitmask);
1449 sony_nc_int_call(sony_nc_acpi_handle, "SN03", &bitmask, &result);
1450
1451
1452 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1453
1454 handle = handles->cap[i];
1455
1456 if (!handle)
1457 continue;
1458
1459 switch (handle) {
1460 case 0x0105:
1461 case 0x0148:
1462 sony_nc_touchpad_cleanup(pd);
1463 break;
1464 case 0x0115:
1465 case 0x0136:
1466 case 0x013f:
1467 sony_nc_battery_care_cleanup(pd);
1468 break;
1469 case 0x0119:
1470 case 0x015D:
1471 sony_nc_lid_resume_cleanup(pd);
1472 break;
1473 case 0x0122:
1474 sony_nc_thermal_cleanup(pd);
1475 break;
1476 case 0x0128:
1477 case 0x0146:
1478 case 0x015B:
1479 sony_nc_gfx_switch_cleanup(pd);
1480 break;
1481 case 0x0131:
1482 sony_nc_highspeed_charging_cleanup(pd);
1483 break;
1484 case 0x0124:
1485 case 0x0135:
1486 sony_nc_rfkill_cleanup();
1487 break;
1488 case 0x0137:
1489 case 0x0143:
1490 case 0x014b:
1491 case 0x014c:
1492 case 0x0163:
1493 sony_nc_kbd_backlight_cleanup(pd, handle);
1494 break;
1495 case 0x0121:
1496 sony_nc_lowbatt_cleanup(pd);
1497 break;
1498 case 0x0149:
1499 sony_nc_fanspeed_cleanup(pd);
1500 break;
1501 case 0x0155:
1502 sony_nc_usb_charge_cleanup(pd);
1503 break;
1504 case 0x011D:
1505 sony_nc_panelid_cleanup(pd);
1506 break;
1507 case 0x0168:
1508 sony_nc_smart_conn_cleanup(pd);
1509 break;
1510 default:
1511 continue;
1512 }
1513 }
1514
1515
1516 sony_nc_handles_cleanup(pd);
1517}
1518
1519#ifdef CONFIG_PM_SLEEP
1520static void sony_nc_function_resume(void)
1521{
1522 unsigned int i, result, bitmask, arg;
1523
1524 dprintk("Resuming SNC device\n");
1525
1526 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1527 unsigned int handle = handles->cap[i];
1528
1529 if (!handle)
1530 continue;
1531
1532 switch (handle) {
1533 case 0x0100:
1534 case 0x0101:
1535 case 0x0127:
1536
1537 sony_call_snc_handle(handle, 0, &result);
1538 break;
1539 case 0x0102:
1540
1541 sony_call_snc_handle(handle, 0x100, &result);
1542 break;
1543 case 0x0122:
1544 sony_nc_thermal_resume();
1545 break;
1546 case 0x0124:
1547 case 0x0135:
1548 sony_nc_rfkill_update();
1549 break;
1550 default:
1551 continue;
1552 }
1553 }
1554
1555
1556 arg = 0x10;
1557 if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
1558 sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
1559 &result);
1560}
1561
1562static int sony_nc_resume(struct device *dev)
1563{
1564 struct sony_nc_value *item;
1565
1566 for (item = sony_nc_values; item->name; item++) {
1567 int ret;
1568
1569 if (!item->valid)
1570 continue;
1571 ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
1572 &item->value, NULL);
1573 if (ret < 0) {
1574 pr_err("%s: %d\n", __func__, ret);
1575 break;
1576 }
1577 }
1578
1579 if (acpi_has_method(sony_nc_acpi_handle, "ECON")) {
1580 int arg = 1;
1581 if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
1582 dprintk("ECON Method failed\n");
1583 }
1584
1585 if (acpi_has_method(sony_nc_acpi_handle, "SN00"))
1586 sony_nc_function_resume();
1587
1588 return 0;
1589}
1590#endif
1591
1592static SIMPLE_DEV_PM_OPS(sony_nc_pm, NULL, sony_nc_resume);
1593
1594static void sony_nc_rfkill_cleanup(void)
1595{
1596 int i;
1597
1598 for (i = 0; i < N_SONY_RFKILL; i++) {
1599 if (sony_rfkill_devices[i]) {
1600 rfkill_unregister(sony_rfkill_devices[i]);
1601 rfkill_destroy(sony_rfkill_devices[i]);
1602 }
1603 }
1604}
1605
1606static int sony_nc_rfkill_set(void *data, bool blocked)
1607{
1608 int result;
1609 int argument = sony_rfkill_address[(long) data] + 0x100;
1610
1611 if (!blocked)
1612 argument |= 0x070000;
1613
1614 return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1615}
1616
1617static const struct rfkill_ops sony_rfkill_ops = {
1618 .set_block = sony_nc_rfkill_set,
1619};
1620
1621static int sony_nc_setup_rfkill(struct acpi_device *device,
1622 enum sony_nc_rfkill nc_type)
1623{
1624 int err = 0;
1625 struct rfkill *rfk;
1626 enum rfkill_type type;
1627 const char *name;
1628 int result;
1629 bool hwblock, swblock;
1630
1631 switch (nc_type) {
1632 case SONY_WIFI:
1633 type = RFKILL_TYPE_WLAN;
1634 name = "sony-wifi";
1635 break;
1636 case SONY_BLUETOOTH:
1637 type = RFKILL_TYPE_BLUETOOTH;
1638 name = "sony-bluetooth";
1639 break;
1640 case SONY_WWAN:
1641 type = RFKILL_TYPE_WWAN;
1642 name = "sony-wwan";
1643 break;
1644 case SONY_WIMAX:
1645 type = RFKILL_TYPE_WIMAX;
1646 name = "sony-wimax";
1647 break;
1648 default:
1649 return -EINVAL;
1650 }
1651
1652 rfk = rfkill_alloc(name, &device->dev, type,
1653 &sony_rfkill_ops, (void *)nc_type);
1654 if (!rfk)
1655 return -ENOMEM;
1656
1657 if (sony_call_snc_handle(sony_rfkill_handle, 0x200, &result) < 0) {
1658 rfkill_destroy(rfk);
1659 return -1;
1660 }
1661 hwblock = !(result & 0x1);
1662
1663 if (sony_call_snc_handle(sony_rfkill_handle,
1664 sony_rfkill_address[nc_type],
1665 &result) < 0) {
1666 rfkill_destroy(rfk);
1667 return -1;
1668 }
1669 swblock = !(result & 0x2);
1670
1671 rfkill_init_sw_state(rfk, swblock);
1672 rfkill_set_hw_state(rfk, hwblock);
1673
1674 err = rfkill_register(rfk);
1675 if (err) {
1676 rfkill_destroy(rfk);
1677 return err;
1678 }
1679 sony_rfkill_devices[nc_type] = rfk;
1680 return err;
1681}
1682
1683static void sony_nc_rfkill_update(void)
1684{
1685 enum sony_nc_rfkill i;
1686 int result;
1687 bool hwblock;
1688
1689 sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1690 hwblock = !(result & 0x1);
1691
1692 for (i = 0; i < N_SONY_RFKILL; i++) {
1693 int argument = sony_rfkill_address[i];
1694
1695 if (!sony_rfkill_devices[i])
1696 continue;
1697
1698 if (hwblock) {
1699 if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) {
1700
1701 }
1702 continue;
1703 }
1704
1705 sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1706 rfkill_set_states(sony_rfkill_devices[i],
1707 !(result & 0x2), false);
1708 }
1709}
1710
1711static int sony_nc_rfkill_setup(struct acpi_device *device,
1712 unsigned int handle)
1713{
1714 u64 offset;
1715 int i;
1716 unsigned char buffer[32] = { 0 };
1717
1718 offset = sony_find_snc_handle(handle);
1719 sony_rfkill_handle = handle;
1720
1721 i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
1722 32);
1723 if (i < 0)
1724 return i;
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745 for (i = 0; i < ARRAY_SIZE(buffer); i++) {
1746
1747 if (buffer[i] == 0xff)
1748 break;
1749
1750 dprintk("Radio devices, found 0x%.2x\n", buffer[i]);
1751
1752 if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI])
1753 sony_nc_setup_rfkill(device, SONY_WIFI);
1754
1755 if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
1756 sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
1757
1758 if (((0xf0 & buffer[i]) == 0x20 ||
1759 (0xf0 & buffer[i]) == 0x50) &&
1760 !sony_rfkill_devices[SONY_WWAN])
1761 sony_nc_setup_rfkill(device, SONY_WWAN);
1762
1763 if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
1764 sony_nc_setup_rfkill(device, SONY_WIMAX);
1765 }
1766 return 0;
1767}
1768
1769
1770struct kbd_backlight {
1771 unsigned int handle;
1772 unsigned int base;
1773 unsigned int mode;
1774 unsigned int timeout;
1775 struct device_attribute mode_attr;
1776 struct device_attribute timeout_attr;
1777};
1778
1779static struct kbd_backlight *kbdbl_ctl;
1780
1781static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1782{
1783 int result;
1784
1785 if (value > 2)
1786 return -EINVAL;
1787
1788 if (sony_call_snc_handle(kbdbl_ctl->handle,
1789 (value << 0x10) | (kbdbl_ctl->base), &result))
1790 return -EIO;
1791
1792
1793 if (value != 1)
1794 sony_call_snc_handle(kbdbl_ctl->handle,
1795 (value << 0x0f) | (kbdbl_ctl->base + 0x100),
1796 &result);
1797
1798 kbdbl_ctl->mode = value;
1799
1800 return 0;
1801}
1802
1803static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
1804 struct device_attribute *attr,
1805 const char *buffer, size_t count)
1806{
1807 int ret = 0;
1808 unsigned long value;
1809
1810 if (count > 31)
1811 return -EINVAL;
1812
1813 if (kstrtoul(buffer, 10, &value))
1814 return -EINVAL;
1815
1816 ret = __sony_nc_kbd_backlight_mode_set(value);
1817 if (ret < 0)
1818 return ret;
1819
1820 return count;
1821}
1822
1823static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
1824 struct device_attribute *attr, char *buffer)
1825{
1826 ssize_t count = 0;
1827 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->mode);
1828 return count;
1829}
1830
1831static int __sony_nc_kbd_backlight_timeout_set(u8 value)
1832{
1833 int result;
1834
1835 if (value > 3)
1836 return -EINVAL;
1837
1838 if (sony_call_snc_handle(kbdbl_ctl->handle, (value << 0x10) |
1839 (kbdbl_ctl->base + 0x200), &result))
1840 return -EIO;
1841
1842 kbdbl_ctl->timeout = value;
1843
1844 return 0;
1845}
1846
1847static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
1848 struct device_attribute *attr,
1849 const char *buffer, size_t count)
1850{
1851 int ret = 0;
1852 unsigned long value;
1853
1854 if (count > 31)
1855 return -EINVAL;
1856
1857 if (kstrtoul(buffer, 10, &value))
1858 return -EINVAL;
1859
1860 ret = __sony_nc_kbd_backlight_timeout_set(value);
1861 if (ret < 0)
1862 return ret;
1863
1864 return count;
1865}
1866
1867static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
1868 struct device_attribute *attr, char *buffer)
1869{
1870 ssize_t count = 0;
1871 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->timeout);
1872 return count;
1873}
1874
1875static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
1876 unsigned int handle)
1877{
1878 int result;
1879 int ret = 0;
1880
1881 if (kbdbl_ctl) {
1882 pr_warn("handle 0x%.4x: keyboard backlight setup already done for 0x%.4x\n",
1883 handle, kbdbl_ctl->handle);
1884 return -EBUSY;
1885 }
1886
1887
1888
1889
1890 ret = sony_call_snc_handle(handle, handle == 0x0137 ? 0x0B00 : 0x0100,
1891 &result);
1892 if (ret)
1893 return ret;
1894
1895 if ((handle == 0x0137 && !(result & 0x02)) ||
1896 !(result & 0x01)) {
1897 dprintk("no backlight keyboard found\n");
1898 return 0;
1899 }
1900
1901 kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL);
1902 if (!kbdbl_ctl)
1903 return -ENOMEM;
1904
1905 kbdbl_ctl->mode = kbd_backlight;
1906 kbdbl_ctl->timeout = kbd_backlight_timeout;
1907 kbdbl_ctl->handle = handle;
1908 if (handle == 0x0137)
1909 kbdbl_ctl->base = 0x0C00;
1910 else
1911 kbdbl_ctl->base = 0x4000;
1912
1913 sysfs_attr_init(&kbdbl_ctl->mode_attr.attr);
1914 kbdbl_ctl->mode_attr.attr.name = "kbd_backlight";
1915 kbdbl_ctl->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
1916 kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show;
1917 kbdbl_ctl->mode_attr.store = sony_nc_kbd_backlight_mode_store;
1918
1919 sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr);
1920 kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout";
1921 kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
1922 kbdbl_ctl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
1923 kbdbl_ctl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
1924
1925 ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr);
1926 if (ret)
1927 goto outkzalloc;
1928
1929 ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr);
1930 if (ret)
1931 goto outmode;
1932
1933 __sony_nc_kbd_backlight_mode_set(kbdbl_ctl->mode);
1934 __sony_nc_kbd_backlight_timeout_set(kbdbl_ctl->timeout);
1935
1936 return 0;
1937
1938outmode:
1939 device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
1940outkzalloc:
1941 kfree(kbdbl_ctl);
1942 kbdbl_ctl = NULL;
1943 return ret;
1944}
1945
1946static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd,
1947 unsigned int handle)
1948{
1949 if (kbdbl_ctl && handle == kbdbl_ctl->handle) {
1950 device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
1951 device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr);
1952 kfree(kbdbl_ctl);
1953 kbdbl_ctl = NULL;
1954 }
1955}
1956
1957struct battery_care_control {
1958 struct device_attribute attrs[2];
1959 unsigned int handle;
1960};
1961static struct battery_care_control *bcare_ctl;
1962
1963static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
1964 struct device_attribute *attr,
1965 const char *buffer, size_t count)
1966{
1967 unsigned int result, cmd;
1968 unsigned long value;
1969
1970 if (count > 31)
1971 return -EINVAL;
1972
1973 if (kstrtoul(buffer, 10, &value))
1974 return -EINVAL;
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988 cmd = 0;
1989
1990 if (value > 0) {
1991 if (value <= 50)
1992 cmd = 0x20;
1993
1994 else if (value <= 80)
1995 cmd = 0x10;
1996
1997 else if (value <= 100)
1998 cmd = 0x30;
1999
2000 else
2001 return -EINVAL;
2002
2003
2004
2005
2006
2007
2008 if (bcare_ctl->handle != 0x013f)
2009 cmd = cmd | (cmd << 2);
2010
2011 cmd = (cmd | 0x1) << 0x10;
2012 }
2013
2014 if (sony_call_snc_handle(bcare_ctl->handle, cmd | 0x0100, &result))
2015 return -EIO;
2016
2017 return count;
2018}
2019
2020static ssize_t sony_nc_battery_care_limit_show(struct device *dev,
2021 struct device_attribute *attr, char *buffer)
2022{
2023 unsigned int result, status;
2024
2025 if (sony_call_snc_handle(bcare_ctl->handle, 0x0000, &result))
2026 return -EIO;
2027
2028 status = (result & 0x01) ? ((result & 0x30) >> 0x04) : 0;
2029 switch (status) {
2030 case 1:
2031 status = 80;
2032 break;
2033 case 2:
2034 status = 50;
2035 break;
2036 case 3:
2037 status = 100;
2038 break;
2039 default:
2040 status = 0;
2041 break;
2042 }
2043
2044 return snprintf(buffer, PAGE_SIZE, "%d\n", status);
2045}
2046
2047static ssize_t sony_nc_battery_care_health_show(struct device *dev,
2048 struct device_attribute *attr, char *buffer)
2049{
2050 ssize_t count = 0;
2051 unsigned int health;
2052
2053 if (sony_call_snc_handle(bcare_ctl->handle, 0x0200, &health))
2054 return -EIO;
2055
2056 count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff);
2057
2058 return count;
2059}
2060
2061static int sony_nc_battery_care_setup(struct platform_device *pd,
2062 unsigned int handle)
2063{
2064 int ret = 0;
2065
2066 bcare_ctl = kzalloc(sizeof(struct battery_care_control), GFP_KERNEL);
2067 if (!bcare_ctl)
2068 return -ENOMEM;
2069
2070 bcare_ctl->handle = handle;
2071
2072 sysfs_attr_init(&bcare_ctl->attrs[0].attr);
2073 bcare_ctl->attrs[0].attr.name = "battery_care_limiter";
2074 bcare_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
2075 bcare_ctl->attrs[0].show = sony_nc_battery_care_limit_show;
2076 bcare_ctl->attrs[0].store = sony_nc_battery_care_limit_store;
2077
2078 ret = device_create_file(&pd->dev, &bcare_ctl->attrs[0]);
2079 if (ret)
2080 goto outkzalloc;
2081
2082
2083 if (handle == 0x0115)
2084 return 0;
2085
2086 sysfs_attr_init(&bcare_ctl->attrs[1].attr);
2087 bcare_ctl->attrs[1].attr.name = "battery_care_health";
2088 bcare_ctl->attrs[1].attr.mode = S_IRUGO;
2089 bcare_ctl->attrs[1].show = sony_nc_battery_care_health_show;
2090
2091 ret = device_create_file(&pd->dev, &bcare_ctl->attrs[1]);
2092 if (ret)
2093 goto outlimiter;
2094
2095 return 0;
2096
2097outlimiter:
2098 device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
2099
2100outkzalloc:
2101 kfree(bcare_ctl);
2102 bcare_ctl = NULL;
2103
2104 return ret;
2105}
2106
2107static void sony_nc_battery_care_cleanup(struct platform_device *pd)
2108{
2109 if (bcare_ctl) {
2110 device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
2111 if (bcare_ctl->handle != 0x0115)
2112 device_remove_file(&pd->dev, &bcare_ctl->attrs[1]);
2113
2114 kfree(bcare_ctl);
2115 bcare_ctl = NULL;
2116 }
2117}
2118
2119struct snc_thermal_ctrl {
2120 unsigned int mode;
2121 unsigned int profiles;
2122 struct device_attribute mode_attr;
2123 struct device_attribute profiles_attr;
2124};
2125static struct snc_thermal_ctrl *th_handle;
2126
2127#define THM_PROFILE_MAX 3
2128static const char * const snc_thermal_profiles[] = {
2129 "balanced",
2130 "silent",
2131 "performance"
2132};
2133
2134static int sony_nc_thermal_mode_set(unsigned short mode)
2135{
2136 unsigned int result;
2137
2138
2139
2140
2141
2142
2143
2144 if ((mode && !(th_handle->profiles & mode)) || mode >= THM_PROFILE_MAX)
2145 return -EINVAL;
2146
2147 if (sony_call_snc_handle(0x0122, mode << 0x10 | 0x0200, &result))
2148 return -EIO;
2149
2150 th_handle->mode = mode;
2151
2152 return 0;
2153}
2154
2155static int sony_nc_thermal_mode_get(void)
2156{
2157 unsigned int result;
2158
2159 if (sony_call_snc_handle(0x0122, 0x0100, &result))
2160 return -EIO;
2161
2162 return result & 0xff;
2163}
2164
2165static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
2166 struct device_attribute *attr, char *buffer)
2167{
2168 short cnt;
2169 size_t idx = 0;
2170
2171 for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) {
2172 if (!cnt || (th_handle->profiles & cnt))
2173 idx += snprintf(buffer + idx, PAGE_SIZE - idx, "%s ",
2174 snc_thermal_profiles[cnt]);
2175 }
2176 idx += snprintf(buffer + idx, PAGE_SIZE - idx, "\n");
2177
2178 return idx;
2179}
2180
2181static ssize_t sony_nc_thermal_mode_store(struct device *dev,
2182 struct device_attribute *attr,
2183 const char *buffer, size_t count)
2184{
2185 unsigned short cmd;
2186 size_t len = count;
2187
2188 if (count == 0)
2189 return -EINVAL;
2190
2191
2192 if (buffer[len - 1] == '\n')
2193 len--;
2194
2195 for (cmd = 0; cmd < THM_PROFILE_MAX; cmd++)
2196 if (strncmp(buffer, snc_thermal_profiles[cmd], len) == 0)
2197 break;
2198
2199 if (sony_nc_thermal_mode_set(cmd))
2200 return -EIO;
2201
2202 return count;
2203}
2204
2205static ssize_t sony_nc_thermal_mode_show(struct device *dev,
2206 struct device_attribute *attr, char *buffer)
2207{
2208 ssize_t count = 0;
2209 int mode = sony_nc_thermal_mode_get();
2210
2211 if (mode < 0)
2212 return mode;
2213
2214 count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]);
2215
2216 return count;
2217}
2218
2219static int sony_nc_thermal_setup(struct platform_device *pd)
2220{
2221 int ret = 0;
2222 th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL);
2223 if (!th_handle)
2224 return -ENOMEM;
2225
2226 ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles);
2227 if (ret) {
2228 pr_warn("couldn't to read the thermal profiles\n");
2229 goto outkzalloc;
2230 }
2231
2232 ret = sony_nc_thermal_mode_get();
2233 if (ret < 0) {
2234 pr_warn("couldn't to read the current thermal profile");
2235 goto outkzalloc;
2236 }
2237 th_handle->mode = ret;
2238
2239 sysfs_attr_init(&th_handle->profiles_attr.attr);
2240 th_handle->profiles_attr.attr.name = "thermal_profiles";
2241 th_handle->profiles_attr.attr.mode = S_IRUGO;
2242 th_handle->profiles_attr.show = sony_nc_thermal_profiles_show;
2243
2244 sysfs_attr_init(&th_handle->mode_attr.attr);
2245 th_handle->mode_attr.attr.name = "thermal_control";
2246 th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
2247 th_handle->mode_attr.show = sony_nc_thermal_mode_show;
2248 th_handle->mode_attr.store = sony_nc_thermal_mode_store;
2249
2250 ret = device_create_file(&pd->dev, &th_handle->profiles_attr);
2251 if (ret)
2252 goto outkzalloc;
2253
2254 ret = device_create_file(&pd->dev, &th_handle->mode_attr);
2255 if (ret)
2256 goto outprofiles;
2257
2258 return 0;
2259
2260outprofiles:
2261 device_remove_file(&pd->dev, &th_handle->profiles_attr);
2262outkzalloc:
2263 kfree(th_handle);
2264 th_handle = NULL;
2265 return ret;
2266}
2267
2268static void sony_nc_thermal_cleanup(struct platform_device *pd)
2269{
2270 if (th_handle) {
2271 device_remove_file(&pd->dev, &th_handle->profiles_attr);
2272 device_remove_file(&pd->dev, &th_handle->mode_attr);
2273 kfree(th_handle);
2274 th_handle = NULL;
2275 }
2276}
2277
2278#ifdef CONFIG_PM_SLEEP
2279static void sony_nc_thermal_resume(void)
2280{
2281 unsigned int status = sony_nc_thermal_mode_get();
2282
2283 if (status != th_handle->mode)
2284 sony_nc_thermal_mode_set(th_handle->mode);
2285}
2286#endif
2287
2288
2289#define LID_RESUME_S5 0
2290#define LID_RESUME_S4 1
2291#define LID_RESUME_S3 2
2292#define LID_RESUME_MAX 3
2293struct snc_lid_resume_control {
2294 struct device_attribute attrs[LID_RESUME_MAX];
2295 unsigned int status;
2296 int handle;
2297};
2298static struct snc_lid_resume_control *lid_ctl;
2299
2300static ssize_t sony_nc_lid_resume_store(struct device *dev,
2301 struct device_attribute *attr,
2302 const char *buffer, size_t count)
2303{
2304 unsigned int result;
2305 unsigned long value;
2306 unsigned int pos = LID_RESUME_S5;
2307 if (count > 31)
2308 return -EINVAL;
2309
2310 if (kstrtoul(buffer, 10, &value) || value > 1)
2311 return -EINVAL;
2312
2313
2314
2315
2316
2317
2318
2319 while (pos < LID_RESUME_MAX) {
2320 if (&lid_ctl->attrs[pos].attr == &attr->attr)
2321 break;
2322 pos++;
2323 }
2324 if (pos == LID_RESUME_MAX)
2325 return -EINVAL;
2326
2327 if (value)
2328 value = lid_ctl->status | (1 << pos);
2329 else
2330 value = lid_ctl->status & ~(1 << pos);
2331
2332 if (sony_call_snc_handle(lid_ctl->handle, value << 0x10 | 0x0100,
2333 &result))
2334 return -EIO;
2335
2336 lid_ctl->status = value;
2337
2338 return count;
2339}
2340
2341static ssize_t sony_nc_lid_resume_show(struct device *dev,
2342 struct device_attribute *attr,
2343 char *buffer)
2344{
2345 unsigned int pos = LID_RESUME_S5;
2346
2347 while (pos < LID_RESUME_MAX) {
2348 if (&lid_ctl->attrs[pos].attr == &attr->attr)
2349 return snprintf(buffer, PAGE_SIZE, "%d\n",
2350 (lid_ctl->status >> pos) & 0x01);
2351 pos++;
2352 }
2353 return -EINVAL;
2354}
2355
2356static int sony_nc_lid_resume_setup(struct platform_device *pd,
2357 unsigned int handle)
2358{
2359 unsigned int result;
2360 int i;
2361
2362 if (sony_call_snc_handle(handle, 0x0000, &result))
2363 return -EIO;
2364
2365 lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL);
2366 if (!lid_ctl)
2367 return -ENOMEM;
2368
2369 lid_ctl->status = result & 0x7;
2370 lid_ctl->handle = handle;
2371
2372 sysfs_attr_init(&lid_ctl->attrs[0].attr);
2373 lid_ctl->attrs[LID_RESUME_S5].attr.name = "lid_resume_S5";
2374 lid_ctl->attrs[LID_RESUME_S5].attr.mode = S_IRUGO | S_IWUSR;
2375 lid_ctl->attrs[LID_RESUME_S5].show = sony_nc_lid_resume_show;
2376 lid_ctl->attrs[LID_RESUME_S5].store = sony_nc_lid_resume_store;
2377
2378 if (handle == 0x0119) {
2379 sysfs_attr_init(&lid_ctl->attrs[1].attr);
2380 lid_ctl->attrs[LID_RESUME_S4].attr.name = "lid_resume_S4";
2381 lid_ctl->attrs[LID_RESUME_S4].attr.mode = S_IRUGO | S_IWUSR;
2382 lid_ctl->attrs[LID_RESUME_S4].show = sony_nc_lid_resume_show;
2383 lid_ctl->attrs[LID_RESUME_S4].store = sony_nc_lid_resume_store;
2384
2385 sysfs_attr_init(&lid_ctl->attrs[2].attr);
2386 lid_ctl->attrs[LID_RESUME_S3].attr.name = "lid_resume_S3";
2387 lid_ctl->attrs[LID_RESUME_S3].attr.mode = S_IRUGO | S_IWUSR;
2388 lid_ctl->attrs[LID_RESUME_S3].show = sony_nc_lid_resume_show;
2389 lid_ctl->attrs[LID_RESUME_S3].store = sony_nc_lid_resume_store;
2390 }
2391 for (i = 0; i < LID_RESUME_MAX &&
2392 lid_ctl->attrs[LID_RESUME_S3].attr.name; i++) {
2393 result = device_create_file(&pd->dev, &lid_ctl->attrs[i]);
2394 if (result)
2395 goto liderror;
2396 }
2397
2398 return 0;
2399
2400liderror:
2401 for (i--; i >= 0; i--)
2402 device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2403
2404 kfree(lid_ctl);
2405 lid_ctl = NULL;
2406
2407 return result;
2408}
2409
2410static void sony_nc_lid_resume_cleanup(struct platform_device *pd)
2411{
2412 int i;
2413
2414 if (lid_ctl) {
2415 for (i = 0; i < LID_RESUME_MAX; i++) {
2416 if (!lid_ctl->attrs[i].attr.name)
2417 break;
2418
2419 device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2420 }
2421
2422 kfree(lid_ctl);
2423 lid_ctl = NULL;
2424 }
2425}
2426
2427
2428enum gfx_switch {
2429 SPEED,
2430 STAMINA,
2431 AUTO
2432};
2433struct snc_gfx_switch_control {
2434 struct device_attribute attr;
2435 unsigned int handle;
2436};
2437static struct snc_gfx_switch_control *gfxs_ctl;
2438
2439
2440static int __sony_nc_gfx_switch_status_get(void)
2441{
2442 unsigned int result;
2443
2444 if (sony_call_snc_handle(gfxs_ctl->handle,
2445 gfxs_ctl->handle == 0x015B ? 0x0000 : 0x0100,
2446 &result))
2447 return -EIO;
2448
2449 switch (gfxs_ctl->handle) {
2450 case 0x0146:
2451
2452
2453
2454 return result & 0x1 ? SPEED : STAMINA;
2455 break;
2456 case 0x015B:
2457
2458
2459
2460 return result & 0x1 ? STAMINA : SPEED;
2461 break;
2462 case 0x0128:
2463
2464
2465
2466
2467 dprintk("GFX Status: 0x%x\n", result);
2468 return result & 0x80 ? AUTO :
2469 result & 0x02 ? STAMINA : SPEED;
2470 break;
2471 }
2472 return -EINVAL;
2473}
2474
2475static ssize_t sony_nc_gfx_switch_status_show(struct device *dev,
2476 struct device_attribute *attr,
2477 char *buffer)
2478{
2479 int pos = __sony_nc_gfx_switch_status_get();
2480
2481 if (pos < 0)
2482 return pos;
2483
2484 return snprintf(buffer, PAGE_SIZE, "%s\n",
2485 pos == SPEED ? "speed" :
2486 pos == STAMINA ? "stamina" :
2487 pos == AUTO ? "auto" : "unknown");
2488}
2489
2490static int sony_nc_gfx_switch_setup(struct platform_device *pd,
2491 unsigned int handle)
2492{
2493 unsigned int result;
2494
2495 gfxs_ctl = kzalloc(sizeof(struct snc_gfx_switch_control), GFP_KERNEL);
2496 if (!gfxs_ctl)
2497 return -ENOMEM;
2498
2499 gfxs_ctl->handle = handle;
2500
2501 sysfs_attr_init(&gfxs_ctl->attr.attr);
2502 gfxs_ctl->attr.attr.name = "gfx_switch_status";
2503 gfxs_ctl->attr.attr.mode = S_IRUGO;
2504 gfxs_ctl->attr.show = sony_nc_gfx_switch_status_show;
2505
2506 result = device_create_file(&pd->dev, &gfxs_ctl->attr);
2507 if (result)
2508 goto gfxerror;
2509
2510 return 0;
2511
2512gfxerror:
2513 kfree(gfxs_ctl);
2514 gfxs_ctl = NULL;
2515
2516 return result;
2517}
2518
2519static void sony_nc_gfx_switch_cleanup(struct platform_device *pd)
2520{
2521 if (gfxs_ctl) {
2522 device_remove_file(&pd->dev, &gfxs_ctl->attr);
2523
2524 kfree(gfxs_ctl);
2525 gfxs_ctl = NULL;
2526 }
2527}
2528
2529
2530static struct device_attribute *hsc_handle;
2531
2532static ssize_t sony_nc_highspeed_charging_store(struct device *dev,
2533 struct device_attribute *attr,
2534 const char *buffer, size_t count)
2535{
2536 unsigned int result;
2537 unsigned long value;
2538
2539 if (count > 31)
2540 return -EINVAL;
2541
2542 if (kstrtoul(buffer, 10, &value) || value > 1)
2543 return -EINVAL;
2544
2545 if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result))
2546 return -EIO;
2547
2548 return count;
2549}
2550
2551static ssize_t sony_nc_highspeed_charging_show(struct device *dev,
2552 struct device_attribute *attr, char *buffer)
2553{
2554 unsigned int result;
2555
2556 if (sony_call_snc_handle(0x0131, 0x0100, &result))
2557 return -EIO;
2558
2559 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2560}
2561
2562static int sony_nc_highspeed_charging_setup(struct platform_device *pd)
2563{
2564 unsigned int result;
2565
2566 if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) {
2567
2568
2569
2570 pr_info("No High Speed Charging capability found\n");
2571 return 0;
2572 }
2573
2574 hsc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2575 if (!hsc_handle)
2576 return -ENOMEM;
2577
2578 sysfs_attr_init(&hsc_handle->attr);
2579 hsc_handle->attr.name = "battery_highspeed_charging";
2580 hsc_handle->attr.mode = S_IRUGO | S_IWUSR;
2581 hsc_handle->show = sony_nc_highspeed_charging_show;
2582 hsc_handle->store = sony_nc_highspeed_charging_store;
2583
2584 result = device_create_file(&pd->dev, hsc_handle);
2585 if (result) {
2586 kfree(hsc_handle);
2587 hsc_handle = NULL;
2588 return result;
2589 }
2590
2591 return 0;
2592}
2593
2594static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
2595{
2596 if (hsc_handle) {
2597 device_remove_file(&pd->dev, hsc_handle);
2598 kfree(hsc_handle);
2599 hsc_handle = NULL;
2600 }
2601}
2602
2603
2604static struct device_attribute *lowbatt_handle;
2605
2606static ssize_t sony_nc_lowbatt_store(struct device *dev,
2607 struct device_attribute *attr,
2608 const char *buffer, size_t count)
2609{
2610 unsigned int result;
2611 unsigned long value;
2612
2613 if (count > 31)
2614 return -EINVAL;
2615
2616 if (kstrtoul(buffer, 10, &value) || value > 1)
2617 return -EINVAL;
2618
2619 if (sony_call_snc_handle(0x0121, value << 8, &result))
2620 return -EIO;
2621
2622 return count;
2623}
2624
2625static ssize_t sony_nc_lowbatt_show(struct device *dev,
2626 struct device_attribute *attr, char *buffer)
2627{
2628 unsigned int result;
2629
2630 if (sony_call_snc_handle(0x0121, 0x0200, &result))
2631 return -EIO;
2632
2633 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 1);
2634}
2635
2636static int sony_nc_lowbatt_setup(struct platform_device *pd)
2637{
2638 unsigned int result;
2639
2640 lowbatt_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2641 if (!lowbatt_handle)
2642 return -ENOMEM;
2643
2644 sysfs_attr_init(&lowbatt_handle->attr);
2645 lowbatt_handle->attr.name = "lowbatt_hibernate";
2646 lowbatt_handle->attr.mode = S_IRUGO | S_IWUSR;
2647 lowbatt_handle->show = sony_nc_lowbatt_show;
2648 lowbatt_handle->store = sony_nc_lowbatt_store;
2649
2650 result = device_create_file(&pd->dev, lowbatt_handle);
2651 if (result) {
2652 kfree(lowbatt_handle);
2653 lowbatt_handle = NULL;
2654 return result;
2655 }
2656
2657 return 0;
2658}
2659
2660static void sony_nc_lowbatt_cleanup(struct platform_device *pd)
2661{
2662 if (lowbatt_handle) {
2663 device_remove_file(&pd->dev, lowbatt_handle);
2664 kfree(lowbatt_handle);
2665 lowbatt_handle = NULL;
2666 }
2667}
2668
2669
2670static struct device_attribute *fan_handle, *hsf_handle;
2671
2672static ssize_t sony_nc_hsfan_store(struct device *dev,
2673 struct device_attribute *attr,
2674 const char *buffer, size_t count)
2675{
2676 unsigned int result;
2677 unsigned long value;
2678
2679 if (count > 31)
2680 return -EINVAL;
2681
2682 if (kstrtoul(buffer, 10, &value) || value > 1)
2683 return -EINVAL;
2684
2685 if (sony_call_snc_handle(0x0149, value << 0x10 | 0x0200, &result))
2686 return -EIO;
2687
2688 return count;
2689}
2690
2691static ssize_t sony_nc_hsfan_show(struct device *dev,
2692 struct device_attribute *attr, char *buffer)
2693{
2694 unsigned int result;
2695
2696 if (sony_call_snc_handle(0x0149, 0x0100, &result))
2697 return -EIO;
2698
2699 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2700}
2701
2702static ssize_t sony_nc_fanspeed_show(struct device *dev,
2703 struct device_attribute *attr, char *buffer)
2704{
2705 unsigned int result;
2706
2707 if (sony_call_snc_handle(0x0149, 0x0300, &result))
2708 return -EIO;
2709
2710 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff);
2711}
2712
2713static int sony_nc_fanspeed_setup(struct platform_device *pd)
2714{
2715 unsigned int result;
2716
2717 fan_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2718 if (!fan_handle)
2719 return -ENOMEM;
2720
2721 hsf_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2722 if (!hsf_handle) {
2723 result = -ENOMEM;
2724 goto out_hsf_handle_alloc;
2725 }
2726
2727 sysfs_attr_init(&fan_handle->attr);
2728 fan_handle->attr.name = "fanspeed";
2729 fan_handle->attr.mode = S_IRUGO;
2730 fan_handle->show = sony_nc_fanspeed_show;
2731 fan_handle->store = NULL;
2732
2733 sysfs_attr_init(&hsf_handle->attr);
2734 hsf_handle->attr.name = "fan_forced";
2735 hsf_handle->attr.mode = S_IRUGO | S_IWUSR;
2736 hsf_handle->show = sony_nc_hsfan_show;
2737 hsf_handle->store = sony_nc_hsfan_store;
2738
2739 result = device_create_file(&pd->dev, fan_handle);
2740 if (result)
2741 goto out_fan_handle;
2742
2743 result = device_create_file(&pd->dev, hsf_handle);
2744 if (result)
2745 goto out_hsf_handle;
2746
2747 return 0;
2748
2749out_hsf_handle:
2750 device_remove_file(&pd->dev, fan_handle);
2751
2752out_fan_handle:
2753 kfree(hsf_handle);
2754 hsf_handle = NULL;
2755
2756out_hsf_handle_alloc:
2757 kfree(fan_handle);
2758 fan_handle = NULL;
2759 return result;
2760}
2761
2762static void sony_nc_fanspeed_cleanup(struct platform_device *pd)
2763{
2764 if (fan_handle) {
2765 device_remove_file(&pd->dev, fan_handle);
2766 kfree(fan_handle);
2767 fan_handle = NULL;
2768 }
2769 if (hsf_handle) {
2770 device_remove_file(&pd->dev, hsf_handle);
2771 kfree(hsf_handle);
2772 hsf_handle = NULL;
2773 }
2774}
2775
2776
2777static struct device_attribute *uc_handle;
2778
2779static ssize_t sony_nc_usb_charge_store(struct device *dev,
2780 struct device_attribute *attr,
2781 const char *buffer, size_t count)
2782{
2783 unsigned int result;
2784 unsigned long value;
2785
2786 if (count > 31)
2787 return -EINVAL;
2788
2789 if (kstrtoul(buffer, 10, &value) || value > 1)
2790 return -EINVAL;
2791
2792 if (sony_call_snc_handle(0x0155, value << 0x10 | 0x0100, &result))
2793 return -EIO;
2794
2795 return count;
2796}
2797
2798static ssize_t sony_nc_usb_charge_show(struct device *dev,
2799 struct device_attribute *attr, char *buffer)
2800{
2801 unsigned int result;
2802
2803 if (sony_call_snc_handle(0x0155, 0x0000, &result))
2804 return -EIO;
2805
2806 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2807}
2808
2809static int sony_nc_usb_charge_setup(struct platform_device *pd)
2810{
2811 unsigned int result;
2812
2813 if (sony_call_snc_handle(0x0155, 0x0000, &result) || !(result & 0x01)) {
2814
2815
2816
2817 pr_info("No USB Charge capability found\n");
2818 return 0;
2819 }
2820
2821 uc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2822 if (!uc_handle)
2823 return -ENOMEM;
2824
2825 sysfs_attr_init(&uc_handle->attr);
2826 uc_handle->attr.name = "usb_charge";
2827 uc_handle->attr.mode = S_IRUGO | S_IWUSR;
2828 uc_handle->show = sony_nc_usb_charge_show;
2829 uc_handle->store = sony_nc_usb_charge_store;
2830
2831 result = device_create_file(&pd->dev, uc_handle);
2832 if (result) {
2833 kfree(uc_handle);
2834 uc_handle = NULL;
2835 return result;
2836 }
2837
2838 return 0;
2839}
2840
2841static void sony_nc_usb_charge_cleanup(struct platform_device *pd)
2842{
2843 if (uc_handle) {
2844 device_remove_file(&pd->dev, uc_handle);
2845 kfree(uc_handle);
2846 uc_handle = NULL;
2847 }
2848}
2849
2850
2851static struct device_attribute *panel_handle;
2852
2853static ssize_t sony_nc_panelid_show(struct device *dev,
2854 struct device_attribute *attr, char *buffer)
2855{
2856 unsigned int result;
2857
2858 if (sony_call_snc_handle(0x011D, 0x0000, &result))
2859 return -EIO;
2860
2861 return snprintf(buffer, PAGE_SIZE, "%d\n", result);
2862}
2863
2864static int sony_nc_panelid_setup(struct platform_device *pd)
2865{
2866 unsigned int result;
2867
2868 panel_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2869 if (!panel_handle)
2870 return -ENOMEM;
2871
2872 sysfs_attr_init(&panel_handle->attr);
2873 panel_handle->attr.name = "panel_id";
2874 panel_handle->attr.mode = S_IRUGO;
2875 panel_handle->show = sony_nc_panelid_show;
2876 panel_handle->store = NULL;
2877
2878 result = device_create_file(&pd->dev, panel_handle);
2879 if (result) {
2880 kfree(panel_handle);
2881 panel_handle = NULL;
2882 return result;
2883 }
2884
2885 return 0;
2886}
2887
2888static void sony_nc_panelid_cleanup(struct platform_device *pd)
2889{
2890 if (panel_handle) {
2891 device_remove_file(&pd->dev, panel_handle);
2892 kfree(panel_handle);
2893 panel_handle = NULL;
2894 }
2895}
2896
2897
2898static struct device_attribute *sc_handle;
2899
2900static ssize_t sony_nc_smart_conn_store(struct device *dev,
2901 struct device_attribute *attr,
2902 const char *buffer, size_t count)
2903{
2904 unsigned int result;
2905 unsigned long value;
2906
2907 if (count > 31)
2908 return -EINVAL;
2909
2910 if (kstrtoul(buffer, 10, &value) || value > 1)
2911 return -EINVAL;
2912
2913 if (sony_call_snc_handle(0x0168, value << 0x10, &result))
2914 return -EIO;
2915
2916 return count;
2917}
2918
2919static int sony_nc_smart_conn_setup(struct platform_device *pd)
2920{
2921 unsigned int result;
2922
2923 sc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2924 if (!sc_handle)
2925 return -ENOMEM;
2926
2927 sysfs_attr_init(&sc_handle->attr);
2928 sc_handle->attr.name = "smart_connect";
2929 sc_handle->attr.mode = S_IWUSR;
2930 sc_handle->show = NULL;
2931 sc_handle->store = sony_nc_smart_conn_store;
2932
2933 result = device_create_file(&pd->dev, sc_handle);
2934 if (result) {
2935 kfree(sc_handle);
2936 sc_handle = NULL;
2937 return result;
2938 }
2939
2940 return 0;
2941}
2942
2943static void sony_nc_smart_conn_cleanup(struct platform_device *pd)
2944{
2945 if (sc_handle) {
2946 device_remove_file(&pd->dev, sc_handle);
2947 kfree(sc_handle);
2948 sc_handle = NULL;
2949 }
2950}
2951
2952
2953struct touchpad_control {
2954 struct device_attribute attr;
2955 int handle;
2956};
2957static struct touchpad_control *tp_ctl;
2958
2959static ssize_t sony_nc_touchpad_store(struct device *dev,
2960 struct device_attribute *attr, const char *buffer, size_t count)
2961{
2962 unsigned int result;
2963 unsigned long value;
2964
2965 if (count > 31)
2966 return -EINVAL;
2967
2968 if (kstrtoul(buffer, 10, &value) || value > 1)
2969 return -EINVAL;
2970
2971
2972
2973
2974 if (sony_call_snc_handle(tp_ctl->handle,
2975 (!value << 0x10) | 0x100, &result))
2976 return -EIO;
2977
2978 return count;
2979}
2980
2981static ssize_t sony_nc_touchpad_show(struct device *dev,
2982 struct device_attribute *attr, char *buffer)
2983{
2984 unsigned int result;
2985
2986 if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result))
2987 return -EINVAL;
2988
2989 return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01));
2990}
2991
2992static int sony_nc_touchpad_setup(struct platform_device *pd,
2993 unsigned int handle)
2994{
2995 int ret = 0;
2996
2997 tp_ctl = kzalloc(sizeof(struct touchpad_control), GFP_KERNEL);
2998 if (!tp_ctl)
2999 return -ENOMEM;
3000
3001 tp_ctl->handle = handle;
3002
3003 sysfs_attr_init(&tp_ctl->attr.attr);
3004 tp_ctl->attr.attr.name = "touchpad";
3005 tp_ctl->attr.attr.mode = S_IRUGO | S_IWUSR;
3006 tp_ctl->attr.show = sony_nc_touchpad_show;
3007 tp_ctl->attr.store = sony_nc_touchpad_store;
3008
3009 ret = device_create_file(&pd->dev, &tp_ctl->attr);
3010 if (ret) {
3011 kfree(tp_ctl);
3012 tp_ctl = NULL;
3013 }
3014
3015 return ret;
3016}
3017
3018static void sony_nc_touchpad_cleanup(struct platform_device *pd)
3019{
3020 if (tp_ctl) {
3021 device_remove_file(&pd->dev, &tp_ctl->attr);
3022 kfree(tp_ctl);
3023 tp_ctl = NULL;
3024 }
3025}
3026
3027static void sony_nc_backlight_ng_read_limits(int handle,
3028 struct sony_backlight_props *props)
3029{
3030 u64 offset;
3031 int i;
3032 int lvl_table_len = 0;
3033 u8 min = 0xff, max = 0x00;
3034 unsigned char buffer[32] = { 0 };
3035
3036 props->handle = handle;
3037 props->offset = 0;
3038 props->maxlvl = 0xff;
3039
3040 offset = sony_find_snc_handle(handle);
3041
3042
3043
3044
3045 i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
3046 32);
3047 if (i < 0)
3048 return;
3049
3050 switch (handle) {
3051 case 0x012f:
3052 case 0x0137:
3053 lvl_table_len = 9;
3054 break;
3055 case 0x143:
3056 case 0x14b:
3057 case 0x14c:
3058 lvl_table_len = 16;
3059 break;
3060 }
3061
3062
3063
3064
3065
3066 for (i = 0; i < lvl_table_len && i < ARRAY_SIZE(buffer); i++) {
3067
3068 dprintk("Brightness level: %d\n", buffer[i]);
3069
3070 if (!buffer[i])
3071 break;
3072
3073 if (buffer[i] > max)
3074 max = buffer[i];
3075 if (buffer[i] < min)
3076 min = buffer[i];
3077 }
3078 props->offset = min;
3079 props->maxlvl = max;
3080 dprintk("Brightness levels: min=%d max=%d\n", props->offset,
3081 props->maxlvl);
3082}
3083
3084static void sony_nc_backlight_setup(void)
3085{
3086 int max_brightness = 0;
3087 const struct backlight_ops *ops = NULL;
3088 struct backlight_properties props;
3089
3090 if (sony_find_snc_handle(0x12f) >= 0) {
3091 ops = &sony_backlight_ng_ops;
3092 sony_bl_props.cmd_base = 0x0100;
3093 sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
3094 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3095
3096 } else if (sony_find_snc_handle(0x137) >= 0) {
3097 ops = &sony_backlight_ng_ops;
3098 sony_bl_props.cmd_base = 0x0100;
3099 sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
3100 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3101
3102 } else if (sony_find_snc_handle(0x143) >= 0) {
3103 ops = &sony_backlight_ng_ops;
3104 sony_bl_props.cmd_base = 0x3000;
3105 sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
3106 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3107
3108 } else if (sony_find_snc_handle(0x14b) >= 0) {
3109 ops = &sony_backlight_ng_ops;
3110 sony_bl_props.cmd_base = 0x3000;
3111 sony_nc_backlight_ng_read_limits(0x14b, &sony_bl_props);
3112 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3113
3114 } else if (sony_find_snc_handle(0x14c) >= 0) {
3115 ops = &sony_backlight_ng_ops;
3116 sony_bl_props.cmd_base = 0x3000;
3117 sony_nc_backlight_ng_read_limits(0x14c, &sony_bl_props);
3118 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3119
3120 } else if (acpi_has_method(sony_nc_acpi_handle, "GBRT")) {
3121 ops = &sony_backlight_ops;
3122 max_brightness = SONY_MAX_BRIGHTNESS - 1;
3123
3124 } else
3125 return;
3126
3127 memset(&props, 0, sizeof(struct backlight_properties));
3128 props.type = BACKLIGHT_PLATFORM;
3129 props.max_brightness = max_brightness;
3130 sony_bl_props.dev = backlight_device_register("sony", NULL,
3131 &sony_bl_props,
3132 ops, &props);
3133
3134 if (IS_ERR(sony_bl_props.dev)) {
3135 pr_warn("unable to register backlight device\n");
3136 sony_bl_props.dev = NULL;
3137 } else
3138 sony_bl_props.dev->props.brightness =
3139 ops->get_brightness(sony_bl_props.dev);
3140}
3141
3142static void sony_nc_backlight_cleanup(void)
3143{
3144 if (sony_bl_props.dev)
3145 backlight_device_unregister(sony_bl_props.dev);
3146}
3147
3148static int sony_nc_add(struct acpi_device *device)
3149{
3150 acpi_status status;
3151 int result = 0;
3152 struct sony_nc_value *item;
3153
3154 sony_nc_acpi_device = device;
3155 strcpy(acpi_device_class(device), "sony/hotkey");
3156
3157 sony_nc_acpi_handle = device->handle;
3158
3159
3160 result = acpi_bus_get_status(device);
3161
3162 if (!result && !device->status.present) {
3163 dprintk("Device not present\n");
3164 result = -ENODEV;
3165 goto outwalk;
3166 }
3167
3168 result = sony_pf_add();
3169 if (result)
3170 goto outpresent;
3171
3172 if (debug) {
3173 status = acpi_walk_namespace(ACPI_TYPE_METHOD,
3174 sony_nc_acpi_handle, 1, sony_walk_callback,
3175 NULL, NULL, NULL);
3176 if (ACPI_FAILURE(status)) {
3177 pr_warn("unable to walk acpi resources\n");
3178 result = -ENODEV;
3179 goto outpresent;
3180 }
3181 }
3182
3183 result = sony_laptop_setup_input(device);
3184 if (result) {
3185 pr_err("Unable to create input devices\n");
3186 goto outplatform;
3187 }
3188
3189 if (acpi_has_method(sony_nc_acpi_handle, "ECON")) {
3190 int arg = 1;
3191 if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
3192 dprintk("ECON Method failed\n");
3193 }
3194
3195 if (acpi_has_method(sony_nc_acpi_handle, "SN00")) {
3196 dprintk("Doing SNC setup\n");
3197
3198 result = sony_nc_handles_setup(sony_pf_device);
3199 if (!result)
3200 sony_nc_function_setup(device, sony_pf_device);
3201 }
3202
3203
3204 if (acpi_video_backlight_support()) {
3205 pr_info("brightness ignored, must be controlled by ACPI video driver\n");
3206 } else {
3207 sony_nc_backlight_setup();
3208 }
3209
3210
3211 for (item = sony_nc_values; item->name; ++item) {
3212
3213 if (!debug && item->debug)
3214 continue;
3215
3216
3217 for (; item->acpiget && *item->acpiget; ++item->acpiget) {
3218 if (acpi_has_method(sony_nc_acpi_handle,
3219 *item->acpiget)) {
3220 dprintk("Found %s getter: %s\n",
3221 item->name, *item->acpiget);
3222 item->devattr.attr.mode |= S_IRUGO;
3223 break;
3224 }
3225 }
3226
3227
3228 for (; item->acpiset && *item->acpiset; ++item->acpiset) {
3229 if (acpi_has_method(sony_nc_acpi_handle,
3230 *item->acpiset)) {
3231 dprintk("Found %s setter: %s\n",
3232 item->name, *item->acpiset);
3233 item->devattr.attr.mode |= S_IWUSR;
3234 break;
3235 }
3236 }
3237
3238 if (item->devattr.attr.mode != 0) {
3239 result =
3240 device_create_file(&sony_pf_device->dev,
3241 &item->devattr);
3242 if (result)
3243 goto out_sysfs;
3244 }
3245 }
3246
3247 pr_info("SNC setup done.\n");
3248 return 0;
3249
3250out_sysfs:
3251 for (item = sony_nc_values; item->name; ++item) {
3252 device_remove_file(&sony_pf_device->dev, &item->devattr);
3253 }
3254 sony_nc_backlight_cleanup();
3255 sony_nc_function_cleanup(sony_pf_device);
3256 sony_nc_handles_cleanup(sony_pf_device);
3257
3258outplatform:
3259 sony_laptop_remove_input();
3260
3261outpresent:
3262 sony_pf_remove();
3263
3264outwalk:
3265 sony_nc_rfkill_cleanup();
3266 return result;
3267}
3268
3269static int sony_nc_remove(struct acpi_device *device)
3270{
3271 struct sony_nc_value *item;
3272
3273 sony_nc_backlight_cleanup();
3274
3275 sony_nc_acpi_device = NULL;
3276
3277 for (item = sony_nc_values; item->name; ++item) {
3278 device_remove_file(&sony_pf_device->dev, &item->devattr);
3279 }
3280
3281 sony_nc_function_cleanup(sony_pf_device);
3282 sony_nc_handles_cleanup(sony_pf_device);
3283 sony_pf_remove();
3284 sony_laptop_remove_input();
3285 dprintk(SONY_NC_DRIVER_NAME " removed.\n");
3286
3287 return 0;
3288}
3289
3290static const struct acpi_device_id sony_device_ids[] = {
3291 {SONY_NC_HID, 0},
3292 {SONY_PIC_HID, 0},
3293 {"", 0},
3294};
3295MODULE_DEVICE_TABLE(acpi, sony_device_ids);
3296
3297static const struct acpi_device_id sony_nc_device_ids[] = {
3298 {SONY_NC_HID, 0},
3299 {"", 0},
3300};
3301
3302static struct acpi_driver sony_nc_driver = {
3303 .name = SONY_NC_DRIVER_NAME,
3304 .class = SONY_NC_CLASS,
3305 .ids = sony_nc_device_ids,
3306 .owner = THIS_MODULE,
3307 .ops = {
3308 .add = sony_nc_add,
3309 .remove = sony_nc_remove,
3310 .notify = sony_nc_notify,
3311 },
3312 .drv.pm = &sony_nc_pm,
3313};
3314
3315
3316
3317#define SONYPI_DEVICE_TYPE1 0x00000001
3318#define SONYPI_DEVICE_TYPE2 0x00000002
3319#define SONYPI_DEVICE_TYPE3 0x00000004
3320
3321#define SONYPI_TYPE1_OFFSET 0x04
3322#define SONYPI_TYPE2_OFFSET 0x12
3323#define SONYPI_TYPE3_OFFSET 0x12
3324
3325struct sony_pic_ioport {
3326 struct acpi_resource_io io1;
3327 struct acpi_resource_io io2;
3328 struct list_head list;
3329};
3330
3331struct sony_pic_irq {
3332 struct acpi_resource_irq irq;
3333 struct list_head list;
3334};
3335
3336struct sonypi_eventtypes {
3337 u8 data;
3338 unsigned long mask;
3339 struct sonypi_event *events;
3340};
3341
3342struct sony_pic_dev {
3343 struct acpi_device *acpi_dev;
3344 struct sony_pic_irq *cur_irq;
3345 struct sony_pic_ioport *cur_ioport;
3346 struct list_head interrupts;
3347 struct list_head ioports;
3348 struct mutex lock;
3349 struct sonypi_eventtypes *event_types;
3350 int (*handle_irq)(const u8, const u8);
3351 int model;
3352 u16 evport_offset;
3353 u8 camera_power;
3354 u8 bluetooth_power;
3355 u8 wwan_power;
3356};
3357
3358static struct sony_pic_dev spic_dev = {
3359 .interrupts = LIST_HEAD_INIT(spic_dev.interrupts),
3360 .ioports = LIST_HEAD_INIT(spic_dev.ioports),
3361};
3362
3363static int spic_drv_registered;
3364
3365
3366#define SONYPI_JOGGER_MASK 0x00000001
3367#define SONYPI_CAPTURE_MASK 0x00000002
3368#define SONYPI_FNKEY_MASK 0x00000004
3369#define SONYPI_BLUETOOTH_MASK 0x00000008
3370#define SONYPI_PKEY_MASK 0x00000010
3371#define SONYPI_BACK_MASK 0x00000020
3372#define SONYPI_HELP_MASK 0x00000040
3373#define SONYPI_LID_MASK 0x00000080
3374#define SONYPI_ZOOM_MASK 0x00000100
3375#define SONYPI_THUMBPHRASE_MASK 0x00000200
3376#define SONYPI_MEYE_MASK 0x00000400
3377#define SONYPI_MEMORYSTICK_MASK 0x00000800
3378#define SONYPI_BATTERY_MASK 0x00001000
3379#define SONYPI_WIRELESS_MASK 0x00002000
3380
3381struct sonypi_event {
3382 u8 data;
3383 u8 event;
3384};
3385
3386
3387static struct sonypi_event sonypi_releaseev[] = {
3388 { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
3389 { 0, 0 }
3390};
3391
3392
3393static struct sonypi_event sonypi_joggerev[] = {
3394 { 0x1f, SONYPI_EVENT_JOGDIAL_UP },
3395 { 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
3396 { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
3397 { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
3398 { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
3399 { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
3400 { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
3401 { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
3402 { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
3403 { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
3404 { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
3405 { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
3406 { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
3407 { 0, 0 }
3408};
3409
3410
3411static struct sonypi_event sonypi_captureev[] = {
3412 { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
3413 { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
3414 { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
3415 { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
3416 { 0, 0 }
3417};
3418
3419
3420static struct sonypi_event sonypi_fnkeyev[] = {
3421 { 0x10, SONYPI_EVENT_FNKEY_ESC },
3422 { 0x11, SONYPI_EVENT_FNKEY_F1 },
3423 { 0x12, SONYPI_EVENT_FNKEY_F2 },
3424 { 0x13, SONYPI_EVENT_FNKEY_F3 },
3425 { 0x14, SONYPI_EVENT_FNKEY_F4 },
3426 { 0x15, SONYPI_EVENT_FNKEY_F5 },
3427 { 0x16, SONYPI_EVENT_FNKEY_F6 },
3428 { 0x17, SONYPI_EVENT_FNKEY_F7 },
3429 { 0x18, SONYPI_EVENT_FNKEY_F8 },
3430 { 0x19, SONYPI_EVENT_FNKEY_F9 },
3431 { 0x1a, SONYPI_EVENT_FNKEY_F10 },
3432 { 0x1b, SONYPI_EVENT_FNKEY_F11 },
3433 { 0x1c, SONYPI_EVENT_FNKEY_F12 },
3434 { 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
3435 { 0x21, SONYPI_EVENT_FNKEY_1 },
3436 { 0x22, SONYPI_EVENT_FNKEY_2 },
3437 { 0x31, SONYPI_EVENT_FNKEY_D },
3438 { 0x32, SONYPI_EVENT_FNKEY_E },
3439 { 0x33, SONYPI_EVENT_FNKEY_F },
3440 { 0x34, SONYPI_EVENT_FNKEY_S },
3441 { 0x35, SONYPI_EVENT_FNKEY_B },
3442 { 0x36, SONYPI_EVENT_FNKEY_ONLY },
3443 { 0, 0 }
3444};
3445
3446
3447static struct sonypi_event sonypi_pkeyev[] = {
3448 { 0x01, SONYPI_EVENT_PKEY_P1 },
3449 { 0x02, SONYPI_EVENT_PKEY_P2 },
3450 { 0x04, SONYPI_EVENT_PKEY_P3 },
3451 { 0x20, SONYPI_EVENT_PKEY_P1 },
3452 { 0, 0 }
3453};
3454
3455
3456static struct sonypi_event sonypi_blueev[] = {
3457 { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
3458 { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
3459 { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
3460 { 0, 0 }
3461};
3462
3463
3464static struct sonypi_event sonypi_wlessev[] = {
3465 { 0x59, SONYPI_EVENT_IGNORE },
3466 { 0x5a, SONYPI_EVENT_IGNORE },
3467 { 0, 0 }
3468};
3469
3470
3471static struct sonypi_event sonypi_backev[] = {
3472 { 0x20, SONYPI_EVENT_BACK_PRESSED },
3473 { 0, 0 }
3474};
3475
3476
3477static struct sonypi_event sonypi_helpev[] = {
3478 { 0x3b, SONYPI_EVENT_HELP_PRESSED },
3479 { 0, 0 }
3480};
3481
3482
3483
3484static struct sonypi_event sonypi_lidev[] = {
3485 { 0x51, SONYPI_EVENT_LID_CLOSED },
3486 { 0x50, SONYPI_EVENT_LID_OPENED },
3487 { 0, 0 }
3488};
3489
3490
3491static struct sonypi_event sonypi_zoomev[] = {
3492 { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
3493 { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
3494 { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
3495 { 0x04, SONYPI_EVENT_ZOOM_PRESSED },
3496 { 0, 0 }
3497};
3498
3499
3500static struct sonypi_event sonypi_thumbphraseev[] = {
3501 { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
3502 { 0, 0 }
3503};
3504
3505
3506static struct sonypi_event sonypi_meyeev[] = {
3507 { 0x00, SONYPI_EVENT_MEYE_FACE },
3508 { 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
3509 { 0, 0 }
3510};
3511
3512
3513static struct sonypi_event sonypi_memorystickev[] = {
3514 { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
3515 { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
3516 { 0, 0 }
3517};
3518
3519
3520static struct sonypi_event sonypi_batteryev[] = {
3521 { 0x20, SONYPI_EVENT_BATTERY_INSERT },
3522 { 0x30, SONYPI_EVENT_BATTERY_REMOVE },
3523 { 0, 0 }
3524};
3525
3526
3527static struct sonypi_event sonypi_volumeev[] = {
3528 { 0x01, SONYPI_EVENT_VOLUME_INC_PRESSED },
3529 { 0x02, SONYPI_EVENT_VOLUME_DEC_PRESSED },
3530 { 0, 0 }
3531};
3532
3533
3534static struct sonypi_event sonypi_brightnessev[] = {
3535 { 0x80, SONYPI_EVENT_BRIGHTNESS_PRESSED },
3536 { 0, 0 }
3537};
3538
3539static struct sonypi_eventtypes type1_events[] = {
3540 { 0, 0xffffffff, sonypi_releaseev },
3541 { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
3542 { 0x30, SONYPI_LID_MASK, sonypi_lidev },
3543 { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
3544 { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
3545 { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3546 { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
3547 { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
3548 { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3549 { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
3550 { 0 },
3551};
3552static struct sonypi_eventtypes type2_events[] = {
3553 { 0, 0xffffffff, sonypi_releaseev },
3554 { 0x38, SONYPI_LID_MASK, sonypi_lidev },
3555 { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
3556 { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
3557 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3558 { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
3559 { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
3560 { 0x11, SONYPI_BACK_MASK, sonypi_backev },
3561 { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
3562 { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
3563 { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
3564 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3565 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
3566 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
3567 { 0 },
3568};
3569static struct sonypi_eventtypes type3_events[] = {
3570 { 0, 0xffffffff, sonypi_releaseev },
3571 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3572 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
3573 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3574 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
3575 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
3576 { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
3577 { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
3578 { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
3579 { 0x05, SONYPI_PKEY_MASK, sonypi_volumeev },
3580 { 0x05, SONYPI_PKEY_MASK, sonypi_brightnessev },
3581 { 0 },
3582};
3583
3584
3585#define ITERATIONS_LONG 10000
3586#define ITERATIONS_SHORT 10
3587#define wait_on_command(command, iterations) { \
3588 unsigned int n = iterations; \
3589 while (--n && (command)) \
3590 udelay(1); \
3591 if (!n) \
3592 dprintk("command failed at %s : %s (line %d)\n", \
3593 __FILE__, __func__, __LINE__); \
3594}
3595
3596static u8 sony_pic_call1(u8 dev)
3597{
3598 u8 v1, v2;
3599
3600 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3601 ITERATIONS_LONG);
3602 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3603 v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
3604 v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
3605 dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
3606 return v2;
3607}
3608
3609static u8 sony_pic_call2(u8 dev, u8 fn)
3610{
3611 u8 v1;
3612
3613 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3614 ITERATIONS_LONG);
3615 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3616 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3617 ITERATIONS_LONG);
3618 outb(fn, spic_dev.cur_ioport->io1.minimum);
3619 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
3620 dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
3621 return v1;
3622}
3623
3624static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
3625{
3626 u8 v1;
3627
3628 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3629 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3630 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3631 outb(fn, spic_dev.cur_ioport->io1.minimum);
3632 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3633 outb(v, spic_dev.cur_ioport->io1.minimum);
3634 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
3635 dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
3636 dev, fn, v, v1);
3637 return v1;
3638}
3639
3640
3641
3642
3643static int type3_handle_irq(const u8 data_mask, const u8 ev)
3644{
3645
3646
3647
3648
3649
3650
3651
3652 if (data_mask == 0x31) {
3653 if (ev == 0x5c || ev == 0x5f)
3654 sony_pic_call1(0xA0);
3655 else if (ev == 0x61)
3656 sony_pic_call1(0xB3);
3657 return 0;
3658 }
3659 return 1;
3660}
3661
3662static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
3663{
3664 struct pci_dev *pcidev;
3665
3666 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3667 PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
3668 if (pcidev) {
3669 dev->model = SONYPI_DEVICE_TYPE1;
3670 dev->evport_offset = SONYPI_TYPE1_OFFSET;
3671 dev->event_types = type1_events;
3672 goto out;
3673 }
3674
3675 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3676 PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
3677 if (pcidev) {
3678 dev->model = SONYPI_DEVICE_TYPE2;
3679 dev->evport_offset = SONYPI_TYPE2_OFFSET;
3680 dev->event_types = type2_events;
3681 goto out;
3682 }
3683
3684 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3685 PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
3686 if (pcidev) {
3687 dev->model = SONYPI_DEVICE_TYPE3;
3688 dev->handle_irq = type3_handle_irq;
3689 dev->evport_offset = SONYPI_TYPE3_OFFSET;
3690 dev->event_types = type3_events;
3691 goto out;
3692 }
3693
3694 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3695 PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
3696 if (pcidev) {
3697 dev->model = SONYPI_DEVICE_TYPE3;
3698 dev->handle_irq = type3_handle_irq;
3699 dev->evport_offset = SONYPI_TYPE3_OFFSET;
3700 dev->event_types = type3_events;
3701 goto out;
3702 }
3703
3704 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3705 PCI_DEVICE_ID_INTEL_ICH9_1, NULL);
3706 if (pcidev) {
3707 dev->model = SONYPI_DEVICE_TYPE3;
3708 dev->handle_irq = type3_handle_irq;
3709 dev->evport_offset = SONYPI_TYPE3_OFFSET;
3710 dev->event_types = type3_events;
3711 goto out;
3712 }
3713
3714
3715 dev->model = SONYPI_DEVICE_TYPE2;
3716 dev->evport_offset = SONYPI_TYPE2_OFFSET;
3717 dev->event_types = type2_events;
3718
3719out:
3720 if (pcidev)
3721 pci_dev_put(pcidev);
3722
3723 pr_info("detected Type%d model\n",
3724 dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
3725 dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
3726}
3727
3728
3729#define SONYPI_CAMERA_PICTURE 5
3730#define SONYPI_CAMERA_CONTROL 0x10
3731
3732#define SONYPI_CAMERA_BRIGHTNESS 0
3733#define SONYPI_CAMERA_CONTRAST 1
3734#define SONYPI_CAMERA_HUE 2
3735#define SONYPI_CAMERA_COLOR 3
3736#define SONYPI_CAMERA_SHARPNESS 4
3737
3738#define SONYPI_CAMERA_EXPOSURE_MASK 0xC
3739#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3
3740#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30
3741#define SONYPI_CAMERA_MUTE_MASK 0x40
3742
3743
3744#define SONYPI_CAMERA_AGC 6
3745#define SONYPI_CAMERA_AGC_MASK 0x30
3746#define SONYPI_CAMERA_SHUTTER_MASK 0x7
3747
3748#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7
3749#define SONYPI_CAMERA_CONTROL 0x10
3750
3751#define SONYPI_CAMERA_STATUS 7
3752#define SONYPI_CAMERA_STATUS_READY 0x2
3753#define SONYPI_CAMERA_STATUS_POSITION 0x4
3754
3755#define SONYPI_DIRECTION_BACKWARDS 0x4
3756
3757#define SONYPI_CAMERA_REVISION 8
3758#define SONYPI_CAMERA_ROMVERSION 9
3759
3760static int __sony_pic_camera_ready(void)
3761{
3762 u8 v;
3763
3764 v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
3765 return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
3766}
3767
3768static int __sony_pic_camera_off(void)
3769{
3770 if (!camera) {
3771 pr_warn("camera control not enabled\n");
3772 return -ENODEV;
3773 }
3774
3775 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
3776 SONYPI_CAMERA_MUTE_MASK),
3777 ITERATIONS_SHORT);
3778
3779 if (spic_dev.camera_power) {
3780 sony_pic_call2(0x91, 0);
3781 spic_dev.camera_power = 0;
3782 }
3783 return 0;
3784}
3785
3786static int __sony_pic_camera_on(void)
3787{
3788 int i, j, x;
3789
3790 if (!camera) {
3791 pr_warn("camera control not enabled\n");
3792 return -ENODEV;
3793 }
3794
3795 if (spic_dev.camera_power)
3796 return 0;
3797
3798 for (j = 5; j > 0; j--) {
3799
3800 for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
3801 msleep(10);
3802 sony_pic_call1(0x93);
3803
3804 for (i = 400; i > 0; i--) {
3805 if (__sony_pic_camera_ready())
3806 break;
3807 msleep(10);
3808 }
3809 if (i)
3810 break;
3811 }
3812
3813 if (j == 0) {
3814 pr_warn("failed to power on camera\n");
3815 return -ENODEV;
3816 }
3817
3818 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
3819 0x5a),
3820 ITERATIONS_SHORT);
3821
3822 spic_dev.camera_power = 1;
3823 return 0;
3824}
3825
3826
3827int sony_pic_camera_command(int command, u8 value)
3828{
3829 if (!camera)
3830 return -EIO;
3831
3832 mutex_lock(&spic_dev.lock);
3833
3834 switch (command) {
3835 case SONY_PIC_COMMAND_SETCAMERA:
3836 if (value)
3837 __sony_pic_camera_on();
3838 else
3839 __sony_pic_camera_off();
3840 break;
3841 case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
3842 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
3843 ITERATIONS_SHORT);
3844 break;
3845 case SONY_PIC_COMMAND_SETCAMERACONTRAST:
3846 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
3847 ITERATIONS_SHORT);
3848 break;
3849 case SONY_PIC_COMMAND_SETCAMERAHUE:
3850 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
3851 ITERATIONS_SHORT);
3852 break;
3853 case SONY_PIC_COMMAND_SETCAMERACOLOR:
3854 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
3855 ITERATIONS_SHORT);
3856 break;
3857 case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
3858 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
3859 ITERATIONS_SHORT);
3860 break;
3861 case SONY_PIC_COMMAND_SETCAMERAPICTURE:
3862 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
3863 ITERATIONS_SHORT);
3864 break;
3865 case SONY_PIC_COMMAND_SETCAMERAAGC:
3866 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
3867 ITERATIONS_SHORT);
3868 break;
3869 default:
3870 pr_err("sony_pic_camera_command invalid: %d\n", command);
3871 break;
3872 }
3873 mutex_unlock(&spic_dev.lock);
3874 return 0;
3875}
3876EXPORT_SYMBOL(sony_pic_camera_command);
3877
3878
3879static void __sony_pic_set_wwanpower(u8 state)
3880{
3881 state = !!state;
3882 if (spic_dev.wwan_power == state)
3883 return;
3884 sony_pic_call2(0xB0, state);
3885 sony_pic_call1(0x82);
3886 spic_dev.wwan_power = state;
3887}
3888
3889static ssize_t sony_pic_wwanpower_store(struct device *dev,
3890 struct device_attribute *attr,
3891 const char *buffer, size_t count)
3892{
3893 unsigned long value;
3894 if (count > 31)
3895 return -EINVAL;
3896
3897 if (kstrtoul(buffer, 10, &value))
3898 return -EINVAL;
3899
3900 mutex_lock(&spic_dev.lock);
3901 __sony_pic_set_wwanpower(value);
3902 mutex_unlock(&spic_dev.lock);
3903
3904 return count;
3905}
3906
3907static ssize_t sony_pic_wwanpower_show(struct device *dev,
3908 struct device_attribute *attr, char *buffer)
3909{
3910 ssize_t count;
3911 mutex_lock(&spic_dev.lock);
3912 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
3913 mutex_unlock(&spic_dev.lock);
3914 return count;
3915}
3916
3917
3918static void __sony_pic_set_bluetoothpower(u8 state)
3919{
3920 state = !!state;
3921 if (spic_dev.bluetooth_power == state)
3922 return;
3923 sony_pic_call2(0x96, state);
3924 sony_pic_call1(0x82);
3925 spic_dev.bluetooth_power = state;
3926}
3927
3928static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
3929 struct device_attribute *attr,
3930 const char *buffer, size_t count)
3931{
3932 unsigned long value;
3933 if (count > 31)
3934 return -EINVAL;
3935
3936 if (kstrtoul(buffer, 10, &value))
3937 return -EINVAL;
3938
3939 mutex_lock(&spic_dev.lock);
3940 __sony_pic_set_bluetoothpower(value);
3941 mutex_unlock(&spic_dev.lock);
3942
3943 return count;
3944}
3945
3946static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
3947 struct device_attribute *attr, char *buffer)
3948{
3949 ssize_t count = 0;
3950 mutex_lock(&spic_dev.lock);
3951 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
3952 mutex_unlock(&spic_dev.lock);
3953 return count;
3954}
3955
3956
3957
3958#define SONY_PIC_FAN0_STATUS 0x93
3959static int sony_pic_set_fanspeed(unsigned long value)
3960{
3961 return ec_write(SONY_PIC_FAN0_STATUS, value);
3962}
3963
3964static int sony_pic_get_fanspeed(u8 *value)
3965{
3966 return ec_read(SONY_PIC_FAN0_STATUS, value);
3967}
3968
3969static ssize_t sony_pic_fanspeed_store(struct device *dev,
3970 struct device_attribute *attr,
3971 const char *buffer, size_t count)
3972{
3973 unsigned long value;
3974 if (count > 31)
3975 return -EINVAL;
3976
3977 if (kstrtoul(buffer, 10, &value))
3978 return -EINVAL;
3979
3980 if (sony_pic_set_fanspeed(value))
3981 return -EIO;
3982
3983 return count;
3984}
3985
3986static ssize_t sony_pic_fanspeed_show(struct device *dev,
3987 struct device_attribute *attr, char *buffer)
3988{
3989 u8 value = 0;
3990 if (sony_pic_get_fanspeed(&value))
3991 return -EIO;
3992
3993 return snprintf(buffer, PAGE_SIZE, "%d\n", value);
3994}
3995
3996#define SPIC_ATTR(_name, _mode) \
3997struct device_attribute spic_attr_##_name = __ATTR(_name, \
3998 _mode, sony_pic_## _name ##_show, \
3999 sony_pic_## _name ##_store)
4000
4001static SPIC_ATTR(bluetoothpower, 0644);
4002static SPIC_ATTR(wwanpower, 0644);
4003static SPIC_ATTR(fanspeed, 0644);
4004
4005static struct attribute *spic_attributes[] = {
4006 &spic_attr_bluetoothpower.attr,
4007 &spic_attr_wwanpower.attr,
4008 &spic_attr_fanspeed.attr,
4009 NULL
4010};
4011
4012static struct attribute_group spic_attribute_group = {
4013 .attrs = spic_attributes
4014};
4015
4016
4017#ifdef CONFIG_SONYPI_COMPAT
4018
4019
4020#define SONYPI_BAT_FLAGS 0x81
4021#define SONYPI_LCD_LIGHT 0x96
4022#define SONYPI_BAT1_PCTRM 0xa0
4023#define SONYPI_BAT1_LEFT 0xa2
4024#define SONYPI_BAT1_MAXRT 0xa4
4025#define SONYPI_BAT2_PCTRM 0xa8
4026#define SONYPI_BAT2_LEFT 0xaa
4027#define SONYPI_BAT2_MAXRT 0xac
4028#define SONYPI_BAT1_MAXTK 0xb0
4029#define SONYPI_BAT1_FULL 0xb2
4030#define SONYPI_BAT2_MAXTK 0xb8
4031#define SONYPI_BAT2_FULL 0xba
4032#define SONYPI_TEMP_STATUS 0xC1
4033
4034struct sonypi_compat_s {
4035 struct fasync_struct *fifo_async;
4036 struct kfifo fifo;
4037 spinlock_t fifo_lock;
4038 wait_queue_head_t fifo_proc_list;
4039 atomic_t open_count;
4040};
4041static struct sonypi_compat_s sonypi_compat = {
4042 .open_count = ATOMIC_INIT(0),
4043};
4044
4045static int sonypi_misc_fasync(int fd, struct file *filp, int on)
4046{
4047 return fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
4048}
4049
4050static int sonypi_misc_release(struct inode *inode, struct file *file)
4051{
4052 atomic_dec(&sonypi_compat.open_count);
4053 return 0;
4054}
4055
4056static int sonypi_misc_open(struct inode *inode, struct file *file)
4057{
4058
4059 unsigned long flags;
4060
4061 spin_lock_irqsave(&sonypi_compat.fifo_lock, flags);
4062
4063 if (atomic_inc_return(&sonypi_compat.open_count) == 1)
4064 kfifo_reset(&sonypi_compat.fifo);
4065
4066 spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags);
4067
4068 return 0;
4069}
4070
4071static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
4072 size_t count, loff_t *pos)
4073{
4074 ssize_t ret;
4075 unsigned char c;
4076
4077 if ((kfifo_len(&sonypi_compat.fifo) == 0) &&
4078 (file->f_flags & O_NONBLOCK))
4079 return -EAGAIN;
4080
4081 ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
4082 kfifo_len(&sonypi_compat.fifo) != 0);
4083 if (ret)
4084 return ret;
4085
4086 while (ret < count &&
4087 (kfifo_out_locked(&sonypi_compat.fifo, &c, sizeof(c),
4088 &sonypi_compat.fifo_lock) == sizeof(c))) {
4089 if (put_user(c, buf++))
4090 return -EFAULT;
4091 ret++;
4092 }
4093
4094 if (ret > 0) {
4095 struct inode *inode = file_inode(file);
4096 inode->i_atime = current_fs_time(inode->i_sb);
4097 }
4098
4099 return ret;
4100}
4101
4102static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
4103{
4104 poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
4105 if (kfifo_len(&sonypi_compat.fifo))
4106 return POLLIN | POLLRDNORM;
4107 return 0;
4108}
4109
4110static int ec_read16(u8 addr, u16 *value)
4111{
4112 u8 val_lb, val_hb;
4113 if (ec_read(addr, &val_lb))
4114 return -1;
4115 if (ec_read(addr + 1, &val_hb))
4116 return -1;
4117 *value = val_lb | (val_hb << 8);
4118 return 0;
4119}
4120
4121static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
4122 unsigned long arg)
4123{
4124 int ret = 0;
4125 void __user *argp = (void __user *)arg;
4126 u8 val8;
4127 u16 val16;
4128 int value;
4129
4130 mutex_lock(&spic_dev.lock);
4131 switch (cmd) {
4132 case SONYPI_IOCGBRT:
4133 if (sony_bl_props.dev == NULL) {
4134 ret = -EIO;
4135 break;
4136 }
4137 if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL,
4138 &value)) {
4139 ret = -EIO;
4140 break;
4141 }
4142 val8 = ((value & 0xff) - 1) << 5;
4143 if (copy_to_user(argp, &val8, sizeof(val8)))
4144 ret = -EFAULT;
4145 break;
4146 case SONYPI_IOCSBRT:
4147 if (sony_bl_props.dev == NULL) {
4148 ret = -EIO;
4149 break;
4150 }
4151 if (copy_from_user(&val8, argp, sizeof(val8))) {
4152 ret = -EFAULT;
4153 break;
4154 }
4155 value = (val8 >> 5) + 1;
4156 if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value,
4157 NULL)) {
4158 ret = -EIO;
4159 break;
4160 }
4161
4162 sony_bl_props.dev->props.brightness =
4163 sony_backlight_get_brightness(sony_bl_props.dev);
4164 break;
4165 case SONYPI_IOCGBAT1CAP:
4166 if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
4167 ret = -EIO;
4168 break;
4169 }
4170 if (copy_to_user(argp, &val16, sizeof(val16)))
4171 ret = -EFAULT;
4172 break;
4173 case SONYPI_IOCGBAT1REM:
4174 if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
4175 ret = -EIO;
4176 break;
4177 }
4178 if (copy_to_user(argp, &val16, sizeof(val16)))
4179 ret = -EFAULT;
4180 break;
4181 case SONYPI_IOCGBAT2CAP:
4182 if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
4183 ret = -EIO;
4184 break;
4185 }
4186 if (copy_to_user(argp, &val16, sizeof(val16)))
4187 ret = -EFAULT;
4188 break;
4189 case SONYPI_IOCGBAT2REM:
4190 if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
4191 ret = -EIO;
4192 break;
4193 }
4194 if (copy_to_user(argp, &val16, sizeof(val16)))
4195 ret = -EFAULT;
4196 break;
4197 case SONYPI_IOCGBATFLAGS:
4198 if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
4199 ret = -EIO;
4200 break;
4201 }
4202 val8 &= 0x07;
4203 if (copy_to_user(argp, &val8, sizeof(val8)))
4204 ret = -EFAULT;
4205 break;
4206 case SONYPI_IOCGBLUE:
4207 val8 = spic_dev.bluetooth_power;
4208 if (copy_to_user(argp, &val8, sizeof(val8)))
4209 ret = -EFAULT;
4210 break;
4211 case SONYPI_IOCSBLUE:
4212 if (copy_from_user(&val8, argp, sizeof(val8))) {
4213 ret = -EFAULT;
4214 break;
4215 }
4216 __sony_pic_set_bluetoothpower(val8);
4217 break;
4218
4219 case SONYPI_IOCGFAN:
4220 if (sony_pic_get_fanspeed(&val8)) {
4221 ret = -EIO;
4222 break;
4223 }
4224 if (copy_to_user(argp, &val8, sizeof(val8)))
4225 ret = -EFAULT;
4226 break;
4227 case SONYPI_IOCSFAN:
4228 if (copy_from_user(&val8, argp, sizeof(val8))) {
4229 ret = -EFAULT;
4230 break;
4231 }
4232 if (sony_pic_set_fanspeed(val8))
4233 ret = -EIO;
4234 break;
4235
4236 case SONYPI_IOCGTEMP:
4237 if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
4238 ret = -EIO;
4239 break;
4240 }
4241 if (copy_to_user(argp, &val8, sizeof(val8)))
4242 ret = -EFAULT;
4243 break;
4244 default:
4245 ret = -EINVAL;
4246 }
4247 mutex_unlock(&spic_dev.lock);
4248 return ret;
4249}
4250
4251static const struct file_operations sonypi_misc_fops = {
4252 .owner = THIS_MODULE,
4253 .read = sonypi_misc_read,
4254 .poll = sonypi_misc_poll,
4255 .open = sonypi_misc_open,
4256 .release = sonypi_misc_release,
4257 .fasync = sonypi_misc_fasync,
4258 .unlocked_ioctl = sonypi_misc_ioctl,
4259 .llseek = noop_llseek,
4260};
4261
4262static struct miscdevice sonypi_misc_device = {
4263 .minor = MISC_DYNAMIC_MINOR,
4264 .name = "sonypi",
4265 .fops = &sonypi_misc_fops,
4266};
4267
4268static void sonypi_compat_report_event(u8 event)
4269{
4270 kfifo_in_locked(&sonypi_compat.fifo, (unsigned char *)&event,
4271 sizeof(event), &sonypi_compat.fifo_lock);
4272 kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
4273 wake_up_interruptible(&sonypi_compat.fifo_proc_list);
4274}
4275
4276static int sonypi_compat_init(void)
4277{
4278 int error;
4279
4280 spin_lock_init(&sonypi_compat.fifo_lock);
4281 error =
4282 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
4283 if (error) {
4284 pr_err("kfifo_alloc failed\n");
4285 return error;
4286 }
4287
4288 init_waitqueue_head(&sonypi_compat.fifo_proc_list);
4289
4290 if (minor != -1)
4291 sonypi_misc_device.minor = minor;
4292 error = misc_register(&sonypi_misc_device);
4293 if (error) {
4294 pr_err("misc_register failed\n");
4295 goto err_free_kfifo;
4296 }
4297 if (minor == -1)
4298 pr_info("device allocated minor is %d\n",
4299 sonypi_misc_device.minor);
4300
4301 return 0;
4302
4303err_free_kfifo:
4304 kfifo_free(&sonypi_compat.fifo);
4305 return error;
4306}
4307
4308static void sonypi_compat_exit(void)
4309{
4310 misc_deregister(&sonypi_misc_device);
4311 kfifo_free(&sonypi_compat.fifo);
4312}
4313#else
4314static int sonypi_compat_init(void) { return 0; }
4315static void sonypi_compat_exit(void) { }
4316static void sonypi_compat_report_event(u8 event) { }
4317#endif
4318
4319
4320
4321
4322static acpi_status
4323sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
4324{
4325 u32 i;
4326 struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
4327
4328 switch (resource->type) {
4329 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
4330 {
4331
4332 struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
4333 if (!ioport)
4334 return AE_ERROR;
4335
4336 list_add(&ioport->list, &dev->ioports);
4337 return AE_OK;
4338 }
4339
4340 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
4341
4342 return AE_OK;
4343
4344 case ACPI_RESOURCE_TYPE_IRQ:
4345 {
4346 struct acpi_resource_irq *p = &resource->data.irq;
4347 struct sony_pic_irq *interrupt = NULL;
4348 if (!p || !p->interrupt_count) {
4349
4350
4351
4352
4353 dprintk("Blank IRQ resource\n");
4354 return AE_OK;
4355 }
4356 for (i = 0; i < p->interrupt_count; i++) {
4357 if (!p->interrupts[i]) {
4358 pr_warn("Invalid IRQ %d\n",
4359 p->interrupts[i]);
4360 continue;
4361 }
4362 interrupt = kzalloc(sizeof(*interrupt),
4363 GFP_KERNEL);
4364 if (!interrupt)
4365 return AE_ERROR;
4366
4367 list_add(&interrupt->list, &dev->interrupts);
4368 interrupt->irq.triggering = p->triggering;
4369 interrupt->irq.polarity = p->polarity;
4370 interrupt->irq.sharable = p->sharable;
4371 interrupt->irq.interrupt_count = 1;
4372 interrupt->irq.interrupts[0] = p->interrupts[i];
4373 }
4374 return AE_OK;
4375 }
4376 case ACPI_RESOURCE_TYPE_IO:
4377 {
4378 struct acpi_resource_io *io = &resource->data.io;
4379 struct sony_pic_ioport *ioport =
4380 list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
4381 if (!io) {
4382 dprintk("Blank IO resource\n");
4383 return AE_OK;
4384 }
4385
4386 if (!ioport->io1.minimum) {
4387 memcpy(&ioport->io1, io, sizeof(*io));
4388 dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
4389 ioport->io1.address_length);
4390 }
4391 else if (!ioport->io2.minimum) {
4392 memcpy(&ioport->io2, io, sizeof(*io));
4393 dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
4394 ioport->io2.address_length);
4395 }
4396 else {
4397 pr_err("Unknown SPIC Type, more than 2 IO Ports\n");
4398 return AE_ERROR;
4399 }
4400 return AE_OK;
4401 }
4402 default:
4403 dprintk("Resource %d isn't an IRQ nor an IO port\n",
4404 resource->type);
4405
4406 case ACPI_RESOURCE_TYPE_END_TAG:
4407 return AE_OK;
4408 }
4409 return AE_CTRL_TERMINATE;
4410}
4411
4412static int sony_pic_possible_resources(struct acpi_device *device)
4413{
4414 int result = 0;
4415 acpi_status status = AE_OK;
4416
4417 if (!device)
4418 return -EINVAL;
4419
4420
4421
4422 dprintk("Evaluating _STA\n");
4423 result = acpi_bus_get_status(device);
4424 if (result) {
4425 pr_warn("Unable to read status\n");
4426 goto end;
4427 }
4428
4429 if (!device->status.enabled)
4430 dprintk("Device disabled\n");
4431 else
4432 dprintk("Device enabled\n");
4433
4434
4435
4436
4437 dprintk("Evaluating %s\n", METHOD_NAME__PRS);
4438 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
4439 sony_pic_read_possible_resource, &spic_dev);
4440 if (ACPI_FAILURE(status)) {
4441 pr_warn("Failure evaluating %s\n", METHOD_NAME__PRS);
4442 result = -ENODEV;
4443 }
4444end:
4445 return result;
4446}
4447
4448
4449
4450
4451static int sony_pic_disable(struct acpi_device *device)
4452{
4453 acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL,
4454 NULL);
4455
4456 if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND)
4457 return -ENXIO;
4458
4459 dprintk("Device disabled\n");
4460 return 0;
4461}
4462
4463
4464
4465
4466
4467
4468
4469static int sony_pic_enable(struct acpi_device *device,
4470 struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
4471{
4472 acpi_status status;
4473 int result = 0;
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485 struct {
4486 struct acpi_resource res1;
4487 struct acpi_resource res2;
4488 struct acpi_resource res3;
4489 struct acpi_resource res4;
4490 } *resource;
4491 struct acpi_buffer buffer = { 0, NULL };
4492
4493 if (!ioport || !irq)
4494 return -EINVAL;
4495
4496
4497 resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
4498 if (!resource)
4499 return -ENOMEM;
4500
4501 buffer.length = sizeof(*resource) + 1;
4502 buffer.pointer = resource;
4503
4504
4505 if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
4506
4507
4508 resource->res1.type = ACPI_RESOURCE_TYPE_IO;
4509 resource->res1.length = sizeof(struct acpi_resource);
4510 memcpy(&resource->res1.data.io, &ioport->io1,
4511 sizeof(struct acpi_resource_io));
4512
4513 resource->res2.type = ACPI_RESOURCE_TYPE_IO;
4514 resource->res2.length = sizeof(struct acpi_resource);
4515 memcpy(&resource->res2.data.io, &ioport->io2,
4516 sizeof(struct acpi_resource_io));
4517
4518
4519 resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
4520 resource->res3.length = sizeof(struct acpi_resource);
4521 memcpy(&resource->res3.data.irq, &irq->irq,
4522 sizeof(struct acpi_resource_irq));
4523
4524 resource->res3.data.irq.sharable = ACPI_SHARED;
4525
4526 resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
4527 resource->res4.length = sizeof(struct acpi_resource);
4528 }
4529
4530 else {
4531
4532 resource->res1.type = ACPI_RESOURCE_TYPE_IO;
4533 resource->res1.length = sizeof(struct acpi_resource);
4534 memcpy(&resource->res1.data.io, &ioport->io1,
4535 sizeof(struct acpi_resource_io));
4536
4537
4538 resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
4539 resource->res2.length = sizeof(struct acpi_resource);
4540 memcpy(&resource->res2.data.irq, &irq->irq,
4541 sizeof(struct acpi_resource_irq));
4542
4543 resource->res2.data.irq.sharable = ACPI_SHARED;
4544
4545 resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
4546 resource->res3.length = sizeof(struct acpi_resource);
4547 }
4548
4549
4550 dprintk("Evaluating _SRS\n");
4551 status = acpi_set_current_resources(device->handle, &buffer);
4552
4553
4554 if (ACPI_FAILURE(status)) {
4555 pr_err("Error evaluating _SRS\n");
4556 result = -ENODEV;
4557 goto end;
4558 }
4559
4560
4561 sony_pic_call1(0x82);
4562 sony_pic_call2(0x81, 0xff);
4563 sony_pic_call1(compat ? 0x92 : 0x82);
4564
4565end:
4566 kfree(resource);
4567 return result;
4568}
4569
4570
4571
4572
4573
4574
4575static irqreturn_t sony_pic_irq(int irq, void *dev_id)
4576{
4577 int i, j;
4578 u8 ev = 0;
4579 u8 data_mask = 0;
4580 u8 device_event = 0;
4581
4582 struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
4583
4584 ev = inb_p(dev->cur_ioport->io1.minimum);
4585 if (dev->cur_ioport->io2.minimum)
4586 data_mask = inb_p(dev->cur_ioport->io2.minimum);
4587 else
4588 data_mask = inb_p(dev->cur_ioport->io1.minimum +
4589 dev->evport_offset);
4590
4591 dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
4592 ev, data_mask, dev->cur_ioport->io1.minimum,
4593 dev->evport_offset);
4594
4595 if (ev == 0x00 || ev == 0xff)
4596 return IRQ_HANDLED;
4597
4598 for (i = 0; dev->event_types[i].mask; i++) {
4599
4600 if ((data_mask & dev->event_types[i].data) !=
4601 dev->event_types[i].data)
4602 continue;
4603
4604 if (!(mask & dev->event_types[i].mask))
4605 continue;
4606
4607 for (j = 0; dev->event_types[i].events[j].event; j++) {
4608 if (ev == dev->event_types[i].events[j].data) {
4609 device_event =
4610 dev->event_types[i].events[j].event;
4611
4612 if (!device_event)
4613 return IRQ_HANDLED;
4614 goto found;
4615 }
4616 }
4617 }
4618
4619
4620
4621 if (dev->handle_irq && dev->handle_irq(data_mask, ev) == 0)
4622 return IRQ_HANDLED;
4623
4624 dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
4625 ev, data_mask, dev->cur_ioport->io1.minimum,
4626 dev->evport_offset);
4627 return IRQ_HANDLED;
4628
4629found:
4630 sony_laptop_report_input_event(device_event);
4631 sonypi_compat_report_event(device_event);
4632 return IRQ_HANDLED;
4633}
4634
4635
4636
4637
4638
4639
4640static int sony_pic_remove(struct acpi_device *device)
4641{
4642 struct sony_pic_ioport *io, *tmp_io;
4643 struct sony_pic_irq *irq, *tmp_irq;
4644
4645 if (sony_pic_disable(device)) {
4646 pr_err("Couldn't disable device\n");
4647 return -ENXIO;
4648 }
4649
4650 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
4651 release_region(spic_dev.cur_ioport->io1.minimum,
4652 spic_dev.cur_ioport->io1.address_length);
4653 if (spic_dev.cur_ioport->io2.minimum)
4654 release_region(spic_dev.cur_ioport->io2.minimum,
4655 spic_dev.cur_ioport->io2.address_length);
4656
4657 sonypi_compat_exit();
4658
4659 sony_laptop_remove_input();
4660
4661
4662 sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
4663 sony_pf_remove();
4664
4665 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
4666 list_del(&io->list);
4667 kfree(io);
4668 }
4669 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
4670 list_del(&irq->list);
4671 kfree(irq);
4672 }
4673 spic_dev.cur_ioport = NULL;
4674 spic_dev.cur_irq = NULL;
4675
4676 dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
4677 return 0;
4678}
4679
4680static int sony_pic_add(struct acpi_device *device)
4681{
4682 int result;
4683 struct sony_pic_ioport *io, *tmp_io;
4684 struct sony_pic_irq *irq, *tmp_irq;
4685
4686 spic_dev.acpi_dev = device;
4687 strcpy(acpi_device_class(device), "sony/hotkey");
4688 sony_pic_detect_device_type(&spic_dev);
4689 mutex_init(&spic_dev.lock);
4690
4691
4692 result = sony_pic_possible_resources(device);
4693 if (result) {
4694 pr_err("Unable to read possible resources\n");
4695 goto err_free_resources;
4696 }
4697
4698
4699 result = sony_laptop_setup_input(device);
4700 if (result) {
4701 pr_err("Unable to create input devices\n");
4702 goto err_free_resources;
4703 }
4704
4705 result = sonypi_compat_init();
4706 if (result)
4707 goto err_remove_input;
4708
4709
4710 list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
4711 if (request_region(io->io1.minimum, io->io1.address_length,
4712 "Sony Programmable I/O Device")) {
4713 dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
4714 io->io1.minimum, io->io1.maximum,
4715 io->io1.address_length);
4716
4717 if (io->io2.minimum) {
4718 if (request_region(io->io2.minimum,
4719 io->io2.address_length,
4720 "Sony Programmable I/O Device")) {
4721 dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
4722 io->io2.minimum, io->io2.maximum,
4723 io->io2.address_length);
4724 spic_dev.cur_ioport = io;
4725 break;
4726 }
4727 else {
4728 dprintk("Unable to get I/O port2: "
4729 "0x%.4x (0x%.4x) + 0x%.2x\n",
4730 io->io2.minimum, io->io2.maximum,
4731 io->io2.address_length);
4732 release_region(io->io1.minimum,
4733 io->io1.address_length);
4734 }
4735 }
4736 else {
4737 spic_dev.cur_ioport = io;
4738 break;
4739 }
4740 }
4741 }
4742 if (!spic_dev.cur_ioport) {
4743 pr_err("Failed to request_region\n");
4744 result = -ENODEV;
4745 goto err_remove_compat;
4746 }
4747
4748
4749 list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
4750 if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
4751 0, "sony-laptop", &spic_dev)) {
4752 dprintk("IRQ: %d - triggering: %d - "
4753 "polarity: %d - shr: %d\n",
4754 irq->irq.interrupts[0],
4755 irq->irq.triggering,
4756 irq->irq.polarity,
4757 irq->irq.sharable);
4758 spic_dev.cur_irq = irq;
4759 break;
4760 }
4761 }
4762 if (!spic_dev.cur_irq) {
4763 pr_err("Failed to request_irq\n");
4764 result = -ENODEV;
4765 goto err_release_region;
4766 }
4767
4768
4769 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
4770 if (result) {
4771 pr_err("Couldn't enable device\n");
4772 goto err_free_irq;
4773 }
4774
4775 spic_dev.bluetooth_power = -1;
4776
4777 result = sony_pf_add();
4778 if (result)
4779 goto err_disable_device;
4780
4781 result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
4782 if (result)
4783 goto err_remove_pf;
4784
4785 pr_info("SPIC setup done.\n");
4786 return 0;
4787
4788err_remove_pf:
4789 sony_pf_remove();
4790
4791err_disable_device:
4792 sony_pic_disable(device);
4793
4794err_free_irq:
4795 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
4796
4797err_release_region:
4798 release_region(spic_dev.cur_ioport->io1.minimum,
4799 spic_dev.cur_ioport->io1.address_length);
4800 if (spic_dev.cur_ioport->io2.minimum)
4801 release_region(spic_dev.cur_ioport->io2.minimum,
4802 spic_dev.cur_ioport->io2.address_length);
4803
4804err_remove_compat:
4805 sonypi_compat_exit();
4806
4807err_remove_input:
4808 sony_laptop_remove_input();
4809
4810err_free_resources:
4811 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
4812 list_del(&io->list);
4813 kfree(io);
4814 }
4815 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
4816 list_del(&irq->list);
4817 kfree(irq);
4818 }
4819 spic_dev.cur_ioport = NULL;
4820 spic_dev.cur_irq = NULL;
4821
4822 return result;
4823}
4824
4825#ifdef CONFIG_PM_SLEEP
4826static int sony_pic_suspend(struct device *dev)
4827{
4828 if (sony_pic_disable(to_acpi_device(dev)))
4829 return -ENXIO;
4830 return 0;
4831}
4832
4833static int sony_pic_resume(struct device *dev)
4834{
4835 sony_pic_enable(to_acpi_device(dev),
4836 spic_dev.cur_ioport, spic_dev.cur_irq);
4837 return 0;
4838}
4839#endif
4840
4841static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume);
4842
4843static const struct acpi_device_id sony_pic_device_ids[] = {
4844 {SONY_PIC_HID, 0},
4845 {"", 0},
4846};
4847
4848static struct acpi_driver sony_pic_driver = {
4849 .name = SONY_PIC_DRIVER_NAME,
4850 .class = SONY_PIC_CLASS,
4851 .ids = sony_pic_device_ids,
4852 .owner = THIS_MODULE,
4853 .ops = {
4854 .add = sony_pic_add,
4855 .remove = sony_pic_remove,
4856 },
4857 .drv.pm = &sony_pic_pm,
4858};
4859
4860static struct dmi_system_id __initdata sonypi_dmi_table[] = {
4861 {
4862 .ident = "Sony Vaio",
4863 .matches = {
4864 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
4865 DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
4866 },
4867 },
4868 {
4869 .ident = "Sony Vaio",
4870 .matches = {
4871 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
4872 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
4873 },
4874 },
4875 { }
4876};
4877
4878static int __init sony_laptop_init(void)
4879{
4880 int result;
4881
4882 if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
4883 result = acpi_bus_register_driver(&sony_pic_driver);
4884 if (result) {
4885 pr_err("Unable to register SPIC driver\n");
4886 goto out;
4887 }
4888 spic_drv_registered = 1;
4889 }
4890
4891 result = acpi_bus_register_driver(&sony_nc_driver);
4892 if (result) {
4893 pr_err("Unable to register SNC driver\n");
4894 goto out_unregister_pic;
4895 }
4896
4897 return 0;
4898
4899out_unregister_pic:
4900 if (spic_drv_registered)
4901 acpi_bus_unregister_driver(&sony_pic_driver);
4902out:
4903 return result;
4904}
4905
4906static void __exit sony_laptop_exit(void)
4907{
4908 acpi_bus_unregister_driver(&sony_nc_driver);
4909 if (spic_drv_registered)
4910 acpi_bus_unregister_driver(&sony_pic_driver);
4911}
4912
4913module_init(sony_laptop_init);
4914module_exit(sony_laptop_exit);
4915