Author Topic: Generic bi-directional HID Driver for Linux  (Read 16773 times)

coolsunny2012

  • Member
  • ***
  • Posts: 19
Generic bi-directional HID Driver for Linux
« on: June 18, 2012, 06:41:28 pm »
Hi,

I am a beginner and started learning more about HID. I need to develop a HID driver as a generic driver with full duplex communication.
I am able to register my device as KeyBoard (http://www.mjmwired.net/kernel/Documentation/usb/gadget_hid.txt) with this link.

But i am not sure whether i can register as generic HID driver with full duplex comm. Following is the structure i thought off and the windows sees my device as "USB Input device" (with warning symbol ) and it fails to start with error code "10".  

 I also was curious how the windows device manager would show up if we configure HID driver as a generic.

Dev Environment:
Linux Kernel 2.6.35 with iMX28 processor.

I would appreciate any help?

static struct hidg_func_descriptor my_hid_data = {
   .subclass      = 0, /* No subclass */
   .protocol      = 0, /* Keyboard */
   .report_length      = 1024,
   .report_desc_length   = 43,
   .report_desc      = {
      0x06, 0xFF00,      /* USAGE_PAGE (Generic Desktop)             */
      0x09, 0x01,         /* USAGE                       */
      0xa1, 0x01,         /* COLLECTION (Application)               */
      0x09, 0x01,
      0x15, 0x00,
      0x26, 0xFF00,
      0x96, 0x04,
      0x75, 0x08,
      0x81, 0x02,
      0x09, 0x01,
      0x15, 0x00,
      0x26, 0xFF,
      0x96, 0x10,
      0x75, 0x08,
      0x91, 0x02,
      0xc0            /* END_COLLECTION                         */
   }
};


static struct usb_device_descriptor device_desc = {
   .bLength =      sizeof device_desc,
   .bDescriptorType =   USB_DT_DEVICE,

   .bcdUSB =      cpu_to_le16(0x0200),

   /* .bDeviceClass =      USB_CLASS_COMM, */
   /* .bDeviceSubClass =   0, */
   /* .bDeviceProtocol =   0, */
   .bDeviceClass =      0xEF,
   .bDeviceSubClass =   2,
   .bDeviceProtocol =   1,
   /* .bMaxPacketSize0 = f(hardware) */

   /* Vendor and product id can be overridden by module parameters.  */
   .idVendor =      cpu_to_le16(HIDG_VENDOR_NUM),
   .idProduct =      cpu_to_le16(HIDG_PRODUCT_NUM),
   /* .bcdDevice = f(hardware) */
   /* .iManufacturer = DYNAMIC */
   /* .iProduct = DYNAMIC */
   /* NO SERIAL NUMBER */
   .bNumConfigurations =   1,
};
« Last Edit: June 18, 2012, 06:46:01 pm by coolsunny2012 »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Generic bi-directional HID Driver for Linux
« Reply #1 on: June 18, 2012, 08:36:26 pm »
If you're looking for generic HID device code for Linux, see my example here:

http://lvr.com/beagleboard.htm

Jan

coolsunny2012

  • Member
  • ***
  • Posts: 19
Re: Generic bi-directional HID Driver for Linux
« Reply #2 on: June 19, 2012, 11:07:07 am »
Thanks for quicker response. The examples that are provided in the link are at application level and definitely they are helpful.
But I am struck at the kernel driver level registration.
Can you let me know if you see any problem with the above structure or please share if you've a generic driver HID "struct hidg_func_descriptor" structure so that i can give a try.

All i was trying to do is to register a Bi-directional HID driver with 1024 bytes packet size.

Tsuneo

  • Frequent Contributor
  • ****
  • Posts: 145
Re: Generic bi-directional HID Driver for Linux
« Reply #3 on: June 19, 2012, 01:46:50 pm »
Hi coolsunny2012,

Your report descriptor has a couple of bugs.

Code: [Select]
0x26, 0xFF00, // <-- 0x26, 0xFF, 0x00, // LOGICAL_MAX(255)
0x96, 0x04,   // <-- 0x95, 0x04,       // REPORT_COUNT(4)
...
0x26, 0xFF,   // <-- 0x26, 0xFF, 0x00, // LOGICAL_MAX(255)
0x96, 0x10,   // <-- 0x95, 0x10,       // REPORT_COUNT(16)

I recommend you to check (parse) it on the HID Descriptor Tool.

HID Descriptor Tool on USB.org
http://www.usb.org/developers/hidpage/dt2_4.zip

Tsuneo

coolsunny2012

  • Member
  • ***
  • Posts: 19
Re: Generic bi-directional HID Driver for Linux
« Reply #4 on: June 20, 2012, 11:22:11 am »
Thanks Tsuneo for your time in helping me to figure out this issue. I figured out that by comparing with Jan's code.

Do you've any pointers for the following:

1. I don't understand how the "report_length" in the structure "hidg_func_descriptor" is decided
2. On USBLyzer i still see my device as KeyBoard and not sure  which descriptor/structure member has to be changed in order to register as Generic HID device.
3. Also in order to increase the report size to 1023 bytes, i tried the following and it didn't work. I've hard time in using the HID descriptor tool to validate my data.
      0x75, 0x08,         /*  Report Size (8 bits)                */
      0x95, 0x03,0xFF,      /*  Report Count (2 fields)             */
4. Is there a way to increase the report size more than 1024 bytes Or this is the max. size any report can have?




Tsuneo

  • Frequent Contributor
  • ****
  • Posts: 145
Re: Generic bi-directional HID Driver for Linux
« Reply #5 on: June 20, 2012, 01:34:06 pm »
Quote
1. I don't understand how the "report_length" in the structure "hidg_func_descriptor" is decided

It's wMaxPacketSize of the interrupt IN endpoint.
report_length of your hidg_func_descriptor is copied to local f_hidg structure.
Code: [Select]
http://lxr.free-electrons.com/source/drivers/usb/gadget/f_hid.c#L609

583 int __init hidg_bind_config(struct usb_configuration *c,
584                             struct hidg_func_descriptor *fdesc, int index)
585 {
        ...
609         hidg->report_length = fdesc->report_length;

And then, report_length is passed to wMaxPacketSize of the IN endpoint.
Code: [Select]
http://lxr.free-electrons.com/source/drivers/usb/gadget/f_hid.c#L487

451 static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
452 {
        ...
487         hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
488         hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);

Quote
2. On USBLyzer i still see my device as KeyBoard and not sure  which descriptor/structure member has to be changed in order to register as Generic HID device.

Did you change VID/PID of your device, for the new report descriptor?

OR

Did you uninstall your keyboard instance on Windows Device Manager, if you would assign the same VID/PID?

To uninstall previous device, which is not in hand,

1) Copy these two lines to a blank text file, and rename the file into DevManager.bat (any .bat will do)

set devmgr_show_nonpresent_devices=1
start devmgmt.msc

2) Double click on DevManager.bat (or choose "run as admin" on right-click menu for Vista and later)
Device Manager comes up.

