Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5d892665 authored by Daniel Ritz's avatar Daniel Ritz Committed by Greg Kroah-Hartman
Browse files

usbtouchscreen: version 0.4



changes over 0.3:
- some more eGalax device IDs (from eGalax driver/spec)
- return the error code in probe()
- 3M/MTouch init fixes, tested by Don Alexander
- eGalax fixes for bugs in multi-packet handling, spottet by Pieter Grimmerink
- support for some eTurboTouch devices, mostly by Pieter Grimmerink
- support for Gunze AHL61 controller (untested, but simple enough)

Signed-off-by: default avatarDaniel Ritz <daniel.ritz@gmx.ch>
Cc: Pieter Grimmerink <p.grimmerink@inepro.com>
Cc: Don Alexander <debug@roosoft.ltd.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d388dab7
Loading
Loading
Loading
Loading
+16 −4
Original line number Diff line number Diff line
@@ -205,10 +205,12 @@ config USB_TOUCHSCREEN
	depends on USB && INPUT
	---help---
	  USB Touchscreen driver for:
	  - eGalax Touchkit USB
	  - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
	  - PanJit TouchSet USB
	  - 3M MicroTouch USB
	  - 3M MicroTouch USB (EX II series)
	  - ITM
	  - some other eTurboTouch
	  - Gunze AHL61

	  Have a look at <http://linux.chapter7.ch/touchkit/> for
	  a usage description and the required user-space stuff.
@@ -218,7 +220,7 @@ config USB_TOUCHSCREEN

config USB_TOUCHSCREEN_EGALAX
	default y
	bool "eGalax device support" if EMBEDDED
	bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
	depends on USB_TOUCHSCREEN

config USB_TOUCHSCREEN_PANJIT
@@ -228,7 +230,7 @@ config USB_TOUCHSCREEN_PANJIT

config USB_TOUCHSCREEN_3M
	default y
	bool "3M/Microtouch device support" if EMBEDDED
	bool "3M/Microtouch EX II series device support" if EMBEDDED
	depends on USB_TOUCHSCREEN

config USB_TOUCHSCREEN_ITM
@@ -236,6 +238,16 @@ config USB_TOUCHSCREEN_ITM
	bool "ITM device support" if EMBEDDED
	depends on USB_TOUCHSCREEN

config USB_TOUCHSCREEN_ETURBO
	default y
	bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
	depends on USB_TOUCHSCREEN

config USB_TOUCHSCREEN_GUNZE
	default y
	bool "Gunze AHL61 device support" if EMBEDDED
	depends on USB_TOUCHSCREEN

config USB_YEALINK
	tristate "Yealink usb-p1k voip phone"
	depends on USB && INPUT && EXPERIMENTAL
+203 −80
Original line number Diff line number Diff line
@@ -2,9 +2,12 @@
 * usbtouchscreen.c
 * Driver for USB Touchscreens, supporting those devices:
 *  - eGalax Touchkit
 *  - 3M/Microtouch
 *    includes eTurboTouch CT-410/510/700
 *  - 3M/Microtouch  EX II series
 *  - ITM
 *  - PanJit TouchSet
 *  - eTurboTouch
 *  - Gunze AHL61
 *
 * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch>
 * Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -42,7 +45,7 @@
#include <linux/usb/input.h>


#define DRIVER_VERSION		"v0.3"
#define DRIVER_VERSION		"v0.4"
#define DRIVER_AUTHOR		"Daniel Ritz <daniel.ritz@gmx.ch>"
#define DRIVER_DESC		"USB Touchscreen Driver"

@@ -60,6 +63,7 @@ struct usbtouch_device_info {
	int flags;

	void (*process_pkt) (struct usbtouch_usb *usbtouch, struct pt_regs *regs, unsigned char *pkt, int len);
	int  (*get_pkt_len) (unsigned char *pkt, int len);
	int  (*read_data)   (unsigned char *pkt, int *x, int *y, int *touch, int *press);
	int  (*init)        (struct usbtouch_usb *usbtouch);
};
@@ -81,8 +85,16 @@ struct usbtouch_usb {
	char phys[64];
};

static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
                                 struct pt_regs *regs, unsigned char *pkt, int len);

#if defined(CONFIG_USB_TOUCHSCREEN_EGALAX) || defined(CONFIG_USB_TOUCHSCREEN_ETURBO)
#define MULTI_PACKET
#endif

#ifdef MULTI_PACKET
static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
                                   struct pt_regs *regs,
                                   unsigned char *pkt, int len);
#endif

