2 * eepc-laptop.c - Asus Eee PC extras
4 * Based on asus_acpi.c as patched for the Eee PC by Asus:
5 * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar
6 * Based on eee.c from eeepc-linux
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/init.h>
22 #include <linux/types.h>
23 #include <linux/platform_device.h>
24 #include <acpi/acpi_drivers.h>
25 #include <acpi/acpi_bus.h>
26 #include <linux/uaccess.h>
28 #define EEEPC_LAPTOP_VERSION "0.1"
30 #define EEEPC_HOTK_NAME "Eee PC Hotkey Driver"
31 #define EEEPC_HOTK_FILE "eeepc"
32 #define EEEPC_HOTK_CLASS "hotkey"
33 #define EEEPC_HOTK_DEVICE_NAME "Hotkey"
34 #define EEEPC_HOTK_HID "ASUS010"
36 #define EEEPC_LOG EEEPC_HOTK_FILE ": "
37 #define EEEPC_ERR KERN_ERR EEEPC_LOG
38 #define EEEPC_WARNING KERN_WARNING EEEPC_LOG
39 #define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG
40 #define EEEPC_INFO KERN_INFO EEEPC_LOG
43 * Definitions for Asus EeePC
45 #define NOTIFY_WLAN_ON 0x10
48 DISABLE_ASL_WLAN
= 0x0001,
49 DISABLE_ASL_BLUETOOTH
= 0x0002,
50 DISABLE_ASL_IRDA
= 0x0004,
51 DISABLE_ASL_CAMERA
= 0x0008,
52 DISABLE_ASL_TV
= 0x0010,
53 DISABLE_ASL_GPS
= 0x0020,
54 DISABLE_ASL_DISPLAYSWITCH
= 0x0040,
55 DISABLE_ASL_MODEM
= 0x0080,
56 DISABLE_ASL_CARDREADER
= 0x0100
73 CM_ASL_CPUTEMPERATURE
,
84 const char *cm_getv
[] = {
85 "WLDG", NULL
, NULL
, NULL
,
86 "CAMG", NULL
, NULL
, NULL
,
87 NULL
, "PBLG", NULL
, NULL
,
88 "CFVG", NULL
, NULL
, NULL
,
89 "USBG", NULL
, NULL
, "MODG",
93 const char *cm_setv
[] = {
94 "WLDS", NULL
, NULL
, NULL
,
95 "CAMS", NULL
, NULL
, NULL
,
96 "SDSP", "PBLS", "HDPS", NULL
,
97 "CFVS", NULL
, NULL
, NULL
,
98 "USBG", NULL
, NULL
, "MODS",
103 * This is the main structure, we can use it to store useful information
104 * about the hotk device
107 struct acpi_device
*device
; /* the device we are in */
108 acpi_handle handle
; /* the handle of the hotk device */
109 u32 cm_supported
; /* the control methods supported
111 uint init_flag
; /* Init flags */
112 u16 event_count
[128]; /* count for each event */
115 /* The actual device the driver binds to */
116 static struct eeepc_hotk
*ehotk
;
118 /* Platform device/driver */
119 static struct platform_driver platform_driver
= {
121 .name
= EEEPC_HOTK_FILE
,
122 .owner
= THIS_MODULE
,
126 static struct platform_device
*platform_device
;
129 * The hotkey driver declaration
131 static int eeepc_hotk_add(struct acpi_device
*device
);
132 static int eeepc_hotk_remove(struct acpi_device
*device
, int type
);
134 static const struct acpi_device_id eeepc_device_ids
[] = {
138 MODULE_DEVICE_TABLE(acpi
, eeepc_device_ids
);
140 static struct acpi_driver eeepc_hotk_driver
= {
141 .name
= EEEPC_HOTK_NAME
,
142 .class = EEEPC_HOTK_CLASS
,
143 .ids
= eeepc_device_ids
,
145 .add
= eeepc_hotk_add
,
146 .remove
= eeepc_hotk_remove
,
150 MODULE_AUTHOR("Corentin Chary, Eric Cooper");
151 MODULE_DESCRIPTION(EEEPC_HOTK_NAME
);
152 MODULE_LICENSE("GPL");
157 static int write_acpi_int(acpi_handle handle
, const char *method
, int val
,
158 struct acpi_buffer
*output
)
160 struct acpi_object_list params
;
161 union acpi_object in_obj
;
165 params
.pointer
= &in_obj
;
166 in_obj
.type
= ACPI_TYPE_INTEGER
;
167 in_obj
.integer
.value
= val
;
169 status
= acpi_evaluate_object(handle
, (char *)method
, ¶ms
, output
);
170 return (status
== AE_OK
? 0 : -1);
173 static int read_acpi_int(acpi_handle handle
, const char *method
, int *val
)
178 status
= acpi_evaluate_integer(handle
, (char *)method
, NULL
, &result
);
179 if (ACPI_FAILURE(status
)) {
188 static int set_acpi(int cm
, int value
)
190 if (ehotk
->cm_supported
& (0x1 << cm
)) {
191 const char *method
= cm_setv
[cm
];
194 if (write_acpi_int(ehotk
->handle
, method
, value
, NULL
))
195 printk(EEEPC_WARNING
"Error writing %s\n", method
);
200 static int get_acpi(int cm
)
203 if ((ehotk
->cm_supported
& (0x1 << cm
))) {
204 const char *method
= cm_getv
[cm
];
207 if (read_acpi_int(ehotk
->handle
, method
, &value
))
208 printk(EEEPC_WARNING
"Error reading %s\n", method
);
216 static int parse_arg(const char *buf
, unsigned long count
, int *val
)
220 if (sscanf(buf
, "%i", val
) != 1)
225 static ssize_t
store_sys_acpi(int cm
, const char *buf
, size_t count
)
229 rv
= parse_arg(buf
, count
, &value
);
235 static ssize_t
show_sys_acpi(int cm
, char *buf
)
237 return sprintf(buf
, "%d\n", get_acpi(cm
));
240 #define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
241 static ssize_t show_##_name(struct device *dev, \
242 struct device_attribute *attr, \
245 return show_sys_acpi(_cm, buf); \
247 static ssize_t store_##_name(struct device *dev, \
248 struct device_attribute *attr, \
249 const char *buf, size_t count) \
251 return store_sys_acpi(_cm, buf, count); \
253 static struct device_attribute dev_attr_##_name = { \
255 .name = __stringify(_name), \
257 .show = show_##_name, \
258 .store = store_##_name, \
261 EEEPC_CREATE_DEVICE_ATTR(camera
, CM_ASL_CAMERA
);
262 EEEPC_CREATE_DEVICE_ATTR(cardr
, CM_ASL_CARDREADER
);
263 EEEPC_CREATE_DEVICE_ATTR(disp
, CM_ASL_DISPLAYSWITCH
);
264 EEEPC_CREATE_DEVICE_ATTR(wlan
, CM_ASL_WLAN
);
266 static struct attribute
*platform_attributes
[] = {
267 &dev_attr_camera
.attr
,
268 &dev_attr_cardr
.attr
,
274 static struct attribute_group platform_attribute_group
= {
275 .attrs
= platform_attributes
281 static int eeepc_hotk_check(void)
283 struct acpi_buffer buffer
= { ACPI_ALLOCATE_BUFFER
, NULL
};
286 result
= acpi_bus_get_status(ehotk
->device
);
289 if (ehotk
->device
->status
.present
) {
290 if (write_acpi_int(ehotk
->handle
, "INIT", ehotk
->init_flag
,
292 printk(EEEPC_ERR
"Hotkey initialization failed\n");
295 printk(EEEPC_NOTICE
"Hotkey init flags 0x%x\n",
298 /* get control methods supported */
299 if (read_acpi_int(ehotk
->handle
, "CMSG"
300 , &ehotk
->cm_supported
)) {
302 "Get control methods supported failed\n");
306 "Get control methods supported: 0x%x\n",
307 ehotk
->cm_supported
);
310 printk(EEEPC_ERR
"Hotkey device not present, aborting\n");
316 static void notify_wlan(u32
*event
)
318 /* if DISABLE_ASL_WLAN is set, the notify code for fn+f2
319 will always be 0x10 */
320 if (ehotk
->cm_supported
& (0x1 << CM_ASL_WLAN
)) {
321 const char *method
= cm_getv
[CM_ASL_WLAN
];
323 if (read_acpi_int(ehotk
->handle
, method
, &value
))
324 printk(EEEPC_WARNING
"Error reading %s\n",
331 static void eeepc_hotk_notify(acpi_handle handle
, u32 event
, void *data
)
335 if (event
== NOTIFY_WLAN_ON
&& (DISABLE_ASL_WLAN
& ehotk
->init_flag
))
337 acpi_bus_generate_proc_event(ehotk
->device
, event
,
338 ehotk
->event_count
[event
% 128]++);
341 static int eeepc_hotk_add(struct acpi_device
*device
)
343 acpi_status status
= AE_OK
;
348 printk(EEEPC_NOTICE EEEPC_HOTK_NAME
"\n");
349 ehotk
= kzalloc(sizeof(struct eeepc_hotk
), GFP_KERNEL
);
352 ehotk
->init_flag
= DISABLE_ASL_WLAN
| DISABLE_ASL_DISPLAYSWITCH
;
353 ehotk
->handle
= device
->handle
;
354 strcpy(acpi_device_name(device
), EEEPC_HOTK_DEVICE_NAME
);
355 strcpy(acpi_device_class(device
), EEEPC_HOTK_CLASS
);
356 acpi_driver_data(device
) = ehotk
;
357 ehotk
->device
= device
;
358 result
= eeepc_hotk_check();
361 status
= acpi_install_notify_handler(ehotk
->handle
, ACPI_SYSTEM_NOTIFY
,
362 eeepc_hotk_notify
, ehotk
);
363 if (ACPI_FAILURE(status
))
364 printk(EEEPC_ERR
"Error installing notify handler\n");
373 static int eeepc_hotk_remove(struct acpi_device
*device
, int type
)
375 acpi_status status
= 0;
377 if (!device
|| !acpi_driver_data(device
))
379 status
= acpi_remove_notify_handler(ehotk
->handle
, ACPI_SYSTEM_NOTIFY
,
381 if (ACPI_FAILURE(status
))
382 printk(EEEPC_ERR
"Error removing notify handler\n");
390 static void __exit
eeepc_laptop_exit(void)
392 acpi_bus_unregister_driver(&eeepc_hotk_driver
);
393 sysfs_remove_group(&platform_device
->dev
.kobj
,
394 &platform_attribute_group
);
395 platform_device_unregister(platform_device
);
396 platform_driver_unregister(&platform_driver
);
399 static int __init
eeepc_laptop_init(void)
406 result
= acpi_bus_register_driver(&eeepc_hotk_driver
);
410 acpi_bus_unregister_driver(&eeepc_hotk_driver
);
413 dev
= acpi_get_physical_device(ehotk
->device
->handle
);
414 /* Register platform stuff */
415 result
= platform_driver_register(&platform_driver
);
417 goto fail_platform_driver
;
418 platform_device
= platform_device_alloc(EEEPC_HOTK_FILE
, -1);
419 if (!platform_device
) {
421 goto fail_platform_device1
;
423 result
= platform_device_add(platform_device
);
425 goto fail_platform_device2
;
426 result
= sysfs_create_group(&platform_device
->dev
.kobj
,
427 &platform_attribute_group
);
432 platform_device_del(platform_device
);
433 fail_platform_device2
:
434 platform_device_put(platform_device
);
435 fail_platform_device1
:
436 platform_driver_unregister(&platform_driver
);
437 fail_platform_driver
:
441 module_init(eeepc_laptop_init
);
442 module_exit(eeepc_laptop_exit
);