aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-10 12:43:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-10 12:43:56 -0400
commit4ba85265790ba3681deeaf73f018c0eb829a7341 (patch)
treed94a9198add02cd11cac825bcad0e2858973d422
parentdd76a786af1f09e9122e150d30156e094e2a94b4 (diff)
parent562c7cec1e92be85ade6f65fff107651e10ee2ed (diff)
Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
Pull x86 platform driver updates from Matthew Garrett: "Support for the new keyboard features on the Thinkpad Carbon, a bunch of updates for the Sony and Toshiba drivers, a new driver for upcoming Alienware hardware and a few misc fixes. There's a couple of patches that got Acked today but aren't invasive, so I'll send a further PR for them next week" * 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: (28 commits) alienware-wmi: cover some scenarios where memory allocations would fail Add WMI driver for controlling AlienFX features on some Alienware products fujitsu-tablet: add support for Lifebook T901 and T902 x86, platform: Make HP_WIRELESS option text more descriptive x86, acpi: LLVMLinux: Remove nested functions from Thinkpad ACPI save and restore adaptive keyboard mode for suspend and,resume support Thinkpad X1 Carbon 2nd generation's adaptive keyboard toshiba_acpi: Fix whitespace toshiba_acpi: Update version and copyright info toshiba_acpi: Add accelerometer support toshiba_acpi: Add ECO mode led support toshiba_acpi: Add touchpad enable/disable support- toshiba_acpi: Add keyboard backlight support toshiba_acpi: Adapt Illumination code to use SCI toshiba_acpi: Add System Configuration Interface thinkpad_acpi: Fix inconsistent mute LED after resume sonypi: Simplify dependencies Revert "X86 platform: New BayTrail IOSF-SB MBI driver" sony-laptop: remove useless sony-laptop versioning sony-laptop: add smart connect control function ...
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/platform/x86/Kconfig22
-rw-r--r--drivers/platform/x86/Makefile2
-rw-r--r--drivers/platform/x86/alienware-wmi.c565
-rw-r--r--drivers/platform/x86/fujitsu-tablet.c65
-rw-r--r--drivers/platform/x86/intel_baytrail.c224
-rw-r--r--drivers/platform/x86/intel_baytrail.h90
-rw-r--r--drivers/platform/x86/panasonic-laptop.c11
-rw-r--r--drivers/platform/x86/sony-laptop.c539
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c227
-rw-r--r--drivers/platform/x86/toshiba_acpi.c635
11 files changed, 1901 insertions, 481 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 1386749b48ff..fbae63e3d304 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -408,7 +408,7 @@ config APPLICOM
408 408
409config SONYPI 409config SONYPI
410 tristate "Sony Vaio Programmable I/O Control Device support" 410 tristate "Sony Vaio Programmable I/O Control Device support"
411 depends on X86 && PCI && INPUT && !64BIT 411 depends on X86_32 && PCI && INPUT
412 ---help--- 412 ---help---
413 This driver enables access to the Sony Programmable I/O Control 413 This driver enables access to the Sony Programmable I/O Control
414 Device which can be found in many (all ?) Sony Vaio laptops. 414 Device which can be found in many (all ?) Sony Vaio laptops.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 5f67843c7fb7..27df2c533b09 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -53,6 +53,18 @@ config ACERHDF
53 If you have an Acer Aspire One netbook, say Y or M 53 If you have an Acer Aspire One netbook, say Y or M
54 here. 54 here.
55 55
56config ALIENWARE_WMI
57 tristate "Alienware Special feature control"
58 depends on ACPI
59 depends on LEDS_CLASS
60 depends on NEW_LEDS
61 depends on ACPI_WMI
62 ---help---
63 This is a driver for controlling Alienware BIOS driven
64 features. It exposes an interface for controlling the AlienFX
65 zones on Alienware machines that don't contain a dedicated AlienFX
66 USB MCU such as the X51 and X51-R2.
67
56config ASUS_LAPTOP 68config ASUS_LAPTOP
57 tristate "Asus Laptop Extras" 69 tristate "Asus Laptop Extras"
58 depends on ACPI 70 depends on ACPI
@@ -196,7 +208,7 @@ config HP_ACCEL
196 be called hp_accel. 208 be called hp_accel.
197 209
198config HP_WIRELESS 210config HP_WIRELESS
199 tristate "HP WIRELESS" 211 tristate "HP wireless button"
200 depends on ACPI 212 depends on ACPI
201 depends on INPUT 213 depends on INPUT
202 help 214 help
@@ -817,12 +829,4 @@ config PVPANIC
817 a paravirtualized device provided by QEMU; it lets a virtual machine 829 a paravirtualized device provided by QEMU; it lets a virtual machine
818 (guest) communicate panic events to the host. 830 (guest) communicate panic events to the host.
819 831
820config INTEL_BAYTRAIL_MBI
821 tristate
822 depends on PCI
823 ---help---
824 Needed on Baytrail platforms for access to the IOSF Sideband Mailbox
825 Interface. This is a requirement for systems that need to configure
826 the PUNIT for power management features such as RAPL.
827
828endif # X86_PLATFORM_DEVICES 832endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 9b87cfc42b84..1a2eafc9d48e 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -55,4 +55,4 @@ obj-$(CONFIG_INTEL_RST) += intel-rst.o
55obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o 55obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o
56 56
57obj-$(CONFIG_PVPANIC) += pvpanic.o 57obj-$(CONFIG_PVPANIC) += pvpanic.o
58obj-$(CONFIG_INTEL_BAYTRAIL_MBI) += intel_baytrail.o 58obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c
new file mode 100644
index 000000000000..541f9514f76f
--- /dev/null
+++ b/drivers/platform/x86/alienware-wmi.c
@@ -0,0 +1,565 @@
1/*
2 * Alienware AlienFX control
3 *
4 * Copyright (C) 2014 Dell Inc <mario_limonciello@dell.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20#include <linux/acpi.h>
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/dmi.h>
24#include <linux/acpi.h>
25#include <linux/leds.h>
26
27#define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
28#define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
29#define WMAX_CONTROL_GUID "A70591CE-A997-11DA-B012-B622A1EF5492"
30
31#define WMAX_METHOD_HDMI_SOURCE 0x1
32#define WMAX_METHOD_HDMI_STATUS 0x2
33#define WMAX_METHOD_BRIGHTNESS 0x3
34#define WMAX_METHOD_ZONE_CONTROL 0x4
35
36MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>");
37MODULE_DESCRIPTION("Alienware special feature control");
38MODULE_LICENSE("GPL");
39MODULE_ALIAS("wmi:" LEGACY_CONTROL_GUID);
40MODULE_ALIAS("wmi:" WMAX_CONTROL_GUID);
41
42enum INTERFACE_FLAGS {
43 LEGACY,
44 WMAX,
45};
46
47enum LEGACY_CONTROL_STATES {
48 LEGACY_RUNNING = 1,
49 LEGACY_BOOTING = 0,
50 LEGACY_SUSPEND = 3,
51};
52
53enum WMAX_CONTROL_STATES {
54 WMAX_RUNNING = 0xFF,
55 WMAX_BOOTING = 0,
56 WMAX_SUSPEND = 3,
57};
58
59struct quirk_entry {
60 u8 num_zones;
61};
62
63static struct quirk_entry *quirks;
64
65static struct quirk_entry quirk_unknown = {
66 .num_zones = 2,
67};
68
69static struct quirk_entry quirk_x51_family = {
70 .num_zones = 3,
71};
72
73static int dmi_matched(const struct dmi_system_id *dmi)
74{
75 quirks = dmi->driver_data;
76 return 1;
77}
78
79static struct dmi_system_id alienware_quirks[] = {
80 {
81 .callback = dmi_matched,
82 .ident = "Alienware X51 R1",
83 .matches = {
84 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
85 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"),
86 },
87 .driver_data = &quirk_x51_family,
88 },
89 {
90 .callback = dmi_matched,
91 .ident = "Alienware X51 R2",
92 .matches = {
93 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
94 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"),
95 },
96 .driver_data = &quirk_x51_family,
97 },
98 {}
99};
100
101struct color_platform {
102 u8 blue;
103 u8 green;
104 u8 red;
105} __packed;
106
107struct platform_zone {
108 u8 location;
109 struct device_attribute *attr;
110 struct color_platform colors;
111};
112
113struct wmax_brightness_args {
114 u32 led_mask;
115 u32 percentage;
116};
117
118struct hdmi_args {
119 u8 arg;
120};
121
122struct legacy_led_args {
123 struct color_platform colors;
124 u8 brightness;
125 u8 state;
126} __packed;
127
128struct wmax_led_args {
129 u32 led_mask;
130 struct color_platform colors;
131 u8 state;
132} __packed;
133
134static struct platform_device *platform_device;
135static struct device_attribute *zone_dev_attrs;
136static struct attribute **zone_attrs;
137static struct platform_zone *zone_data;
138
139static struct platform_driver platform_driver = {
140 .driver = {
141 .name = "alienware-wmi",
142 .owner = THIS_MODULE,
143 }
144};
145
146static struct attribute_group zone_attribute_group = {
147 .name = "rgb_zones",
148};
149
150static u8 interface;
151static u8 lighting_control_state;
152static u8 global_brightness;
153
154/*
155 * Helpers used for zone control
156*/
157static int parse_rgb(const char *buf, struct platform_zone *zone)
158{
159 long unsigned int rgb;
160 int ret;
161 union color_union {
162 struct color_platform cp;
163 int package;
164 } repackager;
165
166 ret = kstrtoul(buf, 16, &rgb);
167 if (ret)
168 return ret;
169
170 /* RGB triplet notation is 24-bit hexadecimal */
171 if (rgb > 0xFFFFFF)
172 return -EINVAL;
173
174 repackager.package = rgb & 0x0f0f0f0f;
175 pr_debug("alienware-wmi: r: %d g:%d b: %d\n",
176 repackager.cp.red, repackager.cp.green, repackager.cp.blue);
177 zone->colors = repackager.cp;
178 return 0;
179}
180
181static struct platform_zone *match_zone(struct device_attribute *attr)
182{
183 int i;
184 for (i = 0; i < quirks->num_zones; i++) {
185 if ((struct device_attribute *)zone_data[i].attr == attr) {
186 pr_debug("alienware-wmi: matched zone location: %d\n",
187 zone_data[i].location);
188 return &zone_data[i];
189 }
190 }
191 return NULL;
192}
193
194/*
195 * Individual RGB zone control
196*/
197static int alienware_update_led(struct platform_zone *zone)
198{
199 int method_id;
200 acpi_status status;
201 char *guid;
202 struct acpi_buffer input;
203 struct legacy_led_args legacy_args;
204 struct wmax_led_args wmax_args;
205 if (interface == WMAX) {
206 wmax_args.led_mask = 1 << zone->location;
207 wmax_args.colors = zone->colors;
208 wmax_args.state = lighting_control_state;
209 guid = WMAX_CONTROL_GUID;
210 method_id = WMAX_METHOD_ZONE_CONTROL;
211
212 input.length = (acpi_size) sizeof(wmax_args);
213 input.pointer = &wmax_args;
214 } else {
215 legacy_args.colors = zone->colors;
216 legacy_args.brightness = global_brightness;
217 legacy_args.state = 0;
218 if (lighting_control_state == LEGACY_BOOTING ||
219 lighting_control_state == LEGACY_SUSPEND) {
220 guid = LEGACY_POWER_CONTROL_GUID;
221 legacy_args.state = lighting_control_state;
222 } else
223 guid = LEGACY_CONTROL_GUID;
224 method_id = zone->location + 1;
225
226 input.length = (acpi_size) sizeof(legacy_args);
227 input.pointer = &legacy_args;
228 }
229 pr_debug("alienware-wmi: guid %s method %d\n", guid, method_id);
230
231 status = wmi_evaluate_method(guid, 1, method_id, &input, NULL);
232 if (ACPI_FAILURE(status))
233 pr_err("alienware-wmi: zone set failure: %u\n", status);
234 return ACPI_FAILURE(status);
235}
236
237static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
238 char *buf)
239{
240 struct platform_zone *target_zone;
241 target_zone = match_zone(attr);
242 if (target_zone == NULL)
243 return sprintf(buf, "red: -1, green: -1, blue: -1\n");
244 return sprintf(buf, "red: %d, green: %d, blue: %d\n",
245 target_zone->colors.red,
246 target_zone->colors.green, target_zone->colors.blue);
247
248}
249
250static ssize_t zone_set(struct device *dev, struct device_attribute *attr,
251 const char *buf, size_t count)
252{
253 struct platform_zone *target_zone;
254 int ret;
255 target_zone = match_zone(attr);
256 if (target_zone == NULL) {
257 pr_err("alienware-wmi: invalid target zone\n");
258 return 1;
259 }
260 ret = parse_rgb(buf, target_zone);
261 if (ret)
262 return ret;
263 ret = alienware_update_led(target_zone);
264 return ret ? ret : count;
265}
266
267/*
268 * LED Brightness (Global)
269*/
270static int wmax_brightness(int brightness)
271{
272 acpi_status status;
273 struct acpi_buffer input;
274 struct wmax_brightness_args args = {
275 .led_mask = 0xFF,
276 .percentage = brightness,
277 };
278 input.length = (acpi_size) sizeof(args);
279 input.pointer = &args;
280 status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
281 WMAX_METHOD_BRIGHTNESS, &input, NULL);
282 if (ACPI_FAILURE(status))
283 pr_err("alienware-wmi: brightness set failure: %u\n", status);
284 return ACPI_FAILURE(status);
285}
286
287static void global_led_set(struct led_classdev *led_cdev,
288 enum led_brightness brightness)
289{
290 int ret;
291 global_brightness = brightness;
292 if (interface == WMAX)
293 ret = wmax_brightness(brightness);
294 else
295 ret = alienware_update_led(&zone_data[0]);
296 if (ret)
297 pr_err("LED brightness update failed\n");
298}
299
300static enum led_brightness global_led_get(struct led_classdev *led_cdev)
301{
302 return global_brightness;
303}
304
305static struct led_classdev global_led = {
306 .brightness_set = global_led_set,
307 .brightness_get = global_led_get,
308 .name = "alienware::global_brightness",
309};
310
311/*
312 * Lighting control state device attribute (Global)
313*/
314static ssize_t show_control_state(struct device *dev,
315 struct device_attribute *attr, char *buf)
316{
317 if (lighting_control_state == LEGACY_BOOTING)
318 return scnprintf(buf, PAGE_SIZE, "[booting] running suspend\n");
319 else if (lighting_control_state == LEGACY_SUSPEND)
320 return scnprintf(buf, PAGE_SIZE, "booting running [suspend]\n");
321 return scnprintf(buf, PAGE_SIZE, "booting [running] suspend\n");
322}
323
324static ssize_t store_control_state(struct device *dev,
325 struct device_attribute *attr,
326 const char *buf, size_t count)
327{
328 long unsigned int val;
329 if (strcmp(buf, "booting\n") == 0)
330 val = LEGACY_BOOTING;
331 else if (strcmp(buf, "suspend\n") == 0)
332 val = LEGACY_SUSPEND;
333 else if (interface == LEGACY)
334 val = LEGACY_RUNNING;
335 else
336 val = WMAX_RUNNING;
337 lighting_control_state = val;
338 pr_debug("alienware-wmi: updated control state to %d\n",
339 lighting_control_state);
340 return count;
341}
342
343static DEVICE_ATTR(lighting_control_state, 0644, show_control_state,
344 store_control_state);
345
346static int alienware_zone_init(struct platform_device *dev)
347{
348 int i;
349 char buffer[10];
350 char *name;
351
352 if (interface == WMAX) {
353 global_led.max_brightness = 100;
354 lighting_control_state = WMAX_RUNNING;
355 } else if (interface == LEGACY) {
356 global_led.max_brightness = 0x0F;
357 lighting_control_state = LEGACY_RUNNING;
358 }
359 global_brightness = global_led.max_brightness;
360
361 /*
362 * - zone_dev_attrs num_zones + 1 is for individual zones and then
363 * null terminated
364 * - zone_attrs num_zones + 2 is for all attrs in zone_dev_attrs +
365 * the lighting control + null terminated
366 * - zone_data num_zones is for the distinct zones
367 */
368 zone_dev_attrs =
369 kzalloc(sizeof(struct device_attribute) * (quirks->num_zones + 1),
370 GFP_KERNEL);
371 if (!zone_dev_attrs)
372 return -ENOMEM;
373
374 zone_attrs =
375 kzalloc(sizeof(struct attribute *) * (quirks->num_zones + 2),
376 GFP_KERNEL);
377 if (!zone_attrs)
378 return -ENOMEM;
379
380 zone_data =
381 kzalloc(sizeof(struct platform_zone) * (quirks->num_zones),
382 GFP_KERNEL);
383 if (!zone_data)
384 return -ENOMEM;
385
386 for (i = 0; i < quirks->num_zones; i++) {
387 sprintf(buffer, "zone%02X", i);
388 name = kstrdup(buffer, GFP_KERNEL);
389 if (name == NULL)
390 return 1;
391 sysfs_attr_init(&zone_dev_attrs[i].attr);
392 zone_dev_attrs[i].attr.name = name;
393 zone_dev_attrs[i].attr.mode = 0644;
394 zone_dev_attrs[i].show = zone_show;
395 zone_dev_attrs[i].store = zone_set;
396 zone_data[i].location = i;
397 zone_attrs[i] = &zone_dev_attrs[i].attr;
398 zone_data[i].attr = &zone_dev_attrs[i];
399 }
400 zone_attrs[quirks->num_zones] = &dev_attr_lighting_control_state.attr;
401 zone_attribute_group.attrs = zone_attrs;
402
403 led_classdev_register(&dev->dev, &global_led);
404
405 return sysfs_create_group(&dev->dev.kobj, &zone_attribute_group);
406}
407
408static void alienware_zone_exit(struct platform_device *dev)
409{
410 sysfs_remove_group(&dev->dev.kobj, &zone_attribute_group);
411 led_classdev_unregister(&global_led);
412 if (zone_dev_attrs) {
413 int i;
414 for (i = 0; i < quirks->num_zones; i++)
415 kfree(zone_dev_attrs[i].attr.name);
416 }
417 kfree(zone_dev_attrs);
418 kfree(zone_data);
419 kfree(zone_attrs);
420}
421
422/*
423 The HDMI mux sysfs node indicates the status of the HDMI input mux.
424 It can toggle between standard system GPU output and HDMI input.
425*/
426static ssize_t show_hdmi(struct device *dev, struct device_attribute *attr,
427 char *buf)
428{
429 acpi_status status;
430 struct acpi_buffer input;
431 union acpi_object *obj;
432 u32 tmp = 0;
433 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
434 struct hdmi_args in_args = {
435 .arg = 0,
436 };
437 input.length = (acpi_size) sizeof(in_args);
438 input.pointer = &in_args;
439 status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
440 WMAX_METHOD_HDMI_STATUS, &input, &output);
441
442 if (ACPI_SUCCESS(status)) {
443 obj = (union acpi_object *)output.pointer;
444 if (obj && obj->type == ACPI_TYPE_INTEGER)
445 tmp = (u32) obj->integer.value;
446 if (tmp == 1)
447 return scnprintf(buf, PAGE_SIZE,
448 "[input] gpu unknown\n");
449 else if (tmp == 2)
450 return scnprintf(buf, PAGE_SIZE,
451 "input [gpu] unknown\n");
452 }
453 pr_err("alienware-wmi: unknown HDMI status: %d\n", status);
454 return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");
455}
456
457static ssize_t toggle_hdmi(struct device *dev, struct device_attribute *attr,
458 const char *buf, size_t count)
459{
460 struct acpi_buffer input;
461 acpi_status status;
462 struct hdmi_args args;
463 if (strcmp(buf, "gpu\n") == 0)
464 args.arg = 1;
465 else if (strcmp(buf, "input\n") == 0)
466 args.arg = 2;
467 else
468 args.arg = 3;
469 pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf);
470 input.length = (acpi_size) sizeof(args);
471 input.pointer = &args;
472 status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
473 WMAX_METHOD_HDMI_SOURCE, &input, NULL);
474 if (ACPI_FAILURE(status))
475 pr_err("alienware-wmi: HDMI toggle failed: results: %u\n",
476 status);
477 return count;
478}
479
480static DEVICE_ATTR(hdmi, S_IRUGO | S_IWUSR, show_hdmi, toggle_hdmi);
481
482static void remove_hdmi(struct platform_device *device)
483{
484 device_remove_file(&device->dev, &dev_attr_hdmi);
485}
486
487static int create_hdmi(void)
488{
489 int ret = -ENOMEM;
490 ret = device_create_file(&platform_device->dev, &dev_attr_hdmi);
491 if (ret)
492 goto error_create_hdmi;
493 return 0;
494
495error_create_hdmi:
496 remove_hdmi(platform_device);
497 return ret;
498}
499
500static int __init alienware_wmi_init(void)
501{
502 int ret;
503
504 if (wmi_has_guid(LEGACY_CONTROL_GUID))
505 interface = LEGACY;
506 else if (wmi_has_guid(WMAX_CONTROL_GUID))
507 interface = WMAX;
508 else {
509 pr_warn("alienware-wmi: No known WMI GUID found\n");
510 return -ENODEV;
511 }
512
513 dmi_check_system(alienware_quirks);
514 if (quirks == NULL)
515 quirks = &quirk_unknown;
516
517 ret = platform_driver_register(&platform_driver);
518 if (ret)
519 goto fail_platform_driver;
520 platform_device = platform_device_alloc("alienware-wmi", -1);
521 if (!platform_device) {
522 ret = -ENOMEM;
523 goto fail_platform_device1;
524 }
525 ret = platform_device_add(platform_device);
526 if (ret)
527 goto fail_platform_device2;
528
529 if (interface == WMAX) {
530 ret = create_hdmi();
531 if (ret)
532 goto fail_prep_hdmi;
533 }
534
535 ret = alienware_zone_init(platform_device);
536 if (ret)
537 goto fail_prep_zones;
538
539 return 0;
540
541fail_prep_zones:
542 alienware_zone_exit(platform_device);
543fail_prep_hdmi:
544 platform_device_del(platform_device);
545fail_platform_device2:
546 platform_device_put(platform_device);
547fail_platform_device1:
548 platform_driver_unregister(&platform_driver);
549fail_platform_driver:
550 return ret;
551}
552
553module_init(alienware_wmi_init);
554
555static void __exit alienware_wmi_exit(void)
556{
557 if (platform_device) {
558 alienware_zone_exit(platform_device);
559 remove_hdmi(platform_device);
560 platform_device_unregister(platform_device);
561 platform_driver_unregister(&platform_driver);
562 }
563}
564
565module_exit(alienware_wmi_exit);
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c
index 570926c10014..c3784baceae3 100644
--- a/drivers/platform/x86/fujitsu-tablet.c
+++ b/drivers/platform/x86/fujitsu-tablet.c
@@ -71,6 +71,44 @@ static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initdata = {
71 KEY_LEFTALT 71 KEY_LEFTALT
72}; 72};
73 73
74static unsigned short keymap_Lifebook_T901[KEYMAP_LEN] __initdata = {
75 KEY_RESERVED,
76 KEY_RESERVED,
77 KEY_RESERVED,
78 KEY_RESERVED,
79 KEY_SCROLLDOWN,
80 KEY_SCROLLUP,
81 KEY_CYCLEWINDOWS,
82 KEY_LEFTCTRL,
83 KEY_RESERVED,
84 KEY_RESERVED,
85 KEY_RESERVED,
86 KEY_RESERVED,
87 KEY_RESERVED,
88 KEY_RESERVED,
89 KEY_RESERVED,
90 KEY_LEFTMETA
91};
92
93static unsigned short keymap_Lifebook_T902[KEYMAP_LEN] __initdata = {
94 KEY_RESERVED,
95 KEY_VOLUMEDOWN,
96 KEY_VOLUMEUP,
97 KEY_CYCLEWINDOWS,
98 KEY_PROG1,
99 KEY_PROG2,
100 KEY_LEFTMETA,
101 KEY_RESERVED,
102 KEY_RESERVED,
103 KEY_RESERVED,
104 KEY_RESERVED,
105 KEY_RESERVED,
106 KEY_RESERVED,
107 KEY_RESERVED,
108 KEY_RESERVED,
109 KEY_RESERVED,
110};
111
74static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initdata = { 112static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initdata = {
75 KEY_RESERVED, 113 KEY_RESERVED,
76 KEY_RESERVED, 114 KEY_RESERVED,
@@ -302,6 +340,33 @@ static int fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
302static const struct dmi_system_id dmi_ids[] __initconst = { 340static const struct dmi_system_id dmi_ids[] __initconst = {
303 { 341 {
304 .callback = fujitsu_dmi_lifebook, 342 .callback = fujitsu_dmi_lifebook,
343 .ident = "Fujitsu Lifebook T901",
344 .matches = {
345 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
346 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook T901")
347 },
348 .driver_data = keymap_Lifebook_T901
349 },
350 {
351 .callback = fujitsu_dmi_lifebook,
352 .ident = "Fujitsu Lifebook T901",
353 .matches = {
354 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
355 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T901")
356 },
357 .driver_data = keymap_Lifebook_T901
358 },
359 {
360 .callback = fujitsu_dmi_lifebook,
361 .ident = "Fujitsu Lifebook T902",
362 .matches = {
363 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
364 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T902")
365 },
366 .driver_data = keymap_Lifebook_T902
367 },
368 {
369 .callback = fujitsu_dmi_lifebook,
305 .ident = "Fujitsu Siemens P/T Series", 370 .ident = "Fujitsu Siemens P/T Series",
306 .matches = { 371 .matches = {
307 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), 372 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
diff --git a/drivers/platform/x86/intel_baytrail.c b/drivers/platform/x86/intel_baytrail.c
deleted file mode 100644
index f96626b17260..000000000000
--- a/drivers/platform/x86/intel_baytrail.c
+++ /dev/null
@@ -1,224 +0,0 @@
1/*
2 * Baytrail IOSF-SB MailBox Interface Driver
3 * Copyright (c) 2013, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 *
15 * The IOSF-SB is a fabric bus available on Atom based SOC's that uses a
16 * mailbox interface (MBI) to communicate with mutiple devices. This
17 * driver implements BayTrail-specific access to this interface.
18 */
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/spinlock.h>
23#include <linux/pci.h>
24
25#include "intel_baytrail.h"
26
27static DEFINE_SPINLOCK(iosf_mbi_lock);
28
29static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset)
30{
31 return (op << 24) | (port << 16) | (offset << 8) | BT_MBI_ENABLE;
32}
33
34static struct pci_dev *mbi_pdev; /* one mbi device */
35
36/* Hold lock before calling */
37static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr)
38{
39 int result;
40
41 if (!mbi_pdev)
42 return -ENODEV;
43
44 if (mcrx) {
45 result = pci_write_config_dword(mbi_pdev,
46 BT_MBI_MCRX_OFFSET, mcrx);
47 if (result < 0)
48 goto iosf_mbi_read_err;
49 }
50
51 result = pci_write_config_dword(mbi_pdev,
52 BT_MBI_MCR_OFFSET, mcr);
53 if (result < 0)
54 goto iosf_mbi_read_err;
55
56 result = pci_read_config_dword(mbi_pdev,
57 BT_MBI_MDR_OFFSET, mdr);
58 if (result < 0)
59 goto iosf_mbi_read_err;
60
61 return 0;
62
63iosf_mbi_read_err:
64 dev_err(&mbi_pdev->dev, "error: PCI config operation returned %d\n",
65 result);
66 return result;
67}
68
69/* Hold lock before calling */
70static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr)
71{
72 int result;
73
74 if (!mbi_pdev)
75 return -ENODEV;
76
77 result = pci_write_config_dword(mbi_pdev,
78 BT_MBI_MDR_OFFSET, mdr);
79 if (result < 0)
80 goto iosf_mbi_write_err;
81
82 if (mcrx) {
83 result = pci_write_config_dword(mbi_pdev,
84 BT_MBI_MCRX_OFFSET, mcrx);
85 if (result < 0)
86 goto iosf_mbi_write_err;
87 }
88
89 result = pci_write_config_dword(mbi_pdev,
90 BT_MBI_MCR_OFFSET, mcr);
91 if (result < 0)
92 goto iosf_mbi_write_err;
93
94 return 0;
95
96iosf_mbi_write_err:
97 dev_err(&mbi_pdev->dev, "error: PCI config operation returned %d\n",
98 result);
99 return result;
100}
101
102int bt_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr)
103{
104 u32 mcr, mcrx;
105 unsigned long flags;
106 int ret;
107
108 /*Access to the GFX unit is handled by GPU code */
109 BUG_ON(port == BT_MBI_UNIT_GFX);
110
111 mcr = iosf_mbi_form_mcr(opcode, port, offset & BT_MBI_MASK_LO);
112 mcrx = offset & BT_MBI_MASK_HI;
113
114 spin_lock_irqsave(&iosf_mbi_lock, flags);
115 ret = iosf_mbi_pci_read_mdr(mcrx, mcr, mdr);
116 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
117
118 return ret;
119}
120EXPORT_SYMBOL(bt_mbi_read);
121
122int bt_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr)
123{
124 u32 mcr, mcrx;
125 unsigned long flags;
126 int ret;
127
128 /*Access to the GFX unit is handled by GPU code */
129 BUG_ON(port == BT_MBI_UNIT_GFX);
130
131 mcr = iosf_mbi_form_mcr(opcode, port, offset & BT_MBI_MASK_LO);
132 mcrx = offset & BT_MBI_MASK_HI;
133
134 spin_lock_irqsave(&iosf_mbi_lock, flags);
135 ret = iosf_mbi_pci_write_mdr(mcrx, mcr, mdr);
136 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
137
138 return ret;
139}
140EXPORT_SYMBOL(bt_mbi_write);
141
142int bt_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask)
143{
144 u32 mcr, mcrx;
145 u32 value;
146 unsigned long flags;
147 int ret;
148
149 /*Access to the GFX unit is handled by GPU code */
150 BUG_ON(port == BT_MBI_UNIT_GFX);
151
152 mcr = iosf_mbi_form_mcr(opcode, port, offset & BT_MBI_MASK_LO);
153 mcrx = offset & BT_MBI_MASK_HI;
154
155 spin_lock_irqsave(&iosf_mbi_lock, flags);
156
157 /* Read current mdr value */
158 ret = iosf_mbi_pci_read_mdr(mcrx, mcr & BT_MBI_RD_MASK, &value);
159 if (ret < 0) {
160 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
161 return ret;
162 }
163
164 /* Apply mask */
165 value &= ~mask;
166 mdr &= mask;
167 value |= mdr;
168
169 /* Write back */
170 ret = iosf_mbi_pci_write_mdr(mcrx, mcr | BT_MBI_WR_MASK, value);
171
172 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
173
174 return ret;
175}
176EXPORT_SYMBOL(bt_mbi_modify);
177
178static int iosf_mbi_probe(struct pci_dev *pdev,
179 const struct pci_device_id *unused)
180{
181 int ret;
182
183 ret = pci_enable_device(pdev);
184 if (ret < 0) {
185 dev_err(&pdev->dev, "error: could not enable device\n");
186 return ret;
187 }
188
189 mbi_pdev = pci_dev_get(pdev);
190 return 0;
191}
192
193static DEFINE_PCI_DEVICE_TABLE(iosf_mbi_pci_ids) = {
194 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F00) },
195 { 0, },
196};
197MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids);
198
199static struct pci_driver iosf_mbi_pci_driver = {
200 .name = "iosf_mbi_pci",
201 .probe = iosf_mbi_probe,
202 .id_table = iosf_mbi_pci_ids,
203};
204
205static int __init bt_mbi_init(void)
206{
207 return pci_register_driver(&iosf_mbi_pci_driver);
208}
209
210static void __exit bt_mbi_exit(void)
211{
212 pci_unregister_driver(&iosf_mbi_pci_driver);
213 if (mbi_pdev) {
214 pci_dev_put(mbi_pdev);
215 mbi_pdev = NULL;
216 }
217}
218
219module_init(bt_mbi_init);
220module_exit(bt_mbi_exit);
221
222MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
223MODULE_DESCRIPTION("BayTrail Mailbox Interface accessor");
224MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_baytrail.h b/drivers/platform/x86/intel_baytrail.h
deleted file mode 100644
index 8bcc311262e9..000000000000
--- a/drivers/platform/x86/intel_baytrail.h
+++ /dev/null
@@ -1,90 +0,0 @@
1/*
2 * intel_baytrail.h: MailBox access support for Intel BayTrail platforms
3 */
4
5#ifndef INTEL_BAYTRAIL_MBI_SYMS_H
6#define INTEL_BAYTRAIL_MBI_SYMS_H
7
8#define BT_MBI_MCR_OFFSET 0xD0
9#define BT_MBI_MDR_OFFSET 0xD4
10#define BT_MBI_MCRX_OFFSET 0xD8
11
12#define BT_MBI_RD_MASK 0xFEFFFFFF
13#define BT_MBI_WR_MASK 0X01000000
14
15#define BT_MBI_MASK_HI 0xFFFFFF00
16#define BT_MBI_MASK_LO 0x000000FF
17#define BT_MBI_ENABLE 0xF0
18
19/* BT-SB unit access methods */
20#define BT_MBI_UNIT_AUNIT 0x00
21#define BT_MBI_UNIT_SMC 0x01
22#define BT_MBI_UNIT_CPU 0x02
23#define BT_MBI_UNIT_BUNIT 0x03
24#define BT_MBI_UNIT_PMC 0x04
25#define BT_MBI_UNIT_GFX 0x06
26#define BT_MBI_UNIT_SMI 0x0C
27#define BT_MBI_UNIT_USB 0x43
28#define BT_MBI_UNIT_SATA 0xA3
29#define BT_MBI_UNIT_PCIE 0xA6
30
31/* Read/write opcodes */
32#define BT_MBI_AUNIT_READ 0x10
33#define BT_MBI_AUNIT_WRITE 0x11
34#define BT_MBI_SMC_READ 0x10
35#define BT_MBI_SMC_WRITE 0x11
36#define BT_MBI_CPU_READ 0x10
37#define BT_MBI_CPU_WRITE 0x11
38#define BT_MBI_BUNIT_READ 0x10
39#define BT_MBI_BUNIT_WRITE 0x11
40#define BT_MBI_PMC_READ 0x06
41#define BT_MBI_PMC_WRITE 0x07
42#define BT_MBI_GFX_READ 0x00
43#define BT_MBI_GFX_WRITE 0x01
44#define BT_MBI_SMIO_READ 0x06
45#define BT_MBI_SMIO_WRITE 0x07
46#define BT_MBI_USB_READ 0x06
47#define BT_MBI_USB_WRITE 0x07
48#define BT_MBI_SATA_READ 0x00
49#define BT_MBI_SATA_WRITE 0x01
50#define BT_MBI_PCIE_READ 0x00
51#define BT_MBI_PCIE_WRITE 0x01
52
53/**
54 * bt_mbi_read() - MailBox Interface read command
55 * @port: port indicating subunit being accessed
56 * @opcode: port specific read or write opcode
57 * @offset: register address offset
58 * @mdr: register data to be read
59 *
60 * Locking is handled by spinlock - cannot sleep.
61 * Return: Nonzero on error
62 */
63int bt_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr);
64
65/**
66 * bt_mbi_write() - MailBox unmasked write command
67 * @port: port indicating subunit being accessed
68 * @opcode: port specific read or write opcode
69 * @offset: register address offset
70 * @mdr: register data to be written
71 *
72 * Locking is handled by spinlock - cannot sleep.
73 * Return: Nonzero on error
74 */
75int bt_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr);
76
77/**
78 * bt_mbi_modify() - MailBox masked write command
79 * @port: port indicating subunit being accessed
80 * @opcode: port specific read or write opcode
81 * @offset: register address offset
82 * @mdr: register data being modified
83 * @mask: mask indicating bits in mdr to be modified
84 *
85 * Locking is handled by spinlock - cannot sleep.
86 * Return: Nonzero on error
87 */
88int bt_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask);
89
90#endif /* INTEL_BAYTRAIL_MBI_SYMS_H */
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 609d38779b26..3f870972247c 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -449,6 +449,7 @@ static struct attribute_group pcc_attr_group = {
449 449
450/* hotkey input device driver */ 450/* hotkey input device driver */
451 451
452static int sleep_keydown_seen;
452static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) 453static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
453{ 454{
454 struct input_dev *hotk_input_dev = pcc->input_dev; 455 struct input_dev *hotk_input_dev = pcc->input_dev;
@@ -462,6 +463,16 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
462 "error getting hotkey status\n")); 463 "error getting hotkey status\n"));
463 return; 464 return;
464 } 465 }
466
467 /* hack: some firmware sends no key down for sleep / hibernate */
468 if ((result & 0xf) == 0x7 || (result & 0xf) == 0xa) {
469 if (result & 0x80)
470 sleep_keydown_seen = 1;
471 if (!sleep_keydown_seen)
472 sparse_keymap_report_event(hotk_input_dev,
473 result & 0xf, 0x80, false);
474 }
475
465 if (!sparse_keymap_report_event(hotk_input_dev, 476 if (!sparse_keymap_report_event(hotk_input_dev,
466 result & 0xf, result & 0x80, false)) 477 result & 0xf, result & 0x80, false))
467 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 478 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 8f8551a63cc0..9c5a07417b2b 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -76,8 +76,6 @@ do { \
76 pr_warn(fmt, ##__VA_ARGS__); \ 76 pr_warn(fmt, ##__VA_ARGS__); \
77} while (0) 77} while (0)
78 78
79#define SONY_LAPTOP_DRIVER_VERSION "0.6"
80
81#define SONY_NC_CLASS "sony-nc" 79#define SONY_NC_CLASS "sony-nc"
82#define SONY_NC_HID "SNY5001" 80#define SONY_NC_HID "SNY5001"
83#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver" 81#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver"
@@ -89,7 +87,6 @@ do { \
89MODULE_AUTHOR("Stelian Pop, Mattia Dongili"); 87MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
90MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)"); 88MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
91MODULE_LICENSE("GPL"); 89MODULE_LICENSE("GPL");
92MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION);
93 90
94static int debug; 91static int debug;
95module_param(debug, int, 0); 92module_param(debug, int, 0);
@@ -129,7 +126,8 @@ static int kbd_backlight = -1;
129module_param(kbd_backlight, int, 0444); 126module_param(kbd_backlight, int, 0444);
130MODULE_PARM_DESC(kbd_backlight, 127MODULE_PARM_DESC(kbd_backlight,
131 "set this to 0 to disable keyboard backlight, " 128 "set this to 0 to disable keyboard backlight, "
132 "1 to enable it (default: no change from current value)"); 129 "1 to enable it with automatic control and 2 to have it always "
130 "on (default: no change from current value)");
133 131
134static int kbd_backlight_timeout = -1; 132static int kbd_backlight_timeout = -1;
135module_param(kbd_backlight_timeout, int, 0444); 133module_param(kbd_backlight_timeout, int, 0444);
@@ -152,7 +150,8 @@ static void sony_nc_battery_care_cleanup(struct platform_device *pd);
152static int sony_nc_thermal_setup(struct platform_device *pd); 150static int sony_nc_thermal_setup(struct platform_device *pd);
153static void sony_nc_thermal_cleanup(struct platform_device *pd); 151static void sony_nc_thermal_cleanup(struct platform_device *pd);
154 152
155static int sony_nc_lid_resume_setup(struct platform_device *pd); 153static int sony_nc_lid_resume_setup(struct platform_device *pd,
154 unsigned int handle);
156static void sony_nc_lid_resume_cleanup(struct platform_device *pd); 155static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
157 156
158static int sony_nc_gfx_switch_setup(struct platform_device *pd, 157static int sony_nc_gfx_switch_setup(struct platform_device *pd,
@@ -163,6 +162,21 @@ static int __sony_nc_gfx_switch_status_get(void);
163static int sony_nc_highspeed_charging_setup(struct platform_device *pd); 162static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
164static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); 163static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
165 164
165static int sony_nc_lowbatt_setup(struct platform_device *pd);
166static void sony_nc_lowbatt_cleanup(struct platform_device *pd);
167
168static int sony_nc_fanspeed_setup(struct platform_device *pd);
169static void sony_nc_fanspeed_cleanup(struct platform_device *pd);
170
171static int sony_nc_usb_charge_setup(struct platform_device *pd);
172static void sony_nc_usb_charge_cleanup(struct platform_device *pd);
173
174static int sony_nc_panelid_setup(struct platform_device *pd);
175static void sony_nc_panelid_cleanup(struct platform_device *pd);
176
177static int sony_nc_smart_conn_setup(struct platform_device *pd);
178static void sony_nc_smart_conn_cleanup(struct platform_device *pd);
179
166static int sony_nc_touchpad_setup(struct platform_device *pd, 180static int sony_nc_touchpad_setup(struct platform_device *pd,
167 unsigned int handle); 181 unsigned int handle);
168static void sony_nc_touchpad_cleanup(struct platform_device *pd); 182static void sony_nc_touchpad_cleanup(struct platform_device *pd);
@@ -1122,6 +1136,8 @@ static struct sony_nc_event sony_100_events[] = {
1122 { 0x25, SONYPI_EVENT_ANYBUTTON_RELEASED }, 1136 { 0x25, SONYPI_EVENT_ANYBUTTON_RELEASED },
1123 { 0xa6, SONYPI_EVENT_HELP_PRESSED }, 1137 { 0xa6, SONYPI_EVENT_HELP_PRESSED },
1124 { 0x26, SONYPI_EVENT_ANYBUTTON_RELEASED }, 1138 { 0x26, SONYPI_EVENT_ANYBUTTON_RELEASED },
1139 { 0xa8, SONYPI_EVENT_FNKEY_1 },
1140 { 0x28, SONYPI_EVENT_ANYBUTTON_RELEASED },
1125 { 0, 0 }, 1141 { 0, 0 },
1126}; 1142};
1127 1143
@@ -1339,7 +1355,8 @@ static void sony_nc_function_setup(struct acpi_device *device,
1339 result); 1355 result);
1340 break; 1356 break;
1341 case 0x0119: 1357 case 0x0119:
1342 result = sony_nc_lid_resume_setup(pf_device); 1358 case 0x015D:
1359 result = sony_nc_lid_resume_setup(pf_device, handle);
1343 if (result) 1360 if (result)
1344 pr_err("couldn't set up lid resume function (%d)\n", 1361 pr_err("couldn't set up lid resume function (%d)\n",
1345 result); 1362 result);
@@ -1381,6 +1398,36 @@ static void sony_nc_function_setup(struct acpi_device *device,
1381 pr_err("couldn't set up keyboard backlight function (%d)\n", 1398 pr_err("couldn't set up keyboard backlight function (%d)\n",
1382 result); 1399 result);
1383 break; 1400 break;
1401 case 0x0121:
1402 result = sony_nc_lowbatt_setup(pf_device);
1403 if (result)
1404 pr_err("couldn't set up low battery function (%d)\n",
1405 result);
1406 break;
1407 case 0x0149:
1408 result = sony_nc_fanspeed_setup(pf_device);
1409 if (result)
1410 pr_err("couldn't set up fan speed function (%d)\n",
1411 result);
1412 break;
1413 case 0x0155:
1414 result = sony_nc_usb_charge_setup(pf_device);
1415 if (result)
1416 pr_err("couldn't set up USB charge support (%d)\n",
1417 result);
1418 break;
1419 case 0x011D:
1420 result = sony_nc_panelid_setup(pf_device);
1421 if (result)
1422 pr_err("couldn't set up panel ID function (%d)\n",
1423 result);
1424 break;
1425 case 0x0168:
1426 result = sony_nc_smart_conn_setup(pf_device);
1427 if (result)
1428 pr_err("couldn't set up smart connect support (%d)\n",
1429 result);
1430 break;
1384 default: 1431 default:
1385 continue; 1432 continue;
1386 } 1433 }
@@ -1420,6 +1467,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
1420 sony_nc_battery_care_cleanup(pd); 1467 sony_nc_battery_care_cleanup(pd);
1421 break; 1468 break;
1422 case 0x0119: 1469 case 0x0119:
1470 case 0x015D:
1423 sony_nc_lid_resume_cleanup(pd); 1471 sony_nc_lid_resume_cleanup(pd);
1424 break; 1472 break;
1425 case 0x0122: 1473 case 0x0122:
@@ -1444,6 +1492,21 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
1444 case 0x0163: 1492 case 0x0163:
1445 sony_nc_kbd_backlight_cleanup(pd, handle); 1493 sony_nc_kbd_backlight_cleanup(pd, handle);
1446 break; 1494 break;
1495 case 0x0121:
1496 sony_nc_lowbatt_cleanup(pd);
1497 break;
1498 case 0x0149:
1499 sony_nc_fanspeed_cleanup(pd);
1500 break;
1501 case 0x0155:
1502 sony_nc_usb_charge_cleanup(pd);
1503 break;
1504 case 0x011D:
1505 sony_nc_panelid_cleanup(pd);
1506 break;
1507 case 0x0168:
1508 sony_nc_smart_conn_cleanup(pd);
1509 break;
1447 default: 1510 default:
1448 continue; 1511 continue;
1449 } 1512 }
@@ -1719,7 +1782,7 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1719{ 1782{
1720 int result; 1783 int result;
1721 1784
1722 if (value > 1) 1785 if (value > 2)
1723 return -EINVAL; 1786 return -EINVAL;
1724 1787
1725 if (sony_call_snc_handle(kbdbl_ctl->handle, 1788 if (sony_call_snc_handle(kbdbl_ctl->handle,
@@ -1727,8 +1790,10 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1727 return -EIO; 1790 return -EIO;
1728 1791
1729 /* Try to turn the light on/off immediately */ 1792 /* Try to turn the light on/off immediately */
1730 sony_call_snc_handle(kbdbl_ctl->handle, 1793 if (value != 1)
1731 (value << 0x10) | (kbdbl_ctl->base + 0x100), &result); 1794 sony_call_snc_handle(kbdbl_ctl->handle,
1795 (value << 0x0f) | (kbdbl_ctl->base + 0x100),
1796 &result);
1732 1797
1733 kbdbl_ctl->mode = value; 1798 kbdbl_ctl->mode = value;
1734 1799
@@ -2221,9 +2286,14 @@ static void sony_nc_thermal_resume(void)
2221#endif 2286#endif
2222 2287
2223/* resume on LID open */ 2288/* resume on LID open */
2289#define LID_RESUME_S5 0
2290#define LID_RESUME_S4 1
2291#define LID_RESUME_S3 2
2292#define LID_RESUME_MAX 3
2224struct snc_lid_resume_control { 2293struct snc_lid_resume_control {
2225 struct device_attribute attrs[3]; 2294 struct device_attribute attrs[LID_RESUME_MAX];
2226 unsigned int status; 2295 unsigned int status;
2296 int handle;
2227}; 2297};
2228static struct snc_lid_resume_control *lid_ctl; 2298static struct snc_lid_resume_control *lid_ctl;
2229 2299
@@ -2231,8 +2301,9 @@ static ssize_t sony_nc_lid_resume_store(struct device *dev,
2231 struct device_attribute *attr, 2301 struct device_attribute *attr,
2232 const char *buffer, size_t count) 2302 const char *buffer, size_t count)
2233{ 2303{
2234 unsigned int result, pos; 2304 unsigned int result;
2235 unsigned long value; 2305 unsigned long value;
2306 unsigned int pos = LID_RESUME_S5;
2236 if (count > 31) 2307 if (count > 31)
2237 return -EINVAL; 2308 return -EINVAL;
2238 2309
@@ -2245,21 +2316,21 @@ static ssize_t sony_nc_lid_resume_store(struct device *dev,
2245 * +--------------+ 2316 * +--------------+
2246 * 2 1 0 2317 * 2 1 0
2247 */ 2318 */
2248 if (strcmp(attr->attr.name, "lid_resume_S3") == 0) 2319 while (pos < LID_RESUME_MAX) {
2249 pos = 2; 2320 if (&lid_ctl->attrs[pos].attr == &attr->attr)
2250 else if (strcmp(attr->attr.name, "lid_resume_S4") == 0) 2321 break;
2251 pos = 1; 2322 pos++;
2252 else if (strcmp(attr->attr.name, "lid_resume_S5") == 0) 2323 }
2253 pos = 0; 2324 if (pos == LID_RESUME_MAX)
2254 else 2325 return -EINVAL;
2255 return -EINVAL;
2256 2326
2257 if (value) 2327 if (value)
2258 value = lid_ctl->status | (1 << pos); 2328 value = lid_ctl->status | (1 << pos);
2259 else 2329 else
2260 value = lid_ctl->status & ~(1 << pos); 2330 value = lid_ctl->status & ~(1 << pos);
2261 2331
2262 if (sony_call_snc_handle(0x0119, value << 0x10 | 0x0100, &result)) 2332 if (sony_call_snc_handle(lid_ctl->handle, value << 0x10 | 0x0100,
2333 &result))
2263 return -EIO; 2334 return -EIO;
2264 2335
2265 lid_ctl->status = value; 2336 lid_ctl->status = value;
@@ -2268,29 +2339,27 @@ static ssize_t sony_nc_lid_resume_store(struct device *dev,
2268} 2339}
2269 2340
2270static ssize_t sony_nc_lid_resume_show(struct device *dev, 2341static ssize_t sony_nc_lid_resume_show(struct device *dev,
2271 struct device_attribute *attr, char *buffer) 2342 struct device_attribute *attr,
2343 char *buffer)
2272{ 2344{
2273 unsigned int pos; 2345 unsigned int pos = LID_RESUME_S5;
2274 2346
2275 if (strcmp(attr->attr.name, "lid_resume_S3") == 0) 2347 while (pos < LID_RESUME_MAX) {
2276 pos = 2; 2348 if (&lid_ctl->attrs[pos].attr == &attr->attr)
2277 else if (strcmp(attr->attr.name, "lid_resume_S4") == 0) 2349 return snprintf(buffer, PAGE_SIZE, "%d\n",
2278 pos = 1; 2350 (lid_ctl->status >> pos) & 0x01);
2279 else if (strcmp(attr->attr.name, "lid_resume_S5") == 0) 2351 pos++;
2280 pos = 0; 2352 }
2281 else 2353 return -EINVAL;
2282 return -EINVAL;
2283
2284 return snprintf(buffer, PAGE_SIZE, "%d\n",
2285 (lid_ctl->status >> pos) & 0x01);
2286} 2354}
2287 2355
2288static int sony_nc_lid_resume_setup(struct platform_device *pd) 2356static int sony_nc_lid_resume_setup(struct platform_device *pd,
2357 unsigned int handle)
2289{ 2358{
2290 unsigned int result; 2359 unsigned int result;
2291 int i; 2360 int i;
2292 2361
2293 if (sony_call_snc_handle(0x0119, 0x0000, &result)) 2362 if (sony_call_snc_handle(handle, 0x0000, &result))
2294 return -EIO; 2363 return -EIO;
2295 2364
2296 lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL); 2365 lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL);
@@ -2298,26 +2367,29 @@ static int sony_nc_lid_resume_setup(struct platform_device *pd)
2298 return -ENOMEM; 2367 return -ENOMEM;
2299 2368
2300 lid_ctl->status = result & 0x7; 2369 lid_ctl->status = result & 0x7;
2370 lid_ctl->handle = handle;
2301 2371
2302 sysfs_attr_init(&lid_ctl->attrs[0].attr); 2372 sysfs_attr_init(&lid_ctl->attrs[0].attr);
2303 lid_ctl->attrs[0].attr.name = "lid_resume_S3"; 2373 lid_ctl->attrs[LID_RESUME_S5].attr.name = "lid_resume_S5";
2304 lid_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR; 2374 lid_ctl->attrs[LID_RESUME_S5].attr.mode = S_IRUGO | S_IWUSR;
2305 lid_ctl->attrs[0].show = sony_nc_lid_resume_show; 2375 lid_ctl->attrs[LID_RESUME_S5].show = sony_nc_lid_resume_show;
2306 lid_ctl->attrs[0].store = sony_nc_lid_resume_store; 2376 lid_ctl->attrs[LID_RESUME_S5].store = sony_nc_lid_resume_store;
2307 2377
2308 sysfs_attr_init(&lid_ctl->attrs[1].attr); 2378 if (handle == 0x0119) {
2309 lid_ctl->attrs[1].attr.name = "lid_resume_S4"; 2379 sysfs_attr_init(&lid_ctl->attrs[1].attr);
2310 lid_ctl->attrs[1].attr.mode = S_IRUGO | S_IWUSR; 2380 lid_ctl->attrs[LID_RESUME_S4].attr.name = "lid_resume_S4";
2311 lid_ctl->attrs[1].show = sony_nc_lid_resume_show; 2381 lid_ctl->attrs[LID_RESUME_S4].attr.mode = S_IRUGO | S_IWUSR;
2312 lid_ctl->attrs[1].store = sony_nc_lid_resume_store; 2382 lid_ctl->attrs[LID_RESUME_S4].show = sony_nc_lid_resume_show;
2313 2383 lid_ctl->attrs[LID_RESUME_S4].store = sony_nc_lid_resume_store;
2314 sysfs_attr_init(&lid_ctl->attrs[2].attr); 2384
2315 lid_ctl->attrs[2].attr.name = "lid_resume_S5"; 2385 sysfs_attr_init(&lid_ctl->attrs[2].attr);
2316 lid_ctl->attrs[2].attr.mode = S_IRUGO | S_IWUSR; 2386 lid_ctl->attrs[LID_RESUME_S3].attr.name = "lid_resume_S3";
2317 lid_ctl->attrs[2].show = sony_nc_lid_resume_show; 2387 lid_ctl->attrs[LID_RESUME_S3].attr.mode = S_IRUGO | S_IWUSR;
2318 lid_ctl->attrs[2].store = sony_nc_lid_resume_store; 2388 lid_ctl->attrs[LID_RESUME_S3].show = sony_nc_lid_resume_show;
2319 2389 lid_ctl->attrs[LID_RESUME_S3].store = sony_nc_lid_resume_store;
2320 for (i = 0; i < 3; i++) { 2390 }
2391 for (i = 0; i < LID_RESUME_MAX &&
2392 lid_ctl->attrs[LID_RESUME_S3].attr.name; i++) {
2321 result = device_create_file(&pd->dev, &lid_ctl->attrs[i]); 2393 result = device_create_file(&pd->dev, &lid_ctl->attrs[i]);
2322 if (result) 2394 if (result)
2323 goto liderror; 2395 goto liderror;
@@ -2340,8 +2412,12 @@ static void sony_nc_lid_resume_cleanup(struct platform_device *pd)
2340 int i; 2412 int i;
2341 2413
2342 if (lid_ctl) { 2414 if (lid_ctl) {
2343 for (i = 0; i < 3; i++) 2415 for (i = 0; i < LID_RESUME_MAX; i++) {
2416 if (!lid_ctl->attrs[i].attr.name)
2417 break;
2418
2344 device_remove_file(&pd->dev, &lid_ctl->attrs[i]); 2419 device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2420 }
2345 2421
2346 kfree(lid_ctl); 2422 kfree(lid_ctl);
2347 lid_ctl = NULL; 2423 lid_ctl = NULL;
@@ -2524,6 +2600,355 @@ static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
2524 } 2600 }
2525} 2601}
2526 2602
2603/* low battery function */
2604static struct device_attribute *lowbatt_handle;
2605
2606static ssize_t sony_nc_lowbatt_store(struct device *dev,
2607 struct device_attribute *attr,
2608 const char *buffer, size_t count)
2609{
2610 unsigned int result;
2611 unsigned long value;
2612
2613 if (count > 31)
2614 return -EINVAL;
2615
2616 if (kstrtoul(buffer, 10, &value) || value > 1)
2617 return -EINVAL;
2618
2619 if (sony_call_snc_handle(0x0121, value << 8, &result))
2620 return -EIO;
2621
2622 return count;
2623}
2624
2625static ssize_t sony_nc_lowbatt_show(struct device *dev,
2626 struct device_attribute *attr, char *buffer)
2627{
2628 unsigned int result;
2629
2630 if (sony_call_snc_handle(0x0121, 0x0200, &result))
2631 return -EIO;
2632
2633 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 1);
2634}
2635
2636static int sony_nc_lowbatt_setup(struct platform_device *pd)
2637{
2638 unsigned int result;
2639
2640 lowbatt_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2641 if (!lowbatt_handle)
2642 return -ENOMEM;
2643
2644 sysfs_attr_init(&lowbatt_handle->attr);
2645 lowbatt_handle->attr.name = "lowbatt_hibernate";
2646 lowbatt_handle->attr.mode = S_IRUGO | S_IWUSR;
2647 lowbatt_handle->show = sony_nc_lowbatt_show;
2648 lowbatt_handle->store = sony_nc_lowbatt_store;
2649
2650 result = device_create_file(&pd->dev, lowbatt_handle);
2651 if (result) {
2652 kfree(lowbatt_handle);
2653 lowbatt_handle = NULL;
2654 return result;
2655 }
2656
2657 return 0;
2658}
2659
2660static void sony_nc_lowbatt_cleanup(struct platform_device *pd)
2661{
2662 if (lowbatt_handle) {
2663 device_remove_file(&pd->dev, lowbatt_handle);
2664 kfree(lowbatt_handle);
2665 lowbatt_handle = NULL;
2666 }
2667}
2668
2669/* fan speed function */
2670static struct device_attribute *fan_handle, *hsf_handle;
2671
2672static ssize_t sony_nc_hsfan_store(struct device *dev,
2673 struct device_attribute *attr,
2674 const char *buffer, size_t count)
2675{
2676 unsigned int result;
2677 unsigned long value;
2678
2679 if (count > 31)
2680 return -EINVAL;
2681
2682 if (kstrtoul(buffer, 10, &value) || value > 1)
2683 return -EINVAL;
2684
2685 if (sony_call_snc_handle(0x0149, value << 0x10 | 0x0200, &result))
2686 return -EIO;
2687
2688 return count;
2689}
2690
2691static ssize_t sony_nc_hsfan_show(struct device *dev,
2692 struct device_attribute *attr, char *buffer)
2693{
2694 unsigned int result;
2695
2696 if (sony_call_snc_handle(0x0149, 0x0100, &result))
2697 return -EIO;
2698
2699 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2700}
2701
2702static ssize_t sony_nc_fanspeed_show(struct device *dev,
2703 struct device_attribute *attr, char *buffer)
2704{
2705 unsigned int result;
2706
2707 if (sony_call_snc_handle(0x0149, 0x0300, &result))
2708 return -EIO;
2709
2710 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff);
2711}
2712
2713static int sony_nc_fanspeed_setup(struct platform_device *pd)
2714{
2715 unsigned int result;
2716
2717 fan_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2718 if (!fan_handle)
2719 return -ENOMEM;
2720
2721 hsf_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2722 if (!hsf_handle) {
2723 result = -ENOMEM;
2724 goto out_hsf_handle_alloc;
2725 }
2726
2727 sysfs_attr_init(&fan_handle->attr);
2728 fan_handle->attr.name = "fanspeed";
2729 fan_handle->attr.mode = S_IRUGO;
2730 fan_handle->show = sony_nc_fanspeed_show;
2731 fan_handle->store = NULL;
2732
2733 sysfs_attr_init(&hsf_handle->attr);
2734 hsf_handle->attr.name = "fan_forced";
2735 hsf_handle->attr.mode = S_IRUGO | S_IWUSR;
2736 hsf_handle->show = sony_nc_hsfan_show;
2737 hsf_handle->store = sony_nc_hsfan_store;
2738
2739 result = device_create_file(&pd->dev, fan_handle);
2740 if (result)
2741 goto out_fan_handle;
2742
2743 result = device_create_file(&pd->dev, hsf_handle);
2744 if (result)
2745 goto out_hsf_handle;
2746
2747 return 0;
2748
2749out_hsf_handle:
2750 device_remove_file(&pd->dev, fan_handle);
2751
2752out_fan_handle:
2753 kfree(hsf_handle);
2754 hsf_handle = NULL;
2755
2756out_hsf_handle_alloc:
2757 kfree(fan_handle);
2758 fan_handle = NULL;
2759 return result;
2760}
2761
2762static void sony_nc_fanspeed_cleanup(struct platform_device *pd)
2763{
2764 if (fan_handle) {
2765 device_remove_file(&pd->dev, fan_handle);
2766 kfree(fan_handle);
2767 fan_handle = NULL;
2768 }
2769 if (hsf_handle) {
2770 device_remove_file(&pd->dev, hsf_handle);
2771 kfree(hsf_handle);
2772 hsf_handle = NULL;
2773 }
2774}
2775
2776/* USB charge function */
2777static struct device_attribute *uc_handle;
2778
2779static ssize_t sony_nc_usb_charge_store(struct device *dev,
2780 struct device_attribute *attr,
2781 const char *buffer, size_t count)
2782{
2783 unsigned int result;
2784 unsigned long value;
2785
2786 if (count > 31)
2787 return -EINVAL;
2788
2789 if (kstrtoul(buffer, 10, &value) || value > 1)
2790 return -EINVAL;
2791
2792 if (sony_call_snc_handle(0x0155, value << 0x10 | 0x0100, &result))
2793 return -EIO;
2794
2795 return count;
2796}
2797
2798static ssize_t sony_nc_usb_charge_show(struct device *dev,
2799 struct device_attribute *attr, char *buffer)
2800{
2801 unsigned int result;
2802
2803 if (sony_call_snc_handle(0x0155, 0x0000, &result))
2804 return -EIO;
2805
2806 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2807}
2808
2809static int sony_nc_usb_charge_setup(struct platform_device *pd)
2810{
2811 unsigned int result;
2812
2813 if (sony_call_snc_handle(0x0155, 0x0000, &result) || !(result & 0x01)) {
2814 /* some models advertise the handle but have no implementation
2815 * for it
2816 */
2817 pr_info("No USB Charge capability found\n");
2818 return 0;
2819 }
2820
2821 uc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2822 if (!uc_handle)
2823 return -ENOMEM;
2824
2825 sysfs_attr_init(&uc_handle->attr);
2826 uc_handle->attr.name = "usb_charge";
2827 uc_handle->attr.mode = S_IRUGO | S_IWUSR;
2828 uc_handle->show = sony_nc_usb_charge_show;
2829 uc_handle->store = sony_nc_usb_charge_store;
2830
2831 result = device_create_file(&pd->dev, uc_handle);
2832 if (result) {
2833 kfree(uc_handle);
2834 uc_handle = NULL;
2835 return result;
2836 }
2837
2838 return 0;
2839}
2840
2841static void sony_nc_usb_charge_cleanup(struct platform_device *pd)
2842{
2843 if (uc_handle) {
2844 device_remove_file(&pd->dev, uc_handle);
2845 kfree(uc_handle);
2846 uc_handle = NULL;
2847 }
2848}
2849
2850/* Panel ID function */
2851static struct device_attribute *panel_handle;
2852
2853static ssize_t sony_nc_panelid_show(struct device *dev,
2854 struct device_attribute *attr, char *buffer)
2855{
2856 unsigned int result;
2857
2858 if (sony_call_snc_handle(0x011D, 0x0000, &result))
2859 return -EIO;
2860
2861 return snprintf(buffer, PAGE_SIZE, "%d\n", result);
2862}
2863
2864static int sony_nc_panelid_setup(struct platform_device *pd)
2865{
2866 unsigned int result;
2867
2868 panel_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2869 if (!panel_handle)
2870 return -ENOMEM;
2871
2872 sysfs_attr_init(&panel_handle->attr);
2873 panel_handle->attr.name = "panel_id";
2874 panel_handle->attr.mode = S_IRUGO;
2875 panel_handle->show = sony_nc_panelid_show;
2876 panel_handle->store = NULL;
2877
2878 result = device_create_file(&pd->dev, panel_handle);
2879 if (result) {
2880 kfree(panel_handle);
2881 panel_handle = NULL;
2882 return result;
2883 }
2884
2885 return 0;
2886}
2887
2888static void sony_nc_panelid_cleanup(struct platform_device *pd)
2889{
2890 if (panel_handle) {
2891 device_remove_file(&pd->dev, panel_handle);
2892 kfree(panel_handle);
2893 panel_handle = NULL;
2894 }
2895}
2896
2897/* smart connect function */
2898static struct device_attribute *sc_handle;
2899
2900static ssize_t sony_nc_smart_conn_store(struct device *dev,
2901 struct device_attribute *attr,
2902 const char *buffer, size_t count)
2903{
2904 unsigned int result;
2905 unsigned long value;
2906
2907 if (count > 31)
2908 return -EINVAL;
2909
2910 if (kstrtoul(buffer, 10, &value) || value > 1)
2911 return -EINVAL;
2912
2913 if (sony_call_snc_handle(0x0168, value << 0x10, &result))
2914 return -EIO;
2915
2916 return count;
2917}
2918
2919static int sony_nc_smart_conn_setup(struct platform_device *pd)
2920{
2921 unsigned int result;
2922
2923 sc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2924 if (!sc_handle)
2925 return -ENOMEM;
2926
2927 sysfs_attr_init(&sc_handle->attr);
2928 sc_handle->attr.name = "smart_connect";
2929 sc_handle->attr.mode = S_IWUSR;
2930 sc_handle->show = NULL;
2931 sc_handle->store = sony_nc_smart_conn_store;
2932
2933 result = device_create_file(&pd->dev, sc_handle);
2934 if (result) {
2935 kfree(sc_handle);
2936 sc_handle = NULL;
2937 return result;
2938 }
2939
2940 return 0;
2941}
2942
2943static void sony_nc_smart_conn_cleanup(struct platform_device *pd)
2944{
2945 if (sc_handle) {
2946 device_remove_file(&pd->dev, sc_handle);
2947 kfree(sc_handle);
2948 sc_handle = NULL;
2949 }
2950}
2951
2527/* Touchpad enable/disable */ 2952/* Touchpad enable/disable */
2528struct touchpad_control { 2953struct touchpad_control {
2529 struct device_attribute attr; 2954 struct device_attribute attr;
@@ -2726,8 +3151,6 @@ static int sony_nc_add(struct acpi_device *device)
2726 int result = 0; 3151 int result = 0;
2727 struct sony_nc_value *item; 3152 struct sony_nc_value *item;
2728 3153
2729 pr_info("%s v%s\n", SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
2730
2731 sony_nc_acpi_device = device; 3154 sony_nc_acpi_device = device;
2732 strcpy(acpi_device_class(device), "sony/hotkey"); 3155 strcpy(acpi_device_class(device), "sony/hotkey");
2733 3156
@@ -2821,6 +3244,7 @@ static int sony_nc_add(struct acpi_device *device)
2821 } 3244 }
2822 } 3245 }
2823 3246
3247 pr_info("SNC setup done.\n");
2824 return 0; 3248 return 0;
2825 3249
2826out_sysfs: 3250out_sysfs:
@@ -4259,8 +4683,6 @@ static int sony_pic_add(struct acpi_device *device)
4259 struct sony_pic_ioport *io, *tmp_io; 4683 struct sony_pic_ioport *io, *tmp_io;
4260 struct sony_pic_irq *irq, *tmp_irq; 4684 struct sony_pic_irq *irq, *tmp_irq;
4261 4685
4262 pr_info("%s v%s\n", SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
4263
4264 spic_dev.acpi_dev = device; 4686 spic_dev.acpi_dev = device;
4265 strcpy(acpi_device_class(device), "sony/hotkey"); 4687 strcpy(acpi_device_class(device), "sony/hotkey");
4266 sony_pic_detect_device_type(&spic_dev); 4688 sony_pic_detect_device_type(&spic_dev);
@@ -4360,6 +4782,7 @@ static int sony_pic_add(struct acpi_device *device)
4360 if (result) 4782 if (result)
4361 goto err_remove_pf; 4783 goto err_remove_pf;
4362 4784
4785 pr_info("SPIC setup done.\n");
4363 return 0; 4786 return 0;
4364 4787
4365err_remove_pf: 4788err_remove_pf:
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 94bb6157c957..15e61c16736e 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -2321,53 +2321,55 @@ static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m)
2321 } 2321 }
2322} 2322}
2323 2323
2324static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
2325 struct tp_nvram_state *newn,
2326 const u32 event_mask)
2327{
2328
2329#define TPACPI_COMPARE_KEY(__scancode, __member) \ 2324#define TPACPI_COMPARE_KEY(__scancode, __member) \
2330 do { \ 2325do { \
2331 if ((event_mask & (1 << __scancode)) && \ 2326 if ((event_mask & (1 << __scancode)) && \
2332 oldn->__member != newn->__member) \ 2327 oldn->__member != newn->__member) \
2333 tpacpi_hotkey_send_key(__scancode); \ 2328 tpacpi_hotkey_send_key(__scancode); \
2334 } while (0) 2329} while (0)
2335 2330
2336#define TPACPI_MAY_SEND_KEY(__scancode) \ 2331#define TPACPI_MAY_SEND_KEY(__scancode) \
2337 do { \ 2332do { \
2338 if (event_mask & (1 << __scancode)) \ 2333 if (event_mask & (1 << __scancode)) \
2339 tpacpi_hotkey_send_key(__scancode); \ 2334 tpacpi_hotkey_send_key(__scancode); \
2340 } while (0) 2335} while (0)
2341 2336
2342 void issue_volchange(const unsigned int oldvol, 2337static void issue_volchange(const unsigned int oldvol,
2343 const unsigned int newvol) 2338 const unsigned int newvol,
2344 { 2339 const u32 event_mask)
2345 unsigned int i = oldvol; 2340{
2341 unsigned int i = oldvol;
2346 2342
2347 while (i > newvol) { 2343 while (i > newvol) {
2348 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); 2344 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
2349 i--; 2345 i--;
2350 } 2346 }
2351 while (i < newvol) { 2347 while (i < newvol) {
2352 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); 2348 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
2353 i++; 2349 i++;
2354 }
2355 } 2350 }
2351}
2356 2352
2357 void issue_brightnesschange(const unsigned int oldbrt, 2353static void issue_brightnesschange(const unsigned int oldbrt,
2358 const unsigned int newbrt) 2354 const unsigned int newbrt,
2359 { 2355 const u32 event_mask)
2360 unsigned int i = oldbrt; 2356{
2357 unsigned int i = oldbrt;
2361 2358
2362 while (i > newbrt) { 2359 while (i > newbrt) {
2363 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); 2360 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
2364 i--; 2361 i--;
2365 }
2366 while (i < newbrt) {
2367 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
2368 i++;
2369 }
2370 } 2362 }
2363 while (i < newbrt) {
2364 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
2365 i++;
2366 }
2367}
2368
2369static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
2370 struct tp_nvram_state *newn,
2371 const u32 event_mask)
2372{
2371 2373
2372 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); 2374 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle);
2373 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); 2375 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle);
@@ -2402,7 +2404,8 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
2402 oldn->volume_level != newn->volume_level) { 2404 oldn->volume_level != newn->volume_level) {
2403 /* recently muted, or repeated mute keypress, or 2405 /* recently muted, or repeated mute keypress, or
2404 * multiple presses ending in mute */ 2406 * multiple presses ending in mute */
2405 issue_volchange(oldn->volume_level, newn->volume_level); 2407 issue_volchange(oldn->volume_level, newn->volume_level,
2408 event_mask);
2406 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); 2409 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
2407 } 2410 }
2408 } else { 2411 } else {
@@ -2412,7 +2415,8 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
2412 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); 2415 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
2413 } 2416 }
2414 if (oldn->volume_level != newn->volume_level) { 2417 if (oldn->volume_level != newn->volume_level) {
2415 issue_volchange(oldn->volume_level, newn->volume_level); 2418 issue_volchange(oldn->volume_level, newn->volume_level,
2419 event_mask);
2416 } else if (oldn->volume_toggle != newn->volume_toggle) { 2420 } else if (oldn->volume_toggle != newn->volume_toggle) {
2417 /* repeated vol up/down keypress at end of scale ? */ 2421 /* repeated vol up/down keypress at end of scale ? */
2418 if (newn->volume_level == 0) 2422 if (newn->volume_level == 0)
@@ -2425,7 +2429,7 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
2425 /* handle brightness */ 2429 /* handle brightness */
2426 if (oldn->brightness_level != newn->brightness_level) { 2430 if (oldn->brightness_level != newn->brightness_level) {
2427 issue_brightnesschange(oldn->brightness_level, 2431 issue_brightnesschange(oldn->brightness_level,
2428 newn->brightness_level); 2432 newn->brightness_level, event_mask);
2429 } else if (oldn->brightness_toggle != newn->brightness_toggle) { 2433 } else if (oldn->brightness_toggle != newn->brightness_toggle) {
2430 /* repeated key presses that didn't change state */ 2434 /* repeated key presses that didn't change state */
2431 if (newn->brightness_level == 0) 2435 if (newn->brightness_level == 0)
@@ -3437,6 +3441,106 @@ err_exit:
3437 return (res < 0)? res : 1; 3441 return (res < 0)? res : 1;
3438} 3442}
3439 3443
3444/* Thinkpad X1 Carbon support 5 modes including Home mode, Web browser
3445 * mode, Web conference mode, Function mode and Lay-flat mode.
3446 * We support Home mode and Function mode currently.
3447 *
3448 * Will consider support rest of modes in future.
3449 *
3450 */
3451enum ADAPTIVE_KEY_MODE {
3452 HOME_MODE,
3453 WEB_BROWSER_MODE,
3454 WEB_CONFERENCE_MODE,
3455 FUNCTION_MODE,
3456 LAYFLAT_MODE
3457};
3458
3459const int adaptive_keyboard_modes[] = {
3460 HOME_MODE,
3461/* WEB_BROWSER_MODE = 2,
3462 WEB_CONFERENCE_MODE = 3, */
3463 FUNCTION_MODE
3464};
3465
3466#define DFR_CHANGE_ROW 0x101
3467#define DFR_SHOW_QUICKVIEW_ROW 0x102
3468
3469/* press Fn key a while second, it will switch to Function Mode. Then
3470 * release Fn key, previous mode be restored.
3471 */
3472static bool adaptive_keyboard_mode_is_saved;
3473static int adaptive_keyboard_prev_mode;
3474
3475static int adaptive_keyboard_get_next_mode(int mode)
3476{
3477 size_t i;
3478 size_t max_mode = ARRAY_SIZE(adaptive_keyboard_modes) - 1;
3479
3480 for (i = 0; i <= max_mode; i++) {
3481 if (adaptive_keyboard_modes[i] == mode)
3482 break;
3483 }
3484
3485 if (i >= max_mode)
3486 i = 0;
3487 else
3488 i++;
3489
3490 return adaptive_keyboard_modes[i];
3491}
3492
3493static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode)
3494{
3495 u32 current_mode = 0;
3496 int new_mode = 0;
3497
3498 switch (scancode) {
3499 case DFR_CHANGE_ROW:
3500 if (adaptive_keyboard_mode_is_saved) {
3501 new_mode = adaptive_keyboard_prev_mode;
3502 adaptive_keyboard_mode_is_saved = false;
3503 } else {
3504 if (!acpi_evalf(
3505 hkey_handle, &current_mode,
3506 "GTRW", "dd", 0)) {
3507 pr_err("Cannot read adaptive keyboard mode\n");
3508 return false;
3509 } else {
3510 new_mode = adaptive_keyboard_get_next_mode(
3511 current_mode);
3512 }
3513 }
3514
3515 if (!acpi_evalf(hkey_handle, NULL, "STRW", "vd", new_mode)) {
3516 pr_err("Cannot set adaptive keyboard mode\n");
3517 return false;
3518 }
3519
3520 return true;
3521
3522 case DFR_SHOW_QUICKVIEW_ROW:
3523 if (!acpi_evalf(hkey_handle,
3524 &adaptive_keyboard_prev_mode,
3525 "GTRW", "dd", 0)) {
3526 pr_err("Cannot read adaptive keyboard mode\n");
3527 return false;
3528 } else {
3529 adaptive_keyboard_mode_is_saved = true;
3530
3531 if (!acpi_evalf(hkey_handle,
3532 NULL, "STRW", "vd", FUNCTION_MODE)) {
3533 pr_err("Cannot set adaptive keyboard mode\n");
3534 return false;
3535 }
3536 }
3537 return true;
3538
3539 default:
3540 return false;
3541 }
3542}
3543
3440static bool hotkey_notify_hotkey(const u32 hkey, 3544static bool hotkey_notify_hotkey(const u32 hkey,
3441 bool *send_acpi_ev, 3545 bool *send_acpi_ev,
3442 bool *ignore_acpi_ev) 3546 bool *ignore_acpi_ev)
@@ -3456,6 +3560,8 @@ static bool hotkey_notify_hotkey(const u32 hkey,
3456 *ignore_acpi_ev = true; 3560 *ignore_acpi_ev = true;
3457 } 3561 }
3458 return true; 3562 return true;
3563 } else {
3564 return adaptive_keyboard_hotkey_notify_hotkey(scancode);
3459 } 3565 }
3460 return false; 3566 return false;
3461} 3567}
@@ -3728,13 +3834,28 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
3728 3834
3729static void hotkey_suspend(void) 3835static void hotkey_suspend(void)
3730{ 3836{
3837 int hkeyv;
3838
3731 /* Do these on suspend, we get the events on early resume! */ 3839 /* Do these on suspend, we get the events on early resume! */
3732 hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE; 3840 hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
3733 hotkey_autosleep_ack = 0; 3841 hotkey_autosleep_ack = 0;
3842
3843 /* save previous mode of adaptive keyboard of X1 Carbon */
3844 if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
3845 if ((hkeyv >> 8) == 2) {
3846 if (!acpi_evalf(hkey_handle,
3847 &adaptive_keyboard_prev_mode,
3848 "GTRW", "dd", 0)) {
3849 pr_err("Cannot read adaptive keyboard mode.\n");
3850 }
3851 }
3852 }
3734} 3853}
3735 3854
3736static void hotkey_resume(void) 3855static void hotkey_resume(void)
3737{ 3856{
3857 int hkeyv;
3858
3738 tpacpi_disable_brightness_delay(); 3859 tpacpi_disable_brightness_delay();
3739 3860
3740 if (hotkey_status_set(true) < 0 || 3861 if (hotkey_status_set(true) < 0 ||
@@ -3747,6 +3868,18 @@ static void hotkey_resume(void)
3747 hotkey_wakeup_reason_notify_change(); 3868 hotkey_wakeup_reason_notify_change();
3748 hotkey_wakeup_hotunplug_complete_notify_change(); 3869 hotkey_wakeup_hotunplug_complete_notify_change();
3749 hotkey_poll_setup_safe(false); 3870 hotkey_poll_setup_safe(false);
3871
3872 /* restore previous mode of adapive keyboard of X1 Carbon */
3873 if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
3874 if ((hkeyv >> 8) == 2) {
3875 if (!acpi_evalf(hkey_handle,
3876 NULL,
3877 "STRW", "vd",
3878 adaptive_keyboard_prev_mode)) {
3879 pr_err("Cannot set adaptive keyboard mode.\n");
3880 }
3881 }
3882 }
3750} 3883}
3751 3884
3752/* procfs -------------------------------------------------------------- */ 3885/* procfs -------------------------------------------------------------- */
@@ -8447,9 +8580,21 @@ static void mute_led_exit(void)
8447 tpacpi_led_set(i, false); 8580 tpacpi_led_set(i, false);
8448} 8581}
8449 8582
8583static void mute_led_resume(void)
8584{
8585 int i;
8586
8587 for (i = 0; i < TPACPI_LED_MAX; i++) {
8588 struct tp_led_table *t = &led_tables[i];
8589 if (t->state >= 0)
8590 mute_led_on_off(t, t->state);
8591 }
8592}
8593
8450static struct ibm_struct mute_led_driver_data = { 8594static struct ibm_struct mute_led_driver_data = {
8451 .name = "mute_led", 8595 .name = "mute_led",
8452 .exit = mute_led_exit, 8596 .exit = mute_led_exit,
8597 .resume = mute_led_resume,
8453}; 8598};
8454 8599
8455/**************************************************************************** 8600/****************************************************************************
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 90dd7645a9e5..46473ca7566b 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -5,6 +5,7 @@
5 * Copyright (C) 2002-2004 John Belmonte 5 * Copyright (C) 2002-2004 John Belmonte
6 * Copyright (C) 2008 Philip Langdale 6 * Copyright (C) 2008 Philip Langdale
7 * Copyright (C) 2010 Pierre Ducroquet 7 * Copyright (C) 2010 Pierre Ducroquet
8 * Copyright (C) 2014 Azael Avalos
8 * 9 *
9 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 11 * it under the terms of the GNU General Public License as published by
@@ -37,7 +38,7 @@
37 38
38#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 39#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
39 40
40#define TOSHIBA_ACPI_VERSION "0.19" 41#define TOSHIBA_ACPI_VERSION "0.20"
41#define PROC_INTERFACE_VERSION 1 42#define PROC_INTERFACE_VERSION 1
42 43
43#include <linux/kernel.h> 44#include <linux/kernel.h>
@@ -77,6 +78,9 @@ MODULE_LICENSE("GPL");
77 * However the ACPI methods seem to be incomplete in some areas (for 78 * However the ACPI methods seem to be incomplete in some areas (for
78 * example they allow setting, but not reading, the LCD brightness value), 79 * example they allow setting, but not reading, the LCD brightness value),
79 * so this is still useful. 80 * so this is still useful.
81 *
82 * SCI stands for "System Configuration Interface" which aim is to
83 * conceal differences in hardware between different models.
80 */ 84 */
81 85
82#define HCI_WORDS 6 86#define HCI_WORDS 6
@@ -84,12 +88,23 @@ MODULE_LICENSE("GPL");
84/* operations */ 88/* operations */
85#define HCI_SET 0xff00 89#define HCI_SET 0xff00
86#define HCI_GET 0xfe00 90#define HCI_GET 0xfe00
91#define SCI_OPEN 0xf100
92#define SCI_CLOSE 0xf200
93#define SCI_GET 0xf300
94#define SCI_SET 0xf400
87 95
88/* return codes */ 96/* return codes */
89#define HCI_SUCCESS 0x0000 97#define HCI_SUCCESS 0x0000
90#define HCI_FAILURE 0x1000 98#define HCI_FAILURE 0x1000
91#define HCI_NOT_SUPPORTED 0x8000 99#define HCI_NOT_SUPPORTED 0x8000
92#define HCI_EMPTY 0x8c00 100#define HCI_EMPTY 0x8c00
101#define HCI_DATA_NOT_AVAILABLE 0x8d20
102#define HCI_NOT_INITIALIZED 0x8d50
103#define SCI_OPEN_CLOSE_OK 0x0044
104#define SCI_ALREADY_OPEN 0x8100
105#define SCI_NOT_OPENED 0x8200
106#define SCI_INPUT_DATA_ERROR 0x8300
107#define SCI_NOT_PRESENT 0x8600
93 108
94/* registers */ 109/* registers */
95#define HCI_FAN 0x0004 110#define HCI_FAN 0x0004
@@ -99,13 +114,22 @@ MODULE_LICENSE("GPL");
99#define HCI_HOTKEY_EVENT 0x001e 114#define HCI_HOTKEY_EVENT 0x001e
100#define HCI_LCD_BRIGHTNESS 0x002a 115#define HCI_LCD_BRIGHTNESS 0x002a
101#define HCI_WIRELESS 0x0056 116#define HCI_WIRELESS 0x0056
117#define HCI_ACCELEROMETER 0x006d
118#define HCI_KBD_ILLUMINATION 0x0095
119#define HCI_ECO_MODE 0x0097
120#define HCI_ACCELEROMETER2 0x00a6
121#define SCI_ILLUMINATION 0x014e
122#define SCI_KBD_ILLUM_STATUS 0x015c
123#define SCI_TOUCHPAD 0x050e
102 124
103/* field definitions */ 125/* field definitions */
126#define HCI_ACCEL_MASK 0x7fff
104#define HCI_HOTKEY_DISABLE 0x0b 127#define HCI_HOTKEY_DISABLE 0x0b
105#define HCI_HOTKEY_ENABLE 0x09 128#define HCI_HOTKEY_ENABLE 0x09
106#define HCI_LCD_BRIGHTNESS_BITS 3 129#define HCI_LCD_BRIGHTNESS_BITS 3
107#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 130#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
108#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 131#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
132#define HCI_MISC_SHIFT 0x10
109#define HCI_VIDEO_OUT_LCD 0x1 133#define HCI_VIDEO_OUT_LCD 0x1
110#define HCI_VIDEO_OUT_CRT 0x2 134#define HCI_VIDEO_OUT_CRT 0x2
111#define HCI_VIDEO_OUT_TV 0x4 135#define HCI_VIDEO_OUT_TV 0x4
@@ -113,6 +137,8 @@ MODULE_LICENSE("GPL");
113#define HCI_WIRELESS_BT_PRESENT 0x0f 137#define HCI_WIRELESS_BT_PRESENT 0x0f
114#define HCI_WIRELESS_BT_ATTACH 0x40 138#define HCI_WIRELESS_BT_ATTACH 0x40
115#define HCI_WIRELESS_BT_POWER 0x80 139#define HCI_WIRELESS_BT_POWER 0x80
140#define SCI_KBD_MODE_FNZ 0x1
141#define SCI_KBD_MODE_AUTO 0x2
116 142
117struct toshiba_acpi_dev { 143struct toshiba_acpi_dev {
118 struct acpi_device *acpi_dev; 144 struct acpi_device *acpi_dev;
@@ -122,10 +148,14 @@ struct toshiba_acpi_dev {
122 struct work_struct hotkey_work; 148 struct work_struct hotkey_work;
123 struct backlight_device *backlight_dev; 149 struct backlight_device *backlight_dev;
124 struct led_classdev led_dev; 150 struct led_classdev led_dev;
151 struct led_classdev kbd_led;
152 struct led_classdev eco_led;
125 153
126 int force_fan; 154 int force_fan;
127 int last_key_event; 155 int last_key_event;
128 int key_event_valid; 156 int key_event_valid;
157 int kbd_mode;
158 int kbd_time;
129 159
130 unsigned int illumination_supported:1; 160 unsigned int illumination_supported:1;
131 unsigned int video_supported:1; 161 unsigned int video_supported:1;
@@ -134,6 +164,12 @@ struct toshiba_acpi_dev {
134 unsigned int ntfy_supported:1; 164 unsigned int ntfy_supported:1;
135 unsigned int info_supported:1; 165 unsigned int info_supported:1;
136 unsigned int tr_backlight_supported:1; 166 unsigned int tr_backlight_supported:1;
167 unsigned int kbd_illum_supported:1;
168 unsigned int kbd_led_registered:1;
169 unsigned int touchpad_supported:1;
170 unsigned int eco_supported:1;
171 unsigned int accelerometer_supported:1;
172 unsigned int sysfs_created:1;
137 173
138 struct mutex mutex; 174 struct mutex mutex;
139}; 175};
@@ -280,21 +316,94 @@ static acpi_status hci_read2(struct toshiba_acpi_dev *dev, u32 reg,
280 return status; 316 return status;
281} 317}
282 318
319/* common sci tasks
320 */
321
322static int sci_open(struct toshiba_acpi_dev *dev)
323{
324 u32 in[HCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
325 u32 out[HCI_WORDS];
326 acpi_status status;
327
328 status = hci_raw(dev, in, out);
329 if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
330 pr_err("ACPI call to open SCI failed\n");
331 return 0;
332 }
333
334 if (out[0] == SCI_OPEN_CLOSE_OK) {
335 return 1;
336 } else if (out[0] == SCI_ALREADY_OPEN) {
337 pr_info("Toshiba SCI already opened\n");
338 return 1;
339 } else if (out[0] == SCI_NOT_PRESENT) {
340 pr_info("Toshiba SCI is not present\n");
341 }
342
343 return 0;
344}
345
346static void sci_close(struct toshiba_acpi_dev *dev)
347{
348 u32 in[HCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
349 u32 out[HCI_WORDS];
350 acpi_status status;
351
352 status = hci_raw(dev, in, out);
353 if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
354 pr_err("ACPI call to close SCI failed\n");
355 return;
356 }
357
358 if (out[0] == SCI_OPEN_CLOSE_OK)
359 return;
360 else if (out[0] == SCI_NOT_OPENED)
361 pr_info("Toshiba SCI not opened\n");
362 else if (out[0] == SCI_NOT_PRESENT)
363 pr_info("Toshiba SCI is not present\n");
364}
365
366static acpi_status sci_read(struct toshiba_acpi_dev *dev, u32 reg,
367 u32 *out1, u32 *result)
368{
369 u32 in[HCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
370 u32 out[HCI_WORDS];
371 acpi_status status = hci_raw(dev, in, out);
372 *out1 = out[2];
373 *result = (ACPI_SUCCESS(status)) ? out[0] : HCI_FAILURE;
374 return status;
375}
376
377static acpi_status sci_write(struct toshiba_acpi_dev *dev, u32 reg,
378 u32 in1, u32 *result)
379{
380 u32 in[HCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
381 u32 out[HCI_WORDS];
382 acpi_status status = hci_raw(dev, in, out);
383 *result = (ACPI_SUCCESS(status)) ? out[0] : HCI_FAILURE;
384 return status;
385}
386
283/* Illumination support */ 387/* Illumination support */
284static int toshiba_illumination_available(struct toshiba_acpi_dev *dev) 388static int toshiba_illumination_available(struct toshiba_acpi_dev *dev)
285{ 389{
286 u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; 390 u32 in[HCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
287 u32 out[HCI_WORDS]; 391 u32 out[HCI_WORDS];
288 acpi_status status; 392 acpi_status status;
289 393
290 in[0] = 0xf100; 394 if (!sci_open(dev))
395 return 0;
396
291 status = hci_raw(dev, in, out); 397 status = hci_raw(dev, in, out);
292 if (ACPI_FAILURE(status)) { 398 sci_close(dev);
399 if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
400 pr_err("ACPI call to query Illumination support failed\n");
401 return 0;
402 } else if (out[0] == HCI_NOT_SUPPORTED || out[1] != 1) {
293 pr_info("Illumination device not available\n"); 403 pr_info("Illumination device not available\n");
294 return 0; 404 return 0;
295 } 405 }
296 in[0] = 0xf400; 406
297 status = hci_raw(dev, in, out);
298 return 1; 407 return 1;
299} 408}
300 409
@@ -303,82 +412,270 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
303{ 412{
304 struct toshiba_acpi_dev *dev = container_of(cdev, 413 struct toshiba_acpi_dev *dev = container_of(cdev,
305 struct toshiba_acpi_dev, led_dev); 414 struct toshiba_acpi_dev, led_dev);
306 u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; 415 u32 state, result;
307 u32 out[HCI_WORDS];
308 acpi_status status; 416 acpi_status status;
309 417
310 /* First request : initialize communication. */ 418 /* First request : initialize communication. */
311 in[0] = 0xf100; 419 if (!sci_open(dev))
312 status = hci_raw(dev, in, out); 420 return;
421
422 /* Switch the illumination on/off */
423 state = brightness ? 1 : 0;
424 status = sci_write(dev, SCI_ILLUMINATION, state, &result);
425 sci_close(dev);
313 if (ACPI_FAILURE(status)) { 426 if (ACPI_FAILURE(status)) {
314 pr_info("Illumination device not available\n"); 427 pr_err("ACPI call for illumination failed\n");
428 return;
429 } else if (result == HCI_NOT_SUPPORTED) {
430 pr_info("Illumination not supported\n");
315 return; 431 return;
316 } 432 }
433}
317 434
318 if (brightness) { 435static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
319 /* Switch the illumination on */ 436{
320 in[0] = 0xf400; 437 struct toshiba_acpi_dev *dev = container_of(cdev,
321 in[1] = 0x14e; 438 struct toshiba_acpi_dev, led_dev);
322 in[2] = 1; 439 u32 state, result;
323 status = hci_raw(dev, in, out); 440 acpi_status status;
324 if (ACPI_FAILURE(status)) { 441
325 pr_info("ACPI call for illumination failed\n"); 442 /* First request : initialize communication. */
326 return; 443 if (!sci_open(dev))
327 } 444 return LED_OFF;
328 } else { 445
329 /* Switch the illumination off */ 446 /* Check the illumination */
330 in[0] = 0xf400; 447 status = sci_read(dev, SCI_ILLUMINATION, &state, &result);
331 in[1] = 0x14e; 448 sci_close(dev);
332 in[2] = 0; 449 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
333 status = hci_raw(dev, in, out); 450 pr_err("ACPI call for illumination failed\n");
334 if (ACPI_FAILURE(status)) { 451 return LED_OFF;
335 pr_info("ACPI call for illumination failed.\n"); 452 } else if (result == HCI_NOT_SUPPORTED) {
336 return; 453 pr_info("Illumination not supported\n");
337 } 454 return LED_OFF;
338 } 455 }
339 456
340 /* Last request : close communication. */ 457 return state ? LED_FULL : LED_OFF;
341 in[0] = 0xf200;
342 in[1] = 0;
343 in[2] = 0;
344 hci_raw(dev, in, out);
345} 458}
346 459
347static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 460/* KBD Illumination */
461static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
462{
463 u32 result;
464 acpi_status status;
465
466 if (!sci_open(dev))
467 return -EIO;
468
469 status = sci_write(dev, SCI_KBD_ILLUM_STATUS, time, &result);
470 sci_close(dev);
471 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
472 pr_err("ACPI call to set KBD backlight status failed\n");
473 return -EIO;
474 } else if (result == HCI_NOT_SUPPORTED) {
475 pr_info("Keyboard backlight status not supported\n");
476 return -ENODEV;
477 }
478
479 return 0;
480}
481
482static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
483{
484 u32 result;
485 acpi_status status;
486
487 if (!sci_open(dev))
488 return -EIO;
489
490 status = sci_read(dev, SCI_KBD_ILLUM_STATUS, time, &result);
491 sci_close(dev);
492 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
493 pr_err("ACPI call to get KBD backlight status failed\n");
494 return -EIO;
495 } else if (result == HCI_NOT_SUPPORTED) {
496 pr_info("Keyboard backlight status not supported\n");
497 return -ENODEV;
498 }
499
500 return 0;
501}
502
503static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
348{ 504{
349 struct toshiba_acpi_dev *dev = container_of(cdev, 505 struct toshiba_acpi_dev *dev = container_of(cdev,
350 struct toshiba_acpi_dev, led_dev); 506 struct toshiba_acpi_dev, kbd_led);
351 u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; 507 u32 state, result;
508 acpi_status status;
509
510 /* Check the keyboard backlight state */
511 status = hci_read1(dev, HCI_KBD_ILLUMINATION, &state, &result);
512 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
513 pr_err("ACPI call to get the keyboard backlight failed\n");
514 return LED_OFF;
515 } else if (result == HCI_NOT_SUPPORTED) {
516 pr_info("Keyboard backlight not supported\n");
517 return LED_OFF;
518 }
519
520 return state ? LED_FULL : LED_OFF;
521}
522
523static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
524 enum led_brightness brightness)
525{
526 struct toshiba_acpi_dev *dev = container_of(cdev,
527 struct toshiba_acpi_dev, kbd_led);
528 u32 state, result;
529 acpi_status status;
530
531 /* Set the keyboard backlight state */
532 state = brightness ? 1 : 0;
533 status = hci_write1(dev, HCI_KBD_ILLUMINATION, state, &result);
534 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
535 pr_err("ACPI call to set KBD Illumination mode failed\n");
536 return;
537 } else if (result == HCI_NOT_SUPPORTED) {
538 pr_info("Keyboard backlight not supported\n");
539 return;
540 }
541}
542
543/* TouchPad support */
544static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
545{
546 u32 result;
547 acpi_status status;
548
549 if (!sci_open(dev))
550 return -EIO;
551
552 status = sci_write(dev, SCI_TOUCHPAD, state, &result);
553 sci_close(dev);
554 if (ACPI_FAILURE(status)) {
555 pr_err("ACPI call to set the touchpad failed\n");
556 return -EIO;
557 } else if (result == HCI_NOT_SUPPORTED) {
558 return -ENODEV;
559 }
560
561 return 0;
562}
563
564static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
565{
566 u32 result;
567 acpi_status status;
568
569 if (!sci_open(dev))
570 return -EIO;
571
572 status = sci_read(dev, SCI_TOUCHPAD, state, &result);
573 sci_close(dev);
574 if (ACPI_FAILURE(status)) {
575 pr_err("ACPI call to query the touchpad failed\n");
576 return -EIO;
577 } else if (result == HCI_NOT_SUPPORTED) {
578 return -ENODEV;
579 }
580
581 return 0;
582}
583
584/* Eco Mode support */
585static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
586{
587 acpi_status status;
588 u32 in[HCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
589 u32 out[HCI_WORDS];
590
591 status = hci_raw(dev, in, out);
592 if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
593 pr_info("ACPI call to get ECO led failed\n");
594 return 0;
595 }
596
597 return 1;
598}
599
600static enum led_brightness toshiba_eco_mode_get_status(struct led_classdev *cdev)
601{
602 struct toshiba_acpi_dev *dev = container_of(cdev,
603 struct toshiba_acpi_dev, eco_led);
604 u32 in[HCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
352 u32 out[HCI_WORDS]; 605 u32 out[HCI_WORDS];
353 acpi_status status; 606 acpi_status status;
354 enum led_brightness result;
355 607
356 /* First request : initialize communication. */
357 in[0] = 0xf100;
358 status = hci_raw(dev, in, out); 608 status = hci_raw(dev, in, out);
359 if (ACPI_FAILURE(status)) { 609 if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
360 pr_info("Illumination device not available\n"); 610 pr_err("ACPI call to get ECO led failed\n");
361 return LED_OFF; 611 return LED_OFF;
362 } 612 }
363 613
364 /* Check the illumination */ 614 return out[2] ? LED_FULL : LED_OFF;
365 in[0] = 0xf300; 615}
366 in[1] = 0x14e; 616
617static void toshiba_eco_mode_set_status(struct led_classdev *cdev,
618 enum led_brightness brightness)
619{
620 struct toshiba_acpi_dev *dev = container_of(cdev,
621 struct toshiba_acpi_dev, eco_led);
622 u32 in[HCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 };
623 u32 out[HCI_WORDS];
624 acpi_status status;
625
626 /* Switch the Eco Mode led on/off */
627 in[2] = (brightness) ? 1 : 0;
367 status = hci_raw(dev, in, out); 628 status = hci_raw(dev, in, out);
368 if (ACPI_FAILURE(status)) { 629 if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
369 pr_info("ACPI call for illumination failed.\n"); 630 pr_err("ACPI call to set ECO led failed\n");
370 return LED_OFF; 631 return;
371 } 632 }
633}
372 634
373 result = out[2] ? LED_FULL : LED_OFF; 635/* Accelerometer support */
636static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev)
637{
638 u32 in[HCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
639 u32 out[HCI_WORDS];
640 acpi_status status;
641
642 /* Check if the accelerometer call exists,
643 * this call also serves as initialization
644 */
645 status = hci_raw(dev, in, out);
646 if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
647 pr_err("ACPI call to query the accelerometer failed\n");
648 return -EIO;
649 } else if (out[0] == HCI_DATA_NOT_AVAILABLE ||
650 out[0] == HCI_NOT_INITIALIZED) {
651 pr_err("Accelerometer not initialized\n");
652 return -EIO;
653 } else if (out[0] == HCI_NOT_SUPPORTED) {
654 pr_info("Accelerometer not supported\n");
655 return -ENODEV;
656 }
657
658 return 0;
659}
660
661static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
662 u32 *xy, u32 *z)
663{
664 u32 in[HCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
665 u32 out[HCI_WORDS];
666 acpi_status status;
667
668 /* Check the Accelerometer status */
669 status = hci_raw(dev, in, out);
670 if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
671 pr_err("ACPI call to query the accelerometer failed\n");
672 return -EIO;
673 }
374 674
375 /* Last request : close communication. */ 675 *xy = out[2];
376 in[0] = 0xf200; 676 *z = out[4];
377 in[1] = 0;
378 in[2] = 0;
379 hci_raw(dev, in, out);
380 677
381 return result; 678 return 0;
382} 679}
383 680
384/* Bluetooth rfkill handlers */ 681/* Bluetooth rfkill handlers */
@@ -904,6 +1201,177 @@ static const struct backlight_ops toshiba_backlight_data = {
904 .update_status = set_lcd_status, 1201 .update_status = set_lcd_status,
905}; 1202};
906 1203
1204/*
1205 * Sysfs files
1206 */
1207
1208static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
1209 struct device_attribute *attr,
1210 const char *buf, size_t count)
1211{
1212 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1213 int mode = -1;
1214 int time = -1;
1215
1216 if (sscanf(buf, "%i", &mode) != 1 && (mode != 2 || mode != 1))
1217 return -EINVAL;
1218
1219 /* Set the Keyboard Backlight Mode where:
1220 * Mode - Auto (2) | FN-Z (1)
1221 * Auto - KBD backlight turns off automatically in given time
1222 * FN-Z - KBD backlight "toggles" when hotkey pressed
1223 */
1224 if (mode != -1 && toshiba->kbd_mode != mode) {
1225 time = toshiba->kbd_time << HCI_MISC_SHIFT;
1226 time = time + toshiba->kbd_mode;
1227 if (toshiba_kbd_illum_status_set(toshiba, time) < 0)
1228 return -EIO;
1229 toshiba->kbd_mode = mode;
1230 }
1231
1232 return count;
1233}
1234
1235static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
1236 struct device_attribute *attr,
1237 char *buf)
1238{
1239 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1240 u32 time;
1241
1242 if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1243 return -EIO;
1244
1245 return sprintf(buf, "%i\n", time & 0x07);
1246}
1247
1248static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
1249 struct device_attribute *attr,
1250 const char *buf, size_t count)
1251{
1252 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1253 int time = -1;
1254
1255 if (sscanf(buf, "%i", &time) != 1 && (time < 0 || time > 60))
1256 return -EINVAL;
1257
1258 /* Set the Keyboard Backlight Timeout: 0-60 seconds */
1259 if (time != -1 && toshiba->kbd_time != time) {
1260 time = time << HCI_MISC_SHIFT;
1261 time = (toshiba->kbd_mode == SCI_KBD_MODE_AUTO) ?
1262 time + 1 : time + 2;
1263 if (toshiba_kbd_illum_status_set(toshiba, time) < 0)
1264 return -EIO;
1265 toshiba->kbd_time = time >> HCI_MISC_SHIFT;
1266 }
1267
1268 return count;
1269}
1270
1271static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
1272 struct device_attribute *attr,
1273 char *buf)
1274{
1275 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1276 u32 time;
1277
1278 if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1279 return -EIO;
1280
1281 return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
1282}
1283
1284static ssize_t toshiba_touchpad_store(struct device *dev,
1285 struct device_attribute *attr,
1286 const char *buf, size_t count)
1287{
1288 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1289 int state;
1290
1291 /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */
1292 if (sscanf(buf, "%i", &state) == 1 && (state == 0 || state == 1)) {
1293 if (toshiba_touchpad_set(toshiba, state) < 0)
1294 return -EIO;
1295 }
1296
1297 return count;
1298}
1299
1300static ssize_t toshiba_touchpad_show(struct device *dev,
1301 struct device_attribute *attr, char *buf)
1302{
1303 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1304 u32 state;
1305 int ret;
1306
1307 ret = toshiba_touchpad_get(toshiba, &state);
1308 if (ret < 0)
1309 return ret;
1310
1311 return sprintf(buf, "%i\n", state);
1312}
1313
1314static ssize_t toshiba_position_show(struct device *dev,
1315 struct device_attribute *attr, char *buf)
1316{
1317 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1318 u32 xyval, zval, tmp;
1319 u16 x, y, z;
1320 int ret;
1321
1322 xyval = zval = 0;
1323 ret = toshiba_accelerometer_get(toshiba, &xyval, &zval);
1324 if (ret < 0)
1325 return ret;
1326
1327 x = xyval & HCI_ACCEL_MASK;
1328 tmp = xyval >> HCI_MISC_SHIFT;
1329 y = tmp & HCI_ACCEL_MASK;
1330 z = zval & HCI_ACCEL_MASK;
1331
1332 return sprintf(buf, "%d %d %d\n", x, y, z);
1333}
1334
1335static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
1336 toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
1337static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
1338 toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
1339static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR,
1340 toshiba_touchpad_show, toshiba_touchpad_store);
1341static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL);
1342
1343static struct attribute *toshiba_attributes[] = {
1344 &dev_attr_kbd_backlight_mode.attr,
1345 &dev_attr_kbd_backlight_timeout.attr,
1346 &dev_attr_touchpad.attr,
1347 &dev_attr_position.attr,
1348 NULL,
1349};
1350
1351static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
1352 struct attribute *attr, int idx)
1353{
1354 struct device *dev = container_of(kobj, struct device, kobj);
1355 struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
1356 bool exists = true;
1357
1358 if (attr == &dev_attr_kbd_backlight_mode.attr)
1359 exists = (drv->kbd_illum_supported) ? true : false;
1360 else if (attr == &dev_attr_kbd_backlight_timeout.attr)
1361 exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
1362 else if (attr == &dev_attr_touchpad.attr)
1363 exists = (drv->touchpad_supported) ? true : false;
1364 else if (attr == &dev_attr_position.attr)
1365 exists = (drv->accelerometer_supported) ? true : false;
1366
1367 return exists ? attr->mode : 0;
1368}
1369
1370static struct attribute_group toshiba_attr_group = {
1371 .is_visible = toshiba_sysfs_is_visible,
1372 .attrs = toshiba_attributes,
1373};
1374
907static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 1375static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
908 struct serio *port) 1376 struct serio *port)
909{ 1377{
@@ -1106,6 +1574,10 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
1106 1574
1107 remove_toshiba_proc_entries(dev); 1575 remove_toshiba_proc_entries(dev);
1108 1576
1577 if (dev->sysfs_created)
1578 sysfs_remove_group(&dev->acpi_dev->dev.kobj,
1579 &toshiba_attr_group);
1580
1109 if (dev->ntfy_supported) { 1581 if (dev->ntfy_supported) {
1110 i8042_remove_filter(toshiba_acpi_i8042_filter); 1582 i8042_remove_filter(toshiba_acpi_i8042_filter);
1111 cancel_work_sync(&dev->hotkey_work); 1583 cancel_work_sync(&dev->hotkey_work);
@@ -1127,6 +1599,12 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
1127 if (dev->illumination_supported) 1599 if (dev->illumination_supported)
1128 led_classdev_unregister(&dev->led_dev); 1600 led_classdev_unregister(&dev->led_dev);
1129 1601
1602 if (dev->kbd_led_registered)
1603 led_classdev_unregister(&dev->kbd_led);
1604
1605 if (dev->eco_supported)
1606 led_classdev_unregister(&dev->eco_led);
1607
1130 if (toshiba_acpi) 1608 if (toshiba_acpi)
1131 toshiba_acpi = NULL; 1609 toshiba_acpi = NULL;
1132 1610
@@ -1172,6 +1650,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
1172 dev->acpi_dev = acpi_dev; 1650 dev->acpi_dev = acpi_dev;
1173 dev->method_hci = hci_method; 1651 dev->method_hci = hci_method;
1174 acpi_dev->driver_data = dev; 1652 acpi_dev->driver_data = dev;
1653 dev_set_drvdata(&acpi_dev->dev, dev);
1175 1654
1176 if (toshiba_acpi_setup_keyboard(dev)) 1655 if (toshiba_acpi_setup_keyboard(dev))
1177 pr_info("Unable to activate hotkeys\n"); 1656 pr_info("Unable to activate hotkeys\n");
@@ -1212,6 +1691,40 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
1212 dev->illumination_supported = 1; 1691 dev->illumination_supported = 1;
1213 } 1692 }
1214 1693
1694 if (toshiba_eco_mode_available(dev)) {
1695 dev->eco_led.name = "toshiba::eco_mode";
1696 dev->eco_led.max_brightness = 1;
1697 dev->eco_led.brightness_set = toshiba_eco_mode_set_status;
1698 dev->eco_led.brightness_get = toshiba_eco_mode_get_status;
1699 if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led))
1700 dev->eco_supported = 1;
1701 }
1702
1703 ret = toshiba_kbd_illum_status_get(dev, &dummy);
1704 if (!ret) {
1705 dev->kbd_time = dummy >> HCI_MISC_SHIFT;
1706 dev->kbd_mode = dummy & 0x07;
1707 }
1708 dev->kbd_illum_supported = !ret;
1709 /*
1710 * Only register the LED if KBD illumination is supported
1711 * and the keyboard backlight operation mode is set to FN-Z
1712 */
1713 if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) {
1714 dev->kbd_led.name = "toshiba::kbd_backlight";
1715 dev->kbd_led.max_brightness = 1;
1716 dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
1717 dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
1718 if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led))
1719 dev->kbd_led_registered = 1;
1720 }
1721
1722 ret = toshiba_touchpad_get(dev, &dummy);
1723 dev->touchpad_supported = !ret;
1724
1725 ret = toshiba_accelerometer_supported(dev);
1726 dev->accelerometer_supported = !ret;
1727
1215 /* Determine whether or not BIOS supports fan and video interfaces */ 1728 /* Determine whether or not BIOS supports fan and video interfaces */
1216 1729
1217 ret = get_video_status(dev, &dummy); 1730 ret = get_video_status(dev, &dummy);
@@ -1220,6 +1733,14 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
1220 ret = get_fan_status(dev, &dummy); 1733 ret = get_fan_status(dev, &dummy);
1221 dev->fan_supported = !ret; 1734 dev->fan_supported = !ret;
1222 1735
1736 ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
1737 &toshiba_attr_group);
1738 if (ret) {
1739 dev->sysfs_created = 0;
1740 goto error;
1741 }
1742 dev->sysfs_created = !ret;
1743
1223 create_toshiba_proc_entries(dev); 1744 create_toshiba_proc_entries(dev);
1224 1745
1225 toshiba_acpi = dev; 1746 toshiba_acpi = dev;