scuti/cleanup (#7) general cleanup of code and docs

This commit is contained in:
scuti 2021-08-11 20:37:53 -07:00 committed by Gitea
parent b9359970c3
commit a91ca3c296
6 changed files with 162 additions and 216 deletions

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "hidapi"]
path = hidapi
url = https://github.com/libusb/hidapi

View File

@ -3,7 +3,7 @@
obj-m += hanvon.o obj-m += hanvon.o
all: all:
gcc hanvon-libusb.c -I/usr/include/libevdev-1.0/ -L/usr/local/lib -lusb-1.0 -ludev -levdev -g gcc hanvon-libusb.c -I/usr/include/libevdev-1.0/ -L/usr/local/lib -lusb-1.0 -ludev -levdev -g -o hvlusb
archive: archive:
tar f - --exclude=.git -C ../ -c hanvon | gzip -c9 > ../hanvon-`date +%Y%m%d`.tgz tar f - --exclude=.git -C ../ -c hanvon | gzip -c9 > ../hanvon-`date +%Y%m%d`.tgz

40
README
View File

@ -1,40 +0,0 @@
Hanvon tablet driver
====================
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
==================
AM3M, AM0605, AM0806, AM1107, AM1209
RL0604, RL0504
GP0504, GP0605, GP0605+, GP0806, GP0906
NXS1315
APPIV0906
AM - Artmaster I, RL - Rollick, GP - GraphicPal, NXS - Nilox
APP - Art Painter Pro
Installation
============
Type 'make' to compile the module. New file hanvon.ko will be produced in
current directory. Load the module with root permissions
insmod ./hanvon.ko
If everything goes right the tablet should start working immediately.
Diagnostics
===========
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

33
README.md Normal file
View File

@ -0,0 +1,33 @@
# Hanvon Tablet Drivers
Userspace driver for Hanvon pen tablets adapted from the original Linux kernel driver. Supports tablet features such as pen coordinates, x and y tilts, proximity and pressure detection.
## Building
make
## Usage
sudo hvlusb
Run the output executable from a terminal with sudo (preferrably in the background).
## Supported Hardware
Currently, only GP0504 is tested and supported.
The original series of supported hardware:
Artmaster I: AM3M, AM0605, AM0806, AM1107, AM1209
Rollick: RL0604, RL0504
GraphicPal: GP0504, GP0605, GP0605+, GP0806, GP0906
Nilox: NXS1315
Art Painter Pro: APPIV0906
__________________
upstream repository: https://git.teknik.io/scuti/hanvon-linux
forked from: https://github.com/ondrah/hanvon

View File

