Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XP-PEN Star G430S_B doesn't work with DIGImend #388

Open
Sturwandan opened this issue May 4, 2020 · 9 comments
Open

XP-PEN Star G430S_B doesn't work with DIGImend #388

Sturwandan opened this issue May 4, 2020 · 9 comments

Comments

@Sturwandan
Copy link

Sturwandan commented May 4, 2020

This tablet is similar in appearance to the white version has same size and buttons, however, USB ID is different.
Black tablet ID is 28bd:0913
White tablet ID is 28bd:0075

When I insert the tablet, following messages appear:

usb 6-3: new full-speed USB device number 37 using ohci-pci
usb 6-3: New USB device found, idVendor=28bd, idProduct=0913, bcdDevice= 0.00
usb 6-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 6-3: Product: 4 inch PenTablet
usb 6-3: Manufacturer: UGTABLET
usb 6-3: SerialNumber: 000000
input: UGTABLET 4 inch PenTablet Mouse as /devices/pci0000:00/0000:00:16.0/usb6/6-3/6-3:1.0/0003:28BD:0913.0085/input/input151
input: UGTABLET 4 inch PenTablet Keyboard as /devices/pci0000:00/0000:00:16.0/usb6/6-3/6-3:1.0/0003:28BD:0913.0085/input/input152
hid-generic 0003:28BD:0913.0085: input,hidraw0: USB HID v1.00 Mouse [UGTABLET 4 inch PenTablet] on usb-0000:00:16.0-3/input0
input: UGTABLET 4 inch PenTablet as /devices/pci0000:00/0000:00:16.0/usb6/6-3/6-3:1.1/0003:28BD:0913.0086/input/input153
hid-generic 0003:28BD:0913.0086: input,hidraw1: USB HID v1.00 Device [UGTABLET 4 inch PenTablet] on usb-0000:00:16.0-3/input1
hid-generic 0003:28BD:0913.0087: hiddev96,hidraw2: USB HID v1.00 Device [UGTABLET 4 inch PenTablet] on usb-0000:00:16.0-3/input2

The tablet works with generic drivers, pressure sensitivity is available in GIMP, however, buttons on the pen do not work as expected: the button next to the tip works as MMB (middle mouse button), while the button further from the tip doesn't work at all. Expected behavior is: close button: RMB, far button: MMB

The far button works in principle, since this command usbhid-dump -m 28bd:0913 -e stream shows lines like 006:036:001:STREAM 1588586846.485230 07 A0 E0 3B 0C 22 00 00 00 00 when no buttons are pressed, but
A0 changes to A1 with tip touch, to A2 with close-to-tip button and A4 with far button. If I both touch the tablet and hold far button, I get A5, as expected (1+4), so we can conclude that the second byte encodes buttons, similar to G430S white, which works with DIGImend.

I have tried to change this line to
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0913
But it wasn't enough. Likely it happens because of different HID packet length, I have seen a bug report with similar problem on Windows drivers: hawku/TabletDriver#520

Playing with the monitor shows that, I get this numbers when I bring the pen to a tablet corner slowly and then pull away, without touching:
07 A0 00 00 00 00 00 00 00 00 || top left corner
07 A0 00 00 FF 7F 00 00 00 00 || bottom left corner
07 A0 FF 7F 00 00 00 00 00 00 || top right corner
07 A0 FF 7F FF 7F 00 00 00 00 || bottom right corner

A0 changes to C0 when I remove the pen from the tablet.

I have noticed that white tablet output is like this:

013:002:001:STREAM 1588592013.478316
07 A0 58 4F B1 39 00 00

So the HID packet length is indeed different.

I guess you will also need this information. I was able to decode it with hidrd-convert -i hex -o spec so I can see it contains data which is probably needed to support the tablet.

# usbhid-dump -m 28bd:0913 -e descriptor
006:038:002:DESCRIPTOR         1588592369.505781
 06 0A FF 09 01 A1 01 85 02 09 02 75 08 95 0B 15
 00 26 FF 00 81 02 09 03 75 08 95 0B 15 00 26 FF
 00 91 02 C0

006:038:001:DESCRIPTOR         1588592369.507730
 05 0D 09 02 A1 01 85 07 09 20 A1 00 09 42 09 44
 09 45 09 3C 15 00 25 01 75 01 95 04 81 02 95 01
 81 03 09 32 95 01 81 02 95 02 81 03 75 10 95 01
 35 00 A4 05 01 09 30 65 13 55 0D 46 A0 0F 26 FF
 7F 81 02 09 31 46 B8 0B 26 FF 7F 81 02 B4 09 30
 45 00 26 FF 1F 81 42 09 3D 15 81 25 7F 75 08 95
 01 81 02 09 3E 15 81 25 7F 81 02 C0 C0

