[libhid-discuss] Digital Arts & Crafts Studio - HID help needed

Charles Lepple clepple at ghz.cc
Wed Nov 7 01:00:35 UTC 2007


On Nov 6, 2007, at 1:21 PM, Bill Kendrick wrote:

> Hi there, I just subscribed.  I'm author of the open source kid's
> drawing program "Tux Paint" ( http://www.tuxpaint.org/ )

Hi!

Tux Paint looks pretty nice... and it's not every day that we hear  
from people wanting to add HID functionality to a fully working project.

> I thought it would be a cool thing to support under Tux Paint, and  
> as a
> gift, my wife bought me one.  (They're about $50USD.)  It comes with
> Windows software, which I've not tried yet, but upon plugging it  
> into a
> Linux 2.6.22 system (a Kubuntu 7.10 laptop), a device node at
> "/dev/usb/hiddev0" appeared.  It sends a continuous stream of data
> when I read it (e.g., using "xxd"), which repeats every 88 bytes.
> The data changes when I press buttons or move the stylus on the  
> device,
> so I was pretty confident I'd get it to do something under Linux.

As a developer, I'm sure this is second nature to you, but thank you  
for giving us a good idea about what system you are working with.

> Some folks directed me to libhid, and I've begun (began?) creating  
> a small
> test app to read from the device.  I'm finally to the point where I  
> can
> call "hid_get_input_report()", but at the moment, I'm getting  
> nothing but
> zeros.  I think I'm using the wrong 'usage' path, so came here to  
> get help.

I am not totally familiar with how the code handles these vendor- 
specific usage paths, but you can get some debug information from  
libhid that should tell you what it is retrieving.

Also, if you were just doing a simple read() on /dev/usb/hiddev0, it  
was probably doing interrupt transfers, and hid_get_input_report()  
uses control transfers.

In theory, the only difference is that interrupt reads will get  
whatever report is available next, and a control transfer will allow  
you to select a specific report.

However, your device only has one report, and in reality, the  
firmware programmers can map interrupt reads to completely different  
functionality than the control transfers. Or maybe they didn't  
implement control transfers at all. In Windows, I believe that a  
simple read of the HID device will try to do an interrupt read on the  
first applicable endpoint, so maybe that's all it supports.

> Here's the output from "lsusb -vvv" for the specific device
> ("-d 0x0813:0x1006").  Based on this, I thought I'd only need to
> specify one path for input, "0xff000001", but...?

It probably has to be { 0xff000001, 0xff00001 } and/or { 0xff000001,  
0xff000002 } because there is a collection item in between the Usage  
Page and the Usage Min/Max statements.

But then again, you don't actually need usage paths for interrupt  
reads. (With a report structure this simple, I will admit that libhid  
is overkill, and you can just use the code as a guide for how to call  
libusb directly.)

>             Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
>                             (null)
>             Item(Local ): Usage, data= [ 0x01 ] 1
>                             (null)
>             Item(Main  ): Collection, data= [ 0x01 ] 1
>                             Application
>             Item(Local ): Usage Minimum, data= [ 0x01 ] 1
>                             (null)
>             Item(Local ): Usage Maximum, data= [ 0x02 ] 2
>                             (null)
>             Item(Global): Logical Minimum, data= [ 0x80 ] 128
>             Item(Global): Logical Maximum, data= [ 0x7f ] 127
>             Item(Global): Report Size, data= [ 0x08 ] 8
>             Item(Global): Report Count, data= [ 0x0b ] 11

The 88 bytes is probably 4 reads of 22 bytes each, or 8 reads of 11  
bytes. (Report Size is in bits.)

>       Endpoint Descriptor:
>         bLength                 7
>         bDescriptorType         5
>         bEndpointAddress     0x82  EP 2 IN

You will want to pass this endpoint address to whichever interrupt  
read function you call (libusb or libhid).

>         bmAttributes            3
>           Transfer Type            Interrupt
>           Synch Type               None
>           Usage Type               Data
>         wMaxPacketSize     0x0010  1x 16 bytes

Bear in mind that in libusb (and as a consequence, libhid), you can  
read more than wMaxPacketSize bytes at a time - the kernel will break  
the request up into smaller URBs as appropriate. I would advise using  
88 bytes, if that's what the minimum repeat length looks like.

-- 
Charles Lepple
clepple at ghz.cc





More information about the libhid-discuss mailing list