Re: [DIGImend-devel] PT-1001 digitizer
Brought to you by:
spb_nick
|
From: Nikolai K. <sp...@gm...> - 2015-01-25 14:41:14
|
Hi Yann,
On 01/20/2015 03:46 PM, Yann Vernier wrote:
> I have a couple of PT-1001 tablets, also known as " Digi Tablet" over USB.
> Mine happen to be branded Leogics, but many other brands occur, including none.
> The USB vendor is 0x099a Zippy Technology Corp.
>
> It presents three interfaces: one keyboard and two pointers. The purpose of
> the second pointer device is somewhat unclear as it does not seem to produce
> events, but its descriptors do describe it as a stylus with only three buttons
> plus presence.
The second pointer interface is probably for a mouse (or "puck" in the old
parlance), which is supported by the hardware, but is not supplied with this
product. OTOH, they support "mouse" mode as is and the tablet working area is
very small, although the hardware might support bigger ones.
> With recent Linux kernels these produce no events and a couple of warnings:
> [ 6719.887522] hid-generic 0003:099A:2620.001C: input,hidraw3: USB HID v1.10 Keyboard [ Digi Tablet] on usb-0000:00:14.0-7/input0
> [ 6719.997108] hid-generic 0003:099A:2620.001D: unknown main item tag 0x0
> [ 6719.997114] hid-generic 0003:099A:2620.001D: unbalanced collection at end of report description
> [ 6719.997121] hid-generic: probe of 0003:099A:2620.001D failed with error -22
>
> I've tracked that problem down; Linux requests precisely the exact buffer and
> transfer size for the report descriptors, and this device has an off by one
> bug where it doesn't send the last byte. In the particular descriptor for the
> events it does send, that last byte is a C0 = End Collection, so the structure
> breaks and Linux ignores that interface (it has three). USB transfer dumps
> show Windows requests 64 bytes more than the descriptor size, which explains
> why it does not trigger this bug.
Wow, that is quite an ugly bug and neat research!
> Possible workarounds include patching in that extra byte or requesting more
> (both tested and work). A proper fix would probably include not trying to
> parse more descriptor data than the device actually returned.
Well, such fix still wouldn't work with devices which would get a more
important part of their report descriptor lost. Then, making the parser handle
all the possible failures it introduces would make it too complicated.
> I do suggest requesting more than the descriptor length by default, since
> this bug may be present in other devices (possibly as a misinterpretation of
> USB's use of a full frame to indicate more data is available). My own test
> was simply to add 1 to rsize and dev_rsize in kmalloc and
> hid_get_class_descriptor calls within drivers/hid/usbhid/hid-core.c, but
> that doesn't check how much was actually received.
This would be one controversial solution. How much more would we need to
request? Would this encourage more sloppy HID descriptors in the future? When
should we stop requesting more and more?
I would say we simply replace the device descriptor with a rewritten
descriptor as is done for many other devices already. See hid-uclogic.c for
example.
> That's not the end of the story, however. Even with proper parsing of the
> descriptors it seems the tablet only has one interface that reports a stylus,
> and it's not the one sending events. This causes the Xorg driver to deduce it
> is a touchpad, not a pen tablet, with all the resulting defects (relative
> mode, ignoring events when the nib isn't pressed). It also reports a rather
> mystifying set of buttons (from xinput list-props, but do come from kernel,
> as confirmed using input-events):
> Button Labels (276): "Button Left" (145), "Button Middle" (146),
> "Button Right" (147), "Button Wheel Up" (148), "Button Wheel Down" (149),
> "Button Horiz Wheel Left" (150), "Button Horiz Wheel Right" (151),
> "Button Side" (265), "Button Extra" (266), "Button Forward" (714),
> "Button Back" (715), "Button Task" (716), "Button Unknown" (264),
> "Button Unknown" (264), "Button Unknown" (264), "Button Unknown" (264)
> The second pointer device reported, which does not produce events, has an
> equally useless button map:
> "Button 0" (630), "Button Unknown" (264), "Button Unknown" (264),
> "Button Wheel Up" (148), "Button Wheel Down" (149)
>
> The actual buttons (nib and two side buttons on the stylus) are those
> reported as Forward, Back and Task. Remapping them with xinput set-button-map
> and setting absolute mode makes it usable but with the serious issue of not
> moving the pointer if the nib isn't pressed (the pressure level works in
> inkscape). I did not find a way to tell Xorg's evdev driver that the device
> is a tablet.
Windows report descriptor parsing works quite differently from Linux and such
mapping issues happen often.
We can avoid this problem altogether by simply using appropriate field
usages in the rewritten report descriptor.
> Among the firmware controlled soft buttons (tappable with the stylus) on
> the tablet itself is a mouse/stylus switch control. The other side fields
> produce other events, mostly keyboard combinations (common zoom hotkeys,
> save, open, copy, paste etc) and scroll events. Using this toggle to set
> mouse mode causes the first group of buttons to be used, so does map to
> mouse buttons by default, but the pointer motion is ignored by X (since
> it does not report pressure, this might be an artifact of its touchpad
> misinterpretation). The keyboard events are sent on interface 0.
>
> So, on interface 1, we have a bunch of possible reports:
> 1 5 button relative XY, sent in mouse mode (boot protocol compatible?)
> 2 scroll wheel? duplicated in descriptor. usages Wheel and AC Pan
> 3 Unknown use, looks like keyboard reports
> 5 multimedia buttons
> 9 tablet mode stylus events
> As it happens, it looks like it sticks to report 9 and keyboard events
> on interface 0, switching to report 1 in mouse mode.
Wow! This is the first tablet I see that is trying to actually convert
various working area events into something else in *hardware*, i.e. on the
device side. All others do this in the driver.
> And the kernel has dutifully collected all those possible buttons in one
> device, placing the tablet ones at number 10-12. The hint that this is
> a pen tablet is in interface 2, which maps to another device. It could
> be that Windows associates the two, maybe by bInterfaceProtocol=3?
>
> The failing heuristic in Xorg's evdev driver is:
> if ((libevdev_has_event_code(pEvdev->dev, EV_ABS, ABS_X) &&
> libevdev_has_event_code(pEvdev->dev, EV_ABS, ABS_Y))) {
> xf86IDrvMsg(pInfo, X_PROBED, "Found x and y absolute axes\n");
> if (libevdev_has_event_code(pEvdev->dev, EV_KEY, BTN_TOOL_PEN) ||
> libevdev_has_event_code(pEvdev->dev, EV_KEY, BTN_STYLUS) ||
> libevdev_has_event_code(pEvdev->dev, EV_KEY, BTN_STYLUS2))
> {
> xf86IDrvMsg(pInfo, X_PROBED, "Found absolute tablet.\n");
> pEvdev->flags |= EVDEV_TABLET;
> if (!pEvdev->num_buttons)
> {
> pEvdev->num_buttons = 7; /* LMR + scroll wheels */
> pEvdev->flags |= EVDEV_BUTTON_EVENTS;
> }
> } else if (libevdev_has_event_code(pEvdev->dev, EV_ABS, ABS_PRESSURE) ||
> libevdev_has_event_code(pEvdev->dev, EV_KEY, BTN_TOUCH)) {
> if (has_lmr || libevdev_has_event_code(pEvdev->dev, EV_KEY, BTN_TOOL_FINGER)) {
> xf86IDrvMsg(pInfo, X_PROBED, "Found absolute touchpad.\n");
> pEvdev->flags |= EVDEV_TOUCHPAD;
> } else {
> xf86IDrvMsg(pInfo, X_PROBED, "Found absolute touchscreen\n");
> pEvdev->flags |= EVDEV_TOUCHSCREEN;
> pEvdev->flags |= EVDEV_BUTTON_EVENTS;
> }
> } else if (!(libevdev_has_event_code(pEvdev->dev, EV_REL, REL_X) &&
> libevdev_has_event_code(pEvdev->dev, EV_REL, REL_Y)) && has_lmr) {
> /* some touchscreens use BTN_LEFT rather than BTN_TOUCH */
> xf86IDrvMsg(pInfo, X_PROBED, "Found absolute touchscreen\n");
> pEvdev->flags |= EVDEV_TOUCHSCREEN;
> pEvdev->flags |= EVDEV_BUTTON_EVENTS;
> }
> } else {
> #ifdef MULTITOUCH
> if (!libevdev_has_event_code(pEvdev->dev, EV_ABS, ABS_MT_POSITION_X) ||
> !libevdev_has_event_code(pEvdev->dev, EV_ABS, ABS_MT_POSITION_Y))
> #endif
> EvdevForceXY(pInfo, Absolute);
> }
>
> For interface 1 this code finds absolute axis, including pressure, but no
> button marked stylus (it is marked as mouse button 1, but mislabeled as Back
> by the kernel somehow), and so it decides on a touchpad. This single error
> causes it to set relative mode and ignore any motion without pressure.
>
>
> So, opinions? How should these flaws be patched?
This X.org heuristic is pretty hairy, yes, but we can still cater to it by
using appropriate report descriptor(s).
So, I think the path to a solution here should be making a separate HID driver
for this tablet and having a new set of report descriptors written, replacing
the original ones. Perhaps with some bit tweaking of the input reports as
well.
You can take hid-uclogic.c for boilerplate, as the most basic HID driver at
the moment doing similar things. If you know how report descriptors work you
can try making one yourself. I can suggest using my hidrd-convert [1] tool for
authoring, although there are a few others. You can find some examples of
rewritten descriptor XML sources in our tablets repo [2] - search for
"fixed*.xml".
Otherwise you can map the bits of all the reports on all the interfaces and I
can try writing them for you, but doing it yourself might be faster and more
fun :)
Thank you for thorough research and description of the problem!
Nick
[1] https://github.com/DIGImend/hidrd
[2] https://github.com/DIGImend/tablets
|