006:038:000:DESCRIPTOR         1588592369.510773
 05 01 09 02 A1 01 85 09 09 01 A1 00 05 09 19 01
 29 03 15 00 25 01 95 03 75 01 81 02 95 05 81 01
 05 01 09 30 09 31 26 FF 7F 95 02 75 10 81 02 05
 0D 09 30 26 FF 07 95 01 75 10 81 02 C0 C0 05 01
 09 02 A1 01 09 01 A1 00 85 01 05 09 19 01 29 05
 95 05 75 01 15 00 25 01 81 02 95 03 81 01 05 01
 09 30 09 31 95 02 75 10 16 00 80 26 FF 7F 81 06
 09 38 15 81 25 7F 95 01 75 08 81 06 05 0C 0A 38
 02 95 01 75 08 81 06 C0 C0 05 01 09 06 A1 01 85
 06 05 07 19 E0 29 E7 15 00 25 01 75 01 95 08 81
 02 05 07 19 00 29 FF 26 FF 00 75 08 95 06 81 00
 C0
@Sturwandan
Copy link
Author

Sturwandan commented May 4, 2020

So, I might be wrong, but it seems that first byte is 07, second byte encodes Button state, then there is horizontal coordinate (2 bytes), vertical coordinate (2 bytes) and pressure (2 bytes), then zero (2 bytes).


Bus 006 Device 040: ID 28bd:0913 UGTABLET 4 inch PenTablet
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x28bd 
  idProduct          0x0913 
  bcdDevice            0.00
  iManufacturer           1 UGTABLET
  iProduct                2 4 inch PenTablet
  iSerial                 3 000000
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x005b
    bNumInterfaces          3
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower               70mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      2 Mouse
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.00
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     177
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               4
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      2 Mouse
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.00
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     109
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               3
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.00
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      36
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x000c  1x 12 bytes
        bInterval               3
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x03  EP 3 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x000c  1x 12 bytes
        bInterval              10
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0000
  (Bus Powered)

Running uclogic-probe breaks the tablet, so it changes USB ID and stops sending any HID events:

# ./uclogic-probe 6 41
M 55 00 47 00 54 00 41 00 42 00 4C 00 45 00 54 00
P 34 00 20 00 69 00 6E 00 63 00 68 00 20 00 50 00 65 00 6E 00 54 00 61 00 62 00 6C 00 65 00 74 00
S 64 0E 03 B0 27 C4 1D 06 00 FF 1F EC 09 00 00
S 65 04 03 00 67
S 6E 0B 03 00 30 00 03 08 01 00 00 00
S 79 10 03 20 20 20 20 20 20 20 20 20 20 20 20 20 20
S 7A 08 03 00 00 00 00 00 00
S 7B 0C 03 48 00 4B 00 20 00 4F 00 6E 00
Failed to get string descriptor 0xC8: Input/Output Error

### after reconnect
# ./uclogic-probe 6 43 | ./uclogic-decode   
    |           Manufacturer: UGTABLET
    |                Product: 4 inch PenTablet
 64 |        Params block #1: ??????
    |                          Max X: 10160
    |                          Max Y: 7620
    |                   Max pressure: 8191
    |                     Resolution: 2540
    |
 79 |         Internal model: ???????
Failed to get string descriptor 0xC8: Input/Output Error
 7b |         Buttons status: HK On

# ./uclogic-probe 6 44 | ./uclogic-decode  
    |           Manufacturer: UGTABLET
    |                Product: TABLET

# lsusb -v -d 28bd:1227

Bus 006 Device 044: ID 28bd:1227 UGTABLET TABLET
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x28bd 
  idProduct          0x1227 
  bcdDevice            0.00
  iManufacturer           1 UGTABLET
  iProduct                2 TABLET
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x007b
    bNumInterfaces          4
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower               70mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.11
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      29
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      2 Mouse
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.00
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     177
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               4
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      2 Mouse
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.00
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     237
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               3
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        3
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.00
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      36
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x84  EP 4 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x000a  1x 10 bytes
        bInterval               3
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x04  EP 4 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              10
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0001
  Self Powered

For this reason I'm going to collect the rest of data after I reconnect the tablet without uclogic-probe anymore.

