kbtab.c revision 331cb022d3ac1f85f7842a51495c33c629e947bc
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 5ae0dadcf0f912cbab2ac84caa437454620bf71b2David Brownell#include <linux/usb/input.h> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v0.0.1 - Original, extremely basic version, 2.4.xx only 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v0.0.2 - Updated, works with 2.5.62 and 2.4.20; 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - added pressure-threshold modules param code from 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alex Perry <alex.perry@ieee.org> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "v0.0.2" 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Josh Myer <josh@joshisanerd.com>" 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB KB Gear JamStudio Tablet driver" 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_LICENSE "GPL" 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR(DRIVER_AUTHOR); 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE(DRIVER_LICENSE); 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_VENDOR_ID_KBGEAR 0x084e 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int kb_pressure_click = 0x10; 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(kb_pressure_click, int, 0); 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks"); 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct kbtab { 324ee1fc8e554593061a71d6af7c94f31764b87606Dmitry Torokhov unsigned char *data; 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t data_dma; 34c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct input_dev *dev; 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *usbdev; 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *irq; 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int x, y; 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int button; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pressure; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u32 serial[2]; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char phys[32]; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 447d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void kbtab_irq(struct urb *urb) 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbtab *kbtab = urb->context; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = kbtab->data; 48c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct input_dev *dev = kbtab->dev; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (urb->status) { 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this urb is terminated, clean up */ 59ea3e6c59266b783b103c0f42a8de5dbe565a43d4Harvey Harrison dbg("%s - urb shutting down with status: %d", __func__, urb->status); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 62ea3e6c59266b783b103c0f42a8de5dbe565a43d4Harvey Harrison dbg("%s - nonzero urb status received: %d", __func__, urb->status); 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66858ad08cf4c32a51d26552d3cb5fa8d5e2f0e579Harvey Harrison kbtab->x = get_unaligned_le16(&data[1]); 67858ad08cf4c32a51d26552d3cb5fa8d5e2f0e579Harvey Harrison kbtab->y = get_unaligned_le16(&data[3]); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->pressure = (data[5]); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_TOOL_PEN, 1); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_X, kbtab->x); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_Y, kbtab->y); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_RIGHT, data[0] & 0x02); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7905f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov if (-1 == kb_pressure_click) { 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_PRESSURE, kbtab->pressure); 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 8405f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exit: 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_submit_urb (urb, GFP_ATOMIC); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err ("%s - usb_submit_urb failed with result %d", 91ea3e6c59266b783b103c0f42a8de5dbe565a43d4Harvey Harrison __func__, retval); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id kbtab_ids[] = { 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(USB_VENDOR_ID_KBGEAR, 0x1001), .driver_info = 0 }, 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(usb, kbtab_ids); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int kbtab_open(struct input_dev *dev) 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1037791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov struct kbtab *kbtab = input_get_drvdata(dev); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq->dev = kbtab->usbdev; 10665cde54b8b0299d7e46b8705338b01d1e44a5eb0Dmitry Torokhov if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void kbtab_close(struct input_dev *dev) 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1147791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov struct kbtab *kbtab = input_get_drvdata(dev); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11665cde54b8b0299d7e46b8705338b01d1e44a5eb0Dmitry Torokhov usb_kill_urb(kbtab->irq); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *dev = interface_to_usbdev(intf); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_endpoint_descriptor *endpoint; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbtab *kbtab; 124c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct input_dev *input_dev; 1255014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov int error = -ENOMEM; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 127c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL); 128c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev = input_allocate_device(); 129c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!kbtab || !input_dev) 130c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail1; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma); 133c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!kbtab->data) 134c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail1; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq = usb_alloc_urb(0, GFP_KERNEL); 137c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!kbtab->irq) 138c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail2; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 140c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbtab->usbdev = dev; 141c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbtab->dev = input_dev; 14205f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 143c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys)); 144c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov strlcat(kbtab->phys, "/input0", sizeof(kbtab->phys)); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 146c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->name = "KB Gear Tablet"; 147c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->phys = kbtab->phys; 148c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov usb_to_input_id(dev, &input_dev->id); 149c0f82d570c84f2592367e350a92ebd71e72ba68aDmitry Torokhov input_dev->dev.parent = &intf->dev; 1507791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov 1517791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov input_set_drvdata(input_dev, kbtab); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 153c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->open = kbtab_open; 154c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->close = kbtab_close; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1567b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | 1577b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby BIT_MASK(EV_MSC); 1587b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | 1597b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); 1607b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | 1617b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby BIT_MASK(BTN_TOUCH); 1627b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL); 163c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0); 1641994754412536d4ab902a81530b49bcaf496a59cDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0); 165c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds endpoint = &intf->cur_altsetting->endpoint[0].desc; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_int_urb(kbtab->irq, dev, 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvintpipe(dev, endpoint->bEndpointAddress), 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->data, 8, 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab_irq, kbtab, endpoint->bInterval); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq->transfer_dma = kbtab->data_dma; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1765014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov error = input_register_device(kbtab->dev); 1775014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov if (error) 1785014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov goto fail3; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(intf, kbtab); 1815014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 183c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov 1845014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov fail3: usb_free_urb(kbtab->irq); 185ee7aa6ce41e08c68f72b5ca8f14fb61286dc2418Axel Lin fail2: usb_buffer_free(dev, 8, kbtab->data, kbtab->data_dma); 1865014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov fail1: input_free_device(input_dev); 187c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kfree(kbtab); 1885014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov return error; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void kbtab_disconnect(struct usb_interface *intf) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 193c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct kbtab *kbtab = usb_get_intfdata(intf); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(intf, NULL); 196331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov 197331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov input_unregister_device(kbtab->dev); 198331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov usb_free_urb(kbtab->irq); 199331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov usb_buffer_free(kbtab->usbdev, 8, kbtab->data, kbtab->data_dma); 200331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov kfree(kbtab); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver kbtab_driver = { 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "kbtab", 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = kbtab_probe, 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = kbtab_disconnect, 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = kbtab_ids, 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init kbtab_init(void) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&kbtab_driver); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 216899ef6e7cf2f057fcfd8071b36de04117313242bGreg Kroah-Hartman printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" 217899ef6e7cf2f057fcfd8071b36de04117313242bGreg Kroah-Hartman DRIVER_DESC "\n"); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit kbtab_exit(void) 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_deregister(&kbtab_driver); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(kbtab_init); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(kbtab_exit); 229