From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965266Ab0CMBbm (ORCPT ); Fri, 12 Mar 2010 20:31:42 -0500 Received: from kroah.org ([198.145.64.141]:60634 "EHLO coco.kroah.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934865Ab0CMATv (ORCPT ); Fri, 12 Mar 2010 19:19:51 -0500 X-Mailbox-Line: From gregkh@kvm.kroah.org Fri Mar 12 16:15:07 2010 Message-Id: <20100313001507.537422976@kvm.kroah.org> User-Agent: quilt/0.48-4.4 Date: Fri, 12 Mar 2010 16:12:05 -0800 From: Greg KH To: linux-kernel@vger.kernel.org, stable@kernel.org Cc: stable-review@kernel.org, torvalds@linux-foundation.org, akpm@linux-foundation.org, alan@lxorguk.ukuu.org.uk, , Phil Hannent , Marc Rousseau Subject: [patch 027/123] Staging: mimio: remove the mimio driver In-Reply-To: <20100313001618.GA9811@kroah.com> In-Reply-To: <20100313001618.GA9811@kroah.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 2.6.33-stable review patch. If anyone has any objections, please let me know. ----------------- From: Greg Kroah-Hartman commit e37bcc0de040127281de13a84a608570355c20eb upstream. It turns out that Mimio has a userspace solution for this product using libusb, and the in-kernel driver is just getting in the way now and causing problems. So they have asked that the in-kernel driver be removed. As the staging driver wasn't quite working anyway, and Mimio supports their libusb solution for all distros, I am removing the in-kernel driver. The libusb solution can be downloaded from: http://www.mimio.com/downloads/mimio_studio_software/linux.asp Cc: Cc: Phil Hannent Cc: Marc Rousseau Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 drivers/staging/Makefile | 1 drivers/staging/mimio/Kconfig | 10 drivers/staging/mimio/Makefile | 1 drivers/staging/mimio/mimio.c | 914 ----------------------------------------- 5 files changed, 928 deletions(-) --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -81,8 +81,6 @@ source "drivers/staging/rtl8192u/Kconfig source "drivers/staging/rtl8192e/Kconfig" -source "drivers/staging/mimio/Kconfig" - source "drivers/staging/frontier/Kconfig" source "drivers/staging/dream/Kconfig" --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_R8187SE) += rtl8187se/ obj-$(CONFIG_RTL8192SU) += rtl8192su/ obj-$(CONFIG_RTL8192U) += rtl8192u/ obj-$(CONFIG_RTL8192E) += rtl8192e/ -obj-$(CONFIG_INPUT_MIMIO) += mimio/ obj-$(CONFIG_TRANZPORT) += frontier/ obj-$(CONFIG_DREAM) += dream/ obj-$(CONFIG_POHMELFS) += pohmelfs/ --- a/drivers/staging/mimio/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config INPUT_MIMIO - tristate "Mimio Xi interactive whiteboard support" - depends on USB && INPUT - default N - help - Say Y here if you want to use a Mimio Xi interactive - whiteboard device. - - To compile this driver as a module, choose M here: the - module will be called mimio. --- a/drivers/staging/mimio/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_INPUT_MIMIO) += mimio.o --- a/drivers/staging/mimio/mimio.c +++ /dev/null @@ -1,914 +0,0 @@ -/* - * Hardware event => input event mapping: - * - * - * - input.h:#define BTN_TOOL_PEN 0x140 black - input.h:#define BTN_TOOL_RUBBER 0x141 blue - input.h:#define BTN_TOOL_BRUSH 0x142 green - input.h:#define BTN_TOOL_PENCIL 0x143 red - input.h:#define BTN_TOOL_AIRBRUSH 0x144 eraser - input.h:#define BTN_TOOL_FINGER 0x145 small eraser - input.h:#define BTN_TOOL_MOUSE 0x146 mimio interactive - input.h:#define BTN_TOOL_LENS 0x147 mimio interactive but1 - input.h:#define LOCALBTN_TOOL_EXTRA1 0x14a mimio interactive but2 == BTN_TOUCH - input.h:#define LOCALBTN_TOOL_EXTRA2 0x14b mimio extra pens (orange, brown, yellow, purple) == BTN_STYLUS - input.h:#define LOCALBTN_TOOL_EXTRA3 0x14c unused == BTN_STYLUS2 - input.h:#define BTN_TOOL_DOUBLETAP 0x14d unused - input.h:#define BTN_TOOL_TRIPLETAP 0x14e unused - * - * MIMIO_EV_PENDOWN(MIMIO_PEN_K) => EV_KEY BIT(BTN_TOOL_PEN) - * MIMIO_EV_PENDOWN(MIMIO_PEN_B) => EV_KEY BIT(BTN_TOOL_RUBBER) - * MIMIO_EV_PENDOWN(MIMIO_PEN_G) => EV_KEY BIT(BTN_TOOL_BRUSH) - * MIMIO_EV_PENDOWN(MIMIO_PEN_R) => EV_KEY BIT(BTN_TOOL_PENCIL) - * MIMIO_EV_PENDOWN(MIMIO_PEN_E) => EV_KEY BIT(BTN_TOOL_AIRBRUSH) - * MIMIO_EV_PENDOWN(MIMIO_PEN_ES) => EV_KEY BIT(BTN_TOOL_FINGER) - * MIMIO_EV_PENDOWN(MIMIO_PEN_I) => EV_KEY BIT(BTN_TOOL_MOUSE) - * MIMIO_EV_PENDOWN(MIMIO_PEN_IL) => EV_KEY BIT(BTN_TOOL_LENS) - * MIMIO_EV_PENDOWN(MIMIO_PEN_IR) => EV_KEY BIT(BTN_TOOL_DOUBLETAP) - * MIMIO_EV_PENDOWN(MIMIO_PEN_EX) => EV_KEY BIT(BTN_TOOL_TRIPLETAP) - * MIMIO_EV_PENDATA => EV_ABS BIT(ABS_X), BIT(ABS_Y) - * MIMIO_EV_MEMRESET => EV_KEY BIT(BTN_0) - * MIMIO_EV_ACC(ACC_NEWPAGE) => EV_KEY BIT(BTN_1) - * MIMIO_EV_ACC(ACC_TAGPAGE) => EV_KEY BIT(BTN_2) - * MIMIO_EV_ACC(ACC_PRINTPAGE) => EV_KEY BIT(BTN_3) - * MIMIO_EV_ACC(ACC_MAXIMIZE) => EV_KEY BIT(BTN_4) - * MIMIO_EV_ACC(ACC_FINDCTLPNL) => EV_KEY BIT(BTN_5) - * - * - * open issues: - * - cold-load of data captured when mimio in standalone mode not yet - * supported; need to snoop Win32 box to see datastream for this. - * - mimio mouse not yet supported; need to snoop Win32 box to see the - * datastream for this. - */ -#include -#include -#include -#include -#include -#include - -#define DRIVER_VERSION "v0.031" -#define DRIVER_AUTHOR "mwilder@cs.nmsu.edu" -#define DRIVER_DESC "USB mimio-xi driver" - -enum {UPVALUE, DOWNVALUE, MOVEVALUE}; - -#define MIMIO_XRANGE_MAX 9600 -#define MIMIO_YRANGE_MAX 4800 - -#define LOCALBTN_TOOL_EXTRA1 BTN_TOUCH -#define LOCALBTN_TOOL_EXTRA2 BTN_STYLUS -#define LOCALBTN_TOOL_EXTRA3 BTN_STYLUS2 - -#define MIMIO_VENDOR_ID 0x08d3 -#define MIMIO_PRODUCT_ID 0x0001 -#define MIMIO_MAXPAYLOAD (8) -#define MIMIO_MAXNAMELEN (64) -#define MIMIO_TXWAIT (1) -#define MIMIO_TXDONE (2) - -#define MIMIO_EV_PENDOWN (0x22) -#define MIMIO_EV_PENDATA (0x24) -#define MIMIO_EV_PENUP (0x51) -#define MIMIO_EV_MEMRESET (0x45) -#define MIMIO_EV_ACC (0xb2) - -#define MIMIO_PEN_K (1) /* black pen */ -#define MIMIO_PEN_B (2) /* blue pen */ -#define MIMIO_PEN_G (3) /* green pen */ -#define MIMIO_PEN_R (4) /* red pen */ -/* 5, 6, 7, 8 are extra pens */ -#define MIMIO_PEN_E (9) /* big eraser */ -#define MIMIO_PEN_ES (10) /* lil eraser */ -#define MIMIO_PENJUMP_START (10) -#define MIMIO_PENJUMP (6) -#define MIMIO_PEN_I (17) /* mimio interactive */ -#define MIMIO_PEN_IL (18) /* mimio interactive button 1 */ -#define MIMIO_PEN_IR (19) /* mimio interactive button 2 */ - -#define MIMIO_PEN_MAX (MIMIO_PEN_IR) - -#define ACC_DONE (0) -#define ACC_NEWPAGE (1) -#define ACC_TAGPAGE (2) -#define ACC_PRINTPAGE (4) -#define ACC_MAXIMIZE (8) -#define ACC_FINDCTLPNL (16) - -#define isvalidtxsize(n) ((n) > 0 && (n) <= MIMIO_MAXPAYLOAD) - - -struct pktbuf { - unsigned char instr; - unsigned char buf[16]; - unsigned char *p; - unsigned char *q; -}; - -struct usbintendpt { - dma_addr_t dma; - struct urb *urb; - unsigned char *buf; - struct usb_endpoint_descriptor *desc; -}; - -struct mimio { - struct input_dev *idev; - struct usb_device *udev; - struct usb_interface *uifc; - int open; - int present; - int greeted; - int txflags; - char phys[MIMIO_MAXNAMELEN]; - struct usbintendpt in; - struct usbintendpt out; - struct pktbuf pktbuf; - unsigned char minor; - wait_queue_head_t waitq; - spinlock_t txlock; - void (*rxhandler)(struct mimio *, unsigned char *, unsigned int); - int last_pen_down; -}; - -static void mimio_close(struct input_dev *); -static void mimio_dealloc(struct mimio *); -static void mimio_disconnect(struct usb_interface *); -static int mimio_greet(struct mimio *); -static void mimio_irq_in(struct urb *); -static void mimio_irq_out(struct urb *); -static int mimio_open(struct input_dev *); -static int mimio_probe(struct usb_interface *, const struct usb_device_id *); -static void mimio_rx_handler(struct mimio *, unsigned char *, unsigned int); -static int mimio_tx(struct mimio *, const char *, int); - -static char mimio_name[] = "VirtualInk mimio-Xi"; -static struct usb_device_id mimio_table [] = { - { USB_DEVICE(MIMIO_VENDOR_ID, MIMIO_PRODUCT_ID) }, - { USB_DEVICE(0x0525, 0xa4a0) }, /* gadget zero firmware */ - { } -}; - -MODULE_DEVICE_TABLE(usb, mimio_table); - -static struct usb_driver mimio_driver = { - .name = "mimio", - .probe = mimio_probe, - .disconnect = mimio_disconnect, - .id_table = mimio_table, -}; - -static DECLARE_MUTEX(disconnect_sem); - -static void mimio_close(struct input_dev *idev) -{ - struct mimio *mimio; - - mimio = input_get_drvdata(idev); - if (!mimio) { - dev_err(&idev->dev, "null mimio attached to input device\n"); - return; - } - - if (mimio->open <= 0) - dev_err(&idev->dev, "mimio not open.\n"); - else - mimio->open--; - - if (mimio->present == 0 && mimio->open == 0) - mimio_dealloc(mimio); -} - -static void mimio_dealloc(struct mimio *mimio) -{ - if (mimio == NULL) - return; - - usb_kill_urb(mimio->in.urb); - - usb_kill_urb(mimio->out.urb); - - if (mimio->idev) { - input_unregister_device(mimio->idev); - if (mimio->idev->grab) - input_close_device(mimio->idev->grab); - else - dev_dbg(&mimio->idev->dev, "mimio->idev->grab == NULL" - " -- didn't call input_close_device\n"); - } - - usb_free_urb(mimio->in.urb); - - usb_free_urb(mimio->out.urb); - - if (mimio->in.buf) { - usb_buffer_free(mimio->udev, MIMIO_MAXPAYLOAD, mimio->in.buf, - mimio->in.dma); - } - - if (mimio->out.buf) - usb_buffer_free(mimio->udev, MIMIO_MAXPAYLOAD, mimio->out.buf, - mimio->out.dma); - - if (mimio->idev) - input_free_device(mimio->idev); - - kfree(mimio); -} - -static void mimio_disconnect(struct usb_interface *ifc) -{ - struct mimio *mimio; - - down(&disconnect_sem); - - mimio = usb_get_intfdata(ifc); - usb_set_intfdata(ifc, NULL); - dev_dbg(&mimio->idev->dev, "disconnect\n"); - - if (mimio) { - mimio->present = 0; - - if (mimio->open <= 0) - mimio_dealloc(mimio); - } - - up(&disconnect_sem); -} - -static int mimio_greet(struct mimio *mimio) -{ - const struct grtpkt { - int nbytes; - unsigned delay; - char data[8]; - } grtpkts[] = { - { 3, 0, { 0x11, 0x55, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { 5, 0, { 0x53, 0x55, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00 } }, - { 5, 0, { 0x43, 0x55, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00 } }, - { 5, 0, { 0x33, 0x55, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00 } }, - { 5, 0, { 0x13, 0x00, 0x5e, 0x02, 0x4f, 0x00, 0x00, 0x00 } }, - { 5, 0, { 0x13, 0x00, 0x04, 0x03, 0x14, 0x00, 0x00, 0x00 } }, - { 5, 2, { 0x13, 0x00, 0x00, 0x04, 0x17, 0x00, 0x00, 0x00 } }, - { 5, 0, { 0x13, 0x00, 0x0d, 0x08, 0x16, 0x00, 0x00, 0x00 } }, - { 5, 0, { 0x13, 0x00, 0x4d, 0x01, 0x5f, 0x00, 0x00, 0x00 } }, - { 3, 0, { 0xf1, 0x55, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { 7, 2, { 0x52, 0x55, 0x00, 0x07, 0x31, 0x55, 0x64, 0x00 } }, - { 0, 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - }; - int rslt; - const struct grtpkt *pkt; - - for (pkt = grtpkts; pkt->nbytes; pkt++) { - rslt = mimio_tx(mimio, pkt->data, pkt->nbytes); - if (rslt) - return rslt; - if (pkt->delay) - msleep(pkt->delay); - } - - return 0; -} - -static void mimio_irq_in(struct urb *urb) -{ - int rslt; - char *data; - const char *reason = "going down"; - struct mimio *mimio; - - mimio = urb->context; - - if (mimio == NULL) - /* paranoia */ - return; - - switch (urb->status) { - case 0: - /* success */ - break; - case -ETIMEDOUT: - reason = "timeout -- unplugged?"; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - dev_dbg(&mimio->idev->dev, "%s.\n", reason); - return; - default: - dev_dbg(&mimio->idev->dev, "unknown urb-status: %d.\n", - urb->status); - goto exit; - } - data = mimio->in.buf; - - if (mimio->rxhandler) - mimio->rxhandler(mimio, data, urb->actual_length); -exit: - /* - * Keep listening to device on same urb. - */ - rslt = usb_submit_urb(urb, GFP_ATOMIC); - if (rslt) - dev_err(&mimio->idev->dev, "usb_submit_urb failure: %d.\n", - rslt); -} - -static void mimio_irq_out(struct urb *urb) -{ - unsigned long flags; - struct mimio *mimio; - - mimio = urb->context; - - if (urb->status) - dev_dbg(&mimio->idev->dev, "urb-status: %d.\n", urb->status); - - spin_lock_irqsave(&mimio->txlock, flags); - mimio->txflags |= MIMIO_TXDONE; - spin_unlock_irqrestore(&mimio->txlock, flags); - wmb(); - wake_up(&mimio->waitq); -} - -static int mimio_open(struct input_dev *idev) -{ - int rslt; - struct mimio *mimio; - - rslt = 0; - down(&disconnect_sem); - mimio = input_get_drvdata(idev); - dev_dbg(&idev->dev, "mimio_open\n"); - - if (mimio == NULL) { - dev_err(&idev->dev, "null mimio.\n"); - rslt = -ENODEV; - goto exit; - } - - if (mimio->open++) - goto exit; - - if (mimio->present && !mimio->greeted) { - struct urb *urb = mimio->in.urb; - mimio->in.urb->dev = mimio->udev; - rslt = usb_submit_urb(mimio->in.urb, GFP_KERNEL); - if (rslt) { - dev_err(&idev->dev, "usb_submit_urb failure " - "(res = %d: %s). Not greeting.\n", - rslt, - (!urb ? "urb is NULL" : - (urb->hcpriv ? "urb->hcpriv is non-NULL" : - (!urb->complete ? "urb is not complete" : - (urb->number_of_packets <= 0 ? "urb has no packets" : - (urb->interval <= 0 ? "urb interval too small" : - "urb interval too large or some other error")))))); - rslt = -EIO; - goto exit; - } - rslt = mimio_greet(mimio); - if (rslt == 0) { - dev_dbg(&idev->dev, "Mimio greeted OK.\n"); - mimio->greeted = 1; - } else { - dev_dbg(&idev->dev, "Mimio greet Failure (%d)\n", - rslt); - } - } - -exit: - up(&disconnect_sem); - return rslt; -} - -static int mimio_probe(struct usb_interface *ifc, - const struct usb_device_id *id) -{ - char path[64]; - int pipe, maxp; - struct mimio *mimio; - struct usb_device *udev; - struct usb_host_interface *hostifc; - struct input_dev *input_dev; - int res = 0; - int i; - - udev = interface_to_usbdev(ifc); - - mimio = kzalloc(sizeof(struct mimio), GFP_KERNEL); - if (!mimio) - return -ENOMEM; - - input_dev = input_allocate_device(); - if (!input_dev) { - mimio_dealloc(mimio); - return -ENOMEM; - } - - mimio->uifc = ifc; - mimio->udev = udev; - mimio->pktbuf.p = mimio->pktbuf.buf; - mimio->pktbuf.q = mimio->pktbuf.buf; - /* init_input_dev(mimio->idev); */ - mimio->idev = input_dev; - init_waitqueue_head(&mimio->waitq); - spin_lock_init(&mimio->txlock); - hostifc = ifc->cur_altsetting; - - if (hostifc->desc.bNumEndpoints != 2) { - dev_err(&udev->dev, "Unexpected endpoint count: %d.\n", - hostifc->desc.bNumEndpoints); - mimio_dealloc(mimio); - return -ENODEV; - } - - mimio->in.desc = &(hostifc->endpoint[0].desc); - mimio->out.desc = &(hostifc->endpoint[1].desc); - - mimio->in.buf = usb_buffer_alloc(udev, MIMIO_MAXPAYLOAD, GFP_KERNEL, - &mimio->in.dma); - mimio->out.buf = usb_buffer_alloc(udev, MIMIO_MAXPAYLOAD, GFP_KERNEL, - &mimio->out.dma); - - if (mimio->in.buf == NULL || mimio->out.buf == NULL) { - dev_err(&udev->dev, "usb_buffer_alloc failure.\n"); - mimio_dealloc(mimio); - return -ENOMEM; - } - - mimio->in.urb = usb_alloc_urb(0, GFP_KERNEL); - mimio->out.urb = usb_alloc_urb(0, GFP_KERNEL); - - if (mimio->in.urb == NULL || mimio->out.urb == NULL) { - dev_err(&udev->dev, "usb_alloc_urb failure.\n"); - mimio_dealloc(mimio); - return -ENOMEM; - } - - /* - * Build the input urb. - */ - pipe = usb_rcvintpipe(udev, mimio->in.desc->bEndpointAddress); - maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - if (maxp > MIMIO_MAXPAYLOAD) - maxp = MIMIO_MAXPAYLOAD; - usb_fill_int_urb(mimio->in.urb, udev, pipe, mimio->in.buf, maxp, - mimio_irq_in, mimio, mimio->in.desc->bInterval); - mimio->in.urb->transfer_dma = mimio->in.dma; - mimio->in.urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - /* - * Build the output urb. - */ - pipe = usb_sndintpipe(udev, mimio->out.desc->bEndpointAddress); - maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - if (maxp > MIMIO_MAXPAYLOAD) - maxp = MIMIO_MAXPAYLOAD; - usb_fill_int_urb(mimio->out.urb, udev, pipe, mimio->out.buf, maxp, - mimio_irq_out, mimio, mimio->out.desc->bInterval); - mimio->out.urb->transfer_dma = mimio->out.dma; - mimio->out.urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - /* - * Build input device info - */ - usb_make_path(udev, path, 64); - snprintf(mimio->phys, MIMIO_MAXNAMELEN, "%s/input0", path); - input_set_drvdata(input_dev, mimio); - /* input_dev->dev = &ifc->dev; */ - input_dev->open = mimio_open; - input_dev->close = mimio_close; - input_dev->name = mimio_name; - input_dev->phys = mimio->phys; - input_dev->dev.parent = &ifc->dev; - - input_dev->id.bustype = BUS_USB; - input_dev->id.vendor = le16_to_cpu(udev->descriptor.idVendor); - input_dev->id.product = le16_to_cpu(udev->descriptor.idProduct); - input_dev->id.version = le16_to_cpu(udev->descriptor.bcdDevice); - - input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS); - for (i = BTN_TOOL_PEN; i <= LOCALBTN_TOOL_EXTRA2; ++i) - set_bit(i, input_dev->keybit); - - input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) | - BIT_MASK(BTN_1) | - BIT_MASK(BTN_2) | - BIT_MASK(BTN_3) | - BIT_MASK(BTN_4) | - BIT_MASK(BTN_5); - /* input_dev->keybit[BTN_MOUSE] |= BIT(BTN_LEFT); */ - input_dev->absbit[0] |= BIT_MASK(ABS_X) | BIT_MASK(ABS_Y); - input_set_abs_params(input_dev, ABS_X, 0, MIMIO_XRANGE_MAX, 0, 0); - input_set_abs_params(input_dev, ABS_Y, 0, MIMIO_YRANGE_MAX, 0, 0); - input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); - -#if 0 - input_dev->absmin[ABS_X] = 0; - input_dev->absmin[ABS_Y] = 0; - input_dev->absmax[ABS_X] = 9600; - input_dev->absmax[ABS_Y] = 4800; - input_dev->absfuzz[ABS_X] = 0; - input_dev->absfuzz[ABS_Y] = 0; - input_dev->absflat[ABS_X] = 0; - input_dev->absflat[ABS_Y] = 0; -#endif - -#if 0 - /* this will just reduce the precision */ - input_dev->absfuzz[ABS_X] = 8; /* experimental; may need to change */ - input_dev->absfuzz[ABS_Y] = 8; /* experimental; may need to change */ -#endif - - /* - * Register the input device. - */ - res = input_register_device(mimio->idev); - if (res) { - dev_err(&udev->dev, "input_register_device failure (%d)\n", - res); - mimio_dealloc(mimio); - return -EIO; - } - dev_dbg(&mimio->idev->dev, "input: %s on %s (res = %d).\n", - input_dev->name, input_dev->phys, res); - - usb_set_intfdata(ifc, mimio); - mimio->present = 1; - - /* - * Submit the input urb to the usb subsystem. - */ - mimio->in.urb->dev = mimio->udev; - res = usb_submit_urb(mimio->in.urb, GFP_KERNEL); - if (res) { - dev_err(&mimio->idev->dev, "usb_submit_urb failure (%d)\n", - res); - mimio_dealloc(mimio); - return -EIO; - } - - /* - * Attempt to greet the mimio after giving - * it some post-init settling time. - * - * note: sometimes this sleep interval isn't - * long enough to permit the device to re-init - * after a hot-swap; maybe need to bump it up. - * - * As it is, this probably breaks module unloading support! - */ - msleep(1024); - - res = mimio_greet(mimio); - if (res == 0) { - dev_dbg(&mimio->idev->dev, "Mimio greeted OK.\n"); - mimio->greeted = 1; - mimio->rxhandler = mimio_rx_handler; - } else { - dev_dbg(&mimio->idev->dev, "Mimio greet Failure (%d)\n", res); - } - - return 0; -} - -static int handle_mimio_rx_penupdown(struct mimio *mimio, - int down, - const char *const instr[], - const int instr_ofst[]) -{ - int penid, x; - if (mimio->pktbuf.q - mimio->pktbuf.p < (down ? 4 : 3)) - return 1; /* partial pkt */ - - if (down) { - x = *mimio->pktbuf.p ^ *(mimio->pktbuf.p + 1) ^ - *(mimio->pktbuf.p + 2); - if (x != *(mimio->pktbuf.p + 3)) { - dev_dbg(&mimio->idev->dev, "EV_PEN%s: bad xsum.\n", - down ? "DOWN":"UP"); - /* skip this event data */ - mimio->pktbuf.p += 4; - /* decode any remaining events */ - return 0; - } - penid = mimio->pktbuf.instr = *(mimio->pktbuf.p + 2); - if (penid > MIMIO_PEN_MAX) { - dev_dbg(&mimio->idev->dev, - "Unmapped penID (not in [0, %d]): %d\n", - MIMIO_PEN_MAX, (int)mimio->pktbuf.instr); - penid = mimio->pktbuf.instr = 0; - } - mimio->last_pen_down = penid; - } else { - penid = mimio->last_pen_down; - } - dev_dbg(&mimio->idev->dev, "%s (id %d, code %d) %s.\n", instr[penid], - instr_ofst[penid], penid, down ? "down" : "up"); - - if (instr_ofst[penid] >= 0) { - int code = BTN_TOOL_PEN + instr_ofst[penid]; - int value = down ? DOWNVALUE : UPVALUE; - if (code > KEY_MAX) - dev_dbg(&mimio->idev->dev, "input_event will ignore " - "-- code (%d) > KEY_MAX\n", code); - if (!test_bit(code, mimio->idev->keybit)) - dev_dbg(&mimio->idev->dev, "input_event will ignore " - "-- bit for code (%d) not enabled\n", code); - if (!!test_bit(code, mimio->idev->key) == value) - dev_dbg(&mimio->idev->dev, "input_event will ignore " - "-- bit for code (%d) already set to %d\n", - code, value); - if (value != DOWNVALUE) { - /* input_regs(mimio->idev, regs); */ - input_report_key(mimio->idev, code, value); - input_sync(mimio->idev); - } else { - /* wait until we get some coordinates */ - } - } else { - dev_dbg(&mimio->idev->dev, "penID offset[%d] == %d is < 0 " - "- not sending\n", penid, instr_ofst[penid]); - } - mimio->pktbuf.p += down ? 4 : 3; /* 3 for up, 4 for down */ - return 0; -} - -/* - * Stay tuned for partial-packet excitement. - * - * This routine buffers data packets received from the mimio device - * in the mimio's data space. This buffering is necessary because - * the mimio's in endpoint can serve us partial packets of data, and - * we want the driver to support the servicing of multiple mimios. - * Empirical evidence gathered so far suggests that the method of - * buffering packet data in the mimio's data space works. Previous - * versions of this driver did not buffer packet data in each mimio's - * data-space, and were therefore not able to service multiple mimios. - * Note that since the caller of this routine is running in interrupt - * context, care needs to be taken to ensure that this routine does not - * become bloated, and it may be that another spinlock is needed in each - * mimio to guard the buffered packet data properly. - */ -static void mimio_rx_handler(struct mimio *mimio, - unsigned char *data, - unsigned int nbytes) -{ - struct device *dev = &mimio->idev->dev; - unsigned int x; - unsigned int y; - static const char * const instr[] = { - "?0", - "black pen", "blue pen", "green pen", "red pen", - "brown pen", "orange pen", "purple pen", "yellow pen", - "big eraser", "lil eraser", - "?11", "?12", "?13", "?14", "?15", "?16", - "mimio interactive", "interactive button1", - "interactive button2" - }; - - /* Mimio Interactive gives: - * down: [0x22 0x01 0x11 0x32 0x24] - * b1 : [0x22 0x01 0x12 0x31 0x24] - * b2 : [0x22 0x01 0x13 0x30 0x24] - */ - static const int instr_ofst[] = { - -1, - 0, 1, 2, 3, - 9, 9, 9, 9, - 4, 5, - -1, -1, -1, -1, -1, -1, - 6, 7, 8, - }; - - memcpy(mimio->pktbuf.q, data, nbytes); - mimio->pktbuf.q += nbytes; - - while (mimio->pktbuf.p < mimio->pktbuf.q) { - int t = *mimio->pktbuf.p; - switch (t) { - case MIMIO_EV_PENUP: - case MIMIO_EV_PENDOWN: - if (handle_mimio_rx_penupdown(mimio, - t == MIMIO_EV_PENDOWN, - instr, instr_ofst)) - return; /* partial packet */ - break; - - case MIMIO_EV_PENDATA: - if (mimio->pktbuf.q - mimio->pktbuf.p < 6) - /* partial pkt */ - return; - x = *mimio->pktbuf.p ^ *(mimio->pktbuf.p + 1) ^ - *(mimio->pktbuf.p + 2) ^ - *(mimio->pktbuf.p + 3) ^ - *(mimio->pktbuf.p + 4); - if (x != *(mimio->pktbuf.p + 5)) { - dev_dbg(dev, "EV_PENDATA: bad xsum.\n"); - mimio->pktbuf.p += 6; /* skip this event data */ - break; /* decode any remaining events */ - } - x = *(mimio->pktbuf.p + 1); - x <<= 8; - x |= *(mimio->pktbuf.p + 2); - y = *(mimio->pktbuf.p + 3); - y <<= 8; - y |= *(mimio->pktbuf.p + 4); - dev_dbg(dev, "coord: (%d, %d)\n", x, y); - if (instr_ofst[mimio->pktbuf.instr] >= 0) { - int code = BTN_TOOL_PEN + - instr_ofst[mimio->last_pen_down]; -#if 0 - /* Utter hack to ensure we get forwarded _AND_ - * so we can identify when a complete signal is - * received */ - mimio->idev->abs[ABS_Y] = -1; - mimio->idev->abs[ABS_X] = -1; -#endif - /* input_regs(mimio->idev, regs); */ - input_report_abs(mimio->idev, ABS_X, x); - input_report_abs(mimio->idev, ABS_Y, y); - /* fake a penup */ - change_bit(code, mimio->idev->key); - input_report_key(mimio->idev, - code, - DOWNVALUE); - /* always sync here */ - mimio->idev->sync = 0; - input_sync(mimio->idev); - } - mimio->pktbuf.p += 6; - break; - case MIMIO_EV_MEMRESET: - if (mimio->pktbuf.q - mimio->pktbuf.p < 7) - /* partial pkt */ - return; - dev_dbg(dev, "mem-reset.\n"); - /* input_regs(mimio->idev, regs); */ - input_event(mimio->idev, EV_KEY, BTN_0, 1); - input_event(mimio->idev, EV_KEY, BTN_0, 0); - input_sync(mimio->idev); - mimio->pktbuf.p += 7; - break; - case MIMIO_EV_ACC: - if (mimio->pktbuf.q - mimio->pktbuf.p < 4) - /* partial pkt */ - return; - x = *mimio->pktbuf.p ^ *(mimio->pktbuf.p + 1) ^ - *(mimio->pktbuf.p + 2); - if (x != *(mimio->pktbuf.p + 3)) { - dev_dbg(dev, "EV_ACC: bad xsum.\n"); - mimio->pktbuf.p += 4; /* skip this event data */ - break; /* decode any remaining events */ - } - switch (*(mimio->pktbuf.p + 2)) { - case ACC_NEWPAGE: - dev_dbg(&mimio->idev->dev, "new-page.\n"); - /* input_regs(mimio->idev, regs); */ - input_event(mimio->idev, EV_KEY, BTN_1, 1); - input_event(mimio->idev, EV_KEY, BTN_1, 0); - input_sync(mimio->idev); - break; - case ACC_TAGPAGE: - dev_dbg(&mimio->idev->dev, "tag-page.\n"); - /* input_regs(mimio->idev, regs); */ - input_event(mimio->idev, EV_KEY, BTN_2, 1); - input_event(mimio->idev, EV_KEY, BTN_2, 0); - input_sync(mimio->idev); - break; - case ACC_PRINTPAGE: - dev_dbg(&mimio->idev->dev, "print-page.\n"); - /* input_regs(mimio->idev, regs);*/ - input_event(mimio->idev, EV_KEY, BTN_3, 1); - input_event(mimio->idev, EV_KEY, BTN_3, 0); - input_sync(mimio->idev); - break; - case ACC_MAXIMIZE: - dev_dbg(&mimio->idev->dev, - "maximize-window.\n"); - /* input_regs(mimio->idev, regs); */ - input_event(mimio->idev, EV_KEY, BTN_4, 1); - input_event(mimio->idev, EV_KEY, BTN_4, 0); - input_sync(mimio->idev); - break; - case ACC_FINDCTLPNL: - dev_dbg(&mimio->idev->dev, "find-ctl-panel.\n"); - /* input_regs(mimio->idev, regs); */ - input_event(mimio->idev, EV_KEY, BTN_5, 1); - input_event(mimio->idev, EV_KEY, BTN_5, 0); - input_sync(mimio->idev); - break; - case ACC_DONE: - dev_dbg(&mimio->idev->dev, "acc-done.\n"); - /* no event is dispatched to the input - * subsystem for this device event. - */ - break; - default: - dev_dbg(dev, "unknown acc event.\n"); - break; - } - mimio->pktbuf.p += 4; - break; - default: - mimio->pktbuf.p++; - break; - } - } - - /* - * No partial event was received, so reset mimio's pktbuf ptrs. - */ - mimio->pktbuf.p = mimio->pktbuf.q = mimio->pktbuf.buf; -} - -static int mimio_tx(struct mimio *mimio, const char *buf, int nbytes) -{ - int rslt; - int timeout; - unsigned long flags; - DECLARE_WAITQUEUE(wait, current); - - if (!(isvalidtxsize(nbytes))) { - dev_err(&mimio->idev->dev, "invalid arg: nbytes: %d.\n", - nbytes); - return -EINVAL; - } - - /* - * Init the out urb and copy the data to send. - */ - mimio->out.urb->dev = mimio->udev; - mimio->out.urb->transfer_buffer_length = nbytes; - memcpy(mimio->out.urb->transfer_buffer, buf, nbytes); - - /* - * Send the data. - */ - spin_lock_irqsave(&mimio->txlock, flags); - mimio->txflags = MIMIO_TXWAIT; - rslt = usb_submit_urb(mimio->out.urb, GFP_ATOMIC); - spin_unlock_irqrestore(&mimio->txlock, flags); - dev_dbg(&mimio->idev->dev, "rslt: %d.\n", rslt); - - if (rslt) { - dev_err(&mimio->idev->dev, "usb_submit_urb failure: %d.\n", - rslt); - return rslt; - } - - /* - * Wait for completion to be signalled (the mimio_irq_out - * completion routine will or MIMIO_TXDONE in with txflags). - */ - timeout = HZ; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&mimio->waitq, &wait); - - while (timeout && ((mimio->txflags & MIMIO_TXDONE) == 0)) { - timeout = schedule_timeout(timeout); - rmb(); - } - - if ((mimio->txflags & MIMIO_TXDONE) == 0) - dev_dbg(&mimio->idev->dev, "tx timed out.\n"); - - /* - * Now that completion has been signalled, - * unlink the urb so that it can be recycled. - */ - set_current_state(TASK_RUNNING); - remove_wait_queue(&mimio->waitq, &wait); - usb_unlink_urb(mimio->out.urb); - - return rslt; -} - -static int __init mimio_init(void) -{ - int rslt; - - rslt = usb_register(&mimio_driver); - if (rslt != 0) { - err("%s: usb_register failure: %d", __func__, rslt); - return rslt; - } - - printk(KERN_INFO KBUILD_MODNAME ":" - DRIVER_DESC " " DRIVER_VERSION "\n"); - return rslt; -} - -static void __exit mimio_exit(void) -{ - usb_deregister(&mimio_driver); -} - -module_init(mimio_init); -module_exit(mimio_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL");