diff --git a/README b/README index 7e32dcd..ca0dc48 100644 --- a/README +++ b/README @@ -10,9 +10,9 @@ one works only together with pen activity), and the slider button. Supported hardware ================== -AM3M, AM0806, AM0605, AM1107, AM1209 +AM3M, AM0605, AM0806, AM1107, AM1209 RL0604, RL0504 -GP0806, GP0605, GP0504 +GP0504, GP0605, GP0605+, GP0806 NXS1315 AM - Artmaster I, RL - Rollick, GP - GraphicPal, NXS - Nilox diff --git a/hanvon.c b/hanvon.c index a33df90..63102e0 100644 --- a/hanvon.c +++ b/hanvon.c @@ -5,7 +5,7 @@ #include #include -#define DRIVER_VERSION "0.5" +#define DRIVER_VERSION "0.6" #define DRIVER_AUTHOR "Ondra Havel " #define DRIVER_DESC "USB Hanvon tablet driver" #define DRIVER_LICENSE "GPL" @@ -25,22 +25,24 @@ MODULE_LICENSE(DRIVER_LICENSE); #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_GP0605A 0x803a #define USB_PRODUCT_ID_GP0504 0x8037 #define USB_PRODUCT_ID_NXS1513 0x8030 +#define USB_PRODUCT_ID_GP0906 0x8521 +#define USB_PRODUCT_ID_APPIV0906 0x8532 -#define USB_AM_PACKET_LEN 10 +#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+ */ +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 +#define AM_WHEEL_THRESHOLD 4 -#define AM_MAX_ABS_X 0x27de -#define AM_MAX_ABS_Y 0x1cfe -#define AM_MAX_TILT_X 0x3f -#define AM_MAX_TILT_Y 0x7f -#define AM_MAX_PRESSURE 0x400 +#define AM_MAX_ABS_X 0x27de +#define AM_MAX_ABS_Y 0x1cfe +#define AM_MAX_TILT_X 0x3f +#define AM_MAX_TILT_Y 0x7f +#define AM_MAX_PRESSURE 0x400 struct hanvon { unsigned char *data; @@ -52,7 +54,7 @@ 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; @@ -61,7 +63,7 @@ static void report_buttons(struct hanvon *hanvon, int buttons[],unsigned char dt 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; if(abs(diff) < AM_WHEEL_THRESHOLD) input_report_rel(dev, REL_WHEEL, diff); @@ -71,16 +73,136 @@ static void report_buttons(struct hanvon *hanvon, int buttons[],unsigned char dt } } +static inline void handle_default(struct hanvon *hanvon) +{ + unsigned char *data = hanvon->data; + struct input_dev *dev = hanvon->dev; + + 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]); + break; + + case 0x02: /* position change */ + if((data[1] & 0xf0) != 0) { + input_report_abs(hanvon->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); /* pen touches the surface */ + input_report_key(dev, BTN_RIGHT, data[1] & 0x2); /* stylus button pressed (right click) */ + input_report_key(dev, lbuttons[0], data[1] & 0x20); /* 'eraser' button */ + break; + } +} + +static inline void handle_gp0906(struct hanvon *hanvon) +{ + unsigned char *data = hanvon->data; + struct input_dev *dev = hanvon->dev; +/* +hanvon graphic pal 3, gp0906! + +- data definition. this is not official... +[header, 1Byte][event type, 1Byte][x, 2Bytes][y, 2Bytes][pressure, 2Bytes][tilt, 2Bytes] +*/ + + switch( data[0] ) { + case 0x02: /* pen event */ + if( ( data[1] & 0xe0) == 0xe0 ) { + if( ( data[1] & 0x01) != 0 ) /* pressure change */ + input_report_abs(dev, ABS_PRESSURE, get_unaligned_be16(&data[6])>>6); + + if( ( data[1] & 0x04 ) != 0 ) + input_report_key(dev, BTN_RIGHT, data[1] & 0x2); /* stylus button pressed (right click) */ + + 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_key(dev, lbuttons[0], data[6]); + } else { + if( data[1] == 0xc2) /* pen enters */ + {} + + if( data[1] == 0x80) /* pen leaves */ + {} + } + break; + + case 0x0c: /* key press on the tablet */ + input_report_key(dev, lbuttons[0], data[3] & 0x01); + input_report_key(dev, lbuttons[1], data[3] & 0x02); + input_report_key(dev, lbuttons[2], data[3] & 0x04); + input_report_key(dev, lbuttons[3], data[3] & 0x08); + break; + } +} + +static inline void handle_appiv0906(struct hanvon *hanvon) +{ + unsigned char *data = hanvon->data; + struct input_dev *dev = hanvon->dev; + + switch(data[0]) { + case 0x01: /* pen event */ + 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[6] & 0x3f); + input_report_abs(dev, ABS_TILT_Y, data[7]); + + if(data[1] != 0x15) { + input_report_key(dev, BTN_LEFT, data[1] & 0x01); /* pen touches the surface */ + input_report_key(dev, BTN_RIGHT, data[1] & 0x02); /* stylus button pressed (right click) */ + input_report_key(dev, BTN_MIDDLE, data[1] & 0x03); /* stylus button pressed (right click) */ + input_report_key(dev, BTN_TOOL_RUBBER, false); /* 'eraser' button */ + } else { + input_report_key(dev, BTN_TOOL_RUBBER, true); /* 'eraser' button */ + } + + break; + + case 0x0c: /* button event */ + input_report_key(dev, BTN_0, data[3] & 0x01); + input_report_key(dev, BTN_1, data[3] & 0x02); + input_report_key(dev, BTN_2, data[3] & 0x04); + input_report_key(dev, BTN_3, data[3] & 0x08); + input_report_key(dev, BTN_4, data[3] & 0x10); + input_report_key(dev, BTN_5, data[3] & 0x20); + input_report_key(dev, BTN_6, data[3] & 0x40); + input_report_key(dev, BTN_7, data[3] & 0x80); + break; + } +} + static void hanvon_irq(struct urb *urb) { struct hanvon *hanvon = urb->context; - unsigned char *data = hanvon->data; - struct input_dev *dev = hanvon->dev; int retval; switch (urb->status) { case 0: /* success */ + switch( hanvon->usbdev->descriptor.idProduct ) { + case USB_PRODUCT_ID_GP0906: + handle_gp0906(hanvon); + break; + case USB_PRODUCT_ID_APPIV0906: + handle_appiv0906(hanvon); + break; + default: + handle_default(hanvon); + break; + } break; case -ECONNRESET: case -ENOENT: @@ -90,36 +212,12 @@ static void hanvon_irq(struct urb *urb) return; default: printk("%s - nonzero urb status received: %d", __func__, urb->status); - goto exit; + break; } - 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]); - break; + input_sync(hanvon->dev); - 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; - } - - input_sync(dev); - -exit: retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) printk("%s - usb_submit_urb failed with result %d", __func__, retval); @@ -138,8 +236,10 @@ static struct usb_device_id hanvon_ids[] = { { 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) }, - { } + { USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_NXS1513) }, + { USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_GP0906) }, + { USB_DEVICE(USB_VENDOR_ID_HANVON, USB_PRODUCT_ID_APPIV0906)}, + {} }; MODULE_DEVICE_TABLE(usb, hanvon_ids); @@ -190,7 +290,7 @@ static int hanvon_probe(struct usb_interface *intf, const struct usb_device_id * usb_make_path(dev, hanvon->phys, sizeof(hanvon->phys)); strlcat(hanvon->phys, "/input0", sizeof(hanvon->phys)); - input_dev->name = "Hanvon Artmaster I tablet"; + input_dev->name = "Hanvon tablet"; input_dev->phys = hanvon->phys; usb_to_input_id(dev, &input_dev->id); input_dev->dev.parent = &intf->dev; @@ -204,9 +304,9 @@ static int hanvon_probe(struct usb_interface *intf, const struct usb_device_id * 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;ikeybit); + __set_bit(lbuttons[i], input_dev->keybit); for(i=0;ikeybit); + __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); @@ -218,9 +318,9 @@ static int hanvon_probe(struct usb_interface *intf, const struct usb_device_id * endpoint = &intf->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(hanvon->irq, dev, - usb_rcvintpipe(dev, endpoint->bEndpointAddress), - hanvon->data, USB_AM_PACKET_LEN, - hanvon_irq, hanvon, endpoint->bInterval); + usb_rcvintpipe(dev, endpoint->bEndpointAddress), + hanvon->data, USB_AM_PACKET_LEN, + hanvon_irq, hanvon, endpoint->bInterval); hanvon->irq->transfer_dma = hanvon->data_dma; hanvon->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -231,9 +331,9 @@ static int hanvon_probe(struct usb_interface *intf, const struct usb_device_id * 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); -fail1: input_free_device(input_dev); +fail3: usb_free_urb(hanvon->irq); +fail2: usb_free_coherent(dev, USB_AM_PACKET_LEN, hanvon->data, hanvon->data_dma); +fail1: input_free_device(input_dev); kfree(hanvon); return error; } @@ -253,10 +353,10 @@ static void hanvon_disconnect(struct usb_interface *intf) } static struct usb_driver hanvon_driver = { - .name = "hanvon", + .name = "hanvon", .probe = hanvon_probe, .disconnect = hanvon_disconnect, - .id_table = hanvon_ids, + .id_table = hanvon_ids, }; static int __init hanvon_init(void)