Confused about USB HID devices

Hi everyone,

I am trying to write a device driver for a USB HID device. The device in question is a Braille display (electronic equipment that transforms letters into braille dots for blind people to read). Potentially, this driver may be the stepping stone for expanding our installer so that blind people may be able to install FreeBSD without sighted assistance.

My problem is that, seemingly no matter what I do, I cannot get my braille display to show any output if I go through my device driver. If I send output from a test program written with the aid of libusb, the display shows everything correctly, but when I send the same data from my test device driver, I get an error code of 22.

When I send the following data packet from my libusb program, I see the word "Hello" on the braille display: (Every value is in decimal. The first three bytes is HID output report byte for this device, next byte is offset on the display and the third is the length of the data to be shown on the display)
Code:
"2 0 40 83 17 7 7 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0"
When I try to send the same data packet from within my device driver, I get an error code with the value 22. I insert my USB callback function below:
Code:
static void alva_write_callback(struct usb_xfer* xfer, usb_error_t err) {
struct alva_softc* sc = usbd_xfer_softc(xfer);
struct usb_device_request req;
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
req.bRequest=UR_SET_REPORT;
USETW2(req.wValue, UHID_OUTPUT_REPORT, 2);
req.wIndex[0]=1;
req.wIndex[1]=0;
USETW(req.wLength, 43);
mtx_lock(&sc->mtx);
switch (USB_GET_STATE(xfer)) {
case USB_ST_SETUP:
printf("Inside USB write setup state.\n");
usbd_xfer_set_frame_data(xfer,0,&req,8);
unsigned char Packet[43] = {0};
Packet[0]=2;
Packet[1]=0;
Packet[2]=40;
Packet[3] = 83;
Packet[4] = 17;
Packet[5] = 7;
Packet[6] = 7;
Packet[8] = 21;
for (int i = 9; i < 43; i++) Packet[i]=0;
usbd_xfer_set_frame_data(xfer,1,Packet,43);
usbd_transfer_submit(xfer);
break;
case USB_ST_TRANSFERRED:
printf("Reached the transferred state.\n");
break;
default:
printf("An error must have occurred. Error code: %d\n", err);
usbd_transfer_clear_stall(xfer);
break;
}
mtx_unlock(&sc->mtx);
}
I am quite out of ideas as to how I might solve the problem. I will gladly provide any additional information, but I'm quite new to writing device drivers, so please bear with me if I have missed anything obvious or missed out important information. I have looked through the USB HID driver, read the HID specification and Googled and nothing has given me any clues. I hope someone out here can help guide me in the right direction.

All the best,
Peter.
FreeBSD 8.2-i386
 
Probably, you have figure it out by yourself, but usbd_xfer_XX() are for bulk pipes. If you want to use control pipe (to pass usb_device_request), you need to use usbd_do_request_flags() or usbd_do_request().
 
Thanks for your reply. I'll try out the method you have suggested. Only thing seeming a little strange is that neither /usr/src/sys/dev/usb/usb_hid.c nor the manual page for usbdi gives any examples of using usbd_do_request() or the other functions.

All the best,

Peter.
FreeBSD 8.2-i386
 
Solved

You pointed me to the solution all along. Thanks a lot. I guess by the time I wrote the post I was too blind to notice that one little function call.

Anyway, for the interested:

I ended up calling
Code:
usbd_req_set_report()
directly instead of going through intermediate layers of function calls. It turns out you can call this function from the function that writes to your HID device without any problems at all.
In my case, this is a character device, so it was chosen because of that.

As of today, my braille device driver supports two separate displays, one HID device and one other device, but that's all for another thread and another time.

All the best,

Peter.
 
Back
Top