Commit 1d491fec authored by Todd E. Johnson's avatar Todd E. Johnson Committed by Greg Kroah-Hartman

[PATCH] USB: add new USB Touchscreen Driver

I have attached a patch which contains a driver and documentation for
the MicroTouch (14-206) USB Capacitive Touchscreen controller.  It based
on some older code that I have been using for quite some time now (since
2.4.17).  This new version has been completely re-written, and now uses
Linux Input.  Greg, It would be great to possibly get it into 2.6.4.
Please let me know if I have it all wrong...

Unfortunately, the X11 mouse driver only seems capable of handling
relative data rather than absolute.  Hopefully some one will create a
suitable X11 driver capable of accepting absolute data from Linux
Input.  If anyone is aware of one, please let me know.  Otherwise, I
will most likely begin some work on a patch for GPM.

Calibration support will be on the way soon, but I'm not sure of the
best way to implement.  Perhaps some abstract functions could come
available in evdev which can call vendor specific commands for the
calibration within this driver (and perhaps others).
parent d1831727
CHANGES
- Created based off of scanner & INSTALL from the original touchscreen
driver on freshmeat (http://freshmeat.net/projects/3mtouchscreendriver)
- Amended for linux-2.4.18, then 2.4.19
- Complete rewrite using Linux Input in 2.6.3
Unfortunately no calibration support at this time
DRIVER NOTES:
Installation is simple, you only need to add Linux Input, Linux USB, and the
driver to the kernel. The driver can also be optionally built as a module.
If you have another MicroTouch device that you wish to experiment with
or try using this driver with, but the Vendor and Product ID's are not
coded in, don't despair. If the driver was compiled as a module, you can
pass options to the driver. Simply try:
/sbin/modprobe mtouchusb vendor=0x#### product=0x****
If it works, send me the iVendor & iProduct (or a patch) and I will add...
This driver appears to be one of possible 2 Linux USB Input Touchscreen
drivers. Although 3M produces a binary only driver available for
download, I persist in updating this driver since I would like to use the
touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
logical choice is to use Linux Imput.
A little info about the MicroTouch USB controller (14-206):
Y is inverted, and the device has a total possible resolution of 0 - 65535.
Y is inverted by the driver by:
input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC;
input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC;
absmin & absmax are also used to scale the data, sine it is rather high
resolution.
---------------touch screen area-----------------
I MicroTouch (xmax,ymax) @I
I X I
I ########visible monitor area############## I
I #@ (xmin,ymin) # I
I # # I
I # # I
I # # I
I # # I
I # # I
I Y # # I
I # # I
I # # I
I # # I
I # # I
I # # I
I # (xmax,ymax) @# I
I ########################################## I
I I
I@ MicroTouch (xmin,ymin) I
-------------------------------------------------
Currently there is no way to calibrate the device via this driver. Perhaps
at some point an abstract function will be placed into evdev so generic
functions like calibrations, resets, and vendor information can be requested
(And the drivers would handle the vendor specific tasks).
ADDITIONAL INFORMATION/UPDATES:
http://groomlakelabs.com/grandamp/code/microtouch/
TODO:
Implement a control urb again to handle requests to and from the device
such as calibration, etc.
DISCLAMER:
I am not a MicroTouch/3M employee, nor have I ever been. 3M does not support
this driver! If you want touch drivers only supported within X, please go to:
http://www.3m.com/3MTouchSystems/downloads/
...@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_AIPTEK) += input/ ...@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_AIPTEK) += input/
obj-$(CONFIG_USB_HID) += input/ obj-$(CONFIG_USB_HID) += input/
obj-$(CONFIG_USB_KBD) += input/ obj-$(CONFIG_USB_KBD) += input/
obj-$(CONFIG_USB_MOUSE) += input/ obj-$(CONFIG_USB_MOUSE) += input/
obj-$(CONFIG_USB_MTOUCH) += input/
obj-$(CONFIG_USB_WACOM) += input/ obj-$(CONFIG_USB_WACOM) += input/
obj-$(CONFIG_USB_DABUSB) += media/ obj-$(CONFIG_USB_DABUSB) += media/
......
...@@ -179,6 +179,18 @@ config USB_POWERMATE ...@@ -179,6 +179,18 @@ config USB_POWERMATE
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called powermate. module will be called powermate.
config USB_MTOUCH
tristate "MicroTouch USB Touchscreen Driver"
depends on USB && INPUT
---help---
Say Y here if you want to use a MicroTouch (Now 3M) USB
Touchscreen controller.
See <file:Documentation/usb/mtouch.txt> for additional information.
To compile this driver as a module, choose M here: the
module will be called mtouchusb.
config USB_XPAD config USB_XPAD
tristate "X-Box gamepad support" tristate "X-Box gamepad support"
depends on USB && INPUT depends on USB && INPUT
......
...@@ -33,5 +33,6 @@ obj-$(CONFIG_USB_MOUSE) += usbmouse.o ...@@ -33,5 +33,6 @@ obj-$(CONFIG_USB_MOUSE) += usbmouse.o
obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_WACOM) += wacom.o
obj-$(CONFIG_USB_KBTAB) += kbtab.o obj-$(CONFIG_USB_KBTAB) += kbtab.o
obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_POWERMATE) += powermate.o
obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o
obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_XPAD) += xpad.o
obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o
/******************************************************************************
* mtouchusb.c -- Driver for Microtouch (Now 3M) USB Touchscreens
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Based upon original work by Radoslaw Garbacz (usb-support@ite.pl)
* (http://freshmeat.net/projects/3mtouchscreendriver)
*
* History
*
* 0.3 & 0.4 2002 (TEJ) tejohnson@yahoo.com
* Updated to 2.4.18, then 2.4.19
* Old version still relied on stealing a minor
*
* 0.5 02/26/2004 (TEJ) tejohnson@yahoo.com
* Complete rewrite using Linux Input in 2.6.3
* Unfortunately no calibration support at this time
*
*****************************************************************************/
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
#define MTOUCHUSB_MIN_XC 0xc8
#define MTOUCHUSB_MAX_XC 0xff78
#define MTOUCHUSB_XC_FUZZ 0x0
#define MTOUCHUSB_XC_FLAT 0x0
#define MTOUCHUSB_MIN_YC 0x0
#define MTOUCHUSB_MAX_YC 0xff78
#define MTOUCHUSB_YC_FUZZ 0x0
#define MTOUCHUSB_YC_FLAT 0x0
#define MTOUCHUSB_ASYC_REPORT 1
#define MTOUCHUSB_REPORT_SIZE_DATA 11
#define MTOUCHUSB_REQ_CTRLLR_ID 10
#define MTOUCHUSB_GET_XC(data) (data[4]<<8 | data[3])
#define MTOUCHUSB_GET_YC(data) (data[6]<<8 | data[5])
#define MTOUCHUSB_GET_TOUCHED(data) ((data[2] & 0x40) ? 1:0)
#define DRIVER_VERSION "v0.1"
#define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com"
#define DRIVER_DESC "Microtouch USB HID Touchscreen Driver"
struct mtouch_usb {
unsigned char *data;
dma_addr_t data_dma;
struct urb *irq;
struct usb_device *udev;
struct input_dev input;
int open;
char name[128];
char phys[64];
};
static __s32 vendor=-1, product=-1;
static struct usb_device_id mtouchusb_devices [] = {
{ USB_DEVICE(0x0596, 0x0001) }, /* 3M (Formerly MicroTouch) 14-206 */
{ } /* Terminating entry */
};
static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
{
struct mtouch_usb *mtouch = urb->context;
int retval;
switch (urb->status) {
case 0:
/* success */
break;
case -ETIMEDOUT:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
__FUNCTION__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d",
__FUNCTION__, urb->status);
goto exit;
}
input_regs(&mtouch->input, regs);
input_report_key(&mtouch->input, BTN_TOUCH,
MTOUCHUSB_GET_TOUCHED(mtouch->data));
input_report_abs(&mtouch->input, ABS_X,
MTOUCHUSB_GET_XC(mtouch->data));
input_report_abs(&mtouch->input, ABS_Y,
MTOUCHUSB_GET_YC(mtouch->data));
input_sync(&mtouch->input);
exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result: %d",
__FUNCTION__, retval);
}
static int mtouchusb_open (struct input_dev *input)
{
struct mtouch_usb *mtouch = input->private;
if (mtouch->open++)
return 0;
mtouch->irq->dev = mtouch->udev;
if (usb_submit_urb (mtouch->irq, GFP_ATOMIC))
return -EIO;
return 0;
}
static void mtouchusb_close (struct input_dev *input)
{
struct mtouch_usb *mtouch = input->private;
if (!--mtouch->open)
usb_unlink_urb (mtouch->irq);
}
static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
{
dbg("%s - called", __FUNCTION__);
mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_SIZE_DATA,
SLAB_ATOMIC, &mtouch->data_dma);
if (!mtouch->data)
return -1;
return 0;
}
static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
{
dbg("%s - called", __FUNCTION__);
if (mtouch->data)
usb_buffer_free(udev, MTOUCHUSB_REPORT_SIZE_DATA,
mtouch->data, mtouch->data_dma);
}
static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
dbg("%s - called", __FUNCTION__);
struct mtouch_usb *mtouch;
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev (intf);
char path[64];
char *buf;
int nRet;
int ix;
char valid_device = 0;
if (vendor != -1 && product != -1) {
info("%s - User specified USB Touch -- Vend:Prod - %x:%x",
__FUNCTION__, vendor, product);
}
for (ix = 0; ix < sizeof (mtouchusb_devices) /
sizeof (struct usb_device_id); ix++) {
if ((udev->descriptor.idVendor ==
mtouchusb_devices [ix].idVendor) &&
(udev->descriptor.idProduct ==
mtouchusb_devices [ix].idProduct)) {
valid_device = 1;
break;
}
}
if (udev->descriptor.idVendor == vendor &&
udev->descriptor.idProduct == product) { /* User specified */
valid_device = 1;
}
if (!valid_device) {
err("%s - No valid device!", __FUNCTION__);
return -EIO;
}
if (udev->descriptor.bNumConfigurations != 1) {
err("%s - Only one device configuration is supported.",
__FUNCTION__);
return -EIO;
}
dbg("%s - setting interface", __FUNCTION__);
interface = &intf->altsetting[intf->act_altsetting];
dbg("%s - setting endpoint", __FUNCTION__);
endpoint = &interface->endpoint[0].desc;
if (interface->desc.bNumEndpoints != 1) {
err("%s - Only one endpoint is supported.", __FUNCTION__);
return -EIO;
}
if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) {
err("%s - Out of memory.", __FUNCTION__);
return -ENOMEM;
}
memset(mtouch, 0, sizeof(struct mtouch_usb));
mtouch->udev = udev;
dbg("%s - allocating buffers", __FUNCTION__);
if (mtouchusb_alloc_buffers(udev, mtouch)) {
mtouchusb_free_buffers(udev, mtouch);
kfree(mtouch);
return -ENOMEM;
}
mtouch->input.private = mtouch;
mtouch->input.open = mtouchusb_open;
mtouch->input.close = mtouchusb_close;
usb_make_path(udev, path, 64);
sprintf(mtouch->phys, "%s/input0", path);
mtouch->input.name = mtouch->name;
mtouch->input.phys = mtouch->phys;
mtouch->input.id.bustype = BUS_USB;
mtouch->input.id.vendor = udev->descriptor.idVendor;
mtouch->input.id.product = udev->descriptor.idProduct;
mtouch->input.id.version = udev->descriptor.bcdDevice;
mtouch->input.dev = &intf->dev;
mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
/* Used to Scale Compensated Data and Flip Y */
mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC;
mtouch->input.absmax[ABS_X] = MTOUCHUSB_MAX_XC;
mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC;
mtouch->input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC;
mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
if (!(buf = kmalloc(63, GFP_KERNEL))) {
kfree(mtouch);
return -ENOMEM;
}
if (udev->descriptor.iManufacturer &&
usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0)
strcat(mtouch->name, buf);
if (udev->descriptor.iProduct &&
usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0)
sprintf(mtouch->name, "%s %s", mtouch->name, buf);
if (!strlen(mtouch->name))
sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
mtouch->input.id.vendor, mtouch->input.id.product);
kfree(buf);
nRet = usb_control_msg(mtouch->udev,
usb_rcvctrlpipe(udev, 0x80),
USB_REQ_GET_CONFIGURATION,
USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
0,
0x81,
NULL,
0,
HZ * USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - USB_REQ_GET_CONFIGURATION - bytes|err: %d",
__FUNCTION__, nRet);
dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!mtouch->irq) {
dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
mtouchusb_free_buffers(udev, mtouch);
kfree(mtouch);
return -ENOMEM;
}
dbg("%s - usb_fill_int_urb", __FUNCTION__);
usb_fill_int_urb(mtouch->irq,
mtouch->udev,
usb_rcvintpipe(mtouch->udev, 0x81),
mtouch->data,
MTOUCHUSB_REPORT_SIZE_DATA,
mtouchusb_irq,
mtouch,
endpoint->bInterval);
dbg("%s - input_register_device", __FUNCTION__);
input_register_device(&mtouch->input);
nRet = usb_control_msg(mtouch->udev,
usb_rcvctrlpipe(udev, 0x80),
MTOUCHUSB_ASYC_REPORT,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
MTOUCHUSB_ASYC_REPORT,
MTOUCHUSB_ASYC_REPORT,
NULL,
0,
HZ * USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - MTOUCHUSB_ASYC_REPORT - bytes|err: %d",
__FUNCTION__, nRet);
printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
usb_set_intfdata(intf, mtouch);
return 0;
}
static void mtouchusb_disconnect(struct usb_interface *intf)
{
struct mtouch_usb *mtouch = usb_get_intfdata (intf);
dbg("%s - called", __FUNCTION__);
usb_set_intfdata(intf, NULL);
if (mtouch) {
dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
usb_unlink_urb(mtouch->irq);
input_unregister_device(&mtouch->input);
usb_free_urb(mtouch->irq);
mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
kfree(mtouch);
}
}
MODULE_DEVICE_TABLE (usb, mtouchusb_devices);
static struct usb_driver mtouchusb_driver = {
.owner = THIS_MODULE,
.name = "mtouchusb",
.probe = mtouchusb_probe,
.disconnect = mtouchusb_disconnect,
.id_table = mtouchusb_devices,
};
static int __init mtouchusb_init(void) {
dbg("%s - called", __FUNCTION__);
return usb_register(&mtouchusb_driver);
}
static void __exit mtouchusb_cleanup(void) {
dbg("%s - called", __FUNCTION__);
usb_deregister(&mtouchusb_driver);
}
module_init(mtouchusb_init);
module_exit(mtouchusb_cleanup);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
MODULE_PARM(vendor, "i");
MODULE_PARM_DESC(vendor, "User specified USB idVendor");
MODULE_PARM(product, "i");
MODULE_PARM_DESC(product, "User specified USB idProduct");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment