Author Topic: Beagleboard HID firmware for Win7 Host  (Read 36305 times)

len_white

  • Member
  • ***
  • Posts: 9
Beagleboard HID firmware for Win7 Host
« on: June 24, 2013, 02:57:29 pm »
Hello! I'm a huge fan of Jan's generous contributions to the USB community. Extremely useful. Thanks.

However, I'm running into a problem I can't get past.
I'm writing HID firmware on a Beagleboard-XM (Angstrom Linux) that allows it to function as a HID multi-touch device, primarily targeting Windows 7, for now.
By modifying hid.c I've created a custom kernel module g_hid.ko that works to create a single-touch HID device.
However, I thought going to multi-touch would be straightforward, but it's not. I can't get Windows 7 to recognized the Beagleboard's multiple touch events.
My suspicion from research is that Windows 7 is making a hid feature request for maximum number of touches that my Beagleboard is not responding to.
Problem is, this is where my understanding of the Linux HID kernel module stops. I can't figure out how to add that functionality.
Anyone know anything about Linux HID kernel module programming?
Any leads on where I can research to understand better are appreciated as well.
I'm really at sea on this one and am willing to hire a freelancer if I can find one to help finish the project.
Thanks and please contact me if you are interested.
-Len



Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Beagleboard HID firmware for Win7 Host
« Reply #1 on: June 24, 2013, 10:46:45 pm »
A protocol analyzer or other debugging techniques can tell you definitively what is happening on the bus.

http://lxr.free-electrons.com/source/drivers/hid/hid-multitouch.c

The BeagleBoard google group might have some advice.

len_white

  • Member
  • ***
  • Posts: 9
Re: Beagleboard HID firmware for Win7 Host
« Reply #2 on: June 26, 2013, 01:50:00 am »
Thanks, Jan.
Correct me if I'm wrong but that code you linked to is for a host-side driver, correct?
The Beagleboard-side firmware driver will have to use the gadget architecture, right?

-Len

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Beagleboard HID firmware for Win7 Host
« Reply #3 on: June 26, 2013, 09:53:21 am »

len_white

  • Member
  • ***
  • Posts: 9
Re: Beagleboard HID firmware for Win7 Host
« Reply #4 on: June 30, 2013, 04:21:29 pm »
Thanks for the leads. I've pored overt those posts previously seeing if they hold the secret to my issue.
However, they still seems focused on the host-side of the equation.
I really need to understand better how linux is handling feature requests to provide the host with the appropriate multi-touch flags.
hid.c is the key, I think. That's the linux source that handles all the requests from the host for report descriptors and, I think, feature requests.
Those feature requests are going un-answered, as far as I can tell from studying the code.
But perhaps there's another file entirely that handles those requests?
As far as I can tell only one socket is being created via hid.c (/dev/hidg0) so that couldn't handle both types of requests, right?

-Len

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Beagleboard HID firmware for Win7 Host
« Reply #5 on: June 30, 2013, 05:32:13 pm »
One way to do it is to attach a similar, working device and monitor the traffic.

Use whatever debugging tools you have to find out how your device is responding to the requests for Feature reports. Is the endpoint STALLing the request to indicate that the device doesn't support the request? Or ??

len_white

  • Member
  • ***
  • Posts: 9
Re: Beagleboard HID firmware for Win7 Host
« Reply #6 on: June 30, 2013, 07:14:07 pm »
Good ideas. Thanks.
Attaching a similar device is not easy for me since I don't have another multi-touch HID peripheral that works with Windows.
From what I can see of hid.c, a feature request response is not part of the linux hid gadget source.
At least not that I can tell.
It opens a socket at /dev/hidg0 and then basic reports (matching the top part of the report descriptor) can be sent through this and received by the Windows host.
However, this lets me send touch point data but, as far as I can tell, not feature request data.
So Windows never acknowledges more than one touch.
I could and will try to monitor the exact structure of the feature requests sent by the windows host (if they are indeed being sent at all).
It's only my guess at this point that a feature request is going un-responded-to. May be some other reason not more than one touch event is processed by the host.
But that won't change the sad fact that I'm a bit at a loss to understand how to respond to those feature requests in the linux kernel module source.
Linux is tough!  : )

-Len


Tsuneo

  • Frequent Contributor
  • ****
  • Posts: 145
Re: Beagleboard HID firmware for Win7 Host
« Reply #7 on: June 30, 2013, 10:31:03 pm »
Hi Len,

Quote
However, this lets me send touch point data but, as far as I can tell, not feature request data.

Multi-touch device should return one-byte "Contact Count Maximum" feature report, either in Parallel/Hybrid/Serial Reporting Mode.

In drivers/usb/gadget/f_hid.c, however, hidg_setup() returns empty report to Get_Report() request, either for input or for feature.

Code: [Select]
http://lxr.free-electrons.com/source/drivers/usb/gadget/f_hid.c#L372

