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