Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 181847
b: refs/heads/master
c: 6335e4d
h: refs/heads/master
i:
  181845: c50b84f
  181843: a781237
  181839: c13adf3
v: v3
  • Loading branch information
Matthew Garrett committed Feb 25, 2010
1 parent 369d7a8 commit cc4d560
Show file tree
Hide file tree
Showing 2 changed files with 200 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: caeacf59af3d114a3121bb04f8057109bbf289ea
refs/heads/master: 6335e4d56681f6f08f24f4b812a72d402793d393
206 changes: 199 additions & 7 deletions trunk/drivers/platform/x86/toshiba_acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
#include <linux/input.h>

#include <asm/uaccess.h>

Expand All @@ -62,9 +63,10 @@ MODULE_LICENSE("GPL");

/* Toshiba ACPI method paths */
#define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM"
#define METHOD_HCI_1 "\\_SB_.VALD.GHCI"
#define METHOD_HCI_2 "\\_SB_.VALZ.GHCI"
#define TOSH_INTERFACE_1 "\\_SB_.VALD"
#define TOSH_INTERFACE_2 "\\_SB_.VALZ"
#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
#define GHCI_METHOD ".GHCI"

/* Toshiba HCI interface definitions
*
Expand Down Expand Up @@ -116,6 +118,36 @@ static const struct acpi_device_id toshiba_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);

struct key_entry {
char type;
u16 code;
u16 keycode;
};

enum {KE_KEY, KE_END};

static struct key_entry toshiba_acpi_keymap[] = {
{KE_KEY, 0x101, KEY_MUTE},
{KE_KEY, 0x13b, KEY_COFFEE},
{KE_KEY, 0x13c, KEY_BATTERY},
{KE_KEY, 0x13d, KEY_SLEEP},
{KE_KEY, 0x13e, KEY_SUSPEND},
{KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
{KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
{KE_KEY, 0x141, KEY_BRIGHTNESSUP},
{KE_KEY, 0x142, KEY_WLAN},
{KE_KEY, 0x143, KEY_PROG1},
{KE_KEY, 0xb05, KEY_PROG2},
{KE_KEY, 0xb06, KEY_WWW},
{KE_KEY, 0xb07, KEY_MAIL},
{KE_KEY, 0xb30, KEY_STOP},
{KE_KEY, 0xb31, KEY_PREVIOUSSONG},
{KE_KEY, 0xb32, KEY_NEXTSONG},
{KE_KEY, 0xb33, KEY_PLAYPAUSE},
{KE_KEY, 0xb5a, KEY_MEDIA},
{KE_END, 0, 0},
};

/* utility
*/

Expand Down Expand Up @@ -251,6 +283,8 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
struct toshiba_acpi_dev {
struct platform_device *p_dev;
struct rfkill *bt_rfk;
struct input_dev *hotkey_dev;
acpi_handle handle;

const char *bt_name;

Expand Down Expand Up @@ -711,8 +745,159 @@ static struct backlight_ops toshiba_backlight_data = {
.update_status = set_lcd_status,
};

static struct key_entry *toshiba_acpi_get_entry_by_scancode(int code)
{
struct key_entry *key;

for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
if (code == key->code)
return key;

return NULL;
}

static struct key_entry *toshiba_acpi_get_entry_by_keycode(int code)
{
struct key_entry *key;

for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
if (code == key->keycode && key->type == KE_KEY)
return key;

return NULL;
}

static int toshiba_acpi_getkeycode(struct input_dev *dev, int scancode,
int *keycode)
{
struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);

if (key && key->type == KE_KEY) {
*keycode = key->keycode;
return 0;
}

return -EINVAL;
}

static int toshiba_acpi_setkeycode(struct input_dev *dev, int scancode,
int keycode)
{
struct key_entry *key;
int old_keycode;

if (keycode < 0 || keycode > KEY_MAX)
return -EINVAL;

key = toshiba_acpi_get_entry_by_scancode(scancode);
if (key && key->type == KE_KEY) {
old_keycode = key->keycode;
key->keycode = keycode;
set_bit(keycode, dev->keybit);
if (!toshiba_acpi_get_entry_by_keycode(old_keycode))
clear_bit(old_keycode, dev->keybit);
return 0;
}

return -EINVAL;
}