3) On 'View' menu of Device Manager, select 'Show hidden devices'

Now, Device Manager shows up all device instances on the registry, regardless of its current connection.


Quote
0x95, 0x03,0xFF,      /*  Report Count (2 fields)             */
For two-bytes field, the Report Count prefix is 0x96 - the LSB two bits of this prefix represents field size.
Also, the data field is aligned in LSB first.

0x96, 0xFF, 0x03,        /*  Report Count (0x03FF)             */

Refer to these chapters of the HID spec,
- 6.2.2.2 Short Items
- 6.2.2.7 Global Items


Quote
4. Is there a way to increase the report size more than 1024 bytes

No problem.
Give right format on the report descriptor.

Tsuneo

coolsunny2012

  • Member
  • ***
  • Posts: 19
Re: Generic bi-directional HID Driver for Linux
« Reply #6 on: June 20, 2012, 07:13:09 pm »
I appreciate your quicker response.

Quote
1. I don't understand how the "report_length" in the structure "hidg_func_descriptor" is decided

O.K.  I now understand the mapping more clearly. Actually my original question was how this "report_length" is calculated.
For the KeyBoard it is "8" and not sure how the report length "8" came up. Is it the maximum size of the report in the collection?.

Code: [Select]
/* hid descriptor for a keyboard */
25 static struct hidg_func_descriptor my_hid_data = {
26 .subclass = 0, /* No subclass */
27 .protocol = 1, /* Keyboard */
[b]28 .report_length = 8,[/b]
29 .report_desc_length = 63,
30 .report_desc = {
31 0x05, 0x01, /* USAGE_PAGE (Generic Desktop)           */
32 0x09, 0x06, /* USAGE (Keyboard)                       */
33 0xa1, 0x01, /* COLLECTION (Application)               */
34 0x05, 0x07, /*   USAGE_PAGE (Keyboard)                */

62 0xc0 /* END_COLLECTION                         */
63 }
64 };


