2020-08-18 06:36:07 +05:30
|
|
|
/*
|
2021-08-12 09:07:53 +05:30
|
|
|
* =====================================================================================
|
|
|
|
*
|
|
|
|
* Filename: hanvon-libusb.c
|
|
|
|
*
|
|
|
|
* Description: libusb Hanvon tablet driver
|
|
|
|
*
|
|
|
|
* Version: 0.1
|
|
|
|
* Created: 08/17/2020 04:05:14 PM
|
|
|
|
* Revision: none
|
|
|
|
* Compiler: gcc
|
|
|
|
*
|
|
|
|
* Maintained by: scuti@teknik.io
|
|
|
|
* surkeh@protonmail.com
|
|
|
|
*
|
|
|
|
* =====================================================================================
|
|
|
|
*/
|
2020-08-18 06:36:07 +05:30
|
|
|
|
2021-07-09 02:00:01 +05:30
|
|
|
#define DEBUG(msg,...) fprintf(stderr,"%s(%d): " msg , __FILE__,__LINE__,__VA_ARGS__)
|
|
|
|
|
2020-08-18 06:36:07 +05:30
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <libusb-1.0/libusb.h>
|
|
|
|
|
2020-10-03 10:07:41 +05:30
|
|
|
#include <libevdev/libevdev.h>
|
|
|
|
#include <libevdev/libevdev-uinput.h>
|
|
|
|
// #include <asm/unaligned.h>
|
2020-09-30 14:37:24 +05:30
|
|
|
|
2020-08-18 06:36:07 +05:30
|
|
|
#define STATE_SUCCESS 0
|
|
|
|
#define STATE_NOT_FOUND 1
|
|
|
|
|
|
|
|
#define VENDOR_ID_HANVON 0x0b57
|
|
|
|
#define PRODUCT_ID_AM3M 0x8528
|
|
|
|
#define PRODUCT_ID_AM0806 0x8502
|
|
|
|
#define PRODUCT_ID_AM0605 0x8503
|
|
|
|
#define PRODUCT_ID_AM1107 0x8505
|
|
|
|
#define PRODUCT_ID_AM1209 0x8501
|
|
|
|
#define PRODUCT_ID_RL0604 0x851f
|
|
|
|
#define PRODUCT_ID_RL0504 0x851d
|
|
|
|
#define PRODUCT_ID_GP0806 0x8039
|
|
|
|
#define PRODUCT_ID_GP0806B 0x8511
|
|
|
|
#define PRODUCT_ID_GP0605 0x8512
|
|
|
|
#define PRODUCT_ID_GP0605A 0x803a
|
|
|
|
#define PRODUCT_ID_GP0504 0x8037
|
|
|
|
#define PRODUCT_ID_NXS1513 0x8030
|
|
|
|
#define PRODUCT_ID_GP0906 0x8521
|
|
|
|
#define PRODUCT_ID_APPIV0906 0x8532
|
|
|
|
|
|
|
|
#define 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
|
|
|
|
|
|
|
|
#define AM_MAX_TILT_X 0x3f
|
|
|
|
#define AM_MAX_TILT_Y 0x7f
|
|
|
|
#define AM_MAX_PRESSURE 0x400
|
|
|
|
|
2021-08-12 09:07:53 +05:30
|
|
|
struct hanvon_message {
|
2021-07-09 02:00:01 +05:30
|
|
|
unsigned char msgtype;
|
|
|
|
unsigned char is_move;
|
|
|
|
unsigned short x_movement;
|
|
|
|
unsigned short y_movement;
|
|
|
|
unsigned char pressure;
|
|
|
|
unsigned char x_tilt;
|
|
|
|
unsigned char y_tilt;
|
2020-08-18 06:36:07 +05:30
|
|
|
};
|
|
|
|
|
2020-09-03 11:39:12 +05:30
|
|
|
int find_device(libusb_device **list, unsigned int count) {
|
2021-08-12 09:07:53 +05:30
|
|
|
if (count < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
int found = -1;
|
|
|
|
struct libusb_device_descriptor desc;
|
|
|
|
for (unsigned int i = 0; i < count; i++) {
|
|
|
|
libusb_device *t = list[i];
|
|
|
|
libusb_get_device_descriptor(list[i], &desc);
|
|
|
|
if (desc.idVendor == VENDOR_ID_HANVON) {
|
|
|
|
switch(desc.idProduct) {
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case PRODUCT_ID_AM0806:
|
|
|
|
case PRODUCT_ID_AM0605:
|
|
|
|
case PRODUCT_ID_AM1107:
|
|
|
|
case PRODUCT_ID_AM1209:
|
|
|
|
case PRODUCT_ID_RL0604:
|
|
|
|
case PRODUCT_ID_RL0504:
|
|
|
|
case PRODUCT_ID_GP0806:
|
|
|
|
case PRODUCT_ID_GP0806B:
|
|
|
|
case PRODUCT_ID_GP0605:
|
|
|
|
case PRODUCT_ID_GP0605A:
|
|
|
|
case PRODUCT_ID_GP0504:
|
|
|
|
case PRODUCT_ID_NXS1513:
|
|
|
|
case PRODUCT_ID_GP0906:
|
|
|
|
case PRODUCT_ID_APPIV0906:
|
|
|
|
return i;
|
|
|
|
} // end switch
|
|
|
|
} // end if
|
|
|
|
} // end for
|
|
|
|
return found;
|
2020-09-03 11:39:12 +05:30
|
|
|
}
|
|
|
|
|
2020-10-03 10:07:41 +05:30
|
|
|
void display_packets(const unsigned char* buf) {
|
|
|
|
for(int i = 0; i < AM_PACKET_LEN; i++) {
|
2021-07-09 02:00:01 +05:30
|
|
|
fprintf(stderr,"0x%x, ", buf[i]);
|
2020-10-03 10:07:41 +05:30
|
|
|
}
|
2021-07-14 09:49:49 +05:30
|
|
|
fprintf(stderr,"\r");
|
2020-10-03 10:07:41 +05:30
|
|
|
}
|
|
|
|
|
2020-09-30 14:37:24 +05:30
|
|
|
void callback(struct libusb_transfer *transfer) {
|
|
|
|
unsigned char *data = transfer -> buffer;
|
2020-10-03 10:07:41 +05:30
|
|
|
display_packets(data);
|
|
|
|
}
|
|
|
|
|
2020-10-03 11:01:39 +05:30
|
|
|
void callback_gp0504 (struct libusb_transfer *tx) { // for callback
|
|
|
|
unsigned char *data = tx -> buffer;
|
2021-07-09 02:00:01 +05:30
|
|
|
struct hanvon_message *msg = (struct hanvon_message *)tx -> buffer;
|
2021-08-12 09:07:53 +05:30
|
|
|
int err = 0;
|
2020-10-03 11:01:39 +05:30
|
|
|
struct libevdev_uinput *ud = tx -> user_data;
|
2021-07-09 02:00:01 +05:30
|
|
|
switch(msg->msgtype) {
|
2020-10-03 10:07:41 +05:30
|
|
|
case 0x01:
|
2021-07-09 02:00:01 +05:30
|
|
|
display_packets(data);
|
2020-10-03 10:07:41 +05:30
|
|
|
break;
|
|
|
|
case 0x02:
|
2021-08-12 09:07:53 +05:30
|
|
|
/* is_move values:
|
|
|
|
0x80: near, 0x02: button press
|
|
|
|
0x10: floating, 0x01: touching */
|
|
|
|
err = libevdev_uinput_write_event(
|
|
|
|
ud, EV_KEY, BTN_TOOL_PEN, msg->is_move & (0x80|0x10)
|
|
|
|
);
|
2021-07-14 09:49:49 +05:30
|
|
|
if(err) { DEBUG("err: %d\n",err); }
|
2021-07-17 09:27:12 +05:30
|
|
|
|
2021-07-14 09:49:49 +05:30
|
|
|
if(msg->is_move & (0x80|0x10)) {
|
2021-07-09 02:00:01 +05:30
|
|
|
msg->x_movement = htobe16(msg->x_movement);
|
|
|
|
//DEBUG("Set X to %x\n",msg->x_movement);
|
2021-08-12 09:07:53 +05:30
|
|
|
err = libevdev_uinput_write_event(
|
|
|
|
ud, EV_ABS, ABS_X, msg->x_movement
|
|
|
|
);
|
2021-07-09 02:00:01 +05:30
|
|
|
if(err) { DEBUG("err: %d\n",err); }
|
|
|
|
msg->y_movement = htobe16(msg->y_movement);
|
|
|
|
//DEBUG("Set Y to %x\n",msg->y_movement);
|
2021-08-12 09:07:53 +05:30
|
|
|
err = libevdev_uinput_write_event(
|
|
|
|
ud, EV_ABS, ABS_Y, msg->y_movement
|
|
|
|
);
|
2021-07-09 02:00:01 +05:30
|
|
|
if(err) { DEBUG("err: %d\n",err); }
|
|
|
|
}
|
2021-08-12 09:07:53 +05:30
|
|
|
err = libevdev_uinput_write_event(
|
|
|
|
ud, EV_ABS, ABS_PRESSURE, msg->pressure
|
|
|
|
);
|
2021-07-17 09:27:12 +05:30
|
|
|
if(err) { DEBUG("err: %d\n",err); }
|
2021-08-12 09:07:53 +05:30
|
|
|
err = libevdev_uinput_write_event(
|
|
|
|
ud, EV_ABS, ABS_TILT_X, msg->x_tilt
|
|
|
|
);
|
2021-07-17 09:27:12 +05:30
|
|
|
if(err) { DEBUG("err: %d\n",err); }
|
2021-08-12 09:07:53 +05:30
|
|
|
err = libevdev_uinput_write_event(
|
|
|
|
ud, EV_ABS, ABS_TILT_Y, msg->y_tilt
|
|
|
|
);
|
2021-07-14 09:49:49 +05:30
|
|
|
if(err) { DEBUG("err: %d\n",err); }
|
2021-08-12 09:07:53 +05:30
|
|
|
err = libevdev_uinput_write_event(
|
|
|
|
ud, EV_KEY, BTN_LEFT, msg->is_move & 0x01
|
|
|
|
);
|
2021-07-09 02:00:01 +05:30
|
|
|
if(err) { DEBUG("err: %d\n",err); }
|
2021-08-12 09:07:53 +05:30
|
|
|
err = libevdev_uinput_write_event(
|
|
|
|
ud, EV_KEY, BTN_RIGHT, (msg->is_move & 0x02) / 2
|
|
|
|
);
|
2021-07-09 02:00:01 +05:30
|
|
|
if(err) { DEBUG("err: %d\n",err); }
|
2020-10-04 23:14:54 +05:30
|
|
|
// data[1]:
|
|
|
|
// 0x10 = lift, 0x90 = close, 0x91 = press
|
|
|
|
// 0x12 = btn (lift), 0x92 = btn (close), 0x93 = btn (press)
|
2021-08-12 09:07:53 +05:30
|
|
|
display_packets(data);
|
2021-07-09 02:00:01 +05:30
|
|
|
break;
|
2020-10-04 23:14:54 +05:30
|
|
|
default:
|
2020-10-03 10:07:41 +05:30
|
|
|
display_packets(data);
|
|
|
|
break;
|
2020-10-04 23:14:54 +05:30
|
|
|
|
|
|
|
}
|
|
|
|
err += libevdev_uinput_write_event(ud, EV_SYN, SYN_REPORT, 0);
|
|
|
|
if (err != 0) {
|
|
|
|
printf("error : gp0504, %i\n", err);
|
2020-09-30 14:37:24 +05:30
|
|
|
}
|
2020-10-04 23:14:54 +05:30
|
|
|
return;
|
2020-10-03 10:07:41 +05:30
|
|
|
}
|
|
|
|
|
2020-10-04 23:14:54 +05:30
|
|
|
// https://www.freedesktop.org/software/libevdev/doc/latest/group__kernel.html
|
2021-08-12 09:07:53 +05:30
|
|
|
int init_ctrl(struct libusb_device * const d,
|
|
|
|
struct libevdev **evdev,
|
|
|
|
struct libevdev_uinput **uidev) {
|
2021-07-09 02:00:01 +05:30
|
|
|
struct input_absinfo *abs;
|
2020-10-03 11:01:39 +05:30
|
|
|
printf("init_ctrl: %x\n", uidev);
|
2020-10-03 10:07:41 +05:30
|
|
|
if (d == NULL) {
|
2021-08-12 09:07:53 +05:30
|
|
|
return -1;
|
2020-10-03 10:07:41 +05:30
|
|
|
}
|
2021-08-12 09:07:53 +05:30
|
|
|
int is_ok = 0;
|
2020-10-03 10:07:41 +05:30
|
|
|
struct libusb_device_descriptor desc;
|
|
|
|
libusb_get_device_descriptor(d, &desc);
|
2020-10-03 11:01:39 +05:30
|
|
|
(*evdev) = libevdev_new();
|
2021-07-14 09:49:49 +05:30
|
|
|
libevdev_enable_property((*evdev), INPUT_PROP_DIRECT);
|
2020-10-04 23:14:54 +05:30
|
|
|
libevdev_enable_event_type((*evdev), EV_SYN);
|
|
|
|
libevdev_enable_event_code((*evdev), EV_SYN, SYN_REPORT, NULL);
|
|
|
|
// every tablet has these features
|
|
|
|
libevdev_enable_event_type((*evdev), EV_KEY); // enable pen button
|
2021-07-14 09:49:49 +05:30
|
|
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_TOOL_PEN, NULL);
|
2020-10-04 23:14:54 +05:30
|
|
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_LEFT, NULL); // pen tap
|
|
|
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_RIGHT, NULL); // pen button
|
2021-08-12 09:07:53 +05:30
|
|
|
// enable absolute position, pressure, tilt
|
|
|
|
libevdev_enable_event_type((*evdev), EV_ABS);
|
2021-07-09 02:00:01 +05:30
|
|
|
abs = malloc(sizeof(struct input_absinfo));
|
2021-07-17 09:27:12 +05:30
|
|
|
// set up absolute x coordinate input
|
2021-07-09 02:00:01 +05:30
|
|
|
abs->value = 0x1000;
|
|
|
|
abs->minimum = 0;
|
|
|
|
abs->maximum = 0x27DE;
|
|
|
|
abs->fuzz = 0;
|
|
|
|
abs->flat = 0;
|
|
|
|
abs->resolution = 40;
|
2021-07-17 09:27:12 +05:30
|
|
|
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_X, abs)<0) {
|
2021-07-09 02:00:01 +05:30
|
|
|
DEBUG("%s","failed to register absolute x\n");
|
2021-08-12 09:07:53 +05:30
|
|
|
is_ok = -1;
|
2021-07-09 02:00:01 +05:30
|
|
|
}
|
2021-07-17 09:27:12 +05:30
|
|
|
// set up absolute y coordinate input
|
2021-07-09 02:00:01 +05:30
|
|
|
abs->value = 0x1000;
|
|
|
|
abs->minimum = 0;
|
|
|
|
abs->maximum = 0x1cfe;
|
|
|
|
abs->resolution = 40;
|
2021-07-17 09:27:12 +05:30
|
|
|
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_Y, abs)<0) {
|
|
|
|
DEBUG("%s","failed to register absolute y\n");
|
2021-08-12 09:07:53 +05:30
|
|
|
is_ok = -1;
|
2021-07-09 02:00:01 +05:30
|
|
|
}
|
2021-07-17 09:27:12 +05:30
|
|
|
// set up pressure input
|
2021-07-14 09:49:49 +05:30
|
|
|
abs -> value = 0;
|
|
|
|
abs -> minimum = 0;
|
2021-08-12 09:07:53 +05:30
|
|
|
abs -> maximum = AM_MAX_PRESSURE;
|
2021-07-14 09:49:49 +05:30
|
|
|
abs -> resolution = 0;
|
|
|
|
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_PRESSURE, abs)<0) {
|
2021-08-12 09:07:53 +05:30
|
|
|
DEBUG("%s","failed to register pressure\n");
|
|
|
|
is_ok = -1;
|
2021-07-14 09:49:49 +05:30
|
|
|
}
|
2021-07-17 09:27:12 +05:30
|
|
|
// set up tilt x input
|
|
|
|
abs -> value = 0;
|
|
|
|
abs -> minimum = 0;
|
|
|
|
abs -> maximum = AM_MAX_TILT_X;
|
|
|
|
abs -> resolution = 0;
|
|
|
|
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_TILT_X, abs)<0) {
|
2021-08-12 09:07:53 +05:30
|
|
|
DEBUG("%s","failed to register x tilt\n");
|
|
|
|
is_ok = -1;
|
2021-07-17 09:27:12 +05:30
|
|
|
}
|
|
|
|
// set up tilt y input
|
|
|
|
abs -> value = 0;
|
|
|
|
abs -> minimum = 0;
|
|
|
|
abs -> maximum = AM_MAX_TILT_Y;
|
|
|
|
abs -> resolution = 0;
|
|
|
|
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_TILT_Y, abs)<0) {
|
2021-08-12 09:07:53 +05:30
|
|
|
DEBUG("%s","failed to register y tilt\n");
|
|
|
|
is_ok = -1;
|
2021-07-17 09:27:12 +05:30
|
|
|
}
|
2020-10-03 10:07:41 +05:30
|
|
|
switch(desc.idProduct) {
|
2020-10-04 23:14:54 +05:30
|
|
|
case PRODUCT_ID_GP0504:
|
|
|
|
libevdev_set_name((*evdev), "Hanvon Graphicpal GP0504");
|
|
|
|
break;
|
2020-10-03 10:07:41 +05:30
|
|
|
case PRODUCT_ID_GP0906:
|
|
|
|
break;
|
|
|
|
case PRODUCT_ID_APPIV0906:
|
|
|
|
break;
|
|
|
|
}
|
2021-08-12 09:07:53 +05:30
|
|
|
int err = libevdev_uinput_create_from_device(
|
|
|
|
(*evdev), LIBEVDEV_UINPUT_OPEN_MANAGED, uidev
|
|
|
|
);
|
2020-10-03 11:01:39 +05:30
|
|
|
printf("Initializing controls status: %x, \n", uidev);
|
2021-07-17 09:27:12 +05:30
|
|
|
free(abs);
|
2020-10-03 10:07:41 +05:30
|
|
|
return is_ok;
|
2020-09-30 14:37:24 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
int handle_device_lusb(libusb_device *d) {
|
2021-08-12 09:07:53 +05:30
|
|
|
libusb_device_handle *h;
|
|
|
|
int status = libusb_open(d, &h);
|
|
|
|
if (status < 0 || h == NULL) {
|
|
|
|
printf("Error opening device, %i.\n", status);
|
2020-09-30 14:37:24 +05:30
|
|
|
return 0;
|
2021-08-12 09:07:53 +05:30
|
|
|
}
|
2020-10-03 10:07:41 +05:30
|
|
|
struct libevdev *evdev = NULL;
|
|
|
|
struct libevdev_uinput *uidev = NULL;
|
2020-10-03 11:01:39 +05:30
|
|
|
printf("handle_device: %x\n", uidev);
|
2021-08-12 09:07:53 +05:30
|
|
|
if (init_ctrl(d, &evdev, &uidev) < 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2020-10-03 11:01:39 +05:30
|
|
|
if (evdev == NULL || uidev == NULL) {
|
|
|
|
printf("Error initializing controls, %x, %x.\n", evdev, uidev);
|
|
|
|
return 0;
|
|
|
|
}
|
2021-08-12 09:07:53 +05:30
|
|
|
struct libusb_transfer *tx;
|
|
|
|
const int ENDPOINT_ADDR = 0x81; // bEndpointAddress from lsusb -v
|
|
|
|
//AM_PACKET_LEN = 10; // wMaxPacketSize from lsusb -v
|
|
|
|
unsigned char buffer[AM_PACKET_LEN];
|
2020-09-30 14:37:24 +05:30
|
|
|
|
|
|
|
// Allocate memory for transfer, configure, then submit
|
|
|
|
tx = libusb_alloc_transfer(0);
|
2021-08-12 09:07:53 +05:30
|
|
|
libusb_fill_interrupt_transfer( tx,
|
|
|
|
h,
|
|
|
|
ENDPOINT_ADDR,
|
|
|
|
buffer,
|
|
|
|
AM_PACKET_LEN,
|
|
|
|
callback_gp0504,
|
|
|
|
uidev, // extra data to send in tx
|
|
|
|
130); // timeout in milliseconds
|
2020-09-30 14:37:24 +05:30
|
|
|
do {
|
2021-08-12 09:07:53 +05:30
|
|
|
status = libusb_submit_transfer(tx);
|
|
|
|
if (status < 0 ) {
|
|
|
|
printf("warning: usb transfer status = %i\n", status);
|
|
|
|
//continue;
|
|
|
|
}
|
|
|
|
libusb_handle_events(NULL);
|
2020-09-30 14:37:24 +05:30
|
|
|
} while (1);
|
2020-10-03 10:07:41 +05:30
|
|
|
libevdev_uinput_destroy(uidev);
|
2020-09-30 14:37:24 +05:30
|
|
|
return 0;
|
|
|
|
}
|
2020-09-03 11:39:12 +05:30
|
|
|
|
2021-08-12 09:07:53 +05:30
|
|
|
int main() {
|
2020-09-03 11:39:12 +05:30
|
|
|
#define UNREF_DEVICE 1
|
|
|
|
#define KEEP_DEVICE_REF 0
|
2020-08-18 06:36:07 +05:30
|
|
|
|
2020-09-03 11:39:12 +05:30
|
|
|
libusb_device ** devs;
|
|
|
|
int r = libusb_init(NULL);
|
|
|
|
if (r < 0) {
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
int count = libusb_get_device_list(NULL, &devs);
|
|
|
|
if (count < 0) {
|
|
|
|
libusb_exit(NULL);
|
|
|
|
return count;
|
|
|
|
}
|
2021-08-12 09:07:53 +05:30
|
|
|
int index = find_device(devs, count);
|
|
|
|
if (index < 0) {
|
|
|
|
printf("Device not plugged in\n");
|
2020-09-30 14:37:24 +05:30
|
|
|
libusb_exit(NULL);
|
2021-08-12 09:07:53 +05:30
|
|
|
return 0;
|
|
|
|
}
|
2020-09-30 14:37:24 +05:30
|
|
|
libusb_device *device = devs[index];
|
|
|
|
libusb_free_device_list (devs, UNREF_DEVICE);
|
|
|
|
int s = handle_device_lusb(device);
|
|
|
|
libusb_exit(NULL);
|
|
|
|
return 0;
|
2020-08-18 06:36:07 +05:30
|
|
|
}
|