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