Please take a look at my modified structure and for time being i put the "report_length"  as "255" and wondering what is the correct value ?.

Code: [Select]
static struct hidg_func_descriptor my_hid_data = {
.subclass = 0, /* No subclass */
.protocol = 0, /* Generic */
.report_length = 255,
.report_desc_length = 47,
.report_desc = {
0x06, 0xA0,0xFF, /* USAGE_PAGE (vendor defined)         */
0x09, 0x01, /* Usage ID (vendor defined) */
0xa1, 0x01, /* COLLECTION (Application)             */
0x09, 0x03, /*  Usage ID - vendor defined */
0x15, 0x00, /*  Logical Minimum (0)     */
0x26, 0xFF,0x03, /*  Logical Maximum (255)     */
0x75, 0x20, /*  Report Size (x bits)                */
0x95, 0xFF, /*  Report Count (x fields) */
0x81, 0x02, /*  Input (Data, Variable, Absolute)    */
0x09, 0x04, /*  Usage ID - vendor defined */
0x15, 0x00, /*  Logical Minimum (0) */
0x26, 0xFF,0x03, /*  Logical Maximum (255)   */
0x75, 0x20, /*  Report Size (8 bits)                */
0x95, 0xFF, /*  Report Count (255 fields)   */
0x91, 0x02, /*  Output (Data, Variable, Absolute)   */
0x09, 0x05, /*  Usage ID - vendor defined  */
0x15, 0x00, /*  Logical Minimum (0) */
0x26, 0xFF,0x03, /*  Logical Maximum (255)   */
0x75, 0x20, /*  Report Size (8 bits)                */
0x95, 0xFF, /*  Report Count (255 fields)   */
0xB1, 0x02, /*  Feature (Data, Variable, Absolute)  */
0xc0 /* END_COLLECTION                       */
}
};

Quote
4. Is there a way to increase the report size more than 1024 bytes

With your suggested changes, I increased the size to 1024 bytes. But can you please let me know what is the maximum size that can be configured for any report.
For our application, I am guessing atleast 10K Bytes/more than 10K Bytes packet size is needed in both ways.

I am able to increase the packet size to 1020 bytes  as below. Please comment.
0x75, 0x20,         /*  Report Size (32 bits)                */
0x95, 0xFF,         /*  Report Count (255 fields)         */


Tsuneo

  • Frequent Contributor
  • ****
  • Posts: 145
Re: Generic bi-directional HID Driver for Linux
« Reply #7 on: June 22, 2012, 04:02:00 am »
Quote
Actually my original question was how this "report_length" is calculated.

As I pointed out in above post, report_length is passed to the wMaxPacketSize of the interrupt IN EP descriptor. Now, your question is, how is wMaxPacketSize determined.

The max allowable payload size of interrupt transaction is 64 bytes on full-speed. For high-speed, it's also 64 bytes, without switching to alternate interface.

While the report size is less than 64 bytes, the report size is assigned to wMaxPacketSize, usually, to save the amount of bus bandwidth reservation. For the report size of 64 bytes or more, wMaxPacketSize is set to 64 bytes.

Quote
With your suggested changes, I increased the size to 1024 bytes.

Huh?
If you would follow my suggestion, we should see
0x75, 0x08,         /*  Report Size (8 bits)                */
0x96, 0x00, 0x04    /*  Report Count (1024 fields)          */

Why don't you use HID Descriptor Tool?
It'll generates above report descriptor code, immediately.


Quote
For our application, I am guessing atleast 10K Bytes/more than 10K Bytes packet size is needed in both ways.

For such a large data, bulk transfer (on CDC or vendor specific) exchanges the data more quickly than HID.

Tsuneo

coolsunny2012

  • Member
  • ***
  • Posts: 19
Re: Generic bi-directional HID Driver for Linux
« Reply #8 on: June 22, 2012, 11:53:18 am »
Thanks Tsuneo for your help !!