diff options
Diffstat (limited to 'drivers/input/misc/wistron_btns.c')
| -rw-r--r-- | drivers/input/misc/wistron_btns.c | 549 |
1 files changed, 363 insertions, 186 deletions
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 961aad7a047..7b7add5061a 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -20,39 +20,34 @@ #include <linux/io.h> #include <linux/dmi.h> #include <linux/init.h> -#include <linux/input.h> +#include <linux/input-polldev.h> +#include <linux/input/sparse-keymap.h> #include <linux/interrupt.h> +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/mc146818rtc.h> #include <linux/module.h> #include <linux/preempt.h> #include <linux/string.h> -#include <linux/timer.h> +#include <linux/slab.h> #include <linux/types.h> #include <linux/platform_device.h> +#include <linux/leds.h> -/* - * Number of attempts to read data from queue per poll; - * the queue can hold up to 31 entries - */ -#define MAX_POLL_ITERATIONS 64 - -#define POLL_FREQUENCY 10 /* Number of polls per second */ - -#if POLL_FREQUENCY > HZ -#error "POLL_FREQUENCY too high" -#endif +/* How often we poll keys - msecs */ +#define POLL_INTERVAL_DEFAULT 500 /* when idle */ +#define POLL_INTERVAL_BURST 100 /* when a key was recently pressed */ /* BIOS subsystem IDs */ #define WIFI 0x35 #define BLUETOOTH 0x34 +#define MAIL_LED 0x31 MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>"); MODULE_DESCRIPTION("Wistron laptop button driver"); MODULE_LICENSE("GPL v2"); -MODULE_VERSION("0.2"); -static int force; /* = 0; */ +static bool force; /* = 0; */ module_param(force, bool, 0); MODULE_PARM_DESC(force, "Load even if computer is not in database"); @@ -174,7 +169,7 @@ static u16 bios_pop_queue(void) return regs.eax; } -static void __devinit bios_attach(void) +static void bios_attach(void) { struct regs regs; @@ -194,7 +189,7 @@ static void bios_detach(void) call_bios(®s); } -static u8 __devinit bios_get_cmos_address(void) +static u8 bios_get_cmos_address(void) { struct regs regs; @@ -206,7 +201,7 @@ static u8 __devinit bios_get_cmos_address(void) return regs.ecx; } -static u16 __devinit bios_get_default_setting(u8 subsys) +static u16 bios_get_default_setting(u8 subsys) { struct regs regs; @@ -230,39 +225,31 @@ static void bios_set_state(u8 subsys, int enable) /* Hardware database */ -struct key_entry { - char type; /* See KE_* below */ - u8 code; - union { - u16 keycode; /* For KE_KEY */ - struct { /* For KE_SW */ - u8 code; - u8 value; - } sw; - }; -}; - -enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH }; +#define KE_WIFI (KE_LAST + 1) +#define KE_BLUETOOTH (KE_LAST + 2) #define FE_MAIL_LED 0x01 #define FE_WIFI_LED 0x02 #define FE_UNTESTED 0x80 -static const struct key_entry *keymap; /* = NULL; Current key map */ -static int have_wifi; -static int have_bluetooth; +static struct key_entry *keymap; /* = NULL; Current key map */ +static bool have_wifi; +static bool have_bluetooth; +static int leds_present; /* bitmask of leds present */ -static int __init dmi_matched(struct dmi_system_id *dmi) +static int __init dmi_matched(const struct dmi_system_id *dmi) { const struct key_entry *key; keymap = dmi->driver_data; for (key = keymap; key->type != KE_END; key++) { if (key->type == KE_WIFI) - have_wifi = 1; + have_wifi = true; else if (key->type == KE_BLUETOOTH) - have_bluetooth = 1; + have_bluetooth = true; } + leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED); + return 1; } @@ -280,6 +267,26 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = { { KE_END, 0 } }; +static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = { + { KE_KEY, 0x01, {KEY_HELP} }, /* Fn+F1 */ + { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */ + { KE_BLUETOOTH, 0x30 }, /* Fn+F10 */ + { KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */ + { KE_KEY, 0x36, {KEY_WWW} }, /* www button */ + { KE_WIFI, 0x78 }, /* satellite dish button */ + { KE_END, 0 } +}; + +static struct key_entry keymap_fs_amilo_pro_v8210[] __initdata = { + { KE_KEY, 0x01, {KEY_HELP} }, /* Fn+F1 */ + { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */ + { KE_BLUETOOTH, 0x30 }, /* Fn+F10 */ + { KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */ + { KE_KEY, 0x36, {KEY_WWW} }, /* www button */ + { KE_WIFI, 0x78 }, /* satelite dish button */ + { KE_END, FE_WIFI_LED } +}; + static struct key_entry keymap_fujitsu_n3510[] __initdata = { { KE_KEY, 0x11, {KEY_PROG1} }, { KE_KEY, 0x12, {KEY_PROG2} }, @@ -565,7 +572,7 @@ static struct key_entry keymap_wistron_md96500[] __initdata = { { KE_KEY, 0x36, {KEY_WWW} }, { KE_WIFI, 0x30 }, { KE_BLUETOOTH, 0x44 }, - { KE_END, FE_UNTESTED } + { KE_END, 0 } }; static struct key_entry keymap_wistron_generic[] __initdata = { @@ -604,15 +611,43 @@ static struct key_entry keymap_wistron_generic[] __initdata = { { KE_END, 0 } }; +static struct key_entry keymap_aopen_1557[] __initdata = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_WIFI, 0x30 }, + { KE_KEY, 0x22, {KEY_REWIND} }, + { KE_KEY, 0x23, {KEY_FORWARD} }, + { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, + { KE_KEY, 0x25, {KEY_STOPCD} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_END, 0 } +}; + +static struct key_entry keymap_prestigio[] __initdata = { + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_WIFI, 0x30 }, + { KE_KEY, 0x22, {KEY_REWIND} }, + { KE_KEY, 0x23, {KEY_FORWARD} }, + { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, + { KE_KEY, 0x25, {KEY_STOPCD} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_END, 0 } +}; + + /* * If your machine is not here (which is currently rather likely), please send * a list of buttons and their key codes (reported when loading this module * with force=1) and the output of dmidecode to $MODULE_AUTHOR. */ -static struct dmi_system_id dmi_ids[] __initdata = { +static const struct dmi_system_id dmi_ids[] __initconst = { { + /* Fujitsu-Siemens Amilo Pro V2000 */ .callback = dmi_matched, - .ident = "Fujitsu-Siemens Amilo Pro V2000", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"), @@ -620,8 +655,26 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v2000 }, { + /* Fujitsu-Siemens Amilo Pro Edition V3505 */ + .callback = dmi_matched, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"), + }, + .driver_data = keymap_fs_amilo_pro_v3505 + }, + { + /* Fujitsu-Siemens Amilo Pro Edition V8210 */ + .callback = dmi_matched, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Series V8210"), + }, + .driver_data = keymap_fs_amilo_pro_v8210 + }, + { + /* Fujitsu-Siemens Amilo M7400 */ .callback = dmi_matched, - .ident = "Fujitsu-Siemens Amilo M7400", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "), @@ -629,8 +682,17 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_pro_v2000 }, { + /* Maxdata Pro 7000 DX */ + .callback = dmi_matched, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"), + }, + .driver_data = keymap_fs_amilo_pro_v2000 + }, + { + /* Fujitsu N3510 */ .callback = dmi_matched, - .ident = "Fujitsu N3510", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_PRODUCT_NAME, "N3510"), @@ -638,8 +700,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fujitsu_n3510 }, { + /* Acer Aspire 1500 */ .callback = dmi_matched, - .ident = "Acer Aspire 1500", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"), @@ -647,8 +709,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_1500 }, { + /* Acer Aspire 1600 */ .callback = dmi_matched, - .ident = "Acer Aspire 1600", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"), @@ -656,8 +718,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_1600 }, { + /* Acer Aspire 3020 */ .callback = dmi_matched, - .ident = "Acer Aspire 3020", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"), @@ -665,8 +727,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_5020 }, { + /* Acer Aspire 5020 */ .callback = dmi_matched, - .ident = "Acer Aspire 5020", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"), @@ -674,8 +736,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_5020 }, { + /* Acer TravelMate 2100 */ .callback = dmi_matched, - .ident = "Acer TravelMate 2100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"), @@ -683,8 +745,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_aspire_5020 }, { + /* Acer TravelMate 2410 */ .callback = dmi_matched, - .ident = "Acer TravelMate 2410", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"), @@ -692,8 +754,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_2410 }, { + /* Acer TravelMate C300 */ .callback = dmi_matched, - .ident = "Acer TravelMate C300", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"), @@ -701,8 +763,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_300 }, { + /* Acer TravelMate C100 */ .callback = dmi_matched, - .ident = "Acer TravelMate C100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"), @@ -710,8 +772,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_300 }, { + /* Acer TravelMate C110 */ .callback = dmi_matched, - .ident = "Acer TravelMate C110", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"), @@ -719,8 +781,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_110 }, { + /* Acer TravelMate 380 */ .callback = dmi_matched, - .ident = "Acer TravelMate 380", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"), @@ -728,8 +790,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_380 }, { + /* Acer TravelMate 370 */ .callback = dmi_matched, - .ident = "Acer TravelMate 370", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"), @@ -737,8 +799,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */ }, { + /* Acer TravelMate 220 */ .callback = dmi_matched, - .ident = "Acer TravelMate 220", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"), @@ -746,8 +808,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_220 }, { + /* Acer TravelMate 260 */ .callback = dmi_matched, - .ident = "Acer TravelMate 260", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"), @@ -755,8 +817,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_220 }, { + /* Acer TravelMate 230 */ .callback = dmi_matched, - .ident = "Acer TravelMate 230", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"), @@ -765,8 +827,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_230 }, { + /* Acer TravelMate 280 */ .callback = dmi_matched, - .ident = "Acer TravelMate 280", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"), @@ -774,8 +836,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_230 }, { + /* Acer TravelMate 240 */ .callback = dmi_matched, - .ident = "Acer TravelMate 240", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"), @@ -783,8 +845,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_240 }, { + /* Acer TravelMate 250 */ .callback = dmi_matched, - .ident = "Acer TravelMate 250", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"), @@ -792,8 +854,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_240 }, { + /* Acer TravelMate 2424NWXCi */ .callback = dmi_matched, - .ident = "Acer TravelMate 2424NWXCi", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"), @@ -801,8 +863,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_240 }, { + /* Acer TravelMate 350 */ .callback = dmi_matched, - .ident = "Acer TravelMate 350", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"), @@ -810,8 +872,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_350 }, { + /* Acer TravelMate 360 */ .callback = dmi_matched, - .ident = "Acer TravelMate 360", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), @@ -819,8 +881,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_360 }, { + /* Acer TravelMate 610 */ .callback = dmi_matched, - .ident = "Acer TravelMate 610", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ACER"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"), @@ -828,8 +890,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_610 }, { + /* Acer TravelMate 620 */ .callback = dmi_matched, - .ident = "Acer TravelMate 620", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"), @@ -837,8 +899,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_630 }, { + /* Acer TravelMate 630 */ .callback = dmi_matched, - .ident = "Acer TravelMate 630", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"), @@ -846,8 +908,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_acer_travelmate_630 }, { + /* AOpen 1559AS */ .callback = dmi_matched, - .ident = "AOpen 1559AS", .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "E2U"), DMI_MATCH(DMI_BOARD_NAME, "E2U"), @@ -855,8 +917,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_aopen_1559as }, { + /* Medion MD 9783 */ .callback = dmi_matched, - .ident = "Medion MD 9783", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"), @@ -864,8 +926,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_ms2111 }, { + /* Medion MD 40100 */ .callback = dmi_matched, - .ident = "Medion MD 40100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"), @@ -873,8 +935,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md40100 }, { + /* Medion MD 2900 */ .callback = dmi_matched, - .ident = "Medion MD 2900", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"), @@ -882,8 +944,17 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md2900 }, { + /* Medion MD 42200 */ + .callback = dmi_matched, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Medion"), + DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"), + }, + .driver_data = keymap_fs_amilo_pro_v2000 + }, + { + /* Medion MD 96500 */ .callback = dmi_matched, - .ident = "Medion MD 96500", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"), @@ -891,8 +962,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md96500 }, { + /* Medion MD 95400 */ .callback = dmi_matched, - .ident = "Medion MD 95400", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"), @@ -900,8 +971,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_wistron_md96500 }, { + /* Fujitsu Siemens Amilo D7820 */ .callback = dmi_matched, - .ident = "Fujitsu Siemens Amilo D7820", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */ DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"), @@ -909,8 +980,8 @@ static struct dmi_system_id dmi_ids[] __initdata = { .driver_data = keymap_fs_amilo_d88x0 }, { + /* Fujitsu Siemens Amilo D88x0 */ .callback = dmi_matched, - .ident = "Fujitsu Siemens Amilo D88x0", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"), @@ -919,6 +990,7 @@ static struct dmi_system_id dmi_ids[] __initdata = { }, { NULL, } }; +MODULE_DEVICE_TABLE(dmi, dmi_ids); /* Copy the good keymap, as the original ones are free'd */ static int __init copy_keymap(void) @@ -930,11 +1002,11 @@ static int __init copy_keymap(void) for (key = keymap; key->type != KE_END; key++) length++; - new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL); + new_keymap = kmemdup(keymap, length * sizeof(struct key_entry), + GFP_KERNEL); if (!new_keymap) return -ENOMEM; - memcpy(new_keymap, keymap, length * sizeof(struct key_entry)); keymap = new_keymap; return 0; @@ -946,6 +1018,10 @@ static int __init select_keymap(void) if (keymap_name != NULL) { if (strcmp (keymap_name, "1557/MS2141") == 0) keymap = keymap_wistron_ms2141; + else if (strcmp (keymap_name, "aopen1557") == 0) + keymap = keymap_aopen_1557; + else if (strcmp (keymap_name, "prestigio") == 0) + keymap = keymap_prestigio; else if (strcmp (keymap_name, "generic") == 0) keymap = keymap_wistron_generic; else { @@ -966,118 +1042,120 @@ static int __init select_keymap(void) /* Input layer interface */ -static struct input_dev *input_dev; +static struct input_polled_dev *wistron_idev; +static unsigned long jiffies_last_press; +static bool wifi_enabled; +static bool bluetooth_enabled; -static int __devinit setup_input_dev(void) + /* led management */ +static void wistron_mail_led_set(struct led_classdev *led_cdev, + enum led_brightness value) { - const struct key_entry *key; - int error; - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; + bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0); +} - input_dev->name = "Wistron laptop buttons"; - input_dev->phys = "wistron/input0"; - input_dev->id.bustype = BUS_HOST; - input_dev->cdev.dev = &wistron_device->dev; +/* same as setting up wifi card, but for laptops on which the led is managed */ +static void wistron_wifi_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0); +} - for (key = keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, input_dev->evbit); - set_bit(key->keycode, input_dev->keybit); - break; - - case KE_SW: - set_bit(EV_SW, input_dev->evbit); - set_bit(key->sw.code, input_dev->swbit); - break; - - default: - ; - } - } +static struct led_classdev wistron_mail_led = { + .name = "wistron:green:mail", + .brightness_set = wistron_mail_led_set, +}; - /* reads information flags on KE_END */ - if (key->code & FE_UNTESTED) - printk(KERN_WARNING "Untested laptop multimedia keys, " - "please report success or failure to eric.piel" - "@tremplin-utc.net\n"); +static struct led_classdev wistron_wifi_led = { + .name = "wistron:red:wifi", + .brightness_set = wistron_wifi_led_set, +}; - error = input_register_device(input_dev); - if (error) { - input_free_device(input_dev); - return error; +static void wistron_led_init(struct device *parent) +{ + if (leds_present & FE_WIFI_LED) { + u16 wifi = bios_get_default_setting(WIFI); + if (wifi & 1) { + wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF; + if (led_classdev_register(parent, &wistron_wifi_led)) + leds_present &= ~FE_WIFI_LED; + else + bios_set_state(WIFI, wistron_wifi_led.brightness); + + } else + leds_present &= ~FE_WIFI_LED; } - return 0; + if (leds_present & FE_MAIL_LED) { + /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */ + wistron_mail_led.brightness = LED_OFF; + if (led_classdev_register(parent, &wistron_mail_led)) + leds_present &= ~FE_MAIL_LED; + else + bios_set_state(MAIL_LED, wistron_mail_led.brightness); + } } -static void report_key(unsigned keycode) +static void wistron_led_remove(void) { - input_report_key(input_dev, keycode, 1); - input_sync(input_dev); - input_report_key(input_dev, keycode, 0); - input_sync(input_dev); -} + if (leds_present & FE_MAIL_LED) + led_classdev_unregister(&wistron_mail_led); -static void report_switch(unsigned code, int value) -{ - input_report_switch(input_dev, code, value); - input_sync(input_dev); + if (leds_present & FE_WIFI_LED) + led_classdev_unregister(&wistron_wifi_led); } - /* Driver core */ +static inline void wistron_led_suspend(void) +{ + if (leds_present & FE_MAIL_LED) + led_classdev_suspend(&wistron_mail_led); -static int wifi_enabled; -static int bluetooth_enabled; + if (leds_present & FE_WIFI_LED) + led_classdev_suspend(&wistron_wifi_led); +} -static void poll_bios(unsigned long); +static inline void wistron_led_resume(void) +{ + if (leds_present & FE_MAIL_LED) + led_classdev_resume(&wistron_mail_led); -static struct timer_list poll_timer = TIMER_INITIALIZER(poll_bios, 0, 0); + if (leds_present & FE_WIFI_LED) + led_classdev_resume(&wistron_wifi_led); +} static void handle_key(u8 code) { - const struct key_entry *key; + const struct key_entry *key = + sparse_keymap_entry_from_scancode(wistron_idev->input, code); - for (key = keymap; key->type != KE_END; key++) { - if (code == key->code) { - switch (key->type) { - case KE_KEY: - report_key(key->keycode); - break; - - case KE_SW: - report_switch(key->sw.code, key->sw.value); - break; - - case KE_WIFI: - if (have_wifi) { - wifi_enabled = !wifi_enabled; - bios_set_state(WIFI, wifi_enabled); - } - break; - - case KE_BLUETOOTH: - if (have_bluetooth) { - bluetooth_enabled = !bluetooth_enabled; - bios_set_state(BLUETOOTH, bluetooth_enabled); - } - break; - - case KE_END: - break; - default: - BUG(); + if (key) { + switch (key->type) { + case KE_WIFI: + if (have_wifi) { + wifi_enabled = !wifi_enabled; + bios_set_state(WIFI, wifi_enabled); + } + break; + + case KE_BLUETOOTH: + if (have_bluetooth) { + bluetooth_enabled = !bluetooth_enabled; + bios_set_state(BLUETOOTH, bluetooth_enabled); } - return; + break; + + default: + sparse_keymap_report_entry(wistron_idev->input, + key, 1, true); + break; } - } - printk(KERN_NOTICE "wistron_btns: Unknown key code %02X\n", code); + jiffies_last_press = jiffies; + } else + printk(KERN_NOTICE + "wistron_btns: Unknown key code %02X\n", code); } -static void poll_bios(unsigned long discard) +static void poll_bios(bool discard) { u8 qlen; u16 val; @@ -1090,15 +1168,97 @@ static void poll_bios(unsigned long discard) if (val != 0 && !discard) handle_key((u8)val); } +} - mod_timer(&poll_timer, jiffies + HZ / POLL_FREQUENCY); +static void wistron_flush(struct input_polled_dev *dev) +{ + /* Flush stale event queue */ + poll_bios(true); } -static int __devinit wistron_probe(struct platform_device *dev) +static void wistron_poll(struct input_polled_dev *dev) { - int err = setup_input_dev(); - if (err) - return err; + poll_bios(false); + + /* Increase poll frequency if user is currently pressing keys (< 2s ago) */ + if (time_before(jiffies, jiffies_last_press + 2 * HZ)) + dev->poll_interval = POLL_INTERVAL_BURST; + else + dev->poll_interval = POLL_INTERVAL_DEFAULT; +} + +static int wistron_setup_keymap(struct input_dev *dev, + struct key_entry *entry) +{ + switch (entry->type) { + + /* if wifi or bluetooth are not available, create normal keys */ + case KE_WIFI: + if (!have_wifi) { + entry->type = KE_KEY; + entry->keycode = KEY_WLAN; + } + break; + + case KE_BLUETOOTH: + if (!have_bluetooth) { + entry->type = KE_KEY; + entry->keycode = KEY_BLUETOOTH; + } + break; + + case KE_END: + if (entry->code & FE_UNTESTED) + printk(KERN_WARNING "Untested laptop multimedia keys, " + "please report success or failure to " + "eric.piel@tremplin-utc.net\n"); + break; + } + + return 0; +} + +static int setup_input_dev(void) +{ + struct input_dev *input_dev; + int error; + + wistron_idev = input_allocate_polled_device(); + if (!wistron_idev) + return -ENOMEM; + + wistron_idev->open = wistron_flush; + wistron_idev->poll = wistron_poll; + wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT; + + input_dev = wistron_idev->input; + input_dev->name = "Wistron laptop buttons"; + input_dev->phys = "wistron/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->dev.parent = &wistron_device->dev; + + error = sparse_keymap_setup(input_dev, keymap, wistron_setup_keymap); + if (error) + goto err_free_dev; + + error = input_register_polled_device(wistron_idev); + if (error) + goto err_free_keymap; + + return 0; + + err_free_keymap: + sparse_keymap_free(input_dev); + err_free_dev: + input_free_polled_device(wistron_idev); + return error; +} + +/* Driver core */ + +static int wistron_probe(struct platform_device *dev) +{ + int err; bios_attach(); cmos_address = bios_get_cmos_address(); @@ -1106,7 +1266,7 @@ static int __devinit wistron_probe(struct platform_device *dev) if (have_wifi) { u16 wifi = bios_get_default_setting(WIFI); if (wifi & 1) - wifi_enabled = (wifi & 2) ? 1 : 0; + wifi_enabled = wifi & 2; else have_wifi = 0; @@ -1117,43 +1277,51 @@ static int __devinit wistron_probe(struct platform_device *dev) if (have_bluetooth) { u16 bt = bios_get_default_setting(BLUETOOTH); if (bt & 1) - bluetooth_enabled = (bt & 2) ? 1 : 0; + bluetooth_enabled = bt & 2; else - have_bluetooth = 0; + have_bluetooth = false; if (have_bluetooth) bios_set_state(BLUETOOTH, bluetooth_enabled); } - poll_bios(1); /* Flush stale event queue and arm timer */ + wistron_led_init(&dev->dev); + + err = setup_input_dev(); + if (err) { + bios_detach(); + return err; + } return 0; } -static int __devexit wistron_remove(struct platform_device *dev) +static int wistron_remove(struct platform_device *dev) { - del_timer_sync(&poll_timer); - input_unregister_device(input_dev); + wistron_led_remove(); + input_unregister_polled_device(wistron_idev); + sparse_keymap_free(wistron_idev->input); + input_free_polled_device(wistron_idev); bios_detach(); return 0; } #ifdef CONFIG_PM -static int wistron_suspend(struct platform_device *dev, pm_message_t state) +static int wistron_suspend(struct device *dev) { - del_timer_sync(&poll_timer); - if (have_wifi) bios_set_state(WIFI, 0); if (have_bluetooth) bios_set_state(BLUETOOTH, 0); + wistron_led_suspend(); + return 0; } -static int wistron_resume(struct platform_device *dev) +static int wistron_resume(struct device *dev) { if (have_wifi) bios_set_state(WIFI, wifi_enabled); @@ -1161,24 +1329,31 @@ static int wistron_resume(struct platform_device *dev) if (have_bluetooth) bios_set_state(BLUETOOTH, bluetooth_enabled); - poll_bios(1); + wistron_led_resume(); + + poll_bios(true); return 0; } -#else -#define wistron_suspend NULL -#define wistron_resume NULL + +static const struct dev_pm_ops wistron_pm_ops = { + .suspend = wistron_suspend, + .resume = wistron_resume, + .poweroff = wistron_suspend, + .restore = wistron_resume, +}; #endif static struct platform_driver wistron_driver = { .driver = { .name = "wistron-bios", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &wistron_pm_ops, +#endif }, .probe = wistron_probe, - .remove = __devexit_p(wistron_remove), - .suspend = wistron_suspend, - .resume = wistron_resume, + .remove = wistron_remove, }; static int __init wb_module_init(void) @@ -1191,7 +1366,7 @@ static int __init wb_module_init(void) err = map_bios(); if (err) - return err; + goto err_free_keymap; err = platform_driver_register(&wistron_driver); if (err) @@ -1215,6 +1390,8 @@ static int __init wb_module_init(void) platform_driver_unregister(&wistron_driver); err_unmap_bios: unmap_bios(); + err_free_keymap: + kfree(keymap); return err; } |
