xref: /linux/drivers/platform/x86/toshiba_acpi.c (revision c8a41669a76381f655f5567d3ccd8449a53f9a7f)
1b4f9fe12SLen Brown /*
2b4f9fe12SLen Brown  *  toshiba_acpi.c - Toshiba Laptop ACPI Extras
3b4f9fe12SLen Brown  *
4b4f9fe12SLen Brown  *
5b4f9fe12SLen Brown  *  Copyright (C) 2002-2004 John Belmonte
6b4f9fe12SLen Brown  *  Copyright (C) 2008 Philip Langdale
76c3f6e6cSPierre Ducroquet  *  Copyright (C) 2010 Pierre Ducroquet
8548c4306SAzael Avalos  *  Copyright (C) 2014 Azael Avalos
9b4f9fe12SLen Brown  *
10b4f9fe12SLen Brown  *  This program is free software; you can redistribute it and/or modify
11b4f9fe12SLen Brown  *  it under the terms of the GNU General Public License as published by
12b4f9fe12SLen Brown  *  the Free Software Foundation; either version 2 of the License, or
13b4f9fe12SLen Brown  *  (at your option) any later version.
14b4f9fe12SLen Brown  *
15b4f9fe12SLen Brown  *  This program is distributed in the hope that it will be useful,
16b4f9fe12SLen Brown  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17b4f9fe12SLen Brown  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18b4f9fe12SLen Brown  *  GNU General Public License for more details.
19b4f9fe12SLen Brown  *
20b4f9fe12SLen Brown  *  You should have received a copy of the GNU General Public License
21b4f9fe12SLen Brown  *  along with this program; if not, write to the Free Software
22b4f9fe12SLen Brown  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23b4f9fe12SLen Brown  *
24b4f9fe12SLen Brown  *
25b4f9fe12SLen Brown  *  The devolpment page for this driver is located at
26b4f9fe12SLen Brown  *  http://memebeam.org/toys/ToshibaAcpiDriver.
27b4f9fe12SLen Brown  *
28b4f9fe12SLen Brown  *  Credits:
29b4f9fe12SLen Brown  *	Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
30b4f9fe12SLen Brown  *		engineering the Windows drivers
31b4f9fe12SLen Brown  *	Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
32b4f9fe12SLen Brown  *	Rob Miller - TV out and hotkeys help
33b4f9fe12SLen Brown  *
34b4f9fe12SLen Brown  *
35b4f9fe12SLen Brown  *  TODO
36b4f9fe12SLen Brown  *
37b4f9fe12SLen Brown  */
38b4f9fe12SLen Brown 
397e33460dSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
407e33460dSJoe Perches 
41548c4306SAzael Avalos #define TOSHIBA_ACPI_VERSION	"0.20"
42b4f9fe12SLen Brown #define PROC_INTERFACE_VERSION	1
43b4f9fe12SLen Brown 
44b4f9fe12SLen Brown #include <linux/kernel.h>
45b4f9fe12SLen Brown #include <linux/module.h>
46b4f9fe12SLen Brown #include <linux/init.h>
47b4f9fe12SLen Brown #include <linux/types.h>
48b4f9fe12SLen Brown #include <linux/proc_fs.h>
49936c8bcdSAlexey Dobriyan #include <linux/seq_file.h>
50b4f9fe12SLen Brown #include <linux/backlight.h>
51b4f9fe12SLen Brown #include <linux/rfkill.h>
526335e4d5SMatthew Garrett #include <linux/input.h>
53384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h>
546c3f6e6cSPierre Ducroquet #include <linux/leds.h>
555a0e3ad6STejun Heo #include <linux/slab.h>
5629cd293fSSeth Forshee #include <linux/workqueue.h>
5729cd293fSSeth Forshee #include <linux/i8042.h>
588b48463fSLv Zheng #include <linux/acpi.h>
59fe808bfbSTakashi Iwai #include <linux/dmi.h>
60b4f9fe12SLen Brown #include <asm/uaccess.h>
61b4f9fe12SLen Brown 
62b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte");
63b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
64b4f9fe12SLen Brown MODULE_LICENSE("GPL");
65b4f9fe12SLen Brown 
66f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
67f11f999eSSeth Forshee 
6829cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */
6929cd293fSSeth Forshee #define TOS1900_FN_SCAN		0x6e
7029cd293fSSeth Forshee 
71b4f9fe12SLen Brown /* Toshiba ACPI method paths */
72b4f9fe12SLen Brown #define METHOD_VIDEO_OUT	"\\_SB_.VALX.DSSX"
73b4f9fe12SLen Brown 
74b4f9fe12SLen Brown /* Toshiba HCI interface definitions
75b4f9fe12SLen Brown  *
76b4f9fe12SLen Brown  * HCI is Toshiba's "Hardware Control Interface" which is supposed to
77b4f9fe12SLen Brown  * be uniform across all their models.  Ideally we would just call
78b4f9fe12SLen Brown  * dedicated ACPI methods instead of using this primitive interface.
79b4f9fe12SLen Brown  * However the ACPI methods seem to be incomplete in some areas (for
80b4f9fe12SLen Brown  * example they allow setting, but not reading, the LCD brightness value),
81b4f9fe12SLen Brown  * so this is still useful.
8284a6273fSAzael Avalos  *
8384a6273fSAzael Avalos  * SCI stands for "System Configuration Interface" which aim is to
8484a6273fSAzael Avalos  * conceal differences in hardware between different models.
85b4f9fe12SLen Brown  */
86b4f9fe12SLen Brown 
87b4f9fe12SLen Brown #define HCI_WORDS			6
88b4f9fe12SLen Brown 
89b4f9fe12SLen Brown /* operations */
90b4f9fe12SLen Brown #define HCI_SET				0xff00
91b4f9fe12SLen Brown #define HCI_GET				0xfe00
9284a6273fSAzael Avalos #define SCI_OPEN			0xf100
9384a6273fSAzael Avalos #define SCI_CLOSE			0xf200
9484a6273fSAzael Avalos #define SCI_GET				0xf300
9584a6273fSAzael Avalos #define SCI_SET				0xf400
96b4f9fe12SLen Brown 
97b4f9fe12SLen Brown /* return codes */
98b4f9fe12SLen Brown #define HCI_SUCCESS			0x0000
99b4f9fe12SLen Brown #define HCI_FAILURE			0x1000
100b4f9fe12SLen Brown #define HCI_NOT_SUPPORTED		0x8000
101b4f9fe12SLen Brown #define HCI_EMPTY			0x8c00
1025a2813e9SAzael Avalos #define HCI_DATA_NOT_AVAILABLE		0x8d20
1035a2813e9SAzael Avalos #define HCI_NOT_INITIALIZED		0x8d50
10484a6273fSAzael Avalos #define SCI_OPEN_CLOSE_OK		0x0044
10584a6273fSAzael Avalos #define SCI_ALREADY_OPEN		0x8100
10684a6273fSAzael Avalos #define SCI_NOT_OPENED			0x8200
107fdb79081SAzael Avalos #define SCI_INPUT_DATA_ERROR		0x8300
10884a6273fSAzael Avalos #define SCI_NOT_PRESENT			0x8600
109b4f9fe12SLen Brown 
110b4f9fe12SLen Brown /* registers */
111b4f9fe12SLen Brown #define HCI_FAN				0x0004
112121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT		0x0005
113b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT		0x0016
114b4f9fe12SLen Brown #define HCI_VIDEO_OUT			0x001c
115b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT		0x001e
116b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS		0x002a
117b4f9fe12SLen Brown #define HCI_WIRELESS			0x0056
1185a2813e9SAzael Avalos #define HCI_ACCELEROMETER		0x006d
119360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION		0x0095
120def6c4e2SAzael Avalos #define HCI_ECO_MODE			0x0097
1215a2813e9SAzael Avalos #define HCI_ACCELEROMETER2		0x00a6
122fdb79081SAzael Avalos #define SCI_ILLUMINATION		0x014e
123360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS		0x015c
1249d8658acSAzael Avalos #define SCI_TOUCHPAD			0x050e
125b4f9fe12SLen Brown 
126b4f9fe12SLen Brown /* field definitions */
1275a2813e9SAzael Avalos #define HCI_ACCEL_MASK			0x7fff
12829cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE		0x0b
12929cd293fSSeth Forshee #define HCI_HOTKEY_ENABLE		0x09
130b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS		3
131b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT	(16-HCI_LCD_BRIGHTNESS_BITS)
132b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS	(1 << HCI_LCD_BRIGHTNESS_BITS)
133360f0f39SAzael Avalos #define HCI_MISC_SHIFT			0x10
134b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD		0x1
135b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT		0x2
136b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV		0x4
137b4f9fe12SLen Brown #define HCI_WIRELESS_KILL_SWITCH	0x01
138b4f9fe12SLen Brown #define HCI_WIRELESS_BT_PRESENT		0x0f
139b4f9fe12SLen Brown #define HCI_WIRELESS_BT_ATTACH		0x40
140b4f9fe12SLen Brown #define HCI_WIRELESS_BT_POWER		0x80
141360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ		0x1
142360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO		0x2
143b4f9fe12SLen Brown 
144135740deSSeth Forshee struct toshiba_acpi_dev {
145135740deSSeth Forshee 	struct acpi_device *acpi_dev;
146135740deSSeth Forshee 	const char *method_hci;
147135740deSSeth Forshee 	struct rfkill *bt_rfk;
148135740deSSeth Forshee 	struct input_dev *hotkey_dev;
14929cd293fSSeth Forshee 	struct work_struct hotkey_work;
150135740deSSeth Forshee 	struct backlight_device *backlight_dev;
151135740deSSeth Forshee 	struct led_classdev led_dev;
152360f0f39SAzael Avalos 	struct led_classdev kbd_led;
153def6c4e2SAzael Avalos 	struct led_classdev eco_led;
15436d03f93SSeth Forshee 
155135740deSSeth Forshee 	int force_fan;
156135740deSSeth Forshee 	int last_key_event;
157135740deSSeth Forshee 	int key_event_valid;
158360f0f39SAzael Avalos 	int kbd_mode;
159360f0f39SAzael Avalos 	int kbd_time;
160135740deSSeth Forshee 
161592b746cSDan Carpenter 	unsigned int illumination_supported:1;
162592b746cSDan Carpenter 	unsigned int video_supported:1;
163592b746cSDan Carpenter 	unsigned int fan_supported:1;
164592b746cSDan Carpenter 	unsigned int system_event_supported:1;
16529cd293fSSeth Forshee 	unsigned int ntfy_supported:1;
16629cd293fSSeth Forshee 	unsigned int info_supported:1;
167121b7b0dSAkio Idehara 	unsigned int tr_backlight_supported:1;
168360f0f39SAzael Avalos 	unsigned int kbd_illum_supported:1;
169360f0f39SAzael Avalos 	unsigned int kbd_led_registered:1;
1709d8658acSAzael Avalos 	unsigned int touchpad_supported:1;
171def6c4e2SAzael Avalos 	unsigned int eco_supported:1;
1725a2813e9SAzael Avalos 	unsigned int accelerometer_supported:1;
173360f0f39SAzael Avalos 	unsigned int sysfs_created:1;
17436d03f93SSeth Forshee 
175135740deSSeth Forshee 	struct mutex mutex;
176135740deSSeth Forshee };
177135740deSSeth Forshee 
17829cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi;
17929cd293fSSeth Forshee 
180b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = {
181b4f9fe12SLen Brown 	{"TOS6200", 0},
182b4f9fe12SLen Brown 	{"TOS6208", 0},
183b4f9fe12SLen Brown 	{"TOS1900", 0},
184b4f9fe12SLen Brown 	{"", 0},
185b4f9fe12SLen Brown };
186b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
187b4f9fe12SLen Brown 
188b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = {
189fec278a1SUnai Uribarri 	{ KE_KEY, 0x9e, { KEY_RFKILL } },
190384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x101, { KEY_MUTE } },
191384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
192384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x103, { KEY_ZOOMIN } },
193408a5d13SAzael Avalos 	{ KE_KEY, 0x10f, { KEY_TAB } },
194af502837SAzael Avalos 	{ KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
195af502837SAzael Avalos 	{ KE_KEY, 0x139, { KEY_ZOOMRESET } },
196384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x13b, { KEY_COFFEE } },
197384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x13c, { KEY_BATTERY } },
198384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x13d, { KEY_SLEEP } },
199384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x13e, { KEY_SUSPEND } },
200384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
201384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
202384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
203384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x142, { KEY_WLAN } },
204af502837SAzael Avalos 	{ KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
205a49010f5SJon Dowland 	{ KE_KEY, 0x17f, { KEY_FN } },
206384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb05, { KEY_PROG2 } },
207384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb06, { KEY_WWW } },
208384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb07, { KEY_MAIL } },
209384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb30, { KEY_STOP } },
210384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
211384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb32, { KEY_NEXTSONG } },
212384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
213384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb5a, { KEY_MEDIA } },
214408a5d13SAzael Avalos 	{ KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */
215408a5d13SAzael Avalos 	{ KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */
216408a5d13SAzael Avalos 	{ KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */
217408a5d13SAzael Avalos 	{ KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */
218408a5d13SAzael Avalos 	{ KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */
219384a7cd9SDmitry Torokhov 	{ KE_END, 0 },
2206335e4d5SMatthew Garrett };
2216335e4d5SMatthew Garrett 
222fe808bfbSTakashi Iwai /* alternative keymap */
223fe808bfbSTakashi Iwai static const struct dmi_system_id toshiba_alt_keymap_dmi[] = {
224fe808bfbSTakashi Iwai 	{
225fe808bfbSTakashi Iwai 		.matches = {
226fe808bfbSTakashi Iwai 			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
227fe808bfbSTakashi Iwai 			DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"),
228fe808bfbSTakashi Iwai 		},
229fe808bfbSTakashi Iwai 	},
230e6efad7fSAzael Avalos 	{
231e6efad7fSAzael Avalos 		.matches = {
232e6efad7fSAzael Avalos 			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
233e6efad7fSAzael Avalos 			DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"),
234e6efad7fSAzael Avalos 		},
235e6efad7fSAzael Avalos 	},
236fe808bfbSTakashi Iwai 	{}
237fe808bfbSTakashi Iwai };
238fe808bfbSTakashi Iwai 
239fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = {
240fe808bfbSTakashi Iwai 	{ KE_KEY, 0x157, { KEY_MUTE } },
241fe808bfbSTakashi Iwai 	{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
242fe808bfbSTakashi Iwai 	{ KE_KEY, 0x103, { KEY_ZOOMIN } },
243e6efad7fSAzael Avalos 	{ KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
244fe808bfbSTakashi Iwai 	{ KE_KEY, 0x139, { KEY_ZOOMRESET } },
245fe808bfbSTakashi Iwai 	{ KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
246fe808bfbSTakashi Iwai 	{ KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
247fe808bfbSTakashi Iwai 	{ KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } },
248fe808bfbSTakashi Iwai 	{ KE_KEY, 0x158, { KEY_WLAN } },
249fe808bfbSTakashi Iwai 	{ KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } },
250fe808bfbSTakashi Iwai 	{ KE_END, 0 },
251fe808bfbSTakashi Iwai };
252fe808bfbSTakashi Iwai 
253b4f9fe12SLen Brown /* utility
254b4f9fe12SLen Brown  */
255b4f9fe12SLen Brown 
256b4f9fe12SLen Brown static __inline__ void _set_bit(u32 * word, u32 mask, int value)
257b4f9fe12SLen Brown {
258b4f9fe12SLen Brown 	*word = (*word & ~mask) | (mask * value);
259b4f9fe12SLen Brown }
260b4f9fe12SLen Brown 
261b4f9fe12SLen Brown /* acpi interface wrappers
262b4f9fe12SLen Brown  */
263b4f9fe12SLen Brown 
264b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val)
265b4f9fe12SLen Brown {
266b4f9fe12SLen Brown 	acpi_status status;
267b4f9fe12SLen Brown 
268619400daSZhang Rui 	status = acpi_execute_simple_method(NULL, (char *)methodName, val);
26932bcd5cbSSeth Forshee 	return (status == AE_OK) ? 0 : -EIO;
270b4f9fe12SLen Brown }
271b4f9fe12SLen Brown 
272b4f9fe12SLen Brown /* Perform a raw HCI call.  Here we don't care about input or output buffer
273b4f9fe12SLen Brown  * format.
274b4f9fe12SLen Brown  */
275135740deSSeth Forshee static acpi_status hci_raw(struct toshiba_acpi_dev *dev,
276135740deSSeth Forshee 			   const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
277b4f9fe12SLen Brown {
278b4f9fe12SLen Brown 	struct acpi_object_list params;
279b4f9fe12SLen Brown 	union acpi_object in_objs[HCI_WORDS];
280b4f9fe12SLen Brown 	struct acpi_buffer results;
281b4f9fe12SLen Brown 	union acpi_object out_objs[HCI_WORDS + 1];
282b4f9fe12SLen Brown 	acpi_status status;
283b4f9fe12SLen Brown 	int i;
284b4f9fe12SLen Brown 
285b4f9fe12SLen Brown 	params.count = HCI_WORDS;
286b4f9fe12SLen Brown 	params.pointer = in_objs;
287b4f9fe12SLen Brown 	for (i = 0; i < HCI_WORDS; ++i) {
288b4f9fe12SLen Brown 		in_objs[i].type = ACPI_TYPE_INTEGER;
289b4f9fe12SLen Brown 		in_objs[i].integer.value = in[i];
290b4f9fe12SLen Brown 	}
291b4f9fe12SLen Brown 
292b4f9fe12SLen Brown 	results.length = sizeof(out_objs);
293b4f9fe12SLen Brown 	results.pointer = out_objs;
294b4f9fe12SLen Brown 
2956e02cc7eSSeth Forshee 	status = acpi_evaluate_object(dev->acpi_dev->handle,
2966e02cc7eSSeth Forshee 				      (char *)dev->method_hci, &params,
297b4f9fe12SLen Brown 				      &results);
298b4f9fe12SLen Brown 	if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) {
299b4f9fe12SLen Brown 		for (i = 0; i < out_objs->package.count; ++i) {
300b4f9fe12SLen Brown 			out[i] = out_objs->package.elements[i].integer.value;
301b4f9fe12SLen Brown 		}
302b4f9fe12SLen Brown 	}
303b4f9fe12SLen Brown 
304b4f9fe12SLen Brown 	return status;
305b4f9fe12SLen Brown }
306b4f9fe12SLen Brown 
307b4f9fe12SLen Brown /* common hci tasks (get or set one or two value)
308b4f9fe12SLen Brown  *
309b4f9fe12SLen Brown  * In addition to the ACPI status, the HCI system returns a result which
310b4f9fe12SLen Brown  * may be useful (such as "not supported").
311b4f9fe12SLen Brown  */
312b4f9fe12SLen Brown 
313135740deSSeth Forshee static acpi_status hci_write1(struct toshiba_acpi_dev *dev, u32 reg,
314135740deSSeth Forshee 			      u32 in1, u32 *result)
315b4f9fe12SLen Brown {
316b4f9fe12SLen Brown 	u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
317b4f9fe12SLen Brown 	u32 out[HCI_WORDS];
318135740deSSeth Forshee 	acpi_status status = hci_raw(dev, in, out);
319b4f9fe12SLen Brown 	*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
320b4f9fe12SLen Brown 	return status;
321b4f9fe12SLen Brown }
322b4f9fe12SLen Brown 
323135740deSSeth Forshee static acpi_status hci_read1(struct toshiba_acpi_dev *dev, u32 reg,
324135740deSSeth Forshee 			     u32 *out1, u32 *result)
325b4f9fe12SLen Brown {
326b4f9fe12SLen Brown 	u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
327b4f9fe12SLen Brown 	u32 out[HCI_WORDS];
328135740deSSeth Forshee 	acpi_status status = hci_raw(dev, in, out);
329b4f9fe12SLen Brown 	*out1 = out[2];
330b4f9fe12SLen Brown 	*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
331b4f9fe12SLen Brown 	return status;
332b4f9fe12SLen Brown }
333b4f9fe12SLen Brown 
334135740deSSeth Forshee static acpi_status hci_write2(struct toshiba_acpi_dev *dev, u32 reg,
335135740deSSeth Forshee 			      u32 in1, u32 in2, u32 *result)
336b4f9fe12SLen Brown {
337b4f9fe12SLen Brown 	u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
338b4f9fe12SLen Brown 	u32 out[HCI_WORDS];
339135740deSSeth Forshee 	acpi_status status = hci_raw(dev, in, out);
340b4f9fe12SLen Brown 	*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
341b4f9fe12SLen Brown 	return status;
342b4f9fe12SLen Brown }
343b4f9fe12SLen Brown 
344135740deSSeth Forshee static acpi_status hci_read2(struct toshiba_acpi_dev *dev, u32 reg,
345135740deSSeth Forshee 			     u32 *out1, u32 *out2, u32 *result)
346b4f9fe12SLen Brown {
347b4f9fe12SLen Brown 	u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
348b4f9fe12SLen Brown 	u32 out[HCI_WORDS];
349135740deSSeth Forshee 	acpi_status status = hci_raw(dev, in, out);
350b4f9fe12SLen Brown 	*out1 = out[2];
351b4f9fe12SLen Brown 	*out2 = out[3];
352b4f9fe12SLen Brown 	*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
353b4f9fe12SLen Brown 	return status;
354b4f9fe12SLen Brown }
355b4f9fe12SLen Brown 
35684a6273fSAzael Avalos /* common sci tasks
35784a6273fSAzael Avalos  */
35884a6273fSAzael Avalos 
35984a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev)
36084a6273fSAzael Avalos {
36184a6273fSAzael Avalos 	u32 in[HCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
36284a6273fSAzael Avalos 	u32 out[HCI_WORDS];
36384a6273fSAzael Avalos 	acpi_status status;
36484a6273fSAzael Avalos 
36584a6273fSAzael Avalos 	status = hci_raw(dev, in, out);
36684a6273fSAzael Avalos 	if  (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
36784a6273fSAzael Avalos 		pr_err("ACPI call to open SCI failed\n");
36884a6273fSAzael Avalos 		return 0;
36984a6273fSAzael Avalos 	}
37084a6273fSAzael Avalos 
37184a6273fSAzael Avalos 	if (out[0] == SCI_OPEN_CLOSE_OK) {
37284a6273fSAzael Avalos 		return 1;
37384a6273fSAzael Avalos 	} else if (out[0] == SCI_ALREADY_OPEN) {
37484a6273fSAzael Avalos 		pr_info("Toshiba SCI already opened\n");
37584a6273fSAzael Avalos 		return 1;
37684a6273fSAzael Avalos 	} else if (out[0] == SCI_NOT_PRESENT) {
37784a6273fSAzael Avalos 		pr_info("Toshiba SCI is not present\n");
37884a6273fSAzael Avalos 	}
37984a6273fSAzael Avalos 
38084a6273fSAzael Avalos 	return 0;
38184a6273fSAzael Avalos }
38284a6273fSAzael Avalos 
38384a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev)
38484a6273fSAzael Avalos {
38584a6273fSAzael Avalos 	u32 in[HCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
38684a6273fSAzael Avalos 	u32 out[HCI_WORDS];
38784a6273fSAzael Avalos 	acpi_status status;
38884a6273fSAzael Avalos 
38984a6273fSAzael Avalos 	status = hci_raw(dev, in, out);
39084a6273fSAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
39184a6273fSAzael Avalos 		pr_err("ACPI call to close SCI failed\n");
39284a6273fSAzael Avalos 		return;
39384a6273fSAzael Avalos 	}
39484a6273fSAzael Avalos 
39584a6273fSAzael Avalos 	if (out[0] == SCI_OPEN_CLOSE_OK)
39684a6273fSAzael Avalos 		return;
39784a6273fSAzael Avalos 	else if (out[0] == SCI_NOT_OPENED)
39884a6273fSAzael Avalos 		pr_info("Toshiba SCI not opened\n");
39984a6273fSAzael Avalos 	else if (out[0] == SCI_NOT_PRESENT)
40084a6273fSAzael Avalos 		pr_info("Toshiba SCI is not present\n");
40184a6273fSAzael Avalos }
40284a6273fSAzael Avalos 
40384a6273fSAzael Avalos static acpi_status sci_read(struct toshiba_acpi_dev *dev, u32 reg,
40484a6273fSAzael Avalos 			    u32 *out1, u32 *result)
40584a6273fSAzael Avalos {
40684a6273fSAzael Avalos 	u32 in[HCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
40784a6273fSAzael Avalos 	u32 out[HCI_WORDS];
40884a6273fSAzael Avalos 	acpi_status status = hci_raw(dev, in, out);
40984a6273fSAzael Avalos 	*out1 = out[2];
41084a6273fSAzael Avalos 	*result = (ACPI_SUCCESS(status)) ? out[0] : HCI_FAILURE;
41184a6273fSAzael Avalos 	return status;
41284a6273fSAzael Avalos }
41384a6273fSAzael Avalos 
41484a6273fSAzael Avalos static acpi_status sci_write(struct toshiba_acpi_dev *dev, u32 reg,
41584a6273fSAzael Avalos 			     u32 in1, u32 *result)
41684a6273fSAzael Avalos {
41784a6273fSAzael Avalos 	u32 in[HCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
41884a6273fSAzael Avalos 	u32 out[HCI_WORDS];
41984a6273fSAzael Avalos 	acpi_status status = hci_raw(dev, in, out);
42084a6273fSAzael Avalos 	*result = (ACPI_SUCCESS(status)) ? out[0] : HCI_FAILURE;
42184a6273fSAzael Avalos 	return status;
42284a6273fSAzael Avalos }
42384a6273fSAzael Avalos 
4246c3f6e6cSPierre Ducroquet /* Illumination support */
425135740deSSeth Forshee static int toshiba_illumination_available(struct toshiba_acpi_dev *dev)
4266c3f6e6cSPierre Ducroquet {
427fdb79081SAzael Avalos 	u32 in[HCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
4286c3f6e6cSPierre Ducroquet 	u32 out[HCI_WORDS];
4296c3f6e6cSPierre Ducroquet 	acpi_status status;
4306c3f6e6cSPierre Ducroquet 
431fdb79081SAzael Avalos 	if (!sci_open(dev))
432fdb79081SAzael Avalos 		return 0;
433fdb79081SAzael Avalos 
434135740deSSeth Forshee 	status = hci_raw(dev, in, out);
435fdb79081SAzael Avalos 	sci_close(dev);
436fdb79081SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
437fdb79081SAzael Avalos 		pr_err("ACPI call to query Illumination support failed\n");
438fdb79081SAzael Avalos 		return 0;
43912962878SAzael Avalos 	} else if (out[0] == HCI_NOT_SUPPORTED) {
4407e33460dSJoe Perches 		pr_info("Illumination device not available\n");
4416c3f6e6cSPierre Ducroquet 		return 0;
4426c3f6e6cSPierre Ducroquet 	}
443fdb79081SAzael Avalos 
4446c3f6e6cSPierre Ducroquet 	return 1;
4456c3f6e6cSPierre Ducroquet }
4466c3f6e6cSPierre Ducroquet 
4476c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev,
4486c3f6e6cSPierre Ducroquet 				     enum led_brightness brightness)
4496c3f6e6cSPierre Ducroquet {
450135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = container_of(cdev,
451135740deSSeth Forshee 			struct toshiba_acpi_dev, led_dev);
452fdb79081SAzael Avalos 	u32 state, result;
4536c3f6e6cSPierre Ducroquet 	acpi_status status;
4546c3f6e6cSPierre Ducroquet 
4556c3f6e6cSPierre Ducroquet 	/* First request : initialize communication. */
456fdb79081SAzael Avalos 	if (!sci_open(dev))
4576c3f6e6cSPierre Ducroquet 		return;
4586c3f6e6cSPierre Ducroquet 
459fdb79081SAzael Avalos 	/* Switch the illumination on/off */
460fdb79081SAzael Avalos 	state = brightness ? 1 : 0;
461fdb79081SAzael Avalos 	status = sci_write(dev, SCI_ILLUMINATION, state, &result);
462fdb79081SAzael Avalos 	sci_close(dev);
4636c3f6e6cSPierre Ducroquet 	if (ACPI_FAILURE(status)) {
464fdb79081SAzael Avalos 		pr_err("ACPI call for illumination failed\n");
465fdb79081SAzael Avalos 		return;
466fdb79081SAzael Avalos 	} else if (result == HCI_NOT_SUPPORTED) {
467fdb79081SAzael Avalos 		pr_info("Illumination not supported\n");
4686c3f6e6cSPierre Ducroquet 		return;
4696c3f6e6cSPierre Ducroquet 	}
4706c3f6e6cSPierre Ducroquet }
4716c3f6e6cSPierre Ducroquet 
4726c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
4736c3f6e6cSPierre Ducroquet {
474135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = container_of(cdev,
475135740deSSeth Forshee 			struct toshiba_acpi_dev, led_dev);
476fdb79081SAzael Avalos 	u32 state, result;
4776c3f6e6cSPierre Ducroquet 	acpi_status status;
4786c3f6e6cSPierre Ducroquet 
4796c3f6e6cSPierre Ducroquet 	/* First request : initialize communication. */
480fdb79081SAzael Avalos 	if (!sci_open(dev))
4816c3f6e6cSPierre Ducroquet 		return LED_OFF;
4826c3f6e6cSPierre Ducroquet 
4836c3f6e6cSPierre Ducroquet 	/* Check the illumination */
484fdb79081SAzael Avalos 	status = sci_read(dev, SCI_ILLUMINATION, &state, &result);
485fdb79081SAzael Avalos 	sci_close(dev);
486fdb79081SAzael Avalos 	if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
487fdb79081SAzael Avalos 		pr_err("ACPI call for illumination failed\n");
488fdb79081SAzael Avalos 		return LED_OFF;
489fdb79081SAzael Avalos 	} else if (result == HCI_NOT_SUPPORTED) {
490fdb79081SAzael Avalos 		pr_info("Illumination not supported\n");
4916c3f6e6cSPierre Ducroquet 		return LED_OFF;
4926c3f6e6cSPierre Ducroquet 	}
4936c3f6e6cSPierre Ducroquet 
494fdb79081SAzael Avalos 	return state ? LED_FULL : LED_OFF;
4956c3f6e6cSPierre Ducroquet }
4966c3f6e6cSPierre Ducroquet 
497360f0f39SAzael Avalos /* KBD Illumination */
498360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
499360f0f39SAzael Avalos {
500360f0f39SAzael Avalos 	u32 result;
501360f0f39SAzael Avalos 	acpi_status status;
502360f0f39SAzael Avalos 
503360f0f39SAzael Avalos 	if (!sci_open(dev))
504360f0f39SAzael Avalos 		return -EIO;
505360f0f39SAzael Avalos 
506360f0f39SAzael Avalos 	status = sci_write(dev, SCI_KBD_ILLUM_STATUS, time, &result);
507360f0f39SAzael Avalos 	sci_close(dev);
508360f0f39SAzael Avalos 	if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
509360f0f39SAzael Avalos 		pr_err("ACPI call to set KBD backlight status failed\n");
510360f0f39SAzael Avalos 		return -EIO;
511360f0f39SAzael Avalos 	} else if (result == HCI_NOT_SUPPORTED) {
512360f0f39SAzael Avalos 		pr_info("Keyboard backlight status not supported\n");
513360f0f39SAzael Avalos 		return -ENODEV;
514360f0f39SAzael Avalos 	}
515360f0f39SAzael Avalos 
516360f0f39SAzael Avalos 	return 0;
517360f0f39SAzael Avalos }
518360f0f39SAzael Avalos 
519360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
520360f0f39SAzael Avalos {
521360f0f39SAzael Avalos 	u32 result;
522360f0f39SAzael Avalos 	acpi_status status;
523360f0f39SAzael Avalos 
524360f0f39SAzael Avalos 	if (!sci_open(dev))
525360f0f39SAzael Avalos 		return -EIO;
526360f0f39SAzael Avalos 
527360f0f39SAzael Avalos 	status = sci_read(dev, SCI_KBD_ILLUM_STATUS, time, &result);
528360f0f39SAzael Avalos 	sci_close(dev);
529360f0f39SAzael Avalos 	if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
530360f0f39SAzael Avalos 		pr_err("ACPI call to get KBD backlight status failed\n");
531360f0f39SAzael Avalos 		return -EIO;
532360f0f39SAzael Avalos 	} else if (result == HCI_NOT_SUPPORTED) {
533360f0f39SAzael Avalos 		pr_info("Keyboard backlight status not supported\n");
534360f0f39SAzael Avalos 		return -ENODEV;
535360f0f39SAzael Avalos 	}
536360f0f39SAzael Avalos 
537360f0f39SAzael Avalos 	return 0;
538360f0f39SAzael Avalos }
539360f0f39SAzael Avalos 
540360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
541360f0f39SAzael Avalos {
542360f0f39SAzael Avalos 	struct toshiba_acpi_dev *dev = container_of(cdev,
543360f0f39SAzael Avalos 			struct toshiba_acpi_dev, kbd_led);
544360f0f39SAzael Avalos 	u32 state, result;
545360f0f39SAzael Avalos 	acpi_status status;
546360f0f39SAzael Avalos 
547360f0f39SAzael Avalos 	/* Check the keyboard backlight state */
548360f0f39SAzael Avalos 	status = hci_read1(dev, HCI_KBD_ILLUMINATION, &state, &result);
549360f0f39SAzael Avalos 	if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
550360f0f39SAzael Avalos 		pr_err("ACPI call to get the keyboard backlight failed\n");
551360f0f39SAzael Avalos 		return LED_OFF;
552360f0f39SAzael Avalos 	} else if (result == HCI_NOT_SUPPORTED) {
553360f0f39SAzael Avalos 		pr_info("Keyboard backlight not supported\n");
554360f0f39SAzael Avalos 		return LED_OFF;
555360f0f39SAzael Avalos 	}
556360f0f39SAzael Avalos 
557360f0f39SAzael Avalos 	return state ? LED_FULL : LED_OFF;
558360f0f39SAzael Avalos }
559360f0f39SAzael Avalos 
560360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
561360f0f39SAzael Avalos 				     enum led_brightness brightness)
562360f0f39SAzael Avalos {
563360f0f39SAzael Avalos 	struct toshiba_acpi_dev *dev = container_of(cdev,
564360f0f39SAzael Avalos 			struct toshiba_acpi_dev, kbd_led);
565360f0f39SAzael Avalos 	u32 state, result;
566360f0f39SAzael Avalos 	acpi_status status;
567360f0f39SAzael Avalos 
568360f0f39SAzael Avalos 	/* Set the keyboard backlight state */
569360f0f39SAzael Avalos 	state = brightness ? 1 : 0;
570360f0f39SAzael Avalos 	status = hci_write1(dev, HCI_KBD_ILLUMINATION, state, &result);
571360f0f39SAzael Avalos 	if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
572360f0f39SAzael Avalos 		pr_err("ACPI call to set KBD Illumination mode failed\n");
573360f0f39SAzael Avalos 		return;
574360f0f39SAzael Avalos 	} else if (result == HCI_NOT_SUPPORTED) {
575360f0f39SAzael Avalos 		pr_info("Keyboard backlight not supported\n");
576360f0f39SAzael Avalos 		return;
577360f0f39SAzael Avalos 	}
578360f0f39SAzael Avalos }
579360f0f39SAzael Avalos 
5809d8658acSAzael Avalos /* TouchPad support */
5819d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
5829d8658acSAzael Avalos {
5839d8658acSAzael Avalos 	u32 result;
5849d8658acSAzael Avalos 	acpi_status status;
5859d8658acSAzael Avalos 
5869d8658acSAzael Avalos 	if (!sci_open(dev))
5879d8658acSAzael Avalos 		return -EIO;
5889d8658acSAzael Avalos 
5899d8658acSAzael Avalos 	status = sci_write(dev, SCI_TOUCHPAD, state, &result);
5909d8658acSAzael Avalos 	sci_close(dev);
5919d8658acSAzael Avalos 	if (ACPI_FAILURE(status)) {
5929d8658acSAzael Avalos 		pr_err("ACPI call to set the touchpad failed\n");
5939d8658acSAzael Avalos 		return -EIO;
5949d8658acSAzael Avalos 	} else if (result == HCI_NOT_SUPPORTED) {
5959d8658acSAzael Avalos 		return -ENODEV;
5969d8658acSAzael Avalos 	}
5979d8658acSAzael Avalos 
5989d8658acSAzael Avalos 	return 0;
5999d8658acSAzael Avalos }
6009d8658acSAzael Avalos 
6019d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
6029d8658acSAzael Avalos {
6039d8658acSAzael Avalos 	u32 result;
6049d8658acSAzael Avalos 	acpi_status status;
6059d8658acSAzael Avalos 
6069d8658acSAzael Avalos 	if (!sci_open(dev))
6079d8658acSAzael Avalos 		return -EIO;
6089d8658acSAzael Avalos 
6099d8658acSAzael Avalos 	status = sci_read(dev, SCI_TOUCHPAD, state, &result);
6109d8658acSAzael Avalos 	sci_close(dev);
6119d8658acSAzael Avalos 	if (ACPI_FAILURE(status)) {
6129d8658acSAzael Avalos 		pr_err("ACPI call to query the touchpad failed\n");
6139d8658acSAzael Avalos 		return -EIO;
6149d8658acSAzael Avalos 	} else if (result == HCI_NOT_SUPPORTED) {
6159d8658acSAzael Avalos 		return -ENODEV;
6169d8658acSAzael Avalos 	}
6179d8658acSAzael Avalos 
6189d8658acSAzael Avalos 	return 0;
6199d8658acSAzael Avalos }
6209d8658acSAzael Avalos 
621def6c4e2SAzael Avalos /* Eco Mode support */
622def6c4e2SAzael Avalos static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
623def6c4e2SAzael Avalos {
624def6c4e2SAzael Avalos 	acpi_status status;
625def6c4e2SAzael Avalos 	u32 in[HCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
626def6c4e2SAzael Avalos 	u32 out[HCI_WORDS];
627def6c4e2SAzael Avalos 
628def6c4e2SAzael Avalos 	status = hci_raw(dev, in, out);
629def6c4e2SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
630def6c4e2SAzael Avalos 		pr_info("ACPI call to get ECO led failed\n");
631def6c4e2SAzael Avalos 		return 0;
632def6c4e2SAzael Avalos 	}
633def6c4e2SAzael Avalos 
634def6c4e2SAzael Avalos 	return 1;
635def6c4e2SAzael Avalos }
636def6c4e2SAzael Avalos 
637def6c4e2SAzael Avalos static enum led_brightness toshiba_eco_mode_get_status(struct led_classdev *cdev)
638def6c4e2SAzael Avalos {
639def6c4e2SAzael Avalos 	struct toshiba_acpi_dev *dev = container_of(cdev,
640def6c4e2SAzael Avalos 			struct toshiba_acpi_dev, eco_led);
641def6c4e2SAzael Avalos 	u32 in[HCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
642def6c4e2SAzael Avalos 	u32 out[HCI_WORDS];
643def6c4e2SAzael Avalos 	acpi_status status;
644def6c4e2SAzael Avalos 
645def6c4e2SAzael Avalos 	status = hci_raw(dev, in, out);
646def6c4e2SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
647def6c4e2SAzael Avalos 		pr_err("ACPI call to get ECO led failed\n");
648def6c4e2SAzael Avalos 		return LED_OFF;
649def6c4e2SAzael Avalos 	}
650def6c4e2SAzael Avalos 
651def6c4e2SAzael Avalos 	return out[2] ? LED_FULL : LED_OFF;
652def6c4e2SAzael Avalos }
653def6c4e2SAzael Avalos 
654def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev,
655def6c4e2SAzael Avalos 				     enum led_brightness brightness)
656def6c4e2SAzael Avalos {
657def6c4e2SAzael Avalos 	struct toshiba_acpi_dev *dev = container_of(cdev,
658def6c4e2SAzael Avalos 			struct toshiba_acpi_dev, eco_led);
659def6c4e2SAzael Avalos 	u32 in[HCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 };
660def6c4e2SAzael Avalos 	u32 out[HCI_WORDS];
661def6c4e2SAzael Avalos 	acpi_status status;
662def6c4e2SAzael Avalos 
663def6c4e2SAzael Avalos 	/* Switch the Eco Mode led on/off */
664def6c4e2SAzael Avalos 	in[2] = (brightness) ? 1 : 0;
665def6c4e2SAzael Avalos 	status = hci_raw(dev, in, out);
666def6c4e2SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
667def6c4e2SAzael Avalos 		pr_err("ACPI call to set ECO led failed\n");
668def6c4e2SAzael Avalos 		return;
669def6c4e2SAzael Avalos 	}
670def6c4e2SAzael Avalos }
671def6c4e2SAzael Avalos 
6725a2813e9SAzael Avalos /* Accelerometer support */
6735a2813e9SAzael Avalos static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev)
6745a2813e9SAzael Avalos {
6755a2813e9SAzael Avalos 	u32 in[HCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
6765a2813e9SAzael Avalos 	u32 out[HCI_WORDS];
6775a2813e9SAzael Avalos 	acpi_status status;
6785a2813e9SAzael Avalos 
6795a2813e9SAzael Avalos 	/* Check if the accelerometer call exists,
6805a2813e9SAzael Avalos 	 * this call also serves as initialization
6815a2813e9SAzael Avalos 	 */
6825a2813e9SAzael Avalos 	status = hci_raw(dev, in, out);
6835a2813e9SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
6845a2813e9SAzael Avalos 		pr_err("ACPI call to query the accelerometer failed\n");
6855a2813e9SAzael Avalos 		return -EIO;
6865a2813e9SAzael Avalos 	} else if (out[0] == HCI_DATA_NOT_AVAILABLE ||
6875a2813e9SAzael Avalos 		   out[0] == HCI_NOT_INITIALIZED) {
6885a2813e9SAzael Avalos 		pr_err("Accelerometer not initialized\n");
6895a2813e9SAzael Avalos 		return -EIO;
6905a2813e9SAzael Avalos 	} else if (out[0] == HCI_NOT_SUPPORTED) {
6915a2813e9SAzael Avalos 		pr_info("Accelerometer not supported\n");
6925a2813e9SAzael Avalos 		return -ENODEV;
6935a2813e9SAzael Avalos 	}
6945a2813e9SAzael Avalos 
6955a2813e9SAzael Avalos 	return 0;
6965a2813e9SAzael Avalos }
6975a2813e9SAzael Avalos 
6985a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
6995a2813e9SAzael Avalos 				      u32 *xy, u32 *z)
7005a2813e9SAzael Avalos {
7015a2813e9SAzael Avalos 	u32 in[HCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
7025a2813e9SAzael Avalos 	u32 out[HCI_WORDS];
7035a2813e9SAzael Avalos 	acpi_status status;
7045a2813e9SAzael Avalos 
7055a2813e9SAzael Avalos 	/* Check the Accelerometer status */
7065a2813e9SAzael Avalos 	status = hci_raw(dev, in, out);
7075a2813e9SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
7085a2813e9SAzael Avalos 		pr_err("ACPI call to query the accelerometer failed\n");
7095a2813e9SAzael Avalos 		return -EIO;
7105a2813e9SAzael Avalos 	}
7115a2813e9SAzael Avalos 
7125a2813e9SAzael Avalos 	*xy = out[2];
7135a2813e9SAzael Avalos 	*z = out[4];
7145a2813e9SAzael Avalos 
7155a2813e9SAzael Avalos 	return 0;
7165a2813e9SAzael Avalos }
7175a2813e9SAzael Avalos 
718b4f9fe12SLen Brown /* Bluetooth rfkill handlers */
719b4f9fe12SLen Brown 
720135740deSSeth Forshee static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
721b4f9fe12SLen Brown {
722b4f9fe12SLen Brown 	u32 hci_result;
723b4f9fe12SLen Brown 	u32 value, value2;
724b4f9fe12SLen Brown 
725b4f9fe12SLen Brown 	value = 0;
726b4f9fe12SLen Brown 	value2 = 0;
727135740deSSeth Forshee 	hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result);
728b4f9fe12SLen Brown 	if (hci_result == HCI_SUCCESS)
729b4f9fe12SLen Brown 		*present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
730b4f9fe12SLen Brown 
731b4f9fe12SLen Brown 	return hci_result;
732b4f9fe12SLen Brown }
733b4f9fe12SLen Brown 
734135740deSSeth Forshee static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state)
735b4f9fe12SLen Brown {
736b4f9fe12SLen Brown 	u32 hci_result;
737b4f9fe12SLen Brown 	u32 value, value2;
738b4f9fe12SLen Brown 
739b4f9fe12SLen Brown 	value = 0;
740b4f9fe12SLen Brown 	value2 = 0x0001;
741135740deSSeth Forshee 	hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result);
742b4f9fe12SLen Brown 
743b4f9fe12SLen Brown 	*radio_state = value & HCI_WIRELESS_KILL_SWITCH;
744b4f9fe12SLen Brown 	return hci_result;
745b4f9fe12SLen Brown }
746b4f9fe12SLen Brown 
74719d337dfSJohannes Berg static int bt_rfkill_set_block(void *data, bool blocked)
748b4f9fe12SLen Brown {
74919d337dfSJohannes Berg 	struct toshiba_acpi_dev *dev = data;
750b4f9fe12SLen Brown 	u32 result1, result2;
751b4f9fe12SLen Brown 	u32 value;
75219d337dfSJohannes Berg 	int err;
753b4f9fe12SLen Brown 	bool radio_state;
754b4f9fe12SLen Brown 
75519d337dfSJohannes Berg 	value = (blocked == false);
756b4f9fe12SLen Brown 
757b4f9fe12SLen Brown 	mutex_lock(&dev->mutex);
758135740deSSeth Forshee 	if (hci_get_radio_state(dev, &radio_state) != HCI_SUCCESS) {
75932bcd5cbSSeth Forshee 		err = -EIO;
76019d337dfSJohannes Berg 		goto out;
761b4f9fe12SLen Brown 	}
762b4f9fe12SLen Brown 
76319d337dfSJohannes Berg 	if (!radio_state) {
76419d337dfSJohannes Berg 		err = 0;
76519d337dfSJohannes Berg 		goto out;
76619d337dfSJohannes Berg 	}
76719d337dfSJohannes Berg 
768135740deSSeth Forshee 	hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
769135740deSSeth Forshee 	hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
77019d337dfSJohannes Berg 
77119d337dfSJohannes Berg 	if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
77232bcd5cbSSeth Forshee 		err = -EIO;
77319d337dfSJohannes Berg 	else
77419d337dfSJohannes Berg 		err = 0;
77519d337dfSJohannes Berg  out:
77619d337dfSJohannes Berg 	mutex_unlock(&dev->mutex);
77719d337dfSJohannes Berg 	return err;
77819d337dfSJohannes Berg }
77919d337dfSJohannes Berg 
78019d337dfSJohannes Berg static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
781b4f9fe12SLen Brown {
782b4f9fe12SLen Brown 	bool new_rfk_state;
783b4f9fe12SLen Brown 	bool value;
784b4f9fe12SLen Brown 	u32 hci_result;
78519d337dfSJohannes Berg 	struct toshiba_acpi_dev *dev = data;
78619d337dfSJohannes Berg 
78719d337dfSJohannes Berg 	mutex_lock(&dev->mutex);
788b4f9fe12SLen Brown 
789135740deSSeth Forshee 	hci_result = hci_get_radio_state(dev, &value);
79019d337dfSJohannes Berg 	if (hci_result != HCI_SUCCESS) {
79119d337dfSJohannes Berg 		/* Can't do anything useful */
79219d337dfSJohannes Berg 		mutex_unlock(&dev->mutex);
79382e7784fSJiri Slaby 		return;
79419d337dfSJohannes Berg 	}
795b4f9fe12SLen Brown 
796b4f9fe12SLen Brown 	new_rfk_state = value;
797b4f9fe12SLen Brown 
798b4f9fe12SLen Brown 	mutex_unlock(&dev->mutex);
799b4f9fe12SLen Brown 
80019d337dfSJohannes Berg 	if (rfkill_set_hw_state(rfkill, !new_rfk_state))
80119d337dfSJohannes Berg 		bt_rfkill_set_block(data, true);
802b4f9fe12SLen Brown }
80319d337dfSJohannes Berg 
80419d337dfSJohannes Berg static const struct rfkill_ops toshiba_rfk_ops = {
80519d337dfSJohannes Berg 	.set_block = bt_rfkill_set_block,
80619d337dfSJohannes Berg 	.poll = bt_rfkill_poll,
80719d337dfSJohannes Berg };
808b4f9fe12SLen Brown 
809121b7b0dSAkio Idehara static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled)
810121b7b0dSAkio Idehara {
811121b7b0dSAkio Idehara 	u32 hci_result;
812121b7b0dSAkio Idehara 	u32 status;
813121b7b0dSAkio Idehara 
814121b7b0dSAkio Idehara 	hci_read1(dev, HCI_TR_BACKLIGHT, &status, &hci_result);
815121b7b0dSAkio Idehara 	*enabled = !status;
816121b7b0dSAkio Idehara 	return hci_result == HCI_SUCCESS ? 0 : -EIO;
817121b7b0dSAkio Idehara }
818121b7b0dSAkio Idehara 
819121b7b0dSAkio Idehara static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
820121b7b0dSAkio Idehara {
821121b7b0dSAkio Idehara 	u32 hci_result;
822121b7b0dSAkio Idehara 	u32 value = !enable;
823121b7b0dSAkio Idehara 
824121b7b0dSAkio Idehara 	hci_write1(dev, HCI_TR_BACKLIGHT, value, &hci_result);
825121b7b0dSAkio Idehara 	return hci_result == HCI_SUCCESS ? 0 : -EIO;
826121b7b0dSAkio Idehara }
827121b7b0dSAkio Idehara 
828b4f9fe12SLen Brown static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
829b4f9fe12SLen Brown 
83062cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
831b4f9fe12SLen Brown {
832b4f9fe12SLen Brown 	u32 hci_result;
833b4f9fe12SLen Brown 	u32 value;
834121b7b0dSAkio Idehara 	int brightness = 0;
835121b7b0dSAkio Idehara 
836121b7b0dSAkio Idehara 	if (dev->tr_backlight_supported) {
837121b7b0dSAkio Idehara 		bool enabled;
838121b7b0dSAkio Idehara 		int ret = get_tr_backlight_status(dev, &enabled);
839121b7b0dSAkio Idehara 		if (ret)
840121b7b0dSAkio Idehara 			return ret;
841121b7b0dSAkio Idehara 		if (enabled)
842121b7b0dSAkio Idehara 			return 0;
843121b7b0dSAkio Idehara 		brightness++;
844121b7b0dSAkio Idehara 	}
845b4f9fe12SLen Brown 
846135740deSSeth Forshee 	hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result);
84732bcd5cbSSeth Forshee 	if (hci_result == HCI_SUCCESS)
848121b7b0dSAkio Idehara 		return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
84932bcd5cbSSeth Forshee 
85032bcd5cbSSeth Forshee 	return -EIO;
851b4f9fe12SLen Brown }
852b4f9fe12SLen Brown 
85362cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd)
85462cce752SSeth Forshee {
85562cce752SSeth Forshee 	struct toshiba_acpi_dev *dev = bl_get_data(bd);
85662cce752SSeth Forshee 	return __get_lcd_brightness(dev);
85762cce752SSeth Forshee }
85862cce752SSeth Forshee 
859936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v)
860b4f9fe12SLen Brown {
861135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = m->private;
862135740deSSeth Forshee 	int value;
863121b7b0dSAkio Idehara 	int levels;
864b4f9fe12SLen Brown 
865135740deSSeth Forshee 	if (!dev->backlight_dev)
866135740deSSeth Forshee 		return -ENODEV;
867135740deSSeth Forshee 
868121b7b0dSAkio Idehara 	levels = dev->backlight_dev->props.max_brightness + 1;
86962cce752SSeth Forshee 	value = get_lcd_brightness(dev->backlight_dev);
870b4f9fe12SLen Brown 	if (value >= 0) {
871936c8bcdSAlexey Dobriyan 		seq_printf(m, "brightness:              %d\n", value);
872121b7b0dSAkio Idehara 		seq_printf(m, "brightness_levels:       %d\n", levels);
87332bcd5cbSSeth Forshee 		return 0;
874b4f9fe12SLen Brown 	}
875b4f9fe12SLen Brown 
87632bcd5cbSSeth Forshee 	pr_err("Error reading LCD brightness\n");
87732bcd5cbSSeth Forshee 	return -EIO;
878936c8bcdSAlexey Dobriyan }
879936c8bcdSAlexey Dobriyan 
880936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file)
881936c8bcdSAlexey Dobriyan {
882d9dda78bSAl Viro 	return single_open(file, lcd_proc_show, PDE_DATA(inode));
883b4f9fe12SLen Brown }
884b4f9fe12SLen Brown 
88562cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
886b4f9fe12SLen Brown {
887f6aac652SAzael Avalos 	u32 in[HCI_WORDS] = { HCI_SET, HCI_LCD_BRIGHTNESS, 0, 0, 0, 0 };
888f6aac652SAzael Avalos 	u32 out[HCI_WORDS];
889f6aac652SAzael Avalos 	acpi_status status;
890b4f9fe12SLen Brown 
891121b7b0dSAkio Idehara 	if (dev->tr_backlight_supported) {
892121b7b0dSAkio Idehara 		bool enable = !value;
893121b7b0dSAkio Idehara 		int ret = set_tr_backlight_status(dev, enable);
894121b7b0dSAkio Idehara 		if (ret)
895121b7b0dSAkio Idehara 			return ret;
896121b7b0dSAkio Idehara 		if (value)
897121b7b0dSAkio Idehara 			value--;
898121b7b0dSAkio Idehara 	}
899121b7b0dSAkio Idehara 
900f6aac652SAzael Avalos 	in[2] = value << HCI_LCD_BRIGHTNESS_SHIFT;
901f6aac652SAzael Avalos 	status = hci_raw(dev, in, out);
902f6aac652SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
903f6aac652SAzael Avalos 		pr_err("ACPI call to set brightness failed");
904f6aac652SAzael Avalos 		return -EIO;
905f6aac652SAzael Avalos 	}
906f6aac652SAzael Avalos 	/* Extra check for "incomplete" backlight method, where the AML code
907f6aac652SAzael Avalos 	 * doesn't check for HCI_SET or HCI_GET and returns HCI_SUCCESS,
908f6aac652SAzael Avalos 	 * the actual brightness, and in some cases the max brightness.
909f6aac652SAzael Avalos 	 */
910f6aac652SAzael Avalos 	if (out[2] > 0  || out[3] == 0xE000)
911f6aac652SAzael Avalos 		return -ENODEV;
912f6aac652SAzael Avalos 
913f6aac652SAzael Avalos 	return out[0] == HCI_SUCCESS ? 0 : -EIO;
914b4f9fe12SLen Brown }
915b4f9fe12SLen Brown 
916b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd)
917b4f9fe12SLen Brown {
918135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = bl_get_data(bd);
91962cce752SSeth Forshee 	return set_lcd_brightness(dev, bd->props.brightness);
920b4f9fe12SLen Brown }
921b4f9fe12SLen Brown 
922936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
923936c8bcdSAlexey Dobriyan 			      size_t count, loff_t *pos)
924b4f9fe12SLen Brown {
925d9dda78bSAl Viro 	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
926936c8bcdSAlexey Dobriyan 	char cmd[42];
927936c8bcdSAlexey Dobriyan 	size_t len;
928b4f9fe12SLen Brown 	int value;
929b4f9fe12SLen Brown 	int ret;
930121b7b0dSAkio Idehara 	int levels = dev->backlight_dev->props.max_brightness + 1;
931b4f9fe12SLen Brown 
932936c8bcdSAlexey Dobriyan 	len = min(count, sizeof(cmd) - 1);
933936c8bcdSAlexey Dobriyan 	if (copy_from_user(cmd, buf, len))
934936c8bcdSAlexey Dobriyan 		return -EFAULT;
935936c8bcdSAlexey Dobriyan 	cmd[len] = '\0';
936936c8bcdSAlexey Dobriyan 
937936c8bcdSAlexey Dobriyan 	if (sscanf(cmd, " brightness : %i", &value) == 1 &&
938121b7b0dSAkio Idehara 	    value >= 0 && value < levels) {
93962cce752SSeth Forshee 		ret = set_lcd_brightness(dev, value);
940b4f9fe12SLen Brown 		if (ret == 0)
941b4f9fe12SLen Brown 			ret = count;
942b4f9fe12SLen Brown 	} else {
943b4f9fe12SLen Brown 		ret = -EINVAL;
944b4f9fe12SLen Brown 	}
945b4f9fe12SLen Brown 	return ret;
946b4f9fe12SLen Brown }
947b4f9fe12SLen Brown 
948936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = {
949936c8bcdSAlexey Dobriyan 	.owner		= THIS_MODULE,
950936c8bcdSAlexey Dobriyan 	.open		= lcd_proc_open,
951936c8bcdSAlexey Dobriyan 	.read		= seq_read,
952936c8bcdSAlexey Dobriyan 	.llseek		= seq_lseek,
953936c8bcdSAlexey Dobriyan 	.release	= single_release,
954936c8bcdSAlexey Dobriyan 	.write		= lcd_proc_write,
955936c8bcdSAlexey Dobriyan };
956936c8bcdSAlexey Dobriyan 
95736d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
95836d03f93SSeth Forshee {
95936d03f93SSeth Forshee 	u32 hci_result;
96036d03f93SSeth Forshee 
96136d03f93SSeth Forshee 	hci_read1(dev, HCI_VIDEO_OUT, status, &hci_result);
96236d03f93SSeth Forshee 	return hci_result == HCI_SUCCESS ? 0 : -EIO;
96336d03f93SSeth Forshee }
96436d03f93SSeth Forshee 
965936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v)
966b4f9fe12SLen Brown {
967135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = m->private;
968b4f9fe12SLen Brown 	u32 value;
96936d03f93SSeth Forshee 	int ret;
970b4f9fe12SLen Brown 
97136d03f93SSeth Forshee 	ret = get_video_status(dev, &value);
97236d03f93SSeth Forshee 	if (!ret) {
973b4f9fe12SLen Brown 		int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
974b4f9fe12SLen Brown 		int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
975b4f9fe12SLen Brown 		int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
976936c8bcdSAlexey Dobriyan 		seq_printf(m, "lcd_out:                 %d\n", is_lcd);
977936c8bcdSAlexey Dobriyan 		seq_printf(m, "crt_out:                 %d\n", is_crt);
978936c8bcdSAlexey Dobriyan 		seq_printf(m, "tv_out:                  %d\n", is_tv);
979b4f9fe12SLen Brown 	}
980b4f9fe12SLen Brown 
98136d03f93SSeth Forshee 	return ret;
982b4f9fe12SLen Brown }
983b4f9fe12SLen Brown 
984936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file)
985b4f9fe12SLen Brown {
986d9dda78bSAl Viro 	return single_open(file, video_proc_show, PDE_DATA(inode));
987936c8bcdSAlexey Dobriyan }
988936c8bcdSAlexey Dobriyan 
989936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf,
990936c8bcdSAlexey Dobriyan 				size_t count, loff_t *pos)
991936c8bcdSAlexey Dobriyan {
992d9dda78bSAl Viro 	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
993936c8bcdSAlexey Dobriyan 	char *cmd, *buffer;
99436d03f93SSeth Forshee 	int ret;
995b4f9fe12SLen Brown 	int value;
996b4f9fe12SLen Brown 	int remain = count;
997b4f9fe12SLen Brown 	int lcd_out = -1;
998b4f9fe12SLen Brown 	int crt_out = -1;
999b4f9fe12SLen Brown 	int tv_out = -1;
1000b4f9fe12SLen Brown 	u32 video_out;
1001b4f9fe12SLen Brown 
1002936c8bcdSAlexey Dobriyan 	cmd = kmalloc(count + 1, GFP_KERNEL);
1003936c8bcdSAlexey Dobriyan 	if (!cmd)
1004936c8bcdSAlexey Dobriyan 		return -ENOMEM;
1005936c8bcdSAlexey Dobriyan 	if (copy_from_user(cmd, buf, count)) {
1006936c8bcdSAlexey Dobriyan 		kfree(cmd);
1007936c8bcdSAlexey Dobriyan 		return -EFAULT;
1008936c8bcdSAlexey Dobriyan 	}
1009936c8bcdSAlexey Dobriyan 	cmd[count] = '\0';
1010936c8bcdSAlexey Dobriyan 
1011936c8bcdSAlexey Dobriyan 	buffer = cmd;
1012936c8bcdSAlexey Dobriyan 
1013b4f9fe12SLen Brown 	/* scan expression.  Multiple expressions may be delimited with ;
1014b4f9fe12SLen Brown 	 *
1015b4f9fe12SLen Brown 	 *  NOTE: to keep scanning simple, invalid fields are ignored
1016b4f9fe12SLen Brown 	 */
1017b4f9fe12SLen Brown 	while (remain) {
1018b4f9fe12SLen Brown 		if (sscanf(buffer, " lcd_out : %i", &value) == 1)
1019b4f9fe12SLen Brown 			lcd_out = value & 1;
1020b4f9fe12SLen Brown 		else if (sscanf(buffer, " crt_out : %i", &value) == 1)
1021b4f9fe12SLen Brown 			crt_out = value & 1;
1022b4f9fe12SLen Brown 		else if (sscanf(buffer, " tv_out : %i", &value) == 1)
1023b4f9fe12SLen Brown 			tv_out = value & 1;
1024b4f9fe12SLen Brown 		/* advance to one character past the next ; */
1025b4f9fe12SLen Brown 		do {
1026b4f9fe12SLen Brown 			++buffer;
1027b4f9fe12SLen Brown 			--remain;
1028b4f9fe12SLen Brown 		}
1029b4f9fe12SLen Brown 		while (remain && *(buffer - 1) != ';');
1030b4f9fe12SLen Brown 	}
1031b4f9fe12SLen Brown 
1032936c8bcdSAlexey Dobriyan 	kfree(cmd);
1033936c8bcdSAlexey Dobriyan 
103436d03f93SSeth Forshee 	ret = get_video_status(dev, &video_out);
103536d03f93SSeth Forshee 	if (!ret) {
1036b4f9fe12SLen Brown 		unsigned int new_video_out = video_out;
1037b4f9fe12SLen Brown 		if (lcd_out != -1)
1038b4f9fe12SLen Brown 			_set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
1039b4f9fe12SLen Brown 		if (crt_out != -1)
1040b4f9fe12SLen Brown 			_set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
1041b4f9fe12SLen Brown 		if (tv_out != -1)
1042b4f9fe12SLen Brown 			_set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
1043b4f9fe12SLen Brown 		/* To avoid unnecessary video disruption, only write the new
1044b4f9fe12SLen Brown 		 * video setting if something changed. */
1045b4f9fe12SLen Brown 		if (new_video_out != video_out)
104632bcd5cbSSeth Forshee 			ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
1047b4f9fe12SLen Brown 	}
1048b4f9fe12SLen Brown 
104932bcd5cbSSeth Forshee 	return ret ? ret : count;
1050b4f9fe12SLen Brown }
1051b4f9fe12SLen Brown 
1052936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = {
1053936c8bcdSAlexey Dobriyan 	.owner		= THIS_MODULE,
1054936c8bcdSAlexey Dobriyan 	.open		= video_proc_open,
1055936c8bcdSAlexey Dobriyan 	.read		= seq_read,
1056936c8bcdSAlexey Dobriyan 	.llseek		= seq_lseek,
1057936c8bcdSAlexey Dobriyan 	.release	= single_release,
1058936c8bcdSAlexey Dobriyan 	.write		= video_proc_write,
1059936c8bcdSAlexey Dobriyan };
1060936c8bcdSAlexey Dobriyan 
106136d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
106236d03f93SSeth Forshee {
106336d03f93SSeth Forshee 	u32 hci_result;
106436d03f93SSeth Forshee 
106536d03f93SSeth Forshee 	hci_read1(dev, HCI_FAN, status, &hci_result);
106636d03f93SSeth Forshee 	return hci_result == HCI_SUCCESS ? 0 : -EIO;
106736d03f93SSeth Forshee }
106836d03f93SSeth Forshee 
1069936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v)
1070b4f9fe12SLen Brown {
1071135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = m->private;
107236d03f93SSeth Forshee 	int ret;
1073b4f9fe12SLen Brown 	u32 value;
1074b4f9fe12SLen Brown 
107536d03f93SSeth Forshee 	ret = get_fan_status(dev, &value);
107636d03f93SSeth Forshee 	if (!ret) {
1077936c8bcdSAlexey Dobriyan 		seq_printf(m, "running:                 %d\n", (value > 0));
1078135740deSSeth Forshee 		seq_printf(m, "force_on:                %d\n", dev->force_fan);
1079b4f9fe12SLen Brown 	}
1080b4f9fe12SLen Brown 
108136d03f93SSeth Forshee 	return ret;
1082b4f9fe12SLen Brown }
1083b4f9fe12SLen Brown 
1084936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file)
1085b4f9fe12SLen Brown {
1086d9dda78bSAl Viro 	return single_open(file, fan_proc_show, PDE_DATA(inode));
1087936c8bcdSAlexey Dobriyan }
1088936c8bcdSAlexey Dobriyan 
1089936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf,
1090936c8bcdSAlexey Dobriyan 			      size_t count, loff_t *pos)
1091936c8bcdSAlexey Dobriyan {
1092d9dda78bSAl Viro 	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
1093936c8bcdSAlexey Dobriyan 	char cmd[42];
1094936c8bcdSAlexey Dobriyan 	size_t len;
1095b4f9fe12SLen Brown 	int value;
1096b4f9fe12SLen Brown 	u32 hci_result;
1097b4f9fe12SLen Brown 
1098936c8bcdSAlexey Dobriyan 	len = min(count, sizeof(cmd) - 1);
1099936c8bcdSAlexey Dobriyan 	if (copy_from_user(cmd, buf, len))
1100936c8bcdSAlexey Dobriyan 		return -EFAULT;
1101936c8bcdSAlexey Dobriyan 	cmd[len] = '\0';
1102936c8bcdSAlexey Dobriyan 
1103936c8bcdSAlexey Dobriyan 	if (sscanf(cmd, " force_on : %i", &value) == 1 &&
1104b4f9fe12SLen Brown 	    value >= 0 && value <= 1) {
1105135740deSSeth Forshee 		hci_write1(dev, HCI_FAN, value, &hci_result);
1106b4f9fe12SLen Brown 		if (hci_result != HCI_SUCCESS)
110732bcd5cbSSeth Forshee 			return -EIO;
1108b4f9fe12SLen Brown 		else
1109135740deSSeth Forshee 			dev->force_fan = value;
1110b4f9fe12SLen Brown 	} else {
1111b4f9fe12SLen Brown 		return -EINVAL;
1112b4f9fe12SLen Brown 	}
1113b4f9fe12SLen Brown 
1114b4f9fe12SLen Brown 	return count;
1115b4f9fe12SLen Brown }
1116b4f9fe12SLen Brown 
1117936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = {
1118936c8bcdSAlexey Dobriyan 	.owner		= THIS_MODULE,
1119936c8bcdSAlexey Dobriyan 	.open		= fan_proc_open,
1120936c8bcdSAlexey Dobriyan 	.read		= seq_read,
1121936c8bcdSAlexey Dobriyan 	.llseek		= seq_lseek,
1122936c8bcdSAlexey Dobriyan 	.release	= single_release,
1123936c8bcdSAlexey Dobriyan 	.write		= fan_proc_write,
1124936c8bcdSAlexey Dobriyan };
1125936c8bcdSAlexey Dobriyan 
1126936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v)
1127b4f9fe12SLen Brown {
1128135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = m->private;
1129b4f9fe12SLen Brown 	u32 hci_result;
1130b4f9fe12SLen Brown 	u32 value;
1131b4f9fe12SLen Brown 
113211948b93SSeth Forshee 	if (!dev->key_event_valid && dev->system_event_supported) {
1133135740deSSeth Forshee 		hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
1134b4f9fe12SLen Brown 		if (hci_result == HCI_SUCCESS) {
1135135740deSSeth Forshee 			dev->key_event_valid = 1;
1136135740deSSeth Forshee 			dev->last_key_event = value;
1137b4f9fe12SLen Brown 		} else if (hci_result == HCI_EMPTY) {
1138b4f9fe12SLen Brown 			/* better luck next time */
1139b4f9fe12SLen Brown 		} else if (hci_result == HCI_NOT_SUPPORTED) {
1140b4f9fe12SLen Brown 			/* This is a workaround for an unresolved issue on
1141b4f9fe12SLen Brown 			 * some machines where system events sporadically
1142b4f9fe12SLen Brown 			 * become disabled. */
1143135740deSSeth Forshee 			hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
11447e33460dSJoe Perches 			pr_notice("Re-enabled hotkeys\n");
1145b4f9fe12SLen Brown 		} else {
11467e33460dSJoe Perches 			pr_err("Error reading hotkey status\n");
114732bcd5cbSSeth Forshee 			return -EIO;
1148b4f9fe12SLen Brown 		}
1149b4f9fe12SLen Brown 	}
1150b4f9fe12SLen Brown 
1151135740deSSeth Forshee 	seq_printf(m, "hotkey_ready:            %d\n", dev->key_event_valid);
1152135740deSSeth Forshee 	seq_printf(m, "hotkey:                  0x%04x\n", dev->last_key_event);
1153936c8bcdSAlexey Dobriyan 	return 0;
1154b4f9fe12SLen Brown }
1155b4f9fe12SLen Brown 
1156936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file)
1157b4f9fe12SLen Brown {
1158d9dda78bSAl Viro 	return single_open(file, keys_proc_show, PDE_DATA(inode));
1159936c8bcdSAlexey Dobriyan }
1160936c8bcdSAlexey Dobriyan 
1161936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf,
1162936c8bcdSAlexey Dobriyan 			       size_t count, loff_t *pos)
1163936c8bcdSAlexey Dobriyan {
1164d9dda78bSAl Viro 	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
1165936c8bcdSAlexey Dobriyan 	char cmd[42];
1166936c8bcdSAlexey Dobriyan 	size_t len;
1167b4f9fe12SLen Brown 	int value;
1168b4f9fe12SLen Brown 
1169936c8bcdSAlexey Dobriyan 	len = min(count, sizeof(cmd) - 1);
1170936c8bcdSAlexey Dobriyan 	if (copy_from_user(cmd, buf, len))
1171936c8bcdSAlexey Dobriyan 		return -EFAULT;
1172936c8bcdSAlexey Dobriyan 	cmd[len] = '\0';
1173936c8bcdSAlexey Dobriyan 
1174936c8bcdSAlexey Dobriyan 	if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) {
1175135740deSSeth Forshee 		dev->key_event_valid = 0;
1176b4f9fe12SLen Brown 	} else {
1177b4f9fe12SLen Brown 		return -EINVAL;
1178b4f9fe12SLen Brown 	}
1179b4f9fe12SLen Brown 
1180b4f9fe12SLen Brown 	return count;
1181b4f9fe12SLen Brown }
1182b4f9fe12SLen Brown 
1183936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = {
1184936c8bcdSAlexey Dobriyan 	.owner		= THIS_MODULE,
1185936c8bcdSAlexey Dobriyan 	.open		= keys_proc_open,
1186936c8bcdSAlexey Dobriyan 	.read		= seq_read,
1187936c8bcdSAlexey Dobriyan 	.llseek		= seq_lseek,
1188936c8bcdSAlexey Dobriyan 	.release	= single_release,
1189936c8bcdSAlexey Dobriyan 	.write		= keys_proc_write,
1190936c8bcdSAlexey Dobriyan };
1191936c8bcdSAlexey Dobriyan 
1192936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v)
1193b4f9fe12SLen Brown {
1194936c8bcdSAlexey Dobriyan 	seq_printf(m, "driver:                  %s\n", TOSHIBA_ACPI_VERSION);
1195936c8bcdSAlexey Dobriyan 	seq_printf(m, "proc_interface:          %d\n", PROC_INTERFACE_VERSION);
1196936c8bcdSAlexey Dobriyan 	return 0;
1197b4f9fe12SLen Brown }
1198b4f9fe12SLen Brown 
1199936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file)
1200936c8bcdSAlexey Dobriyan {
1201d9dda78bSAl Viro 	return single_open(file, version_proc_show, PDE_DATA(inode));
1202936c8bcdSAlexey Dobriyan }
1203936c8bcdSAlexey Dobriyan 
1204936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = {
1205936c8bcdSAlexey Dobriyan 	.owner		= THIS_MODULE,
1206936c8bcdSAlexey Dobriyan 	.open		= version_proc_open,
1207936c8bcdSAlexey Dobriyan 	.read		= seq_read,
1208936c8bcdSAlexey Dobriyan 	.llseek		= seq_lseek,
1209936c8bcdSAlexey Dobriyan 	.release	= single_release,
1210936c8bcdSAlexey Dobriyan };
1211936c8bcdSAlexey Dobriyan 
1212b4f9fe12SLen Brown /* proc and module init
1213b4f9fe12SLen Brown  */
1214b4f9fe12SLen Brown 
1215b4f9fe12SLen Brown #define PROC_TOSHIBA		"toshiba"
1216b4f9fe12SLen Brown 
1217b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
1218b4f9fe12SLen Brown {
121936d03f93SSeth Forshee 	if (dev->backlight_dev)
1220135740deSSeth Forshee 		proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1221135740deSSeth Forshee 				 &lcd_proc_fops, dev);
122236d03f93SSeth Forshee 	if (dev->video_supported)
1223135740deSSeth Forshee 		proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1224135740deSSeth Forshee 				 &video_proc_fops, dev);
122536d03f93SSeth Forshee 	if (dev->fan_supported)
1226135740deSSeth Forshee 		proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1227135740deSSeth Forshee 				 &fan_proc_fops, dev);
122836d03f93SSeth Forshee 	if (dev->hotkey_dev)
1229135740deSSeth Forshee 		proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1230135740deSSeth Forshee 				 &keys_proc_fops, dev);
1231135740deSSeth Forshee 	proc_create_data("version", S_IRUGO, toshiba_proc_dir,
1232135740deSSeth Forshee 			 &version_proc_fops, dev);
1233b4f9fe12SLen Brown }
1234b4f9fe12SLen Brown 
123536d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
1236b4f9fe12SLen Brown {
123736d03f93SSeth Forshee 	if (dev->backlight_dev)
1238936c8bcdSAlexey Dobriyan 		remove_proc_entry("lcd", toshiba_proc_dir);
123936d03f93SSeth Forshee 	if (dev->video_supported)
1240936c8bcdSAlexey Dobriyan 		remove_proc_entry("video", toshiba_proc_dir);
124136d03f93SSeth Forshee 	if (dev->fan_supported)
1242936c8bcdSAlexey Dobriyan 		remove_proc_entry("fan", toshiba_proc_dir);
124336d03f93SSeth Forshee 	if (dev->hotkey_dev)
1244936c8bcdSAlexey Dobriyan 		remove_proc_entry("keys", toshiba_proc_dir);
1245936c8bcdSAlexey Dobriyan 	remove_proc_entry("version", toshiba_proc_dir);
1246b4f9fe12SLen Brown }
1247b4f9fe12SLen Brown 
1248acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = {
1249121b7b0dSAkio Idehara 	.options = BL_CORE_SUSPENDRESUME,
125062cce752SSeth Forshee 	.get_brightness = get_lcd_brightness,
1251b4f9fe12SLen Brown 	.update_status  = set_lcd_status,
1252b4f9fe12SLen Brown };
1253b4f9fe12SLen Brown 
1254360f0f39SAzael Avalos /*
1255360f0f39SAzael Avalos  * Sysfs files
1256360f0f39SAzael Avalos  */
1257360f0f39SAzael Avalos 
1258360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
1259360f0f39SAzael Avalos 					 struct device_attribute *attr,
1260360f0f39SAzael Avalos 					 const char *buf, size_t count)
1261360f0f39SAzael Avalos {
1262360f0f39SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1263aeaac098SDan Carpenter 	int mode;
1264aeaac098SDan Carpenter 	int time;
1265aeaac098SDan Carpenter 	int ret;
1266360f0f39SAzael Avalos 
1267aeaac098SDan Carpenter 
1268aeaac098SDan Carpenter 	ret = kstrtoint(buf, 0, &mode);
1269aeaac098SDan Carpenter 	if (ret)
1270aeaac098SDan Carpenter 		return ret;
1271aeaac098SDan Carpenter 	if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
1272360f0f39SAzael Avalos 		return -EINVAL;
1273360f0f39SAzael Avalos 
1274360f0f39SAzael Avalos 	/* Set the Keyboard Backlight Mode where:
1275360f0f39SAzael Avalos 	 * Mode - Auto (2) | FN-Z (1)
1276360f0f39SAzael Avalos 	 *	Auto - KBD backlight turns off automatically in given time
1277360f0f39SAzael Avalos 	 *	FN-Z - KBD backlight "toggles" when hotkey pressed
1278360f0f39SAzael Avalos 	 */
1279aeaac098SDan Carpenter 	if (toshiba->kbd_mode != mode) {
1280360f0f39SAzael Avalos 		time = toshiba->kbd_time << HCI_MISC_SHIFT;
1281360f0f39SAzael Avalos 		time = time + toshiba->kbd_mode;
1282aeaac098SDan Carpenter 		ret = toshiba_kbd_illum_status_set(toshiba, time);
1283aeaac098SDan Carpenter 		if (ret)
1284aeaac098SDan Carpenter 			return ret;
1285360f0f39SAzael Avalos 		toshiba->kbd_mode = mode;
1286360f0f39SAzael Avalos 	}
1287360f0f39SAzael Avalos 
1288360f0f39SAzael Avalos 	return count;
1289360f0f39SAzael Avalos }
1290360f0f39SAzael Avalos 
1291360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
1292360f0f39SAzael Avalos 					struct device_attribute *attr,
1293360f0f39SAzael Avalos 					char *buf)
1294360f0f39SAzael Avalos {
1295360f0f39SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1296360f0f39SAzael Avalos 	u32 time;
1297360f0f39SAzael Avalos 
1298360f0f39SAzael Avalos 	if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1299360f0f39SAzael Avalos 		return -EIO;
1300360f0f39SAzael Avalos 
1301360f0f39SAzael Avalos 	return sprintf(buf, "%i\n", time & 0x07);
1302360f0f39SAzael Avalos }
1303360f0f39SAzael Avalos 
1304360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
1305360f0f39SAzael Avalos 					    struct device_attribute *attr,
1306360f0f39SAzael Avalos 					    const char *buf, size_t count)
1307360f0f39SAzael Avalos {
1308360f0f39SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1309360f0f39SAzael Avalos 	int time = -1;
1310360f0f39SAzael Avalos 
1311360f0f39SAzael Avalos 	if (sscanf(buf, "%i", &time) != 1 && (time < 0 || time > 60))
1312360f0f39SAzael Avalos 		return -EINVAL;
1313360f0f39SAzael Avalos 
1314360f0f39SAzael Avalos 	/* Set the Keyboard Backlight Timeout: 0-60 seconds */
1315360f0f39SAzael Avalos 	if (time != -1 && toshiba->kbd_time != time) {
1316360f0f39SAzael Avalos 		time = time << HCI_MISC_SHIFT;
1317360f0f39SAzael Avalos 		time = (toshiba->kbd_mode == SCI_KBD_MODE_AUTO) ?
1318360f0f39SAzael Avalos 							time + 1 : time + 2;
1319360f0f39SAzael Avalos 		if (toshiba_kbd_illum_status_set(toshiba, time) < 0)
1320360f0f39SAzael Avalos 			return -EIO;
1321360f0f39SAzael Avalos 		toshiba->kbd_time = time >> HCI_MISC_SHIFT;
1322360f0f39SAzael Avalos 	}
1323360f0f39SAzael Avalos 
1324360f0f39SAzael Avalos 	return count;
1325360f0f39SAzael Avalos }
1326360f0f39SAzael Avalos 
1327360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
1328360f0f39SAzael Avalos 					   struct device_attribute *attr,
1329360f0f39SAzael Avalos 					   char *buf)
1330360f0f39SAzael Avalos {
1331360f0f39SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1332360f0f39SAzael Avalos 	u32 time;
1333360f0f39SAzael Avalos 
1334360f0f39SAzael Avalos 	if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1335360f0f39SAzael Avalos 		return -EIO;
1336360f0f39SAzael Avalos 
1337360f0f39SAzael Avalos 	return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
1338360f0f39SAzael Avalos }
1339360f0f39SAzael Avalos 
13409d8658acSAzael Avalos static ssize_t toshiba_touchpad_store(struct device *dev,
13419d8658acSAzael Avalos 				      struct device_attribute *attr,
13429d8658acSAzael Avalos 				      const char *buf, size_t count)
13439d8658acSAzael Avalos {
13449d8658acSAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
13459d8658acSAzael Avalos 	int state;
1346*c8a41669SAzael Avalos 	int ret;
13479d8658acSAzael Avalos 
13489d8658acSAzael Avalos 	/* Set the TouchPad on/off, 0 - Disable | 1 - Enable */
1349*c8a41669SAzael Avalos 	ret = kstrtoint(buf, 0, &state);
1350*c8a41669SAzael Avalos 	if (ret)
1351*c8a41669SAzael Avalos 		return ret;
1352*c8a41669SAzael Avalos 	if (state != 0 && state != 1)
1353*c8a41669SAzael Avalos 		return -EINVAL;
1354*c8a41669SAzael Avalos 
1355*c8a41669SAzael Avalos 	ret = toshiba_touchpad_set(toshiba, state);
1356*c8a41669SAzael Avalos 	if (ret)
1357*c8a41669SAzael Avalos 		return ret;
13589d8658acSAzael Avalos 
13599d8658acSAzael Avalos 	return count;
13609d8658acSAzael Avalos }
13619d8658acSAzael Avalos 
13629d8658acSAzael Avalos static ssize_t toshiba_touchpad_show(struct device *dev,
13639d8658acSAzael Avalos 				     struct device_attribute *attr, char *buf)
13649d8658acSAzael Avalos {
13659d8658acSAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
13669d8658acSAzael Avalos 	u32 state;
13679d8658acSAzael Avalos 	int ret;
13689d8658acSAzael Avalos 
13699d8658acSAzael Avalos 	ret = toshiba_touchpad_get(toshiba, &state);
13709d8658acSAzael Avalos 	if (ret < 0)
13719d8658acSAzael Avalos 		return ret;
13729d8658acSAzael Avalos 
13739d8658acSAzael Avalos 	return sprintf(buf, "%i\n", state);
13749d8658acSAzael Avalos }
13759d8658acSAzael Avalos 
13765a2813e9SAzael Avalos static ssize_t toshiba_position_show(struct device *dev,
13775a2813e9SAzael Avalos 				     struct device_attribute *attr, char *buf)
13785a2813e9SAzael Avalos {
13795a2813e9SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
13805a2813e9SAzael Avalos 	u32 xyval, zval, tmp;
13815a2813e9SAzael Avalos 	u16 x, y, z;
13825a2813e9SAzael Avalos 	int ret;
13835a2813e9SAzael Avalos 
13845a2813e9SAzael Avalos 	xyval = zval = 0;
13855a2813e9SAzael Avalos 	ret = toshiba_accelerometer_get(toshiba, &xyval, &zval);
13865a2813e9SAzael Avalos 	if (ret < 0)
13875a2813e9SAzael Avalos 		return ret;
13885a2813e9SAzael Avalos 
13895a2813e9SAzael Avalos 	x = xyval & HCI_ACCEL_MASK;
13905a2813e9SAzael Avalos 	tmp = xyval >> HCI_MISC_SHIFT;
13915a2813e9SAzael Avalos 	y = tmp & HCI_ACCEL_MASK;
13925a2813e9SAzael Avalos 	z = zval & HCI_ACCEL_MASK;
13935a2813e9SAzael Avalos 
13945a2813e9SAzael Avalos 	return sprintf(buf, "%d %d %d\n", x, y, z);
13955a2813e9SAzael Avalos }
13965a2813e9SAzael Avalos 
1397360f0f39SAzael Avalos static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
1398360f0f39SAzael Avalos 		   toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
1399360f0f39SAzael Avalos static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
1400360f0f39SAzael Avalos 		   toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
14019d8658acSAzael Avalos static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR,
14029d8658acSAzael Avalos 		   toshiba_touchpad_show, toshiba_touchpad_store);
14035a2813e9SAzael Avalos static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL);
1404360f0f39SAzael Avalos 
1405360f0f39SAzael Avalos static struct attribute *toshiba_attributes[] = {
1406360f0f39SAzael Avalos 	&dev_attr_kbd_backlight_mode.attr,
1407360f0f39SAzael Avalos 	&dev_attr_kbd_backlight_timeout.attr,
14089d8658acSAzael Avalos 	&dev_attr_touchpad.attr,
14095a2813e9SAzael Avalos 	&dev_attr_position.attr,
1410360f0f39SAzael Avalos 	NULL,
1411360f0f39SAzael Avalos };
1412360f0f39SAzael Avalos 
1413360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
1414360f0f39SAzael Avalos 					struct attribute *attr, int idx)
1415360f0f39SAzael Avalos {
1416360f0f39SAzael Avalos 	struct device *dev = container_of(kobj, struct device, kobj);
1417360f0f39SAzael Avalos 	struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
1418360f0f39SAzael Avalos 	bool exists = true;
1419360f0f39SAzael Avalos 
1420360f0f39SAzael Avalos 	if (attr == &dev_attr_kbd_backlight_mode.attr)
1421360f0f39SAzael Avalos 		exists = (drv->kbd_illum_supported) ? true : false;
1422360f0f39SAzael Avalos 	else if (attr == &dev_attr_kbd_backlight_timeout.attr)
1423360f0f39SAzael Avalos 		exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
14249d8658acSAzael Avalos 	else if (attr == &dev_attr_touchpad.attr)
14259d8658acSAzael Avalos 		exists = (drv->touchpad_supported) ? true : false;
14265a2813e9SAzael Avalos 	else if (attr == &dev_attr_position.attr)
14275a2813e9SAzael Avalos 		exists = (drv->accelerometer_supported) ? true : false;
1428360f0f39SAzael Avalos 
1429360f0f39SAzael Avalos 	return exists ? attr->mode : 0;
1430360f0f39SAzael Avalos }
1431360f0f39SAzael Avalos 
1432360f0f39SAzael Avalos static struct attribute_group toshiba_attr_group = {
1433360f0f39SAzael Avalos 	.is_visible = toshiba_sysfs_is_visible,
1434360f0f39SAzael Avalos 	.attrs = toshiba_attributes,
1435360f0f39SAzael Avalos };
1436360f0f39SAzael Avalos 
143729cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
143829cd293fSSeth Forshee 				      struct serio *port)
143929cd293fSSeth Forshee {
144029cd293fSSeth Forshee 	if (str & 0x20)
144129cd293fSSeth Forshee 		return false;
144229cd293fSSeth Forshee 
144329cd293fSSeth Forshee 	if (unlikely(data == 0xe0))
144429cd293fSSeth Forshee 		return false;
144529cd293fSSeth Forshee 
144629cd293fSSeth Forshee 	if ((data & 0x7f) == TOS1900_FN_SCAN) {
144729cd293fSSeth Forshee 		schedule_work(&toshiba_acpi->hotkey_work);
144829cd293fSSeth Forshee 		return true;
144929cd293fSSeth Forshee 	}
145029cd293fSSeth Forshee 
145129cd293fSSeth Forshee 	return false;
145229cd293fSSeth Forshee }
145329cd293fSSeth Forshee 
145429cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work)
145529cd293fSSeth Forshee {
145629cd293fSSeth Forshee 	acpi_handle ec_handle = ec_get_handle();
145729cd293fSSeth Forshee 	acpi_status status;
145829cd293fSSeth Forshee 
145929cd293fSSeth Forshee 	if (!ec_handle)
146029cd293fSSeth Forshee 		return;
146129cd293fSSeth Forshee 
146229cd293fSSeth Forshee 	status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
146329cd293fSSeth Forshee 	if (ACPI_FAILURE(status))
146429cd293fSSeth Forshee 		pr_err("ACPI NTFY method execution failed\n");
146529cd293fSSeth Forshee }
146629cd293fSSeth Forshee 
146729cd293fSSeth Forshee /*
146829cd293fSSeth Forshee  * Returns hotkey scancode, or < 0 on failure.
146929cd293fSSeth Forshee  */
147029cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
147129cd293fSSeth Forshee {
147274facaf7SZhang Rui 	unsigned long long value;
147329cd293fSSeth Forshee 	acpi_status status;
147429cd293fSSeth Forshee 
147574facaf7SZhang Rui 	status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO",
147674facaf7SZhang Rui 				      NULL, &value);
147774facaf7SZhang Rui 	if (ACPI_FAILURE(status)) {
147829cd293fSSeth Forshee 		pr_err("ACPI INFO method execution failed\n");
147929cd293fSSeth Forshee 		return -EIO;
148029cd293fSSeth Forshee 	}
148129cd293fSSeth Forshee 
148274facaf7SZhang Rui 	return value;
148329cd293fSSeth Forshee }
148429cd293fSSeth Forshee 
148529cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
148629cd293fSSeth Forshee 				       int scancode)
148729cd293fSSeth Forshee {
148829cd293fSSeth Forshee 	if (scancode == 0x100)
148929cd293fSSeth Forshee 		return;
149029cd293fSSeth Forshee 
149129cd293fSSeth Forshee 	/* act on key press; ignore key release */
149229cd293fSSeth Forshee 	if (scancode & 0x80)
149329cd293fSSeth Forshee 		return;
149429cd293fSSeth Forshee 
149529cd293fSSeth Forshee 	if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
149629cd293fSSeth Forshee 		pr_info("Unknown key %x\n", scancode);
149729cd293fSSeth Forshee }
149829cd293fSSeth Forshee 
1499b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
15006335e4d5SMatthew Garrett {
1501135740deSSeth Forshee 	acpi_status status;
1502e2e19606SZhang Rui 	acpi_handle ec_handle;
1503135740deSSeth Forshee 	int error;
150429cd293fSSeth Forshee 	u32 hci_result;
1505fe808bfbSTakashi Iwai 	const struct key_entry *keymap = toshiba_acpi_keymap;
1506135740deSSeth Forshee 
1507135740deSSeth Forshee 	dev->hotkey_dev = input_allocate_device();
1508b222cca6SJoe Perches 	if (!dev->hotkey_dev)
1509135740deSSeth Forshee 		return -ENOMEM;
1510135740deSSeth Forshee 
1511135740deSSeth Forshee 	dev->hotkey_dev->name = "Toshiba input device";
15126e02cc7eSSeth Forshee 	dev->hotkey_dev->phys = "toshiba_acpi/input0";
1513135740deSSeth Forshee 	dev->hotkey_dev->id.bustype = BUS_HOST;
1514135740deSSeth Forshee 
1515fe808bfbSTakashi Iwai 	if (dmi_check_system(toshiba_alt_keymap_dmi))
1516fe808bfbSTakashi Iwai 		keymap = toshiba_acpi_alt_keymap;
1517fe808bfbSTakashi Iwai 	error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
1518135740deSSeth Forshee 	if (error)
1519135740deSSeth Forshee 		goto err_free_dev;
1520135740deSSeth Forshee 
152129cd293fSSeth Forshee 	/*
152229cd293fSSeth Forshee 	 * For some machines the SCI responsible for providing hotkey
152329cd293fSSeth Forshee 	 * notification doesn't fire. We can trigger the notification
152429cd293fSSeth Forshee 	 * whenever the Fn key is pressed using the NTFY method, if
152529cd293fSSeth Forshee 	 * supported, so if it's present set up an i8042 key filter
152629cd293fSSeth Forshee 	 * for this purpose.
152729cd293fSSeth Forshee 	 */
152829cd293fSSeth Forshee 	status = AE_ERROR;
152929cd293fSSeth Forshee 	ec_handle = ec_get_handle();
1530e2e19606SZhang Rui 	if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
153129cd293fSSeth Forshee 		INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
153229cd293fSSeth Forshee 
153329cd293fSSeth Forshee 		error = i8042_install_filter(toshiba_acpi_i8042_filter);
153429cd293fSSeth Forshee 		if (error) {
153529cd293fSSeth Forshee 			pr_err("Error installing key filter\n");
153629cd293fSSeth Forshee 			goto err_free_keymap;
153729cd293fSSeth Forshee 		}
153829cd293fSSeth Forshee 
153929cd293fSSeth Forshee 		dev->ntfy_supported = 1;
154029cd293fSSeth Forshee 	}
154129cd293fSSeth Forshee 
154229cd293fSSeth Forshee 	/*
154329cd293fSSeth Forshee 	 * Determine hotkey query interface. Prefer using the INFO
154429cd293fSSeth Forshee 	 * method when it is available.
154529cd293fSSeth Forshee 	 */
1546e2e19606SZhang Rui 	if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
154729cd293fSSeth Forshee 		dev->info_supported = 1;
1548e2e19606SZhang Rui 	else {
154929cd293fSSeth Forshee 		hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
155029cd293fSSeth Forshee 		if (hci_result == HCI_SUCCESS)
155129cd293fSSeth Forshee 			dev->system_event_supported = 1;
155229cd293fSSeth Forshee 	}
155329cd293fSSeth Forshee 
155429cd293fSSeth Forshee 	if (!dev->info_supported && !dev->system_event_supported) {
155529cd293fSSeth Forshee 		pr_warn("No hotkey query interface found\n");
155629cd293fSSeth Forshee 		goto err_remove_filter;
155729cd293fSSeth Forshee 	}
155829cd293fSSeth Forshee 
15596e02cc7eSSeth Forshee 	status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL);
1560135740deSSeth Forshee 	if (ACPI_FAILURE(status)) {
1561135740deSSeth Forshee 		pr_info("Unable to enable hotkeys\n");
1562135740deSSeth Forshee 		error = -ENODEV;
156329cd293fSSeth Forshee 		goto err_remove_filter;
1564135740deSSeth Forshee 	}
1565135740deSSeth Forshee 
1566135740deSSeth Forshee 	error = input_register_device(dev->hotkey_dev);
1567135740deSSeth Forshee 	if (error) {
1568135740deSSeth Forshee 		pr_info("Unable to register input device\n");
156929cd293fSSeth Forshee 		goto err_remove_filter;
1570135740deSSeth Forshee 	}
1571135740deSSeth Forshee 
157229cd293fSSeth Forshee 	hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &hci_result);
1573135740deSSeth Forshee 	return 0;
1574135740deSSeth Forshee 
157529cd293fSSeth Forshee  err_remove_filter:
157629cd293fSSeth Forshee 	if (dev->ntfy_supported)
157729cd293fSSeth Forshee 		i8042_remove_filter(toshiba_acpi_i8042_filter);
1578135740deSSeth Forshee  err_free_keymap:
1579135740deSSeth Forshee 	sparse_keymap_free(dev->hotkey_dev);
1580135740deSSeth Forshee  err_free_dev:
1581135740deSSeth Forshee 	input_free_device(dev->hotkey_dev);
1582135740deSSeth Forshee 	dev->hotkey_dev = NULL;
1583135740deSSeth Forshee 	return error;
1584135740deSSeth Forshee }
1585135740deSSeth Forshee 
1586b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
158762cce752SSeth Forshee {
158862cce752SSeth Forshee 	struct backlight_properties props;
158962cce752SSeth Forshee 	int brightness;
159062cce752SSeth Forshee 	int ret;
1591121b7b0dSAkio Idehara 	bool enabled;
159262cce752SSeth Forshee 
159362cce752SSeth Forshee 	/*
159462cce752SSeth Forshee 	 * Some machines don't support the backlight methods at all, and
159562cce752SSeth Forshee 	 * others support it read-only. Either of these is pretty useless,
159662cce752SSeth Forshee 	 * so only register the backlight device if the backlight method
159762cce752SSeth Forshee 	 * supports both reads and writes.
159862cce752SSeth Forshee 	 */
159962cce752SSeth Forshee 	brightness = __get_lcd_brightness(dev);
160062cce752SSeth Forshee 	if (brightness < 0)
160162cce752SSeth Forshee 		return 0;
160262cce752SSeth Forshee 	ret = set_lcd_brightness(dev, brightness);
160362cce752SSeth Forshee 	if (ret) {
160462cce752SSeth Forshee 		pr_debug("Backlight method is read-only, disabling backlight support\n");
160562cce752SSeth Forshee 		return 0;
160662cce752SSeth Forshee 	}
160762cce752SSeth Forshee 
1608121b7b0dSAkio Idehara 	/* Determine whether or not BIOS supports transflective backlight */
1609121b7b0dSAkio Idehara 	ret = get_tr_backlight_status(dev, &enabled);
1610121b7b0dSAkio Idehara 	dev->tr_backlight_supported = !ret;
1611121b7b0dSAkio Idehara 
161253039f22SMatthew Garrett 	memset(&props, 0, sizeof(props));
161362cce752SSeth Forshee 	props.type = BACKLIGHT_PLATFORM;
161462cce752SSeth Forshee 	props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
161562cce752SSeth Forshee 
1616121b7b0dSAkio Idehara 	/* adding an extra level and having 0 change to transflective mode */
1617121b7b0dSAkio Idehara 	if (dev->tr_backlight_supported)
1618121b7b0dSAkio Idehara 		props.max_brightness++;
1619121b7b0dSAkio Idehara 
162062cce752SSeth Forshee 	dev->backlight_dev = backlight_device_register("toshiba",
162162cce752SSeth Forshee 						       &dev->acpi_dev->dev,
162262cce752SSeth Forshee 						       dev,
162362cce752SSeth Forshee 						       &toshiba_backlight_data,
162462cce752SSeth Forshee 						       &props);
162562cce752SSeth Forshee 	if (IS_ERR(dev->backlight_dev)) {
162662cce752SSeth Forshee 		ret = PTR_ERR(dev->backlight_dev);
162762cce752SSeth Forshee 		pr_err("Could not register toshiba backlight device\n");
162862cce752SSeth Forshee 		dev->backlight_dev = NULL;
162962cce752SSeth Forshee 		return ret;
163062cce752SSeth Forshee 	}
163162cce752SSeth Forshee 
163262cce752SSeth Forshee 	dev->backlight_dev->props.brightness = brightness;
163362cce752SSeth Forshee 	return 0;
163462cce752SSeth Forshee }
163562cce752SSeth Forshee 
163651fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
1637135740deSSeth Forshee {
1638135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
1639135740deSSeth Forshee 
164036d03f93SSeth Forshee 	remove_toshiba_proc_entries(dev);
1641135740deSSeth Forshee 
1642360f0f39SAzael Avalos 	if (dev->sysfs_created)
1643360f0f39SAzael Avalos 		sysfs_remove_group(&dev->acpi_dev->dev.kobj,
1644360f0f39SAzael Avalos 				   &toshiba_attr_group);
1645360f0f39SAzael Avalos 
164629cd293fSSeth Forshee 	if (dev->ntfy_supported) {
164729cd293fSSeth Forshee 		i8042_remove_filter(toshiba_acpi_i8042_filter);
164829cd293fSSeth Forshee 		cancel_work_sync(&dev->hotkey_work);
164929cd293fSSeth Forshee 	}
165029cd293fSSeth Forshee 
1651135740deSSeth Forshee 	if (dev->hotkey_dev) {
1652135740deSSeth Forshee 		input_unregister_device(dev->hotkey_dev);
1653135740deSSeth Forshee 		sparse_keymap_free(dev->hotkey_dev);
1654135740deSSeth Forshee 	}
1655135740deSSeth Forshee 
1656135740deSSeth Forshee 	if (dev->bt_rfk) {
1657135740deSSeth Forshee 		rfkill_unregister(dev->bt_rfk);
1658135740deSSeth Forshee 		rfkill_destroy(dev->bt_rfk);
1659135740deSSeth Forshee 	}
1660135740deSSeth Forshee 
1661135740deSSeth Forshee 	if (dev->backlight_dev)
1662135740deSSeth Forshee 		backlight_device_unregister(dev->backlight_dev);
1663135740deSSeth Forshee 
166436d03f93SSeth Forshee 	if (dev->illumination_supported)
1665135740deSSeth Forshee 		led_classdev_unregister(&dev->led_dev);
1666135740deSSeth Forshee 
1667360f0f39SAzael Avalos 	if (dev->kbd_led_registered)
1668360f0f39SAzael Avalos 		led_classdev_unregister(&dev->kbd_led);
1669360f0f39SAzael Avalos 
1670def6c4e2SAzael Avalos 	if (dev->eco_supported)
1671def6c4e2SAzael Avalos 		led_classdev_unregister(&dev->eco_led);
1672def6c4e2SAzael Avalos 
167329cd293fSSeth Forshee 	if (toshiba_acpi)
167429cd293fSSeth Forshee 		toshiba_acpi = NULL;
167529cd293fSSeth Forshee 
1676135740deSSeth Forshee 	kfree(dev);
1677135740deSSeth Forshee 
1678135740deSSeth Forshee 	return 0;
1679135740deSSeth Forshee }
1680135740deSSeth Forshee 
1681b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle)
1682a540d6b5SSeth Forshee {
1683e2e19606SZhang Rui 	if (acpi_has_method(handle, "GHCI"))
1684a540d6b5SSeth Forshee 		return "GHCI";
1685a540d6b5SSeth Forshee 
1686e2e19606SZhang Rui 	if (acpi_has_method(handle, "SPFC"))
1687a540d6b5SSeth Forshee 		return "SPFC";
1688a540d6b5SSeth Forshee 
1689a540d6b5SSeth Forshee 	return NULL;
1690a540d6b5SSeth Forshee }
1691a540d6b5SSeth Forshee 
1692b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev)
1693135740deSSeth Forshee {
1694135740deSSeth Forshee 	struct toshiba_acpi_dev *dev;
1695a540d6b5SSeth Forshee 	const char *hci_method;
169636d03f93SSeth Forshee 	u32 dummy;
1697135740deSSeth Forshee 	bool bt_present;
1698135740deSSeth Forshee 	int ret = 0;
1699135740deSSeth Forshee 
170029cd293fSSeth Forshee 	if (toshiba_acpi)
170129cd293fSSeth Forshee 		return -EBUSY;
170229cd293fSSeth Forshee 
1703135740deSSeth Forshee 	pr_info("Toshiba Laptop ACPI Extras version %s\n",
1704135740deSSeth Forshee 	       TOSHIBA_ACPI_VERSION);
1705135740deSSeth Forshee 
1706a540d6b5SSeth Forshee 	hci_method = find_hci_method(acpi_dev->handle);
1707a540d6b5SSeth Forshee 	if (!hci_method) {
1708a540d6b5SSeth Forshee 		pr_err("HCI interface not found\n");
17096e02cc7eSSeth Forshee 		return -ENODEV;
1710a540d6b5SSeth Forshee 	}
17116e02cc7eSSeth Forshee 
1712135740deSSeth Forshee 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1713135740deSSeth Forshee 	if (!dev)
1714135740deSSeth Forshee 		return -ENOMEM;
1715135740deSSeth Forshee 	dev->acpi_dev = acpi_dev;
1716a540d6b5SSeth Forshee 	dev->method_hci = hci_method;
1717135740deSSeth Forshee 	acpi_dev->driver_data = dev;
1718360f0f39SAzael Avalos 	dev_set_drvdata(&acpi_dev->dev, dev);
1719135740deSSeth Forshee 
17206e02cc7eSSeth Forshee 	if (toshiba_acpi_setup_keyboard(dev))
1721135740deSSeth Forshee 		pr_info("Unable to activate hotkeys\n");
1722135740deSSeth Forshee 
1723135740deSSeth Forshee 	mutex_init(&dev->mutex);
1724135740deSSeth Forshee 
172562cce752SSeth Forshee 	ret = toshiba_acpi_setup_backlight(dev);
172662cce752SSeth Forshee 	if (ret)
1727135740deSSeth Forshee 		goto error;
1728135740deSSeth Forshee 
1729135740deSSeth Forshee 	/* Register rfkill switch for Bluetooth */
1730135740deSSeth Forshee 	if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) {
1731135740deSSeth Forshee 		dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth",
1732135740deSSeth Forshee 					   &acpi_dev->dev,
1733135740deSSeth Forshee 					   RFKILL_TYPE_BLUETOOTH,
1734135740deSSeth Forshee 					   &toshiba_rfk_ops,
1735135740deSSeth Forshee 					   dev);
1736135740deSSeth Forshee 		if (!dev->bt_rfk) {
1737135740deSSeth Forshee 			pr_err("unable to allocate rfkill device\n");
1738135740deSSeth Forshee 			ret = -ENOMEM;
1739135740deSSeth Forshee 			goto error;
1740135740deSSeth Forshee 		}
1741135740deSSeth Forshee 
1742135740deSSeth Forshee 		ret = rfkill_register(dev->bt_rfk);
1743135740deSSeth Forshee 		if (ret) {
1744135740deSSeth Forshee 			pr_err("unable to register rfkill device\n");
1745135740deSSeth Forshee 			rfkill_destroy(dev->bt_rfk);
1746135740deSSeth Forshee 			goto error;
1747135740deSSeth Forshee 		}
1748135740deSSeth Forshee 	}
1749135740deSSeth Forshee 
1750135740deSSeth Forshee 	if (toshiba_illumination_available(dev)) {
1751135740deSSeth Forshee 		dev->led_dev.name = "toshiba::illumination";
1752135740deSSeth Forshee 		dev->led_dev.max_brightness = 1;
1753135740deSSeth Forshee 		dev->led_dev.brightness_set = toshiba_illumination_set;
1754135740deSSeth Forshee 		dev->led_dev.brightness_get = toshiba_illumination_get;
1755135740deSSeth Forshee 		if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev))
175636d03f93SSeth Forshee 			dev->illumination_supported = 1;
1757135740deSSeth Forshee 	}
1758135740deSSeth Forshee 
1759def6c4e2SAzael Avalos 	if (toshiba_eco_mode_available(dev)) {
1760def6c4e2SAzael Avalos 		dev->eco_led.name = "toshiba::eco_mode";
1761def6c4e2SAzael Avalos 		dev->eco_led.max_brightness = 1;
1762def6c4e2SAzael Avalos 		dev->eco_led.brightness_set = toshiba_eco_mode_set_status;
1763def6c4e2SAzael Avalos 		dev->eco_led.brightness_get = toshiba_eco_mode_get_status;
1764def6c4e2SAzael Avalos 		if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led))
1765def6c4e2SAzael Avalos 			dev->eco_supported = 1;
1766def6c4e2SAzael Avalos 	}
1767def6c4e2SAzael Avalos 
1768360f0f39SAzael Avalos 	ret = toshiba_kbd_illum_status_get(dev, &dummy);
1769360f0f39SAzael Avalos 	if (!ret) {
1770360f0f39SAzael Avalos 		dev->kbd_time = dummy >> HCI_MISC_SHIFT;
1771360f0f39SAzael Avalos 		dev->kbd_mode = dummy & 0x07;
1772360f0f39SAzael Avalos 	}
1773360f0f39SAzael Avalos 	dev->kbd_illum_supported = !ret;
1774360f0f39SAzael Avalos 	/*
1775360f0f39SAzael Avalos 	 * Only register the LED if KBD illumination is supported
1776360f0f39SAzael Avalos 	 * and the keyboard backlight operation mode is set to FN-Z
1777360f0f39SAzael Avalos 	 */
1778360f0f39SAzael Avalos 	if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) {
1779360f0f39SAzael Avalos 		dev->kbd_led.name = "toshiba::kbd_backlight";
1780360f0f39SAzael Avalos 		dev->kbd_led.max_brightness = 1;
1781360f0f39SAzael Avalos 		dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
1782360f0f39SAzael Avalos 		dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
1783360f0f39SAzael Avalos 		if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led))
1784360f0f39SAzael Avalos 			dev->kbd_led_registered = 1;
1785360f0f39SAzael Avalos 	}
1786360f0f39SAzael Avalos 
17879d8658acSAzael Avalos 	ret = toshiba_touchpad_get(dev, &dummy);
17889d8658acSAzael Avalos 	dev->touchpad_supported = !ret;
17899d8658acSAzael Avalos 
17905a2813e9SAzael Avalos 	ret = toshiba_accelerometer_supported(dev);
17915a2813e9SAzael Avalos 	dev->accelerometer_supported = !ret;
17925a2813e9SAzael Avalos 
179336d03f93SSeth Forshee 	/* Determine whether or not BIOS supports fan and video interfaces */
179436d03f93SSeth Forshee 
179536d03f93SSeth Forshee 	ret = get_video_status(dev, &dummy);
179636d03f93SSeth Forshee 	dev->video_supported = !ret;
179736d03f93SSeth Forshee 
179836d03f93SSeth Forshee 	ret = get_fan_status(dev, &dummy);
179936d03f93SSeth Forshee 	dev->fan_supported = !ret;
180036d03f93SSeth Forshee 
1801360f0f39SAzael Avalos 	ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
1802360f0f39SAzael Avalos 				 &toshiba_attr_group);
1803360f0f39SAzael Avalos 	if (ret) {
1804360f0f39SAzael Avalos 		dev->sysfs_created = 0;
1805360f0f39SAzael Avalos 		goto error;
1806360f0f39SAzael Avalos 	}
1807360f0f39SAzael Avalos 	dev->sysfs_created = !ret;
1808360f0f39SAzael Avalos 
180936d03f93SSeth Forshee 	create_toshiba_proc_entries(dev);
181036d03f93SSeth Forshee 
181129cd293fSSeth Forshee 	toshiba_acpi = dev;
181229cd293fSSeth Forshee 
1813135740deSSeth Forshee 	return 0;
1814135740deSSeth Forshee 
1815135740deSSeth Forshee error:
181651fac838SRafael J. Wysocki 	toshiba_acpi_remove(acpi_dev);
1817135740deSSeth Forshee 	return ret;
1818135740deSSeth Forshee }
1819135740deSSeth Forshee 
1820135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
1821135740deSSeth Forshee {
1822135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
18236335e4d5SMatthew Garrett 	u32 hci_result, value;
182411948b93SSeth Forshee 	int retries = 3;
182529cd293fSSeth Forshee 	int scancode;
18266335e4d5SMatthew Garrett 
182729cd293fSSeth Forshee 	if (event != 0x80)
18286335e4d5SMatthew Garrett 		return;
182911948b93SSeth Forshee 
183029cd293fSSeth Forshee 	if (dev->info_supported) {
183129cd293fSSeth Forshee 		scancode = toshiba_acpi_query_hotkey(dev);
183229cd293fSSeth Forshee 		if (scancode < 0)
183329cd293fSSeth Forshee 			pr_err("Failed to query hotkey event\n");
183429cd293fSSeth Forshee 		else if (scancode != 0)
183529cd293fSSeth Forshee 			toshiba_acpi_report_hotkey(dev, scancode);
183629cd293fSSeth Forshee 	} else if (dev->system_event_supported) {
18376335e4d5SMatthew Garrett 		do {
1838135740deSSeth Forshee 			hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
183911948b93SSeth Forshee 			switch (hci_result) {
184011948b93SSeth Forshee 			case HCI_SUCCESS:
184129cd293fSSeth Forshee 				toshiba_acpi_report_hotkey(dev, (int)value);
184211948b93SSeth Forshee 				break;
184311948b93SSeth Forshee 			case HCI_NOT_SUPPORTED:
184429cd293fSSeth Forshee 				/*
184529cd293fSSeth Forshee 				 * This is a workaround for an unresolved
184629cd293fSSeth Forshee 				 * issue on some machines where system events
184729cd293fSSeth Forshee 				 * sporadically become disabled.
184829cd293fSSeth Forshee 				 */
184929cd293fSSeth Forshee 				hci_write1(dev, HCI_SYSTEM_EVENT, 1,
185029cd293fSSeth Forshee 					   &hci_result);
18517e33460dSJoe Perches 				pr_notice("Re-enabled hotkeys\n");
185211948b93SSeth Forshee 				/* fall through */
185311948b93SSeth Forshee 			default:
185411948b93SSeth Forshee 				retries--;
185511948b93SSeth Forshee 				break;
18566335e4d5SMatthew Garrett 			}
185711948b93SSeth Forshee 		} while (retries && hci_result != HCI_EMPTY);
18586335e4d5SMatthew Garrett 	}
185929cd293fSSeth Forshee }
18606335e4d5SMatthew Garrett 
18613567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
186243d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device)
186329cd293fSSeth Forshee {
186443d2fd3bSRafael J. Wysocki 	struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
186529cd293fSSeth Forshee 	u32 result;
186629cd293fSSeth Forshee 
186729cd293fSSeth Forshee 	if (dev->hotkey_dev)
186829cd293fSSeth Forshee 		hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE, &result);
186929cd293fSSeth Forshee 
187029cd293fSSeth Forshee 	return 0;
187129cd293fSSeth Forshee }
187229cd293fSSeth Forshee 
187343d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device)
187429cd293fSSeth Forshee {
187543d2fd3bSRafael J. Wysocki 	struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
187629cd293fSSeth Forshee 	u32 result;
1877e7fdb762SBenjamin Tissoires 	acpi_status status;
187829cd293fSSeth Forshee 
1879e7fdb762SBenjamin Tissoires 	if (dev->hotkey_dev) {
1880e7fdb762SBenjamin Tissoires 		status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB",
1881e7fdb762SBenjamin Tissoires 				NULL, NULL);
1882e7fdb762SBenjamin Tissoires 		if (ACPI_FAILURE(status))
1883e7fdb762SBenjamin Tissoires 			pr_info("Unable to re-enable hotkeys\n");
1884e7fdb762SBenjamin Tissoires 
188529cd293fSSeth Forshee 		hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
1886e7fdb762SBenjamin Tissoires 	}
188729cd293fSSeth Forshee 
188829cd293fSSeth Forshee 	return 0;
188929cd293fSSeth Forshee }
18903567a4e2SRafael J. Wysocki #endif
18916335e4d5SMatthew Garrett 
189243d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
189343d2fd3bSRafael J. Wysocki 			 toshiba_acpi_suspend, toshiba_acpi_resume);
189443d2fd3bSRafael J. Wysocki 
1895135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = {
1896135740deSSeth Forshee 	.name	= "Toshiba ACPI driver",
1897135740deSSeth Forshee 	.owner	= THIS_MODULE,
1898135740deSSeth Forshee 	.ids	= toshiba_device_ids,
1899135740deSSeth Forshee 	.flags	= ACPI_DRIVER_ALL_NOTIFY_EVENTS,
1900135740deSSeth Forshee 	.ops	= {
1901135740deSSeth Forshee 		.add		= toshiba_acpi_add,
1902135740deSSeth Forshee 		.remove		= toshiba_acpi_remove,
1903135740deSSeth Forshee 		.notify		= toshiba_acpi_notify,
1904135740deSSeth Forshee 	},
190543d2fd3bSRafael J. Wysocki 	.drv.pm	= &toshiba_acpi_pm,
1906135740deSSeth Forshee };
1907b4f9fe12SLen Brown 
1908b4f9fe12SLen Brown static int __init toshiba_acpi_init(void)
1909b4f9fe12SLen Brown {
1910135740deSSeth Forshee 	int ret;
1911b4f9fe12SLen Brown 
1912f11f999eSSeth Forshee 	/*
1913f11f999eSSeth Forshee 	 * Machines with this WMI guid aren't supported due to bugs in
1914f11f999eSSeth Forshee 	 * their AML. This check relies on wmi initializing before
1915f11f999eSSeth Forshee 	 * toshiba_acpi to guarantee guids have been identified.
1916f11f999eSSeth Forshee 	 */
1917f11f999eSSeth Forshee 	if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
1918f11f999eSSeth Forshee 		return -ENODEV;
1919f11f999eSSeth Forshee 
1920b4f9fe12SLen Brown 	toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
1921b4f9fe12SLen Brown 	if (!toshiba_proc_dir) {
1922135740deSSeth Forshee 		pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
1923b4f9fe12SLen Brown 		return -ENODEV;
1924b4f9fe12SLen Brown 	}
1925b4f9fe12SLen Brown 
1926135740deSSeth Forshee 	ret = acpi_bus_register_driver(&toshiba_acpi_driver);
1927b4f9fe12SLen Brown 	if (ret) {
1928135740deSSeth Forshee 		pr_err("Failed to register ACPI driver: %d\n", ret);
1929135740deSSeth Forshee 		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
1930135740deSSeth Forshee 	}
1931135740deSSeth Forshee 
1932b4f9fe12SLen Brown 	return ret;
1933b4f9fe12SLen Brown }
1934b4f9fe12SLen Brown 
1935135740deSSeth Forshee static void __exit toshiba_acpi_exit(void)
1936135740deSSeth Forshee {
1937135740deSSeth Forshee 	acpi_bus_unregister_driver(&toshiba_acpi_driver);
1938135740deSSeth Forshee 	if (toshiba_proc_dir)
1939135740deSSeth Forshee 		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
1940b4f9fe12SLen Brown }
1941b4f9fe12SLen Brown 
1942b4f9fe12SLen Brown module_init(toshiba_acpi_init);
1943b4f9fe12SLen Brown module_exit(toshiba_acpi_exit);
1944