kbtab.c revision 7a9b149212f3716c598afe973b6261fd58453b7a
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 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 */ 56ea3e6c59266b783b103c0f42a8de5dbe565a43d4Harvey Harrison dbg("%s - urb shutting down with status: %d", __func__, urb->status); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 59ea3e6c59266b783b103c0f42a8de5dbe565a43d4Harvey Harrison dbg("%s - nonzero urb status received: %d", __func__, urb->status); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_TOOL_PEN, 1); 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_report_abs(dev, ABS_X, get_unaligned_le16(&data[1])); 67f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_report_abs(dev, ABS_Y, get_unaligned_le16(&data[3])); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_RIGHT, data[0] & 0x02); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov pressure = data[5]; 73f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov if (kb_pressure_click == -1) 74f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_report_abs(dev, ABS_PRESSURE, pressure); 75f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov else 76f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_report_key(dev, BTN_LEFT, pressure > kb_pressure_click ? 1 : 0); 7705f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exit: 81f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov retval = usb_submit_urb(urb, GFP_ATOMIC); 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 83f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov err("%s - usb_submit_urb failed with result %d", 84ea3e6c59266b783b103c0f42a8de5dbe565a43d4Harvey Harrison __func__, retval); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id kbtab_ids[] = { 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(USB_VENDOR_ID_KBGEAR, 0x1001), .driver_info = 0 }, 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(usb, kbtab_ids); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int kbtab_open(struct input_dev *dev) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 967791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov struct kbtab *kbtab = input_get_drvdata(dev); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq->dev = kbtab->usbdev; 9965cde54b8b0299d7e46b8705338b01d1e44a5eb0Dmitry Torokhov if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void kbtab_close(struct input_dev *dev) 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1077791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov struct kbtab *kbtab = input_get_drvdata(dev); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10965cde54b8b0299d7e46b8705338b01d1e44a5eb0Dmitry Torokhov usb_kill_urb(kbtab->irq); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id) 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *dev = interface_to_usbdev(intf); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_endpoint_descriptor *endpoint; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbtab *kbtab; 117c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct input_dev *input_dev; 1185014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov int error = -ENOMEM; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 120c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL); 121c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev = input_allocate_device(); 122c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!kbtab || !input_dev) 123c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail1; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 125997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack kbtab->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &kbtab->data_dma); 126c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!kbtab->data) 127c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail1; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq = usb_alloc_urb(0, GFP_KERNEL); 130c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!kbtab->irq) 131c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail2; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 133c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbtab->usbdev = dev; 134c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbtab->dev = input_dev; 13505f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 136c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys)); 137c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov strlcat(kbtab->phys, "/input0", sizeof(kbtab->phys)); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 139c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->name = "KB Gear Tablet"; 140c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->phys = kbtab->phys; 141c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov usb_to_input_id(dev, &input_dev->id); 142c0f82d570c84f2592367e350a92ebd71e72ba68aDmitry Torokhov input_dev->dev.parent = &intf->dev; 1437791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov 1447791bdae71243050132ede7ea1558c828b69458fDmitry Torokhov input_set_drvdata(input_dev, kbtab); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 146c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->open = kbtab_open; 147c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->close = kbtab_close; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 149f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 150f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_dev->keybit[BIT_WORD(BTN_LEFT)] |= 151f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); 152f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov input_dev->keybit[BIT_WORD(BTN_DIGI)] |= 153f3192090df1e17dbd0f7c4b3820d31719422eb96Dmitry Torokhov BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOUCH); 154c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0); 1551994754412536d4ab902a81530b49bcaf496a59cDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0); 156c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds endpoint = &intf->cur_altsetting->endpoint[0].desc; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_int_urb(kbtab->irq, dev, 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvintpipe(dev, endpoint->bEndpointAddress), 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->data, 8, 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab_irq, kbtab, endpoint->bInterval); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq->transfer_dma = kbtab->data_dma; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1675014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov error = input_register_device(kbtab->dev); 1685014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov if (error) 1695014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov goto fail3; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(intf, kbtab); 1725014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 174c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov 1755014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov fail3: usb_free_urb(kbtab->irq); 1767a9b149212f3716c598afe973b6261fd58453b7aLinus Torvalds fail2: usb_free_coherent(dev, 8, kbtab->data, kbtab->data_dma); 1775014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov fail1: input_free_device(input_dev); 178c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kfree(kbtab); 1795014186de89708d0e9eed60526b698d5b786b707Dmitry Torokhov return error; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void kbtab_disconnect(struct usb_interface *intf) 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 184c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct kbtab *kbtab = usb_get_intfdata(intf); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(intf, NULL); 187331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov 188331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov input_unregister_device(kbtab->dev); 189331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov usb_free_urb(kbtab->irq); 1907a9b149212f3716c598afe973b6261fd58453b7aLinus Torvalds usb_free_coherent(kbtab->usbdev, 8, kbtab->data, kbtab->data_dma); 191331cb022d3ac1f85f7842a51495c33c629e947bcDmitry Torokhov kfree(kbtab); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver kbtab_driver = { 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "kbtab", 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = kbtab_probe, 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = kbtab_disconnect, 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = kbtab_ids, 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init kbtab_init(void) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&kbtab_driver); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 207899ef6e7cf2f057fcfd8071b36de04117313242bGreg Kroah-Hartman printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" 208899ef6e7cf2f057fcfd8071b36de04117313242bGreg Kroah-Hartman DRIVER_DESC "\n"); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit kbtab_exit(void) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_deregister(&kbtab_driver); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(kbtab_init); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(kbtab_exit); 220