I have repeated every test several times in one file. The device likely doesn't support tilt but I have tried to record it as well just in case.
pen_buttons.txt
pen_pressure.txt
pen_tilt.txt
pen_coords.clockwise.txt

I have also run some tests from http://digimend.github.io/support/howto/trbl/locating_failure/

# ls /sys/kernel/debug/hid/
0003:28BD:0913.00CA/  0003:28BD:0913.00CB/  0003:28BD:0913.00CC/
## The first and last device produce no output, the middle device produces events like this:

report (size 10) (numbered) =  07 a0 88 27 76 75 00 00 00 00
Digitizers.TipSwitch = 0
Digitizers.BarrelSwitch = 0
Digitizers.Eraser = 0
Digitizers.Invert = 0
Digitizers.InRange = 1
GenericDesktop.X = 10120
GenericDesktop.Y = 30070
Digitizers.TipPressure = 0
Digitizers.003d = 0
Digitizers.003e = 0

TipSwitch corresponds to touch,
BarrelSwitch corresponds to lower pen button,
Eraser corresponds to upper pen button,
Invert is 0, InRange is indicating whenever the pen is within ~ 1 inch from the tablet
X, Y, TipPressure seems to report pen coordinates from 0 to 32767 and tip pressure from 0 to 8191,
003d and 003e remain 0.

So the default kernel driver seems to work correctly with this pen for Linux 5.4.

