diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 20:57:44 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 20:57:44 (GMT) |
commit | 6e5565f949af1322f8f3d3f43d044645ae448499 (patch) | |
tree | 92868f6d3dcc6c105a0d35f9412f75c07139402e /drivers/input/misc | |
parent | e5a9e8e6890d9b9c7a0f25b03ffdaf28614a9a4c (diff) | |
parent | 03366e7b9bf1544cb0b98f1a5cd6d340654f486a (diff) | |
download | linux-6e5565f949af1322f8f3d3f43d044645ae448499.tar.xz |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (34 commits)
Input: i8042 - non-x86 build fix
Input: pxa27x_keypad - also enable on PXA3xx
Input: pxa27x_keypad - add debounce_interval to the keypad platform data
Input: pxa27x_keypad - use device resources for I/O memory mapping and IRQ
Input: pxa27x_keypad - enable rotary encoders and direct keys
Input: pxa27x_keypad - introduce pxa27x_keypad_config()
Input: pxa27x_keypad - introduce driver structure and use KEY() to define matrix keys
Input: pxa27x_keypad - remove pin configuration from the driver
Input: pxa27x_keypad - rename the driver (was pxa27x_keyboard)
Input: constify function pointer tables (seq_operations)
Input: i8042 - add Fujitsu-Siemens Amilo Pro 2010 to nomux list
Input: i8042 - enable DMI quirks on x86-64
Input: i8042 - add Dritek quirk for Acer Aspire 9110
Input: add input event to APM event bridge
Input: mousedev - use BIT_MASK instead of BIT
Input: remove duplicate includes
Input: remove cdev from input_dev structure
Input: remove duplicated headers in drivers/char/keyboard.c
Input: i8042 - add Dritek keyboard extension quirk
Input: add Tosa keyboard driver
...
Diffstat (limited to 'drivers/input/misc')
-rw-r--r-- | drivers/input/misc/Kconfig | 14 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/misc/apanel.c | 378 | ||||
-rw-r--r-- | drivers/input/misc/ati_remote.c | 1 | ||||
-rw-r--r-- | drivers/input/misc/atlas_btns.c | 39 | ||||
-rw-r--r-- | drivers/input/misc/cobalt_btns.c | 73 | ||||
-rw-r--r-- | drivers/input/misc/keyspan_remote.c | 119 |
7 files changed, 519 insertions, 106 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 8f5c7b9..8b10d9f 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -40,6 +40,20 @@ config INPUT_M68K_BEEP tristate "M68k Beeper support" depends on M68K +config INPUT_APANEL + tristate "Fujitsu Lifebook Application Panel buttons" + depends on X86 + select I2C_I801 + select INPUT_POLLDEV + select CHECK_SIGNATURE + help + Say Y here for support of the Application Panel buttons, used on + Fujitsu Lifebook. These are attached to the mainboard through + an SMBus interface managed by the I2C Intel ICH (i801) driver. + + To compile this driver as a module, choose M here: the module will + be called apanel. + config INPUT_IXP4XX_BEEPER tristate "IXP4XX Beeper support" depends on ARCH_IXP4XX diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 3585b50..ebd39f2 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o +obj-$(CONFIG_INPUT_APANEL) += apanel.o diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c new file mode 100644 index 0000000..9531d8c --- /dev/null +++ b/drivers/input/misc/apanel.c @@ -0,0 +1,378 @@ +/* + * Fujitsu Lifebook Application Panel button drive + * + * Copyright (C) 2007 Stephen Hemminger <shemminger@linux-foundation.org> + * Copyright (C) 2001-2003 Jochen Eisinger <jochen@penguin-breeder.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Many Fujitsu Lifebook laptops have a small panel of buttons that are + * accessible via the i2c/smbus interface. This driver polls those + * buttons and generates input events. + * + * For more details see: + * http://apanel.sourceforge.net/tech.php + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/input-polldev.h> +#include <linux/i2c.h> +#include <linux/workqueue.h> +#include <linux/leds.h> + +#define APANEL_NAME "Fujitsu Application Panel" +#define APANEL_VERSION "1.3.1" +#define APANEL "apanel" + +/* How often we poll keys - msecs */ +#define POLL_INTERVAL_DEFAULT 1000 + +/* Magic constants in BIOS that tell about buttons */ +enum apanel_devid { + APANEL_DEV_NONE = 0, + APANEL_DEV_APPBTN = 1, + APANEL_DEV_CDBTN = 2, + APANEL_DEV_LCD = 3, + APANEL_DEV_LED = 4, + + APANEL_DEV_MAX, +}; + +enum apanel_chip { + CHIP_NONE = 0, + CHIP_OZ992C = 1, + CHIP_OZ163T = 2, + CHIP_OZ711M3 = 4, +}; + +/* Result of BIOS snooping/probing -- what features are supported */ +static enum apanel_chip device_chip[APANEL_DEV_MAX]; + +#define MAX_PANEL_KEYS 12 + +struct apanel { + struct input_polled_dev *ipdev; + struct i2c_client client; + unsigned short keymap[MAX_PANEL_KEYS]; + u16 nkeys; + u16 led_bits; + struct work_struct led_work; + struct led_classdev mail_led; +}; + + +static int apanel_probe(struct i2c_adapter *, int, int); + +/* for now, we only support one address */ +static unsigned short normal_i2c[] = {0, I2C_CLIENT_END}; +static unsigned short ignore = I2C_CLIENT_END; +static struct i2c_client_address_data addr_data = { + .normal_i2c = normal_i2c, + .probe = &ignore, + .ignore = &ignore, +}; + +static void report_key(struct input_dev *input, unsigned keycode) +{ + pr_debug(APANEL ": report key %#x\n", keycode); + input_report_key(input, keycode, 1); + input_sync(input); + + input_report_key(input, keycode, 0); + input_sync(input); +} + +/* Poll for key changes + * + * Read Application keys via SMI + * A (0x4), B (0x8), Internet (0x2), Email (0x1). + * + * CD keys: + * Forward (0x100), Rewind (0x200), Stop (0x400), Pause (0x800) + */ +static void apanel_poll(struct input_polled_dev *ipdev) +{ + struct apanel *ap = ipdev->private; + struct input_dev *idev = ipdev->input; + u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8; + s32 data; + int i; + + data = i2c_smbus_read_word_data(&ap->client, cmd); + if (data < 0) + return; /* ignore errors (due to ACPI??) */ + + /* write back to clear latch */ + i2c_smbus_write_word_data(&ap->client, cmd, 0); + + if (!data) + return; + + dev_dbg(&idev->dev, APANEL ": data %#x\n", data); + for (i = 0; i < idev->keycodemax; i++) + if ((1u << i) & data) + report_key(idev, ap->keymap[i]); +} + +/* Track state changes of LED */ +static void led_update(struct work_struct *work) +{ + struct apanel *ap = container_of(work, struct apanel, led_work); + + i2c_smbus_write_word_data(&ap->client, 0x10, ap->led_bits); +} + +static void mail_led_set(struct led_classdev *led, + enum led_brightness value) +{ + struct apanel *ap = container_of(led, struct apanel, mail_led); + + if (value != LED_OFF) + ap->led_bits |= 0x8000; + else + ap->led_bits &= ~0x8000; + + schedule_work(&ap->led_work); +} + +static int apanel_detach_client(struct i2c_client *client) +{ + struct apanel *ap = i2c_get_clientdata(client); + + if (device_chip[APANEL_DEV_LED] != CHIP_NONE) + led_classdev_unregister(&ap->mail_led); + + input_unregister_polled_device(ap->ipdev); + i2c_detach_client(&ap->client); + input_free_polled_device(ap->ipdev); + + return 0; +} + +/* Function is invoked for every i2c adapter. */ +static int apanel_attach_adapter(struct i2c_adapter *adap) +{ + dev_dbg(&adap->dev, APANEL ": attach adapter id=%d\n", adap->id); + + /* Our device is connected only to i801 on laptop */ + if (adap->id != I2C_HW_SMBUS_I801) + return -ENODEV; + + return i2c_probe(adap, &addr_data, apanel_probe); +} + +static void apanel_shutdown(struct i2c_client *client) +{ + apanel_detach_client(client); +} + +static struct i2c_driver apanel_driver = { + .driver = { + .name = APANEL, + }, + .attach_adapter = &apanel_attach_adapter, + .detach_client = &apanel_detach_client, + .shutdown = &apanel_shutdown, +}; + +static struct apanel apanel = { + .client = { + .driver = &apanel_driver, + .name = APANEL, + }, + .keymap = { + [0] = KEY_MAIL, + [1] = KEY_WWW, + [2] = KEY_PROG2, + [3] = KEY_PROG1, + + [8] = KEY_FORWARD, + [9] = KEY_REWIND, + [10] = KEY_STOPCD, + [11] = KEY_PLAYPAUSE, + + }, + .mail_led = { + .name = "mail:blue", + .brightness_set = mail_led_set, + }, +}; + +/* NB: Only one panel on the i2c. */ +static int apanel_probe(struct i2c_adapter *bus, int address, int kind) +{ + struct apanel *ap; + struct input_polled_dev *ipdev; + struct input_dev *idev; + u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8; + int i, err = -ENOMEM; + + dev_dbg(&bus->dev, APANEL ": probe adapter %p addr %d kind %d\n", + bus, address, kind); + + ap = &apanel; + + ipdev = input_allocate_polled_device(); + if (!ipdev) + goto out1; + + ap->ipdev = ipdev; + ap->client.adapter = bus; + ap->client.addr = address; + + i2c_set_clientdata(&ap->client, ap); + + err = i2c_attach_client(&ap->client); + if (err) + goto out2; + + err = i2c_smbus_write_word_data(&ap->client, cmd, 0); + if (err) { + dev_warn(&ap->client.dev, APANEL ": smbus write error %d\n", + err); + goto out3; + } + + ipdev->poll = apanel_poll; + ipdev->poll_interval = POLL_INTERVAL_DEFAULT; + ipdev->private = ap; + + idev = ipdev->input; + idev->name = APANEL_NAME " buttons"; + idev->phys = "apanel/input0"; + idev->id.bustype = BUS_HOST; + idev->dev.parent = &ap->client.dev; + + set_bit(EV_KEY, idev->evbit); + + idev->keycode = ap->keymap; + idev->keycodesize = sizeof(ap->keymap[0]); + idev->keycodemax = (device_chip[APANEL_DEV_CDBTN] != CHIP_NONE) ? 12 : 4; + + for (i = 0; i < idev->keycodemax; i++) + if (ap->keymap[i]) + set_bit(ap->keymap[i], idev->keybit); + + err = input_register_polled_device(ipdev); + if (err) + goto out3; + + INIT_WORK(&ap->led_work, led_update); + if (device_chip[APANEL_DEV_LED] != CHIP_NONE) { + err = led_classdev_register(&ap->client.dev, &ap->mail_led); + if (err) + goto out4; + } + + return 0; +out4: + input_unregister_polled_device(ipdev); +out3: + i2c_detach_client(&ap->client); +out2: + input_free_polled_device(ipdev); +out1: + return err; +} + +/* Scan the system ROM for the signature "FJKEYINF" */ +static __init const void __iomem *bios_signature(const void __iomem *bios) +{ + ssize_t offset; + const unsigned char signature[] = "FJKEYINF"; + + for (offset = 0; offset < 0x10000; offset += 0x10) { + if (check_signature(bios + offset, signature, + sizeof(signature)-1)) + return bios + offset; + } + pr_notice(APANEL ": Fujitsu BIOS signature '%s' not found...\n", + signature); + return NULL; +} + +static int __init apanel_init(void) +{ + void __iomem *bios; + const void __iomem *p; + u8 devno; + int found = 0; + + bios = ioremap(0xF0000, 0x10000); /* Can't fail */ + + p = bios_signature(bios); + if (!p) { + iounmap(bios); + return -ENODEV; + } + + /* just use the first address */ + p += 8; + normal_i2c[0] = readb(p+3) >> 1; + + for ( ; (devno = readb(p)) & 0x7f; p += 4) { + unsigned char method, slave, chip; + + method = readb(p + 1); + chip = readb(p + 2); + slave = readb(p + 3) >> 1; + + if (slave != normal_i2c[0]) { + pr_notice(APANEL ": only one SMBus slave " + "address supported, skiping device...\n"); + continue; + } + + /* translate alternative device numbers */ + switch (devno) { + case 6: + devno = APANEL_DEV_APPBTN; + break; + case 7: + devno = APANEL_DEV_LED; + break; + } + + if (devno >= APANEL_DEV_MAX) + pr_notice(APANEL ": unknown device %u found\n", devno); + else if (device_chip[devno] != CHIP_NONE) + pr_warning(APANEL ": duplicate entry for devno %u\n", devno); + + else if (method != 1 && method != 2 && method != 4) { + pr_notice(APANEL ": unknown method %u for devno %u\n", + method, devno); + } else { + device_chip[devno] = (enum apanel_chip) chip; + ++found; + } + } + iounmap(bios); + + if (found == 0) { + pr_info(APANEL ": no input devices reported by BIOS\n"); + return -EIO; + } + + return i2c_add_driver(&apanel_driver); +} +module_init(apanel_init); + +static void __exit apanel_cleanup(void) +{ + i2c_del_driver(&apanel_driver); +} +module_exit(apanel_cleanup); + +MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); +MODULE_DESCRIPTION(APANEL_NAME " driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(APANEL_VERSION); + +MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifeBook*:pvr*:rvnFUJITSU:*"); +MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifebook*:pvr*:rvnFUJITSU:*"); diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c index 3a79374..f3b86c2 100644 --- a/drivers/input/misc/ati_remote.c +++ b/drivers/input/misc/ati_remote.c @@ -90,7 +90,6 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/usb/input.h> #include <linux/wait.h> #include <linux/jiffies.h> diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c index 4e3ad65..1b87191 100644 --- a/drivers/input/misc/atlas_btns.c +++ b/drivers/input/misc/atlas_btns.c @@ -29,9 +29,10 @@ #include <asm/uaccess.h> #include <acpi/acpi_drivers.h> -#define ACPI_ATLAS_NAME "Atlas ACPI" -#define ACPI_ATLAS_CLASS "Atlas" +#define ACPI_ATLAS_NAME "Atlas ACPI" +#define ACPI_ATLAS_CLASS "Atlas" +static unsigned short atlas_keymap[16]; static struct input_dev *input_dev; /* button handling code */ @@ -50,12 +51,15 @@ static acpi_status acpi_atlas_button_handler(u32 function, void *handler_context, void *region_context) { acpi_status status; - int keycode; if (function == ACPI_WRITE) { - keycode = KEY_F1 + (address & 0x0F); - input_report_key(input_dev, keycode, !(address & 0x10)); + int code = address & 0x0f; + int key_down = !(address & 0x10); + + input_event(input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(input_dev, atlas_keymap[code], key_down); input_sync(input_dev); + status = 0; } else { printk(KERN_WARNING "atlas: shrugged on unexpected function" @@ -70,6 +74,7 @@ static acpi_status acpi_atlas_button_handler(u32 function, static int atlas_acpi_button_add(struct acpi_device *device) { acpi_status status; + int i; int err; input_dev = input_allocate_device(); @@ -81,17 +86,19 @@ static int atlas_acpi_button_add(struct acpi_device *device) input_dev->name = "Atlas ACPI button driver"; input_dev->phys = "ASIM0000/atlas/input0"; input_dev->id.bustype = BUS_HOST; - input_dev->evbit[BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY); - - set_bit(KEY_F1, input_dev->keybit); - set_bit(KEY_F2, input_dev->keybit); - set_bit(KEY_F3, input_dev->keybit); - set_bit(KEY_F4, input_dev->keybit); - set_bit(KEY_F5, input_dev->keybit); - set_bit(KEY_F6, input_dev->keybit); - set_bit(KEY_F7, input_dev->keybit); - set_bit(KEY_F8, input_dev->keybit); - set_bit(KEY_F9, input_dev->keybit); + input_dev->keycode = atlas_keymap; + input_dev->keycodesize = sizeof(unsigned short); + input_dev->keycodemax = ARRAY_SIZE(atlas_keymap); + + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + __set_bit(EV_KEY, input_dev->evbit); + for (i = 0; i < ARRAY_SIZE(atlas_keymap); i++) { + if (i < 9) { + atlas_keymap[i] = KEY_F1 + i; + __set_bit(KEY_F1 + i, input_dev->keybit); + } else + atlas_keymap[i] = KEY_RESERVED; + } err = input_register_device(input_dev); if (err) { diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c index 1aef97e..4833b1a 100644 --- a/drivers/input/misc/cobalt_btns.c +++ b/drivers/input/misc/cobalt_btns.c @@ -27,55 +27,48 @@ #define BUTTONS_COUNT_THRESHOLD 3 #define BUTTONS_STATUS_MASK 0xfe000000 +static const unsigned short cobalt_map[] = { + KEY_RESERVED, + KEY_RESTART, + KEY_LEFT, + KEY_UP, + KEY_DOWN, + KEY_RIGHT, + KEY_ENTER, + KEY_SELECT +}; + struct buttons_dev { struct input_polled_dev *poll_dev; + unsigned short keymap[ARRAY_SIZE(cobalt_map)]; + int count[ARRAY_SIZE(cobalt_map)]; void __iomem *reg; }; -struct buttons_map { - uint32_t mask; - int keycode; - int count; -}; - -static struct buttons_map buttons_map[] = { - { 0x02000000, KEY_RESTART, }, - { 0x04000000, KEY_LEFT, }, - { 0x08000000, KEY_UP, }, - { 0x10000000, KEY_DOWN, }, - { 0x20000000, KEY_RIGHT, }, - { 0x40000000, KEY_ENTER, }, - { 0x80000000, KEY_SELECT, }, -}; - static void handle_buttons(struct input_polled_dev *dev) { - struct buttons_map *button = buttons_map; struct buttons_dev *bdev = dev->private; struct input_dev *input = dev->input; uint32_t status; int i; - status = readl(bdev->reg); - status = ~status & BUTTONS_STATUS_MASK; + status = ~readl(bdev->reg) >> 24; - for (i = 0; i < ARRAY_SIZE(buttons_map); i++) { - if (status & button->mask) { - button->count++; + for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) { + if (status & (1UL << i)) { + if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) { + input_event(input, EV_MSC, MSC_SCAN, i); + input_report_key(input, bdev->keymap[i], 1); + input_sync(input); + } } else { - if (button->count >= BUTTONS_COUNT_THRESHOLD) { - input_report_key(input, button->keycode, 0); + if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) { + input_event(input, EV_MSC, MSC_SCAN, i); + input_report_key(input, bdev->keymap[i], 0); input_sync(input); } - button->count = 0; - } - - if (button->count == BUTTONS_COUNT_THRESHOLD) { - input_report_key(input, button->keycode, 1); - input_sync(input); + bdev->count[i] = 0; } - - button++; } } @@ -94,6 +87,8 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev) goto err_free_mem; } + memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap)); + poll_dev->private = bdev; poll_dev->poll = handle_buttons; poll_dev->poll_interval = BUTTONS_POLL_INTERVAL; @@ -104,11 +99,15 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev) input->id.bustype = BUS_HOST; input->cdev.dev = &pdev->dev; - input->evbit[0] = BIT_MASK(EV_KEY); - for (i = 0; i < ARRAY_SIZE(buttons_map); i++) { - set_bit(buttons_map[i].keycode, input->keybit); - buttons_map[i].count = 0; - } + input->keycode = pdev->keymap; + input->keycodemax = ARRAY_SIZE(pdev->keymap); + input->keycodesize = sizeof(unsigned short); + + input_set_capability(input, EV_MSC, MSC_SCAN); + __set_bit(EV_KEY, input->evbit); + for (i = 0; i < ARRAY_SIZE(buttons_map); i++) + __set_bit(input->keycode[i], input->keybit); + __clear_bit(KEY_RESERVED, input->keybit); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c index fd74347..952938a 100644 --- a/drivers/input/misc/keyspan_remote.c +++ b/drivers/input/misc/keyspan_remote.c @@ -16,7 +16,6 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/usb/input.h> #define DRIVER_VERSION "v0.1" @@ -46,53 +45,12 @@ MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); #define RECV_SIZE 8 /* The UIA-11 type have a 8 byte limit. */ -/* table of devices that work with this driver */ -static struct usb_device_id keyspan_table[] = { - { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) }, - { } /* Terminating entry */ -}; - -/* Structure to store all the real stuff that a remote sends to us. */ -struct keyspan_message { - u16 system; - u8 button; - u8 toggle; -}; - -/* Structure used for all the bit testing magic needed to be done. */ -struct bit_tester { - u32 tester; - int len; - int pos; - int bits_left; - u8 buffer[32]; -}; - -/* Structure to hold all of our driver specific stuff */ -struct usb_keyspan { - char name[128]; - char phys[64]; - struct usb_device* udev; - struct input_dev *input; - struct usb_interface* interface; - struct usb_endpoint_descriptor* in_endpoint; - struct urb* irq_urb; - int open; - dma_addr_t in_dma; - unsigned char* in_buffer; - - /* variables used to parse messages from remote. */ - struct bit_tester data; - int stage; - int toggle; -}; - /* * Table that maps the 31 possible keycodes to input keys. * Currently there are 15 and 17 button models so RESERVED codes * are blank areas in the mapping. */ -static const int keyspan_key_table[] = { +static const unsigned short keyspan_key_table[] = { KEY_RESERVED, /* 0 is just a place holder. */ KEY_RESERVED, KEY_STOP, @@ -127,6 +85,48 @@ static const int keyspan_key_table[] = { KEY_MENU }; +/* table of devices that work with this driver */ +static struct usb_device_id keyspan_table[] = { + { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) }, + { } /* Terminating entry */ +}; + +/* Structure to store all the real stuff that a remote sends to us. */ +struct keyspan_message { + u16 system; + u8 button; + u8 toggle; +}; + +/* Structure used for all the bit testing magic needed to be done. */ +struct bit_tester { + u32 tester; + int len; + int pos; + int bits_left; + u8 buffer[32]; +}; + +/* Structure to hold all of our driver specific stuff */ +struct usb_keyspan { + char name[128]; + char phys[64]; + unsigned short keymap[ARRAY_SIZE(keyspan_key_table)]; + struct usb_device *udev; + struct input_dev *input; + struct usb_interface *interface; + struct usb_endpoint_descriptor *in_endpoint; + struct urb* irq_urb; + int open; + dma_addr_t in_dma; + unsigned char *in_buffer; + + /* variables used to parse messages from remote. */ + struct bit_tester data; + int stage; + int toggle; +}; + static struct usb_driver keyspan_driver; /* @@ -173,6 +173,15 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) return 0; } +static void keyspan_report_button(struct usb_keyspan *remote, int button, int press) +{ + struct input_dev *input = remote->input; + + input_event(input, EV_MSC, MSC_SCAN, button); + input_report_key(input, remote->keymap[button], press); + input_sync(input); +} + /* * Routine that handles all the logic needed to parse out the message from the remote. */ @@ -311,9 +320,8 @@ static void keyspan_check_data(struct usb_keyspan *remote) __FUNCTION__, message.system, message.button, message.toggle); if (message.toggle != remote->toggle) { - input_report_key(remote->input, keyspan_key_table[message.button], 1); - input_report_key(remote->input, keyspan_key_table[message.button], 0); - input_sync(remote->input); + keyspan_report_button(remote, message.button, 1); + keyspan_report_button(remote, message.button, 0); remote->toggle = message.toggle; } @@ -491,16 +499,21 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic usb_make_path(udev, remote->phys, sizeof(remote->phys)); strlcat(remote->phys, "/input0", sizeof(remote->phys)); + memcpy(remote->keymap, keyspan_key_table, sizeof(remote->keymap)); input_dev->name = remote->name; input_dev->phys = remote->phys; usb_to_input_id(udev, &input_dev->id); input_dev->dev.parent = &interface->dev; + input_dev->keycode = remote->keymap; + input_dev->keycodesize = sizeof(unsigned short); + input_dev->keycodemax = ARRAY_SIZE(remote->keymap); - input_dev->evbit[0] = BIT_MASK(EV_KEY); /* We will only report KEY events. */ + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + __set_bit(EV_KEY, input_dev->evbit); for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++) - if (keyspan_key_table[i] != KEY_RESERVED) - set_bit(keyspan_key_table[i], input_dev->keybit); + __set_bit(keyspan_key_table[i], input_dev->keybit); + __clear_bit(KEY_RESERVED, input_dev->keybit); input_set_drvdata(input_dev, remote); @@ -508,12 +521,14 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic input_dev->close = keyspan_close; /* - * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open() + * Initialize the URB to access the device. + * The urb gets sent to the device in keyspan_open() */ usb_fill_int_urb(remote->irq_urb, - remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress), + remote->udev, + usb_rcvintpipe(remote->udev, endpoint->bEndpointAddress), remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote, - remote->in_endpoint->bInterval); + endpoint->bInterval); remote->irq_urb->transfer_dma = remote->in_dma; remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |