11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 4ae0dadcf0f912cbab2ac84caa437454620bf71b2David Brownell#include <linux/usb/input.h> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v0.0.1 - Original, extremely basic version, 2.4.xx only 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v0.0.2 - Updated, works with 2.5.62 and 2.4.20; 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - added pressure-threshold modules param code from 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alex Perry <alex.perry@ieee.org> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "v0.0.2" 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Josh Myer <josh@joshisanerd.com>" 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB KB Gear JamStudio Tablet driver" 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_LICENSE "GPL" 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR(DRIVER_AUTHOR); 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE(DRIVER_LICENSE); 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_VENDOR_ID_KBGEAR 0x084e 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int kb_pressure_click = 0x10; 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(kb_pressure_click, int, 0); 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks"); 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct kbtab { 314ee1fc8e554593061a71d6af7c94f31764b87606Dmitry Torokhov unsigned char *data; 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t data_dma; 33c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct input_dev *dev; 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *usbdev; 35ed2b2f2db2d52098bdda3877367d59984febdd9fGreg Kroah-Hartman struct usb_interface *intf; 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *irq; 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char phys[32]; 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 407d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void kbtab_irq(struct urb *urb) 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbtab *kbtab = urb->context; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = kbtab->data; 44c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct input_dev *dev = kbtab->dev; 45f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov int pressure; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (urb->status) { 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this urb is terminated, clean up */ 56ed2b2f2db2d52098bdda3877367d59984febdd9fGreg Kroah-Hartman dev_dbg(&kbtab->intf->dev, 57ed2b2f2db2d52098bdda3877367d59984febdd9fGreg Kroah-Hartman "%s - urb shutting down with status: %d\n", 586d0f7dcba6ea0d04fb0d1374188c2479abf7f951Greg Kroah-Hartman __func__, urb->status); 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 61ed2b2f2db2d52098bdda3877367d59984febdd9fGreg Kroah-Hartman dev_dbg(&kbtab->intf->dev, 62ed2b2f2db2d52098bdda3877367d59984febdd9fGreg Kroah-Hartman "%s - nonzero urb status received: %d\n", 636d0f7dcba6ea0d04fb0d1374188c2479abf7f951Greg Kroah-Hartman __func__, urb->status); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_TOOL_PEN, 1); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_report_abs(dev, ABS_X, get_unaligned_le16(&data[1])); 71f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_report_abs(dev, ABS_Y, get_unaligned_le16(&data[3])); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_RIGHT, data[0] & 0x02); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov pressure = data[5]; 77f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov if (kb_pressure_click == -1) 78f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_report_abs(dev, ABS_PRESSURE, pressure); 79f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov else 80f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_report_key(dev, BTN_LEFT, pressure > kb_pressure_click ? 1 : 0); 8105f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exit: 85f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov retval = usb_submit_urb(urb, GFP_ATOMIC); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 87ed2b2f2db2d52098bdda3877367d59984febdd9fGreg Kroah-Hartman dev_err(&kbtab->intf->dev, 88202712c2322a1b87f3359046f5ebe92e0384ff6dGreg Kroah-Hartman "%s - usb_submit_urb failed with result %d\n", 89202712c2322a1b87f3359046f5ebe92e0384ff6dGreg Kroah-Hartman __func__, retval); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id kbtab_ids[] = { 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(USB_VENDOR_ID_KBGEAR, 0x1001), .driver_info = 0 }, 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(usb, kbtab_ids); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int kbtab_open(struct input_dev *dev) 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1017791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov struct kbtab *kbtab = input_get_drvdata(dev); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq->dev = kbtab->usbdev; 10465cde54b8b0299d7e46b8705338b01d1e44a5eb0Dmitry Torokhov if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void kbtab_close(struct input_dev *dev) 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1127791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov struct kbtab *kbtab = input_get_drvdata(dev); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11465cde54b8b0299d7e46b8705338b01d1e44a5eb0Dmitry Torokhov usb_kill_urb(kbtab->irq); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id) 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *dev = interface_to_usbdev(intf); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_endpoint_descriptor *endpoint; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbtab *kbtab; 122c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct input_dev *input_dev; 1235014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov int error = -ENOMEM; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 125c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL); 126c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev = input_allocate_device(); 127c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!kbtab || !input_dev) 128c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail1; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 130997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack kbtab->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &kbtab->data_dma); 131c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!kbtab->data) 132c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail1; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq = usb_alloc_urb(0, GFP_KERNEL); 135c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!kbtab->irq) 136c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail2; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 138c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbtab->usbdev = dev; 139ed2b2f2db2d52098bdda3877367d59984febdd9fGreg Kroah-Hartman kbtab->intf = intf; 140c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbtab->dev = input_dev; 14105f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 142c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys)); 143c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov strlcat(kbtab->phys, "/input0", sizeof(kbtab->phys)); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 145c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->name = "KB Gear Tablet"; 146c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->phys = kbtab->phys; 147c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov usb_to_input_id(dev, &input_dev->id); 148c0f82d570c84f2592367e350a92ebd71e72ba68aDmitry Torokhov input_dev->dev.parent = &intf->dev; 1497791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov 1507791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov input_set_drvdata(input_dev, kbtab); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 152c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->open = kbtab_open; 153c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->close = kbtab_close; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 155f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 156f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_dev->keybit[BIT_WORD(BTN_LEFT)] |= 157f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); 158f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_dev->keybit[BIT_WORD(BTN_DIGI)] |= 159f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOUCH); 160c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0); 1611994754412536d4ab902a81530b49bcaf496a59cDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0); 162c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds endpoint = &intf->cur_altsetting->endpoint[0].desc; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_int_urb(kbtab->irq, dev, 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvintpipe(dev, endpoint->bEndpointAddress), 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->data, 8, 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab_irq, kbtab, endpoint->bInterval); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq->transfer_dma = kbtab->data_dma; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1735014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov error = input_register_device(kbtab->dev); 1745014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov if (error) 1755014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov goto fail3; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(intf, kbtab); 1785014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 180c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov 1815014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov fail3: usb_free_urb(kbtab->irq); 1827a9b149212f3716c598afe973b6261fd58453b7aLinus Torvalds fail2: usb_free_coherent(dev, 8, kbtab->data, kbtab->data_dma); 1835014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov fail1: input_free_device(input_dev); 184c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kfree(kbtab); 1855014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov return error; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void kbtab_disconnect(struct usb_interface *intf) 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 190c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct kbtab *kbtab = usb_get_intfdata(intf); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(intf, NULL); 193331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov 194331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov input_unregister_device(kbtab->dev); 195331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov usb_free_urb(kbtab->irq); 1967a9b149212f3716c598afe973b6261fd58453b7aLinus Torvalds usb_free_coherent(kbtab->usbdev, 8, kbtab->data, kbtab->data_dma); 197331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov kfree(kbtab); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver kbtab_driver = { 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "kbtab", 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = kbtab_probe, 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = kbtab_disconnect, 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = kbtab_ids, 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20708642e7c52cf43616821520828e504bc717e54a6Greg Kroah-Hartmanmodule_usb_driver(kbtab_driver); 208