/* device types */
enum {
@@ -91,14 +103,19 @@ enum {
	DEVTYPE_PANJIT,
	DEVTYPE_3M,
	DEVTYPE_ITM,
	DEVTYPE_ETURBO,
	DEVTYPE_GUNZE,
};

static struct usb_device_id usbtouch_devices[] = {
#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX
	{USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
	{USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
	{USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
	{USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
	{USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
	{USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
	{USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
#endif

#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT
@@ -116,6 +133,14 @@ static struct usb_device_id usbtouch_devices[] = {
	{USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
#endif

#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
	{USB_DEVICE(0x1234, 0x5678), .driver_info = DEVTYPE_ETURBO},
#endif

#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
	{USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE},
#endif

	{}
};

@@ -140,82 +165,23 @@ static int egalax_read_data(unsigned char *pkt, int *x, int *y, int *touch, int
	*touch = pkt[0] & 0x01;

	return 1;

}

static int egalax_get_pkt_len(unsigned char *buf)
static int egalax_get_pkt_len(unsigned char *buf, int len)
{
	switch (buf[0] & EGALAX_PKT_TYPE_MASK) {
	case EGALAX_PKT_TYPE_REPT:
		return 5;

	case EGALAX_PKT_TYPE_DIAG:
		if (len < 2)
			return -1;

		return buf[1] + 2;
	}

	return 0;
}

static void egalax_process(struct usbtouch_usb *usbtouch, struct pt_regs *regs,
                           unsigned char *pkt, int len)
{
	unsigned char *buffer;
	int pkt_len, buf_len, pos;

	/* if the buffer contains data, append */
	if (unlikely(usbtouch->buf_len)) {
		int tmp;

		/* if only 1 byte in buffer, add another one to get length */
		if (usbtouch->buf_len == 1)
			usbtouch->buffer[1] = pkt[0];

		pkt_len = egalax_get_pkt_len(usbtouch->buffer);

		/* unknown packet: drop everything */
		if (!pkt_len)
			return;

		/* append, process */
		tmp = pkt_len - usbtouch->buf_len;
		memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
		usbtouch_process_pkt(usbtouch, regs, usbtouch->buffer, pkt_len);

		buffer = pkt + tmp;
		buf_len = len - tmp;
	} else {
		buffer = pkt;
		buf_len = len;
	}

	/* only one byte left in buffer */
	if (unlikely(buf_len == 1)) {
		usbtouch->buffer[0] = buffer[0];
		usbtouch->buf_len = 1;
		return;
	}

	/* loop over the buffer */
	pos = 0;
	while (pos < buf_len) {
		/* get packet len */
		pkt_len = egalax_get_pkt_len(buffer + pos);

		/* unknown packet: drop everything */
		if (unlikely(!pkt_len))
			return;

		/* full packet: process */
		if (likely(pkt_len <= buf_len)) {
			usbtouch_process_pkt(usbtouch, regs, buffer + pos, pkt_len);
		} else {
			/* incomplete packet: save in buffer */
			memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
			usbtouch->buf_len = buf_len - pos;
		}
		pos += pkt_len;
	}
}
#endif


@@ -254,7 +220,7 @@ static int mtouch_read_data(unsigned char *pkt, int *x, int *y, int *touch, int

static int mtouch_init(struct usbtouch_usb *usbtouch)
{
	int ret;
	int ret, i;

	ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
	                      MTOUCHUSB_RESET,
@@ -264,15 +230,20 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
	    __FUNCTION__, ret);
	if (ret < 0)
		return ret;
	msleep(150);

	for (i = 0; i < 3; i++) {
		ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
				      MTOUCHUSB_ASYNC_REPORT,
				      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				      1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
		dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
		    __FUNCTION__, ret);
	if (ret < 0)
		if (ret >= 0)
			break;
		if (ret != -EPIPE)
			return ret;
	}

	return 0;
}
@@ -295,6 +266,54 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr
#endif


/*****************************************************************************
 * eTurboTouch part
 */
#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
static int eturbo_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
{
	unsigned int shift;

	/* packets should start with sync */
	if (!(pkt[0] & 0x80))
		return 0;

	shift = (6 - (pkt[0] & 0x03));
	*x = ((pkt[3] << 7) | pkt[4]) >> shift;
	*y = ((pkt[1] << 7) | pkt[2]) >> shift;
	*touch = (pkt[0] & 0x10) ? 1 : 0;

	return 1;
}

static int eturbo_get_pkt_len(unsigned char *buf, int len)
{
	if (buf[0] & 0x80)
		return 5;
	if (buf[0] == 0x01)
		return 3;
	return 0;
}
#endif


/*****************************************************************************
 * Gunze part
 */
#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
static int gunze_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
{
	if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80))
		return 0;

	*x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
	*y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
	*touch = pkt[0] & 0x20;

	return 1;
}
#endif

/*****************************************************************************
 * the different device descriptors
 */
@@ -307,7 +326,8 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
		.max_yc		= 0x07ff,
		.rept_size	= 16,
		.flags		= USBTOUCH_FLG_BUFFER,
		.process_pkt	= egalax_process,
		.process_pkt	= usbtouch_process_multi,
		.get_pkt_len	= egalax_get_pkt_len,
		.read_data	= egalax_read_data,
	},
#endif
@@ -346,6 +366,31 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
		.read_data	= itm_read_data,
	},
#endif

#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
	[DEVTYPE_ETURBO] = {
		.min_xc		= 0x0,
		.max_xc		= 0x07ff,
		.min_yc		= 0x0,
		.max_yc		= 0x07ff,
		.rept_size	= 8,
		.flags		= USBTOUCH_FLG_BUFFER,
		.process_pkt	= usbtouch_process_multi,
		.get_pkt_len	= eturbo_get_pkt_len,
		.read_data	= eturbo_read_data,
	},
#endif

#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
	[DEVTYPE_GUNZE] = {
		.min_xc		= 0x0,
		.max_xc		= 0x0fff,
		.min_yc		= 0x0,
		.max_yc		= 0x0fff,
		.rept_size	= 4,
		.read_data	= gunze_read_data,
	},
#endif
};


@@ -377,6 +422,83 @@ static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
}


#ifdef MULTI_PACKET
static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
                                   struct pt_regs *regs,
                                   unsigned char *pkt, int len)
{
	unsigned char *buffer;
	int pkt_len, pos, buf_len, tmp;

	/* process buffer */
	if (unlikely(usbtouch->buf_len)) {
		/* try to get size */
		pkt_len = usbtouch->type->get_pkt_len(
				usbtouch->buffer, usbtouch->buf_len);

		/* drop? */
		if (unlikely(!pkt_len))
			goto out_flush_buf;

		/* need to append -pkt_len bytes before able to get size */
		if (unlikely(pkt_len < 0)) {
			int append = -pkt_len;
			if (unlikely(append > len))
			       append = len;
			if (usbtouch->buf_len + append >= usbtouch->type->rept_size)
				goto out_flush_buf;
			memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, append);
			usbtouch->buf_len += append;

			pkt_len = usbtouch->type->get_pkt_len(
					usbtouch->buffer, usbtouch->buf_len);
			if (pkt_len < 0)
				return;
		}

		/* append */
		tmp = pkt_len - usbtouch->buf_len;
		if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size)
			goto out_flush_buf;
		memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
		usbtouch_process_pkt(usbtouch, regs, usbtouch->buffer, pkt_len);