@ -1,20 +1,20 @@
/* /*
* ===================================================================================== * =====================================================================================
* *
* Filename: hanvon-libusb.c * Filename: hanvon-libusb.c
* *
* Description: libusb Hanvon tablet driver * Description: libusb Hanvon tablet driver
* *
* Version: 0.1 * Version: 0.1
* Created: 08/17/2020 04:05:14 PM * Created: 08/17/2020 04:05:14 PM
* Revision: none * Revision: none
* Compiler: gcc * Compiler: gcc
* *
* Maintaned by: scuti@teknik.io * Maintained by: scuti@teknik.io
* surkeh@protonmail.com * surkeh@protonmail.com
* *
* ===================================================================================== * =====================================================================================
*/ */
#define DEBUG(msg,...) fprintf(stderr,"%s(%d): " msg , __FILE__,__LINE__,__VA_ARGS__) #define DEBUG(msg,...) fprintf(stderr,"%s(%d): " msg , __FILE__,__LINE__,__VA_ARGS__)
@ -24,15 +24,11 @@
#include <libevdev/libevdev.h> #include <libevdev/libevdev.h>
#include <libevdev/libevdev-uinput.h> #include <libevdev/libevdev-uinput.h>
// #include <asm/unaligned.h> // #include <asm/unaligned.h>
#define STATE_SUCCESS 0 #define STATE_SUCCESS 0
#define STATE_NOT_FOUND 1 #define STATE_NOT_FOUND 1
#define UNREF_DEVICE 1
#define KEEP_DEVICE_REF 0
#define VENDOR_ID_HANVON 0x0b57 #define VENDOR_ID_HANVON 0x0b57
#define PRODUCT_ID_AM3M 0x8528 #define PRODUCT_ID_AM3M 0x8528
#define PRODUCT_ID_AM0806 0x8502 #define PRODUCT_ID_AM0806 0x8502
@ -61,8 +57,7 @@
#define AM_MAX_TILT_Y 0x7f #define AM_MAX_TILT_Y 0x7f
#define AM_MAX_PRESSURE 0x400 #define AM_MAX_PRESSURE 0x400
struct hanvon_message struct hanvon_message {
{
unsigned char msgtype; unsigned char msgtype;
unsigned char is_move; unsigned char is_move;
unsigned short x_movement; unsigned short x_movement;
@ -73,40 +68,37 @@ struct hanvon_message
}; };
int find_device(libusb_device **list, unsigned int count) { int find_device(libusb_device **list, unsigned int count) {
if (count < 0) { if (count < 0) {
return -1; return -1;
} }
int found = -1; int found = -1;
struct libusb_device_descriptor desc; struct libusb_device_descriptor desc;
for (unsigned int i = 0; i < count; i++) { for (unsigned int i = 0; i < count; i++) {
libusb_device *t = list[i]; libusb_device *t = list[i];
libusb_get_device_descriptor(list[i], &desc); libusb_get_device_descriptor(list[i], &desc);
if (desc.idVendor == VENDOR_ID_HANVON) {
// printf( "Dev%u ID %04x:%04x\n", (i), desc.idVendor, desc.idProduct ); switch(desc.idProduct) {
default:
if (desc.idVendor == VENDOR_ID_HANVON) { break;
switch(desc.idProduct) { case PRODUCT_ID_AM0806:
default: case PRODUCT_ID_AM0605:
break; case PRODUCT_ID_AM1107:
case PRODUCT_ID_AM0806: case PRODUCT_ID_AM1209:
case PRODUCT_ID_AM0605: case PRODUCT_ID_RL0604:
case PRODUCT_ID_AM1107: case PRODUCT_ID_RL0504:
case PRODUCT_ID_AM1209: case PRODUCT_ID_GP0806:
case PRODUCT_ID_RL0604: case PRODUCT_ID_GP0806B:
case PRODUCT_ID_RL0504: case PRODUCT_ID_GP0605:
case PRODUCT_ID_GP0806: case PRODUCT_ID_GP0605A:
case PRODUCT_ID_GP0806B: case PRODUCT_ID_GP0504:
case PRODUCT_ID_GP0605: case PRODUCT_ID_NXS1513:
case PRODUCT_ID_GP0605A: case PRODUCT_ID_GP0906:
case PRODUCT_ID_GP0504: case PRODUCT_ID_APPIV0906:
case PRODUCT_ID_NXS1513: return i;
case PRODUCT_ID_GP0906: } // end switch
case PRODUCT_ID_APPIV0906: } // end if
return i; } // end for
} // end switch return found;
} // end if
} // end for
return found;
} }
void display_packets(const unsigned char* buf) { void display_packets(const unsigned char* buf) {
@ -124,51 +116,59 @@ void callback(struct libusb_transfer *transfer) {
void callback_gp0504 (struct libusb_transfer *tx) { // for callback void callback_gp0504 (struct libusb_transfer *tx) { // for callback
unsigned char *data = tx -> buffer; unsigned char *data = tx -> buffer;
struct hanvon_message *msg = (struct hanvon_message *)tx -> buffer; struct hanvon_message *msg = (struct hanvon_message *)tx -> buffer;
unsigned short temp; int err = 0;
int err = 0;
struct libevdev_uinput *ud = tx -> user_data; struct libevdev_uinput *ud = tx -> user_data;
switch(msg->msgtype) { switch(msg->msgtype) {
case 0x01: case 0x01:
display_packets(data); display_packets(data);
break; break;
case 0x02: case 0x02:
/*is_move values: /* is_move values:
0x80: near 0x80: near, 0x02: button press
0x10: floating 0x10: floating, 0x01: touching */
0x02: button press err = libevdev_uinput_write_event(
0x01: touching ud, EV_KEY, BTN_TOOL_PEN, msg->is_move & (0x80|0x10)
*/ );
err = libevdev_uinput_write_event(ud, EV_KEY, BTN_TOOL_PEN, msg->is_move & (0x80|0x10));
if(err) { DEBUG("err: %d\n",err); } if(err) { DEBUG("err: %d\n",err); }
if(msg->is_move & (0x80|0x10)) { if(msg->is_move & (0x80|0x10)) {
msg->x_movement = htobe16(msg->x_movement); msg->x_movement = htobe16(msg->x_movement);
//DEBUG("Set X to %x\n",msg->x_movement); //DEBUG("Set X to %x\n",msg->x_movement);
err = libevdev_uinput_write_event(ud, EV_ABS, ABS_X, msg->x_movement); err = libevdev_uinput_write_event(
ud, EV_ABS, ABS_X, msg->x_movement
);
if(err) { DEBUG("err: %d\n",err); } if(err) { DEBUG("err: %d\n",err); }
msg->y_movement = htobe16(msg->y_movement); msg->y_movement = htobe16(msg->y_movement);
//DEBUG("Set Y to %x\n",msg->y_movement); //DEBUG("Set Y to %x\n",msg->y_movement);
err = libevdev_uinput_write_event(ud, EV_ABS, ABS_Y, msg->y_movement); err = libevdev_uinput_write_event(
ud, EV_ABS, ABS_Y, msg->y_movement
);
if(err) { DEBUG("err: %d\n",err); } if(err) { DEBUG("err: %d\n",err); }
} }
err = libevdev_uinput_write_event(
err = libevdev_uinput_write_event(ud, EV_ABS, ABS_PRESSURE, msg->pressure); ud, EV_ABS, ABS_PRESSURE, msg->pressure
);
if(err) { DEBUG("err: %d\n",err); } if(err) { DEBUG("err: %d\n",err); }
err = libevdev_uinput_write_event(ud, EV_ABS, ABS_TILT_X, msg->y_tilt); err = libevdev_uinput_write_event(
ud, EV_ABS, ABS_TILT_X, msg->x_tilt
);
if(err) { DEBUG("err: %d\n",err); } if(err) { DEBUG("err: %d\n",err); }
err = libevdev_uinput_write_event(ud, EV_ABS, ABS_TILT_Y, msg->x_tilt); err = libevdev_uinput_write_event(
ud, EV_ABS, ABS_TILT_Y, msg->y_tilt
);
if(err) { DEBUG("err: %d\n",err); } if(err) { DEBUG("err: %d\n",err); }
err = libevdev_uinput_write_event(ud, EV_KEY, BTN_LEFT, msg->is_move & 0x01); err = libevdev_uinput_write_event(
ud, EV_KEY, BTN_LEFT, msg->is_move & 0x01
);
if(err) { DEBUG("err: %d\n",err); } if(err) { DEBUG("err: %d\n",err); }
err = libevdev_uinput_write_event(ud, EV_KEY, BTN_RIGHT, (msg->is_move & 0x02) / 2); err = libevdev_uinput_write_event(
ud, EV_KEY, BTN_RIGHT, (msg->is_move & 0x02) / 2
);
if(err) { DEBUG("err: %d\n",err); } if(err) { DEBUG("err: %d\n",err); }
// data[1]: // data[1]:
// 0x10 = lift, 0x90 = close, 0x91 = press // 0x10 = lift, 0x90 = close, 0x91 = press
// 0x12 = btn (lift), 0x92 = btn (close), 0x93 = btn (press) // 0x12 = btn (lift), 0x92 = btn (close), 0x93 = btn (press)
{ display_packets(data);
display_packets(data);
}
break; break;
default: default:
display_packets(data); display_packets(data);
@ -183,13 +183,15 @@ void callback_gp0504 (struct libusb_transfer *tx) { // for callback
} }
// https://www.freedesktop.org/software/libevdev/doc/latest/group__kernel.html // https://www.freedesktop.org/software/libevdev/doc/latest/group__kernel.html
int init_ctrl(struct libusb_device * const d, struct libevdev **evdev, struct libevdev_uinput **uidev) { int init_ctrl(struct libusb_device * const d,
struct libevdev **evdev,
struct libevdev_uinput **uidev) {
struct input_absinfo *abs; struct input_absinfo *abs;
printf("init_ctrl: %x\n", uidev); printf("init_ctrl: %x\n", uidev);
int is_ok = 0;
if (d == NULL) { if (d == NULL) {
return is_ok; return -1;
} }
int is_ok = 0;
struct libusb_device_descriptor desc; struct libusb_device_descriptor desc;
libusb_get_device_descriptor(d, &desc); libusb_get_device_descriptor(d, &desc);
(*evdev) = libevdev_new(); (*evdev) = libevdev_new();
@ -201,8 +203,8 @@ int init_ctrl(struct libusb_device * const d, struct libevdev **evdev, struct li
libevdev_enable_event_code((*evdev), EV_KEY, BTN_TOOL_PEN, NULL); libevdev_enable_event_code((*evdev), EV_KEY, BTN_TOOL_PEN, NULL);
libevdev_enable_event_code((*evdev), EV_KEY, BTN_LEFT, NULL); // pen tap libevdev_enable_event_code((*evdev), EV_KEY, BTN_LEFT, NULL); // pen tap
libevdev_enable_event_code((*evdev), EV_KEY, BTN_RIGHT, NULL); // pen button libevdev_enable_event_code((*evdev), EV_KEY, BTN_RIGHT, NULL); // pen button
libevdev_enable_event_type((*evdev), EV_ABS); // enable absolute position, pressure, tilt // enable absolute position, pressure, tilt
libevdev_enable_event_type((*evdev), EV_ABS);
abs = malloc(sizeof(struct input_absinfo)); abs = malloc(sizeof(struct input_absinfo));
// set up absolute x coordinate input // set up absolute x coordinate input
abs->value = 0x1000; abs->value = 0x1000;
@ -213,24 +215,25 @@ int init_ctrl(struct libusb_device * const d, struct libevdev **evdev, struct li
abs->resolution = 40; abs->resolution = 40;
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_X, abs)<0) { if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_X, abs)<0) {
DEBUG("%s","failed to register absolute x\n"); DEBUG("%s","failed to register absolute x\n");
is_ok = -1;
} }
// set up absolute y coordinate input // set up absolute y coordinate input
abs->value = 0x1000; abs->value = 0x1000;
abs->minimum = 0; abs->minimum = 0;
abs->maximum = 0x1cfe; abs->maximum = 0x1cfe;
abs->fuzz = 0;
abs->flat = 0;
abs->resolution = 40; abs->resolution = 40;
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_Y, abs)<0) { if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_Y, abs)<0) {
DEBUG("%s","failed to register absolute y\n"); DEBUG("%s","failed to register absolute y\n");
is_ok = -1;
} }
// set up pressure input // set up pressure input
abs -> value = 0; abs -> value = 0;
abs -> minimum = 0; abs -> minimum = 0;
abs -> maximum = 0xff; abs -> maximum = AM_MAX_PRESSURE;
abs -> resolution = 0; abs -> resolution = 0;
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_PRESSURE, abs)<0) { if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_PRESSURE, abs)<0) {
DEBUG("%s","failed to register pressure\n"); DEBUG("%s","failed to register pressure\n");
is_ok = -1;
} }
// set up tilt x input // set up tilt x input
abs -> value = 0; abs -> value = 0;
@ -238,7 +241,8 @@ int init_ctrl(struct libusb_device * const d, struct libevdev **evdev, struct li
abs -> maximum = AM_MAX_TILT_X; abs -> maximum = AM_MAX_TILT_X;
abs -> resolution = 0; abs -> resolution = 0;
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_TILT_X, abs)<0) { if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_TILT_X, abs)<0) {
DEBUG("%s","failed to register x tilt\n"); DEBUG("%s","failed to register x tilt\n");
is_ok = -1;
} }
// set up tilt y input // set up tilt y input
abs -> value = 0; abs -> value = 0;
@ -246,9 +250,9 @@ int init_ctrl(struct libusb_device * const d, struct libevdev **evdev, struct li
abs -> maximum = AM_MAX_TILT_Y; abs -> maximum = AM_MAX_TILT_Y;
abs -> resolution = 0; abs -> resolution = 0;
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_TILT_Y, abs)<0) { if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_TILT_Y, abs)<0) {
DEBUG("%s","failed to register y tilt\n"); DEBUG("%s","failed to register y tilt\n");
is_ok = -1;
} }
switch(desc.idProduct) { switch(desc.idProduct) {
case PRODUCT_ID_GP0504: case PRODUCT_ID_GP0504:
libevdev_set_name((*evdev), "Hanvon Graphicpal GP0504"); libevdev_set_name((*evdev), "Hanvon Graphicpal GP0504");
@ -258,61 +262,59 @@ int init_ctrl(struct libusb_device * const d, struct libevdev **evdev, struct li
case PRODUCT_ID_APPIV0906: case PRODUCT_ID_APPIV0906:
break; break;
} }
int err = libevdev_uinput_create_from_device((*evdev), LIBEVDEV_UINPUT_OPEN_MANAGED, uidev); int err = libevdev_uinput_create_from_device(
(*evdev), LIBEVDEV_UINPUT_OPEN_MANAGED, uidev
);
printf("Initializing controls status: %x, \n", uidev); printf("Initializing controls status: %x, \n", uidev);
free(abs); free(abs);
return is_ok; return is_ok;
} }
int handle_device_lusb(libusb_device *d) { int handle_device_lusb(libusb_device *d) {
libusb_device_handle *h; libusb_device_handle *h;
int status = libusb_open(d, &h); int status = libusb_open(d, &h);
if (status < 0 || h == NULL) { if (status < 0 || h == NULL) {
printf("Error opening device, %i.\n", status); printf("Error opening device, %i.\n", status);
return 0; return 0;
} }
struct libevdev *evdev = NULL; struct libevdev *evdev = NULL;
struct libevdev_uinput *uidev = NULL; struct libevdev_uinput *uidev = NULL;
printf("handle_device: %x\n", uidev); printf("handle_device: %x\n", uidev);
init_ctrl(d, &evdev, &uidev); if (init_ctrl(d, &evdev, &uidev) < 0) {
return 0;
}
if (evdev == NULL || uidev == NULL) { if (evdev == NULL || uidev == NULL) {
printf("Error initializing controls, %x, %x.\n", evdev, uidev); printf("Error initializing controls, %x, %x.\n", evdev, uidev);
return 0; return 0;
} }
struct libusb_transfer *tx;
struct libusb_transfer *tx; const int ENDPOINT_ADDR = 0x81; // bEndpointAddress from lsusb -v
const int ENDPOINT_ADDR = 0x81; // bEndpointAddress from lsusb -v //AM_PACKET_LEN = 10; // wMaxPacketSize from lsusb -v
// AM_PACKET_LEN = 10; // wMaxPacketSize from lsusb -v unsigned char buffer[AM_PACKET_LEN];
unsigned char buffer[AM_PACKET_LEN];
// Allocate memory for transfer, configure, then submit // Allocate memory for transfer, configure, then submit
tx = libusb_alloc_transfer(0); tx = libusb_alloc_transfer(0);
libusb_fill_interrupt_transfer( tx, libusb_fill_interrupt_transfer( tx,
h, h,
ENDPOINT_ADDR, ENDPOINT_ADDR,
buffer, buffer,
AM_PACKET_LEN, AM_PACKET_LEN,
callback_gp0504, callback_gp0504,
uidev, // extra data to send in tx uidev, // extra data to send in tx
130); // timeout in milliseconds 130); // timeout in milliseconds
do { do {
status = libusb_submit_transfer(tx); status = libusb_submit_transfer(tx);
if (status < 0 ) { if (status < 0 ) {
//return status; printf("warning: usb transfer status = %i\n", status);
//continue; //continue;
} }
libusb_handle_events(NULL); libusb_handle_events(NULL);
} while (1); } while (1);
libevdev_uinput_destroy(uidev); libevdev_uinput_destroy(uidev);
return 0; return 0;
} }
libusb_device *FindHanvon( libusb_context **context); int main() {
int HandleData( void );
int main()
{
#define UNREF_DEVICE 1 #define UNREF_DEVICE 1
#define KEEP_DEVICE_REF 0 #define KEEP_DEVICE_REF 0
@ -326,60 +328,15 @@ int main()
libusb_exit(NULL); libusb_exit(NULL);
return count; return count;
} }
int index = find_device(devs, count); int index = find_device(devs, count);
if (index < 0) { if (index < 0) {
printf("Device not plugged in\n"); printf("Device not plugged in\n");
libusb_exit(NULL); libusb_exit(NULL);
return 0; return 0;
} }
libusb_device *device = devs[index]; libusb_device *device = devs[index];
libusb_free_device_list (devs, UNREF_DEVICE); libusb_free_device_list (devs, UNREF_DEVICE);
int s = handle_device_lusb(device); int s = handle_device_lusb(device);
libusb_exit(NULL); libusb_exit(NULL);
return 0; return 0;
} }
libusb_device *FindHanvon( libusb_context **context)
{
libusb_device **deviceList;
libusb_device *found = NULL;
ssize_t nDevices = libusb_get_device_list( context[0], &deviceList);
if( nDevices > 0 )
{
struct libusb_device_descriptor description;
for( ssize_t i = 0; i < nDevices; i++ )
{
libusb_device *device = deviceList[i];
libusb_get_device_descriptor(device, &description);
//printf( "Dev%u ID %04x:%04x\n", (i + 1), description.idVendor, description.idProduct );
if( description.idVendor == VENDOR_ID_HANVON )
{
switch( description.idProduct )
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:
found = device;
break;
}
}
printf( "\n\n" );
}
libusb_free_device_list( deviceList, UNREF_DEVICE );
return found;
}

1
hidapi

@ -1 +0,0 @@
Subproject commit cdc473dfe43f6432dda7ad53d7656b8ae8ff968b