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