I don't know if this is going to be useful, I also add this command's output:
head -n 9999 /sys/kernel/debug/hid/*/rdesc

@Sturwandan
Copy link
Author

I have tried to fix it myself with this patch, but did achieve nothing:

diff --git a/hid-ids.h b/hid-ids.h
--- a/hid-ids.h
+++ b/hid-ids.h
@@ -52,6 +52,8 @@
 #define USB_VENDOR_ID_UGEE			0x28bd
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540	0x0075
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640	0x0094
+// XP-PEN G430S_B stands for black version
+#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G430S_B	0x0913
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01	0x0042
 #define USB_DEVICE_ID_UGEE_TABLET_G5		0x0074
 #define USB_DEVICE_ID_UGEE_TABLET_EX07S		0x0071
diff --git a/hid-uclogic-core.c b/hid-uclogic-core.c
--- a/hid-uclogic-core.c
+++ b/hid-uclogic-core.c
@@ -529,6 +529,8 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
 				USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
+				USB_DEVICE_ID_UGEE_XPPEN_TABLET_G430S_B) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
 				USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
 				USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
diff --git a/hid-uclogic-params.c b/hid-uclogic-params.c
--- a/hid-uclogic-params.c
+++ b/hid-uclogic-params.c
@@ -1178,6 +1178,9 @@
 		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45):
 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
 		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47):
+	// an attempt to hack G430S_B here
+	case VID_PID(USB_VENDOR_ID_UGEE,
+		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G430S_B):
 		rc = uclogic_params_huion_init(&p, hdev);
 		if (rc != 0)
 			goto cleanup;

DIGImend detects the tablet, but the code makes it change USB ID to 28bd:1227 and the tablet doesn't work anymore until it is reconnected.

When I add the new ID near G430S white (which shares ID with G540), I have same effect as I had when I tried to just replace USB ID.
The console is flooded with
usb 6-3: input irq status -75 received
When I bring the pen close to the tablet, and the tablet doesn't work, here is dmesg:

usb 6-3: new full-speed USB device number 53 using ohci-pci
usb 6-3: New USB device found, idVendor=28bd, idProduct=0913, bcdDevice= 0.00
usb 6-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 6-3: Product: 4 inch PenTablet
usb 6-3: Manufacturer: UGTABLET
usb 6-3: SerialNumber: 000000
input: UGTABLET 4 inch PenTablet Mouse as /devices/pci0000:00/0000:00:16.0/usb6/6-3/6-3:1.0/0003:28BD:0913.00DC/input/input238
input: UGTABLET 4 inch PenTablet Keyboard as /devices/pci0000:00/0000:00:16.0/usb6/6-3/6-3:1.0/0003:28BD:0913.00DC/input/input239
hid-generic 0003:28BD:0913.00DC: input,hidraw0: USB HID v1.00 Mouse [UGTABLET 4 inch PenTablet] on usb-0000:00:16.0-3/input0
input: UGTABLET 4 inch PenTablet as /devices/pci0000:00/0000:00:16.0/usb6/6-3/6-3:1.1/0003:28BD:0913.00DD/input/input240
hid-generic 0003:28BD:0913.00DD: input,hidraw1: USB HID v1.00 Device [UGTABLET 4 inch PenTablet] on usb-0000:00:16.0-3/input1
hid-generic 0003:28BD:0913.00DE: hiddev96,hidraw2: USB HID v1.00 Device [UGTABLET 4 inch PenTablet] on usb-0000:00:16.0-3/input2
usb 6-3: USB disconnect, device number 53
uclogic 0003:28BD:0913.00DC: failed retrieving string descriptor #200: -62
uclogic 0003:28BD:0913.00DC: failed retrieving pen parameters: -62
uclogic 0003:28BD:0913.00DC: failed probing pen v2 parameters: -62
uclogic 0003:28BD:0913.00DC: failed probing parameters: -62
uclogic: probe of 0003:28BD:0913.00DC failed with error -62
uclogic 0003:28BD:0913.00DD: No inputs registered, leaving
uclogic 0003:28BD:0913.00DD: hidraw0: USB HID v1.00 Device [UGTABLET 4 inch PenTablet] on usb-0000:00:16.0-3/input1
uclogic 0003:28BD:0913.00DE: interface is invalid, ignoring
usb 6-3: new full-speed USB device number 54 using ohci-pci
usb 6-3: New USB device found, idVendor=28bd, idProduct=1227, bcdDevice= 0.00
usb 6-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 6-3: Product: TABLET
usb 6-3: Manufacturer: UGTABLET
hid-generic 0003:28BD:1227.00DF: hiddev96,hidraw0: USB HID v1.11 Device [UGTABLET TABLET] on usb-0000:00:16.0-3/input0
input: UGTABLET TABLET Mouse as /devices/pci0000:00/0000:00:16.0/usb6/6-3/6-3:1.1/0003:28BD:1227.00E0/input/input242
input: UGTABLET TABLET Keyboard as /devices/pci0000:00/0000:00:16.0/usb6/6-3/6-3:1.1/0003:28BD:1227.00E0/input/input243
hid-generic 0003:28BD:1227.00E0: input,hidraw1: USB HID v1.00 Mouse [UGTABLET TABLET] on usb-0000:00:16.0-3/input1
input: UGTABLET TABLET as /devices/pci0000:00/0000:00:16.0/usb6/6-3/6-3:1.2/0003:28BD:1227.00E1/input/input244
input: UGTABLET TABLET as /devices/pci0000:00/0000:00:16.0/usb6/6-3/6-3:1.2/0003:28BD:1227.00E1/input/input245
hid-generic 0003:28BD:1227.00E1: input,hiddev97,hidraw2: USB HID v1.00 Device [UGTABLET TABLET] on usb-0000:00:16.0-3/input2
hid-generic 0003:28BD:1227.00E2: hiddev98,hidraw3: USB HID v1.00 Device [UGTABLET TABLET] on usb-0000:00:16.0-3/input3

I guess, either I am doing something wrong or adding support for this tablet is not that easy.
I have tried to put the code near white tablet, then I didn't have the device to change ID, but it didn't work either, emitting interface is invalid, ignoring and flooding the logs with usb 6-3: input irq status -75 received when pen is in range.

@Sturwandan
Copy link
Author

Sturwandan commented May 8, 2020

I have fixed the tablet behavior with this change within thekernel source:

--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -828,8 +828,9 @@
                         * Actual eraser (BTN_TOOL_RUBBER) is set by Invert usage when
                         * tool gets in proximity.
                         */
-                       map_key_clear(BTN_TOUCH);
-                       break;
+                       // A dirty hack to make G430S_B work as it should
+                       //map_key_clear(BTN_TOUCH);
+                       //break;
 
                case 0x46: /* TabletPick */
                case 0x5a: /* SecondaryBarrelSwitch */

This patch does, of course, break support for all tablets which do have an actual eraser switch on the back, but it works as temporary fix for people who only have one tablet.

In order for The GIMP to recognize the tablet you need to (re)start GIMP while the tablet is connected.

The reason, why the button did not work is the HID descriptor sent by the tablet itself (I have posted it above in binary form). It reports that it has an eraser, however generic input driver expects the tablet having an eraser to be flipped over and change the state of "Inverted" to set the tool to eraser, and then eraser button will work as use of this tool. While G430S_B does not have a backside button and the pen can't be detected when flipped upside down. This patch changes eraser behavior making it act as second side button, but this is not a proper fix, only a hack to make this particular tablet work properly. After this patch lower button works as middle mouse button as before, but upper button starts to work as right mouse button.

