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

181
hanvon.c
View File

@ -3,7 +3,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/usb/input.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_AUTHOR "Ondra Havel <ondra.havel@gmail.com>"
#define DRIVER_DESC "USB Hanvon tablet driver" #define DRIVER_DESC "USB Hanvon tablet driver"
#define DRIVER_LICENSE "GPL" #define DRIVER_LICENSE "GPL"
@ -13,19 +15,24 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE); MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_HANVON 0x0b57 #define USB_VENDOR_ID_HANVON 0x0b57
#define USB_AM_PACKET_LEN 10 #define USB_PRODUCT_ID_AM3M 0x8528
#define USB_PRODUCT_ID_AM0605 0x8503
#define USB_PRODUCT_ID_AM0806 0x8502 #define USB_PRODUCT_ID_AM0806 0x8502
#define USB_PRODUCT_ID_AM0605 0x8503
#define USB_PRODUCT_ID_AM1107 0x8505 #define USB_PRODUCT_ID_AM1107 0x8505
#define USB_PRODUCT_ID_AM1209 0x8501 #define USB_PRODUCT_ID_AM1209 0x8501
#define USB_PRODUCT_ID_RL0604 0x851f #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 */ #define USB_AM_PACKET_LEN 10
static int lbuttons[] = {BTN_0, BTN_1, BTN_2, BTN_3};
/* reported on AM1107+ */ 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}; static int rbuttons[]={BTN_4,BTN_5,BTN_6,BTN_7}; /* reported on AM1107+ */
#define AM_WHEEL_THRESHOLD 4 #define AM_WHEEL_THRESHOLD 4
@ -45,20 +52,18 @@ struct hanvon {
char phys[32]; char phys[32];
}; };
static void report_buttons(struct hanvon *hanvon, static void report_buttons(struct hanvon *hanvon, int buttons[],unsigned char dta)
int buttons[], unsigned char dta)
{ {
struct input_dev *dev = hanvon->dev; 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[1], dta & 0x02);
input_report_key(dev, buttons[2], dta & 0x04); input_report_key(dev, buttons[2], dta & 0x04);
input_report_key(dev, buttons[3], dta & 0x08); input_report_key(dev, buttons[3], dta & 0x08);
} else { } else {
if (dta <= 0x3f) { /* slider area active */ if(dta <= 0x3f) { /* slider area active */
int diff = dta - hanvon->old_wheel_pos; 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); input_report_rel(dev, REL_WHEEL, diff);
hanvon->old_wheel_pos = dta; hanvon->old_wheel_pos = dta;
@ -71,64 +76,69 @@ static void hanvon_irq(struct urb *urb)
struct hanvon *hanvon = urb->context; struct hanvon *hanvon = urb->context;
unsigned char *data = hanvon->data; unsigned char *data = hanvon->data;
struct input_dev *dev = hanvon->dev; struct input_dev *dev = hanvon->dev;
int ret; int retval;
switch (urb->status) { switch (urb->status) {
case 0: case 0:
/* success */ /* success */
break; break;
case -ECONNRESET: case -ECONNRESET:
case -ENOENT: case -ENOENT:
case -ESHUTDOWN: case -ESHUTDOWN:
/* this urb is terminated, clean up */ /* this urb is terminated, clean up */
return; printk("%s - urb shutting down with status: %d", __func__, urb->status);
default: return;
goto exit; default:
printk("%s - nonzero urb status received: %d", __func__, urb->status);
goto exit;
} }
switch (data[0]) { switch(data[0]) {
case 0x01: /* button press */ case 0x01: /* button press */
if (data[1] == 0x55) /* left side */ if(data[1]==0x55) /* left side */
report_buttons(hanvon, lbuttons, data[2]); report_buttons(hanvon,lbuttons,data[2]);
if (data[3] == 0xaa) /* right side (am1107, am1209) */ if(data[3]==0xaa) /* right side (am1107, am1209) */
report_buttons(hanvon, rbuttons, data[4]); 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; 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); input_sync(dev);
exit: exit:
ret = usb_submit_urb(urb, GFP_ATOMIC); retval = usb_submit_urb (urb, GFP_ATOMIC);
if (ret) if (retval)
err("%s - usb_submit_urb failed with result %d", printk("%s - usb_submit_urb failed with result %d", __func__, retval);
__func__, ret);
} }
static struct usb_device_id hanvon_ids[] = { 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_AM1209) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_AM1107) }, { 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_AM0806) },
{ USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_AM0605) }, { 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_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_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); usb_kill_urb(hanvon->irq);
} }
static int hanvon_probe(struct usb_interface *intf, static int hanvon_probe(struct usb_interface *intf, const struct usb_device_id *id)
const struct usb_device_id *id)
{ {
struct usb_device *dev = interface_to_usbdev(intf); struct usb_device *dev = interface_to_usbdev(intf);
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
@ -167,8 +176,7 @@ static int hanvon_probe(struct usb_interface *intf,
if (!hanvon || !input_dev) if (!hanvon || !input_dev)
goto fail1; goto fail1;
hanvon->data = usb_alloc_coherent(dev, hanvon->data = (unsigned char *)usb_alloc_coherent(dev, USB_AM_PACKET_LEN, GFP_KERNEL, &hanvon->data_dma);
USB_AM_PACKET_LEN, GFP_KERNEL, &hanvon->data_dma);
if (!hanvon->data) if (!hanvon->data)
goto fail1; goto fail1;
@ -192,26 +200,19 @@ static int hanvon_probe(struct usb_interface *intf,
input_dev->open = hanvon_open; input_dev->open = hanvon_open;
input_dev->close = hanvon_close; input_dev->close = hanvon_close;
__set_bit(EV_KEY, input_dev->evbit); input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT_MASK(EV_REL);
__set_bit(EV_ABS, input_dev->evbit); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_TOUCH);
__set_bit(EV_REL, input_dev->evbit); input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
__set_bit(BTN_TOOL_PEN, input_dev->keybit); for(i=0;i<sizeof(lbuttons)/sizeof(lbuttons[0]);i++)
__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++)
__set_bit(lbuttons[i], input_dev->keybit); __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); __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_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_Y, 0, AM_MAX_ABS_Y, 4, 0);
input_set_abs_params(input_dev, ABS_TILT_X, input_set_abs_params(input_dev, ABS_TILT_X, 0, AM_MAX_TILT_X, 0, 0);
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_TILT_Y, input_set_abs_params(input_dev, ABS_PRESSURE, 0, AM_MAX_PRESSURE, 0, 0);
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); input_set_capability(input_dev, EV_REL, REL_WHEEL);
endpoint = &intf->cur_altsetting->endpoint[0].desc; 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_dma = hanvon->data_dma;
hanvon->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; hanvon->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_set_intfdata(intf, hanvon);
error = input_register_device(hanvon->dev); error = input_register_device(hanvon->dev);
if (error) if (error)
goto fail3; goto fail3;
usb_set_intfdata(intf, hanvon);
return 0; return 0;
fail3: usb_free_urb(hanvon->irq); fail3: usb_free_urb(hanvon->irq);
fail2: usb_free_coherent(dev, USB_AM_PACKET_LEN, fail2: usb_free_coherent(dev, USB_AM_PACKET_LEN, hanvon->data, hanvon->data_dma);
hanvon->data, hanvon->data_dma);
fail1: input_free_device(input_dev); fail1: input_free_device(input_dev);
kfree(hanvon); kfree(hanvon);
return error; return error;
@ -243,12 +242,14 @@ static void hanvon_disconnect(struct usb_interface *intf)
{ {
struct hanvon *hanvon = usb_get_intfdata(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); 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 = { static struct usb_driver hanvon_driver = {
@ -258,4 +259,22 @@ static struct usb_driver hanvon_driver = {
.id_table = hanvon_ids, .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);