static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
{
u32 hci_result, value;
struct key_entry *key;

if (event != 0x80)
return;
do {
hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
if (hci_result == HCI_SUCCESS) {
if (value == 0x100)
continue;
else if (value & 0x80) {
key = toshiba_acpi_get_entry_by_scancode
(value & ~0x80);
if (!key) {
printk(MY_INFO "Unknown key %x\n",
value & ~0x80);
continue;
}
input_report_key(toshiba_acpi.hotkey_dev,
key->keycode, 1);
input_sync(toshiba_acpi.hotkey_dev);
input_report_key(toshiba_acpi.hotkey_dev,
key->keycode, 0);
input_sync(toshiba_acpi.hotkey_dev);
}
} else if (hci_result == HCI_NOT_SUPPORTED) {
/* This is a workaround for an unresolved issue on
* some machines where system events sporadically
* become disabled. */
hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
printk(MY_NOTICE "Re-enabled hotkeys\n");
}
} while (hci_result != HCI_EMPTY);
}

static int toshiba_acpi_setup_keyboard(char *device)
{
acpi_status status;
acpi_handle handle;
int result;
const struct key_entry *key;

status = acpi_get_handle(NULL, device, &handle);
if (ACPI_FAILURE(status)) {
printk(MY_INFO "Unable to get notification device\n");
return -ENODEV;
}

toshiba_acpi.handle = handle;

status = acpi_evaluate_object(handle, "ENAB", NULL, NULL);
if (ACPI_FAILURE(status)) {
printk(MY_INFO "Unable to enable hotkeys\n");
return -ENODEV;
}

status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY,
toshiba_acpi_notify, NULL);
if (ACPI_FAILURE(status)) {
printk(MY_INFO "Unable to install hotkey notification\n");
return -ENODEV;
}

toshiba_acpi.hotkey_dev = input_allocate_device();
if (!toshiba_acpi.hotkey_dev) {
printk(MY_INFO "Unable to register input device\n");
return -ENOMEM;
}

toshiba_acpi.hotkey_dev->name = "Toshiba input device";
toshiba_acpi.hotkey_dev->phys = device;
toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode;
toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode;

for (key = toshiba_acpi_keymap; key->type != KE_END; key++) {
set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit);
set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit);
}

result = input_register_device(toshiba_acpi.hotkey_dev);
if (result) {
printk(MY_INFO "Unable to register input device\n");
return result;
}

return 0;
}

static void toshiba_acpi_exit(void)
{
if (toshiba_acpi.hotkey_dev)
input_unregister_device(toshiba_acpi.hotkey_dev);

if (toshiba_acpi.bt_rfk) {
rfkill_unregister(toshiba_acpi.bt_rfk);
rfkill_destroy(toshiba_acpi.bt_rfk);
Expand All @@ -726,6 +911,9 @@ static void toshiba_acpi_exit(void)
if (toshiba_proc_dir)
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);

acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
toshiba_acpi_notify);

platform_device_unregister(toshiba_acpi.p_dev);

return;
Expand All @@ -742,11 +930,15 @@ static int __init toshiba_acpi_init(void)
return -ENODEV;

/* simple device detection: look for HCI method */
if (is_valid_acpi_path(METHOD_HCI_1))
method_hci = METHOD_HCI_1;
else if (is_valid_acpi_path(METHOD_HCI_2))
method_hci = METHOD_HCI_2;
else
if (is_valid_acpi_path(TOSH_INTERFACE_1 GHCI_METHOD)) {
method_hci = TOSH_INTERFACE_1 GHCI_METHOD;
if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_1))
printk(MY_INFO "Unable to activate hotkeys\n");
} else if (is_valid_acpi_path(TOSH_INTERFACE_2 GHCI_METHOD)) {
method_hci = TOSH_INTERFACE_2 GHCI_METHOD;
if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2))
printk(MY_INFO "Unable to activate hotkeys\n");
} else
return -ENODEV;

printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",
Expand Down

0 comments on commit cc4d560

Please sign in to comment.