aboutsummaryrefslogtreecommitdiffstats
diff options
-rw-r--r--input-add-mimio-xi-driver.patch968
-rw-r--r--series1
-rw-r--r--version2
3 files changed, 970 insertions, 1 deletions
diff --git a/input-add-mimio-xi-driver.patch b/input-add-mimio-xi-driver.patch
new file mode 100644
index 00000000000000..286bbc788be7be
--- /dev/null
+++ b/input-add-mimio-xi-driver.patch
@@ -0,0 +1,968 @@
+From foo@baz Tue Apr 9 12:12:43 2002
+Date: Tue, 24 Jun 2008 15:19:47 +0100
+To: Greg KH <greg@kroah.com>
+From: Greg Kroah-Hartman <gregkh@suse.de>
+Subject: input: add mimio xi driver
+
+This patch adds the Mimio Xi interactive whiteboard driver to the tree.
+
+It was originally written by mwilder@cs.nmsu.edu, but cleaned up and
+forward ported by me to the latest kernel version.
+
+
+Cc: Phil Hannent <phil@hannent.co.uk>
+Cc: <mwilder@cs.nmsu.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/misc/Kconfig | 11
+ drivers/input/misc/Makefile | 1
+ drivers/input/misc/mimio.c | 913 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 925 insertions(+)
+
+--- a/drivers/input/misc/Kconfig
++++ b/drivers/input/misc/Kconfig
+@@ -164,6 +164,17 @@ config INPUT_POWERMATE
+ To compile this driver as a module, choose M here: the
+ module will be called powermate.
+
++config INPUT_MIMIO
++ tristate "Mimio Xi interactive whiteboard support"
++ depends on USB_ARCH_HAS_HCD
++ select USB
++ 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.
++
+ config INPUT_YEALINK
+ tristate "Yealink usb-p1k voip phone"
+ depends on EXPERIMENTAL
+--- a/drivers/input/misc/Makefile
++++ b/drivers/input/misc/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_r
+ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
+ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
+ obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
++obj-$(CONFIG_INPUT_MIMIO) += mimio.o
+ obj-$(CONFIG_INPUT_YEALINK) += yealink.o
+ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
+ obj-$(CONFIG_INPUT_UINPUT) += uinput.o
+--- /dev/null
++++ b/drivers/input/misc/mimio.c
+@@ -0,0 +1,913 @@
++/*
++ * 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 <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/input.h>
++#include <linux/usb.h>
++
++#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;
++ }
++
++ info(DRIVER_DESC " " DRIVER_VERSION);
++ 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");
diff --git a/series b/series
index 7390102017934d..5cabee7c2556df 100644
--- a/series
+++ b/series
@@ -292,3 +292,4 @@ usb/usb-gotemp.patch
#module-usb-serial.patch
#modpost
+input-add-mimio-xi-driver.patch
diff --git a/version b/version
index dabe3bdbc37a6e..badfbdf0010d08 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-2.6.26-rc7-git1
+2.6.26-rc8