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