From 8608471262ddf4b8ed4120d7211251e8b8dcbda9 Mon Sep 17 00:00:00 2001 From: Hans-Christian Egtvedt Date: Sun, 29 May 2005 02:27:45 -0500 Subject: Input: Add driver for ITM Touch USB touchscreens. From: Hans-Christian Egtvedt Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/usb/input/Kconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/usb/input/Kconfig') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index d28e7eab6f98..fcae574f3106 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -190,6 +190,18 @@ config USB_MTOUCH To compile this driver as a module, choose M here: the module will be called mtouchusb. +config USB_ITMTOUCH + tristate "ITM Touch USB Touchscreen Driver" + depends on USB && INPUT + ---help--- + Say Y here if you want to use a ITM Touch USB + Touchscreen controller. + + This touchscreen is used in LG 1510SF monitors. + + To compile this driver as a module, choose M here: the + module will be called itmtouch. + config USB_EGALAX tristate "eGalax TouchKit USB Touchscreen Driver" depends on USB && INPUT -- cgit v1.2.3 From 53880546979605dae20ee0404a0e998e188fe7ad Mon Sep 17 00:00:00 2001 From: Stephane VOLTZ Date: Mon, 6 Jun 2005 02:22:37 -0500 Subject: Input: add driver for Acecad Flair USB tablets Signed-off-by: Dmitry Torokhov --- drivers/usb/Makefile | 1 + drivers/usb/input/Kconfig | 12 ++ drivers/usb/input/Makefile | 1 + drivers/usb/input/acecad.c | 285 +++++++++++++++++++++++++++++++++++++++++++ drivers/usb/input/hid-core.c | 7 ++ 5 files changed, 306 insertions(+) create mode 100644 drivers/usb/input/acecad.c (limited to 'drivers/usb/input/Kconfig') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index a61d4433a989..a708a1dbb530 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_MOUSE) += input/ obj-$(CONFIG_USB_MTOUCH) += input/ obj-$(CONFIG_USB_POWERMATE) += input/ obj-$(CONFIG_USB_WACOM) += input/ +obj-$(CONFIG_USB_ACECAD) += input/ obj-$(CONFIG_USB_XPAD) += input/ obj-$(CONFIG_USB_DABUSB) += media/ diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index fcae574f3106..fd59f6bdd67f 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -151,6 +151,18 @@ config USB_WACOM To compile this driver as a module, choose M here: the module will be called wacom. +config USB_ACECAD + tristate "Acecad Flair tablet support" + depends on USB && INPUT + help + Say Y here if you want to use the USB version of the Acecad Flair + tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + To compile this driver as a module, choose M here: the + module will be called acecad. + config USB_KBTAB tristate "KB Gear JamStudio tablet support" depends on USB && INPUT diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index f0fd02e00d32..831b2b0f1f05 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -37,4 +37,5 @@ obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o obj-$(CONFIG_USB_EGALAX) += touchkitusb.o obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_WACOM) += wacom.o +obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_XPAD) += xpad.o diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c new file mode 100644 index 000000000000..ebcf7c955800 --- /dev/null +++ b/drivers/usb/input/acecad.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2001-2005 Edouard TISSERANT + * Copyright (c) 2004-2005 Stephane VOLTZ + * + * USB Acecad "Acecad Flair" tablet support + * + * Changelog: + * v3.2 - Added sysfs support + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +/* + * Version Information + */ +#define DRIVER_VERSION "v3.2" +#define DRIVER_DESC "USB Acecad Flair tablet driver" +#define DRIVER_LICENSE "GPL" +#define DRIVER_AUTHOR "Edouard TISSERANT " + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); + +#define USB_VENDOR_ID_ACECAD 0x0460 +#define USB_DEVICE_ID_FLAIR 0x0004 +#define USB_DEVICE_ID_302 0x0008 + +struct usb_acecad { + char name[128]; + char phys[64]; + struct usb_device *usbdev; + struct input_dev dev; + struct urb *irq; + + signed char *data; + dma_addr_t data_dma; +}; + +static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs) +{ + struct usb_acecad *acecad = urb->context; + unsigned char *data = acecad->data; + struct input_dev *dev = &acecad->dev; + int prox, status; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + goto resubmit; + } + + prox = (data[0] & 0x04) >> 2; + input_report_key(dev, BTN_TOOL_PEN, prox); + + if (prox) { + int x = data[1] | (data[2] << 8); + int y = data[3] | (data[4] << 8); + /*Pressure should compute the same way for flair and 302*/ + int pressure = data[5] | ((int)data[6] << 8); + int touch = data[0] & 0x01; + int stylus = (data[0] & 0x10) >> 4; + int stylus2 = (data[0] & 0x20) >> 5; + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + input_report_abs(dev, ABS_PRESSURE, pressure); + input_report_key(dev, BTN_TOUCH, touch); + input_report_key(dev, BTN_STYLUS, stylus); + input_report_key(dev, BTN_STYLUS2, stylus2); + } + + /* event termination */ + input_sync(dev); + +resubmit: + status = usb_submit_urb (urb, GFP_ATOMIC); + if (status) + err ("can't resubmit intr, %s-%s/input0, status %d", + acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status); +} + +static int usb_acecad_open(struct input_dev *dev) +{ + struct usb_acecad *acecad = dev->private; + + acecad->irq->dev = acecad->usbdev; + if (usb_submit_urb(acecad->irq, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void usb_acecad_close(struct input_dev *dev) +{ + struct usb_acecad *acecad = dev->private; + + usb_kill_urb(acecad->irq); +} + +static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *interface = intf->cur_altsetting; + struct usb_endpoint_descriptor *endpoint; + struct usb_acecad *acecad; + int pipe, maxp; + char path[64]; + + if (interface->desc.bNumEndpoints != 1) + return -ENODEV; + + endpoint = &interface->endpoint[0].desc; + + if (!(endpoint->bEndpointAddress & 0x80)) + return -ENODEV; + + if ((endpoint->bmAttributes & 3) != 3) + return -ENODEV; + + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + acecad = kcalloc(1, sizeof(struct usb_acecad), GFP_KERNEL); + if (!acecad) + return -ENOMEM; + + acecad->data = usb_buffer_alloc(dev, 8, SLAB_KERNEL, &acecad->data_dma); + if (!acecad->data) + goto fail1; + + acecad->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!acecad->irq) + goto fail2; + + if (dev->manufacturer) + strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name)); + + if (dev->product) { + if (dev->manufacturer) + strlcat(acecad->name, " ", sizeof(acecad->name)); + strlcat(acecad->name, dev->product, sizeof(acecad->name)); + } + + usb_make_path(dev, path, sizeof(path)); + snprintf(acecad->phys, sizeof(acecad->phys), "%s/input0", path); + + acecad->usbdev = dev; + + acecad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + acecad->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + acecad->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + acecad->dev.keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2); + + switch (id->driver_info) { + case 0: + acecad->dev.absmax[ABS_X] = 5000; + acecad->dev.absmax[ABS_Y] = 3750; + acecad->dev.absmax[ABS_PRESSURE] = 512; + if (!strlen(acecad->name)) + snprintf(acecad->name, sizeof(acecad->name), + "USB Acecad Flair Tablet %04x:%04x", + dev->descriptor.idVendor, dev->descriptor.idProduct); + break; + case 1: + acecad->dev.absmax[ABS_X] = 3000; + acecad->dev.absmax[ABS_Y] = 2250; + acecad->dev.absmax[ABS_PRESSURE] = 1024; + if (!strlen(acecad->name)) + snprintf(acecad->name, sizeof(acecad->name), + "USB Acecad 302 Tablet %04x:%04x", + dev->descriptor.idVendor, dev->descriptor.idProduct); + break; + } + + acecad->dev.absfuzz[ABS_X] = 4; + acecad->dev.absfuzz[ABS_Y] = 4; + + acecad->dev.private = acecad; + acecad->dev.open = usb_acecad_open; + acecad->dev.close = usb_acecad_close; + + acecad->dev.name = acecad->name; + acecad->dev.phys = acecad->phys; + acecad->dev.id.bustype = BUS_USB; + acecad->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor); + acecad->dev.id.product = le16_to_cpu(dev->descriptor.idProduct); + acecad->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice); + acecad->dev.dev = &intf->dev; + + usb_fill_int_urb(acecad->irq, dev, pipe, + acecad->data, maxp > 8 ? 8 : maxp, + usb_acecad_irq, acecad, endpoint->bInterval); + acecad->irq->transfer_dma = acecad->data_dma; + acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + input_register_device(&acecad->dev); + + printk(KERN_INFO "input: %s with packet size %d on %s\n", + acecad->name, maxp, path); + + usb_set_intfdata(intf, acecad); + + return 0; + + fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma); + fail1: kfree(acecad); + return -ENOMEM; +} + +static void usb_acecad_disconnect(struct usb_interface *intf) +{ + struct usb_acecad *acecad = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + if (acecad) { + usb_kill_urb(acecad->irq); + input_unregister_device(&acecad->dev); + usb_free_urb(acecad->irq); + usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma); + kfree(acecad); + } +} + +static struct usb_device_id usb_acecad_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 }, + { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302), .driver_info = 1 }, + { } +}; + +MODULE_DEVICE_TABLE(usb, usb_acecad_id_table); + +static struct usb_driver usb_acecad_driver = { + .owner = THIS_MODULE, + .name = "usb_acecad", + .probe = usb_acecad_probe, + .disconnect = usb_acecad_disconnect, + .id_table = usb_acecad_id_table, +}; + +static int __init usb_acecad_init(void) +{ + int result = usb_register(&usb_acecad_driver); + if (result == 0) + info(DRIVER_VERSION ":" DRIVER_DESC); + return result; +} + +static void __exit usb_acecad_exit(void) +{ + usb_deregister(&usb_acecad_driver); +} + +module_init(usb_acecad_init); +module_exit(usb_acecad_exit); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 96959ec590a3..d88e588ff178 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1321,6 +1321,10 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_WACOM_INTUOS3 0x00B0 #define USB_DEVICE_ID_WACOM_CINTIQ 0x003F +#define USB_VENDOR_ID_ACECAD 0x0460 +#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004 +#define USB_DEVICE_ID_ACECAD_302 0x0008 + #define USB_VENDOR_ID_KBGEAR 0x084e #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 @@ -1505,6 +1509,9 @@ static struct hid_blacklist { { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, -- cgit v1.2.3 From 99f83c9c9ac994c844ecf3e64e848c2f8dd7dfe0 Mon Sep 17 00:00:00 2001 From: Michael Downey Date: Mon, 27 Jun 2005 11:48:26 -0600 Subject: [PATCH] USB: add driver for Keyspan Digital Remote This driver is a basic keypress input driver for the Keyspan Digital Remote with part number UIA-11. Currently there is an older remote with part number UIA-10 which isn't supported by this driver. Support for the older UIA-10 could be added but a binary file is required to be download to the device, and I don't have that file. I also don't have a UIA-10 device so I wouldn't be able to test any of the changes. Signed-off-by: Michael Downey Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/Kconfig | 13 + drivers/usb/input/Makefile | 1 + drivers/usb/input/keyspan_remote.c | 633 +++++++++++++++++++++++++++++++++++++ 3 files changed, 647 insertions(+) create mode 100644 drivers/usb/input/keyspan_remote.c (limited to 'drivers/usb/input/Kconfig') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index fd59f6bdd67f..298e4a25e3d3 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -259,3 +259,16 @@ config USB_ATI_REMOTE To compile this driver as a module, choose M here: the module will be called ati_remote. +config USB_KEYSPAN_REMOTE + tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" + depends on USB && INPUT && EXPERIMENTAL + ---help--- + Say Y here if you want to use a Keyspan DMR USB remote control. + Currently only the UIA-11 type of receiver has been tested. The tag + on the receiver that connects to the USB port should have a P/N that + will tell you what type of DMR you have. The UIA-10 type is not + supported at this time. This driver maps all buttons to keypress + events. + + To compile this driver as a module, choose M here: the module will + be called keyspan_remote. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 831b2b0f1f05..f1547be632d4 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_USB_HID) += usbhid.o obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_KBTAB) += kbtab.o +obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c new file mode 100644 index 000000000000..67dc93685203 --- /dev/null +++ b/drivers/usb/input/keyspan_remote.c @@ -0,0 +1,633 @@ +/* + * keyspan_remote: USB driver for the Keyspan DMR + * + * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + * This driver has been put together with the support of Innosys, Inc. + * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "v0.1" +#define DRIVER_AUTHOR "Michael Downey " +#define DRIVER_DESC "Driver for the USB Keyspan remote control." +#define DRIVER_LICENSE "GPL" + +/* Parameters that can be passed to the driver. */ +static int debug; +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); + +/* Vendor and product ids */ +#define USB_KEYSPAN_VENDOR_ID 0x06CD +#define USB_KEYSPAN_PRODUCT_UIA11 0x0202 + +/* Defines for converting the data from the remote. */ +#define ZERO 0x18 +#define ZERO_MASK 0x1F /* 5 bits for a 0 */ +#define ONE 0x3C +#define ONE_MASK 0x3F /* 6 bits for a 1 */ +#define SYNC 0x3F80 +#define SYNC_MASK 0x3FFF /* 14 bits for a SYNC sequence */ +#define STOP 0x00 +#define STOP_MASK 0x1F /* 5 bits for the STOP sequence */ +#define GAP 0xFF + +#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 int keyspan_key_table[] = { + KEY_RESERVED, /* 0 is just a place holder. */ + KEY_RESERVED, + KEY_STOP, + KEY_PLAYCD, + KEY_RESERVED, + KEY_PREVIOUSSONG, + KEY_REWIND, + KEY_FORWARD, + KEY_NEXTSONG, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_PAUSE, + KEY_VOLUMEUP, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_VOLUMEDOWN, + KEY_RESERVED, + KEY_UP, + KEY_RESERVED, + KEY_MUTE, + KEY_LEFT, + KEY_ENTER, + KEY_RIGHT, + KEY_RESERVED, + KEY_RESERVED, + KEY_DOWN, + KEY_RESERVED, + KEY_KPASTERISK, + KEY_RESERVED, + KEY_MENU +}; + +static struct usb_driver keyspan_driver; + +/* + * Debug routine that prints out what we've received from the remote. + */ +static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/ +{ + char codes[4*RECV_SIZE]; + int i; + + for (i = 0; i < RECV_SIZE; i++) { + snprintf(codes+i*3, 4, "%02x ", dev->in_buffer[i]); + } + + dev_info(&dev->udev->dev, "%s\n", codes); +} + +/* + * Routine that manages the bit_tester structure. It makes sure that there are + * at least bits_needed bits loaded into the tester. + */ +static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) +{ + if (dev->data.bits_left >= bits_needed) + return(0); + + /* + * Somehow we've missed the last message. The message will be repeated + * though so it's not too big a deal + */ + if (dev->data.pos >= dev->data.len) { + dev_dbg(&dev->udev, "%s - Error ran out of data. pos: %d, len: %d\n", + __FUNCTION__, dev->data.pos, dev->data.len); + return(-1); + } + + /* Load as much as we can into the tester. */ + while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) && + (dev->data.pos < dev->data.len)) { + dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left); + dev->data.bits_left += 8; + } + + return(0); +} + +/* + * Routine that handles all the logic needed to parse out the message from the remote. + */ +static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs) +{ + int i; + int found = 0; + struct keyspan_message message; + + switch(remote->stage) { + case 0: + /* + * In stage 0 we want to find the start of a message. The remote sends a 0xFF as filler. + * So the first byte that isn't a FF should be the start of a new message. + */ + for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i); + + if (i < RECV_SIZE) { + memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE); + remote->data.len = RECV_SIZE; + remote->data.pos = 0; + remote->data.tester = 0; + remote->data.bits_left = 0; + remote->stage = 1; + } + break; + + case 1: + /* + * Stage 1 we should have 16 bytes and should be able to detect a + * SYNC. The SYNC is 14 bits, 7 0's and then 7 1's. + */ + memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE); + remote->data.len += RECV_SIZE; + + found = 0; + while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) { + for (i = 0; i < 8; ++i) { + if (keyspan_load_tester(remote, 14) != 0) { + remote->stage = 0; + return; + } + + if ((remote->data.tester & SYNC_MASK) == SYNC) { + remote->data.tester = remote->data.tester >> 14; + remote->data.bits_left -= 14; + found = 1; + break; + } else { + remote->data.tester = remote->data.tester >> 1; + --remote->data.bits_left; + } + } + } + + if (!found) { + remote->stage = 0; + remote->data.len = 0; + } else { + remote->stage = 2; + } + break; + + case 2: + /* + * Stage 2 we should have 24 bytes which will be enough for a full + * message. We need to parse out the system code, button code, + * toggle code, and stop. + */ + memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE); + remote->data.len += RECV_SIZE; + + message.system = 0; + for (i = 0; i < 9; i++) { + keyspan_load_tester(remote, 6); + + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.system = message.system << 1; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.system = (message.system << 1) + 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Unknown sequence found in system data.\n", __FUNCTION__); + remote->stage = 0; + return; + } + } + + message.button = 0; + for (i = 0; i < 5; i++) { + keyspan_load_tester(remote, 6); + + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.button = message.button << 1; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.button = (message.button << 1) + 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Unknown sequence found in button data.\n", __FUNCTION__); + remote->stage = 0; + return; + } + } + + keyspan_load_tester(remote, 6); + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.toggle = 0; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.toggle = 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Error in message, invalid toggle.\n", __FUNCTION__); + } + + keyspan_load_tester(remote, 5); + if ((remote->data.tester & STOP_MASK) == STOP) { + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else { + err("Bad message recieved, no stop bit found.\n"); + } + + dev_dbg(&remote->udev, + "%s found valid message: system: %d, button: %d, toggle: %d\n", + __FUNCTION__, message.system, message.button, message.toggle); + + if (message.toggle != remote->toggle) { + input_regs(&remote->input, regs); + 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); + remote->toggle = message.toggle; + } + + remote->stage = 0; + break; + } +} + +/* + * Routine for sending all the initialization messages to the remote. + */ +static int keyspan_setup(struct usb_device* dev) +{ + int retval = 0; + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x44, 0x40, 0x0, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x22, 0x40, 0x0, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__); + return(retval); +} + +/* + * Routine used to handle a new message that has come in. + */ +static void keyspan_irq_recv(struct urb *urb, struct pt_regs *regs) +{ + struct usb_keyspan *dev = urb->context; + int retval; + + /* Check our status in case we need to bail out early. */ + switch (urb->status) { + case 0: + break; + + /* Device went away so don't keep trying to read from it. */ + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + + default: + goto resubmit; + break; + } + + if (debug) + keyspan_print(dev); + + keyspan_check_data(dev, regs); + +resubmit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval); +} + +static int keyspan_open(struct input_dev *dev) +{ + struct usb_keyspan *remote = dev->private; + + if (remote->open++) + return 0; + + remote->irq_urb->dev = remote->udev; + if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) { + remote->open--; + return -EIO; + } + + return 0; +} + +static void keyspan_close(struct input_dev *dev) +{ + struct usb_keyspan *remote = dev->private; + + if (!--remote->open) + usb_kill_urb(remote->irq_urb); +} + +/* + * Routine that sets up the driver to handle a specific USB device detected on the bus. + */ +static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + int i; + int retval = -ENOMEM; + char path[64]; + char *buf; + struct usb_keyspan *remote = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface)); + + /* See if the offered device matches what we can accept */ + if ((udev->descriptor.idVendor != USB_KEYSPAN_VENDOR_ID) || + (udev->descriptor.idProduct != USB_KEYSPAN_PRODUCT_UIA11) ) + return -ENODEV; + + /* allocate memory for our device state and initialize it */ + remote = kmalloc(sizeof(*remote), GFP_KERNEL); + if (remote == NULL) { + err("Out of memory\n"); + goto error; + } + memset(remote, 0x00, sizeof(*remote)); + + remote->udev = udev; + remote->interface = interface; + remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */ + + /* set up the endpoint information */ + /* use only the first in interrupt endpoint */ + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!remote->in_endpoint && + (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + /* we found our interrupt in endpoint */ + remote->in_endpoint = endpoint; + + remote->in_buffer = usb_buffer_alloc(remote->udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma); + if (!remote->in_buffer) { + retval = -ENOMEM; + goto error; + } + } + } + + if (!remote->in_endpoint) { + err("Could not find interrupt input endpoint.\n"); + retval = -ENODEV; + goto error; + } + + remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!remote->irq_urb) { + err("Failed to allocate urb.\n"); + retval = -ENOMEM; + goto error; + } + + retval = keyspan_setup(remote->udev); + if (retval) { + err("Failed to setup device.\n"); + retval = -ENODEV; + goto error; + } + + /* + * Setup the input system with the bits we are going to be reporting + */ + remote->input.evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */ + for (i = 0; i < 32; ++i) { + if (keyspan_key_table[i] != KEY_RESERVED) { + set_bit(keyspan_key_table[i], remote->input.keybit); + } + } + + remote->input.private = remote; + remote->input.open = keyspan_open; + remote->input.close = keyspan_close; + + usb_make_path(remote->udev, path, 64); + sprintf(remote->phys, "%s/input0", path); + + remote->input.name = remote->name; + remote->input.phys = remote->phys; + remote->input.id.bustype = BUS_USB; + remote->input.id.vendor = le16_to_cpu(remote->udev->descriptor.idVendor); + remote->input.id.product = le16_to_cpu(remote->udev->descriptor.idProduct); + remote->input.id.version = le16_to_cpu(remote->udev->descriptor.bcdDevice); + + if (!(buf = kmalloc(63, GFP_KERNEL))) { + usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + kfree(remote); + return -ENOMEM; + } + + if (remote->udev->descriptor.iManufacturer && + usb_string(remote->udev, remote->udev->descriptor.iManufacturer, buf, 63) > 0) + strcat(remote->name, buf); + + if (remote->udev->descriptor.iProduct && + usb_string(remote->udev, remote->udev->descriptor.iProduct, buf, 63) > 0) + sprintf(remote->name, "%s %s", remote->name, buf); + + if (!strlen(remote->name)) + sprintf(remote->name, "USB Keyspan Remote %04x:%04x", + remote->input.id.vendor, remote->input.id.product); + + kfree(buf); + + /* + * 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->in_buffer, RECV_SIZE, keyspan_irq_recv, remote, + remote->in_endpoint->bInterval); + remote->irq_urb->transfer_dma = remote->in_dma; + remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* we can register the device now, as it is ready */ + input_register_device(&remote->input); + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, remote); + + /* let the user know what node this device is now attached to */ + info("connected: %s on %s", remote->name, path); + return 0; + +error: + /* + * In case of error we need to clean up any allocated buffers + */ + if (remote->irq_urb) + usb_free_urb(remote->irq_urb); + + if (remote->in_buffer) + usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + + if (remote) + kfree(remote); + + return retval; +} + +/* + * Routine called when a device is disconnected from the USB. + */ +static void keyspan_disconnect(struct usb_interface *interface) +{ + struct usb_keyspan *remote; + + /* prevent keyspan_open() from racing keyspan_disconnect() */ + lock_kernel(); + + remote = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + if (remote) { /* We have a valid driver structure so clean up everything we allocated. */ + input_unregister_device(&remote->input); + usb_kill_urb(remote->irq_urb); + usb_free_urb(remote->irq_urb); + usb_buffer_free(interface_to_usbdev(interface), RECV_SIZE, remote->in_buffer, remote->in_dma); + kfree(remote); + } + + unlock_kernel(); + + info("USB Keyspan now disconnected"); +} + +/* + * Standard driver set up sections + */ +static struct usb_driver keyspan_driver = +{ + .owner = THIS_MODULE, + .name = "keyspan_remote", + .probe = keyspan_probe, + .disconnect = keyspan_disconnect, + .id_table = keyspan_table +}; + +static int __init usb_keyspan_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&keyspan_driver); + if (result) + err("usb_register failed. Error number %d\n", result); + + return result; +} + +static void __exit usb_keyspan_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&keyspan_driver); +} + +module_init(usb_keyspan_init); +module_exit(usb_keyspan_exit); + +MODULE_DEVICE_TABLE(usb, keyspan_table); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); -- cgit v1.2.3