@Sturwandan
Copy link
Author

Sturwandan commented May 10, 2020

Next step is to try and switch the tablet to its native mode with coordinates going up to (10160, 7620) instead of (32767, 32767) and HID reports being 12 bytes long instead of 10.
In order to do this, I had to read some articles regarding USB protocol and monitoring.
First of all, I have tried to record the text dump of exchange between a proprietary driver Linux_Pentablet_V1.2.13.1.tar.gz(20200428) and the tablet, this is done simply by this command:

cat /sys/kernel/debug/usb/usbmon/4u | tee usbmon_4u.txt

This method works, but it's kinda hard to analyze. If you want anyway, read this.

There is a program, vusb-analyzer, which is supposed to help decoding the text dumps, however I didn't get it to work on a modern system. There is a newer version moved from sourceforge to github, however it's also old and I didn't try it.

So, I have had to use tcpdump -i usbmon4 -w usbmon4.pcap to record USB events in a different format, which can be fed into wireshark.
Later on, comparing both text and binary output I was able to pinpoint two exchanges, which are of interest. The first one:

ffff99e840165480 3047498234 S Ci:3:007:0 s 80 06 0364 0409 0200 512 <
ffff99e840165480 3047499053 C Ci:3:007:0 0 14 = 0e03b027 c41d0600 ff1fec09 0000

This is request and answer to get string descriptor 0x64, which is similar to what is done by uclogic-probe above:

S 64 0E 03 B0 27 C4 1D 06 00 FF 1F EC 09 00 00
 64 |        Params block #1: ??????
    |                          Max X: 10160
    |                          Max Y: 7620
    |                   Max pressure: 8191
    |                     Resolution: 2540

The next echange is this one:

ffff99e840165b40 3047581421 S Io:3:007:3 -115:8 3 = 02b004
ffff99e840165b40 3047589051 C Io:3:007:3 0:8 3 >
ffff99e834042000 3047591046 C Ii:3:007:3 0:2 10 = 02b10400 00000000 0000

The first line means sending three bytes {0x02, 0xB0, 0x04} as interrupt transfer to endpoint 0x03

I have tried to change uclogic-probe.c to make it send this interrupt transfer after it's done with probing. This task proved quite challenging because even after I had the code in place, it would not work, returning -1 which means I/O error. After a while I have looked in dmesg and noticed this message: usb 4-5: usbfs: process 1080 (uclogic-probe) did not claim interface 1 before use
This have explained why I wasn't able to send the packet and now I made it work:

--- uclogic-probe.c.orig
+++ uclogic-probe.c
@@ -127,8 +127,9 @@
     libusb_device_handle   *handle      = NULL;
     unsigned char           buf[257];
     int                     len;
-    uint8_t                 idx_list[]  = {0x64, 0x65, 0x6E, 0x79, 0x7A,
-                                           0x7B, 0xC8, 0xC9, 0xCA};
+//    uint8_t                 idx_list[]  = {0x64, 0x65, 0x6E, 0x79, 0x7A,
+//                                           0x7B, 0xC8, 0xC9, 0xCA};
+    uint8_t                 idx_list[] = {0x64};
     uint8_t                 idx;
 
     struct libusb_device_descriptor     dev_desc;
@@ -197,6 +198,25 @@
         /* Print the descriptor */
         print_chunk('S', buf, len + 1);
     }
+
+/* Trying to send some bytes to USB device
+ *int libusb_interrupt_transfer(struct libusb_device_handle *devh,
+ *                                            unsigned char endpoint, 
+ *                                            unsigned char *data, 
+ *                                                      int length, 
+ *                                                      int *transferred, 
+ *                                             unsigned int timeout)
+ */
+    int bytes_transferred = 0;
+    unsigned char interrupt_data[3] = {0x02, 0xB0, 0x04};
+    int driver_active = libusb_kernel_driver_active(handle, 1);
+    int claim_status = libusb_claim_interface(handle, 1);
+    int interrupt_status = libusb_interrupt_transfer(handle, 0x03, interrupt_data, sizeof(interrupt_data), &bytes_transferred, 500);
+    int release_status = libusb_release_interface(handle, 1);
+    printf("INTERRUPT: DRV:%d CLAIMED:%d INT:%d RELEASED:%d Bytes:%d | %p, %08X, %d\n", driver_active, claim_status, interrupt_status, release_status,
+          bytes_transferred, handle, *(uint32_t*)interrupt_data, sizeof(interrupt_data));
+// end of packet transfer.
+
     result = 0;
 
 cleanup:

This code works as expected:

# modprobe -r usbhid hid_generic
# ./uclogic-probe 4 21
M 55 00 47 00 54 00 41 00 42 00 4C 00 45 00 54 00
P 34 00 20 00 69 00 6E 00 63 00 68 00 20 00 50 00 65 00 6E 00 54 00 61 00 62 00 6C 00 65 00 74 00
S 64 0E 03 B0 27 C4 1D 06 00 FF 1F EC 09 00 00
INTERRUPT: DRV:0 CLAIMED:0 INT:0 RELEASED:0 Bytes:3 | 0x167d9d0, 0304B002, 3
# modprobe usbhid hid_generic

After it's done, I start to get 12 bytes HID reports:

# usbhid-dump -es | head -30
Starting dumping interrupt transfer stream
with 1 minute timeout.

004:021:002:STREAM             1589085235.477630
 02 B1 04 00 00 00 00 00 00 00

004:021:002:STREAM             1589085239.289547
 02 A0 26 15 22 16 00 00 00 00 00 00

004:021:002:STREAM             1589085239.293632
 02 A0 27 15 28 16 00 00 00 00 00 00

The first report corresponds to USB dump from exchange with proprietary driver, other reports have similar formats to 10-bytes reports above, but the first byte is 02 instead of 07 and coordinates are going from (0, 0) to native tablet resolution. The last four bytes remain 00.

However, tablet does not work anymore after that, and HID reports from it are only recognized by usbhid-dump and usbmon. /sys/kernel/debug/hid/*/events do not register any events anymore.

The same thing can be seen if you start and then stop proprietary driver. The tablet is sending events, but they are not processed. The likely reason is that the HID report descriptor is still the same, as it was, so the hid driver cannot decode the tablet events anymore, after their format has been changed.

@Sturwandan
Copy link
Author

Sturwandan commented May 12, 2020

So, the next step is to make the kernel driver. There are two possibilities: easier and harder.
The easy way is to model the new driver after existing hid-redragon.c in the kernel source.
It does only change only one byte in HID report descriptor of that keyboard and it's very short.

The harder way involves sending bytes 0x02, 0xB0, 0x04 via an interrupt transfer, similar to what modified uclogic-probe.c does, as described above. The driver will also need a freshly written HID Report descriptor which allow the kernel to understand 12-bytes long reports, which in this mode, are sent from interface 2, rather than interface 1 (starting from 0).

The result of easy way is very short and easy to understand:

/*
 *  HID driver for XP-PEN G430S_B, simple version
 *  Based on hid-redragon.c Copyright (c) 2017 Robert Munteanu
 *  Copyright (c) 2020 Sturwandan
 *  SPDX-License-Identifier: GPL-2.0+
 */

/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 */

#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>

#include "hid-ids.h"

/* The original report descriptor usage for upper button is set to Eraser (0x09 0x45),
*  While the correct usage is TabletPick (0x09 0x46). This code fixes it. */
static __u8 *g430sb_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) {
	if (*rsize == 109 && rdesc[16] == 0x09 && rdesc[17] == 0x45) {
		dev_info(&hdev->dev, "Fixing XP-PEN Star G430S_B report descriptor.\n");
		rdesc[17] = 0x46;
	}
	return rdesc;
}

static const struct hid_device_id g430sb_devices[] = {
	{HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_G430SB)},
	{}
};

MODULE_DEVICE_TABLE(hid, g430sb_devices);

static struct hid_driver g430sb_driver = {
	.name = "g430sb",
	.id_table = g430sb_devices,
	.report_fixup = g430sb_report_fixup
};

module_hid_driver(g430sb_driver);

MODULE_LICENSE("GPL");

However in order for this driver to work, this patch is necessary so it's build together with other DIGImend drivers:

diff -ru digimend-kernel-drivers-master/Makefile digimend-kernel-drivers-modified/Makefile
--- digimend-kernel-drivers-master/Makefile
+++ digimend-kernel-drivers-modified/Makefile
@@ -1,4 +1,4 @@
-obj-m := hid-kye.o hid-uclogic.o hid-polostar.o hid-viewsonic.o
+obj-m := hid-kye.o hid-uclogic.o hid-polostar.o hid-viewsonic.o hid-g430sb.o
 hid-uclogic-objs := \
 	hid-uclogic-core.o \
 	hid-uclogic-rdesc.o \
