blob: 95ae1ffaf4093364eb7f6840fd58e26dbc4d5651 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * toshiba_acpi.c - Toshiba Laptop ACPI Extras
3 *
4 *
5 * Copyright (C) 2002-2004 John Belmonte
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04006 * Copyright (C) 2008 Philip Langdale
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +02007 * Copyright (C) 2010 Pierre Ducroquet
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 *
24 * The devolpment page for this driver is located at
25 * http://memebeam.org/toys/ToshibaAcpiDriver.
26 *
27 * Credits:
28 * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
29 * engineering the Windows drivers
30 * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
31 * Rob Miller - TV out and hotkeys help
32 *
33 *
34 * TODO
35 *
36 */
37
Joe Perches7e334602011-03-29 15:21:52 -070038#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
39
philipl@overt.orgc41a40c2008-08-30 11:57:39 -040040#define TOSHIBA_ACPI_VERSION "0.19"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#define PROC_INTERFACE_VERSION 1
42
43#include <linux/kernel.h>
44#include <linux/module.h>
45#include <linux/init.h>
46#include <linux/types.h>
47#include <linux/proc_fs.h>
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -080048#include <linux/seq_file.h>
Holger Machtc9263552006-10-20 14:30:29 -070049#include <linux/backlight.h>
philipl@overt.orgc41a40c2008-08-30 11:57:39 -040050#include <linux/rfkill.h>
Matthew Garrett6335e4d2010-02-25 15:20:54 -050051#include <linux/input.h>
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -070052#include <linux/input/sparse-keymap.h>
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +020053#include <linux/leds.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090054#include <linux/slab.h>
Seth Forshee29cd2932012-01-18 13:44:09 -060055#include <linux/workqueue.h>
56#include <linux/i8042.h>
Lv Zheng8b484632013-12-03 08:49:16 +080057#include <linux/acpi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <asm/uaccess.h>
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060MODULE_AUTHOR("John Belmonte");
61MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
62MODULE_LICENSE("GPL");
63
Seth Forsheef11f9992012-01-18 13:44:11 -060064#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
65
Seth Forshee29cd2932012-01-18 13:44:09 -060066/* Scan code for Fn key on TOS1900 models */
67#define TOS1900_FN_SCAN 0x6e
68
Linus Torvalds1da177e2005-04-16 15:20:36 -070069/* Toshiba ACPI method paths */
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
71
72/* Toshiba HCI interface definitions
73 *
74 * HCI is Toshiba's "Hardware Control Interface" which is supposed to
75 * be uniform across all their models. Ideally we would just call
76 * dedicated ACPI methods instead of using this primitive interface.
77 * However the ACPI methods seem to be incomplete in some areas (for
78 * example they allow setting, but not reading, the LCD brightness value),
79 * so this is still useful.
Azael Avalos84a62732014-03-25 20:38:29 -060080 *
81 * SCI stands for "System Configuration Interface" which aim is to
82 * conceal differences in hardware between different models.
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 */
84
85#define HCI_WORDS 6
86
87/* operations */
88#define HCI_SET 0xff00
89#define HCI_GET 0xfe00
Azael Avalos84a62732014-03-25 20:38:29 -060090#define SCI_OPEN 0xf100
91#define SCI_CLOSE 0xf200
92#define SCI_GET 0xf300
93#define SCI_SET 0xf400
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95/* return codes */
96#define HCI_SUCCESS 0x0000
97#define HCI_FAILURE 0x1000
98#define HCI_NOT_SUPPORTED 0x8000
99#define HCI_EMPTY 0x8c00
Azael Avalos84a62732014-03-25 20:38:29 -0600100#define SCI_OPEN_CLOSE_OK 0x0044
101#define SCI_ALREADY_OPEN 0x8100
102#define SCI_NOT_OPENED 0x8200
Azael Avalosfdb79082014-03-25 20:38:30 -0600103#define SCI_INPUT_DATA_ERROR 0x8300
Azael Avalos84a62732014-03-25 20:38:29 -0600104#define SCI_NOT_PRESENT 0x8600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
106/* registers */
107#define HCI_FAN 0x0004
Akio Idehara121b7b02012-04-06 01:46:43 +0900108#define HCI_TR_BACKLIGHT 0x0005
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#define HCI_SYSTEM_EVENT 0x0016
110#define HCI_VIDEO_OUT 0x001c
111#define HCI_HOTKEY_EVENT 0x001e
112#define HCI_LCD_BRIGHTNESS 0x002a
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400113#define HCI_WIRELESS 0x0056
Azael Avalos360f0f32014-03-25 20:38:31 -0600114#define HCI_KBD_ILLUMINATION 0x0095
Azael Avalosfdb79082014-03-25 20:38:30 -0600115#define SCI_ILLUMINATION 0x014e
Azael Avalos360f0f32014-03-25 20:38:31 -0600116#define SCI_KBD_ILLUM_STATUS 0x015c
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
118/* field definitions */
Seth Forshee29cd2932012-01-18 13:44:09 -0600119#define HCI_HOTKEY_DISABLE 0x0b
120#define HCI_HOTKEY_ENABLE 0x09
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#define HCI_LCD_BRIGHTNESS_BITS 3
122#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
123#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
Azael Avalos360f0f32014-03-25 20:38:31 -0600124#define HCI_MISC_SHIFT 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125#define HCI_VIDEO_OUT_LCD 0x1
126#define HCI_VIDEO_OUT_CRT 0x2
127#define HCI_VIDEO_OUT_TV 0x4
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400128#define HCI_WIRELESS_KILL_SWITCH 0x01
129#define HCI_WIRELESS_BT_PRESENT 0x0f
130#define HCI_WIRELESS_BT_ATTACH 0x40
131#define HCI_WIRELESS_BT_POWER 0x80
Azael Avalos360f0f32014-03-25 20:38:31 -0600132#define SCI_KBD_MODE_FNZ 0x1
133#define SCI_KBD_MODE_AUTO 0x2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Seth Forshee135740d2011-09-20 16:55:49 -0500135struct toshiba_acpi_dev {
136 struct acpi_device *acpi_dev;
137 const char *method_hci;
138 struct rfkill *bt_rfk;
139 struct input_dev *hotkey_dev;
Seth Forshee29cd2932012-01-18 13:44:09 -0600140 struct work_struct hotkey_work;
Seth Forshee135740d2011-09-20 16:55:49 -0500141 struct backlight_device *backlight_dev;
142 struct led_classdev led_dev;
Azael Avalos360f0f32014-03-25 20:38:31 -0600143 struct led_classdev kbd_led;
Seth Forshee36d03f92011-09-20 16:55:53 -0500144
Seth Forshee135740d2011-09-20 16:55:49 -0500145 int force_fan;
146 int last_key_event;
147 int key_event_valid;
Azael Avalos360f0f32014-03-25 20:38:31 -0600148 int kbd_mode;
149 int kbd_time;
Seth Forshee135740d2011-09-20 16:55:49 -0500150
Dan Carpenter592b7462012-01-15 14:28:20 +0300151 unsigned int illumination_supported:1;
152 unsigned int video_supported:1;
153 unsigned int fan_supported:1;
154 unsigned int system_event_supported:1;
Seth Forshee29cd2932012-01-18 13:44:09 -0600155 unsigned int ntfy_supported:1;
156 unsigned int info_supported:1;
Akio Idehara121b7b02012-04-06 01:46:43 +0900157 unsigned int tr_backlight_supported:1;
Azael Avalos360f0f32014-03-25 20:38:31 -0600158 unsigned int kbd_illum_supported:1;
159 unsigned int kbd_led_registered:1;
160 unsigned int sysfs_created:1;
Seth Forshee36d03f92011-09-20 16:55:53 -0500161
Seth Forshee135740d2011-09-20 16:55:49 -0500162 struct mutex mutex;
163};
164
Seth Forshee29cd2932012-01-18 13:44:09 -0600165static struct toshiba_acpi_dev *toshiba_acpi;
166
arvidjaar@mail.ru4db42c52008-03-04 15:06:34 -0800167static const struct acpi_device_id toshiba_device_ids[] = {
168 {"TOS6200", 0},
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400169 {"TOS6208", 0},
arvidjaar@mail.ru4db42c52008-03-04 15:06:34 -0800170 {"TOS1900", 0},
171 {"", 0},
172};
173MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
174
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -0800175static const struct key_entry toshiba_acpi_keymap[] = {
Unai Uribarrifec278a2014-01-14 11:06:47 +0100176 { KE_KEY, 0x9e, { KEY_RFKILL } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700177 { KE_KEY, 0x101, { KEY_MUTE } },
178 { KE_KEY, 0x102, { KEY_ZOOMOUT } },
179 { KE_KEY, 0x103, { KEY_ZOOMIN } },
Azael Avalosaf502832012-01-18 13:44:10 -0600180 { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
181 { KE_KEY, 0x139, { KEY_ZOOMRESET } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700182 { KE_KEY, 0x13b, { KEY_COFFEE } },
183 { KE_KEY, 0x13c, { KEY_BATTERY } },
184 { KE_KEY, 0x13d, { KEY_SLEEP } },
185 { KE_KEY, 0x13e, { KEY_SUSPEND } },
186 { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
187 { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
188 { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
189 { KE_KEY, 0x142, { KEY_WLAN } },
Azael Avalosaf502832012-01-18 13:44:10 -0600190 { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
Jon Dowlanda49010f2010-10-27 00:24:59 +0100191 { KE_KEY, 0x17f, { KEY_FN } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700192 { KE_KEY, 0xb05, { KEY_PROG2 } },
193 { KE_KEY, 0xb06, { KEY_WWW } },
194 { KE_KEY, 0xb07, { KEY_MAIL } },
195 { KE_KEY, 0xb30, { KEY_STOP } },
196 { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
197 { KE_KEY, 0xb32, { KEY_NEXTSONG } },
198 { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
199 { KE_KEY, 0xb5a, { KEY_MEDIA } },
Azael Avalosaf502832012-01-18 13:44:10 -0600200 { KE_IGNORE, 0x1430, { KEY_RESERVED } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700201 { KE_END, 0 },
Matthew Garrett6335e4d2010-02-25 15:20:54 -0500202};
203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204/* utility
205 */
206
Len Brown4be44fc2005-08-05 00:44:28 -0400207static __inline__ void _set_bit(u32 * word, u32 mask, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 *word = (*word & ~mask) | (mask * value);
210}
211
212/* acpi interface wrappers
213 */
214
Len Brown4be44fc2005-08-05 00:44:28 -0400215static int write_acpi_int(const char *methodName, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 acpi_status status;
218
Zhang Rui619400d2013-09-03 08:31:56 +0800219 status = acpi_execute_simple_method(NULL, (char *)methodName, val);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500220 return (status == AE_OK) ? 0 : -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221}
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223/* Perform a raw HCI call. Here we don't care about input or output buffer
224 * format.
225 */
Seth Forshee135740d2011-09-20 16:55:49 -0500226static acpi_status hci_raw(struct toshiba_acpi_dev *dev,
227 const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 struct acpi_object_list params;
230 union acpi_object in_objs[HCI_WORDS];
231 struct acpi_buffer results;
Len Brown4be44fc2005-08-05 00:44:28 -0400232 union acpi_object out_objs[HCI_WORDS + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 acpi_status status;
234 int i;
235
236 params.count = HCI_WORDS;
237 params.pointer = in_objs;
238 for (i = 0; i < HCI_WORDS; ++i) {
239 in_objs[i].type = ACPI_TYPE_INTEGER;
240 in_objs[i].integer.value = in[i];
241 }
242
243 results.length = sizeof(out_objs);
244 results.pointer = out_objs;
245
Seth Forshee6e02cc72011-09-20 16:55:51 -0500246 status = acpi_evaluate_object(dev->acpi_dev->handle,
247 (char *)dev->method_hci, &params,
Len Brown4be44fc2005-08-05 00:44:28 -0400248 &results);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) {
250 for (i = 0; i < out_objs->package.count; ++i) {
251 out[i] = out_objs->package.elements[i].integer.value;
252 }
253 }
254
255 return status;
256}
257
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400258/* common hci tasks (get or set one or two value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 *
260 * In addition to the ACPI status, the HCI system returns a result which
261 * may be useful (such as "not supported").
262 */
263
Seth Forshee135740d2011-09-20 16:55:49 -0500264static acpi_status hci_write1(struct toshiba_acpi_dev *dev, u32 reg,
265 u32 in1, u32 *result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
267 u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
268 u32 out[HCI_WORDS];
Seth Forshee135740d2011-09-20 16:55:49 -0500269 acpi_status status = hci_raw(dev, in, out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
271 return status;
272}
273
Seth Forshee135740d2011-09-20 16:55:49 -0500274static acpi_status hci_read1(struct toshiba_acpi_dev *dev, u32 reg,
275 u32 *out1, u32 *result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
277 u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
278 u32 out[HCI_WORDS];
Seth Forshee135740d2011-09-20 16:55:49 -0500279 acpi_status status = hci_raw(dev, in, out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 *out1 = out[2];
281 *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
282 return status;
283}
284
Seth Forshee135740d2011-09-20 16:55:49 -0500285static acpi_status hci_write2(struct toshiba_acpi_dev *dev, u32 reg,
286 u32 in1, u32 in2, u32 *result)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400287{
288 u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
289 u32 out[HCI_WORDS];
Seth Forshee135740d2011-09-20 16:55:49 -0500290 acpi_status status = hci_raw(dev, in, out);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400291 *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
292 return status;
293}
294
Seth Forshee135740d2011-09-20 16:55:49 -0500295static acpi_status hci_read2(struct toshiba_acpi_dev *dev, u32 reg,
296 u32 *out1, u32 *out2, u32 *result)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400297{
298 u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
299 u32 out[HCI_WORDS];
Seth Forshee135740d2011-09-20 16:55:49 -0500300 acpi_status status = hci_raw(dev, in, out);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400301 *out1 = out[2];
302 *out2 = out[3];
303 *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
304 return status;
305}
306
Azael Avalos84a62732014-03-25 20:38:29 -0600307/* common sci tasks
308 */
309
310static int sci_open(struct toshiba_acpi_dev *dev)
311{
312 u32 in[HCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
313 u32 out[HCI_WORDS];
314 acpi_status status;
315
316 status = hci_raw(dev, in, out);
317 if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
318 pr_err("ACPI call to open SCI failed\n");
319 return 0;
320 }
321
322 if (out[0] == SCI_OPEN_CLOSE_OK) {
323 return 1;
324 } else if (out[0] == SCI_ALREADY_OPEN) {
325 pr_info("Toshiba SCI already opened\n");
326 return 1;
327 } else if (out[0] == SCI_NOT_PRESENT) {
328 pr_info("Toshiba SCI is not present\n");
329 }
330
331 return 0;
332}
333
334static void sci_close(struct toshiba_acpi_dev *dev)
335{
336 u32 in[HCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
337 u32 out[HCI_WORDS];
338 acpi_status status;
339
340 status = hci_raw(dev, in, out);
341 if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
342 pr_err("ACPI call to close SCI failed\n");
343 return;
344 }
345
346 if (out[0] == SCI_OPEN_CLOSE_OK)
347 return;
348 else if (out[0] == SCI_NOT_OPENED)
349 pr_info("Toshiba SCI not opened\n");
350 else if (out[0] == SCI_NOT_PRESENT)
351 pr_info("Toshiba SCI is not present\n");
352}
353
354static acpi_status sci_read(struct toshiba_acpi_dev *dev, u32 reg,
355 u32 *out1, u32 *result)
356{
357 u32 in[HCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
358 u32 out[HCI_WORDS];
359 acpi_status status = hci_raw(dev, in, out);
360 *out1 = out[2];
361 *result = (ACPI_SUCCESS(status)) ? out[0] : HCI_FAILURE;
362 return status;
363}
364
365static acpi_status sci_write(struct toshiba_acpi_dev *dev, u32 reg,
366 u32 in1, u32 *result)
367{
368 u32 in[HCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
369 u32 out[HCI_WORDS];
370 acpi_status status = hci_raw(dev, in, out);
371 *result = (ACPI_SUCCESS(status)) ? out[0] : HCI_FAILURE;
372 return status;
373}
374
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200375/* Illumination support */
Seth Forshee135740d2011-09-20 16:55:49 -0500376static int toshiba_illumination_available(struct toshiba_acpi_dev *dev)
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200377{
Azael Avalosfdb79082014-03-25 20:38:30 -0600378 u32 in[HCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200379 u32 out[HCI_WORDS];
380 acpi_status status;
381
Azael Avalosfdb79082014-03-25 20:38:30 -0600382 if (!sci_open(dev))
383 return 0;
384
Seth Forshee135740d2011-09-20 16:55:49 -0500385 status = hci_raw(dev, in, out);
Azael Avalosfdb79082014-03-25 20:38:30 -0600386 sci_close(dev);
387 if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
388 pr_err("ACPI call to query Illumination support failed\n");
389 return 0;
390 } else if (out[0] == HCI_NOT_SUPPORTED || out[1] != 1) {
Joe Perches7e334602011-03-29 15:21:52 -0700391 pr_info("Illumination device not available\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200392 return 0;
393 }
Azael Avalosfdb79082014-03-25 20:38:30 -0600394
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200395 return 1;
396}
397
398static void toshiba_illumination_set(struct led_classdev *cdev,
399 enum led_brightness brightness)
400{
Seth Forshee135740d2011-09-20 16:55:49 -0500401 struct toshiba_acpi_dev *dev = container_of(cdev,
402 struct toshiba_acpi_dev, led_dev);
Azael Avalosfdb79082014-03-25 20:38:30 -0600403 u32 state, result;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200404 acpi_status status;
405
406 /* First request : initialize communication. */
Azael Avalosfdb79082014-03-25 20:38:30 -0600407 if (!sci_open(dev))
408 return;
409
410 /* Switch the illumination on/off */
411 state = brightness ? 1 : 0;
412 status = sci_write(dev, SCI_ILLUMINATION, state, &result);
413 sci_close(dev);
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200414 if (ACPI_FAILURE(status)) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600415 pr_err("ACPI call for illumination failed\n");
416 return;
417 } else if (result == HCI_NOT_SUPPORTED) {
418 pr_info("Illumination not supported\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200419 return;
420 }
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200421}
422
423static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
424{
Seth Forshee135740d2011-09-20 16:55:49 -0500425 struct toshiba_acpi_dev *dev = container_of(cdev,
426 struct toshiba_acpi_dev, led_dev);
Azael Avalosfdb79082014-03-25 20:38:30 -0600427 u32 state, result;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200428 acpi_status status;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200429
430 /* First request : initialize communication. */
Azael Avalosfdb79082014-03-25 20:38:30 -0600431 if (!sci_open(dev))
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200432 return LED_OFF;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200433
434 /* Check the illumination */
Azael Avalosfdb79082014-03-25 20:38:30 -0600435 status = sci_read(dev, SCI_ILLUMINATION, &state, &result);
436 sci_close(dev);
437 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
438 pr_err("ACPI call for illumination failed\n");
439 return LED_OFF;
440 } else if (result == HCI_NOT_SUPPORTED) {
441 pr_info("Illumination not supported\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200442 return LED_OFF;
443 }
444
Azael Avalosfdb79082014-03-25 20:38:30 -0600445 return state ? LED_FULL : LED_OFF;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200446}
Azael Avalos360f0f32014-03-25 20:38:31 -0600447
448/* KBD Illumination */
449static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
450{
451 u32 result;
452 acpi_status status;
453
454 if (!sci_open(dev))
455 return -EIO;
456
457 status = sci_write(dev, SCI_KBD_ILLUM_STATUS, time, &result);
458 sci_close(dev);
459 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
460 pr_err("ACPI call to set KBD backlight status failed\n");
461 return -EIO;
462 } else if (result == HCI_NOT_SUPPORTED) {
463 pr_info("Keyboard backlight status not supported\n");
464 return -ENODEV;
465 }
466
467 return 0;
468}
469
470static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
471{
472 u32 result;
473 acpi_status status;
474
475 if (!sci_open(dev))
476 return -EIO;
477
478 status = sci_read(dev, SCI_KBD_ILLUM_STATUS, time, &result);
479 sci_close(dev);
480 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
481 pr_err("ACPI call to get KBD backlight status failed\n");
482 return -EIO;
483 } else if (result == HCI_NOT_SUPPORTED) {
484 pr_info("Keyboard backlight status not supported\n");
485 return -ENODEV;
486 }
487
488 return 0;
489}
490
491static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
492{
493 struct toshiba_acpi_dev *dev = container_of(cdev,
494 struct toshiba_acpi_dev, kbd_led);
495 u32 state, result;
496 acpi_status status;
497
498 /* Check the keyboard backlight state */
499 status = hci_read1(dev, HCI_KBD_ILLUMINATION, &state, &result);
500 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
501 pr_err("ACPI call to get the keyboard backlight failed\n");
502 return LED_OFF;
503 } else if (result == HCI_NOT_SUPPORTED) {
504 pr_info("Keyboard backlight not supported\n");
505 return LED_OFF;
506 }
507
508 return state ? LED_FULL : LED_OFF;
509}
510
511static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
512 enum led_brightness brightness)
513{
514 struct toshiba_acpi_dev *dev = container_of(cdev,
515 struct toshiba_acpi_dev, kbd_led);
516 u32 state, result;
517 acpi_status status;
518
519 /* Set the keyboard backlight state */
520 state = brightness ? 1 : 0;
521 status = hci_write1(dev, HCI_KBD_ILLUMINATION, state, &result);
522 if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
523 pr_err("ACPI call to set KBD Illumination mode failed\n");
524 return;
525 } else if (result == HCI_NOT_SUPPORTED) {
526 pr_info("Keyboard backlight not supported\n");
527 return;
528 }
529}
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200530
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400531/* Bluetooth rfkill handlers */
532
Seth Forshee135740d2011-09-20 16:55:49 -0500533static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400534{
535 u32 hci_result;
536 u32 value, value2;
537
538 value = 0;
539 value2 = 0;
Seth Forshee135740d2011-09-20 16:55:49 -0500540 hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400541 if (hci_result == HCI_SUCCESS)
542 *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
543
544 return hci_result;
545}
546
Seth Forshee135740d2011-09-20 16:55:49 -0500547static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400548{
549 u32 hci_result;
550 u32 value, value2;
551
552 value = 0;
553 value2 = 0x0001;
Seth Forshee135740d2011-09-20 16:55:49 -0500554 hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400555
556 *radio_state = value & HCI_WIRELESS_KILL_SWITCH;
557 return hci_result;
558}
559
Johannes Berg19d337d2009-06-02 13:01:37 +0200560static int bt_rfkill_set_block(void *data, bool blocked)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400561{
Johannes Berg19d337d2009-06-02 13:01:37 +0200562 struct toshiba_acpi_dev *dev = data;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400563 u32 result1, result2;
564 u32 value;
Johannes Berg19d337d2009-06-02 13:01:37 +0200565 int err;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400566 bool radio_state;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400567
Johannes Berg19d337d2009-06-02 13:01:37 +0200568 value = (blocked == false);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400569
570 mutex_lock(&dev->mutex);
Seth Forshee135740d2011-09-20 16:55:49 -0500571 if (hci_get_radio_state(dev, &radio_state) != HCI_SUCCESS) {
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500572 err = -EIO;
Johannes Berg19d337d2009-06-02 13:01:37 +0200573 goto out;
574 }
575
576 if (!radio_state) {
577 err = 0;
578 goto out;
579 }
580
Seth Forshee135740d2011-09-20 16:55:49 -0500581 hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
582 hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400583
584 if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500585 err = -EIO;
Johannes Berg19d337d2009-06-02 13:01:37 +0200586 else
587 err = 0;
588 out:
589 mutex_unlock(&dev->mutex);
590 return err;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400591}
592
Johannes Berg19d337d2009-06-02 13:01:37 +0200593static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400594{
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400595 bool new_rfk_state;
596 bool value;
597 u32 hci_result;
Johannes Berg19d337d2009-06-02 13:01:37 +0200598 struct toshiba_acpi_dev *dev = data;
599
600 mutex_lock(&dev->mutex);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400601
Seth Forshee135740d2011-09-20 16:55:49 -0500602 hci_result = hci_get_radio_state(dev, &value);
Johannes Berg19d337d2009-06-02 13:01:37 +0200603 if (hci_result != HCI_SUCCESS) {
604 /* Can't do anything useful */
605 mutex_unlock(&dev->mutex);
Jiri Slaby82e77842009-08-06 15:57:51 -0700606 return;
Johannes Berg19d337d2009-06-02 13:01:37 +0200607 }
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400608
609 new_rfk_state = value;
610
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400611 mutex_unlock(&dev->mutex);
612
Johannes Berg19d337d2009-06-02 13:01:37 +0200613 if (rfkill_set_hw_state(rfkill, !new_rfk_state))
614 bt_rfkill_set_block(data, true);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400615}
616
Johannes Berg19d337d2009-06-02 13:01:37 +0200617static const struct rfkill_ops toshiba_rfk_ops = {
618 .set_block = bt_rfkill_set_block,
619 .poll = bt_rfkill_poll,
620};
621
Akio Idehara121b7b02012-04-06 01:46:43 +0900622static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled)
623{
624 u32 hci_result;
625 u32 status;
626
627 hci_read1(dev, HCI_TR_BACKLIGHT, &status, &hci_result);
628 *enabled = !status;
629 return hci_result == HCI_SUCCESS ? 0 : -EIO;
630}
631
632static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
633{
634 u32 hci_result;
635 u32 value = !enable;
636
637 hci_write1(dev, HCI_TR_BACKLIGHT, value, &hci_result);
638 return hci_result == HCI_SUCCESS ? 0 : -EIO;
639}
640
Len Brown4be44fc2005-08-05 00:44:28 -0400641static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Seth Forshee62cce752012-04-19 11:23:50 -0500643static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
645 u32 hci_result;
646 u32 value;
Akio Idehara121b7b02012-04-06 01:46:43 +0900647 int brightness = 0;
648
649 if (dev->tr_backlight_supported) {
650 bool enabled;
651 int ret = get_tr_backlight_status(dev, &enabled);
652 if (ret)
653 return ret;
654 if (enabled)
655 return 0;
656 brightness++;
657 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Seth Forshee135740d2011-09-20 16:55:49 -0500659 hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500660 if (hci_result == HCI_SUCCESS)
Akio Idehara121b7b02012-04-06 01:46:43 +0900661 return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500662
663 return -EIO;
Holger Machtc9263552006-10-20 14:30:29 -0700664}
665
Seth Forshee62cce752012-04-19 11:23:50 -0500666static int get_lcd_brightness(struct backlight_device *bd)
667{
668 struct toshiba_acpi_dev *dev = bl_get_data(bd);
669 return __get_lcd_brightness(dev);
670}
671
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800672static int lcd_proc_show(struct seq_file *m, void *v)
Holger Machtc9263552006-10-20 14:30:29 -0700673{
Seth Forshee135740d2011-09-20 16:55:49 -0500674 struct toshiba_acpi_dev *dev = m->private;
675 int value;
Akio Idehara121b7b02012-04-06 01:46:43 +0900676 int levels;
Holger Machtc9263552006-10-20 14:30:29 -0700677
Seth Forshee135740d2011-09-20 16:55:49 -0500678 if (!dev->backlight_dev)
679 return -ENODEV;
680
Akio Idehara121b7b02012-04-06 01:46:43 +0900681 levels = dev->backlight_dev->props.max_brightness + 1;
Seth Forshee62cce752012-04-19 11:23:50 -0500682 value = get_lcd_brightness(dev->backlight_dev);
Holger Machtc9263552006-10-20 14:30:29 -0700683 if (value >= 0) {
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800684 seq_printf(m, "brightness: %d\n", value);
Akio Idehara121b7b02012-04-06 01:46:43 +0900685 seq_printf(m, "brightness_levels: %d\n", levels);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500686 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
688
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500689 pr_err("Error reading LCD brightness\n");
690 return -EIO;
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800691}
692
693static int lcd_proc_open(struct inode *inode, struct file *file)
694{
Al Virod9dda782013-03-31 18:16:14 -0400695 return single_open(file, lcd_proc_show, PDE_DATA(inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696}
697
Seth Forshee62cce752012-04-19 11:23:50 -0500698static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
Holger Machtc9263552006-10-20 14:30:29 -0700699{
700 u32 hci_result;
701
Akio Idehara121b7b02012-04-06 01:46:43 +0900702 if (dev->tr_backlight_supported) {
703 bool enable = !value;
704 int ret = set_tr_backlight_status(dev, enable);
705 if (ret)
706 return ret;
707 if (value)
708 value--;
709 }
710
Holger Machtc9263552006-10-20 14:30:29 -0700711 value = value << HCI_LCD_BRIGHTNESS_SHIFT;
Seth Forshee135740d2011-09-20 16:55:49 -0500712 hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500713 return hci_result == HCI_SUCCESS ? 0 : -EIO;
Holger Machtc9263552006-10-20 14:30:29 -0700714}
715
716static int set_lcd_status(struct backlight_device *bd)
717{
Seth Forshee135740d2011-09-20 16:55:49 -0500718 struct toshiba_acpi_dev *dev = bl_get_data(bd);
Seth Forshee62cce752012-04-19 11:23:50 -0500719 return set_lcd_brightness(dev, bd->props.brightness);
Holger Machtc9263552006-10-20 14:30:29 -0700720}
721
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800722static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
723 size_t count, loff_t *pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724{
Al Virod9dda782013-03-31 18:16:14 -0400725 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800726 char cmd[42];
727 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 int value;
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -0800729 int ret;
Akio Idehara121b7b02012-04-06 01:46:43 +0900730 int levels = dev->backlight_dev->props.max_brightness + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800732 len = min(count, sizeof(cmd) - 1);
733 if (copy_from_user(cmd, buf, len))
734 return -EFAULT;
735 cmd[len] = '\0';
736
737 if (sscanf(cmd, " brightness : %i", &value) == 1 &&
Akio Idehara121b7b02012-04-06 01:46:43 +0900738 value >= 0 && value < levels) {
Seth Forshee62cce752012-04-19 11:23:50 -0500739 ret = set_lcd_brightness(dev, value);
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -0800740 if (ret == 0)
741 ret = count;
742 } else {
Holger Machtc9263552006-10-20 14:30:29 -0700743 ret = -EINVAL;
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -0800744 }
Holger Machtc9263552006-10-20 14:30:29 -0700745 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746}
747
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800748static const struct file_operations lcd_proc_fops = {
749 .owner = THIS_MODULE,
750 .open = lcd_proc_open,
751 .read = seq_read,
752 .llseek = seq_lseek,
753 .release = single_release,
754 .write = lcd_proc_write,
755};
756
Seth Forshee36d03f92011-09-20 16:55:53 -0500757static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
758{
759 u32 hci_result;
760
761 hci_read1(dev, HCI_VIDEO_OUT, status, &hci_result);
762 return hci_result == HCI_SUCCESS ? 0 : -EIO;
763}
764
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800765static int video_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
Seth Forshee135740d2011-09-20 16:55:49 -0500767 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 u32 value;
Seth Forshee36d03f92011-09-20 16:55:53 -0500769 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Seth Forshee36d03f92011-09-20 16:55:53 -0500771 ret = get_video_status(dev, &value);
772 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
774 int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
Len Brown4be44fc2005-08-05 00:44:28 -0400775 int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800776 seq_printf(m, "lcd_out: %d\n", is_lcd);
777 seq_printf(m, "crt_out: %d\n", is_crt);
778 seq_printf(m, "tv_out: %d\n", is_tv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780
Seth Forshee36d03f92011-09-20 16:55:53 -0500781 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782}
783
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800784static int video_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785{
Al Virod9dda782013-03-31 18:16:14 -0400786 return single_open(file, video_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800787}
788
789static ssize_t video_proc_write(struct file *file, const char __user *buf,
790 size_t count, loff_t *pos)
791{
Al Virod9dda782013-03-31 18:16:14 -0400792 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800793 char *cmd, *buffer;
Seth Forshee36d03f92011-09-20 16:55:53 -0500794 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 int value;
796 int remain = count;
797 int lcd_out = -1;
798 int crt_out = -1;
799 int tv_out = -1;
Al Virob4482a42007-10-14 19:35:40 +0100800 u32 video_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800802 cmd = kmalloc(count + 1, GFP_KERNEL);
803 if (!cmd)
804 return -ENOMEM;
805 if (copy_from_user(cmd, buf, count)) {
806 kfree(cmd);
807 return -EFAULT;
808 }
809 cmd[count] = '\0';
810
811 buffer = cmd;
812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 /* scan expression. Multiple expressions may be delimited with ;
814 *
815 * NOTE: to keep scanning simple, invalid fields are ignored
816 */
817 while (remain) {
818 if (sscanf(buffer, " lcd_out : %i", &value) == 1)
819 lcd_out = value & 1;
820 else if (sscanf(buffer, " crt_out : %i", &value) == 1)
821 crt_out = value & 1;
822 else if (sscanf(buffer, " tv_out : %i", &value) == 1)
823 tv_out = value & 1;
824 /* advance to one character past the next ; */
825 do {
826 ++buffer;
827 --remain;
828 }
Len Brown4be44fc2005-08-05 00:44:28 -0400829 while (remain && *(buffer - 1) != ';');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
831
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800832 kfree(cmd);
833
Seth Forshee36d03f92011-09-20 16:55:53 -0500834 ret = get_video_status(dev, &video_out);
835 if (!ret) {
Harvey Harrison9e113e02008-09-22 14:37:29 -0700836 unsigned int new_video_out = video_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 if (lcd_out != -1)
838 _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
839 if (crt_out != -1)
840 _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
841 if (tv_out != -1)
842 _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
843 /* To avoid unnecessary video disruption, only write the new
844 * video setting if something changed. */
845 if (new_video_out != video_out)
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500846 ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500849 return ret ? ret : count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850}
851
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800852static const struct file_operations video_proc_fops = {
853 .owner = THIS_MODULE,
854 .open = video_proc_open,
855 .read = seq_read,
856 .llseek = seq_lseek,
857 .release = single_release,
858 .write = video_proc_write,
859};
860
Seth Forshee36d03f92011-09-20 16:55:53 -0500861static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
862{
863 u32 hci_result;
864
865 hci_read1(dev, HCI_FAN, status, &hci_result);
866 return hci_result == HCI_SUCCESS ? 0 : -EIO;
867}
868
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800869static int fan_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
Seth Forshee135740d2011-09-20 16:55:49 -0500871 struct toshiba_acpi_dev *dev = m->private;
Seth Forshee36d03f92011-09-20 16:55:53 -0500872 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 u32 value;
874
Seth Forshee36d03f92011-09-20 16:55:53 -0500875 ret = get_fan_status(dev, &value);
876 if (!ret) {
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800877 seq_printf(m, "running: %d\n", (value > 0));
Seth Forshee135740d2011-09-20 16:55:49 -0500878 seq_printf(m, "force_on: %d\n", dev->force_fan);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 }
880
Seth Forshee36d03f92011-09-20 16:55:53 -0500881 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882}
883
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800884static int fan_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885{
Al Virod9dda782013-03-31 18:16:14 -0400886 return single_open(file, fan_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800887}
888
889static ssize_t fan_proc_write(struct file *file, const char __user *buf,
890 size_t count, loff_t *pos)
891{
Al Virod9dda782013-03-31 18:16:14 -0400892 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800893 char cmd[42];
894 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 int value;
896 u32 hci_result;
897
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800898 len = min(count, sizeof(cmd) - 1);
899 if (copy_from_user(cmd, buf, len))
900 return -EFAULT;
901 cmd[len] = '\0';
902
903 if (sscanf(cmd, " force_on : %i", &value) == 1 &&
Len Brown4be44fc2005-08-05 00:44:28 -0400904 value >= 0 && value <= 1) {
Seth Forshee135740d2011-09-20 16:55:49 -0500905 hci_write1(dev, HCI_FAN, value, &hci_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 if (hci_result != HCI_SUCCESS)
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500907 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 else
Seth Forshee135740d2011-09-20 16:55:49 -0500909 dev->force_fan = value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 } else {
911 return -EINVAL;
912 }
913
914 return count;
915}
916
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800917static const struct file_operations fan_proc_fops = {
918 .owner = THIS_MODULE,
919 .open = fan_proc_open,
920 .read = seq_read,
921 .llseek = seq_lseek,
922 .release = single_release,
923 .write = fan_proc_write,
924};
925
926static int keys_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
Seth Forshee135740d2011-09-20 16:55:49 -0500928 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 u32 hci_result;
930 u32 value;
931
Seth Forshee11948b92011-11-16 17:37:45 -0600932 if (!dev->key_event_valid && dev->system_event_supported) {
Seth Forshee135740d2011-09-20 16:55:49 -0500933 hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 if (hci_result == HCI_SUCCESS) {
Seth Forshee135740d2011-09-20 16:55:49 -0500935 dev->key_event_valid = 1;
936 dev->last_key_event = value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 } else if (hci_result == HCI_EMPTY) {
938 /* better luck next time */
939 } else if (hci_result == HCI_NOT_SUPPORTED) {
940 /* This is a workaround for an unresolved issue on
941 * some machines where system events sporadically
942 * become disabled. */
Seth Forshee135740d2011-09-20 16:55:49 -0500943 hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
Joe Perches7e334602011-03-29 15:21:52 -0700944 pr_notice("Re-enabled hotkeys\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 } else {
Joe Perches7e334602011-03-29 15:21:52 -0700946 pr_err("Error reading hotkey status\n");
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500947 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 }
949 }
950
Seth Forshee135740d2011-09-20 16:55:49 -0500951 seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid);
952 seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event);
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800953 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954}
955
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800956static int keys_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957{
Al Virod9dda782013-03-31 18:16:14 -0400958 return single_open(file, keys_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800959}
960
961static ssize_t keys_proc_write(struct file *file, const char __user *buf,
962 size_t count, loff_t *pos)
963{
Al Virod9dda782013-03-31 18:16:14 -0400964 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800965 char cmd[42];
966 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 int value;
968
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800969 len = min(count, sizeof(cmd) - 1);
970 if (copy_from_user(cmd, buf, len))
971 return -EFAULT;
972 cmd[len] = '\0';
973
974 if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) {
Seth Forshee135740d2011-09-20 16:55:49 -0500975 dev->key_event_valid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 } else {
977 return -EINVAL;
978 }
979
980 return count;
981}
982
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800983static const struct file_operations keys_proc_fops = {
984 .owner = THIS_MODULE,
985 .open = keys_proc_open,
986 .read = seq_read,
987 .llseek = seq_lseek,
988 .release = single_release,
989 .write = keys_proc_write,
990};
991
992static int version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993{
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800994 seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION);
995 seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION);
996 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997}
998
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -0800999static int version_proc_open(struct inode *inode, struct file *file)
1000{
Al Virod9dda782013-03-31 18:16:14 -04001001 return single_open(file, version_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001002}
1003
1004static const struct file_operations version_proc_fops = {
1005 .owner = THIS_MODULE,
1006 .open = version_proc_open,
1007 .read = seq_read,
1008 .llseek = seq_lseek,
1009 .release = single_release,
1010};
1011
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012/* proc and module init
1013 */
1014
1015#define PROC_TOSHIBA "toshiba"
1016
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001017static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
Seth Forshee36d03f92011-09-20 16:55:53 -05001019 if (dev->backlight_dev)
1020 proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1021 &lcd_proc_fops, dev);
1022 if (dev->video_supported)
1023 proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1024 &video_proc_fops, dev);
1025 if (dev->fan_supported)
1026 proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1027 &fan_proc_fops, dev);
1028 if (dev->hotkey_dev)
1029 proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1030 &keys_proc_fops, dev);
Seth Forshee135740d2011-09-20 16:55:49 -05001031 proc_create_data("version", S_IRUGO, toshiba_proc_dir,
1032 &version_proc_fops, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
1034
Seth Forshee36d03f92011-09-20 16:55:53 -05001035static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036{
Seth Forshee36d03f92011-09-20 16:55:53 -05001037 if (dev->backlight_dev)
1038 remove_proc_entry("lcd", toshiba_proc_dir);
1039 if (dev->video_supported)
1040 remove_proc_entry("video", toshiba_proc_dir);
1041 if (dev->fan_supported)
1042 remove_proc_entry("fan", toshiba_proc_dir);
1043 if (dev->hotkey_dev)
1044 remove_proc_entry("keys", toshiba_proc_dir);
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001045 remove_proc_entry("version", toshiba_proc_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046}
1047
Lionel Debrouxacc24722010-11-16 14:14:02 +01001048static const struct backlight_ops toshiba_backlight_data = {
Akio Idehara121b7b02012-04-06 01:46:43 +09001049 .options = BL_CORE_SUSPENDRESUME,
Seth Forshee62cce752012-04-19 11:23:50 -05001050 .get_brightness = get_lcd_brightness,
1051 .update_status = set_lcd_status,
Holger Machtc9263552006-10-20 14:30:29 -07001052};
Azael Avalos360f0f32014-03-25 20:38:31 -06001053
1054/*
1055 * Sysfs files
1056 */
1057
1058static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
1059 struct device_attribute *attr,
1060 const char *buf, size_t count)
1061{
1062 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1063 int mode = -1;
1064 int time = -1;
1065
1066 if (sscanf(buf, "%i", &mode) != 1 && (mode != 2 || mode != 1))
1067 return -EINVAL;
1068
1069 /* Set the Keyboard Backlight Mode where:
1070 * Mode - Auto (2) | FN-Z (1)
1071 * Auto - KBD backlight turns off automatically in given time
1072 * FN-Z - KBD backlight "toggles" when hotkey pressed
1073 */
1074 if (mode != -1 && toshiba->kbd_mode != mode) {
1075 time = toshiba->kbd_time << HCI_MISC_SHIFT;
1076 time = time + toshiba->kbd_mode;
1077 if (toshiba_kbd_illum_status_set(toshiba, time) < 0)
1078 return -EIO;
1079 toshiba->kbd_mode = mode;
1080 }
1081
1082 return count;
1083}
1084
1085static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
1086 struct device_attribute *attr,
1087 char *buf)
1088{
1089 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1090 u32 time;
1091
1092 if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1093 return -EIO;
1094
1095 return sprintf(buf, "%i\n", time & 0x07);
1096}
1097
1098static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
1099 struct device_attribute *attr,
1100 const char *buf, size_t count)
1101{
1102 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1103 int time = -1;
1104
1105 if (sscanf(buf, "%i", &time) != 1 && (time < 0 || time > 60))
1106 return -EINVAL;
1107
1108 /* Set the Keyboard Backlight Timeout: 0-60 seconds */
1109 if (time != -1 && toshiba->kbd_time != time) {
1110 time = time << HCI_MISC_SHIFT;
1111 time = (toshiba->kbd_mode == SCI_KBD_MODE_AUTO) ?
1112 time + 1 : time + 2;
1113 if (toshiba_kbd_illum_status_set(toshiba, time) < 0)
1114 return -EIO;
1115 toshiba->kbd_time = time >> HCI_MISC_SHIFT;
1116 }
1117
1118 return count;
1119}
1120
1121static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
1122 struct device_attribute *attr,
1123 char *buf)
1124{
1125 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1126 u32 time;
1127
1128 if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1129 return -EIO;
1130
1131 return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
1132}
1133
1134static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
1135 toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
1136static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
1137 toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
1138
1139static struct attribute *toshiba_attributes[] = {
1140 &dev_attr_kbd_backlight_mode.attr,
1141 &dev_attr_kbd_backlight_timeout.attr,
1142 NULL,
1143};
1144
1145static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
1146 struct attribute *attr, int idx)
1147{
1148 struct device *dev = container_of(kobj, struct device, kobj);
1149 struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
1150 bool exists = true;
1151
1152 if (attr == &dev_attr_kbd_backlight_mode.attr)
1153 exists = (drv->kbd_illum_supported) ? true : false;
1154 else if (attr == &dev_attr_kbd_backlight_timeout.attr)
1155 exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
1156
1157 return exists ? attr->mode : 0;
1158}
1159
1160static struct attribute_group toshiba_attr_group = {
1161 .is_visible = toshiba_sysfs_is_visible,
1162 .attrs = toshiba_attributes,
1163};
Holger Machtc9263552006-10-20 14:30:29 -07001164
Seth Forshee29cd2932012-01-18 13:44:09 -06001165static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
1166 struct serio *port)
1167{
1168 if (str & 0x20)
1169 return false;
1170
1171 if (unlikely(data == 0xe0))
1172 return false;
1173
1174 if ((data & 0x7f) == TOS1900_FN_SCAN) {
1175 schedule_work(&toshiba_acpi->hotkey_work);
1176 return true;
1177 }
1178
1179 return false;
1180}
1181
1182static void toshiba_acpi_hotkey_work(struct work_struct *work)
1183{
1184 acpi_handle ec_handle = ec_get_handle();
1185 acpi_status status;
1186
1187 if (!ec_handle)
1188 return;
1189
1190 status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
1191 if (ACPI_FAILURE(status))
1192 pr_err("ACPI NTFY method execution failed\n");
1193}
1194
1195/*
1196 * Returns hotkey scancode, or < 0 on failure.
1197 */
1198static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
1199{
Zhang Rui74facaf2013-09-03 08:32:15 +08001200 unsigned long long value;
Seth Forshee29cd2932012-01-18 13:44:09 -06001201 acpi_status status;
1202
Zhang Rui74facaf2013-09-03 08:32:15 +08001203 status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO",
1204 NULL, &value);
1205 if (ACPI_FAILURE(status)) {
Seth Forshee29cd2932012-01-18 13:44:09 -06001206 pr_err("ACPI INFO method execution failed\n");
1207 return -EIO;
1208 }
1209
Zhang Rui74facaf2013-09-03 08:32:15 +08001210 return value;
Seth Forshee29cd2932012-01-18 13:44:09 -06001211}
1212
1213static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
1214 int scancode)
1215{
1216 if (scancode == 0x100)
1217 return;
1218
1219 /* act on key press; ignore key release */
1220 if (scancode & 0x80)
1221 return;
1222
1223 if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
1224 pr_info("Unknown key %x\n", scancode);
1225}
1226
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001227static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001228{
Seth Forshee135740d2011-09-20 16:55:49 -05001229 acpi_status status;
Zhang Ruie2e19602013-09-03 08:32:06 +08001230 acpi_handle ec_handle;
Seth Forshee135740d2011-09-20 16:55:49 -05001231 int error;
Seth Forshee29cd2932012-01-18 13:44:09 -06001232 u32 hci_result;
Seth Forshee135740d2011-09-20 16:55:49 -05001233
Seth Forshee135740d2011-09-20 16:55:49 -05001234 dev->hotkey_dev = input_allocate_device();
Joe Perchesb222cca2013-10-23 12:14:52 -07001235 if (!dev->hotkey_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05001236 return -ENOMEM;
Seth Forshee135740d2011-09-20 16:55:49 -05001237
1238 dev->hotkey_dev->name = "Toshiba input device";
Seth Forshee6e02cc72011-09-20 16:55:51 -05001239 dev->hotkey_dev->phys = "toshiba_acpi/input0";
Seth Forshee135740d2011-09-20 16:55:49 -05001240 dev->hotkey_dev->id.bustype = BUS_HOST;
1241
1242 error = sparse_keymap_setup(dev->hotkey_dev, toshiba_acpi_keymap, NULL);
1243 if (error)
1244 goto err_free_dev;
1245
Seth Forshee29cd2932012-01-18 13:44:09 -06001246 /*
1247 * For some machines the SCI responsible for providing hotkey
1248 * notification doesn't fire. We can trigger the notification
1249 * whenever the Fn key is pressed using the NTFY method, if
1250 * supported, so if it's present set up an i8042 key filter
1251 * for this purpose.
1252 */
1253 status = AE_ERROR;
1254 ec_handle = ec_get_handle();
Zhang Ruie2e19602013-09-03 08:32:06 +08001255 if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
Seth Forshee29cd2932012-01-18 13:44:09 -06001256 INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
1257
1258 error = i8042_install_filter(toshiba_acpi_i8042_filter);
1259 if (error) {
1260 pr_err("Error installing key filter\n");
1261 goto err_free_keymap;
1262 }
1263
1264 dev->ntfy_supported = 1;
1265 }
1266
1267 /*
1268 * Determine hotkey query interface. Prefer using the INFO
1269 * method when it is available.
1270 */
Zhang Ruie2e19602013-09-03 08:32:06 +08001271 if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
Seth Forshee29cd2932012-01-18 13:44:09 -06001272 dev->info_supported = 1;
Zhang Ruie2e19602013-09-03 08:32:06 +08001273 else {
Seth Forshee29cd2932012-01-18 13:44:09 -06001274 hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
1275 if (hci_result == HCI_SUCCESS)
1276 dev->system_event_supported = 1;
1277 }
1278
1279 if (!dev->info_supported && !dev->system_event_supported) {
1280 pr_warn("No hotkey query interface found\n");
1281 goto err_remove_filter;
1282 }
1283
Seth Forshee6e02cc72011-09-20 16:55:51 -05001284 status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL);
Seth Forshee135740d2011-09-20 16:55:49 -05001285 if (ACPI_FAILURE(status)) {
1286 pr_info("Unable to enable hotkeys\n");
1287 error = -ENODEV;
Seth Forshee29cd2932012-01-18 13:44:09 -06001288 goto err_remove_filter;
Seth Forshee135740d2011-09-20 16:55:49 -05001289 }
1290
1291 error = input_register_device(dev->hotkey_dev);
1292 if (error) {
1293 pr_info("Unable to register input device\n");
Seth Forshee29cd2932012-01-18 13:44:09 -06001294 goto err_remove_filter;
Seth Forshee135740d2011-09-20 16:55:49 -05001295 }
1296
Seth Forshee29cd2932012-01-18 13:44:09 -06001297 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &hci_result);
Seth Forshee135740d2011-09-20 16:55:49 -05001298 return 0;
1299
Seth Forshee29cd2932012-01-18 13:44:09 -06001300 err_remove_filter:
1301 if (dev->ntfy_supported)
1302 i8042_remove_filter(toshiba_acpi_i8042_filter);
Seth Forshee135740d2011-09-20 16:55:49 -05001303 err_free_keymap:
1304 sparse_keymap_free(dev->hotkey_dev);
1305 err_free_dev:
1306 input_free_device(dev->hotkey_dev);
1307 dev->hotkey_dev = NULL;
1308 return error;
1309}
1310
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001311static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
Seth Forshee62cce752012-04-19 11:23:50 -05001312{
1313 struct backlight_properties props;
1314 int brightness;
1315 int ret;
Akio Idehara121b7b02012-04-06 01:46:43 +09001316 bool enabled;
Seth Forshee62cce752012-04-19 11:23:50 -05001317
1318 /*
1319 * Some machines don't support the backlight methods at all, and
1320 * others support it read-only. Either of these is pretty useless,
1321 * so only register the backlight device if the backlight method
1322 * supports both reads and writes.
1323 */
1324 brightness = __get_lcd_brightness(dev);
1325 if (brightness < 0)
1326 return 0;
1327 ret = set_lcd_brightness(dev, brightness);
1328 if (ret) {
1329 pr_debug("Backlight method is read-only, disabling backlight support\n");
1330 return 0;
1331 }
1332
Akio Idehara121b7b02012-04-06 01:46:43 +09001333 /* Determine whether or not BIOS supports transflective backlight */
1334 ret = get_tr_backlight_status(dev, &enabled);
1335 dev->tr_backlight_supported = !ret;
1336
Matthew Garrett53039f22012-06-01 11:02:36 -04001337 memset(&props, 0, sizeof(props));
Seth Forshee62cce752012-04-19 11:23:50 -05001338 props.type = BACKLIGHT_PLATFORM;
1339 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
Seth Forshee62cce752012-04-19 11:23:50 -05001340
Akio Idehara121b7b02012-04-06 01:46:43 +09001341 /* adding an extra level and having 0 change to transflective mode */
1342 if (dev->tr_backlight_supported)
1343 props.max_brightness++;
1344
Seth Forshee62cce752012-04-19 11:23:50 -05001345 dev->backlight_dev = backlight_device_register("toshiba",
1346 &dev->acpi_dev->dev,
1347 dev,
1348 &toshiba_backlight_data,
1349 &props);
1350 if (IS_ERR(dev->backlight_dev)) {
1351 ret = PTR_ERR(dev->backlight_dev);
1352 pr_err("Could not register toshiba backlight device\n");
1353 dev->backlight_dev = NULL;
1354 return ret;
1355 }
1356
1357 dev->backlight_dev->props.brightness = brightness;
1358 return 0;
1359}
1360
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01001361static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05001362{
1363 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
1364
Seth Forshee36d03f92011-09-20 16:55:53 -05001365 remove_toshiba_proc_entries(dev);
Azael Avalos360f0f32014-03-25 20:38:31 -06001366
1367 if (dev->sysfs_created)
1368 sysfs_remove_group(&dev->acpi_dev->dev.kobj,
1369 &toshiba_attr_group);
Seth Forshee135740d2011-09-20 16:55:49 -05001370
Seth Forshee29cd2932012-01-18 13:44:09 -06001371 if (dev->ntfy_supported) {
1372 i8042_remove_filter(toshiba_acpi_i8042_filter);
1373 cancel_work_sync(&dev->hotkey_work);
1374 }
1375
Seth Forshee135740d2011-09-20 16:55:49 -05001376 if (dev->hotkey_dev) {
1377 input_unregister_device(dev->hotkey_dev);
1378 sparse_keymap_free(dev->hotkey_dev);
1379 }
1380
1381 if (dev->bt_rfk) {
1382 rfkill_unregister(dev->bt_rfk);
1383 rfkill_destroy(dev->bt_rfk);
1384 }
1385
1386 if (dev->backlight_dev)
1387 backlight_device_unregister(dev->backlight_dev);
1388
Seth Forshee36d03f92011-09-20 16:55:53 -05001389 if (dev->illumination_supported)
Seth Forshee135740d2011-09-20 16:55:49 -05001390 led_classdev_unregister(&dev->led_dev);
Azael Avalos360f0f32014-03-25 20:38:31 -06001391
1392 if (dev->kbd_led_registered)
1393 led_classdev_unregister(&dev->kbd_led);
Seth Forshee135740d2011-09-20 16:55:49 -05001394
Seth Forshee29cd2932012-01-18 13:44:09 -06001395 if (toshiba_acpi)
1396 toshiba_acpi = NULL;
1397
Seth Forshee135740d2011-09-20 16:55:49 -05001398 kfree(dev);
1399
1400 return 0;
1401}
1402
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001403static const char *find_hci_method(acpi_handle handle)
Seth Forsheea540d6b2011-09-20 16:55:52 -05001404{
Zhang Ruie2e19602013-09-03 08:32:06 +08001405 if (acpi_has_method(handle, "GHCI"))
Seth Forsheea540d6b2011-09-20 16:55:52 -05001406 return "GHCI";
1407
Zhang Ruie2e19602013-09-03 08:32:06 +08001408 if (acpi_has_method(handle, "SPFC"))
Seth Forsheea540d6b2011-09-20 16:55:52 -05001409 return "SPFC";
1410
1411 return NULL;
1412}
1413
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001414static int toshiba_acpi_add(struct acpi_device *acpi_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05001415{
1416 struct toshiba_acpi_dev *dev;
Seth Forsheea540d6b2011-09-20 16:55:52 -05001417 const char *hci_method;
Seth Forshee36d03f92011-09-20 16:55:53 -05001418 u32 dummy;
Seth Forshee135740d2011-09-20 16:55:49 -05001419 bool bt_present;
1420 int ret = 0;
Seth Forshee135740d2011-09-20 16:55:49 -05001421
Seth Forshee29cd2932012-01-18 13:44:09 -06001422 if (toshiba_acpi)
1423 return -EBUSY;
1424
Seth Forshee135740d2011-09-20 16:55:49 -05001425 pr_info("Toshiba Laptop ACPI Extras version %s\n",
1426 TOSHIBA_ACPI_VERSION);
1427
Seth Forsheea540d6b2011-09-20 16:55:52 -05001428 hci_method = find_hci_method(acpi_dev->handle);
1429 if (!hci_method) {
1430 pr_err("HCI interface not found\n");
Seth Forshee6e02cc72011-09-20 16:55:51 -05001431 return -ENODEV;
Seth Forsheea540d6b2011-09-20 16:55:52 -05001432 }
Seth Forshee6e02cc72011-09-20 16:55:51 -05001433
Seth Forshee135740d2011-09-20 16:55:49 -05001434 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1435 if (!dev)
1436 return -ENOMEM;
1437 dev->acpi_dev = acpi_dev;
Seth Forsheea540d6b2011-09-20 16:55:52 -05001438 dev->method_hci = hci_method;
Seth Forshee135740d2011-09-20 16:55:49 -05001439 acpi_dev->driver_data = dev;
Azael Avalos360f0f32014-03-25 20:38:31 -06001440 dev_set_drvdata(&acpi_dev->dev, dev);
Seth Forshee135740d2011-09-20 16:55:49 -05001441
Seth Forshee6e02cc72011-09-20 16:55:51 -05001442 if (toshiba_acpi_setup_keyboard(dev))
1443 pr_info("Unable to activate hotkeys\n");
Seth Forshee135740d2011-09-20 16:55:49 -05001444
1445 mutex_init(&dev->mutex);
1446
Seth Forshee62cce752012-04-19 11:23:50 -05001447 ret = toshiba_acpi_setup_backlight(dev);
1448 if (ret)
Seth Forshee135740d2011-09-20 16:55:49 -05001449 goto error;
Seth Forshee135740d2011-09-20 16:55:49 -05001450
1451 /* Register rfkill switch for Bluetooth */
1452 if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) {
1453 dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth",
1454 &acpi_dev->dev,
1455 RFKILL_TYPE_BLUETOOTH,
1456 &toshiba_rfk_ops,
1457 dev);
1458 if (!dev->bt_rfk) {
1459 pr_err("unable to allocate rfkill device\n");
1460 ret = -ENOMEM;
1461 goto error;
1462 }
1463
1464 ret = rfkill_register(dev->bt_rfk);
1465 if (ret) {
1466 pr_err("unable to register rfkill device\n");
1467 rfkill_destroy(dev->bt_rfk);
1468 goto error;
1469 }
1470 }
1471
1472 if (toshiba_illumination_available(dev)) {
1473 dev->led_dev.name = "toshiba::illumination";
1474 dev->led_dev.max_brightness = 1;
1475 dev->led_dev.brightness_set = toshiba_illumination_set;
1476 dev->led_dev.brightness_get = toshiba_illumination_get;
1477 if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev))
Seth Forshee36d03f92011-09-20 16:55:53 -05001478 dev->illumination_supported = 1;
Seth Forshee135740d2011-09-20 16:55:49 -05001479 }
Azael Avalos360f0f32014-03-25 20:38:31 -06001480
1481 ret = toshiba_kbd_illum_status_get(dev, &dummy);
1482 if (!ret) {
1483 dev->kbd_time = dummy >> HCI_MISC_SHIFT;
1484 dev->kbd_mode = dummy & 0x07;
1485 }
1486 dev->kbd_illum_supported = !ret;
1487 /*
1488 * Only register the LED if KBD illumination is supported
1489 * and the keyboard backlight operation mode is set to FN-Z
1490 */
1491 if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) {
1492 dev->kbd_led.name = "toshiba::kbd_backlight";
1493 dev->kbd_led.max_brightness = 1;
1494 dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
1495 dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
1496 if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led))
1497 dev->kbd_led_registered = 1;
1498 }
Seth Forshee135740d2011-09-20 16:55:49 -05001499
Seth Forshee36d03f92011-09-20 16:55:53 -05001500 /* Determine whether or not BIOS supports fan and video interfaces */
1501
1502 ret = get_video_status(dev, &dummy);
1503 dev->video_supported = !ret;
1504
1505 ret = get_fan_status(dev, &dummy);
1506 dev->fan_supported = !ret;
1507
Azael Avalos360f0f32014-03-25 20:38:31 -06001508 ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
1509 &toshiba_attr_group);
1510 if (ret) {
1511 dev->sysfs_created = 0;
1512 goto error;
1513 }
1514 dev->sysfs_created = !ret;
1515
Seth Forshee36d03f92011-09-20 16:55:53 -05001516 create_toshiba_proc_entries(dev);
1517
Seth Forshee29cd2932012-01-18 13:44:09 -06001518 toshiba_acpi = dev;
1519
Seth Forshee135740d2011-09-20 16:55:49 -05001520 return 0;
1521
1522error:
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01001523 toshiba_acpi_remove(acpi_dev);
Seth Forshee135740d2011-09-20 16:55:49 -05001524 return ret;
1525}
1526
1527static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
1528{
1529 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001530 u32 hci_result, value;
Seth Forshee11948b92011-11-16 17:37:45 -06001531 int retries = 3;
Seth Forshee29cd2932012-01-18 13:44:09 -06001532 int scancode;
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001533
Seth Forshee29cd2932012-01-18 13:44:09 -06001534 if (event != 0x80)
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001535 return;
Seth Forshee11948b92011-11-16 17:37:45 -06001536
Seth Forshee29cd2932012-01-18 13:44:09 -06001537 if (dev->info_supported) {
1538 scancode = toshiba_acpi_query_hotkey(dev);
1539 if (scancode < 0)
1540 pr_err("Failed to query hotkey event\n");
1541 else if (scancode != 0)
1542 toshiba_acpi_report_hotkey(dev, scancode);
1543 } else if (dev->system_event_supported) {
1544 do {
1545 hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
1546 switch (hci_result) {
1547 case HCI_SUCCESS:
1548 toshiba_acpi_report_hotkey(dev, (int)value);
1549 break;
1550 case HCI_NOT_SUPPORTED:
1551 /*
1552 * This is a workaround for an unresolved
1553 * issue on some machines where system events
1554 * sporadically become disabled.
1555 */
1556 hci_write1(dev, HCI_SYSTEM_EVENT, 1,
1557 &hci_result);
1558 pr_notice("Re-enabled hotkeys\n");
1559 /* fall through */
1560 default:
1561 retries--;
1562 break;
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001563 }
Seth Forshee29cd2932012-01-18 13:44:09 -06001564 } while (retries && hci_result != HCI_EMPTY);
1565 }
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001566}
1567
Rafael J. Wysocki3567a4e22012-08-09 23:00:13 +02001568#ifdef CONFIG_PM_SLEEP
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001569static int toshiba_acpi_suspend(struct device *device)
Seth Forshee29cd2932012-01-18 13:44:09 -06001570{
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001571 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
Seth Forshee29cd2932012-01-18 13:44:09 -06001572 u32 result;
1573
1574 if (dev->hotkey_dev)
1575 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE, &result);
1576
1577 return 0;
1578}
1579
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001580static int toshiba_acpi_resume(struct device *device)
Seth Forshee29cd2932012-01-18 13:44:09 -06001581{
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001582 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
Seth Forshee29cd2932012-01-18 13:44:09 -06001583 u32 result;
1584
1585 if (dev->hotkey_dev)
1586 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
1587
1588 return 0;
1589}
Rafael J. Wysocki3567a4e22012-08-09 23:00:13 +02001590#endif
Matthew Garrett6335e4d2010-02-25 15:20:54 -05001591
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001592static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
1593 toshiba_acpi_suspend, toshiba_acpi_resume);
1594
Seth Forshee135740d2011-09-20 16:55:49 -05001595static struct acpi_driver toshiba_acpi_driver = {
1596 .name = "Toshiba ACPI driver",
1597 .owner = THIS_MODULE,
1598 .ids = toshiba_device_ids,
1599 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
1600 .ops = {
1601 .add = toshiba_acpi_add,
1602 .remove = toshiba_acpi_remove,
1603 .notify = toshiba_acpi_notify,
1604 },
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02001605 .drv.pm = &toshiba_acpi_pm,
Seth Forshee135740d2011-09-20 16:55:49 -05001606};
Holger Machtc9263552006-10-20 14:30:29 -07001607
Len Brown4be44fc2005-08-05 00:44:28 -04001608static int __init toshiba_acpi_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609{
Seth Forshee135740d2011-09-20 16:55:49 -05001610 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
Seth Forsheef11f9992012-01-18 13:44:11 -06001612 /*
1613 * Machines with this WMI guid aren't supported due to bugs in
1614 * their AML. This check relies on wmi initializing before
1615 * toshiba_acpi to guarantee guids have been identified.
1616 */
1617 if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
1618 return -ENODEV;
1619
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
1621 if (!toshiba_proc_dir) {
Seth Forshee135740d2011-09-20 16:55:49 -05001622 pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001623 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 }
1625
Seth Forshee135740d2011-09-20 16:55:49 -05001626 ret = acpi_bus_register_driver(&toshiba_acpi_driver);
1627 if (ret) {
1628 pr_err("Failed to register ACPI driver: %d\n", ret);
1629 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
Holger Machtc9263552006-10-20 14:30:29 -07001630 }
1631
Seth Forshee135740d2011-09-20 16:55:49 -05001632 return ret;
1633}
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001634
Seth Forshee135740d2011-09-20 16:55:49 -05001635static void __exit toshiba_acpi_exit(void)
1636{
1637 acpi_bus_unregister_driver(&toshiba_acpi_driver);
1638 if (toshiba_proc_dir)
1639 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640}
1641
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642module_init(toshiba_acpi_init);
1643module_exit(toshiba_acpi_exit);