linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Input: add mmio xi driver
@ 2008-09-25 23:22 Greg KH
       [not found] ` <20080925232237.GA22938-l3A5Bk7waGM@public.gmane.org>
  2008-10-02  6:12 ` Andrew Morton
  0 siblings, 2 replies; 8+ messages in thread
From: Greg KH @ 2008-09-25 23:22 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, linux-usb, phil, mwilder


From: Greg Kroah-Hartman <gregkh@suse.de>

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");

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Input: add mmio xi driver
       [not found] ` <20080925232237.GA22938-l3A5Bk7waGM@public.gmane.org>
@ 2008-09-26  1:20   ` Randy Dunlap
  2008-09-26  3:19     ` Greg KH
  0 siblings, 1 reply; 8+ messages in thread
From: Randy Dunlap @ 2008-09-26  1:20 UTC (permalink / raw)
  To: Greg KH
  Cc: Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, phil-+6o+yPtToBIqdlJmJB21zg,
	mwilder-qcTL/1vZYtiVc3sceRu5cw

On Thu, 25 Sep 2008 16:22:37 -0700 Greg KH wrote:

> 
> From: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
> 
> This patch adds the Mimio Xi interactive whiteboard driver to the tree.
> 
> It was originally written by mwilder-qcTL/1vZYtiVc3sceRu5cw@public.gmane.org, but cleaned up and
> forward ported by me to the latest kernel version.
> 
> 
> Cc: Phil Hannent <phil-+6o+yPtToBIqdlJmJB21zg@public.gmane.org>
> Cc: <mwilder-qcTL/1vZYtiVc3sceRu5cw@public.gmane.org>
> Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
> 
> ---
>  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

Prefer not to select entire subsystems, but to depend on them.
However, lots of drivers in drivers/input/ 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

> --- /dev/null
> +++ b/drivers/input/misc/mimio.c
> @@ -0,0 +1,913 @@

> +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();

We want comments/explanation on all barriers or just "barrier();" ??

> +	wake_up(&mimio->waitq);
> +}

> +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);

s/64/sizeof(path)/

> +	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;
> +}

---
~Randy
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Input: add mmio xi driver
  2008-09-26  1:20   ` Randy Dunlap
@ 2008-09-26  3:19     ` Greg KH
  2008-09-26 10:51       ` Phil Hannent
  0 siblings, 1 reply; 8+ messages in thread
From: Greg KH @ 2008-09-26  3:19 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: Dmitry Torokhov, linux-input, linux-kernel, linux-usb, phil,
	mwilder

On Thu, Sep 25, 2008 at 06:20:55PM -0700, Randy Dunlap wrote:
> On Thu, 25 Sep 2008 16:22:37 -0700 Greg KH wrote:
> 
> > 
> > From: Greg Kroah-Hartman <gregkh@suse.de>
> > 
> > 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
> 
> Prefer not to select entire subsystems, but to depend on them.
> However, lots of drivers in drivers/input/ select USB...  :(

When in Rome... :)

> > +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();
> 
> We want comments/explanation on all barriers or just "barrier();" ??

Ick, good catch, that shouldn't be needed, I'll go delete it.

> > +	/*
> > +	 * Build input device info
> > +	 */
> > +	usb_make_path(udev, path, 64);
> 
> s/64/sizeof(path)/

Thanks, will fix.

Thanks for the review, I appreciate it.

greg k-h

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Input: add mmio xi driver
  2008-09-26  3:19     ` Greg KH
@ 2008-09-26 10:51       ` Phil Hannent
  2008-09-26 17:46         ` Greg KH
  0 siblings, 1 reply; 8+ messages in thread
From: Phil Hannent @ 2008-09-26 10:51 UTC (permalink / raw)
  To: Greg KH
  Cc: Randy Dunlap, Dmitry Torokhov, linux-input, linux-kernel,
	linux-usb, mwilder

[-- Attachment #1: Type: text/plain, Size: 931 bytes --]

Greg KH wrote:
> On Thu, Sep 25, 2008 at 06:20:55PM -0700, Randy Dunlap wrote:
>> On Thu, 25 Sep 2008 16:22:37 -0700 Greg KH wrote:
>>
>>> From: Greg Kroah-Hartman <gregkh@suse.de>
>>>
>>> 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.
I have been given the protocol document for the whiteboards, I am not allowed to
share it with anybody unfortunately.

I am just waiting for approval of funds for me to start development of this
driver and an X11 library to make the ink capture work.

I expect to start work at the end of October, I could do with a mentor to help
me with this.

Just so you do not get the wrong idea, I plan on sticking around to maintain the
driver once its complete even if its my spare time to do so.

Regards
Phil Hannent



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Input: add mmio xi driver
  2008-09-26 10:51       ` Phil Hannent