@@ -44,7 +44,8 @@
 	rm -vf /lib/modules/*/extra/hid-kye.ko \
 	       /lib/modules/*/extra/hid-polostar.ko \
 	       /lib/modules/*/extra/hid-uclogic.ko \
-	       /lib/modules/*/extra/hid-viewsonic.ko
+	       /lib/modules/*/extra/hid-viewsonic.ko \
+	       /lib/modules/*/extra/hid-g430sb.ko
 
 install: modules_install udev_rules_install depmod_conf_install xorg_conf_install
 	udevadm control --reload
diff -ru digimend-kernel-drivers-master/dkms.conf digimend-kernel-drivers-modified/dkms.conf
--- digimend-kernel-drivers-master/dkms.conf
+++ digimend-kernel-drivers-modified/dkms.conf
@@ -6,7 +6,9 @@
 BUILT_MODULE_NAME[1]="hid-uclogic"
 BUILT_MODULE_NAME[2]="hid-polostar"
 BUILT_MODULE_NAME[3]="hid-viewsonic"
+BUILT_MODULE_NAME[4]="hid-g430sb"
 DEST_MODULE_LOCATION[0]="/extra"
 DEST_MODULE_LOCATION[1]="/extra"
 DEST_MODULE_LOCATION[2]="/extra"
 DEST_MODULE_LOCATION[3]="/extra"
+DEST_MODULE_LOCATION[4]="/extra"
diff -ru digimend-kernel-drivers-master/hid-ids.h digimend-kernel-drivers-modified/hid-ids.h
--- digimend-kernel-drivers-master/hid-ids.h
+++ digimend-kernel-drivers-modified/hid-ids.h
@@ -52,6 +52,8 @@
 #define USB_VENDOR_ID_UGEE			0x28bd
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540	0x0075
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640	0x0094
+// XP-PEN G430S_B stands for black version
+#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G430SB	0x0913
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01	0x0042
 #define USB_DEVICE_ID_UGEE_TABLET_G5		0x0074
 #define USB_DEVICE_ID_UGEE_TABLET_EX07S		0x0071

I have tested this driver with my tablet and it seems to work fine.

@Sturwandan
Copy link
Author

I have also made a native mode driver, it works, however there is an unsolved problem still.
The source code is here
Along with this file you also need to apply the patch from comment above, to make the build system recognize it.

This driver switches the tablet to native mode first, sending bytes 0x02, 0xB0, 0x04 via an interrupt transfer to interface 0x03. This is different from all other tablets supported by DIGImend, so it's easier to write this driver in a separate file.

In order to make this driver, I have taken hid-viewsonic.c driver and replaced the text strings with appropriate. It turns out that all the drivers have similar layout and I could have started from hid-redragon.c too, but I didn't discover it until much later.

In order to send interrupt transfer, I needed to know the name of kernel function (which is not same as name of libusb function above) and how to use it.
It was easy to figure out the name: First of all by reading uclogic driver, I have found that usb_control_msg was used to get string descriptors. Then grepping it in linux kernel source, I have found the include file, which it is from: /usr/src/linux/include/linux/usb.h
Then, figuring out the other USB functions are there too, I have found this definition:

extern int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
        void *data, int len, int *actual_length, int timeout);

The same include file usb.h has explanation, how to make a pipe knowing the endpoint: usb_sndintpipe(udev, endpoint), and other arguments are similar to what is found in libusb.

However there is a pitfall: for some reason this function can't just send data from regular variable, it needs that data to be located in a specific kind of memory, while local variables in functions are in kernel stack and not suitable. So I had to learn how to use kmalloc and kcalloc and copy those three bytes into a newly created buffer. Otherwise I was getting error -11 (EAGAIN) and wasn't able to figure out where it's coming from, since in wireshark it seemed that the USB packet was sent correctly and then the device responded with this error.

