aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/eeepc-laptop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/eeepc-laptop.c')
-rw-r--r--drivers/misc/eeepc-laptop.c228
1 files changed, 209 insertions, 19 deletions
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index 1ee8501e90f1..5baa10bcaf6d 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -28,6 +28,8 @@
28#include <acpi/acpi_drivers.h> 28#include <acpi/acpi_drivers.h>
29#include <acpi/acpi_bus.h> 29#include <acpi/acpi_bus.h>
30#include <linux/uaccess.h> 30#include <linux/uaccess.h>
31#include <linux/input.h>
32#include <linux/rfkill.h>
31 33
32#define EEEPC_LAPTOP_VERSION "0.1" 34#define EEEPC_LAPTOP_VERSION "0.1"
33 35
@@ -125,6 +127,10 @@ struct eeepc_hotk {
125 by this BIOS */ 127 by this BIOS */
126 uint init_flag; /* Init flags */ 128 uint init_flag; /* Init flags */
127 u16 event_count[128]; /* count for each event */ 129 u16 event_count[128]; /* count for each event */
130 struct input_dev *inputdev;
131 u16 *keycode_map;
132 struct rfkill *eeepc_wlan_rfkill;
133 struct rfkill *eeepc_bluetooth_rfkill;
128}; 134};
129 135
130/* The actual device the driver binds to */ 136/* The actual device the driver binds to */
@@ -140,6 +146,27 @@ static struct platform_driver platform_driver = {
140 146
141static struct platform_device *platform_device; 147static struct platform_device *platform_device;
142 148
149struct key_entry {
150 char type;
151 u8 code;
152 u16 keycode;
153};
154
155enum { KE_KEY, KE_END };
156
157static struct key_entry eeepc_keymap[] = {
158 /* Sleep already handled via generic ACPI code */
159 {KE_KEY, 0x10, KEY_WLAN },
160 {KE_KEY, 0x12, KEY_PROG1 },
161 {KE_KEY, 0x13, KEY_MUTE },
162 {KE_KEY, 0x14, KEY_VOLUMEDOWN },
163 {KE_KEY, 0x15, KEY_VOLUMEUP },
164 {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
165 {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
166 {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
167 {KE_END, 0},
168};
169
143/* 170/*
144 * The hotkey driver declaration 171 * The hotkey driver declaration
145 */ 172 */
@@ -261,6 +288,44 @@ static int update_bl_status(struct backlight_device *bd)
261} 288}
262 289
263/* 290/*
291 * Rfkill helpers
292 */
293
294static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
295{
296 if (state == RFKILL_STATE_SOFT_BLOCKED)
297 return set_acpi(CM_ASL_WLAN, 0);
298 else
299 return set_acpi(CM_ASL_WLAN, 1);
300}
301
302static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
303{
304 if (get_acpi(CM_ASL_WLAN) == 1)
305 *state = RFKILL_STATE_UNBLOCKED;
306 else
307 *state = RFKILL_STATE_SOFT_BLOCKED;
308 return 0;
309}
310
311static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state)
312{
313 if (state == RFKILL_STATE_SOFT_BLOCKED)
314 return set_acpi(CM_ASL_BLUETOOTH, 0);
315 else
316 return set_acpi(CM_ASL_BLUETOOTH, 1);
317}
318
319static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
320{
321 if (get_acpi(CM_ASL_BLUETOOTH) == 1)
322 *state = RFKILL_STATE_UNBLOCKED;
323 else
324 *state = RFKILL_STATE_SOFT_BLOCKED;
325 return 0;
326}
327
328/*
264 * Sys helpers 329 * Sys helpers
265 */ 330 */
266static int parse_arg(const char *buf, unsigned long count, int *val) 331static int parse_arg(const char *buf, unsigned long count, int *val)
@@ -311,13 +376,11 @@ static ssize_t show_sys_acpi(int cm, char *buf)
311EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); 376EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
312EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); 377EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
313EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); 378EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
314EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN);
315 379
316static struct attribute *platform_attributes[] = { 380static struct attribute *platform_attributes[] = {
317 &dev_attr_camera.attr, 381 &dev_attr_camera.attr,
318 &dev_attr_cardr.attr, 382 &dev_attr_cardr.attr,
319 &dev_attr_disp.attr, 383 &dev_attr_disp.attr,
320 &dev_attr_wlan.attr,
321 NULL 384 NULL
322}; 385};
323 386
@@ -328,8 +391,64 @@ static struct attribute_group platform_attribute_group = {
328/* 391/*
329 * Hotkey functions 392 * Hotkey functions
330 */ 393 */
394static struct key_entry *eepc_get_entry_by_scancode(int code)
395{
396 struct key_entry *key;
397
398 for (key = eeepc_keymap; key->type != KE_END; key++)
399 if (code == key->code)
400 return key;
401
402 return NULL;
403}
404
405static struct key_entry *eepc_get_entry_by_keycode(int code)
406{
407 struct key_entry *key;
408
409 for (key = eeepc_keymap; key->type != KE_END; key++)
410 if (code == key->keycode && key->type == KE_KEY)
411 return key;
412
413 return NULL;
414}
415
416static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
417{
418 struct key_entry *key = eepc_get_entry_by_scancode(scancode);
419
420 if (key && key->type == KE_KEY) {
421 *keycode = key->keycode;
422 return 0;
423 }
424
425 return -EINVAL;
426}
427
428static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
429{
430 struct key_entry *key;
431 int old_keycode;
432
433 if (keycode < 0 || keycode > KEY_MAX)
434 return -EINVAL;
435
436 key = eepc_get_entry_by_scancode(scancode);
437 if (key && key->type == KE_KEY) {
438 old_keycode = key->keycode;
439 key->keycode = keycode;
440 set_bit(keycode, dev->keybit);
441 if (!eepc_get_entry_by_keycode(old_keycode))
442 clear_bit(old_keycode, dev->keybit);
443 return 0;
444 }
445
446 return -EINVAL;
447}
448
331static int eeepc_hotk_check(void) 449static int eeepc_hotk_check(void)
332{ 450{
451 const struct key_entry *key;
333 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 452 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
334 int result; 453 int result;
335 454
@@ -356,6 +475,31 @@ static int eeepc_hotk_check(void)
356 "Get control methods supported: 0x%x\n", 475 "Get control methods supported: 0x%x\n",
357 ehotk->cm_supported); 476 ehotk->cm_supported);
358 } 477 }
478 ehotk->inputdev = input_allocate_device();
479 if (!ehotk->inputdev) {
480 printk(EEEPC_INFO "Unable to allocate input device\n");
481 return 0;
482 }
483 ehotk->inputdev->name = "Asus EeePC extra buttons";
484 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
485 ehotk->inputdev->id.bustype = BUS_HOST;
486 ehotk->inputdev->getkeycode = eeepc_getkeycode;
487 ehotk->inputdev->setkeycode = eeepc_setkeycode;
488
489 for (key = eeepc_keymap; key->type != KE_END; key++) {
490 switch (key->type) {
491 case KE_KEY:
492 set_bit(EV_KEY, ehotk->inputdev->evbit);
493 set_bit(key->keycode, ehotk->inputdev->keybit);
494 break;
495 }
496 }
497 result = input_register_device(ehotk->inputdev);
498 if (result) {
499 printk(EEEPC_INFO "Unable to register input device\n");
500 input_free_device(ehotk->inputdev);
501 return 0;
502 }
359 } else { 503 } else {
360 printk(EEEPC_ERR "Hotkey device not present, aborting\n"); 504 printk(EEEPC_ERR "Hotkey device not present, aborting\n");
361 return -EINVAL; 505 return -EINVAL;
@@ -363,21 +507,6 @@ static int eeepc_hotk_check(void)
363 return 0; 507 return 0;
364} 508}
365 509
366static void notify_wlan(u32 *event)
367{
368 /* if DISABLE_ASL_WLAN is set, the notify code for fn+f2
369 will always be 0x10 */
370 if (ehotk->cm_supported & (0x1 << CM_ASL_WLAN)) {
371 const char *method = cm_getv[CM_ASL_WLAN];
372 int value;
373 if (read_acpi_int(ehotk->handle, method, &value))
374 printk(EEEPC_WARNING "Error reading %s\n",
375 method);
376 else if (value == 1)
377 *event = 0x11;
378 }
379}
380
381static void notify_brn(void) 510static void notify_brn(void)
382{ 511{
383 struct backlight_device *bd = eeepc_backlight_device; 512 struct backlight_device *bd = eeepc_backlight_device;
@@ -386,14 +515,28 @@ static void notify_brn(void)
386 515
387static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) 516static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
388{ 517{
518 static struct key_entry *key;
389 if (!ehotk) 519 if (!ehotk)
390 return; 520 return;
391 if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag))
392 notify_wlan(&event);
393 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) 521 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
394 notify_brn(); 522 notify_brn();
395 acpi_bus_generate_proc_event(ehotk->device, event, 523 acpi_bus_generate_proc_event(ehotk->device, event,
396 ehotk->event_count[event % 128]++); 524 ehotk->event_count[event % 128]++);
525 if (ehotk->inputdev) {
526 key = eepc_get_entry_by_scancode(event);
527 if (key) {
528 switch (key->type) {
529 case KE_KEY:
530 input_report_key(ehotk->inputdev, key->keycode,
531 1);
532 input_sync(ehotk->inputdev);
533 input_report_key(ehotk->inputdev, key->keycode,
534 0);
535 input_sync(ehotk->inputdev);
536 break;
537 }
538 }
539 }
397} 540}
398 541
399static int eeepc_hotk_add(struct acpi_device *device) 542static int eeepc_hotk_add(struct acpi_device *device)
@@ -420,6 +563,47 @@ static int eeepc_hotk_add(struct acpi_device *device)
420 eeepc_hotk_notify, ehotk); 563 eeepc_hotk_notify, ehotk);
421 if (ACPI_FAILURE(status)) 564 if (ACPI_FAILURE(status))
422 printk(EEEPC_ERR "Error installing notify handler\n"); 565 printk(EEEPC_ERR "Error installing notify handler\n");
566
567 if (get_acpi(CM_ASL_WLAN) != -1) {
568 ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
569 RFKILL_TYPE_WLAN);
570
571 if (!ehotk->eeepc_wlan_rfkill)
572 goto end;
573
574 ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
575 ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
576 ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
577 if (get_acpi(CM_ASL_WLAN) == 1)
578 ehotk->eeepc_wlan_rfkill->state =
579 RFKILL_STATE_UNBLOCKED;
580 else
581 ehotk->eeepc_wlan_rfkill->state =
582 RFKILL_STATE_SOFT_BLOCKED;
583 rfkill_register(ehotk->eeepc_wlan_rfkill);
584 }
585
586 if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
587 ehotk->eeepc_bluetooth_rfkill =
588 rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
589
590 if (!ehotk->eeepc_bluetooth_rfkill)
591 goto end;
592
593 ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
594 ehotk->eeepc_bluetooth_rfkill->toggle_radio =
595 eeepc_bluetooth_rfkill_set;
596 ehotk->eeepc_bluetooth_rfkill->get_state =
597 eeepc_bluetooth_rfkill_state;
598 if (get_acpi(CM_ASL_BLUETOOTH) == 1)
599 ehotk->eeepc_bluetooth_rfkill->state =
600 RFKILL_STATE_UNBLOCKED;
601 else
602 ehotk->eeepc_bluetooth_rfkill->state =
603 RFKILL_STATE_SOFT_BLOCKED;
604 rfkill_register(ehotk->eeepc_bluetooth_rfkill);
605 }
606
423 end: 607 end:
424 if (result) { 608 if (result) {
425 kfree(ehotk); 609 kfree(ehotk);
@@ -553,6 +737,12 @@ static void eeepc_backlight_exit(void)
553{ 737{
554 if (eeepc_backlight_device) 738 if (eeepc_backlight_device)
555 backlight_device_unregister(eeepc_backlight_device); 739 backlight_device_unregister(eeepc_backlight_device);
740 if (ehotk->inputdev)
741 input_unregister_device(ehotk->inputdev);
742 if (ehotk->eeepc_wlan_rfkill)
743 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
744 if (ehotk->eeepc_bluetooth_rfkill)
745 rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
556 eeepc_backlight_device = NULL; 746 eeepc_backlight_device = NULL;
557} 747}
558 748