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 break;
2471 case 0x015B:
2472
2473
2474
2475 return result & 0x1 ? STAMINA : SPEED;
2476 break;
2477 case 0x0128:
2478
2479
2480
2481
2482 dprintk("GFX Status: 0x%x\n", result);
2483 return result & 0x80 ? AUTO :
2484 result & 0x02 ? STAMINA : SPEED;
2485 break;
2486 }
2487 return -EINVAL;
2488}
2489
2490static ssize_t sony_nc_gfx_switch_status_show(struct device *dev,
2491 struct device_attribute *attr,
2492 char *buffer)
2493{
2494 int pos = __sony_nc_gfx_switch_status_get();
2495
2496 if (pos < 0)
2497 return pos;
2498
2499 return snprintf(buffer, PAGE_SIZE, "%s\n",
2500 pos == SPEED ? "speed" :
2501 pos == STAMINA ? "stamina" :
2502 pos == AUTO ? "auto" : "unknown");
2503}
2504
2505static int sony_nc_gfx_switch_setup(struct platform_device *pd,
2506 unsigned int handle)
2507{
2508 unsigned int result;
2509
2510 gfxs_ctl = kzalloc(sizeof(struct snc_gfx_switch_control), GFP_KERNEL);
2511 if (!gfxs_ctl)
2512 return -ENOMEM;
2513
2514 gfxs_ctl->handle = handle;
2515
2516 sysfs_attr_init(&gfxs_ctl->attr.attr);
2517 gfxs_ctl->attr.attr.name = "gfx_switch_status";
2518 gfxs_ctl->attr.attr.mode = S_IRUGO;
2519 gfxs_ctl->attr.show = sony_nc_gfx_switch_status_show;
2520
2521 result = device_create_file(&pd->dev, &gfxs_ctl->attr);
2522 if (result)
2523 goto gfxerror;
2524
2525 return 0;
2526
2527gfxerror:
2528 kfree(gfxs_ctl);
2529 gfxs_ctl = NULL;
2530
2531 return result;
2532}
2533
2534static void sony_nc_gfx_switch_cleanup(struct platform_device *pd)
2535{
2536 if (gfxs_ctl) {
2537 device_remove_file(&pd->dev, &gfxs_ctl->attr);
2538
2539 kfree(gfxs_ctl);
2540 gfxs_ctl = NULL;
2541 }
2542}
2543
2544
2545static struct device_attribute *hsc_handle;
2546
2547static ssize_t sony_nc_highspeed_charging_store(struct device *dev,
2548 struct device_attribute *attr,
2549 const char *buffer, size_t count)
2550{
2551 unsigned int result;
2552 unsigned long value;
2553
2554 if (count > 31)
2555 return -EINVAL;
2556
2557 if (kstrtoul(buffer, 10, &value) || value > 1)
2558 return -EINVAL;
2559
2560 if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result))
2561 return -EIO;
2562
2563 return count;
2564}
2565
2566static ssize_t sony_nc_highspeed_charging_show(struct device *dev,
2567 struct device_attribute *attr, char *buffer)
2568{
2569 unsigned int result;
2570
2571 if (sony_call_snc_handle(0x0131, 0x0100, &result))
2572 return -EIO;
2573
2574 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2575}
2576
2577static int sony_nc_highspeed_charging_setup(struct platform_device *pd)
2578{
2579 unsigned int result;
2580
2581 if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) {
2582
2583
2584
2585 pr_info("No High Speed Charging capability found\n");
2586 return 0;
2587 }
2588
2589 hsc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2590 if (!hsc_handle)
2591 return -ENOMEM;
2592
2593 sysfs_attr_init(&hsc_handle->attr);
2594 hsc_handle->attr.name = "battery_highspeed_charging";
2595 hsc_handle->attr.mode = S_IRUGO | S_IWUSR;
2596 hsc_handle->show = sony_nc_highspeed_charging_show;
2597 hsc_handle->store = sony_nc_highspeed_charging_store;
2598
2599 result = device_create_file(&pd->dev, hsc_handle);
2600 if (result) {
2601 kfree(hsc_handle);
2602 hsc_handle = NULL;
2603 return result;
2604 }
2605
2606 return 0;
2607}
2608
2609static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
2610{
2611 if (hsc_handle) {
2612 device_remove_file(&pd->dev, hsc_handle);
2613 kfree(hsc_handle);
2614 hsc_handle = NULL;
2615 }
2616}
2617
2618
2619static struct device_attribute *lowbatt_handle;
2620
2621static ssize_t sony_nc_lowbatt_store(struct device *dev,
2622 struct device_attribute *attr,
2623 const char *buffer, size_t count)
2624{
2625 unsigned int result;
2626 unsigned long value;
2627
2628 if (count > 31)
2629 return -EINVAL;
2630
2631 if (kstrtoul(buffer, 10, &value) || value > 1)
2632 return -EINVAL;
2633
2634 if (sony_call_snc_handle(0x0121, value << 8, &result))
2635 return -EIO;
2636
2637 return count;
2638}
2639
2640static ssize_t sony_nc_lowbatt_show(struct device *dev,
2641 struct device_attribute *attr, char *buffer)
2642{
2643 unsigned int result;
2644
2645 if (sony_call_snc_handle(0x0121, 0x0200, &result))
2646 return -EIO;
2647
2648 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 1);
2649}
2650
2651static int sony_nc_lowbatt_setup(struct platform_device *pd)
2652{
2653 unsigned int result;
2654
2655 lowbatt_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2656 if (!lowbatt_handle)
2657 return -ENOMEM;
2658
2659 sysfs_attr_init(&lowbatt_handle->attr);
2660 lowbatt_handle->attr.name = "lowbatt_hibernate";
2661 lowbatt_handle->attr.mode = S_IRUGO | S_IWUSR;
2662 lowbatt_handle->show = sony_nc_lowbatt_show;
2663 lowbatt_handle->store = sony_nc_lowbatt_store;
2664
2665 result = device_create_file(&pd->dev, lowbatt_handle);
2666 if (result) {
2667 kfree(lowbatt_handle);
2668 lowbatt_handle = NULL;
2669 return result;
2670 }
2671
2672 return 0;
2673}
2674
2675static void sony_nc_lowbatt_cleanup(struct platform_device *pd)
2676{
2677 if (lowbatt_handle) {
2678 device_remove_file(&pd->dev, lowbatt_handle);
2679 kfree(lowbatt_handle);
2680 lowbatt_handle = NULL;
2681 }
2682}
2683
2684
2685static struct device_attribute *fan_handle, *hsf_handle;
2686
2687static ssize_t sony_nc_hsfan_store(struct device *dev,
2688 struct device_attribute *attr,
2689 const char *buffer, size_t count)
2690{
2691 unsigned int result;
2692 unsigned long value;
2693
2694 if (count > 31)
2695 return -EINVAL;
2696
2697 if (kstrtoul(buffer, 10, &value) || value > 1)
2698 return -EINVAL;
2699
2700 if (sony_call_snc_handle(0x0149, value << 0x10 | 0x0200, &result))
2701 return -EIO;
2702
2703 return count;
2704}
2705
2706static ssize_t sony_nc_hsfan_show(struct device *dev,
2707 struct device_attribute *attr, char *buffer)
2708{
2709 unsigned int result;
2710
2711 if (sony_call_snc_handle(0x0149, 0x0100, &result))
2712 return -EIO;
2713
2714 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2715}
2716
2717static ssize_t sony_nc_fanspeed_show(struct device *dev,
2718 struct device_attribute *attr, char *buffer)
2719{
2720 unsigned int result;
2721
2722 if (sony_call_snc_handle(0x0149, 0x0300, &result))
2723 return -EIO;
2724
2725 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff);
2726}
2727
2728static int sony_nc_fanspeed_setup(struct platform_device *pd)
2729{
2730 unsigned int result;
2731
2732 fan_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2733 if (!fan_handle)
2734 return -ENOMEM;
2735
2736 hsf_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2737 if (!hsf_handle) {
2738 result = -ENOMEM;
2739 goto out_hsf_handle_alloc;
2740 }
2741
2742 sysfs_attr_init(&fan_handle->attr);
2743 fan_handle->attr.name = "fanspeed";
2744 fan_handle->attr.mode = S_IRUGO;
2745 fan_handle->show = sony_nc_fanspeed_show;
2746 fan_handle->store = NULL;
2747
2748 sysfs_attr_init(&hsf_handle->attr);
2749 hsf_handle->attr.name = "fan_forced";
2750 hsf_handle->attr.mode = S_IRUGO | S_IWUSR;
2751 hsf_handle->show = sony_nc_hsfan_show;
2752 hsf_handle->store = sony_nc_hsfan_store;
2753
2754 result = device_create_file(&pd->dev, fan_handle);
2755 if (result)
2756 goto out_fan_handle;
2757
2758 result = device_create_file(&pd->dev, hsf_handle);
2759 if (result)
2760 goto out_hsf_handle;
2761
2762 return 0;
2763
2764out_hsf_handle:
2765 device_remove_file(&pd->dev, fan_handle);
2766
2767out_fan_handle:
2768 kfree(hsf_handle);
2769 hsf_handle = NULL;
2770
2771out_hsf_handle_alloc:
2772 kfree(fan_handle);
2773 fan_handle = NULL;
2774 return result;
2775}
2776
2777static void sony_nc_fanspeed_cleanup(struct platform_device *pd)
2778{
2779 if (fan_handle) {
2780 device_remove_file(&pd->dev, fan_handle);
2781 kfree(fan_handle);
2782 fan_handle = NULL;
2783 }
2784 if (hsf_handle) {
2785 device_remove_file(&pd->dev, hsf_handle);
2786 kfree(hsf_handle);
2787 hsf_handle = NULL;
2788 }
2789}
2790
2791
2792static struct device_attribute *uc_handle;
2793
2794static ssize_t sony_nc_usb_charge_store(struct device *dev,
2795 struct device_attribute *attr,
2796 const char *buffer, size_t count)
2797{
2798 unsigned int result;
2799 unsigned long value;
2800
2801 if (count > 31)
2802 return -EINVAL;
2803
2804 if (kstrtoul(buffer, 10, &value) || value > 1)
2805 return -EINVAL;
2806
2807 if (sony_call_snc_handle(0x0155, value << 0x10 | 0x0100, &result))
2808 return -EIO;
2809
2810 return count;
2811}
2812
2813static ssize_t sony_nc_usb_charge_show(struct device *dev,
2814 struct device_attribute *attr, char *buffer)
2815{
2816 unsigned int result;
2817
2818 if (sony_call_snc_handle(0x0155, 0x0000, &result))
2819 return -EIO;
2820
2821 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2822}
2823
2824static int sony_nc_usb_charge_setup(struct platform_device *pd)
2825{
2826 unsigned int result;
2827
2828 if (sony_call_snc_handle(0x0155, 0x0000, &result) || !(result & 0x01)) {
2829
2830
2831
2832 pr_info("No USB Charge capability found\n");
2833 return 0;
2834 }
2835
2836 uc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2837 if (!uc_handle)
2838 return -ENOMEM;
2839
2840 sysfs_attr_init(&uc_handle->attr);
2841 uc_handle->attr.name = "usb_charge";
2842 uc_handle->attr.mode = S_IRUGO | S_IWUSR;
2843 uc_handle->show = sony_nc_usb_charge_show;
2844 uc_handle->store = sony_nc_usb_charge_store;
2845
2846 result = device_create_file(&pd->dev, uc_handle);
2847 if (result) {
2848 kfree(uc_handle);
2849 uc_handle = NULL;
2850 return result;
2851 }
2852
2853 return 0;
2854}
2855
2856static void sony_nc_usb_charge_cleanup(struct platform_device *pd)
2857{
2858 if (uc_handle) {
2859 device_remove_file(&pd->dev, uc_handle);
2860 kfree(uc_handle);
2861 uc_handle = NULL;
2862 }
2863}
2864
2865
2866static struct device_attribute *panel_handle;
2867
2868static ssize_t sony_nc_panelid_show(struct device *dev,
2869 struct device_attribute *attr, char *buffer)
2870{
2871 unsigned int result;
2872
2873 if (sony_call_snc_handle(0x011D, 0x0000, &result))
2874 return -EIO;
2875
2876 return snprintf(buffer, PAGE_SIZE, "%d\n", result);
2877}
2878
2879static int sony_nc_panelid_setup(struct platform_device *pd)
2880{
2881 unsigned int result;
2882
2883 panel_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2884 if (!panel_handle)
2885 return -ENOMEM;
2886
2887 sysfs_attr_init(&panel_handle->attr);
2888 panel_handle->attr.name = "panel_id";
2889 panel_handle->attr.mode = S_IRUGO;
2890 panel_handle->show = sony_nc_panelid_show;
2891 panel_handle->store = NULL;
2892
2893 result = device_create_file(&pd->dev, panel_handle);
2894 if (result) {
2895 kfree(panel_handle);
2896 panel_handle = NULL;
2897 return result;
2898 }
2899
2900 return 0;
2901}
2902
2903static void sony_nc_panelid_cleanup(struct platform_device *pd)
2904{
2905 if (panel_handle) {
2906 device_remove_file(&pd->dev, panel_handle);
2907 kfree(panel_handle);
2908 panel_handle = NULL;
2909 }
2910}
2911
2912
2913static struct device_attribute *sc_handle;
2914
2915static ssize_t sony_nc_smart_conn_store(struct device *dev,
2916 struct device_attribute *attr,
2917 const char *buffer, size_t count)
2918{
2919 unsigned int result;
2920 unsigned long value;
2921
2922 if (count > 31)
2923 return -EINVAL;
2924
2925 if (kstrtoul(buffer, 10, &value) || value > 1)
2926 return -EINVAL;
2927
2928 if (sony_call_snc_handle(0x0168, value << 0x10, &result))
2929 return -EIO;
2930
2931 return count;
2932}
2933
2934static int sony_nc_smart_conn_setup(struct platform_device *pd)
2935{
2936 unsigned int result;
2937
2938 sc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2939 if (!sc_handle)
2940 return -ENOMEM;
2941
2942 sysfs_attr_init(&sc_handle->attr);
2943 sc_handle->attr.name = "smart_connect";
2944 sc_handle->attr.mode = S_IWUSR;
2945 sc_handle->show = NULL;
2946 sc_handle->store = sony_nc_smart_conn_store;
2947
2948 result = device_create_file(&pd->dev, sc_handle);
2949 if (result) {
2950 kfree(sc_handle);
2951 sc_handle = NULL;
2952 return result;
2953 }
2954
2955 return 0;
2956}
2957
2958static void sony_nc_smart_conn_cleanup(struct platform_device *pd)
2959{
2960 if (sc_handle) {
2961 device_remove_file(&pd->dev, sc_handle);
2962 kfree(sc_handle);
2963 sc_handle = NULL;
2964 }
2965}
2966
2967
2968struct touchpad_control {
2969 struct device_attribute attr;
2970 int handle;
2971};
2972static struct touchpad_control *tp_ctl;
2973
2974static ssize_t sony_nc_touchpad_store(struct device *dev,
2975 struct device_attribute *attr, const char *buffer, size_t count)
2976{
2977 unsigned int result;
2978 unsigned long value;
2979
2980 if (count > 31)
2981 return -EINVAL;
2982
2983 if (kstrtoul(buffer, 10, &value) || value > 1)
2984 return -EINVAL;
2985
2986
2987
2988
2989 if (sony_call_snc_handle(tp_ctl->handle,
2990 (!value << 0x10) | 0x100, &result))
2991 return -EIO;
2992
2993 return count;
2994}
2995
2996static ssize_t sony_nc_touchpad_show(struct device *dev,
2997 struct device_attribute *attr, char *buffer)
2998{
2999 unsigned int result;
3000
3001 if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result))
3002 return -EINVAL;
3003
3004 return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01));
3005}
3006
3007static int sony_nc_touchpad_setup(struct platform_device *pd,
3008 unsigned int handle)
3009{
3010 int ret = 0;
3011
3012 tp_ctl = kzalloc(sizeof(struct touchpad_control), GFP_KERNEL);
3013 if (!tp_ctl)
3014 return -ENOMEM;
3015
3016 tp_ctl->handle = handle;
3017
3018 sysfs_attr_init(&tp_ctl->attr.attr);
3019 tp_ctl->attr.attr.name = "touchpad";
3020 tp_ctl->attr.attr.mode = S_IRUGO | S_IWUSR;
3021 tp_ctl->attr.show = sony_nc_touchpad_show;
3022 tp_ctl->attr.store = sony_nc_touchpad_store;
3023
3024 ret = device_create_file(&pd->dev, &tp_ctl->attr);
3025 if (ret) {
3026 kfree(tp_ctl);
3027 tp_ctl = NULL;
3028 }
3029
3030 return ret;
3031}
3032
3033static void sony_nc_touchpad_cleanup(struct platform_device *pd)
3034{
3035 if (tp_ctl) {
3036 device_remove_file(&pd->dev, &tp_ctl->attr);
3037 kfree(tp_ctl);
3038 tp_ctl = NULL;
3039 }
3040}
3041
3042static void sony_nc_backlight_ng_read_limits(int handle,
3043 struct sony_backlight_props *props)
3044{
3045 u64 offset;
3046 int i;
3047 int lvl_table_len = 0;
3048 u8 min = 0xff, max = 0x00;
3049 unsigned char buffer[32] = { 0 };
3050
3051 props->handle = handle;
3052 props->offset = 0;
3053 props->maxlvl = 0xff;
3054
3055 offset = sony_find_snc_handle(handle);
3056
3057
3058
3059
3060 i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
3061 32);
3062 if (i < 0)
3063 return;
3064
3065 switch (handle) {
3066 case 0x012f:
3067 case 0x0137:
3068 lvl_table_len = 9;
3069 break;
3070 case 0x143:
3071 case 0x14b:
3072 case 0x14c:
3073 lvl_table_len = 16;
3074 break;
3075 }
3076
3077
3078
3079
3080
3081 for (i = 0; i < lvl_table_len && i < ARRAY_SIZE(buffer); i++) {
3082
3083 dprintk("Brightness level: %d\n", buffer[i]);
3084
3085 if (!buffer[i])
3086 break;
3087
3088 if (buffer[i] > max)
3089 max = buffer[i];
3090 if (buffer[i] < min)
3091 min = buffer[i];
3092 }
3093 props->offset = min;
3094 props->maxlvl = max;
3095 dprintk("Brightness levels: min=%d max=%d\n", props->offset,
3096 props->maxlvl);
3097}
3098
3099static void sony_nc_backlight_setup(void)
3100{
3101 int max_brightness = 0;
3102 const struct backlight_ops *ops = NULL;
3103 struct backlight_properties props;
3104
3105 if (sony_find_snc_handle(0x12f) >= 0) {
3106 ops = &sony_backlight_ng_ops;
3107 sony_bl_props.cmd_base = 0x0100;
3108 sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
3109 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3110
3111 } else if (sony_find_snc_handle(0x137) >= 0) {
3112 ops = &sony_backlight_ng_ops;
3113 sony_bl_props.cmd_base = 0x0100;
3114 sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
3115 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3116
3117 } else if (sony_find_snc_handle(0x143) >= 0) {
3118 ops = &sony_backlight_ng_ops;
3119 sony_bl_props.cmd_base = 0x3000;
3120 sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
3121 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3122
3123 } else if (sony_find_snc_handle(0x14b) >= 0) {
3124 ops = &sony_backlight_ng_ops;
3125 sony_bl_props.cmd_base = 0x3000;
3126 sony_nc_backlight_ng_read_limits(0x14b, &sony_bl_props);
3127 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3128
3129 } else if (sony_find_snc_handle(0x14c) >= 0) {
3130 ops = &sony_backlight_ng_ops;
3131 sony_bl_props.cmd_base = 0x3000;
3132 sony_nc_backlight_ng_read_limits(0x14c, &sony_bl_props);
3133 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3134
3135 } else if (acpi_has_method(sony_nc_acpi_handle, "GBRT")) {
3136 ops = &sony_backlight_ops;
3137 max_brightness = SONY_MAX_BRIGHTNESS - 1;
3138
3139 } else
3140 return;
3141
3142 memset(&props, 0, sizeof(struct backlight_properties));
3143 props.type = BACKLIGHT_PLATFORM;
3144 props.max_brightness = max_brightness;
3145 sony_bl_props.dev = backlight_device_register("sony", NULL,
3146 &sony_bl_props,
3147 ops, &props);
3148
3149 if (IS_ERR(sony_bl_props.dev)) {
3150 pr_warn("unable to register backlight device\n");
3151 sony_bl_props.dev = NULL;
3152 } else
3153 sony_bl_props.dev->props.brightness =
3154 ops->get_brightness(sony_bl_props.dev);
3155}
3156
3157static void sony_nc_backlight_cleanup(void)
3158{
3159 backlight_device_unregister(sony_bl_props.dev);
3160}
3161
3162static int sony_nc_add(struct acpi_device *device)
3163{
3164 acpi_status status;
3165 int result = 0;
3166 struct sony_nc_value *item;
3167
3168 sony_nc_acpi_device = device;
3169 strcpy(acpi_device_class(device), "sony/hotkey");
3170
3171 sony_nc_acpi_handle = device->handle;
3172
3173
3174 result = acpi_bus_get_status(device);
3175
3176 if (!result && !device->status.present) {
3177 dprintk("Device not present\n");
3178 result = -ENODEV;
3179 goto outwalk;
3180 }
3181
3182 result = sony_pf_add();
3183 if (result)
3184 goto outpresent;
3185
3186 if (debug) {
3187 status = acpi_walk_namespace(ACPI_TYPE_METHOD,
3188 sony_nc_acpi_handle, 1, sony_walk_callback,
3189 NULL, NULL, NULL);
3190 if (ACPI_FAILURE(status)) {
3191 pr_warn("unable to walk acpi resources\n");
3192 result = -ENODEV;
3193 goto outpresent;
3194 }
3195 }
3196
3197 result = sony_laptop_setup_input(device);
3198 if (result) {
3199 pr_err("Unable to create input devices\n");
3200 goto outplatform;
3201 }
3202
3203 if (acpi_has_method(sony_nc_acpi_handle, "ECON")) {
3204 int arg = 1;
3205 if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
3206 dprintk("ECON Method failed\n");
3207 }
3208
3209 if (acpi_has_method(sony_nc_acpi_handle, "SN00")) {
3210 dprintk("Doing SNC setup\n");
3211
3212 result = sony_nc_handles_setup(sony_pf_device);
3213 if (!result)
3214 sony_nc_function_setup(device, sony_pf_device);
3215 }
3216
3217 if (acpi_video_get_backlight_type() == acpi_backlight_vendor)
3218 sony_nc_backlight_setup();
3219
3220
3221 for (item = sony_nc_values; item->name; ++item) {
3222
3223 if (!debug && item->debug)
3224 continue;
3225
3226
3227 for (; item->acpiget && *item->acpiget; ++item->acpiget) {
3228 if (acpi_has_method(sony_nc_acpi_handle,
3229 *item->acpiget)) {
3230 dprintk("Found %s getter: %s\n",
3231 item->name, *item->acpiget);
3232 item->devattr.attr.mode |= S_IRUGO;
3233 break;
3234 }
3235 }
3236
3237
3238 for (; item->acpiset && *item->acpiset; ++item->acpiset) {
3239 if (acpi_has_method(sony_nc_acpi_handle,
3240 *item->acpiset)) {
3241 dprintk("Found %s setter: %s\n",
3242 item->name, *item->acpiset);
3243 item->devattr.attr.mode |= S_IWUSR;
3244 break;
3245 }
3246 }
3247
3248 if (item->devattr.attr.mode != 0) {
3249 result =
3250 device_create_file(&sony_pf_device->dev,
3251 &item->devattr);
3252 if (result)
3253 goto out_sysfs;
3254 }
3255 }
3256
3257 pr_info("SNC setup done.\n");
3258 return 0;
3259
3260out_sysfs:
3261 for (item = sony_nc_values; item->name; ++item) {
3262 device_remove_file(&sony_pf_device->dev, &item->devattr);
3263 }
3264 sony_nc_backlight_cleanup();
3265 sony_nc_function_cleanup(sony_pf_device);
3266 sony_nc_handles_cleanup(sony_pf_device);
3267
3268outplatform:
3269 sony_laptop_remove_input();
3270
3271outpresent:
3272 sony_pf_remove();
3273
3274outwalk:
3275 sony_nc_rfkill_cleanup();
3276 return result;
3277}
3278
3279static int sony_nc_remove(struct acpi_device *device)
3280{
3281 struct sony_nc_value *item;
3282
3283 sony_nc_backlight_cleanup();
3284
3285 sony_nc_acpi_device = NULL;
3286
3287 for (item = sony_nc_values; item->name; ++item) {
3288 device_remove_file(&sony_pf_device->dev, &item->devattr);
3289 }
3290
3291 sony_nc_function_cleanup(sony_pf_device);
3292 sony_nc_handles_cleanup(sony_pf_device);
3293 sony_pf_remove();
3294 sony_laptop_remove_input();
3295 dprintk(SONY_NC_DRIVER_NAME " removed.\n");
3296
3297 return 0;
3298}
3299
3300static const struct acpi_device_id sony_device_ids[] = {
3301 {SONY_NC_HID, 0},
3302 {SONY_PIC_HID, 0},
3303 {"", 0},
3304};
3305MODULE_DEVICE_TABLE(acpi, sony_device_ids);
3306
3307static const struct acpi_device_id sony_nc_device_ids[] = {
3308 {SONY_NC_HID, 0},
3309 {"", 0},
3310};
3311
3312static struct acpi_driver sony_nc_driver = {
3313 .name = SONY_NC_DRIVER_NAME,
3314 .class = SONY_NC_CLASS,
3315 .ids = sony_nc_device_ids,
3316 .owner = THIS_MODULE,
3317 .ops = {
3318 .add = sony_nc_add,
3319 .remove = sony_nc_remove,
3320 .notify = sony_nc_notify,
3321 },
3322 .drv.pm = &sony_nc_pm,
3323};
3324
3325
3326
3327#define SONYPI_DEVICE_TYPE1 0x00000001
3328#define SONYPI_DEVICE_TYPE2 0x00000002
3329#define SONYPI_DEVICE_TYPE3 0x00000004
3330
3331#define SONYPI_TYPE1_OFFSET 0x04
3332#define SONYPI_TYPE2_OFFSET 0x12
3333#define SONYPI_TYPE3_OFFSET 0x12
3334
3335struct sony_pic_ioport {
3336 struct acpi_resource_io io1;
3337 struct acpi_resource_io io2;
3338 struct list_head list;
3339};
3340
3341struct sony_pic_irq {
3342 struct acpi_resource_irq irq;
3343 struct list_head list;
3344};
3345
3346struct sonypi_eventtypes {
3347 u8 data;
3348 unsigned long mask;
3349 struct sonypi_event *events;
3350};
3351
3352struct sony_pic_dev {
3353 struct acpi_device *acpi_dev;
3354 struct sony_pic_irq *cur_irq;
3355 struct sony_pic_ioport *cur_ioport;
3356 struct list_head interrupts;
3357 struct list_head ioports;
3358 struct mutex lock;
3359 struct sonypi_eventtypes *event_types;
3360 int (*handle_irq)(const u8, const u8);
3361 int model;
3362 u16 evport_offset;
3363 u8 camera_power;
3364 u8 bluetooth_power;
3365 u8 wwan_power;
3366};
3367
3368static struct sony_pic_dev spic_dev = {
3369 .interrupts = LIST_HEAD_INIT(spic_dev.interrupts),
3370 .ioports = LIST_HEAD_INIT(spic_dev.ioports),
3371};
3372
3373static int spic_drv_registered;
3374
3375
3376#define SONYPI_JOGGER_MASK 0x00000001
3377#define SONYPI_CAPTURE_MASK 0x00000002
3378#define SONYPI_FNKEY_MASK 0x00000004
3379#define SONYPI_BLUETOOTH_MASK 0x00000008
3380#define SONYPI_PKEY_MASK 0x00000010
3381#define SONYPI_BACK_MASK 0x00000020
3382#define SONYPI_HELP_MASK 0x00000040
3383#define SONYPI_LID_MASK 0x00000080
3384#define SONYPI_ZOOM_MASK 0x00000100
3385#define SONYPI_THUMBPHRASE_MASK 0x00000200
3386#define SONYPI_MEYE_MASK 0x00000400
3387#define SONYPI_MEMORYSTICK_MASK 0x00000800
3388#define SONYPI_BATTERY_MASK 0x00001000
3389#define SONYPI_WIRELESS_MASK 0x00002000
3390
3391struct sonypi_event {
3392 u8 data;
3393 u8 event;
3394};
3395
3396
3397static struct sonypi_event sonypi_releaseev[] = {
3398 { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
3399 { 0, 0 }
3400};
3401
3402
3403static struct sonypi_event sonypi_joggerev[] = {
3404 { 0x1f, SONYPI_EVENT_JOGDIAL_UP },
3405 { 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
3406 { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
3407 { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
3408 { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
3409 { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
3410 { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
3411 { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
3412 { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
3413 { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
3414 { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
3415 { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
3416 { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
3417 { 0, 0 }
3418};
3419
3420
3421static struct sonypi_event sonypi_captureev[] = {
3422 { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
3423 { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
3424 { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
3425 { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
3426 { 0, 0 }
3427};
3428
3429
3430static struct sonypi_event sonypi_fnkeyev[] = {
3431 { 0x10, SONYPI_EVENT_FNKEY_ESC },
3432 { 0x11, SONYPI_EVENT_FNKEY_F1 },
3433 { 0x12, SONYPI_EVENT_FNKEY_F2 },
3434 { 0x13, SONYPI_EVENT_FNKEY_F3 },
3435 { 0x14, SONYPI_EVENT_FNKEY_F4 },
3436 { 0x15, SONYPI_EVENT_FNKEY_F5 },
3437 { 0x16, SONYPI_EVENT_FNKEY_F6 },
3438 { 0x17, SONYPI_EVENT_FNKEY_F7 },
3439 { 0x18, SONYPI_EVENT_FNKEY_F8 },
3440 { 0x19, SONYPI_EVENT_FNKEY_F9 },
3441 { 0x1a, SONYPI_EVENT_FNKEY_F10 },
3442 { 0x1b, SONYPI_EVENT_FNKEY_F11 },
3443 { 0x1c, SONYPI_EVENT_FNKEY_F12 },
3444 { 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
3445 { 0x21, SONYPI_EVENT_FNKEY_1 },
3446 { 0x22, SONYPI_EVENT_FNKEY_2 },
3447 { 0x31, SONYPI_EVENT_FNKEY_D },
3448 { 0x32, SONYPI_EVENT_FNKEY_E },
3449 { 0x33, SONYPI_EVENT_FNKEY_F },
3450 { 0x34, SONYPI_EVENT_FNKEY_S },
3451 { 0x35, SONYPI_EVENT_FNKEY_B },
3452 { 0x36, SONYPI_EVENT_FNKEY_ONLY },
3453 { 0, 0 }
3454};
3455
3456
3457static struct sonypi_event sonypi_pkeyev[] = {
3458 { 0x01, SONYPI_EVENT_PKEY_P1 },
3459 { 0x02, SONYPI_EVENT_PKEY_P2 },
3460 { 0x04, SONYPI_EVENT_PKEY_P3 },
3461 { 0x20, SONYPI_EVENT_PKEY_P1 },
3462 { 0, 0 }
3463};
3464
3465
3466static struct sonypi_event sonypi_blueev[] = {
3467 { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
3468 { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
3469 { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
3470 { 0, 0 }
3471};
3472
3473
3474static struct sonypi_event sonypi_wlessev[] = {
3475 { 0x59, SONYPI_EVENT_IGNORE },
3476 { 0x5a, SONYPI_EVENT_IGNORE },
3477 { 0, 0 }
3478};
3479
3480
3481static struct sonypi_event sonypi_backev[] = {
3482 { 0x20, SONYPI_EVENT_BACK_PRESSED },
3483 { 0, 0 }
3484};
3485
3486
3487static struct sonypi_event sonypi_helpev[] = {
3488 { 0x3b, SONYPI_EVENT_HELP_PRESSED },
3489 { 0, 0 }
3490};
3491
3492
3493
3494static struct sonypi_event sonypi_lidev[] = {
3495 { 0x51, SONYPI_EVENT_LID_CLOSED },
3496 { 0x50, SONYPI_EVENT_LID_OPENED },
3497 { 0, 0 }
3498};
3499
3500
3501static struct sonypi_event sonypi_zoomev[] = {
3502 { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
3503 { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
3504 { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
3505 { 0x04, SONYPI_EVENT_ZOOM_PRESSED },
3506 { 0, 0 }
3507};
3508
3509
3510static struct sonypi_event sonypi_thumbphraseev[] = {
3511 { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
3512 { 0, 0 }
3513};
3514
3515
3516static struct sonypi_event sonypi_meyeev[] = {
3517 { 0x00, SONYPI_EVENT_MEYE_FACE },
3518 { 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
3519 { 0, 0 }
3520};
3521
3522
3523static struct sonypi_event sonypi_memorystickev[] = {
3524 { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
3525 { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
3526 { 0, 0 }
3527};
3528
3529
3530static struct sonypi_event sonypi_batteryev[] = {
3531 { 0x20, SONYPI_EVENT_BATTERY_INSERT },
3532 { 0x30, SONYPI_EVENT_BATTERY_REMOVE },
3533 { 0, 0 }
3534};
3535
3536
3537static struct sonypi_event sonypi_volumeev[] = {
3538 { 0x01, SONYPI_EVENT_VOLUME_INC_PRESSED },
3539 { 0x02, SONYPI_EVENT_VOLUME_DEC_PRESSED },
3540 { 0, 0 }
3541};
3542
3543
3544static struct sonypi_event sonypi_brightnessev[] = {
3545 { 0x80, SONYPI_EVENT_BRIGHTNESS_PRESSED },
3546 { 0, 0 }
3547};
3548
3549static struct sonypi_eventtypes type1_events[] = {
3550 { 0, 0xffffffff, sonypi_releaseev },
3551 { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
3552 { 0x30, SONYPI_LID_MASK, sonypi_lidev },
3553 { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
3554 { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
3555 { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3556 { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
3557 { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
3558 { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3559 { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
3560 { 0 },
3561};
3562static struct sonypi_eventtypes type2_events[] = {
3563 { 0, 0xffffffff, sonypi_releaseev },
3564 { 0x38, SONYPI_LID_MASK, sonypi_lidev },
3565 { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
3566 { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
3567 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3568 { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
3569 { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
3570 { 0x11, SONYPI_BACK_MASK, sonypi_backev },
3571 { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
3572 { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
3573 { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
3574 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3575 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
3576 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
3577 { 0 },
3578};
3579static struct sonypi_eventtypes type3_events[] = {
3580 { 0, 0xffffffff, sonypi_releaseev },
3581 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3582 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
3583 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3584 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
3585 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
3586 { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
3587 { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
3588 { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
3589 { 0x05, SONYPI_PKEY_MASK, sonypi_volumeev },
3590 { 0x05, SONYPI_PKEY_MASK, sonypi_brightnessev },
3591 { 0 },
3592};
3593
3594
3595#define ITERATIONS_LONG 10000
3596#define ITERATIONS_SHORT 10
3597#define wait_on_command(command, iterations) { \
3598 unsigned int n = iterations; \
3599 while (--n && (command)) \
3600 udelay(1); \
3601 if (!n) \
3602 dprintk("command failed at %s : %s (line %d)\n", \
3603 __FILE__, __func__, __LINE__); \
3604}
3605
3606static u8 sony_pic_call1(u8 dev)
3607{
3608 u8 v1, v2;
3609
3610 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3611 ITERATIONS_LONG);
3612 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3613 v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
3614 v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
3615 dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
3616 return v2;
3617}
3618
3619static u8 sony_pic_call2(u8 dev, u8 fn)
3620{
3621 u8 v1;
3622
3623 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3624 ITERATIONS_LONG);
3625 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3626 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3627 ITERATIONS_LONG);
3628 outb(fn, spic_dev.cur_ioport->io1.minimum);
3629 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
3630 dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
3631 return v1;
3632}
3633
3634static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
3635{
3636 u8 v1;
3637
3638 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3639 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3640 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3641 outb(fn, spic_dev.cur_ioport->io1.minimum);
3642 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3643 outb(v, spic_dev.cur_ioport->io1.minimum);
3644 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
3645 dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
3646 dev, fn, v, v1);
3647 return v1;
3648}
3649
3650
3651
3652
3653static int type3_handle_irq(const u8 data_mask, const u8 ev)
3654{
3655
3656
3657
3658
3659
3660
3661
3662 if (data_mask == 0x31) {
3663 if (ev == 0x5c || ev == 0x5f)
3664 sony_pic_call1(0xA0);
3665 else if (ev == 0x61)
3666 sony_pic_call1(0xB3);
3667 return 0;
3668 }
3669 return 1;
3670}
3671
3672static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
3673{
3674 struct pci_dev *pcidev;
3675
3676 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3677 PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
3678 if (pcidev) {
3679 dev->model = SONYPI_DEVICE_TYPE1;
3680 dev->evport_offset = SONYPI_TYPE1_OFFSET;
3681 dev->event_types = type1_events;
3682 goto out;
3683 }
3684
3685 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3686 PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
3687 if (pcidev) {
3688 dev->model = SONYPI_DEVICE_TYPE2;
3689 dev->evport_offset = SONYPI_TYPE2_OFFSET;
3690 dev->event_types = type2_events;
3691 goto out;
3692 }
3693
3694 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3695 PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
3696 if (pcidev) {
3697 dev->model = SONYPI_DEVICE_TYPE3;
3698 dev->handle_irq = type3_handle_irq;
3699 dev->evport_offset = SONYPI_TYPE3_OFFSET;
3700 dev->event_types = type3_events;
3701 goto out;
3702 }
3703
3704 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3705 PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
3706 if (pcidev) {
3707 dev->model = SONYPI_DEVICE_TYPE3;
3708 dev->handle_irq = type3_handle_irq;
3709 dev->evport_offset = SONYPI_TYPE3_OFFSET;
3710 dev->event_types = type3_events;
3711 goto out;
3712 }
3713
3714 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3715 PCI_DEVICE_ID_INTEL_ICH9_1, NULL);
3716 if (pcidev) {
3717 dev->model = SONYPI_DEVICE_TYPE3;
3718 dev->handle_irq = type3_handle_irq;
3719 dev->evport_offset = SONYPI_TYPE3_OFFSET;
3720 dev->event_types = type3_events;
3721 goto out;
3722 }
3723
3724
3725 dev->model = SONYPI_DEVICE_TYPE2;
3726 dev->evport_offset = SONYPI_TYPE2_OFFSET;
3727 dev->event_types = type2_events;
3728
3729out:
3730 pci_dev_put(pcidev);
3731
3732 pr_info("detected Type%d model\n",
3733 dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
3734 dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
3735}
3736
3737
3738#define SONYPI_CAMERA_PICTURE 5
3739#define SONYPI_CAMERA_CONTROL 0x10
3740
3741#define SONYPI_CAMERA_BRIGHTNESS 0
3742#define SONYPI_CAMERA_CONTRAST 1
3743#define SONYPI_CAMERA_HUE 2
3744#define SONYPI_CAMERA_COLOR 3
3745#define SONYPI_CAMERA_SHARPNESS 4
3746
3747#define SONYPI_CAMERA_EXPOSURE_MASK 0xC
3748#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3
3749#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30
3750#define SONYPI_CAMERA_MUTE_MASK 0x40
3751
3752
3753#define SONYPI_CAMERA_AGC 6
3754#define SONYPI_CAMERA_AGC_MASK 0x30
3755#define SONYPI_CAMERA_SHUTTER_MASK 0x7
3756
3757#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7
3758#define SONYPI_CAMERA_CONTROL 0x10
3759
3760#define SONYPI_CAMERA_STATUS 7
3761#define SONYPI_CAMERA_STATUS_READY 0x2
3762#define SONYPI_CAMERA_STATUS_POSITION 0x4
3763
3764#define SONYPI_DIRECTION_BACKWARDS 0x4
3765
3766#define SONYPI_CAMERA_REVISION 8
3767#define SONYPI_CAMERA_ROMVERSION 9
3768
3769static int __sony_pic_camera_ready(void)
3770{
3771 u8 v;
3772
3773 v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
3774 return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
3775}
3776
3777static int __sony_pic_camera_off(void)
3778{
3779 if (!camera) {
3780 pr_warn("camera control not enabled\n");
3781 return -ENODEV;
3782 }
3783
3784 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
3785 SONYPI_CAMERA_MUTE_MASK),
3786 ITERATIONS_SHORT);
3787
3788 if (spic_dev.camera_power) {
3789 sony_pic_call2(0x91, 0);
3790 spic_dev.camera_power = 0;
3791 }
3792 return 0;
3793}
3794
3795static int __sony_pic_camera_on(void)
3796{
3797 int i, j, x;
3798
3799 if (!camera) {
3800 pr_warn("camera control not enabled\n");
3801 return -ENODEV;
3802 }
3803
3804 if (spic_dev.camera_power)
3805 return 0;
3806
3807 for (j = 5; j > 0; j--) {
3808
3809 for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
3810 msleep(10);
3811 sony_pic_call1(0x93);
3812
3813 for (i = 400; i > 0; i--) {
3814 if (__sony_pic_camera_ready())
3815 break;
3816 msleep(10);
3817 }
3818 if (i)
3819 break;
3820 }
3821
3822 if (j == 0) {
3823 pr_warn("failed to power on camera\n");
3824 return -ENODEV;
3825 }
3826
3827 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
3828 0x5a),
3829 ITERATIONS_SHORT);
3830
3831 spic_dev.camera_power = 1;
3832 return 0;
3833}
3834
3835
3836int sony_pic_camera_command(int command, u8 value)
3837{
3838 if (!camera)
3839 return -EIO;
3840
3841 mutex_lock(&spic_dev.lock);
3842
3843 switch (command) {
3844 case SONY_PIC_COMMAND_SETCAMERA:
3845 if (value)
3846 __sony_pic_camera_on();
3847 else
3848 __sony_pic_camera_off();
3849 break;
3850 case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
3851 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
3852 ITERATIONS_SHORT);
3853 break;
3854 case SONY_PIC_COMMAND_SETCAMERACONTRAST:
3855 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
3856 ITERATIONS_SHORT);
3857 break;
3858 case SONY_PIC_COMMAND_SETCAMERAHUE:
3859 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
3860 ITERATIONS_SHORT);
3861 break;
3862 case SONY_PIC_COMMAND_SETCAMERACOLOR:
3863 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
3864 ITERATIONS_SHORT);
3865 break;
3866 case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
3867 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
3868 ITERATIONS_SHORT);
3869 break;
3870 case SONY_PIC_COMMAND_SETCAMERAPICTURE:
3871 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
3872 ITERATIONS_SHORT);
3873 break;
3874 case SONY_PIC_COMMAND_SETCAMERAAGC:
3875 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
3876 ITERATIONS_SHORT);
3877 break;
3878 default:
3879 pr_err("sony_pic_camera_command invalid: %d\n", command);
3880 break;
3881 }
3882 mutex_unlock(&spic_dev.lock);
3883 return 0;
3884}
3885EXPORT_SYMBOL(sony_pic_camera_command);
3886
3887
3888static void __sony_pic_set_wwanpower(u8 state)
3889{
3890 state = !!state;
3891 if (spic_dev.wwan_power == state)
3892 return;
3893 sony_pic_call2(0xB0, state);
3894 sony_pic_call1(0x82);
3895 spic_dev.wwan_power = state;
3896}
3897
3898static ssize_t sony_pic_wwanpower_store(struct device *dev,
3899 struct device_attribute *attr,
3900 const char *buffer, size_t count)
3901{
3902 unsigned long value;
3903 if (count > 31)
3904 return -EINVAL;
3905
3906 if (kstrtoul(buffer, 10, &value))
3907 return -EINVAL;
3908
3909 mutex_lock(&spic_dev.lock);
3910 __sony_pic_set_wwanpower(value);
3911 mutex_unlock(&spic_dev.lock);
3912
3913 return count;
3914}
3915
3916static ssize_t sony_pic_wwanpower_show(struct device *dev,
3917 struct device_attribute *attr, char *buffer)
3918{
3919 ssize_t count;
3920 mutex_lock(&spic_dev.lock);
3921 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
3922 mutex_unlock(&spic_dev.lock);
3923 return count;
3924}
3925
3926
3927static void __sony_pic_set_bluetoothpower(u8 state)
3928{
3929 state = !!state;
3930 if (spic_dev.bluetooth_power == state)
3931 return;
3932 sony_pic_call2(0x96, state);
3933 sony_pic_call1(0x82);
3934 spic_dev.bluetooth_power = state;
3935}
3936
3937static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
3938 struct device_attribute *attr,
3939 const char *buffer, size_t count)
3940{
3941 unsigned long value;
3942 if (count > 31)
3943 return -EINVAL;
3944
3945 if (kstrtoul(buffer, 10, &value))
3946 return -EINVAL;
3947
3948 mutex_lock(&spic_dev.lock);
3949 __sony_pic_set_bluetoothpower(value);
3950 mutex_unlock(&spic_dev.lock);
3951
3952 return count;
3953}
3954
3955static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
3956 struct device_attribute *attr, char *buffer)
3957{
3958 ssize_t count = 0;
3959 mutex_lock(&spic_dev.lock);
3960 count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
3961 mutex_unlock(&spic_dev.lock);
3962 return count;
3963}
3964
3965
3966
3967#define SONY_PIC_FAN0_STATUS 0x93
3968static int sony_pic_set_fanspeed(unsigned long value)
3969{
3970 return ec_write(SONY_PIC_FAN0_STATUS, value);
3971}
3972
3973static int sony_pic_get_fanspeed(u8 *value)
3974{
3975 return ec_read(SONY_PIC_FAN0_STATUS, value);
3976}
3977
3978static ssize_t sony_pic_fanspeed_store(struct device *dev,
3979 struct device_attribute *attr,
3980 const char *buffer, size_t count)
3981{
3982 unsigned long value;
3983 if (count > 31)
3984 return -EINVAL;
3985
3986 if (kstrtoul(buffer, 10, &value))
3987 return -EINVAL;
3988
3989 if (sony_pic_set_fanspeed(value))
3990 return -EIO;
3991
3992 return count;
3993}
3994
3995static ssize_t sony_pic_fanspeed_show(struct device *dev,
3996 struct device_attribute *attr, char *buffer)
3997{
3998 u8 value = 0;
3999 if (sony_pic_get_fanspeed(&value))
4000 return -EIO;
4001
4002 return snprintf(buffer, PAGE_SIZE, "%d\n", value);
4003}
4004
4005#define SPIC_ATTR(_name, _mode) \
4006struct device_attribute spic_attr_##_name = __ATTR(_name, \
4007 _mode, sony_pic_## _name ##_show, \
4008 sony_pic_## _name ##_store)
4009
4010static SPIC_ATTR(bluetoothpower, 0644);
4011static SPIC_ATTR(wwanpower, 0644);
4012static SPIC_ATTR(fanspeed, 0644);
4013
4014static struct attribute *spic_attributes[] = {
4015 &spic_attr_bluetoothpower.attr,
4016 &spic_attr_wwanpower.attr,
4017 &spic_attr_fanspeed.attr,
4018 NULL
4019};
4020
4021static const struct attribute_group spic_attribute_group = {
4022 .attrs = spic_attributes
4023};
4024
4025
4026#ifdef CONFIG_SONYPI_COMPAT
4027
4028
4029#define SONYPI_BAT_FLAGS 0x81
4030#define SONYPI_LCD_LIGHT 0x96
4031#define SONYPI_BAT1_PCTRM 0xa0
4032#define SONYPI_BAT1_LEFT 0xa2
4033#define SONYPI_BAT1_MAXRT 0xa4
4034#define SONYPI_BAT2_PCTRM 0xa8
4035#define SONYPI_BAT2_LEFT 0xaa
4036#define SONYPI_BAT2_MAXRT 0xac
4037#define SONYPI_BAT1_MAXTK 0xb0
4038#define SONYPI_BAT1_FULL 0xb2
4039#define SONYPI_BAT2_MAXTK 0xb8
4040#define SONYPI_BAT2_FULL 0xba
4041#define SONYPI_TEMP_STATUS 0xC1
4042
4043struct sonypi_compat_s {
4044 struct fasync_struct *fifo_async;
4045 struct kfifo fifo;
4046 spinlock_t fifo_lock;
4047 wait_queue_head_t fifo_proc_list;
4048 atomic_t open_count;
4049};
4050static struct sonypi_compat_s sonypi_compat = {
4051 .open_count = ATOMIC_INIT(0),
4052};
4053
4054static int sonypi_misc_fasync(int fd, struct file *filp, int on)
4055{
4056 return fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
4057}
4058
4059static int sonypi_misc_release(struct inode *inode, struct file *file)
4060{
4061 atomic_dec(&sonypi_compat.open_count);
4062 return 0;
4063}
4064
4065static int sonypi_misc_open(struct inode *inode, struct file *file)
4066{
4067
4068 unsigned long flags;
4069
4070 spin_lock_irqsave(&sonypi_compat.fifo_lock, flags);
4071
4072 if (atomic_inc_return(&sonypi_compat.open_count) == 1)
4073 kfifo_reset(&sonypi_compat.fifo);
4074
4075 spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags);
4076
4077 return 0;
4078}
4079
4080static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
4081 size_t count, loff_t *pos)
4082{
4083 ssize_t ret;
4084 unsigned char c;
4085
4086 if ((kfifo_len(&sonypi_compat.fifo) == 0) &&
4087 (file->f_flags & O_NONBLOCK))
4088 return -EAGAIN;
4089
4090 ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
4091 kfifo_len(&sonypi_compat.fifo) != 0);
4092 if (ret)
4093 return ret;
4094
4095 while (ret < count &&
4096 (kfifo_out_locked(&sonypi_compat.fifo, &c, sizeof(c),
4097 &sonypi_compat.fifo_lock) == sizeof(c))) {
4098 if (put_user(c, buf++))
4099 return -EFAULT;
4100 ret++;
4101 }
4102
4103 if (ret > 0) {
4104 struct inode *inode = file_inode(file);
4105 inode->i_atime = current_time(inode);
4106 }
4107
4108 return ret;
4109}
4110
4111static __poll_t sonypi_misc_poll(struct file *file, poll_table *wait)
4112{
4113 poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
4114 if (kfifo_len(&sonypi_compat.fifo))
4115 return EPOLLIN | EPOLLRDNORM;
4116 return 0;
4117}
4118
4119static int ec_read16(u8 addr, u16 *value)
4120{
4121 u8 val_lb, val_hb;
4122 if (ec_read(addr, &val_lb))
4123 return -1;
4124 if (ec_read(addr + 1, &val_hb))
4125 return -1;
4126 *value = val_lb | (val_hb << 8);
4127 return 0;
4128}
4129
4130static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
4131 unsigned long arg)
4132{
4133 int ret = 0;
4134 void __user *argp = (void __user *)arg;
4135 u8 val8;
4136 u16 val16;
4137 int value;
4138
4139 mutex_lock(&spic_dev.lock);
4140 switch (cmd) {
4141 case SONYPI_IOCGBRT:
4142 if (sony_bl_props.dev == NULL) {
4143 ret = -EIO;
4144 break;
4145 }
4146 if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL,
4147 &value)) {
4148 ret = -EIO;
4149 break;
4150 }
4151 val8 = ((value & 0xff) - 1) << 5;
4152 if (copy_to_user(argp, &val8, sizeof(val8)))
4153 ret = -EFAULT;
4154 break;
4155 case SONYPI_IOCSBRT:
4156 if (sony_bl_props.dev == NULL) {
4157 ret = -EIO;
4158 break;
4159 }
4160 if (copy_from_user(&val8, argp, sizeof(val8))) {
4161 ret = -EFAULT;
4162 break;
4163 }
4164 value = (val8 >> 5) + 1;
4165 if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value,
4166 NULL)) {
4167 ret = -EIO;
4168 break;
4169 }
4170
4171 sony_bl_props.dev->props.brightness =
4172 sony_backlight_get_brightness(sony_bl_props.dev);
4173 break;
4174 case SONYPI_IOCGBAT1CAP:
4175 if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
4176 ret = -EIO;
4177 break;
4178 }
4179 if (copy_to_user(argp, &val16, sizeof(val16)))
4180 ret = -EFAULT;
4181 break;
4182 case SONYPI_IOCGBAT1REM:
4183 if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
4184 ret = -EIO;
4185 break;
4186 }
4187 if (copy_to_user(argp, &val16, sizeof(val16)))
4188 ret = -EFAULT;
4189 break;
4190 case SONYPI_IOCGBAT2CAP:
4191 if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
4192 ret = -EIO;
4193 break;
4194 }
4195 if (copy_to_user(argp, &val16, sizeof(val16)))
4196 ret = -EFAULT;
4197 break;
4198 case SONYPI_IOCGBAT2REM:
4199 if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
4200 ret = -EIO;
4201 break;
4202 }
4203 if (copy_to_user(argp, &val16, sizeof(val16)))
4204 ret = -EFAULT;
4205 break;
4206 case SONYPI_IOCGBATFLAGS:
4207 if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
4208 ret = -EIO;
4209 break;
4210 }
4211 val8 &= 0x07;
4212 if (copy_to_user(argp, &val8, sizeof(val8)))
4213 ret = -EFAULT;
4214 break;
4215 case SONYPI_IOCGBLUE:
4216 val8 = spic_dev.bluetooth_power;
4217 if (copy_to_user(argp, &val8, sizeof(val8)))
4218 ret = -EFAULT;
4219 break;
4220 case SONYPI_IOCSBLUE:
4221 if (copy_from_user(&val8, argp, sizeof(val8))) {
4222 ret = -EFAULT;
4223 break;
4224 }
4225 __sony_pic_set_bluetoothpower(val8);
4226 break;
4227
4228 case SONYPI_IOCGFAN:
4229 if (sony_pic_get_fanspeed(&val8)) {
4230 ret = -EIO;
4231 break;
4232 }
4233 if (copy_to_user(argp, &val8, sizeof(val8)))
4234 ret = -EFAULT;
4235 break;
4236 case SONYPI_IOCSFAN:
4237 if (copy_from_user(&val8, argp, sizeof(val8))) {
4238 ret = -EFAULT;
4239 break;
4240 }
4241 if (sony_pic_set_fanspeed(val8))
4242 ret = -EIO;
4243 break;
4244
4245 case SONYPI_IOCGTEMP:
4246 if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
4247 ret = -EIO;
4248 break;
4249 }
4250 if (copy_to_user(argp, &val8, sizeof(val8)))
4251 ret = -EFAULT;
4252 break;
4253 default:
4254 ret = -EINVAL;
4255 }
4256 mutex_unlock(&spic_dev.lock);
4257 return ret;
4258}
4259
4260static const struct file_operations sonypi_misc_fops = {
4261 .owner = THIS_MODULE,
4262 .read = sonypi_misc_read,
4263 .poll = sonypi_misc_poll,
4264 .open = sonypi_misc_open,
4265 .release = sonypi_misc_release,
4266 .fasync = sonypi_misc_fasync,
4267 .unlocked_ioctl = sonypi_misc_ioctl,
4268 .llseek = noop_llseek,
4269};
4270
4271static struct miscdevice sonypi_misc_device = {
4272 .minor = MISC_DYNAMIC_MINOR,
4273 .name = "sonypi",
4274 .fops = &sonypi_misc_fops,
4275};
4276
4277static void sonypi_compat_report_event(u8 event)
4278{
4279 kfifo_in_locked(&sonypi_compat.fifo, (unsigned char *)&event,
4280 sizeof(event), &sonypi_compat.fifo_lock);
4281 kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
4282 wake_up_interruptible(&sonypi_compat.fifo_proc_list);
4283}
4284
4285static int sonypi_compat_init(void)
4286{
4287 int error;
4288
4289 spin_lock_init(&sonypi_compat.fifo_lock);
4290 error =
4291 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
4292 if (error) {
4293 pr_err("kfifo_alloc failed\n");
4294 return error;
4295 }
4296
4297 init_waitqueue_head(&sonypi_compat.fifo_proc_list);
4298
4299 if (minor != -1)
4300 sonypi_misc_device.minor = minor;
4301 error = misc_register(&sonypi_misc_device);
4302 if (error) {
4303 pr_err("misc_register failed\n");
4304 goto err_free_kfifo;
4305 }
4306 if (minor == -1)
4307 pr_info("device allocated minor is %d\n",
4308 sonypi_misc_device.minor);
4309
4310 return 0;
4311
4312err_free_kfifo:
4313 kfifo_free(&sonypi_compat.fifo);
4314 return error;
4315}
4316
4317static void sonypi_compat_exit(void)
4318{
4319 misc_deregister(&sonypi_misc_device);
4320 kfifo_free(&sonypi_compat.fifo);
4321}
4322#else
4323static int sonypi_compat_init(void) { return 0; }
4324static void sonypi_compat_exit(void) { }
4325static void sonypi_compat_report_event(u8 event) { }
4326#endif
4327
4328
4329
4330
4331static acpi_status
4332sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
4333{
4334 u32 i;
4335 struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
4336
4337 switch (resource->type) {
4338 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
4339 {
4340
4341 struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
4342 if (!ioport)
4343 return AE_ERROR;
4344
4345 list_add(&ioport->list, &dev->ioports);
4346 return AE_OK;
4347 }
4348
4349 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
4350
4351 return AE_OK;
4352
4353 case ACPI_RESOURCE_TYPE_IRQ:
4354 {
4355 struct acpi_resource_irq *p = &resource->data.irq;
4356 struct sony_pic_irq *interrupt = NULL;
4357 if (!p || !p->interrupt_count) {
4358
4359
4360
4361
4362 dprintk("Blank IRQ resource\n");
4363 return AE_OK;
4364 }
4365 for (i = 0; i < p->interrupt_count; i++) {
4366 if (!p->interrupts[i]) {
4367 pr_warn("Invalid IRQ %d\n",
4368 p->interrupts[i]);
4369 continue;
4370 }
4371 interrupt = kzalloc(sizeof(*interrupt),
4372 GFP_KERNEL);
4373 if (!interrupt)
4374 return AE_ERROR;
4375
4376 list_add(&interrupt->list, &dev->interrupts);
4377 interrupt->irq.triggering = p->triggering;
4378 interrupt->irq.polarity = p->polarity;
4379 interrupt->irq.shareable = p->shareable;
4380 interrupt->irq.interrupt_count = 1;
4381 interrupt->irq.interrupts[0] = p->interrupts[i];
4382 }
4383 return AE_OK;
4384 }
4385 case ACPI_RESOURCE_TYPE_IO:
4386 {
4387 struct acpi_resource_io *io = &resource->data.io;
4388 struct sony_pic_ioport *ioport =
4389 list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
4390 if (!io) {
4391 dprintk("Blank IO resource\n");
4392 return AE_OK;
4393 }
4394
4395 if (!ioport->io1.minimum) {
4396 memcpy(&ioport->io1, io, sizeof(*io));
4397 dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
4398 ioport->io1.address_length);
4399 }
4400 else if (!ioport->io2.minimum) {
4401 memcpy(&ioport->io2, io, sizeof(*io));
4402 dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
4403 ioport->io2.address_length);
4404 }
4405 else {
4406 pr_err("Unknown SPIC Type, more than 2 IO Ports\n");
4407 return AE_ERROR;
4408 }
4409 return AE_OK;
4410 }
4411
4412 case ACPI_RESOURCE_TYPE_END_TAG:
4413 return AE_OK;
4414
4415 default:
4416 dprintk("Resource %d isn't an IRQ nor an IO port\n",
4417 resource->type);
4418 return AE_CTRL_TERMINATE;
4419
4420 }
4421}
4422
4423static int sony_pic_possible_resources(struct acpi_device *device)
4424{
4425 int result = 0;
4426 acpi_status status = AE_OK;
4427
4428 if (!device)
4429 return -EINVAL;
4430
4431
4432
4433 dprintk("Evaluating _STA\n");
4434 result = acpi_bus_get_status(device);
4435 if (result) {
4436 pr_warn("Unable to read status\n");
4437 goto end;
4438 }
4439
4440 if (!device->status.enabled)
4441 dprintk("Device disabled\n");
4442 else
4443 dprintk("Device enabled\n");
4444
4445
4446
4447
4448 dprintk("Evaluating %s\n", METHOD_NAME__PRS);
4449 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
4450 sony_pic_read_possible_resource, &spic_dev);
4451 if (ACPI_FAILURE(status)) {
4452 pr_warn("Failure evaluating %s\n", METHOD_NAME__PRS);
4453 result = -ENODEV;
4454 }
4455end:
4456 return result;
4457}
4458
4459
4460
4461
4462static int sony_pic_disable(struct acpi_device *device)
4463{
4464 acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL,
4465 NULL);
4466
4467 if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND)
4468 return -ENXIO;
4469
4470 dprintk("Device disabled\n");
4471 return 0;
4472}
4473
4474
4475
4476
4477
4478
4479
4480static int sony_pic_enable(struct acpi_device *device,
4481 struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
4482{
4483 acpi_status status;
4484 int result = 0;
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496 struct {
4497 struct acpi_resource res1;
4498 struct acpi_resource res2;
4499 struct acpi_resource res3;
4500 struct acpi_resource res4;
4501 } *resource;
4502 struct acpi_buffer buffer = { 0, NULL };
4503
4504 if (!ioport || !irq)
4505 return -EINVAL;
4506
4507
4508 resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
4509 if (!resource)
4510 return -ENOMEM;
4511
4512 buffer.length = sizeof(*resource) + 1;
4513 buffer.pointer = resource;
4514
4515
4516 if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
4517
4518
4519 resource->res1.type = ACPI_RESOURCE_TYPE_IO;
4520 resource->res1.length = sizeof(struct acpi_resource);
4521 memcpy(&resource->res1.data.io, &ioport->io1,
4522 sizeof(struct acpi_resource_io));
4523
4524 resource->res2.type = ACPI_RESOURCE_TYPE_IO;
4525 resource->res2.length = sizeof(struct acpi_resource);
4526 memcpy(&resource->res2.data.io, &ioport->io2,
4527 sizeof(struct acpi_resource_io));
4528
4529
4530 resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
4531 resource->res3.length = sizeof(struct acpi_resource);
4532 memcpy(&resource->res3.data.irq, &irq->irq,
4533 sizeof(struct acpi_resource_irq));
4534
4535 resource->res3.data.irq.shareable = ACPI_SHARED;
4536
4537 resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
4538 resource->res4.length = sizeof(struct acpi_resource);
4539 }
4540
4541 else {
4542
4543 resource->res1.type = ACPI_RESOURCE_TYPE_IO;
4544 resource->res1.length = sizeof(struct acpi_resource);
4545 memcpy(&resource->res1.data.io, &ioport->io1,
4546 sizeof(struct acpi_resource_io));
4547
4548
4549 resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
4550 resource->res2.length = sizeof(struct acpi_resource);
4551 memcpy(&resource->res2.data.irq, &irq->irq,
4552 sizeof(struct acpi_resource_irq));
4553
4554 resource->res2.data.irq.shareable = ACPI_SHARED;
4555
4556 resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
4557 resource->res3.length = sizeof(struct acpi_resource);
4558 }
4559
4560
4561 dprintk("Evaluating _SRS\n");
4562 status = acpi_set_current_resources(device->handle, &buffer);
4563
4564
4565 if (ACPI_FAILURE(status)) {
4566 pr_err("Error evaluating _SRS\n");
4567 result = -ENODEV;
4568 goto end;
4569 }
4570
4571
4572 sony_pic_call1(0x82);
4573 sony_pic_call2(0x81, 0xff);
4574 sony_pic_call1(compat ? 0x92 : 0x82);
4575
4576end:
4577 kfree(resource);
4578 return result;
4579}
4580
4581
4582
4583
4584
4585
4586static irqreturn_t sony_pic_irq(int irq, void *dev_id)
4587{
4588 int i, j;
4589 u8 ev = 0;
4590 u8 data_mask = 0;
4591 u8 device_event = 0;
4592
4593 struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
4594
4595 ev = inb_p(dev->cur_ioport->io1.minimum);
4596 if (dev->cur_ioport->io2.minimum)
4597 data_mask = inb_p(dev->cur_ioport->io2.minimum);
4598 else
4599 data_mask = inb_p(dev->cur_ioport->io1.minimum +
4600 dev->evport_offset);
4601
4602 dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
4603 ev, data_mask, dev->cur_ioport->io1.minimum,
4604 dev->evport_offset);
4605
4606 if (ev == 0x00 || ev == 0xff)
4607 return IRQ_HANDLED;
4608
4609 for (i = 0; dev->event_types[i].mask; i++) {
4610
4611 if ((data_mask & dev->event_types[i].data) !=
4612 dev->event_types[i].data)
4613 continue;
4614
4615 if (!(mask & dev->event_types[i].mask))
4616 continue;
4617
4618 for (j = 0; dev->event_types[i].events[j].event; j++) {
4619 if (ev == dev->event_types[i].events[j].data) {
4620 device_event =
4621 dev->event_types[i].events[j].event;
4622
4623 if (!device_event)
4624 return IRQ_HANDLED;
4625 goto found;
4626 }
4627 }
4628 }
4629
4630
4631
4632 if (dev->handle_irq && dev->handle_irq(data_mask, ev) == 0)
4633 return IRQ_HANDLED;
4634
4635 dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
4636 ev, data_mask, dev->cur_ioport->io1.minimum,
4637 dev->evport_offset);
4638 return IRQ_HANDLED;
4639
4640found:
4641 sony_laptop_report_input_event(device_event);
4642 sonypi_compat_report_event(device_event);
4643 return IRQ_HANDLED;
4644}
4645
4646
4647
4648
4649
4650
4651static int sony_pic_remove(struct acpi_device *device)
4652{
4653 struct sony_pic_ioport *io, *tmp_io;
4654 struct sony_pic_irq *irq, *tmp_irq;
4655
4656 if (sony_pic_disable(device)) {
4657 pr_err("Couldn't disable device\n");
4658 return -ENXIO;
4659 }
4660
4661 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
4662 release_region(spic_dev.cur_ioport->io1.minimum,
4663 spic_dev.cur_ioport->io1.address_length);
4664 if (spic_dev.cur_ioport->io2.minimum)
4665 release_region(spic_dev.cur_ioport->io2.minimum,
4666 spic_dev.cur_ioport->io2.address_length);
4667
4668 sonypi_compat_exit();
4669
4670 sony_laptop_remove_input();
4671
4672
4673 sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
4674 sony_pf_remove();
4675
4676 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
4677 list_del(&io->list);
4678 kfree(io);
4679 }
4680 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
4681 list_del(&irq->list);
4682 kfree(irq);
4683 }
4684 spic_dev.cur_ioport = NULL;
4685 spic_dev.cur_irq = NULL;
4686
4687 dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
4688 return 0;
4689}
4690
4691static int sony_pic_add(struct acpi_device *device)
4692{
4693 int result;
4694 struct sony_pic_ioport *io, *tmp_io;
4695 struct sony_pic_irq *irq, *tmp_irq;
4696
4697 spic_dev.acpi_dev = device;
4698 strcpy(acpi_device_class(device), "sony/hotkey");
4699 sony_pic_detect_device_type(&spic_dev);
4700 mutex_init(&spic_dev.lock);
4701
4702
4703 result = sony_pic_possible_resources(device);
4704 if (result) {
4705 pr_err("Unable to read possible resources\n");
4706 goto err_free_resources;
4707 }
4708
4709
4710 result = sony_laptop_setup_input(device);
4711 if (result) {
4712 pr_err("Unable to create input devices\n");
4713 goto err_free_resources;
4714 }
4715
4716 result = sonypi_compat_init();
4717 if (result)
4718 goto err_remove_input;
4719
4720
4721 list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
4722 if (request_region(io->io1.minimum, io->io1.address_length,
4723 "Sony Programmable I/O Device")) {
4724 dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
4725 io->io1.minimum, io->io1.maximum,
4726 io->io1.address_length);
4727
4728 if (io->io2.minimum) {
4729 if (request_region(io->io2.minimum,
4730 io->io2.address_length,
4731 "Sony Programmable I/O Device")) {
4732 dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
4733 io->io2.minimum, io->io2.maximum,
4734 io->io2.address_length);
4735 spic_dev.cur_ioport = io;
4736 break;
4737 }
4738 else {
4739 dprintk("Unable to get I/O port2: "
4740 "0x%.4x (0x%.4x) + 0x%.2x\n",
4741 io->io2.minimum, io->io2.maximum,
4742 io->io2.address_length);
4743 release_region(io->io1.minimum,
4744 io->io1.address_length);
4745 }
4746 }
4747 else {
4748 spic_dev.cur_ioport = io;
4749 break;
4750 }
4751 }
4752 }
4753 if (!spic_dev.cur_ioport) {
4754 pr_err("Failed to request_region\n");
4755 result = -ENODEV;
4756 goto err_remove_compat;
4757 }
4758
4759
4760 list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
4761 if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
4762 0, "sony-laptop", &spic_dev)) {
4763 dprintk("IRQ: %d - triggering: %d - "
4764 "polarity: %d - shr: %d\n",
4765 irq->irq.interrupts[0],
4766 irq->irq.triggering,
4767 irq->irq.polarity,
4768 irq->irq.shareable);
4769 spic_dev.cur_irq = irq;
4770 break;
4771 }
4772 }
4773 if (!spic_dev.cur_irq) {
4774 pr_err("Failed to request_irq\n");
4775 result = -ENODEV;
4776 goto err_release_region;
4777 }
4778
4779
4780 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
4781 if (result) {
4782 pr_err("Couldn't enable device\n");
4783 goto err_free_irq;
4784 }
4785
4786 spic_dev.bluetooth_power = -1;
4787
4788 result = sony_pf_add();
4789 if (result)
4790 goto err_disable_device;
4791
4792 result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
4793 if (result)
4794 goto err_remove_pf;
4795
4796 pr_info("SPIC setup done.\n");
4797 return 0;
4798
4799err_remove_pf:
4800 sony_pf_remove();
4801
4802err_disable_device:
4803 sony_pic_disable(device);
4804
4805err_free_irq:
4806 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
4807
4808err_release_region:
4809 release_region(spic_dev.cur_ioport->io1.minimum,
4810 spic_dev.cur_ioport->io1.address_length);
4811 if (spic_dev.cur_ioport->io2.minimum)
4812 release_region(spic_dev.cur_ioport->io2.minimum,
4813 spic_dev.cur_ioport->io2.address_length);
4814
4815err_remove_compat:
4816 sonypi_compat_exit();
4817
4818err_remove_input:
4819 sony_laptop_remove_input();
4820
4821err_free_resources:
4822 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
4823 list_del(&io->list);
4824 kfree(io);
4825 }
4826 list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
4827 list_del(&irq->list);
4828 kfree(irq);
4829 }
4830 spic_dev.cur_ioport = NULL;
4831 spic_dev.cur_irq = NULL;
4832
4833 return result;
4834}
4835
4836#ifdef CONFIG_PM_SLEEP
4837static int sony_pic_suspend(struct device *dev)
4838{
4839 if (sony_pic_disable(to_acpi_device(dev)))
4840 return -ENXIO;
4841 return 0;
4842}
4843
4844static int sony_pic_resume(struct device *dev)
4845{
4846 sony_pic_enable(to_acpi_device(dev),
4847 spic_dev.cur_ioport, spic_dev.cur_irq);
4848 return 0;
4849}
4850#endif
4851
4852static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume);
4853
4854static const struct acpi_device_id sony_pic_device_ids[] = {
4855 {SONY_PIC_HID, 0},
4856 {"", 0},
4857};
4858
4859static struct acpi_driver sony_pic_driver = {
4860 .name = SONY_PIC_DRIVER_NAME,
4861 .class = SONY_PIC_CLASS,
4862 .ids = sony_pic_device_ids,
4863 .owner = THIS_MODULE,
4864 .ops = {
4865 .add = sony_pic_add,
4866 .remove = sony_pic_remove,
4867 },
4868 .drv.pm = &sony_pic_pm,
4869};
4870
4871static const struct dmi_system_id sonypi_dmi_table[] __initconst = {
4872 {
4873 .ident = "Sony Vaio",
4874 .matches = {
4875 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
4876 DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
4877 },
4878 },
4879 {
4880 .ident = "Sony Vaio",
4881 .matches = {
4882 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
4883 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
4884 },
4885 },
4886 { }
4887};
4888
4889static int __init sony_laptop_init(void)
4890{
4891 int result;
4892
4893 if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
4894 result = acpi_bus_register_driver(&sony_pic_driver);
4895 if (result) {
4896 pr_err("Unable to register SPIC driver\n");
4897 goto out;
4898 }
4899 spic_drv_registered = 1;
4900 }
4901
4902 result = acpi_bus_register_driver(&sony_nc_driver);
4903 if (result) {
4904 pr_err("Unable to register SNC driver\n");
4905 goto out_unregister_pic;
4906 }
4907
4908 return 0;
4909
4910out_unregister_pic:
4911 if (spic_drv_registered)
4912 acpi_bus_unregister_driver(&sony_pic_driver);
4913out:
4914 return result;
4915}
4916
4917static void __exit sony_laptop_exit(void)
4918{
4919 acpi_bus_unregister_driver(&sony_nc_driver);
4920 if (spic_drv_registered)
4921 acpi_bus_unregister_driver(&sony_pic_driver);
4922}
4923
4924module_init(sony_laptop_init);
4925module_exit(sony_laptop_exit);
4926