372 static int hidg_setup(struct usb_function *f,
373                 const struct usb_ctrlrequest *ctrl)
374 {
    ...
387         switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
388         case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
389                   | HID_REQ_GET_REPORT):
390                 VDBG(cdev, "get_report\n");
391
392                 /* send an empty report */
393                 length = min_t(unsigned, length, hidg->report_length);
394                 memset(req->buf, 0x0, length);
395
396                 goto respond;
397                 break;

Modify it as follows, and try if any other problem would occur.
Code: [Select]
#define HID_REPORT_TYPE_INPUT    0x01
#define HID_REPORT_TYPE_OUTPUT   0x02
#define HID_REPORT_TYPE_FEATTURE 0x03

if ( ctrl->wValue == HID_REPORT_TYPE_FEATTURE << 8 ) {  // for Get_Report( FEATURE )
    length = 1;
    req->buf[0] = your_Contact_Count_Maximum;
    goto respond;
}

Tsuneo

len_white

  • Member
  • ***
  • Posts: 9
Re: Beagleboard HID firmware for Win7 Host
« Reply #8 on: July 21, 2013, 01:00:57 pm »
That is fantastic!
Thank you Tsuneo! I'm going to try your suggestions today and see how it goes.
(sorry for the late response - been crunched at my new job)

-Len

len_white

  • Member
  • ***
  • Posts: 9
Re: Beagleboard HID firmware for Win7 Host
« Reply #9 on: July 28, 2013, 03:35:50 pm »
I'm not getting the result I expected with this code update.
I insert the following just inside hidg_setup of f_hid.c but get no indication of the printk from dmesg, meaning that the condition is never being met.

if ( ctrl->wValue == HID_REPORT_TYPE_FEATURE << 8 ) {  // for Get_Report( FEATURE )
         memset(req->buf, 0x0f, 1);
         printk(KERN_ALERT, "Feature report requested and responded!");
         goto respond;
}

I can confirm that hidg_setup is being called correct from another printk just within.
Should the feature request be made every time a new hid connection is established or more often?

Thanks for the very useful help thus far.
-Len

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Beagleboard HID firmware for Win7 Host
« Reply #10 on: July 28, 2013, 09:54:38 pm »
A host can request a HID Feature report whenever it wants.

Tsuneo

  • Frequent Contributor
  • ****
  • Posts: 145
Re: Beagleboard HID firmware for Win7 Host
« Reply #11 on: July 29, 2013, 08:28:40 am »
Quote
the condition is never being met.
Ah, I missed that report ID of the Contact Count Max should be coded.

Code: [Select]
#define HID_REPORT_ID_MAX_COUNT  0x02