@ 2008-09-26 17:46         ` Greg KH
       [not found]           ` <20080926174607.GA700-l3A5Bk7waGM@public.gmane.org>
  0 siblings, 1 reply; 8+ messages in thread
From: Greg KH @ 2008-09-26 17:46 UTC (permalink / raw)
  To: Phil Hannent
  Cc: Randy Dunlap, Dmitry Torokhov, linux-input, linux-kernel,
	linux-usb, mwilder

On Fri, Sep 26, 2008 at 11:51:47AM +0100, Phil Hannent wrote:
> Greg KH wrote:
> > On Thu, Sep 25, 2008 at 06:20:55PM -0700, Randy Dunlap wrote:
> >> On Thu, 25 Sep 2008 16:22:37 -0700 Greg KH wrote:
> >>
> >>> From: Greg Kroah-Hartman <gregkh@suse.de>
> >>>
> >>> 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.
> I have been given the protocol document for the whiteboards, I am not allowed to
> share it with anybody unfortunately.

That's great news, and not that big of a deal about the "no share" issue
as long as you are allowed to contribute.

> I am just waiting for approval of funds for me to start development of this
> driver and an X11 library to make the ink capture work.

Um, what's wrong with the driver that I just posted?  Does it not work
properly?  I'll gladly accept patches for things that are wrong, but
don't start over from scratch please.

> I expect to start work at the end of October, I could do with a mentor to help
> me with this.

If you need help on the kernel side, feel free to contact me off-list.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Input: add mmio xi driver
  2008-09-25 23:22 [PATCH] Input: add mmio xi driver Greg KH
       [not found] ` <20080925232237.GA22938-l3A5Bk7waGM@public.gmane.org>
@ 2008-10-02  6:12 ` Andrew Morton
  1 sibling, 0 replies; 8+ messages in thread
From: Andrew Morton @ 2008-10-02  6:12 UTC (permalink / raw)
  To: Greg KH
  Cc: dmitry.torokhov, linux-input, linux-kernel, linux-usb, phil,
	mwilder

> On Thu, 25 Sep 2008 16:22:37 -0700 Greg KH <gregkh@suse.de> wrote:
> 
> From: Greg Kroah-Hartman <gregkh@suse.de>

Is this true?

> 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.

Oh.  Tricky.
 
>
> ...
>
> +#define isvalidtxsize(n)	((n) > 0 && (n) <= MIMIO_MAXPAYLOAD)

grumble.

- should be written in C

- buggy when passed expresion-with-side-effects.

>
> ...
>
> +static DECLARE_MUTEX(disconnect_sem);

ooh, a semaphore - I remember them.

checkpatch used to warn about newly-added semaphores but a) it broke and
b) this patch doesn't seem to have met checkpatch.

>
> ...
>
> +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 } },
> +	};

I believe that gcc does the right thing here, but an explict `static' would set
minds at ease.



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Input: add mmio xi driver
       [not found]           ` <20080926174607.GA700-l3A5Bk7waGM@public.gmane.org>
@ 2008-11-25  4:19             ` mwilder
  2008-11-25  9:48               ` Phil Hannent
  0 siblings, 1 reply; 8+ messages in thread
From: mwilder @ 2008-11-25  4:19 UTC (permalink / raw)
  To: Greg KH
  Cc: Phil Hannent, Randy Dunlap, Dmitry Torokhov,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA

Hello.  I am the original developer of the mimio Xi driver for 2.4 
kernel linux. I have been observing this particular thread of emails for 
quite some time. I haven't been able to devote much attention to the 
developments in this thread because my primary research emphasis lies 
elsewhere.  Recent events, however, have provoked me to pay close 
attention to this thread.

