On Monday 04 August 2008, Matthew Garrett wrote: > eeepc-laptop currently only sends key events via ACPI and has > non-standard rfkill control. Add an input device and use the rfkill > infrastructure. > > Signed-off-by: Matthew Garrett <mjg@xxxxxxxxxx> Please use the rfkill_force_state() to report state changes, that will ensure that the events are immediately send to the rfkill layer. Otherwise events will not be reported untill the next get_state() event. Ivo > --- > > This attempts to ensure that bluetoth and wlan rfkill devices are only > created if the device is prseent, but I don't have a Bluetooth-enabled > Eee to hand so I'm not certain it's correct. Testing with rfkill-input > shows that the wifi interface works, though. > > commit 0656cf909274db0e59bb570c2bddd242cf075e7f > Author: Matthew Garrett <mjg59@xxxxxxxxxxxxx> > Date: Mon Aug 4 18:00:57 2008 +0100 > > Rationalise interfacse > > diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c > index facdb98..ad55e60 100644 > --- a/drivers/misc/eeepc-laptop.c > +++ b/drivers/misc/eeepc-laptop.c > @@ -28,6 +28,8 @@ > #include <acpi/acpi_drivers.h> > #include <acpi/acpi_bus.h> > #include <linux/uaccess.h> > +#include <linux/input.h> > +#include <linux/rfkill.h> > > #define EEEPC_LAPTOP_VERSION "0.1" > > @@ -125,6 +127,10 @@ struct eeepc_hotk { > by this BIOS */ > uint init_flag; /* Init flags */ > u16 event_count[128]; /* count for each event */ > + struct input_dev *inputdev; > + u16 *keycode_map; > + struct rfkill *eeepc_wlan_rfkill; > + struct rfkill *eeepc_bluetooth_rfkill; > }; > > /* The actual device the driver binds to */ > @@ -140,6 +146,27 @@ static struct platform_driver platform_driver = { > > static struct platform_device *platform_device; > > +struct key_entry { > + char type; > + u8 code; > + u16 keycode; > +}; > + > +enum { KE_KEY, KE_END }; > + > +static struct key_entry eeepc_keymap[] = { > + /* Sleep already handled via generic ACPI code */ > + {KE_KEY, 0x10, KEY_WLAN }, > + {KE_KEY, 0x12, KEY_PROG1 }, > + {KE_KEY, 0x13, KEY_MUTE }, > + {KE_KEY, 0x14, KEY_VOLUMEDOWN }, > + {KE_KEY, 0x15, KEY_VOLUMEUP }, > + {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE }, > + {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE }, > + {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE }, > + {KE_END, 0}, > +}; > + > /* > * The hotkey driver declaration > */ > @@ -261,6 +288,32 @@ static int update_bl_status(struct backlight_device *bd) > } > > /* > + * Rfkill helpers > + */ > + > +static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state) > +{ > + return set_acpi(CM_ASL_WLAN, state); > +} > + > +static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state) > +{ > + *state = get_acpi(CM_ASL_WLAN); > + return 0; > +} > + > +static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state) > +{ > + return set_acpi(CM_ASL_BLUETOOTH, state); > +} > + > +static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state) > +{ > + *state = get_acpi(CM_ASL_BLUETOOTH); > + return 0; > +} > + > +/* > * Sys helpers > */ > static int parse_arg(const char *buf, unsigned long count, int *val) > @@ -311,13 +364,11 @@ static ssize_t show_sys_acpi(int cm, char *buf) > EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); > EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); > EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); > -EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN); > > static struct attribute *platform_attributes[] = { > &dev_attr_camera.attr, > &dev_attr_cardr.attr, > &dev_attr_disp.attr, > - &dev_attr_wlan.attr, > NULL > }; > > @@ -328,8 +379,64 @@ static struct attribute_group platform_attribute_group = { > /* > * Hotkey functions > */ > +static struct key_entry *eepc_get_entry_by_scancode(int code) > +{ > + struct key_entry *key; > + > + for (key = eeepc_keymap; key->type != KE_END; key++) > + if (code == key->code) > + return key; > + > + return NULL; > +} > + > +static struct key_entry *eepc_get_entry_by_keycode(int code) > +{ > + struct key_entry *key; > + > + for (key = eeepc_keymap; key->type != KE_END; key++) > + if (code == key->keycode && key->type == KE_KEY) > + return key; > + > + return NULL; > +} > + > +static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode) > +{ > + struct key_entry *key = eepc_get_entry_by_scancode(scancode); > + > + if (key && key->type == KE_KEY) { > + *keycode = key->keycode; > + return 0; > + } > + > + return -EINVAL; > +} > + > +static int eeepc_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 = eepc_get_entry_by_scancode(scancode); > + if (key && key->type == KE_KEY) { > + old_keycode = key->keycode; > + key->keycode = keycode; > + set_bit(keycode, dev->keybit); > + if (!eepc_get_entry_by_keycode(old_keycode)) > + clear_bit(old_keycode, dev->keybit); > + return 0; > + } > + > + return -EINVAL; > +} > + > static int eeepc_hotk_check(void) > { > + const struct key_entry *key; > struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; > int result; > > @@ -356,6 +463,31 @@ static int eeepc_hotk_check(void) > "Get control methods supported: 0x%x\n", > ehotk->cm_supported); > } > + ehotk->inputdev = input_allocate_device(); > + if (!ehotk->inputdev) { > + printk(EEEPC_INFO "Unable to allocate input device\n"); > + return 0; > + } > + ehotk->inputdev->name = "Asus EeePC extra buttons"; > + ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0"; > + ehotk->inputdev->id.bustype = BUS_HOST; > + ehotk->inputdev->getkeycode = eeepc_getkeycode; > + ehotk->inputdev->setkeycode = eeepc_setkeycode; > + > + for (key = eeepc_keymap; key->type != KE_END; key++) { > + switch (key->type) { > + case KE_KEY: > + set_bit(EV_KEY, ehotk->inputdev->evbit); > + set_bit(key->keycode, ehotk->inputdev->keybit); > + break; > + } > + } > + result = input_register_device(ehotk->inputdev); > + if (result) { > + printk(EEEPC_INFO "Unable to register input device\n"); > + input_free_device(ehotk->inputdev); > + return 0; > + } > } else { > printk(EEEPC_ERR "Hotkey device not present, aborting\n"); > return -EINVAL; > @@ -363,21 +495,6 @@ static int eeepc_hotk_check(void) > return 0; > } > > -static void notify_wlan(u32 *event) > -{ > - /* if DISABLE_ASL_WLAN is set, the notify code for fn+f2 > - will always be 0x10 */ > - if (ehotk->cm_supported & (0x1 << CM_ASL_WLAN)) { > - const char *method = cm_getv[CM_ASL_WLAN]; > - int value; > - if (read_acpi_int(ehotk->handle, method, &value)) > - printk(EEEPC_WARNING "Error reading %s\n", > - method); > - else if (value == 1) > - *event = 0x11; > - } > -} > - > static void notify_brn(void) > { > struct backlight_device *bd = eeepc_backlight_device; > @@ -386,14 +503,28 @@ static void notify_brn(void) > > static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) > { > + static struct key_entry *key; > if (!ehotk) > return; > - if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag)) > - notify_wlan(&event); > if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) > notify_brn(); > acpi_bus_generate_proc_event(ehotk->device, event, > ehotk->event_count[event % 128]++); > + if (ehotk->inputdev) { > + key = eepc_get_entry_by_scancode(event); > + if (key) { > + switch (key->type) { > + case KE_KEY: > + input_report_key(ehotk->inputdev, key->keycode, > + 1); > + input_sync(ehotk->inputdev); > + input_report_key(ehotk->inputdev, key->keycode, > + 0); > + input_sync(ehotk->inputdev); > + break; > + } > + } > + } > } > > static int eeepc_hotk_add(struct acpi_device *device) > @@ -420,6 +551,37 @@ static int eeepc_hotk_add(struct acpi_device *device) > eeepc_hotk_notify, ehotk); > if (ACPI_FAILURE(status)) > printk(EEEPC_ERR "Error installing notify handler\n"); > + > + if (get_acpi(CM_ASL_WLAN) != -1) { > + ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev, > + RFKILL_TYPE_WLAN); > + > + if (!ehotk->eeepc_wlan_rfkill) > + goto end; > + > + ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan"; > + ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set; > + ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state; > + ehotk->eeepc_wlan_rfkill->user_claim_unsupported = 0; > + rfkill_register(ehotk->eeepc_wlan_rfkill); > + } > + > + if (get_acpi(CM_ASL_BLUETOOTH) != -1) { > + ehotk->eeepc_bluetooth_rfkill = > + rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH); > + > + if (!ehotk->eeepc_bluetooth_rfkill) > + goto end; > + > + ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth"; > + ehotk->eeepc_bluetooth_rfkill->toggle_radio = > + eeepc_bluetooth_rfkill_set; > + ehotk->eeepc_bluetooth_rfkill->get_state = > + eeepc_bluetooth_rfkill_state; > + ehotk->eeepc_bluetooth_rfkill->user_claim_unsupported = 0; > + rfkill_register(ehotk->eeepc_bluetooth_rfkill); > + } > + > end: > if (result) { > kfree(ehotk); > @@ -543,6 +705,12 @@ static void eeepc_backlight_exit(void) > { > if (eeepc_backlight_device) > backlight_device_unregister(eeepc_backlight_device); > + if (ehotk->inputdev) > + input_unregister_device(ehotk->inputdev); > + if (ehotk->eeepc_wlan_rfkill) > + rfkill_unregister(ehotk->eeepc_wlan_rfkill); > + if (ehotk->eeepc_bluetooth_rfkill) > + rfkill_unregister(ehotk->eeepc_bluetooth_rfkill); > eeepc_backlight_device = NULL; > } > > > -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html