if ( ctrl->wValue == ((HID_REPORT_TYPE_FEATTURE << 8) | HID_REPORT_ID_MAX_COUNT ) ) {

On your report descriptor, the report ID value may be different from above one. Tune it.

Tsuneo

len_white

  • Member
  • ***
  • Posts: 9
Re: Beagleboard HID firmware for Win7 Host
« Reply #12 on: August 07, 2013, 10:27:59 am »
I see. Interesting. Thank you. I'll try that.
MAX_COUNT can be a much larger number than 2, right?
Does anyone know what Windows allows?

Tsuneo

  • Frequent Contributor
  • ****
  • Posts: 145
Re: Beagleboard HID firmware for Win7 Host
« Reply #13 on: August 08, 2013, 09:56:45 am »
To pass Device.Digitizer Testing of Windows Hardware Certification Kit, at least five touches are required.

Windows Touch Five Point Minimum Test
http://msdn.microsoft.com/en-us/library/windows/hardware/jj125183.aspx

Tsuneo

len_white

  • Member
  • ***
  • Posts: 9
Re: Beagleboard HID firmware for Win7 Host
« Reply #14 on: August 10, 2013, 01:09:38 pm »
Unfortunately, that didn't help.
It's still not satisfying that conditional:
ctrl->wValue == ((HID_REPORT_TYPE_FEATTURE << 8) | HID_REPORT_ID_MAX_COUNT

I wonder...is there something in the feature descriptor that needs to match HID_REPORT_ID_MAX_COUNT?
I don't see it appearing anywhere.
Could a mismatch there cause a problem?

I've copied my report descriptor (from hid.c) for trying to get two simultaneous touches working next. Could you see if it looks ok? Thanks so much for the aid.

static struct hidg_func_descriptor my_hid_data_multitouch_2 = {
.subclass      = 0, /* No subclass */
   .protocol      = 0, /* 1=Keyboard 2=Mouse */
   .report_length      = 15,
   .report_desc_length   = 145,
   .report_desc      = {
    0x05, 0x0D,           // USAGE_PAGE (Digitizers)       
    0x09, 0x04,           // USAGE (Touch Screen)             
    0xA1, 0x01,           // COLLECTION (Application)         
    0x85, 0x01,           //   REPORT_ID (Touch)      DATA - byte #1           
    0x09, 0x22,           //   USAGE (Finger)                 
    0xA1, 0x02,           //     COLLECTION (Logical)    - first touch
    0x09, 0x42,           //       USAGE (Tip Switch)           
    0x15, 0x00,           //       LOGICAL_MINIMUM (0)         
    0x25, 0x01,           //       LOGICAL_MAXIMUM (1)         
    0x75, 0x01,           //       REPORT_SIZE (1)             
    0x95, 0x01,           //       REPORT_COUNT (1)             
    0x81, 0x02,           //       INPUT (Data,Var,Abs)    DATA   - 1 bit
    0x09, 0x32,           //       USAGE (In Range)             
    0x81, 0x02,           //       INPUT (Data,Var,Abs)    DATA  - 1 bit
    0x95, 0x06,           //       REPORT_COUNT (6) 
    0x81, 0x03,           //       INPUT (Cnst,Ary,Abs)    DATA  - byte #2 
    0x75, 0x08,           //       REPORT_SIZE (8)
    0x09, 0x51,           //       USAGE (Contact Identifier) 
    0x95, 0x01,           //       REPORT_COUNT (1)             
    0x81, 0x02,           //       INPUT (Data,Var,Abs)      DATA  - byte #3
    0x05, 0x01,           //       USAGE_PAGE (Generic Desk..
    0x26, 0xFF, 0x0F,     //       LOGICAL_MAXIMUM (4095)         
    0x75, 0x10,           //       REPORT_SIZE (16)             
    0x55, 0x00,           //       UNIT_EXPONENT (0)           
    0x65, 0x00,           //       UNIT (None)                 
    0x09, 0x30,           //       USAGE (X)                   
    0x35, 0x00,           //       PHYSICAL_MINIMUM (0)         
    0x46, 0x00, 0x00,     //       PHYSICAL_MAXIMUM (0)         
    0x81, 0x02,           //       INPUT (Data,Var,Abs)        DATA - byte #4,5
    0x26, 0xFF, 0x0B,     //       LOGICAL_MAXIMUM (3071)     
    0x09, 0x31,           //       USAGE (Y)                   
    0x81, 0x02,           //       INPUT (Data,Var,Abs)          DATA - byte #6,7    (67)
    0xC0,                 //    END_COLLECTION
    0xA1, 0x02,           //     COLLECTION (Logical)   - second touch
    0x09, 0x42,           //       USAGE (Tip Switch)           
    0x15, 0x00,           //       LOGICAL_MINIMUM (0)         
    0x25, 0x01,           //       LOGICAL_MAXIMUM (1)         
    0x75, 0x01,           //       REPORT_SIZE (1)             
    0x95, 0x01,           //       REPORT_COUNT (1)             
    0x81, 0x02,           //       INPUT (Data,Var,Abs)       
    0x09, 0x32,           //       USAGE (In Range)             
    0x81, 0x02,           //       INPUT (Data,Var,Abs)         
    0x95, 0x06,           //       REPORT_COUNT (6) 
    0x81, 0x03,           //       INPUT (Cnst,Ary,Abs)         
    0x75, 0x08,           //       REPORT_SIZE (8)
    0x09, 0x51,           //       USAGE (Contact Identifier) 
    0x95, 0x01,           //       REPORT_COUNT (1)             
    0x81, 0x02,           //       INPUT (Data,Var,Abs)       
    0x05, 0x01,           //       USAGE_PAGE (Generic Desk..
    0x26, 0xFF, 0x0F,     //       LOGICAL_MAXIMUM (4095)         
    0x75, 0x10,           //       REPORT_SIZE (16)             
    0x55, 0x00,           //       UNIT_EXPONENT (0)           
    0x65, 0x00,           //       UNIT (None)                 
    0x09, 0x30,           //       USAGE (X)                   
    0x35, 0x00,           //       PHYSICAL_MINIMUM (0)         
    0x46, 0x00, 0x00,     //       PHYSICAL_MAXIMUM (0)         
    0x81, 0x02,           //       INPUT (Data,Var,Abs)       
    0x26, 0xFF, 0x0B,     //       LOGICAL_MAXIMUM (3071)     
    0x09, 0x31,           //       USAGE (Y)                   
    0x81, 0x02,           //       INPUT (Data,Var,Abs)         
    0xC0,                 //    END_COLLECTION  (67 + 59)

    0x05, 0x0D,           //   USAGE_PAGE (Digitizers)   
    0x09, 0x54,           //   USAGE (Actual count)
    0x95, 0x01,           //   REPORT_COUNT (1)
    0x75, 0x08,           //   REPORT_SIZE (8) 
    0x15, 0x00,           //    LOGICAL_MINIMUM (0)
   0x25, 0x08,           //    LOGICAL_MAXIMUM (8)
    0x81, 0x02,           //   INPUT (Data,Var,Abs)     DATA - byte #8 or #14 (two touch)                 
    0x09, 0x55,           //   USAGE(Maximum Count)
    0xB1, 0x02,           //   FEATURE (Data,Var,Abs)    DATA - byte #15 -- ?
    0xC0                  // END_COLLECTION  (67 + 59 + 19)
}