USB Multi configuration device

I am writing a USB class device driver for a USB device that has two configurations in it (FreeLite5200, QNX 6.3.2). The active default configuration is of USB mass storage class and the other configuration is of USB HID class.

I am trying to change the device configuration to the non-default one, i.e., HID class from my driver’s driver insertion call back. I used the QNX USB library function usbd_select_config to change the configuration. And the function returns EOK, giving an impression that the configuration is changed.

But the device is not functioning as an HID device. I used the QNX HID utility ‘hidview’ to see the HID devices connected to the system, but I couldn’t see my device listed in it.

So I think, either the configuration is still not changed in the device or the host is not becoming aware of this change.

Could any one give more insight into whether QNX supports the handling of USB devices with multiple configurations? Or is there anything more my driver has to do?

Shehan

Shehan,

I don’t have a definitive answer for you because I’ve never tried to do what you are doing but I do have a suggestion.

What does usb -vvv report for your usb device before you do the usbd_select_config call? What does it report afterwards? That might tell you if usbd_select_config actually worked.

I suspect you may need to restart devi-hid (the HID driver) after you do your usbd_select_config call so that devi-hid goes out and checks again for HID devices because I assume you aren’t re-inserting the actual USB device (and I further assume hidview doesn’t re-interrogate all the USB devices but rather just has the driver print out what it already knows about).

Tim

I know that QNX USB stack had huge problems handling multiple interfaces and multiple alternate settings therein. Maybe it has a problem handling multiple configurations, too…

After your call to usbd_select_config(), can you access the first configuration once more or is it gone forever?

Albrecht

Hi,

Thank you for your response.

Tim, usb -vvv reports the same before and after usbd_select_config call.

Albrecht, I couldn’t access the first configuration after usbd_select_config() call, may be because config 2 selection succeeded. Later, further experiments revealed that the usbd_select_config call indeed worked. I could set an HID report using usbd_setup_vendor (for control endpoint 0 of config2) & usbd_io calls. The device gave the response as expected for that report, indicating that the config selection worked.

As you can see, I haven’t used any HID interface functions (hidd_xx) for this. Now, I have to use the hidd_ interface for getting/setting HID reports & interpret them in a meaningful format.

My thinking:
For using the hidd_ interface functions, hidd_connect must be called during initialization. This probably causes the corresponding hid device insertion callback to be called on an HID-device-insert. But, my driver has to act as a non-HID USB device driver till the HID configuration selection and later on, act as an HID driver. How can this be made possible?

My issue:

Generally, the issue is, how to use the io-hid interface functions from my driver? Now since the HID class configuration is successfully selected, I might be able to.

I tried writing separate drivers, but after changing the configuration from the first driver, I expected the hid insert callback of the second driver (HID) to be called, but it didn’t. I think re-enumeration may cause the HID insert routine to be called, am I correct? How can I make the device reenumerated without removal and reinsert (device removal and reinsertion causes the configuration to change back to the default mass storage one).

Thanks
Shehan

Shehan,

You should only get the insertion callback if you actually re-insert the device (which you can’t do for the reasons you stated).

Afrer you reconfigure the usb device as a HID device I believe you are going to have to stop and restart io-hid. Otherwise I can’t see how io-hid is going to know that the configuration changed.

So in your driver try stopping and restarting io-hid after you reconfigure your usb device and then see if you can use the hidd_xx calls.

Tim

Tim,

Thanks for the inputs.

I tried the following from the usb device insertion callback.

(1) attach the device using usbd_attach
(2) changed the configuration to 2, using usbd_select_config
(3) detach the device using usbd_detach
(4) slayed and restarted io_hid
(5) called hidd_connect

I expected the hidd insertion callback to be called. But it didn’t.

Is there anything wrong in the steps?

Shehan

Shehan,

The steps you describe are the ones I would expect would work.

Two things:

  1. If you run hidview before changing the configuration via usbd_select_config and then after slaying/restarting io-hid what do the two hidviews show? I would expect the 2nd one would now show your device. If it doesn’t, that would indicate one reason why you aren’t being called.

  2. Here is some code I have for a connecting to USB hid device and getting my insertion callback. I assume yours is similar (tho in my case I don’t have to change usb configurations like you do as I have a pure hid device)?

void PMD_Insertion(struct hidd_connection *conn, hidd_device_instance_t *device)
{
    printf("PMD_Insertion - Got insertion callback\n");

    // Rest stripped out
}

int PMD_Connect(int vendor, int product, int fd[])
{
	int i;
	int retVal = 0;
	int num_interfaces = 1;    // number of interfaces for this HID device
	char devname[80];
	char devname_old[80];
	hidd_device_ident_t *device_info;
	hidd_funcs_t *device_fns;
	
	printf("PMD_Connect\n");

	hidParam = malloc(sizeof(struct hidd_connect_parm));
	
	device_info = malloc(sizeof(hidd_device_ident_t));
	device_info->vendor_id = vendor;
	device_info->product_id = product;
	device_info->version = HIDD_CONNECT_WILDCARD;

	device_fns = malloc(sizeof(hidd_funcs_t));
	device_fns->nentries = _HIDDI_NFUNCS;
	device_fns->insertion = &PMD_Insertion;
	device_fns->removal = &PMD_Removal;
	device_fns->report = NULL;
	device_fns->event = NULL;
						 
	hidParam->path = NULL;
	hidParam->vhid = HID_VERSION;
	hidParam->vhid = HIDD_VERSION;
	hidParam->flags = 0;
	hidParam->evtbufsz = 0;
	hidParam->device_ident = device_info;
	hidParam->funcs = device_fns;
	hidParam->connect_wait = HIDD_CONNECT_WAIT;

	retVal = hidd_connect(hidParam, &hidCon);
	if (retVal != EOK)
	{
		printf ("PMD_Connect() - hidd_connect returned error of %d\n", retVal);
	}
	
	return num_interfaces;
}