The next problem was that there were no hid-reports from the device in evtest or /sys/kernel/debug/hid/*/events but usbhid-dump tool was able to demonstrate 12 byte reports, so the kernel was sending the correct packets.

I have thought that was because of incorrect HID Report descriptor and tried to debug it.
It turns out that the best tool to check whenever it's correct or not is to load it into the kernel and check corresponding rdesc file. For example with the final version of the report I am getting this:

==> /sys/kernel/debug/hid/0003:28BD:0913.0003/rdesc <==
05 0d 09 02 a1 01 85 02 09 20 a1 00 09 42 09 44 09 46 15 00 25 01 75 01 95 03 81 02 95 02 81 03 09 32 95 01 81 02 95 02 81 03 a4 05 01 09 30 15 00 26 b0 27 65 11 55 0d 35 00 46 b0 27 75 10 95 01 81 22 09 31 26 c4 1d 46 c4 1d 81 22 b4 09 30 15 00 26 ff 1f 75 10 95 01 81 02 95 02 81 03 c0 c0 

  INPUT(2)[INPUT]
    Field(0)
      Physical(Digitizers.Stylus)
      Application(Digitizers.Pen)
      Usage(3)
        Digitizers.TipSwitch
        Digitizers.BarrelSwitch
        Digitizers.TabletPick
      Logical Minimum(0)
      Logical Maximum(1)
      Report Size(1)
      Report Count(3)
      Report Offset(0)
      Flags( Variable Absolute )
    Field(1)
      Physical(Digitizers.Stylus)
      Application(Digitizers.Pen)
      Usage(1)
        Digitizers.InRange
      Logical Minimum(0)
      Logical Maximum(1)
      Report Size(1)
      Report Count(1)
      Report Offset(5)
      Flags( Variable Absolute )
    Field(2)
      Physical(Digitizers.Stylus)
      Application(Digitizers.Pen)
      Usage(1)
        GenericDesktop.X
      Logical Minimum(0)
      Logical Maximum(10160)
      Physical Minimum(0)
      Physical Maximum(10160)
      Unit Exponent(-3)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(8)
      Flags( Variable Absolute NoPreferredState )
    Field(3)
      Physical(Digitizers.Stylus)
      Application(Digitizers.Pen)
      Usage(1)
        GenericDesktop.Y
      Logical Minimum(0)
      Logical Maximum(7620)
      Physical Minimum(0)
      Physical Maximum(7620)
      Unit Exponent(-3)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(24)
      Flags( Variable Absolute NoPreferredState )
    Field(4)
      Physical(Digitizers.Stylus)
      Application(Digitizers.Pen)
      Usage(1)
        Digitizers.TipPressure
      Logical Minimum(0)
      Logical Maximum(8191)
      Report Size(16)
      Report Count(1)
      Report Offset(40)
      Flags( Variable Absolute )

Digitizers.TipSwitch ---> Key.Touch
Digitizers.BarrelSwitch ---> Key.Stylus
Digitizers.TabletPick ---> Key.Stylus2
Digitizers.InRange ---> Key.ToolPen
GenericDesktop.X ---> Absolute.X
GenericDesktop.Y ---> Absolute.Y
Digitizers.TipPressure ---> Absolute.Pressure

As you can see, unlike this tool or hidrd, kernel provides full info about every field you are trying to interpret, including its bit-offset in hid reports.

While trying to catch this problem, I have added check for interface number in both fixup and probe functions, so that will be only run once and added some more minor improvements.
It didn't help at first, because I haven't noticed immediately, that the HID reports are emitted from the third interface in native mode, while they were emitted from the second one in default mode.

So after all those problems were fixed, I got a working driver for my tablet. However, one problem is still unsolved:
The driver works only if it is loaded after the tablet plugged in, and doesn't work, if you replug the table, however reinserting the driver with modprobe makes it work again.
I would be grateful if anybody provided me any insights why it could be happened.

@alfazaz
Copy link

alfazaz commented May 23, 2020

Hello @Sturwandan,

Thank you for all these informations.

I have no idea about your problem unsolved but I see that in #291 , there is also the same init of tablet in the function uclogic_params_init_ugee_xppen_a156p and may be there is somewhere an answer to your problem ?

As for me, I'm still blocked for my XP PEN Artist 12 Pro (#351). usbhid-dump tool is able to demonstrate 12 byte reports, so the kernel sends the correct packets but... still no success with evtest. May be a small detail but... :-(

@Sturwandan
Copy link
Author

@alfazaz, actually, usbhid-dump bypasses kernel drivers and talks with hardware directly. So if you see something in it, it only means that the tablet sends reports correctly, but it doesn't mean that it is interpreted correctly. I suggest to try doing the same thing I did: find out encoding of your tablet reports and make sure that its description in rdesc is correct, especially bit offsets and usages. And make sure that it's coming from interface you expect.

@alfazaz
Copy link

alfazaz commented May 23, 2020

So, if I understand things well, I need to write a good rdesc. I'm working on it (I'm not an expert of these things so it's hard for me... If you have concrete tricks, you can write them on #351). Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants