blob: 6ed5be030d5885a03306d39425e0951ea9da7129 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * toshiba_acpi.c - Toshiba Laptop ACPI Extras
3 *
4 *
5 * Copyright (C) 2002-2004 John Belmonte
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04006 * Copyright (C) 2008 Philip Langdale
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +02007 * Copyright (C) 2010 Pierre Ducroquet
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
9 * 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 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 *
24 * The devolpment page for this driver is located at
25 * http://memebeam.org/toys/ToshibaAcpiDriver.
26 *
27 * Credits:
28 * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
29 * engineering the Windows drivers
30 * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
31 * Rob Miller - TV out and hotkeys help
32 *
33 *
34 * TODO
35 *
36 */
37
Joe Perches7e334602011-03-29 15:21:52 -070038#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
39
philipl@overt.orgc41a40c2008-08-30 11:57:39 -040040#define TOSHIBA_ACPI_VERSION "0.19"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#define PROC_INTERFACE_VERSION 1
42
43#include <linux/kernel.h>
44#include <linux/module.h>
45#include <linux/init.h>
46#include <linux/types.h>
47#include <linux/proc_fs.h>
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -080048#include <linux/seq_file.h>
Holger Machtc9263552006-10-20 14:30:29 -070049#include <linux/backlight.h>
philipl@overt.orgc41a40c2008-08-30 11:57:39 -040050#include <linux/rfkill.h>
Matthew Garrett6335e4d2010-02-25 15:20:54 -050051#include <linux/input.h>
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -070052#include <linux/input/sparse-keymap.h>
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +020053#include <linux/leds.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090054#include <linux/slab.h>
Seth Forshee29cd2932012-01-18 13:44:09 -060055#include <linux/workqueue.h>
56#include <linux/i8042.h>
Lv Zheng8b484632013-12-03 08:49:16 +080057#include <linux/acpi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <asm/uaccess.h>
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060MODULE_AUTHOR("John Belmonte");
61MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
62MODULE_LICENSE("GPL");
63
Seth Forsheef11f9992012-01-18 13:44:11 -060064#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
65
Seth Forshee29cd2932012-01-18 13:44:09 -060066/* Scan code for Fn key on TOS1900 models */
67#define TOS1900_FN_SCAN 0x6e
68
Linus Torvalds1da177e2005-04-16 15:20:36 -070069/* Toshiba ACPI method paths */
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
71
72/* Toshiba HCI interface definitions
73 *
74 * HCI is Toshiba's "Hardware Control Interface" which is supposed to
75 * be uniform across all their models. Ideally we would just call
76 * dedicated ACPI methods instead of using this primitive interface.
77 * 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 * so this is still useful.
Azael Avalos84a62732014-03-25 20:38:29 -060080 *
81 * SCI stands for "System Configuration Interface" which aim is to
82 * conceal differences in hardware between different models.
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 */
84
85#define HCI_WORDS 6
86
87/* operations */
88#define HCI_SET 0xff00
89#define HCI_GET 0xfe00
Azael Avalos84a62732014-03-25 20:38:29 -060090#define SCI_OPEN 0xf100
91#define SCI_CLOSE 0xf200
92#define SCI_GET 0xf300
93#define SCI_SET 0xf400
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95/* return codes */
96#define HCI_SUCCESS 0x0000
97#define HCI_FAILURE 0x1000
98#define HCI_NOT_SUPPORTED 0x8000
99#define HCI_EMPTY 0x8c00
Azael Avalos84a62732014-03-25 20:38:29 -0600100#define SCI_OPEN_CLOSE_OK 0x0044
101#define SCI_ALREADY_OPEN 0x8100
102#define SCI_NOT_OPENED 0x8200
Azael Avalosfdb79082014-03-25 20:38:30 -0600103#define SCI_INPUT_DATA_ERROR 0x8300
Azael Avalos84a62732014-03-25 20:38:29 -0600104#define SCI_NOT_PRESENT 0x8600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
106/* registers */
107#define HCI_FAN 0x0004
Akio Idehara121b7b02012-04-06 01:46:43 +0900108#define HCI_TR_BACKLIGHT 0x0005
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#define HCI_SYSTEM_EVENT 0x0016
110#define HCI_VIDEO_OUT 0x001c
111#define HCI_HOTKEY_EVENT 0x001e
112#define HCI_LCD_BRIGHTNESS 0x002a
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400113#define HCI_WIRELESS 0x0056
Azael Avalosfdb79082014-03-25 20:38:30 -0600114#define SCI_ILLUMINATION 0x014e
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116/* field definitions */
Seth Forshee29cd2932012-01-18 13:44:09 -0600117#define HCI_HOTKEY_DISABLE 0x0b
118#define HCI_HOTKEY_ENABLE 0x09
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#define HCI_LCD_BRIGHTNESS_BITS 3
120#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
121#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
122#define HCI_VIDEO_OUT_LCD 0x1
123#define HCI_VIDEO_OUT_CRT 0x2
124#define HCI_VIDEO_OUT_TV 0x4
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400125#define HCI_WIRELESS_KILL_SWITCH 0x01
126#define HCI_WIRELESS_BT_PRESENT 0x0f
127#define HCI_WIRELESS_BT_ATTACH 0x40
128#define HCI_WIRELESS_BT_POWER 0x80
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Seth Forshee135740d2011-09-20 16:55:49 -0500130struct toshiba_acpi_dev {
131 struct acpi_device *acpi_dev;
132 const char *method_hci;
133 struct rfkill *bt_rfk;
134 struct input_dev *hotkey_dev;
Seth Forshee29cd2932012-01-18 13:44:09 -0600135 struct work_struct hotkey_work;
Seth Forshee135740d2011-09-20 16:55:49 -0500136 struct backlight_device *backlight_dev;
137 struct led_classdev led_dev;
Seth Forshee36d03f92011-09-20 16:55:53 -0500138
Seth Forshee135740d2011-09-20 16:55:49 -0500139 int force_fan;
140 int last_key_event;
141 int key_event_valid;
Seth Forshee135740d2011-09-20 16:55:49 -0500142
Dan Carpenter592b7462012-01-15 14:28:20 +0300143 unsigned int illumination_supported:1;
144 unsigned int video_supported:1;
145 unsigned int fan_supported:1;
146 unsigned int system_event_supported:1;
Seth Forshee29cd2932012-01-18 13:44:09 -0600147 unsigned int ntfy_supported:1;
148 unsigned int info_supported:1;
Akio Idehara121b7b02012-04-06 01:46:43 +0900149 unsigned int tr_backlight_supported:1;
Seth Forshee36d03f92011-09-20 16:55:53 -0500150
Seth Forshee135740d2011-09-20 16:55:49 -0500151 struct mutex mutex;
152};
153
Seth Forshee29cd2932012-01-18 13:44:09 -0600154static struct toshiba_acpi_dev *toshiba_acpi;
155
arvidjaar@mail.ru4db42c52008-03-04 15:06:34 -0800156static const struct acpi_device_id toshiba_device_ids[] = {
157 {"TOS6200", 0},
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400158 {"TOS6208", 0},
arvidjaar@mail.ru4db42c52008-03-04 15:06:34 -0800159 {"TOS1900", 0},
160 {"", 0},
161};
162MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
163
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -0800164static const struct key_entry toshiba_acpi_keymap[] = {
Unai Uribarrifec278a2014-01-14 11:06:47 +0100165 { KE_KEY, 0x9e, { KEY_RFKILL } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700166 { KE_KEY, 0x101, { KEY_MUTE } },
167 { KE_KEY, 0x102, { KEY_ZOOMOUT } },
168 { KE_KEY, 0x103, { KEY_ZOOMIN } },
Azael Avalosaf502832012-01-18 13:44:10 -0600169 { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
170 { KE_KEY, 0x139, { KEY_ZOOMRESET } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700171 { KE_KEY, 0x13b, { KEY_COFFEE } },
172 { KE_KEY, 0x13c, { KEY_BATTERY } },
173 { KE_KEY, 0x13d, { KEY_SLEEP } },
174 { KE_KEY, 0x13e, { KEY_SUSPEND } },
175 { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
176 { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
177 { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
178 { KE_KEY, 0x142, { KEY_WLAN } },
Azael Avalosaf502832012-01-18 13:44:10 -0600179 { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
Jon Dowlanda49010f2010-10-27 00:24:59 +0100180 { KE_KEY, 0x17f, { KEY_FN } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700181 { KE_KEY, 0xb05, { KEY_PROG2 } },
182 { KE_KEY, 0xb06, { KEY_WWW } },
183 { KE_KEY, 0xb07, { KEY_MAIL } },
184 { KE_KEY, 0xb30, { KEY_STOP } },
185 { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
186 { KE_KEY, 0xb32, { KEY_NEXTSONG } },
187 { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
188 { KE_KEY, 0xb5a, { KEY_MEDIA } },
Azael Avalosaf502832012-01-18 13:44:10 -0600189 { KE_IGNORE, 0x1430, { KEY_RESERVED } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700190 { KE_END, 0 },
Matthew Garrett6335e4d2010-02-25 15:20:54 -0500191};
192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193/* utility
194 */
195
Len Brown4be44fc2005-08-05 00:44:28 -0400196static __inline__ void _set_bit(u32 * word, u32 mask, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197{
198 *word = (*word & ~mask) | (mask * value);
199}
200
201/* acpi interface wrappers
202 */
203
Len Brown4be44fc2005-08-05 00:44:28 -0400204static int write_acpi_int(const char *methodName, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 acpi_status status;
207
Zhang Rui619400d2013-09-03 08:31:56 +0800208 status = acpi_execute_simple_method(NULL, (char *)methodName, val);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500209 return (status == AE_OK) ? 0 : -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210}
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212/* Perform a raw HCI call. Here we don't care about input or output buffer
213 * format.
214 */
Seth Forshee135740d2011-09-20 16:55:49 -0500215static acpi_status hci_raw(struct toshiba_acpi_dev *dev,
216 const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217{
218 struct acpi_object_list params;
219 union acpi_object in_objs[HCI_WORDS];
220 struct acpi_buffer results;
Len Brown4be44fc2005-08-05 00:44:28 -0400221 union acpi_object out_objs[HCI_WORDS + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 acpi_status status;
223 int i;
224
225 params.count = HCI_WORDS;
226 params.pointer = in_objs;
227 for (i = 0; i < HCI_WORDS; ++i) {
228 in_objs[i].type = ACPI_TYPE_INTEGER;
229 in_objs[i].integer.value = in[i];
230 }
231
232 results.length = sizeof(out_objs);
233 results.pointer = out_objs;
234
Seth Forshee6e02cc72011-09-20 16:55:51 -0500235 status = acpi_evaluate_object(dev->acpi_dev->handle,
236 (char *)dev->method_hci, &params,
Len Brown4be44fc2005-08-05 00:44:28 -0400237 &results);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) {
239 for (i = 0; i < out_objs->package.count; ++i) {
240 out[i] = out_objs->package.elements[i].integer.value;
241 }
242 }
243
244 return status;
245}
246
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400247/* common hci tasks (get or set one or two value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 *
249 * In addition to the ACPI status, the HCI system returns a result which
250 * may be useful (such as "not supported").
251 */
252
Seth Forshee135740d2011-09-20 16:55:49 -0500253static acpi_status hci_write1(struct toshiba_acpi_dev *dev, u32 reg,
254 u32 in1, u32 *result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
256 u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
257 u32 out[HCI_WORDS];
Seth Forshee135740d2011-09-20 16:55:49 -0500258 acpi_status status = hci_raw(dev, in, out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
260 return status;
261}
262
Seth Forshee135740d2011-09-20 16:55:49 -0500263static acpi_status hci_read1(struct toshiba_acpi_dev *dev, u32 reg,
264 u32 *out1, u32 *result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
266 u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
267 u32 out[HCI_WORDS];
Seth Forshee135740d2011-09-20 16:55:49 -0500268 acpi_status status = hci_raw(dev, in, out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 *out1 = out[2];
270 *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
271 return status;
272}
273
Seth Forshee135740d2011-09-20 16:55:49 -0500274static acpi_status hci_write2(struct toshiba_acpi_dev *dev, u32 reg,
275 u32 in1, u32 in2, u32 *result)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400276{
277 u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
278 u32 out[HCI_WORDS];
Seth Forshee135740d2011-09-20 16:55:49 -0500279 acpi_status status = hci_raw(dev, in, out);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400280 *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
281 return status;
282}
283
Seth Forshee135740d2011-09-20 16:55:49 -0500284static acpi_status hci_read2(struct toshiba_acpi_dev *dev, u32 reg,
285 u32 *out1, u32 *out2, u32 *result)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400286{
287 u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
288 u32 out[HCI_WORDS];
Seth Forshee135740d2011-09-20 16:55:49 -0500289 acpi_status status = hci_raw(dev, in, out);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400290 *out1 = out[2];
291 *out2 = out[3];
292 *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
293 return status;
294}
295
Azael Avalos84a62732014-03-25 20:38:29 -0600296/* common sci tasks
297 */
298
299static int sci_open(struct toshiba_acpi_dev *dev)
300{
301 u32 in[HCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
302 u32 out[HCI_WORDS];
303 acpi_status status;
304
305 status = hci_raw(dev, in, out);
306 if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
307 pr_err("ACPI call to open SCI failed\n");
308 return 0;
309 }
310
311 if (out[0] == SCI_OPEN_CLOSE_OK) {
312 return 1;
313 } else if (out[0] == SCI_ALREADY_OPEN) {
314 pr_info("Toshiba SCI already opened\n");
315 return 1;
316 } else if (out[0] == SCI_NOT_PRESENT) {
317 pr_info("Toshiba SCI is not present\n");
318 }
319
320 return 0;
321}
322
323static void sci_close(struct toshiba_acpi_dev *dev)
324{
325 u32 in[HCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
326 u32 out[HCI_WORDS];
327 acpi_status status;
328
329 status = hci_raw(dev, in, out);
330 if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
331 pr_err("ACPI call to close SCI failed\n");
332 return;
333 }
334
335 if (out[0] == SCI_OPEN_CLOSE_OK)
336 return;
337 else if (out[0] == SCI_NOT_OPENED)
338 pr_info("Toshiba SCI not opened\n");
339 else if (out[0] == SCI_NOT_PRESENT)
340 pr_info("Toshiba SCI is not present\n");
341}
342
343static acpi_status sci_read(struct toshiba_acpi_dev *dev, u32 reg,
344 u32 *out1, u32 *result)
345{
346 u32 in[HCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
347 u32 out[HCI_WORDS];
348 acpi_status status = hci_raw(dev, in, out);
349 *out1 = out[2];
350 *result = (ACPI_SUCCESS(status)) ? out[0] : HCI_FAILURE;
351 return status;
352}
353
354static acpi_status sci_write(struct toshiba_acpi_dev *dev, u32 reg,
355 u32 in1, u32 *result)
356{
357 u32 in[HCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
358 u32 out[HCI_WORDS];
359 acpi_status status = hci_raw(dev, in, out);
360 *result = (ACPI_SUCCESS(status)) ? out[0] : HCI_FAILURE;
361 return status;
362}
363
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200364/* Illumination support */
Seth Forshee135740d2011-09-20 16:55:49 -0500365static int toshiba_illumination_available(struct toshiba_acpi_dev *dev)
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200366{
Azael Avalosfdb79082014-03-25 20:38:30 -0600367 u32 in[HCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200368 u32 out[HCI_WORDS];
369 acpi_status status;
370
Azael Avalosfdb79082014-03-25 20:38:30 -0600371 if (!sci_open(dev))
372 return 0;
373
Seth Forshee135740d2011-09-20 16:55:49 -0500374 status = hci_raw(dev, in, out);
Azael Avalosfdb79082014-03-25 20:38:30 -0600375 sci_close(dev);
376 if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
377 pr_err("ACPI call to query Illumination support failed\n");
378 return 0;
379 } else if (out[0] == HCI_NOT_SUPPORTED || out[1] != 1) {
Joe Perches7e334602011-03-29 15:21:52 -0700380 pr_info("Illumination device not available\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200381 return 0;
382 }
Azael Avalosfdb79082014-03-25 20:38:30 -0600383
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200384 return 1;
385}
386
387static void toshiba_illumination_set(struct led_classdev *cdev,
388 enum led_brightness brightness)
389{
Seth Forshee135740d2011-09-20 16:55:49 -0500390 struct toshiba_acpi_dev *dev = container_of(cdev,
391 struct toshiba_acpi_dev, led_dev);
Azael Avalosfdb79082014-03-25 20:38:30 -0600392 u32 state, result;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200393 acpi_status status;
394
395 /* First request : initialize communication. */
Azael Avalosfdb79082014-03-25 20:38:30 -0600396 if (!sci_open(dev))
397 return;
398
399 /* Switch the illumination on/off */
400 state = brightness ? 1 : 0;
401 status = sci_write(dev, SCI_ILLUMINATION, state, &result);
402 sci_close(dev);
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200403 if (ACPI_FAILURE(status)) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600404 pr_err("ACPI call for illumination failed\n");
405 return;
406 } else if (result == HCI_NOT_SUPPORTED) {
407 pr_info("Illumination not supported\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200408 return;
409 }
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200410}
411
412static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
413{
Seth Forshee135740d2011-09-20 16:55:49 -0500414 struct toshiba_acpi_dev *dev = container_of(cdev,
415 struct toshiba_acpi_dev, led_dev);
Azael Avalosfdb79082014-03-25 20:38:30 -0600416 u32 state, result;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200417 acpi_status status;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200418
419 /* First request : initialize communication. */
Azael Avalosfdb79082014-03-25 20:38:30 -0600420 if (!sci_open(dev))
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200421 return LED_OFF;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200422
423 /* Check the illumination */
Azael Avalosfdb79082014-03-25 20:38:30 -0600424 status = sci_read(dev, SCI_ILLUMINATION, &state, &result);
425 sci_close(dev);
426 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
427 pr_err("ACPI call for illumination failed\n");
428 return LED_OFF;
429 } else if (result == HCI_NOT_SUPPORTED) {
430 pr_info("Illumination not supported\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200431 return LED_OFF;
432 }
433
Azael Avalosfdb79082014-03-25 20:38:30 -0600434 return state ? LED_FULL : LED_OFF;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200435}
436
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400437/* Bluetooth rfkill handlers */
438
Seth Forshee135740d2011-09-20 16:55:49 -0500439static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400440{
441 u32 hci_result;
442 u32 value, value2;
443
444 value = 0;
445 value2 = 0;
Seth Forshee135740d2011-09-20 16:55:49 -0500446 hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400447 if (hci_result == HCI_SUCCESS)
448 *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
449
450 return hci_result;
451}
452
Seth Forshee135740d2011-09-20 16:55:49 -0500453static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400454{
455 u32 hci_result;
456 u32 value, value2;
457
458 value = 0;
459 value2 = 0x0001;
Seth Forshee135740d2011-09-20 16:55:49 -0500460 hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400461
462 *radio_state = value & HCI_WIRELESS_KILL_SWITCH;
463 return hci_result;
464}
465
Johannes Berg19d337d2009-06-02 13:01:37 +0200466static int bt_rfkill_set_block(void *data, bool blocked)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400467{
Johannes Berg19d337d2009-06-02 13:01:37 +0200468 struct toshiba_acpi_dev *dev = data;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400469 u32 result1, result2;
470 u32 value;
Johannes Berg19d337d2009-06-02 13:01:37 +0200471 int err;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400472 bool radio_state;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400473
Johannes Berg19d337d2009-06-02 13:01:37 +0200474 value = (blocked == false);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400475
476 mutex_lock(&dev->mutex);
Seth Forshee135740d2011-09-20 16:55:49 -0500477 if (hci_get_radio_state(dev, &radio_state) != HCI_SUCCESS) {
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500478 err = -EIO;
Johannes Berg19d337d2009-06-02 13:01:37 +0200479 goto out;
480 }
481
482 if (!radio_state) {
483 err = 0;
484 goto out;
485 }
486
Seth Forshee135740d2011-09-20 16:55:49 -0500487 hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
488 hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400489
490 if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500491 err = -EIO;
Johannes Berg19d337d2009-06-02 13:01:37 +0200492 else
493 err = 0;
494 out:
495 mutex_unlock(&dev->mutex);
496 return err;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400497}
498
Johannes Berg19d337d2009-06-02 13:01:37 +0200499static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400500{
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400501 bool new_rfk_state;
502 bool value;
503 u32 hci_result;
Johannes Berg19d337d2009-06-02 13:01:37 +0200504 struct toshiba_acpi_dev *dev = data;
505
506 mutex_lock(&dev->mutex);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400507
Seth Forshee135740d2011-09-20 16:55:49 -0500508 hci_result = hci_get_radio_state(dev, &value);
Johannes Berg19d337d2009-06-02 13:01:37 +0200509 if (hci_result != HCI_SUCCESS) {
510 /* Can't do anything useful */
511 mutex_unlock(&dev->mutex);
Jiri Slaby82e77842009-08-06 15:57:51 -0700512 return;
Johannes Berg19d337d2009-06-02 13:01:37 +0200513 }
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400514
515 new_rfk_state = value;
516
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400517 mutex_unlock(&dev->mutex);
518
Johannes Berg19d337d2009-06-02 13:01:37 +0200519 if (rfkill_set_hw_state(rfkill, !new_rfk_state))
520 bt_rfkill_set_block(data, true);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400521}
522
Johannes Berg19d337d2009-06-02 13:01:37 +0200523static const struct rfkill_ops toshiba_rfk_ops = {
524 .set_block = bt_rfkill_set_block,
525 .poll = bt_rfkill_poll,
526};
527
Akio Idehara121b7b02012-04-06 01:46:43 +0900528static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled)
529{
530 u32 hci_result;
531 u32 status;
532
533 hci_read1(dev, HCI_TR_BACKLIGHT, &status, &hci_result);
534 *enabled = !status;
535 return hci_result == HCI_SUCCESS ? 0 : -EIO;
536}
537
538static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
539{
540 u32 hci_result;
541 u32 value = !enable;
542
543 hci_write1(dev, HCI_TR_BACKLIGHT, value, &hci_result);
544 return hci_result == HCI_SUCCESS ? 0 : -EIO;
545}
546
Len Brown4be44fc2005-08-05 00:44:28 -0400547static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Seth Forshee62cce752012-04-19 11:23:50 -0500549static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550{
551 u32 hci_result;
552 u32 value;
Akio Idehara121b7b02012-04-06 01:46:43 +0900553 int brightness = 0;
554
555 if (dev->tr_backlight_supported) {
556 bool enabled;
557 int ret = get_tr_backlight_status(dev, &enabled);
558 if (ret)
559 return ret;
560 if (enabled)
561 return 0;
562 brightness++;
563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Seth Forshee135740d2011-09-20 16:55:49 -0500565 hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500566 if (hci_result == HCI_SUCCESS)
Akio Idehara121b7b02012-04-06 01:46:43 +0900567 return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500568
569 return -EIO;
Holger Machtc9263552006-10-20 14:30:29 -0700570}
571
Seth Forshee62cce752012-04-19 11:23:50 -0500572static int get_lcd_brightness(struct backlight_device *bd)
573{
574 struct toshiba_acpi_dev *dev = bl_get_data(bd);
575 return __get_lcd_brightness(dev);
576}
577
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800578static int lcd_proc_show(struct seq_file *m, void *v)
Holger Machtc9263552006-10-20 14:30:29 -0700579{
Seth Forshee135740d2011-09-20 16:55:49 -0500580 struct toshiba_acpi_dev *dev = m->private;
581 int value;
Akio Idehara121b7b02012-04-06 01:46:43 +0900582 int levels;
Holger Machtc9263552006-10-20 14:30:29 -0700583
Seth Forshee135740d2011-09-20 16:55:49 -0500584 if (!dev->backlight_dev)
585 return -ENODEV;
586
Akio Idehara121b7b02012-04-06 01:46:43 +0900587 levels = dev->backlight_dev->props.max_brightness + 1;
Seth Forshee62cce752012-04-19 11:23:50 -0500588 value = get_lcd_brightness(dev->backlight_dev);
Holger Machtc9263552006-10-20 14:30:29 -0700589 if (value >= 0) {
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800590 seq_printf(m, "brightness: %d\n", value);
Akio Idehara121b7b02012-04-06 01:46:43 +0900591 seq_printf(m, "brightness_levels: %d\n", levels);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500592 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 }
594
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500595 pr_err("Error reading LCD brightness\n");
596 return -EIO;
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800597}
598
599static int lcd_proc_open(struct inode *inode, struct file *file)
600{
Al Virod9dda782013-03-31 18:16:14 -0400601 return single_open(file, lcd_proc_show, PDE_DATA(inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602}
603
Seth Forshee62cce752012-04-19 11:23:50 -0500604static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
Holger Machtc9263552006-10-20 14:30:29 -0700605{
606 u32 hci_result;
607
Akio Idehara121b7b02012-04-06 01:46:43 +0900608 if (dev->tr_backlight_supported) {
609 bool enable = !value;
610 int ret = set_tr_backlight_status(dev, enable);
611 if (ret)
612 return ret;
613 if (value)
614 value--;
615 }
616
Holger Machtc9263552006-10-20 14:30:29 -0700617 value = value << HCI_LCD_BRIGHTNESS_SHIFT;
Seth Forshee135740d2011-09-20 16:55:49 -0500618 hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500619 return hci_result == HCI_SUCCESS ? 0 : -EIO;
Holger Machtc9263552006-10-20 14:30:29 -0700620}
621
622static int set_lcd_status(struct backlight_device *bd)
623{
Seth Forshee135740d2011-09-20 16:55:49 -0500624 struct toshiba_acpi_dev *dev = bl_get_data(bd);
Seth Forshee62cce752012-04-19 11:23:50 -0500625 return set_lcd_brightness(dev, bd->props.brightness);
Holger Machtc9263552006-10-20 14:30:29 -0700626}
627
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800628static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
629 size_t count, loff_t *pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
Al Virod9dda782013-03-31 18:16:14 -0400631 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800632 char cmd[42];
633 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 int value;
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -0800635 int ret;
Akio Idehara121b7b02012-04-06 01:46:43 +0900636 int levels = dev->backlight_dev->props.max_brightness + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800638 len = min(count, sizeof(cmd) - 1);
639 if (copy_from_user(cmd, buf, len))
640 return -EFAULT;
641 cmd[len] = '\0';
642
643 if (sscanf(cmd, " brightness : %i", &value) == 1 &&
Akio Idehara121b7b02012-04-06 01:46:43 +0900644 value >= 0 && value < levels) {
Seth Forshee62cce752012-04-19 11:23:50 -0500645 ret = set_lcd_brightness(dev, value);
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -0800646 if (ret == 0)
647 ret = count;
648 } else {
Holger Machtc9263552006-10-20 14:30:29 -0700649 ret = -EINVAL;
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -0800650 }
Holger Machtc9263552006-10-20 14:30:29 -0700651 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652}
653
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800654static const struct file_operations lcd_proc_fops = {
655 .owner = THIS_MODULE,
656 .open = lcd_proc_open,
657 .read = seq_read,
658 .llseek = seq_lseek,
659 .release = single_release,
660 .write = lcd_proc_write,
661};
662
Seth Forshee36d03f92011-09-20 16:55:53 -0500663static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
664{
665 u32 hci_result;
666
667 hci_read1(dev, HCI_VIDEO_OUT, status, &hci_result);
668 return hci_result == HCI_SUCCESS ? 0 : -EIO;
669}
670
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800671static int video_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672{
Seth Forshee135740d2011-09-20 16:55:49 -0500673 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 u32 value;
Seth Forshee36d03f92011-09-20 16:55:53 -0500675 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Seth Forshee36d03f92011-09-20 16:55:53 -0500677 ret = get_video_status(dev, &value);
678 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
680 int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
Len Brown4be44fc2005-08-05 00:44:28 -0400681 int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800682 seq_printf(m, "lcd_out: %d\n", is_lcd);
683 seq_printf(m, "crt_out: %d\n", is_crt);
684 seq_printf(m, "tv_out: %d\n", is_tv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 }
686
Seth Forshee36d03f92011-09-20 16:55:53 -0500687 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688}
689
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800690static int video_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691{
Al Virod9dda782013-03-31 18:16:14 -0400692 return single_open(file, video_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800693}
694
695static ssize_t video_proc_write(struct file *file, const char __user *buf,
696 size_t count, loff_t *pos)
697{
Al Virod9dda782013-03-31 18:16:14 -0400698 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800699 char *cmd, *buffer;
Seth Forshee36d03f92011-09-20 16:55:53 -0500700 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 int value;
702 int remain = count;
703 int lcd_out = -1;
704 int crt_out = -1;
705 int tv_out = -1;
Al Virob4482a42007-10-14 19:35:40 +0100706 u32 video_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800708 cmd = kmalloc(count + 1, GFP_KERNEL);
709 if (!cmd)
710 return -ENOMEM;
711 if (copy_from_user(cmd, buf, count)) {
712 kfree(cmd);
713 return -EFAULT;
714 }
715 cmd[count] = '\0';
716
717 buffer = cmd;
718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 /* scan expression. Multiple expressions may be delimited with ;
720 *
721 * NOTE: to keep scanning simple, invalid fields are ignored
722 */
723 while (remain) {
724 if (sscanf(buffer, " lcd_out : %i", &value) == 1)
725 lcd_out = value & 1;
726 else if (sscanf(buffer, " crt_out : %i", &value) == 1)
727 crt_out = value & 1;
728 else if (sscanf(buffer, " tv_out : %i", &value) == 1)
729 tv_out = value & 1;
730 /* advance to one character past the next ; */
731 do {
732 ++buffer;
733 --remain;
734 }
Len Brown4be44fc2005-08-05 00:44:28 -0400735 while (remain && *(buffer - 1) != ';');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 }
737
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800738 kfree(cmd);
739
Seth Forshee36d03f92011-09-20 16:55:53 -0500740 ret = get_video_status(dev, &video_out);
741 if (!ret) {
Harvey Harrison9e113e02008-09-22 14:37:29 -0700742 unsigned int new_video_out = video_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (lcd_out != -1)
744 _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
745 if (crt_out != -1)
746 _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
747 if (tv_out != -1)
748 _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
749 /* To avoid unnecessary video disruption, only write the new
750 * video setting if something changed. */
751 if (new_video_out != video_out)
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500752 ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 }
754
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500755 return ret ? ret : count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756}
757
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800758static const struct file_operations video_proc_fops = {
759 .owner = THIS_MODULE,
760 .open = video_proc_open,
761 .read = seq_read,
762 .llseek = seq_lseek,
763 .release = single_release,
764 .write = video_proc_write,
765};
766
Seth Forshee36d03f92011-09-20 16:55:53 -0500767static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
768{
769 u32 hci_result;
770
771 hci_read1(dev, HCI_FAN, status, &hci_result);
772 return hci_result == HCI_SUCCESS ? 0 : -EIO;
773}
774
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800775static int fan_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
Seth Forshee135740d2011-09-20 16:55:49 -0500777 struct toshiba_acpi_dev *dev = m->private;
Seth Forshee36d03f92011-09-20 16:55:53 -0500778 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 u32 value;
780
Seth Forshee36d03f92011-09-20 16:55:53 -0500781 ret = get_fan_status(dev, &value);
782 if (!ret) {
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800783 seq_printf(m, "running: %d\n", (value > 0));
Seth Forshee135740d2011-09-20 16:55:49 -0500784 seq_printf(m, "force_on: %d\n", dev->force_fan);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 }
786
Seth Forshee36d03f92011-09-20 16:55:53 -0500787 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788}
789
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800790static int fan_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791{
Al Virod9dda782013-03-31 18:16:14 -0400792 return single_open(file, fan_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800793}
794
795static ssize_t fan_proc_write(struct file *file, const char __user *buf,
796 size_t count, loff_t *pos)
797{
Al Virod9dda782013-03-31 18:16:14 -0400798 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800799 char cmd[42];
800 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 int value;
802 u32 hci_result;
803
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800804 len = min(count, sizeof(cmd) - 1);
805 if (copy_from_user(cmd, buf, len))
806 return -EFAULT;
807 cmd[len] = '\0';
808
809 if (sscanf(cmd, " force_on : %i", &value) == 1 &&
Len Brown4be44fc2005-08-05 00:44:28 -0400810 value >= 0 && value <= 1) {
Seth Forshee135740d2011-09-20 16:55:49 -0500811 hci_write1(dev, HCI_FAN, value, &hci_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 if (hci_result != HCI_SUCCESS)
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500813 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 else
Seth Forshee135740d2011-09-20 16:55:49 -0500815 dev->force_fan = value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 } else {
817 return -EINVAL;
818 }
819
820 return count;
821}
822
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800823static const struct file_operations fan_proc_fops = {
824 .owner = THIS_MODULE,
825 .open = fan_proc_open,
826 .read = seq_read,
827 .llseek = seq_lseek,
828 .release = single_release,
829 .write = fan_proc_write,
830};
831
832static int keys_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833{
Seth Forshee135740d2011-09-20 16:55:49 -0500834 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 u32 hci_result;
836 u32 value;
837
Seth Forshee11948b92011-11-16 17:37:45 -0600838 if (!dev->key_event_valid && dev->system_event_supported) {
Seth Forshee135740d2011-09-20 16:55:49 -0500839 hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (hci_result == HCI_SUCCESS) {
Seth Forshee135740d2011-09-20 16:55:49 -0500841 dev->key_event_valid = 1;
842 dev->last_key_event = value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 } else if (hci_result == HCI_EMPTY) {
844 /* better luck next time */
845 } else if (hci_result == HCI_NOT_SUPPORTED) {
846 /* This is a workaround for an unresolved issue on
847 * some machines where system events sporadically
848 * become disabled. */
Seth Forshee135740d2011-09-20 16:55:49 -0500849 hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
Joe Perches7e334602011-03-29 15:21:52 -0700850 pr_notice("Re-enabled hotkeys\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 } else {
Joe Perches7e334602011-03-29 15:21:52 -0700852 pr_err("Error reading hotkey status\n");
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500853 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
855 }
856
Seth Forshee135740d2011-09-20 16:55:49 -0500857 seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid);
858 seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event);
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800859 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800862static int keys_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
Al Virod9dda782013-03-31 18:16:14 -0400864 return single_open(file, keys_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800865}
866
867static ssize_t keys_proc_write(struct file *file, const char __user *buf,
868 size_t count, loff_t *pos)
869{
Al Virod9dda782013-03-31 18:16:14 -0400870 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800871 char cmd[42];
872 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 int value;
874
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800875 len = min(count, sizeof(cmd) - 1);
876 if (copy_from_user(cmd, buf, len))
877 return -EFAULT;
878 cmd[len] = '\0';
879
880 if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) {
Seth Forshee135740d2011-09-20 16:55:49 -0500881 dev->key_event_valid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 } else {
883 return -EINVAL;
884 }
885
886 return count;
887}
888
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800889static const struct file_operations keys_proc_fops = {
890 .owner = THIS_MODULE,
891 .open = keys_proc_open,
892 .read = seq_read,
893 .llseek = seq_lseek,
894 .release = single_release,
895 .write = keys_proc_write,
896};
897
898static int version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800900 seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION);
901 seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION);
902 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903}
904
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800905static int version_proc_open(struct inode *inode, struct file *file)
906{
Al Virod9dda782013-03-31 18:16:14 -0400907 return single_open(file, version_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800908}
909
910static const struct file_operations version_proc_fops = {
911 .owner = THIS_MODULE,
912 .open = version_proc_open,
913 .read = seq_read,
914 .llseek = seq_lseek,
915 .release = single_release,
916};
917
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918/* proc and module init
919 */
920
921#define PROC_TOSHIBA "toshiba"
922
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -0800923static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924{
Seth Forshee36d03f92011-09-20 16:55:53 -0500925 if (dev->backlight_dev)
926 proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
927 &lcd_proc_fops, dev);
928 if (dev->video_supported)
929 proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir,
930 &video_proc_fops, dev);
931 if (dev->fan_supported)
932 proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir,
933 &fan_proc_fops, dev);
934 if (dev->hotkey_dev)
935 proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir,
936 &keys_proc_fops, dev);
Seth Forshee135740d2011-09-20 16:55:49 -0500937 proc_create_data("version", S_IRUGO, toshiba_proc_dir,
938 &version_proc_fops, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939}
940
Seth Forshee36d03f92011-09-20 16:55:53 -0500941static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942{
Seth Forshee36d03f92011-09-20 16:55:53 -0500943 if (dev->backlight_dev)
944 remove_proc_entry("lcd", toshiba_proc_dir);
945 if (dev->video_supported)
946 remove_proc_entry("video", toshiba_proc_dir);
947 if (dev->fan_supported)
948 remove_proc_entry("fan", toshiba_proc_dir);
949 if (dev->hotkey_dev)
950 remove_proc_entry("keys", toshiba_proc_dir);
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800951 remove_proc_entry("version", toshiba_proc_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952}
953
Lionel Debrouxacc24722010-11-16 14:14:02 +0100954static const struct backlight_ops toshiba_backlight_data = {
Akio Idehara121b7b02012-04-06 01:46:43 +0900955 .options = BL_CORE_SUSPENDRESUME,
Seth Forshee62cce752012-04-19 11:23:50 -0500956 .get_brightness = get_lcd_brightness,
957 .update_status = set_lcd_status,
Holger Machtc9263552006-10-20 14:30:29 -0700958};
959
Seth Forshee29cd2932012-01-18 13:44:09 -0600960static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
961 struct serio *port)
962{
963 if (str & 0x20)
964 return false;
965
966 if (unlikely(data == 0xe0))
967 return false;
968
969 if ((data & 0x7f) == TOS1900_FN_SCAN) {
970 schedule_work(&toshiba_acpi->hotkey_work);
971 return true;
972 }
973
974 return false;
975}
976
977static void toshiba_acpi_hotkey_work(struct work_struct *work)
978{
979 acpi_handle ec_handle = ec_get_handle();
980 acpi_status status;
981
982 if (!ec_handle)
983 return;
984
985 status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
986 if (ACPI_FAILURE(status))
987 pr_err("ACPI NTFY method execution failed\n");
988}
989
990/*
991 * Returns hotkey scancode, or < 0 on failure.
992 */
993static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
994{
Zhang Rui74facaf2013-09-03 08:32:15 +0800995 unsigned long long value;
Seth Forshee29cd2932012-01-18 13:44:09 -0600996 acpi_status status;
997
Zhang Rui74facaf2013-09-03 08:32:15 +0800998 status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO",
999 NULL, &value);
1000 if (ACPI_FAILURE(status)) {
Seth Forshee29cd2932012-01-18 13:44:09 -06001001 pr_err("ACPI INFO method execution failed\n");
1002 return -EIO;
1003 }
1004
Zhang Rui74facaf2013-09-03 08:32:15 +08001005 return value;
Seth Forshee29cd2932012-01-18 13:44:09 -06001006}
1007
1008static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
1009 int scancode)
1010{
1011 if (scancode == 0x100)
1012 return;
1013
1014 /* act on key press; ignore key release */
1015 if (scancode & 0x80)
1016 return;
1017
1018 if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
1019 pr_info("Unknown key %x\n", scancode);
1020}
1021
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001022static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001023{
Seth Forshee135740d2011-09-20 16:55:49 -05001024 acpi_status status;
Zhang Ruie2e19602013-09-03 08:32:06 +08001025 acpi_handle ec_handle;
Seth Forshee135740d2011-09-20 16:55:49 -05001026 int error;
Seth Forshee29cd2932012-01-18 13:44:09 -06001027 u32 hci_result;
Seth Forshee135740d2011-09-20 16:55:49 -05001028
Seth Forshee135740d2011-09-20 16:55:49 -05001029 dev->hotkey_dev = input_allocate_device();
Joe Perchesb222cca2013-10-23 12:14:52 -07001030 if (!dev->hotkey_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05001031 return -ENOMEM;
Seth Forshee135740d2011-09-20 16:55:49 -05001032
1033 dev->hotkey_dev->name = "Toshiba input device";
Seth Forshee6e02cc72011-09-20 16:55:51 -05001034 dev->hotkey_dev->phys = "toshiba_acpi/input0";
Seth Forshee135740d2011-09-20 16:55:49 -05001035 dev->hotkey_dev->id.bustype = BUS_HOST;
1036
1037 error = sparse_keymap_setup(dev->hotkey_dev, toshiba_acpi_keymap, NULL);
1038 if (error)
1039 goto err_free_dev;
1040
Seth Forshee29cd2932012-01-18 13:44:09 -06001041 /*
1042 * For some machines the SCI responsible for providing hotkey
1043 * notification doesn't fire. We can trigger the notification
1044 * whenever the Fn key is pressed using the NTFY method, if
1045 * supported, so if it's present set up an i8042 key filter
1046 * for this purpose.
1047 */
1048 status = AE_ERROR;
1049 ec_handle = ec_get_handle();
Zhang Ruie2e19602013-09-03 08:32:06 +08001050 if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
Seth Forshee29cd2932012-01-18 13:44:09 -06001051 INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
1052
1053 error = i8042_install_filter(toshiba_acpi_i8042_filter);
1054 if (error) {
1055 pr_err("Error installing key filter\n");
1056 goto err_free_keymap;
1057 }
1058
1059 dev->ntfy_supported = 1;
1060 }
1061
1062 /*
1063 * Determine hotkey query interface. Prefer using the INFO
1064 * method when it is available.
1065 */
Zhang Ruie2e19602013-09-03 08:32:06 +08001066 if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
Seth Forshee29cd2932012-01-18 13:44:09 -06001067 dev->info_supported = 1;
Zhang Ruie2e19602013-09-03 08:32:06 +08001068 else {
Seth Forshee29cd2932012-01-18 13:44:09 -06001069 hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
1070 if (hci_result == HCI_SUCCESS)
1071 dev->system_event_supported = 1;
1072 }
1073
1074 if (!dev->info_supported && !dev->system_event_supported) {
1075 pr_warn("No hotkey query interface found\n");
1076 goto err_remove_filter;
1077 }
1078
Seth Forshee6e02cc72011-09-20 16:55:51 -05001079 status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL);
Seth Forshee135740d2011-09-20 16:55:49 -05001080 if (ACPI_FAILURE(status)) {
1081 pr_info("Unable to enable hotkeys\n");
1082 error = -ENODEV;
Seth Forshee29cd2932012-01-18 13:44:09 -06001083 goto err_remove_filter;
Seth Forshee135740d2011-09-20 16:55:49 -05001084 }
1085
1086 error = input_register_device(dev->hotkey_dev);
1087 if (error) {
1088 pr_info("Unable to register input device\n");
Seth Forshee29cd2932012-01-18 13:44:09 -06001089 goto err_remove_filter;
Seth Forshee135740d2011-09-20 16:55:49 -05001090 }
1091
Seth Forshee29cd2932012-01-18 13:44:09 -06001092 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &hci_result);
Seth Forshee135740d2011-09-20 16:55:49 -05001093 return 0;
1094
Seth Forshee29cd2932012-01-18 13:44:09 -06001095 err_remove_filter:
1096 if (dev->ntfy_supported)
1097 i8042_remove_filter(toshiba_acpi_i8042_filter);
Seth Forshee135740d2011-09-20 16:55:49 -05001098 err_free_keymap:
1099 sparse_keymap_free(dev->hotkey_dev);
1100 err_free_dev:
1101 input_free_device(dev->hotkey_dev);
1102 dev->hotkey_dev = NULL;
1103 return error;
1104}
1105
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001106static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
Seth Forshee62cce752012-04-19 11:23:50 -05001107{
1108 struct backlight_properties props;
1109 int brightness;
1110 int ret;
Akio Idehara121b7b02012-04-06 01:46:43 +09001111 bool enabled;
Seth Forshee62cce752012-04-19 11:23:50 -05001112
1113 /*
1114 * Some machines don't support the backlight methods at all, and
1115 * others support it read-only. Either of these is pretty useless,
1116 * so only register the backlight device if the backlight method
1117 * supports both reads and writes.
1118 */
1119 brightness = __get_lcd_brightness(dev);
1120 if (brightness < 0)
1121 return 0;
1122 ret = set_lcd_brightness(dev, brightness);
1123 if (ret) {
1124 pr_debug("Backlight method is read-only, disabling backlight support\n");
1125 return 0;
1126 }
1127
Akio Idehara121b7b02012-04-06 01:46:43 +09001128 /* Determine whether or not BIOS supports transflective backlight */
1129 ret = get_tr_backlight_status(dev, &enabled);
1130 dev->tr_backlight_supported = !ret;
1131
Matthew Garrett53039f22012-06-01 11:02:36 -04001132 memset(&props, 0, sizeof(props));
Seth Forshee62cce752012-04-19 11:23:50 -05001133 props.type = BACKLIGHT_PLATFORM;
1134 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
Seth Forshee62cce752012-04-19 11:23:50 -05001135
Akio Idehara121b7b02012-04-06 01:46:43 +09001136 /* adding an extra level and having 0 change to transflective mode */
1137 if (dev->tr_backlight_supported)
1138 props.max_brightness++;
1139
Seth Forshee62cce752012-04-19 11:23:50 -05001140 dev->backlight_dev = backlight_device_register("toshiba",
1141 &dev->acpi_dev->dev,
1142 dev,
1143 &toshiba_backlight_data,
1144 &props);
1145 if (IS_ERR(dev->backlight_dev)) {
1146 ret = PTR_ERR(dev->backlight_dev);
1147 pr_err("Could not register toshiba backlight device\n");
1148 dev->backlight_dev = NULL;
1149 return ret;
1150 }
1151
1152 dev->backlight_dev->props.brightness = brightness;
1153 return 0;
1154}
1155
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01001156static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05001157{
1158 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
1159
Seth Forshee36d03f92011-09-20 16:55:53 -05001160 remove_toshiba_proc_entries(dev);
Seth Forshee135740d2011-09-20 16:55:49 -05001161
Seth Forshee29cd2932012-01-18 13:44:09 -06001162 if (dev->ntfy_supported) {
1163 i8042_remove_filter(toshiba_acpi_i8042_filter);
1164 cancel_work_sync(&dev->hotkey_work);
1165 }
1166
Seth Forshee135740d2011-09-20 16:55:49 -05001167 if (dev->hotkey_dev) {
1168 input_unregister_device(dev->hotkey_dev);
1169 sparse_keymap_free(dev->hotkey_dev);
1170 }
1171
1172 if (dev->bt_rfk) {
1173 rfkill_unregister(dev->bt_rfk);
1174 rfkill_destroy(dev->bt_rfk);
1175 }
1176
1177 if (dev->backlight_dev)
1178 backlight_device_unregister(dev->backlight_dev);
1179
Seth Forshee36d03f92011-09-20 16:55:53 -05001180 if (dev->illumination_supported)
Seth Forshee135740d2011-09-20 16:55:49 -05001181 led_classdev_unregister(&dev->led_dev);
1182
Seth Forshee29cd2932012-01-18 13:44:09 -06001183 if (toshiba_acpi)
1184 toshiba_acpi = NULL;
1185
Seth Forshee135740d2011-09-20 16:55:49 -05001186 kfree(dev);
1187
1188 return 0;
1189}
1190
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001191static const char *find_hci_method(acpi_handle handle)
Seth Forsheea540d6b2011-09-20 16:55:52 -05001192{
Zhang Ruie2e19602013-09-03 08:32:06 +08001193 if (acpi_has_method(handle, "GHCI"))
Seth Forsheea540d6b2011-09-20 16:55:52 -05001194 return "GHCI";
1195
Zhang Ruie2e19602013-09-03 08:32:06 +08001196 if (acpi_has_method(handle, "SPFC"))
Seth Forsheea540d6b2011-09-20 16:55:52 -05001197 return "SPFC";
1198
1199 return NULL;
1200}
1201
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001202static int toshiba_acpi_add(struct acpi_device *acpi_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05001203{
1204 struct toshiba_acpi_dev *dev;
Seth Forsheea540d6b2011-09-20 16:55:52 -05001205 const char *hci_method;
Seth Forshee36d03f92011-09-20 16:55:53 -05001206 u32 dummy;
Seth Forshee135740d2011-09-20 16:55:49 -05001207 bool bt_present;
1208 int ret = 0;
Seth Forshee135740d2011-09-20 16:55:49 -05001209
Seth Forshee29cd2932012-01-18 13:44:09 -06001210 if (toshiba_acpi)
1211 return -EBUSY;
1212
Seth Forshee135740d2011-09-20 16:55:49 -05001213 pr_info("Toshiba Laptop ACPI Extras version %s\n",
1214 TOSHIBA_ACPI_VERSION);
1215
Seth Forsheea540d6b2011-09-20 16:55:52 -05001216 hci_method = find_hci_method(acpi_dev->handle);
1217 if (!hci_method) {
1218 pr_err("HCI interface not found\n");
Seth Forshee6e02cc72011-09-20 16:55:51 -05001219 return -ENODEV;
Seth Forsheea540d6b2011-09-20 16:55:52 -05001220 }
Seth Forshee6e02cc72011-09-20 16:55:51 -05001221
Seth Forshee135740d2011-09-20 16:55:49 -05001222 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1223 if (!dev)
1224 return -ENOMEM;
1225 dev->acpi_dev = acpi_dev;
Seth Forsheea540d6b2011-09-20 16:55:52 -05001226 dev->method_hci = hci_method;
Seth Forshee135740d2011-09-20 16:55:49 -05001227 acpi_dev->driver_data = dev;
1228
Seth Forshee6e02cc72011-09-20 16:55:51 -05001229 if (toshiba_acpi_setup_keyboard(dev))
1230 pr_info("Unable to activate hotkeys\n");
Seth Forshee135740d2011-09-20 16:55:49 -05001231
1232 mutex_init(&dev->mutex);
1233
Seth Forshee62cce752012-04-19 11:23:50 -05001234 ret = toshiba_acpi_setup_backlight(dev);
1235 if (ret)
Seth Forshee135740d2011-09-20 16:55:49 -05001236 goto error;
Seth Forshee135740d2011-09-20 16:55:49 -05001237
1238 /* Register rfkill switch for Bluetooth */
1239 if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) {
1240 dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth",
1241 &acpi_dev->dev,
1242 RFKILL_TYPE_BLUETOOTH,
1243 &toshiba_rfk_ops,
1244 dev);
1245 if (!dev->bt_rfk) {
1246 pr_err("unable to allocate rfkill device\n");
1247 ret = -ENOMEM;
1248 goto error;
1249 }
1250
1251 ret = rfkill_register(dev->bt_rfk);
1252 if (ret) {
1253 pr_err("unable to register rfkill device\n");
1254 rfkill_destroy(dev->bt_rfk);
1255 goto error;
1256 }
1257 }
1258
1259 if (toshiba_illumination_available(dev)) {
1260 dev->led_dev.name = "toshiba::illumination";
1261 dev->led_dev.max_brightness = 1;
1262 dev->led_dev.brightness_set = toshiba_illumination_set;
1263 dev->led_dev.brightness_get = toshiba_illumination_get;
1264 if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev))
Seth Forshee36d03f92011-09-20 16:55:53 -05001265 dev->illumination_supported = 1;
Seth Forshee135740d2011-09-20 16:55:49 -05001266 }
1267
Seth Forshee36d03f92011-09-20 16:55:53 -05001268 /* Determine whether or not BIOS supports fan and video interfaces */
1269
1270 ret = get_video_status(dev, &dummy);
1271 dev->video_supported = !ret;
1272
1273 ret = get_fan_status(dev, &dummy);
1274 dev->fan_supported = !ret;
1275
1276 create_toshiba_proc_entries(dev);
1277
Seth Forshee29cd2932012-01-18 13:44:09 -06001278 toshiba_acpi = dev;
1279
Seth Forshee135740d2011-09-20 16:55:49 -05001280 return 0;
1281
1282error:
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01001283 toshiba_acpi_remove(acpi_dev);
Seth Forshee135740d2011-09-20 16:55:49 -05001284 return ret;
1285}
1286
1287static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
1288{
1289 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001290 u32 hci_result, value;
Seth Forshee11948b92011-11-16 17:37:45 -06001291 int retries = 3;
Seth Forshee29cd2932012-01-18 13:44:09 -06001292 int scancode;
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001293
Seth Forshee29cd2932012-01-18 13:44:09 -06001294 if (event != 0x80)
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001295 return;
Seth Forshee11948b92011-11-16 17:37:45 -06001296
Seth Forshee29cd2932012-01-18 13:44:09 -06001297 if (dev->info_supported) {
1298 scancode = toshiba_acpi_query_hotkey(dev);
1299 if (scancode < 0)
1300 pr_err("Failed to query hotkey event\n");
1301 else if (scancode != 0)
1302 toshiba_acpi_report_hotkey(dev, scancode);
1303 } else if (dev->system_event_supported) {
1304 do {
1305 hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
1306 switch (hci_result) {
1307 case HCI_SUCCESS:
1308 toshiba_acpi_report_hotkey(dev, (int)value);
1309 break;
1310 case HCI_NOT_SUPPORTED:
1311 /*
1312 * This is a workaround for an unresolved
1313 * issue on some machines where system events
1314 * sporadically become disabled.
1315 */
1316 hci_write1(dev, HCI_SYSTEM_EVENT, 1,
1317 &hci_result);
1318 pr_notice("Re-enabled hotkeys\n");
1319 /* fall through */
1320 default:
1321 retries--;
1322 break;
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001323 }
Seth Forshee29cd2932012-01-18 13:44:09 -06001324 } while (retries && hci_result != HCI_EMPTY);
1325 }
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001326}
1327
Rafael J. Wysocki3567a4e22012-08-09 23:00:13 +02001328#ifdef CONFIG_PM_SLEEP
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001329static int toshiba_acpi_suspend(struct device *device)
Seth Forshee29cd2932012-01-18 13:44:09 -06001330{
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001331 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
Seth Forshee29cd2932012-01-18 13:44:09 -06001332 u32 result;
1333
1334 if (dev->hotkey_dev)
1335 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE, &result);
1336
1337 return 0;
1338}
1339
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001340static int toshiba_acpi_resume(struct device *device)
Seth Forshee29cd2932012-01-18 13:44:09 -06001341{
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001342 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
Seth Forshee29cd2932012-01-18 13:44:09 -06001343 u32 result;
1344
1345 if (dev->hotkey_dev)
1346 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
1347
1348 return 0;
1349}
Rafael J. Wysocki3567a4e22012-08-09 23:00:13 +02001350#endif
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001351
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001352static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
1353 toshiba_acpi_suspend, toshiba_acpi_resume);
1354
Seth Forshee135740d2011-09-20 16:55:49 -05001355static struct acpi_driver toshiba_acpi_driver = {
1356 .name = "Toshiba ACPI driver",
1357 .owner = THIS_MODULE,
1358 .ids = toshiba_device_ids,
1359 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
1360 .ops = {
1361 .add = toshiba_acpi_add,
1362 .remove = toshiba_acpi_remove,
1363 .notify = toshiba_acpi_notify,
1364 },
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001365 .drv.pm = &toshiba_acpi_pm,
Seth Forshee135740d2011-09-20 16:55:49 -05001366};
Holger Machtc9263552006-10-20 14:30:29 -07001367
Len Brown4be44fc2005-08-05 00:44:28 -04001368static int __init toshiba_acpi_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369{
Seth Forshee135740d2011-09-20 16:55:49 -05001370 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Seth Forsheef11f9992012-01-18 13:44:11 -06001372 /*
1373 * Machines with this WMI guid aren't supported due to bugs in
1374 * their AML. This check relies on wmi initializing before
1375 * toshiba_acpi to guarantee guids have been identified.
1376 */
1377 if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
1378 return -ENODEV;
1379
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
1381 if (!toshiba_proc_dir) {
Seth Forshee135740d2011-09-20 16:55:49 -05001382 pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001383 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 }
1385
Seth Forshee135740d2011-09-20 16:55:49 -05001386 ret = acpi_bus_register_driver(&toshiba_acpi_driver);
1387 if (ret) {
1388 pr_err("Failed to register ACPI driver: %d\n", ret);
1389 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
Holger Machtc9263552006-10-20 14:30:29 -07001390 }
1391
Seth Forshee135740d2011-09-20 16:55:49 -05001392 return ret;
1393}
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001394
Seth Forshee135740d2011-09-20 16:55:49 -05001395static void __exit toshiba_acpi_exit(void)
1396{
1397 acpi_bus_unregister_driver(&toshiba_acpi_driver);
1398 if (toshiba_proc_dir)
1399 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400}
1401
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402module_init(toshiba_acpi_init);
1403module_exit(toshiba_acpi_exit);