I would like to thank gregkh-l3A5Bk7waGM@public.gmane.org for his work folding in the 
2.6-specific mods to the driver.  This is something that I do not have the 
time to do, and I am glad to see that he has taken up the slack so 
that others may benefit from this work.

I would like to discuss the following dialog:

> On Fri, Sep 26, 2008 at 11:51:47AM +0100, Phil Hannent wrote:
> > Greg KH wrote:
> > > On Thu, Sep 25, 2008 at 06:20:55PM -0700, Randy Dunlap wrote:
> > >> On Thu, 25 Sep 2008 16:22:37 -0700 Greg KH wrote:
> > >>
> > >>> From: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
> > >>>
> > >>> This patch adds the Mimio Xi interactive whiteboard driver to the tree.
> > >>>
> > >>> It was originally written by mwilder-qcTL/1vZYtiVc3sceRu5cw@public.gmane.org, but cleaned up and
> > >>> forward ported by me to the latest kernel version.
> > I have been given the protocol document for the whiteboards, I am not allowed to
> > share it with anybody unfortunately.
> 
> That's great news, and not that big of a deal about the "no share" issue
> as long as you are allowed to contribute.
> 
> > I am just waiting for approval of funds for me to start development of this
> > driver and an X11 library to make the ink capture work.
> 
> Um, what's wrong with the driver that I just posted?  Does it not work
> properly?  I'll gladly accept patches for things that are wrong, but
> don't start over from scratch please.
> 

> > I expect to start work at the end of October, I could do with a mentor to help
> > me with this.
> 
> If you need help on the kernel side, feel free to contact me off-list.
> 
>

What _is_ wrong with the driver?  I am guessing that phil-U4DcaGvlwG/QXOPxS62xeg@public.gmane.org is 
just struggling with creating X bindings for the module, but I would like 
to hear some elaboration on what is actually happening here.  Enlighten 
me.



--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Input: add mmio xi driver
  2008-11-25  4:19             ` mwilder
@ 2008-11-25  9:48               ` Phil Hannent
  0 siblings, 0 replies; 8+ messages in thread
From: Phil Hannent @ 2008-11-25  9:48 UTC (permalink / raw)
  To: mwilder; +Cc: Greg KH, linux-input, linux-usb

[-- Attachment #1: Type: text/plain, Size: 1293 bytes --]

mwilder wrote:
> What _is_ wrong with the driver?  I am guessing that phil@hannet.co.uk is 
> just struggling with creating X bindings for the module, but I would like 
> to hear some elaboration on what is actually happening here.  Enlighten 
> me.
>   
Hello,

The driver is great, however I have been given the Mimio Xi protocol
documentation and it describes what all of the hex is doing. 
Unfortunately I am not at liberty to share the documentation with
anybody due to an NDA, however I would hope that the code will be fairly
clear as to what's happening as a lot of the protocol hex I have setup
as defines.

The initialisation sequence in the current driver is just a series of
hex codes which I am reimplementing as per the Xi protocol.  Also the
board has on-board flash for the boards layout, dpi and firmware based
upgrade methods.  I am going to implement access to these.

I am also, as you state, working on the X side of things. 

I certainly would not want to tread on your toes with regard to the
development of this driver, however as you had mentioned to me in the
past that you did not have the time to devote to this I decided to move
ahead with it myself.  Are you planing on making changes to the existing
driver?

Regards
Phil Hannent


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2008-11-25  9:57 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-25 23:22 [PATCH] Input: add mmio xi driver Greg KH
     [not found] ` <20080925232237.GA22938-l3A5Bk7waGM@public.gmane.org>
2008-09-26  1:20   ` Randy Dunlap
2008-09-26  3:19     ` Greg KH
2008-09-26 10:51       ` Phil Hannent
2008-09-26 17:46         ` Greg KH
     [not found]           ` <20080926174607.GA700-l3A5Bk7waGM@public.gmane.org>
2008-11-25  4:19             ` mwilder
2008-11-25  9:48               ` Phil Hannent
2008-10-02  6:12 ` Andrew Morton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).