diff options
Diffstat (limited to 'drivers/platform/x86/toshiba_acpi.c')
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 635 |
1 files changed, 578 insertions, 57 deletions
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 | ||
117 | struct toshiba_acpi_dev { | 143 | struct 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 | |||
322 | static 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 | |||
346 | static 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 | |||
366 | static 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 | |||
377 | static 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 */ |
284 | static int toshiba_illumination_available(struct toshiba_acpi_dev *dev) | 388 | static 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) { | 435 | static 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 | ||
347 | static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) | 460 | /* KBD Illumination */ |
461 | static 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 | |||
482 | static 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 | |||
503 | static 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 | |||
523 | static 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 */ | ||
544 | static 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 | |||
564 | static 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 */ | ||
585 | static 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 | |||
600 | static 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 | |
617 | static 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 */ |
636 | static 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 | |||
661 | static 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 | |||
1208 | static 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 | |||
1235 | static 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 | |||
1248 | static 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 | |||
1271 | static 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 | |||
1284 | static 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 | |||
1300 | static 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 | |||
1314 | static 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 | |||
1335 | static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR, | ||
1336 | toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store); | ||
1337 | static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR, | ||
1338 | toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store); | ||
1339 | static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR, | ||
1340 | toshiba_touchpad_show, toshiba_touchpad_store); | ||
1341 | static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL); | ||
1342 | |||
1343 | static 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 | |||
1351 | static 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 | |||
1370 | static struct attribute_group toshiba_attr_group = { | ||
1371 | .is_visible = toshiba_sysfs_is_visible, | ||
1372 | .attrs = toshiba_attributes, | ||
1373 | }; | ||
1374 | |||
907 | static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, | 1375 | static 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; |