		buffer = pkt + tmp;
		buf_len = len - tmp;
	} else {
		buffer = pkt;
		buf_len = len;
	}

	/* loop over the received packet, process */
	pos = 0;
	while (pos < buf_len) {
		/* get packet len */
		pkt_len = usbtouch->type->get_pkt_len(buffer + pos, len);

		/* unknown packet: drop everything */
		if (unlikely(!pkt_len))
			goto out_flush_buf;

		/* full packet: process */
		if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
			usbtouch_process_pkt(usbtouch, regs, buffer + pos, pkt_len);
		} else {
			/* incomplete packet: save in buffer */
			memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
			usbtouch->buf_len = buf_len - pos;
			return;
		}
		pos += pkt_len;
	}

out_flush_buf:
	usbtouch->buf_len = 0;
	return;
}
#endif


static void usbtouch_irq(struct urb *urb, struct pt_regs *regs)
{
	struct usbtouch_usb *usbtouch = urb->context;
@@ -452,7 +574,7 @@ static int usbtouch_probe(struct usb_interface *intf,
	struct usb_endpoint_descriptor *endpoint;
	struct usb_device *udev = interface_to_usbdev(intf);
	struct usbtouch_device_info *type;
	int err;
	int err = -ENOMEM;

	interface = intf->cur_altsetting;
	endpoint = &interface->endpoint[0].desc;
@@ -526,6 +648,7 @@ static int usbtouch_probe(struct usb_interface *intf,
			 usbtouch->data, type->rept_size,
			 usbtouch_irq, usbtouch, endpoint->bInterval);

	usbtouch->irq->dev = usbtouch->udev;
	usbtouch->irq->transfer_dma = usbtouch->data_dma;
	usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

@@ -553,7 +676,7 @@ static int usbtouch_probe(struct usb_interface *intf,
out_free:
	input_free_device(input_dev);
	kfree(usbtouch);
	return -ENOMEM;
	return err;
}

static void usbtouch_disconnect(struct usb_interface *intf)