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