Merge branch 'backport'

dbg removed

Conflicts:
	README
	hanvon.c
This commit is contained in:
ond 2014-01-27 11:05:12 +01:00
commit b4570bf14b
2 changed files with 115 additions and 96 deletions

30
README
View File

@ -1,17 +1,21 @@
Hanvon tablet driver
====================
Linux kernel driver for some Hanvon tablet usb models. Following functionality
is covered. pen coordinates, touch/float/click detection, pressure, x and y
tilt, pen button. On Artmaster I four simple tablet buttons (note that the first
Driver for Linux kernels which supports complete functionality of the tablet:
pen coordinates, touch/float/click detection, pressure, x and y tilt, pen
button. On Artmaster I four simple tablet buttons (note that the first
one works only together with pen activity), and the slider button.
Supported hardware
==================
Artmaster I: AM0605, AM0806, AM1107, AM1209
Rollick: RL0604
AM3M, AM0806, AM0605, AM1107, AM1209
RL0604, RL0504
GP0806, GP0605, GP0504
NXS1315
AM - Artmaster I, RL - Rollick, GP - GraphicPal, NXS - Nilox
Installation
@ -25,14 +29,10 @@ insmod ./hanvon.ko
If everything goes right the tablet should start working immediately.
Revision history
================
Diagnostics
===========
0.0.1 - initial release
0.2 - corrected pressure detection, working slider button
0.3 - remaining buttons also working, added x and y tilting
0.3b - patch for AM1209 from Markus Zucker applied
0.3c - patch for AM1107 from Daniel Koch applied
0.3d - support for right side buttons of AM1107 and AM1209
0.4 - code cleanup, RL0604 patch from Daniel Clemmer
0.5 - code cleanup, AM0605 support
After insmod, check with dmesg, if the module was loaded properly.
"USB Hanvon tablet driver" should appear in the listing.
lsmod should also contain hanvon in its listing: lsmod | grep hanvon

181
hanvon.c
View File

@ -3,7 +3,9 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <asm/unaligned.h>
#define DRIVER_VERSION "0.5"
#define DRIVER_AUTHOR "Ondra Havel <ondra.havel@gmail.com>"
#define DRIVER_DESC "USB Hanvon tablet driver"
#define DRIVER_LICENSE "GPL"
@ -13,19 +15,24 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_HANVON 0x0b57
#define USB_AM_PACKET_LEN 10
#define USB_PRODUCT_ID_AM0605 0x8503
#define USB_PRODUCT_ID_AM3M 0x8528
#define USB_PRODUCT_ID_AM0806 0x8502
#define USB_PRODUCT_ID_AM0605 0x8503
#define USB_PRODUCT_ID_AM1107 0x8505
#define USB_PRODUCT_ID_AM1209 0x8501
#define USB_PRODUCT_ID_RL0604 0x851f
#define USB_PRODUCT_ID_GP0605A 0x803a
#define USB_PRODUCT_ID_RL0504 0x851d
#define USB_PRODUCT_ID_GP0806 0x8039
#define USB_PRODUCT_ID_GP0806B 0x8511
#define USB_PRODUCT_ID_GP0605 0x8512
#define USB_PRODUCT_ID_GP0605A 0x803a
#define USB_PRODUCT_ID_GP0504 0x8037
#define USB_PRODUCT_ID_NXS1513 0x8030
/* reported on all AMs */
static int lbuttons[] = {BTN_0, BTN_1, BTN_2, BTN_3};
/* reported on AM1107+ */
static int rbuttons[] = {BTN_4, BTN_5, BTN_6, BTN_7};
#define USB_AM_PACKET_LEN 10
static int lbuttons[]={BTN_0,BTN_1,BTN_2,BTN_3}; /* reported on all AMs */
static int rbuttons[]={BTN_4,BTN_5,BTN_6,BTN_7}; /* reported on AM1107+ */
#define AM_WHEEL_THRESHOLD 4
@ -45,20 +52,18 @@ struct hanvon {
char phys[32];
};
static void report_buttons(struct hanvon *hanvon,
int buttons[], unsigned char dta)
static void report_buttons(struct hanvon *hanvon, int buttons[],unsigned char dta)
{
struct input_dev *dev = hanvon->dev;
if ((dta & 0xf0) == 0xa0) {
if((dta & 0xf0) == 0xa0) {
input_report_key(dev, buttons[1], dta & 0x02);
input_report_key(dev, buttons[2], dta & 0x04);
input_report_key(dev, buttons[3], dta & 0x08);
} else {
if (dta <= 0x3f) { /* slider area active */
if(dta <= 0x3f) { /* slider area active */
int diff = dta - hanvon->old_wheel_pos;
/* detect new/continue old move */
if (abs(diff) < AM_WHEEL_THRESHOLD)
if(abs(diff) < AM_WHEEL_THRESHOLD)
input_report_rel(dev, REL_WHEEL, diff);
hanvon->old_wheel_pos = dta;
@ -71,64 +76,69 @@ static void hanvon_irq(struct urb *urb)
struct hanvon *hanvon = urb->context;
unsigned char *data = hanvon->data;
struct input_dev *dev = hanvon->dev;
int ret;
int retval;
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
return;
default:
goto exit;
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
printk("%s - urb shutting down with status: %d", __func__, urb->status);
return;
default:
printk("%s - nonzero urb status received: %d", __func__, urb->status);
goto exit;
}
switch (data[0]) {
case 0x01: /* button press */
if (data[1] == 0x55) /* left side */
report_buttons(hanvon, lbuttons, data[2]);
switch(data[0]) {
case 0x01: /* button press */
if(data[1]==0x55) /* left side */
report_buttons(hanvon,lbuttons,data[2]);
if (data[3] == 0xaa) /* right side (am1107, am1209) */
report_buttons(hanvon, rbuttons, data[4]);
if(data[3]==0xaa) /* right side (am1107, am1209) */
report_buttons(hanvon,rbuttons,data[4]);
break;
case 0x02: /* position change */
if((data[1] & 0xf0) != 0) {
input_report_abs(dev, ABS_X, get_unaligned_be16(&data[2]));
input_report_abs(dev, ABS_Y, get_unaligned_be16(&data[4]));
input_report_abs(dev, ABS_TILT_X, data[7] & 0x3f);
input_report_abs(dev, ABS_TILT_Y, data[8]);
input_report_abs(dev, ABS_PRESSURE, get_unaligned_be16(&data[6])>>6);
}
input_report_key(dev, BTN_LEFT, data[1] & 0x1);
input_report_key(dev, BTN_RIGHT, data[1] & 0x2); /* stylus button pressed (right click) */
input_report_key(dev, lbuttons[0], data[1] & 0x20);
break;
case 0x02: /* position change */
if ((data[1] & 0xf0) != 0) {
input_report_abs(dev, ABS_X,
be16_to_cpup((__be16 *)&data[2]));
input_report_abs(dev, ABS_Y,
be16_to_cpup((__be16 *)&data[4]));
input_report_abs(dev, ABS_TILT_X, data[7] & 0x3f);
input_report_abs(dev, ABS_TILT_Y, data[8]);
input_report_abs(dev, ABS_PRESSURE,
be16_to_cpup((__be16 *)&data[6])>>6);
}
input_report_key(dev, BTN_LEFT, data[1] & 0x1);
/* stylus button pressed (right click) */
input_report_key(dev, BTN_RIGHT, data[1] & 0x2);
input_report_key(dev, lbuttons[0], data[1] & 0x20);
break;
}
input_sync(dev);
exit:
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret)
err("%s - usb_submit_urb failed with result %d",
__func__, ret);
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
printk("%s - usb_submit_urb failed with result %d", __func__, retval);
}
static struct usb_device_id hanvon_ids[] = {
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_AM3M) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_AM1209) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_AM1107) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_AM0806) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_AM0605) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_RL0604) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_RL0504) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_GP0806) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_GP0806B) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_GP0605) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_GP0605A) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_GP0504) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_NXS1513) },
{ }
};
@ -153,8 +163,7 @@ static void hanvon_close(struct input_dev *dev)
usb_kill_urb(hanvon->irq);
}
static int hanvon_probe(struct usb_interface *intf,
const struct usb_device_id *id)
static int hanvon_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_endpoint_descriptor *endpoint;
@ -167,8 +176,7 @@ static int hanvon_probe(struct usb_interface *intf,
if (!hanvon || !input_dev)
goto fail1;
hanvon->data = usb_alloc_coherent(dev,
USB_AM_PACKET_LEN, GFP_KERNEL, &hanvon->data_dma);
hanvon->data = (unsigned char *)usb_alloc_coherent(dev, USB_AM_PACKET_LEN, GFP_KERNEL, &hanvon->data_dma);
if (!hanvon->data)
goto fail1;
@ -192,26 +200,19 @@ static int hanvon_probe(struct usb_interface *intf,
input_dev->open = hanvon_open;
input_dev->close = hanvon_close;
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_REL, input_dev->evbit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_RIGHT, input_dev->keybit);
for (i = 0; i < sizeof(lbuttons) / sizeof(lbuttons[0]); i++)
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT_MASK(EV_REL);
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOUCH);
input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
for(i=0;i<sizeof(lbuttons)/sizeof(lbuttons[0]);i++)
__set_bit(lbuttons[i], input_dev->keybit);
for (i = 0; i < sizeof(rbuttons) / sizeof(rbuttons[0]); i++)
for(i=0;i<sizeof(rbuttons)/sizeof(rbuttons[0]);i++)
__set_bit(rbuttons[i], input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, 0, AM_MAX_ABS_X, 4, 0);
input_set_abs_params(input_dev, ABS_Y, 0, AM_MAX_ABS_Y, 4, 0);
input_set_abs_params(input_dev, ABS_TILT_X,
0, AM_MAX_TILT_X, 0, 0);
input_set_abs_params(input_dev, ABS_TILT_Y,
0, AM_MAX_TILT_Y, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE,
0, AM_MAX_PRESSURE, 0, 0);
input_set_abs_params(input_dev, ABS_TILT_X, 0, AM_MAX_TILT_X, 0, 0);
input_set_abs_params(input_dev, ABS_TILT_Y, 0, AM_MAX_TILT_Y, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, AM_MAX_PRESSURE, 0, 0);
input_set_capability(input_dev, EV_REL, REL_WHEEL);
endpoint = &intf->cur_altsetting->endpoint[0].desc;
@ -223,17 +224,15 @@ static int hanvon_probe(struct usb_interface *intf,
hanvon->irq->transfer_dma = hanvon->data_dma;
hanvon->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_set_intfdata(intf, hanvon);
error = input_register_device(hanvon->dev);
if (error)
goto fail3;
usb_set_intfdata(intf, hanvon);
return 0;
fail3: usb_free_urb(hanvon->irq);
fail2: usb_free_coherent(dev, USB_AM_PACKET_LEN,
hanvon->data, hanvon->data_dma);
fail2: usb_free_coherent(dev, USB_AM_PACKET_LEN, hanvon->data, hanvon->data_dma);
fail1: input_free_device(input_dev);
kfree(hanvon);
return error;
@ -243,12 +242,14 @@ static void hanvon_disconnect(struct usb_interface *intf)
{
struct hanvon *hanvon = usb_get_intfdata(intf);
input_unregister_device(hanvon->dev);
usb_free_urb(hanvon->irq);
usb_free_coherent(interface_to_usbdev(intf),
USB_AM_PACKET_LEN, hanvon->data, hanvon->data_dma);
kfree(hanvon);
usb_set_intfdata(intf, NULL);
if (hanvon) {
usb_kill_urb(hanvon->irq);
input_unregister_device(hanvon->dev);
usb_free_urb(hanvon->irq);
usb_free_coherent(interface_to_usbdev(intf), USB_AM_PACKET_LEN, hanvon->data, hanvon->data_dma);
kfree(hanvon);
}
}
static struct usb_driver hanvon_driver = {
@ -258,4 +259,22 @@ static struct usb_driver hanvon_driver = {
.id_table = hanvon_ids,
};
module_usb_driver(hanvon_driver);
static int __init hanvon_init(void)
{
int rv;
if((rv = usb_register(&hanvon_driver)) != 0)
return rv;
printk(DRIVER_DESC " " DRIVER_VERSION "\n");
return 0;
}
static void __exit hanvon_exit(void)
{
usb_deregister(&hanvon_driver);
}
module_init(hanvon_init);
module_exit(hanvon_exit);