Tim

Tim,

(1) hidview before and after usbd_select_config show the same thing.

HIDD v1.00, v1.00 DDK

But I am pretty sure that the config changed to the HID one, as I could succesfully set a report and the device responded as expected.

(2) My code is also similar except in the case of vendor & prod IDs in the hidd_device_ident_t object, for which I used wild-cards. And, for an HID mouse, I found my drivers HID insertion callback getting invoked, but not for my device. I have changed the vendor & product ID filters to specific values for my device, but that also didn’t work.

Any more experiments, which I can do to figure out what could be wrong?

The QNX USB & HID driver documentation is poor. Do you have any pointers to documents on QNX HID driver development?

Shehan

Shehan,

  1. Since hidview isn’t finding your device then I suspect that stopping and restarting io-hid isn’t enough.

It’s possible you will have stop and start io-usb as well. That of course would mean your own program would have to handle io-usb going away and being restarted. In other words:

(A) attach the device using usbd_attach
(B) changed the configuration to 2, using usbd_select_config
(C) detach the device using usbd_detach
(D) slayed io_hid
(D1) slayed io-usb (your own program may need to handle io-usb going away)
(D2) start io-usb
(D3) start io-hid
(E) called hidd_connect

  1. Attached is the inputddk document for interfacing with io-hid. It explains all the hidd_() commands in detail and how to use them (tho it doesn’t say anything about what you are trying to accomplish in terms of reconfiguring a usb device since that’s not hid related). I got this directly from QNX tech support a couple of years ago when I was doing my own hid device. It’s in beta form because the ddk wasn’t released at that time and AFAIK it’s still not released officially. Some things may also be out of date now with the release of SP3 (and the upcoming 6.4)

Tim

Tim,

Thanks for the document.

As you suggested, I have restarted io-usb. (io-usb -d ohci)

But, after io-usb restart, the device configuration switched back to the default mass storage one (Config 1).

Any thoughts?

Shehan

Shehan,

Maybe it’s currently not possible to get the insertion call back called after reconfiguring the usb device to run in hid mode (tho that makes no sense).

When you restart io-hid, if you add the -v (verbose) option does it tell you anything useful. Also, when you restart io-hid, do you get insertion callbacks for a mouse/keyboard that are already plugged in?

At this point I’m rather out of suggestions (unless ‘io-hid -v’ reveals something) since io-usb forces the device back to mass storage mode. You are probably going to have to contact QNX tech support (hopefully you purchased support) and ask them about it. If you don’t have a tech support package your QNX rep can sometimes help with stuff like this to at least get a yes/no answer so you’ll know whether it’s possible or not.

I do have a question for you though. Why do you need the insertion callback to work? After all, your driver has already been told by io-usb the device was inserted (since you reconfigured it for hid mode) and you are able to send/receive reports. So can you not get the device to function properly using hidd_* calls?

Tim

Tim,

Thank you for your support. I will have to try to get in touch with QNX rep.

Regarding your question:

The input arguments for certain hidd_xx functions like hidd report attach(), hidd_get_collections() etc. are hidd_connection* & hidd_device_instance_t*. As per my understanding, these are obtained only through insertion callback to which these are input args.

By the way, I haven’t used any hidd_xx functions for send/receive reports. I used only the usbd_xx calls through following steps.

(1) Obtained the report descriptor through usbd_descriptor() call.

status = usbd_descriptor( ipod_usb_device, 0, // set/get USB_DESC_REPORT, // type - report USB_RECIPIENT_INTERFACE, // type of request 0, // index 0, // language buffer_class_descr, // buffer to store descriptor 200 );

(2) Analyzed the report desc. manually to identify the report IDs, count, value etc. for trying out a sample report send.

===================================

(3) Used usbd_alloc for the URB

u8_t *send_iAP_buff = (u8_t *) usbd_alloc( 63 );

(4) Filled the URB with the contents of the report which is to be sent

(5) Used usbd_setup_vendor & usb_io functions for sending the reports to the ctrl end point.

[code] struct usbd_urb *ctrl_urb = NULL;

// Allocate and init URB
ctrl_urb = usbd_alloc_urb( NULL );

usbd_setup_vendor( 
    ctrl_urb,               // URB
    URB_DIR_OUT,            // flags: Direction
    0x09,                   // Request
    USB_RECIPIENT_INTERFACE | USB_TYPE_CLASS, //Type
    0x29,             // value: Set this value based on the report desc 
    0,                      // index 
    send_iAP_buff,          // Address of buffer
    63 );                   // Length: Set this value based on the report desc
	    
// Submit the urb to stack
if( ( usbd_io( ctrl_urb,    // URB 
	   ipod_ctl_ep, // pipe
	   NULL,        // Call back
	   NULL,        // Private data 
	   3000         // Time in ms
	   )) == EOK ) 
{
    Os_LogWarning("iPod_USB: sent urb successfully\n");		
}  [/code]

My device sent back the report through interrupt end point (the intr endpt recv callback), whose contents were as expected for the sent report.

Shehan

Shehan,

Ah, so you’ve never actually sent/received using hidd_* calls after doing a reconfiguration.

Now I am wondering whether the reconfiguration truly worked. I believe the device itself might have internally changed to hid mode but I suspect it didn’t tell io-usb/io-hid that it is now a hid device. That’s why the call back isn’t getting called.

Who makes this device? Is there any way you can contact them and ask them why reconfiguring the device to hid mode doesn’t cause the device to report itself as a hid device? Maybe there is something else you need to send via the usbd_* calls to complete the configuration.

Tim