ChangeSet 1.1002.3.20, 2003/02/25 13:50:42-08:00, josh@joshisanerd.com [PATCH] USB: KB Gear USB Tablet Drivers Attached are drivers for the KB Gear JamStudio Tablet. There are two files, one is against 2.4.20, the other against 2.5.62. I'm hoping this isn't too late in the 2.4.21-pre stages to get included (or the 2.5, for that matter =). This driver Works For Me, on both 2.4.20 and 2.5.62. Anyway, as usual, comments, complaints, and patches are more than welcome. drivers/usb/input/Kconfig | 14 ++ drivers/usb/input/Makefile | 1 drivers/usb/input/hid-core.c | 5 drivers/usb/input/kbtab.c | 229 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 249 insertions(+) diff -Nru a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig --- a/drivers/usb/input/Kconfig Fri Feb 28 14:49:42 2003 +++ b/drivers/usb/input/Kconfig Fri Feb 28 14:49:42 2003 @@ -159,6 +159,20 @@ The module will be called wacom. If you want to compile it as a module, say M here and read . +config USB_KBTAB + tristate "KB Gear JamStudio tablet support" + depends on USB && INPUT + help + Say Y here if you want to use the USB version of the KB Gear + JamStudio tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called kbtab.o. If you want to compile it as a + module, say M here and read . + config USB_POWERMATE tristate "Griffin PowerMate and Contour Jog support" depends on USB && INPUT diff -Nru a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile --- a/drivers/usb/input/Makefile Fri Feb 28 14:49:42 2003 +++ b/drivers/usb/input/Makefile Fri Feb 28 14:49:42 2003 @@ -31,5 +31,6 @@ obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_WACOM) += wacom.o +obj-$(CONFIG_USB_KBTAB) += kbtab.o obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_XPAD) += xpad.o diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c --- a/drivers/usb/input/hid-core.c Fri Feb 28 14:49:42 2003 +++ b/drivers/usb/input/hid-core.c Fri Feb 28 14:49:42 2003 @@ -1304,6 +1304,10 @@ #define USB_DEVICE_ID_WACOM_PL 0x0030 #define USB_DEVICE_ID_WACOM_INTUOS2 0x0040 +#define USB_VENDOR_ID_KBGEAR 0x084e +#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 + + #define USB_VENDOR_ID_AIPTEK 0x08ca #define USB_DEVICE_ID_AIPTEK_6000 0x0020 @@ -1355,6 +1359,7 @@ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, diff -Nru a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/input/kbtab.c Fri Feb 28 14:49:42 2003 @@ -0,0 +1,229 @@ +#include +#include +#include +#include +#include +#include + +/* + * Version Information + * v0.0.1 - Original, extremely basic version, 2.4.xx only + * v0.0.2 - Updated, works with 2.5.62 and 2.4.20; + * - added pressure-threshold modules param code from + * Alex Perry + */ + +#define DRIVER_VERSION "v0.0.2" +#define DRIVER_AUTHOR "Josh Myer " +#define DRIVER_DESC "USB KB Gear JamStudio Tablet driver" +#define DRIVER_LICENSE "GPL" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); + +#define USB_VENDOR_ID_KBGEAR 0x084e + +static int kb_pressure_click = 0x10; +MODULE_PARM (kb_pressure_click,"i"); +MODULE_PARM_DESC(kb_pressure_click, + "pressure threshold for clicks"); + +struct kbtab { + signed char *data; + dma_addr_t data_dma; + struct input_dev dev; + struct usb_device *usbdev; + struct urb *irq; + int open; + int x, y; + int button; + int pressure; + __u32 serial[2]; + char phys[32]; +}; + +static void kbtab_irq(struct urb *urb, struct pt_regs *regs) +{ + struct kbtab *kbtab = urb->context; + unsigned char *data = kbtab->data; + struct input_dev *dev = &kbtab->dev; + int retval; + + 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 exit; + } + + kbtab->x = (data[2] << 8) + data[1]; + kbtab->y = (data[4] << 8) + data[3]; + + kbtab->pressure = (data[5]); + + input_report_key(dev, BTN_TOOL_PEN, 1); + + input_report_abs(dev, ABS_X, kbtab->x); + input_report_abs(dev, ABS_Y, kbtab->y); + /*input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);*/ + + /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ + input_report_key(dev, BTN_RIGHT, data[0] & 0x02); + + input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0); + + input_sync(dev); + + exit: + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result %d", + __FUNCTION__, retval); +} + +struct usb_device_id kbtab_ids[] = { + { USB_DEVICE(USB_VENDOR_ID_KBGEAR, 0x1001), driver_info : 0 }, + { } +}; + +MODULE_DEVICE_TABLE(usb, kbtab_ids); + +static int kbtab_open(struct input_dev *dev) +{ + struct kbtab *kbtab = dev->private; + + if (kbtab->open++) + return 0; + + kbtab->irq->dev = kbtab->usbdev; + if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void kbtab_close(struct input_dev *dev) +{ + struct kbtab *kbtab = dev->private; + + if (!--kbtab->open) + usb_unlink_urb(kbtab->irq); +} + +static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_endpoint_descriptor *endpoint; + struct kbtab *kbtab; + char path[64]; + + if (!(kbtab = kmalloc(sizeof(struct kbtab), GFP_KERNEL))) + return -ENOMEM; + memset(kbtab, 0, sizeof(struct kbtab)); + + kbtab->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kbtab->data_dma); + if (!kbtab->data) { + kfree(kbtab); + return -ENOMEM; + } + + kbtab->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!kbtab->irq) { + usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma); + kfree(kbtab); + return -ENOMEM; + } + + kbtab->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC); + kbtab->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + + kbtab->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + + kbtab->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH); + + kbtab->dev.mscbit[0] |= BIT(MSC_SERIAL); + + kbtab->dev.absmax[ABS_X] = 0x2000; + kbtab->dev.absmax[ABS_Y] = 0x1750; + kbtab->dev.absmax[ABS_PRESSURE] = 0xff; + + kbtab->dev.absfuzz[ABS_X] = 4; + kbtab->dev.absfuzz[ABS_Y] = 4; + + kbtab->dev.private = kbtab; + kbtab->dev.open = kbtab_open; + kbtab->dev.close = kbtab_close; + + usb_make_path(dev, path, 64); + sprintf(kbtab->phys, "%s/input0", path); + + kbtab->dev.name = "KB Gear Tablet"; + kbtab->dev.phys = kbtab->phys; + kbtab->dev.id.bustype = BUS_USB; + kbtab->dev.id.vendor = dev->descriptor.idVendor; + kbtab->dev.id.product = dev->descriptor.idProduct; + kbtab->dev.id.version = dev->descriptor.bcdDevice; + kbtab->usbdev = dev; + + endpoint = &intf->altsetting[0].endpoint[0].desc; + + usb_fill_int_urb(kbtab->irq, dev, + usb_rcvintpipe(dev, endpoint->bEndpointAddress), + kbtab->data, 8, + kbtab_irq, kbtab, endpoint->bInterval); + kbtab->irq->transfer_dma = kbtab->data_dma; + kbtab->irq->transfer_flags |= URB_NO_DMA_MAP; + + input_register_device(&kbtab->dev); + + printk(KERN_INFO "input: KB Gear Tablet on %s\n", path); + + usb_set_intfdata(intf, kbtab); + + return 0; +} + +static void kbtab_disconnect(struct usb_interface *intf) +{ + struct kbtab *kbtab = usb_get_intfdata (intf); + + usb_set_intfdata(intf, NULL); + if (kbtab) { + usb_unlink_urb(kbtab->irq); + input_unregister_device(&kbtab->dev); + usb_free_urb(kbtab->irq); + usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma); + kfree(kbtab); + } +} + +static struct usb_driver kbtab_driver = { + .name = "kbtab", + .probe = kbtab_probe, + .disconnect = kbtab_disconnect, + .id_table = kbtab_ids, +}; + +static int __init kbtab_init(void) +{ + usb_register(&kbtab_driver); + info(DRIVER_VERSION ":" DRIVER_DESC); + return 0; +} + +static void __exit kbtab_exit(void) +{ + usb_deregister(&kbtab_driver); +} + +module_init(kbtab_init); +module_exit(kbtab_exit);