USB
  USB Composite Device

Post New Topic  Post A Reply
profile | register | preferences | faq | search

UBBFriend: Email This Page to Someone! next newest topic | next oldest topic
Author Topic:   USB Composite Device
Tsuneo
Member
posted October 23, 2006 01:22 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
USB composite device

Examples

USB_CDC_HID_IAD_10.zip


May 10, 2008 rev 1.0 Initial release

This example implements a composite device of CDC (with IAD) and HID
The CDC interface is based on the code of "USB CDC implementation for 'F32x and 'F34x"
In either interface, CDC and HID, the device loops back the OUT transfer to IN.

Passed USBCV R1.3.1, the ch9 and HID test
Tested on these Windows version,
- Windows Vista SP1
- WinXP SP3 (usbser.sys: 5.1.2600.5508, usbccgp.sys: 5.1.2600.5512)

On the original WinXP SP2 (usbser.sys, usbccgp.sys: 5.1.2600.2180),
the HID interface of the device works well, but CDC causes BSOD when a test app opens the VCP.


USB_HID_composite_01.zip


Oct 17, 2007 rev 0.1 Released just firmware

This example implements three HID interfaces to SiLabs 'F320/'F340 DK.
Each interface has an interrupt IN EP and an interrupt OUT EP.
The firmware loops back the data sent to the OUT EP to the IN EP, on each interface.

Passed the USB compliance test, USBCV 1.3, ch9 and HID test.
Tested on HClient host app example on WinDDK.


USB_Mouse_INT_01.zip


Oct 23, 2006 rev 0.1 Initial release

This is a demonstration which shows a composite device combined SiLabs USB_HID\MouseExample and USB_Interrupt (USB_INT)
  • When you are asked a device driver, specify the INF folder attached to this zip file.
  • USB_Interrupt host application and device driver works with this implementation without any change.


1. What is composite device
Composite device is defined in the USB spec as follows (usb_20.pdf 5.2.3),
"A device that has multiple interfaces controlled independently of each other is referred to as a composite device."

Using composite device, multiple functions are combined into a single device.
Ex.
- Keyboard + Mouse
- Video + USB Hard disk
- I/O device (HID + USB_bulk)

Another advantage of composite device is that it eases the device driver development.
OS assigns a separate device driver to each Interface of the composite device as follows. Therefore, a dedicated monolithic driver is not required for newly designed device; you can realize it using existing drivers.

  +----------------------------+      +----------------------
| Composite Device | | Host PC
| | |
| Function 0 -- Interface 0 --------- Device driver A <--->
| | |
| Function 1 -- Interface 1 --------- Device driver B <--->
+----------------------------+ +-----------------------

When OS has some required drivers as built-in, they are available for the composite device. These OS built-in device drivers are called as USB class driver.
"Approved Class Specification Documents" from USB.org
http://www.usb.org/developers/devclass_docs#approved

Windows have these built-in class drivers.
"USB FAQ: Introductory Level - USB Class Drivers" from MS WHDC
http://www.microsoft.com/whdc/system/bus/usb/USBFAQ_intro.mspx

Please note, available drivers for a composite device are not limited only to class drivers. Any driver can be applied, as long as it doesn't require a device class (class defined in device descriptor). For example, SiLabs USB_INT and USB_bulk drivers are also applicable for composite devices.


2. How Windows handles a composite device
When a device satisfies these three requirement, Windows system recognizes the device as a composite device.

  1. The class field of the device descriptor equals to zero: (bDeviceClass) = (0x00)
  2. Single Configuration
  3. Multiple Interfaces

[Note]
WinXP SP2, Win2k3 SP1 and Vista supports this alternative requirement.
1'. The class, subclass and protocol fields of the device are that of Interface Association Descriptor:
(bDeviceClass, bDeviceSubClass, bDeviceProtocol) = (0xEF, 0x02, 0x01)

When an USB device is plugged in to a PC, the system reads out the device descriptor of the device and makes these Device ID.
USB\VID_vvvv&PID_pppp
USB\VID_vvvv&PID_pppp&REV_rrrr
(vvvv, pppp, rrrr: four digit hex number for the VID, PID, device release number. Matches to idVendor/ idProduct/ bcdDevice, defined in the device descriptor)

The system searches device database on the registry, installed by INF files. When the system finds the Device ID in a device record, it assigns the device driver specified by the record. However, when it cannot find any matched record, and the device Configuration satisfies above criteria, the generic composite parent driver is loaded. This parent driver parses the Configuration of the device, and assigns this Device ID to each Interfaces.
USB\VID_vvvv&PID_pppp&MI_mm
USB\VID_vvvv&PID_pppp&REV_rrrr&MI_mm
(mm: Interface number of the corresponding function, two digit hex number)

As of the Interface which specifies a class, the system also assigns this Compatible ID.
USB\CLASS_cc
USB\CLASS_cc&SUBCLASS_ss
USB\CLASS_cc&SUBCLASS_ss&PROT_pp
(cc/ ss / pp: two digits hex number.
bInterfaceClass/ bInterfaceSubClass/ bInterfaceProtocol, from the Interface descriptor)

The system searches these Device ID and Compatible ID in the device database again. When it finds a matched record, it assigns the specified device driver to the Interface. However, when it cannot find any matched record, it shows 'New Hardware Wizard' to users and asks them to install the device driver.

"Enumeration of the Composite Parent Device" from MSDN
http://msdn2.microsoft.com/en-us/library/aa476434.aspx

3. Implementation
On USB application, firmware, device driver and host application are closely related. It is desirable to make separate prototypes of firmwares and host applications for each Interface first. After confirming them to work properly, combine them together.

3.1 Device firmware
When the source code is well organized, modification of the firmware is easy. Based on one of the prototypes, copy a part of code from other prototypes and insert it to corresponding part of the base source code.
In other word, the source codes should be organized considering to make it a composite device. When these parameters are defined by #define macro or enum instead of direct number in each prototype, the combination of prototypes is done smoothly.

  • Interface number
  • Endpoint address
  • Endpoint status (IDLE / HALT)

3.1.1 Descriptors

3.1.1.1 Device descriptor
  • bDeviceClass: Must be assigned to zero
  • idVendor, idProduct: VID/PID must be unique, to avoid conflict to other devices.

3.1.1.2 Configuration descriptor

  • wTotalLength: The total number of bytes of Configuration set, includes all of Interface sets
  • bNumInterfaces: Number of Interfaces included in this Configuration

Configuration set means these descriptors, for example.

Configuration descriptor
- Interface descriptor (0)
- - accessory descriptor, such as HID class descriptor, if any
- - Endpoint descriptors
- Interface descriptor (1)
- - accessory descriptor, such as HID class descriptor, if any
- - Endpoint descriptors

HID report descriptor and String descriptors are not included in the Configuration set.

3.1.1.3 Interface descriptors

  • bInterfaceNumber: Index of Interfaces, starting from zero
  • bInterfaceClass: Specify class code for this Interface

If any specific class code is not assigned to the Interface, set bInterfaceClass to 0xFF (Vendor specific). 0x00 (Reserved) would work, but 0xFF is better.

3.1.1.4 Endpoint descriptors

  • bEndpointAddress: must be unique on each Endpoint descriptor

Any duplicated Endpoint across Interfaces is not allowed in a composite device.

3.1.2 Standard requests

3.1.2.1 Additional Descriptor handling
Get_Descriptor must support additional descriptors asked by the host.
  • Configuration descriptor: return full Configuration set (see 3.1.1.2)
  • Class-specific descriptors:

When the descriptor type in request (MSB of wValue) is not Device(1), Configuration(2) or String(3), the request may be for class-specific descriptor (in full-speed devices). In this case, wIndex field of the Setup data shows the Interface number in question. According to the class specified by the Interface (wIndex), Get_Descriptor must return the class-specific descriptor specified by the MSB of wValue.

When the class supports Set_Descriptor request, it must be handled similarly to Get_Descriptor.

Interface and Endpoint descriptors cannot be directly accessed with Get_Descriptor or Set_Descriptor. Therefore, Get_Descriptor and Set_Descriptor have no need to support them.

3.1.2.2 Additional Interfaces handling
wIndex field of the Setup data shows the Interface number in question. When this Interface number matches to the additional Interfaces, handle the requests as follows.

  • Get_Status: return Zero
  • Get_Interface: return current alternate Interface number
  • Set_Interface: set current alternate Interface to one specified by the request

When the Interface in question doesn't have any alternate Interface, Get_Interface returns Zero. And Set_Interface succeeds when the wValue is Zero, otherwise return STALL.

3.1.2.3 Additional Endpoints handling

  • Get_Status: return HALT condition of the Endpoint
  • Clear_Feature: recover the Endpoint from HALT
  • Set_Feature: set the Endpoint to HALT
  • Set_Configuration: Setup additional Endpoints

When Get_Status, Clear_Feature and Set_Feature are issued to an Endpoint, wIndex field of the Setup data indicates the Endpoint address.

When the Interfaces doesn't have any alternate Interface, set up the Endpoints in Set_Configuration request. As of the Interface with any alternate Interface, set up the Endpoints belonging to the Interface in Set_Interface.


3.1.3 Class-specific requests
wIndex field of the Setup data of the request indicates the Interface to which this request is issued. Therefore, dispatch the request by wIndex first, and copy the each handler for class-specific requests from the prototypes under each case.

3.1.4 Endpoint handling
When the Endpoint address and Endpoint status are defined by macro, modification on this part finishes by copying the Endpoint handler of each prototype to the base one.

3.2 Device driver and host application
OS built-in class drivers are designed to work with composite devices. In most case, these drivers are applicable to composite devices without any change of default INF file. However, device drivers provided by vendors are not always designed to work with composite devices. INF file and host application code should be modified for these drivers. The device driver itself should work without any change. Of course, rare exception may exist.

3.2.1 INF file

When the device driver requires an INF file even for single use, the INF file is required as a part of composite device. The INF file defines the Device ID as follows.
USB\VID_vvvv&PID_pppp
USB\VID_vvvv&PID_pppp&REV_rrrr

For a composite device, the Interface number must be added to this Device ID.
USB\VID_vvvv&PID_pppp&MI_mm
USB\VID_vvvv&PID_pppp&REV_rrrr&MI_mm

For example, when you add the USB_Bulk function (Interface with bulk IN/OUT Endpoints) to your composite device as the Interface number 1, the Device ID in the INF file (SilabsBulk.inf) is modified as follows.
USB\VID_vvvv&PID_pppp&MI_01
(vvvv, pppp: VID/PID must be unique)


3.2.2 Endpoint address and pipe name / device path name
When two or more devices are combined into a single composite device, the Endpoint addresses must be often changed to fit to the newly designed device. Usually, the pipe name and device path name from device drivers are designed to hide the Endpoint address. Therefore, in most case, Endpoint address reassignment doesn't affect to the host application.

However, there are some drivers which expose the Endpoint address directly to the pipe name. For these drivers, the host application must be modified to reflect the Endpoint address assignment. Confirmation for this point is desirable before planning a new device.


  • OS built-in class drivers hide Endpoint address behind its device path name.
  • MS WinDDK bulkusb and isousb example driver hide Endpoint address behind the pipe name (a part of device path name).
  • SiLabs USB_INT and USB_Bulk device drivers hide it behind the pipe name (a part of device path name).
  • Cypress ezusb.sys driver hides Endpoint address behind its pipe number.
  • Cypress CyUSB.sys driver exposes Endpoint address directly. But when the code follows the example of CCyUSBDevice::BulkInEndPt in CyAPI.chm, the Endpoint address is hidden behind the index of the Endpoint array.

When a device applies the same class to multiple Interfaces, the host application should be modified to distinguish these Interfaces.

Tsuneo

[This message has been edited by Tsuneo (edited May 10, 2008).]

IP: Logged

Patryk
Member
posted October 23, 2006 05:51 AM     Click Here to See the Profile for Patryk     Edit/Delete Message
Just some spottings/clarifications to make your excellent post perfect :-)

1. 3.1.2.1...
When the descriptor type in request (MSB of wValue) is not Device(1), Configuration(2) or String(3), the request may be for class-specific descriptor (in full-speed devices)."

For example HID devices - HID and report descriptors must be supported that way. And these devices can be (and mostly are) low-speed. Recipient field of bmRequestType (set to INTERFACE or ENDPOINT) should be used to distinguish class descriptors from standard ones.
USB Common Class Specification, p.8:
"3.11 Identifying Class and Vendor-Specific Requests and Descriptors
The standard GET_DESCRIPTOR request (with the bRequestType.Type field set to standard) is used to directly request class or vendor-specific descriptors. The class associated with such a request is determined by the class of the bmRequestType.Recipient. When the bmRequestType.Recipient field is set to INTERFACE or ENDPOINT, the wIndex field identifies the desired interface or endpoint. All endpoints within an interface use that interface’s class, subclass and protocol."

2. "3.1.2.2 ...
When the Interface in question doesn't have any alternate Interface, Get_Interface returns Zero. And Set_Interface succeeds when the wValue is Zero, otherwise return STALL."

Set_Interface need not to be supported at all in such (most common) case.
USB 2.0 spec, p.259:
"9.4.10 Set Interface
If a device only supports a default setting for the specified interface, then a STALL may be returned in the Status stage of the request."

3. "3.2.2..."
USBIO.SYS driver from Thesycon driver exposes Endpoint address directly.

Regards,
Patryk

IP: Logged

Tsuneo
Member
posted October 17, 2007 09:31 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Added an example, USB_HID_composite
See the first post.

Tsuneo

IP: Logged

MikeB
New Member
posted November 02, 2007 06:29 AM     Click Here to See the Profile for MikeB     Edit/Delete Message
Tsuneo,

Thank you for providing this excellent example. Can you point me to a clear description of how one communicates with composite HID devices from Windows? I have found several examples for single devices but I have not yet worked out how this translates to the composite device case.

Many thanks.

Mike.

IP: Logged

LiMing.Sun
Member
posted November 02, 2007 09:33 PM     Click Here to See the Profile for LiMing.Sun   Click Here to Email LiMing.Sun     Edit/Delete Message
Seems that the 3-HID composite devices share the same VID and PID,i just want to know how to distinguish them on host;
Besides,as mentioned by tsuneo,packets between the composite device and host may miss their order,we need to build some rules to arrange packets in their order for right HID.

IP: Logged

Tsuneo
Member
posted November 03, 2007 10:00 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
I was writing a host app example for the three HID composite firmware.

I'm using a note PC for the development of these personal projects, but the hard disk was broken on Wednesday of the last week. I have a recent backup for data files (one week ago), then the crash is not so much disastrous, I thought so at first time.

But it takes so long to recover the OS and applications on a new HD, because tons of heavy apps are installed, like KEIL (C51 and ARM), Xilinx and Altera, TI DSP, MS VS (2005,2003 VC6) and Office, Eclipse, etc. etc...
Then, this weekend is wasted out for installations.

Please wait for a while.


"Seems that the 3-HID composite devices share the same VID and PID,i just want to know how to distinguish them on host;"

As I wrote in the first post of this topic,
an independent device driver instance is assigned to each interface of the three HIDs. These instances share the same VID/PID, but the interface number is attached to the device ID.

USB\VID_vvvv&PID_pppp&MI_mm
(mm: Interface number of the corresponding function, two digit hex number)

Run msinfo32.exe (included in the Windows system) and you'll confirm it.

This is an example of msinfo32 output from MS Coding4Fun brog.
"Is that you? Writing Better Software for Cool USB Hardware"

Click here for larger image
(click image to zoom)


When the host app searches the device using SetupDi-API with the given VID/PID, it will find more than one instance. The usual code breaks the search loop when it finds a single instance, but the search loop should continue until no more matched instance is found.

These instances are distinguished by the device "path" string.
The DevicePath strings are almost same as "PNP Device ID" of msinfo32,
and contains different "MI_mm".

Tsuneo

[This message has been edited by Tsuneo (edited November 03, 2007).]

IP: Logged

MikeB
New Member
posted November 05, 2007 05:21 AM     Click Here to See the Profile for MikeB     Edit/Delete Message
Tsuneo,

I'm sorry for your laptop problems. Thanks for the extra explanation.

Mike.

IP: Logged

Tsuneo
Member
posted May 10, 2008 08:10 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Added an example of a composite device, CDC (with IAD) + HID, to the first post.

Interface Association Descriptor (IAD)

There are classes like CDC, which consists of multiple interfaces.
IAD emphasize these bound interfaces which belongs to single class on the configuration set.

On the Device descriptor, the triad (Class, Subclass, Protocol) is set to that of IAD as follows.


0xEF, // bDeviceClass (Misc)
0x02, // bDeviceSubClass (common)
0x01, // bDeviceProtocol (IAD)

On the Config descriptor set, IAD is placed just before the interface descriptors which are tied together.


// Interface Association Descriptor
sizeof(Tinterface_association_descriptor), // bLength
DSC_TYPE_IAD, // bDescriptorType = 11
0x00, // bFirstInterface
0x02, // bInterfaceCount
0x02, // bFunctionClass (Communication Class)
0x02, // bFunctionSubClass (Abstract Control Model)
0x01, // bFunctionProcotol (V.25ter, Common AT commands)
0x00, // iInterface
},
//
// Follows the first interface bound by the IAD
//

IAD declares the index of the first interface, and the number of the bound interfaces, placed contiguously. The triad on the IAD matches to that of the main interface of the class.

There is no other difference from ordinary composite devices.

Tsuneo

IP: Logged

smhinchy
New Member
posted May 13, 2008 04:20 PM     Click Here to See the Profile for smhinchy     Edit/Delete Message
Hello,

Should this example work out of the box? I am using SiLabs IDE 3.3, SDCC Version 2.8.0 and Windows XP SP2. The program compiles and downloads, but when I run it I get the USB three dings and nothing else.

Any suggestions?

Shawn

IP: Logged

vanmierlo
Member
posted May 14, 2008 04:01 AM     Click Here to See the Profile for vanmierlo   Click Here to Email vanmierlo     Edit/Delete Message
In the ReadMe.txt Tsuneo wrote that it works on WinXP SP3 and Vista SP1. I suggest installing the latest SP.

Maarten

IP: Logged

xiaofan
Member
posted May 15, 2008 03:42 AM     Click Here to See the Profile for xiaofan     Edit/Delete Message
As discussed previously, you need two hot fixes for Windows XP SP2.
http://www.cygnal.org/ubb/Forum9/HTML/001572.html

It is easier to use Windows XP SP3. I have tested a dual CDC-ACM IAD USB Composite device under Windows XP SP3 and it is working.

IP: Logged

ryyu
New Member
posted May 15, 2008 09:48 PM     Click Here to See the Profile for ryyu   Click Here to Email ryyu     Edit/Delete Message
I am currently studying USB HID.
I want to make a composite HID mouse + keyboard.Besides, I have downloaded the USB_HID_composite_01. However, I don't know how to control the cursor or keyboard through that example. Therefore, could anyone give me some more helpful examples, Thanks

Ray

IP: Logged

Tsuneo
Member
posted May 15, 2008 11:49 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hello Ray,

I recommend you to make separated mouse and keyboard implementations at first.
Then, combine them into a single composite device.

SiLabs provides a mouse example.
C:\SiLabs\MCU\Examples\C8051F320_1\USB_HID\MouseExample
C:\SiLabs\MCU\Examples\C8051F34x\USB_HID\MouseExample

Then, you have to make a keyboard implementation.
The USB keyboard and mouse implementation is fully described on the USB HID spec.

USB HID spec 1.11
http://www.usb.org/developers/devclass_docs/HID1_11.pdf"
HID Usage Table 1.12
http://www.usb.org/developers/devclass_docs/Hut1_12.pdf

Of course, the HID spec is massive one and it isn't written just for keyboard and mouse. Then, you have to extract the concerning description from the spec.
This topic guides you how to find the keyboard implementation on the spec.
USB HID KEYBOARD (Search a Programmer)

On the spec, the mouse description follows the keyboard one.


You have to assign different VID/PID (at least PID) for the single keyboard, and the composite device implementation.

If you assign the same VID/PID to another implementation, delete the device instance on the Device Manager, once.

You can see all instances on the Device Manager using following procedure.
1) Copy these two lines to a blank text file, and rename the file to DevManager.bat
set devmgr_show_nonpresent_devices=1
start devmgmt.msc

2) Double click DevManager.bat, and Device Manager comes up.
From 'View' menu, select 'Show hidden devices'

Tsuneo

IP: Logged

xiaofan
Member
posted May 16, 2008 03:31 AM     Click Here to See the Profile for xiaofan     Edit/Delete Message
There is another way to do this without using a composite device. You can actually implement using an HID device with two reports, one for keyboard and one for mouse.

IP: Logged

xiaofan
Member
posted May 16, 2008 03:41 AM     Click Here to See the Profile for xiaofan     Edit/Delete Message
Example from ST.
Keyboard + Mouse + Gamepad:

http://www.st.com/stonline/books/pdf/docs/6904.pdf

The code is here:
http://www.st.com/mcu/forums-cat-5673-12.html

IP: Logged

Tsuneo
Member
posted May 16, 2008 04:28 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Ah, you are talking about multiple top-level collections.
It was discussed once on this topic.

multiple HID and one MSD on a -340

The flaw of this method is that it doesn't support boot device.

Tsuneo

IP: Logged

Robonz
New Member
posted May 20, 2008 09:40 AM     Click Here to See the Profile for Robonz     Edit/Delete Message
Hi Tsuneo

Firstly thanks for all your reference code I hope Silabs are sending you money or beer or something, because you have helped us a lot over the years. I dont know how you find the time to do all the posting you do.

Two of us have been working on an urgent bug for a commercial product we sell. We have spent 4 x 12 hour days to find the cause using a bus analyser. The root cause was quite simple but it took us a long time. I thought I would share this fix with you all.

When you have firmware that must turn off USB interrupts for timing critical reasons there is a catch with the current code.

A sent stall flag can arrive with a setup packet in one interrupt. All our previous code did not turn off interrupts. Sent stalls always (well we didnt have a bus analyser) came as a seperate interrupt.

Here is the fix, but it doesnt work, see
http://www.cygnal.org/ubb/Forum9/HTML/001600.html

if (ControlReg & rbSTSTL){
POLL_WRITE_BYTE(E0CSR, 0);
Ep_Status[0] = EP_IDLE;
// DO NOT return;
}
// continue processing other interrupt flags. If you return you could ignore an out packet like we were. This results in a very intermitent packet loss and can crash Vista during S3 resuming.

Cheers
Keith

[This message has been edited by Robonz (edited May 21, 2008).]

IP: Logged

Tsuneo
Member
posted May 21, 2008 03:36 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Thanks Keith,

You make me aware the problem of STALL handling here.

Following USB spec, STALL condition of the default endpoint is cleared just by SETUP packet from the host. Then, the stack has to clear SDSTL and return to EP_IDLE, just when the engine receives SETUP.

However, my code (and SiLabs' also) clears SDSTL when it sees STSTL bit, ie. when the STALL is sent to the host, before it sees SETUP. Usually, it works fine, because the host sends SETUP next to STALL reception, but it is not guaranteed.

I should examine the behavior of the engine on this STALL handling more.
The "if" clause which sees rbSTSTL may be deleted entirely.

Tsuneo

IP: Logged

scene
New Member
posted August 01, 2008 05:01 AM     Click Here to See the Profile for scene     Edit/Delete Message
Hi Tsuneo,

I wonder if you could help me with me with a related question.

I have a situation where I need to emulate a commercial HID device which is supplied with it's own vendor driver (say, a touch screen). Additionally, I want to add keyboard and mouse interfaces to this device to make a composite device. The VID/PID will 'copied' from the commercial HID device.

I would like Windows to bind the original vendor driver to the device and also bind it's KB/Mouse drivers to the other interfaces.

Is this possible?

In my initial experiments I cannot get the original vendor driver to bind if any additional interfaces are added to the original descriptors. Would IAD help?

Thanks.

Ray.

[This message has been edited by scene (edited August 01, 2008).]

IP: Logged

Tsuneo
Member
posted August 01, 2008 06:34 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hello Ray,

"Is this possible?

Sound like possible.

"In my initial experiments I cannot get the original vendor driver to bind if any additional interfaces are added to the original descriptors.

Did you modify the INF file of the original device?
The custom HID device should have an INF file, to bind it to the custom device driver.
As I wrote in above "3.2.1 INF file" section, you have to modify the Device ID on the INF file. Find the Device ID like USB\VID_vvvv&PID_pppp, and add the interface number, USB\VID_vvvv&PID_pppp&MI_mm

After modifying the INF file, delete the device instance of the original HID device once. Device instance records are held on the registry. Windows doesn't refresh it automatically, even when the device or INF file is changed. You have to do it manually. This utility is handy for this job.

USBDeview
http://www.nirsoft.net/utils/usb_devices_view.html

For the additional keyboard and mouse, no INF file is required.

Tsuneo

IP: Logged

scene
New Member
posted August 01, 2008 09:08 AM     Click Here to See the Profile for scene     Edit/Delete Message
Thanks for your prompt reply.

Is there ANY way to do this without editing the .inf file?

Alternatively, is there a way to make the vendor driver bind to the first interface found?

Ray.

[This message has been edited by scene (edited August 01, 2008).]

IP: Logged

Tsuneo
Member
posted August 03, 2008 02:16 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
In above post, I described a popular method.
But some tablet manufacturers implement the HID device in another way.

I examined a Wacom tablet and it's device driver.
This tablet is a generic HID device with digitizer usage.


===>Device Descriptor<===
bLength: 0x12
bDescriptorType: 0x01
bcdUSB: 0x0100
bDeviceClass: 0x00 -> This is an Interface Class Defined Device
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x08 = (8) Bytes
idVendor: 0x056A = WACOM Co., Ltd.
idProduct: 0x0021
bcdDevice: 0x0101
iManufacturer: 0x01
English (United States) "Tablet"
iProduct: 0x02
English (United States) "GD-0608-U"
iSerialNumber: 0x00
bNumConfigurations: 0x01

===>Configuration Descriptor<===
bLength: 0x09
bDescriptorType: 0x02
wTotalLength: 0x0022 -> Validated
bNumInterfaces: 0x01
bConfigurationValue: 0x01
iConfiguration: 0x00
bmAttributes: 0x80 -> Bus Powered
MaxPower: 0xFA = 500 mA

===>Interface Descriptor<===
bLength: 0x09
bDescriptorType: 0x04
bInterfaceNumber: 0x00
bAlternateSetting: 0x00
bNumEndpoints: 0x01
bInterfaceClass: 0x03 -> HID Interface Class
bInterfaceSubClass: 0x01
bInterfaceProtocol: 0x02
CAUTION: This may be an invalid bInterfaceProtocol
iInterface: 0x00

===>HID Descriptor<===
bLength: 0x09
bDescriptorType: 0x21
bcdHID: 0x0100
bCountryCode: 0x00
bNumDescriptors: 0x01
bDescriptorType: 0x22
wDescriptorLength: 0x004E

===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x81 -> Direction: IN - EndpointID: 1
bmAttributes: 0x03 -> Interrupt Transfer Type
wMaxPacketSize: 0x000A = 0x0A bytes
bInterval: 0x05


HID Report Descriptor
Usage Page: 13 (Digitizer)
Usage: 1 (Digitizer)
Collection
Report ID: 2
Usage: 0 (Undefined)
Report Size: 8
Report Count: 9
Logical Minimum: 0
Logical Maximum: 255
Input: 2 (Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position)

Usage: 58 (Program Change Keys)
Logical Maximum: 2
Report Count: 1
Feature: 2 (Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position)

Report ID: 3
Usage: 0 (Undefined)
Logical Maximum: 255
Feature: 2 (Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position)

Report ID: 4
Usage: 58 (Program Change Keys)
Logical Maximum: 1
Feature: 2 (Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position)

Report ID: 5
Usage: 0 (Undefined)
Logical Maximum: 255
Report Count: 8
Feature: 2 (Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position)

Report ID: 6
Usage: 0 (Undefined)
Feature: 2 (Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position)

Report ID: 7
Usage: 0 (Undefined)
Report Count: 4
Feature: 2 (Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position)

Report ID: 8
Usage: 0 (Undefined)
Feature: 2 (Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position)

End Collection

As this device tree shows, this HID tablet is recognized as generic HID device with the built-in HID driver using the default input.inf on Windows. Instead of providing a custom device driver directly to this device, Wacom installs HID minidrivers for the two virtual HID devices, one for mouse and one for keyboard. The minidrivers catch the generic HID device, and translate the device traffic into those of HID mouse and keyboard. Clever way.


Device manager
Device connection tree

ACPI- PCI bus - Host controller - USB root hub
- USB Human Interface device USB\VID_056A&PID_0021\6&39649F58&0&4
- - HID device HID\VID_056A&PID_0021\7&AC1626&0&0000

Wacom virtual HID Driver ROOT\HIDCLASS\0000
- Wacom HID Pen HID\WACOMVIRTUALHID&COL01\1&2D595CA7&0&0000
- Wacom HID Digitizer HID\WACOMVIRTUALHID&COL02\1&2D595CA7&0&0001
- Wacom Mouse HID\WACOMVIRTUALHID&COL03\1&2D595CA7&0&0002
- HID device HID\WACOMVIRTUALHID&COL04\1&2D595CA7&0&0003

Virtual Keyboard Driver ROOT\HIDCLASS\0001
- Virtual Keyboard Interface HID\WACOMVKHID&COL01\1&4784345&0&0000
- Virtual Keyboard HID\WACOMVKHID&COL02\1&4784345&0&0001
- Virtual Media Keys HID\WACOMVKHID&COL03\1&4784345&0&0002

For this configuration, there is no need to modify the INF file to make it a composite device or top-level collections.

Tsuneo

IP: Logged

egawtry
Member
posted October 13, 2008 07:18 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Tsuneo (or anyone who knows),

I implemented this setup, but while I see the CDC just fine, I am not seeing the HID when I enumerate HIDs. Any ideas? If I have to I can post code, but I would like to avoid posting huge amounts of code.

Above you mention changes to the INF file - could that be an issue? I am using my standard CDC driver INF.

-Erik

IP: Logged

Tsuneo
Member
posted October 13, 2008 08:39 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hi Erik,

At the top of the first post of this topic, I posted a composite device of CDC and HID, USB_CDC_HID_IAD_10.zip

For a composite device of CDC, IAD (Interface Association Descriptor) is required. And it is supported after WinXP SP3 and Vista SP1.

Tsuneo

IP: Logged

egawtry
Member
posted October 15, 2008 03:28 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Ok, I must be a dummy because I cannot figure out several things:

1. Why do you have only one buffer for both input and output packets?

2. What do you mean by "loopback"?

3. Why was everything moved to the main loop and polled instead of leaving it in the interrupt? (Timing?)

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

I am seeing the CDC and HID interfaces, but I cannot get the HID to read/write (it is always NULLs on the PC end). Any ideas there?

Thanks,
-Erik

IP: Logged

Tsuneo
Member
posted October 16, 2008 12:51 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
"1. Why do you have only one buffer for both input and output packets?"

For loopback.
I could use two separate buffers for IN and OUT, and copy the contents from OUT to IN.
But I cut the corners


"2. What do you mean by "loopback"?"

Loopback means, sending back the output report from the host directly to the host.
Orthodox way to check communication.


"3. Why was everything moved to the main loop and polled instead of leaving it in the interrupt? (Timing?)"

Which interrupt do you mean?
If it is the Endpoint interrupt, it's because,
- to show the variety of the endpoint handling
- to make the modification target clear

When the data load/unload is handled in the endpoint interrupts, its timing is determined by the host.
When it is handled in a main loop task, or in an other interrupt like timer ISR, its timing is determined by the event on the device side. ie. it is possible that the device returns an input report just when a user pushes a key.

If the USB routines, POLL_WRITE_BYTE, etc., are called in a main loop task, these calls are guarded by disabling USB interrupt around the call, as the example shows.

If the USB routines are called an other ISR like timer, no guard is required, but the interrupt priority of the ISR should be the same as USB ISR.


"but I cannot get the HID to read/write"

Modify Jan Axelson's HID example for host app, and check it.
http://www.lvr.com/hidpage.htm
These examples fill just the first 2 bytes of the output report.
Modify it to fill full 64 bytes, and run the example.

Tsuneo

IP: Logged

egawtry
Member
posted October 17, 2008 09:48 AM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
"Loopback means, sending back the output report from the host directly to the host.
Orthodox way to check communication."

Why would I want to do that? I just want to send packets to and from the device, like in the HID from INT example. I cannot do everything from the InputReport and OutputReport calls - the USB HID spec says that to do that is bad.

I guess I will have to hack on it to resolve this.

-Erik

IP: Logged

Tsuneo
Member
posted October 17, 2008 10:35 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
"Why would I want to do that?"

Of course, you don't need to do that, once the USB side has been established. But I needed it to test the implementation. Also, it was needed to show the implementation works fine.

As this topic has been discussed on the composite device, I posted the simplest implementation just along with the theme. The usage of HID endpoints was discussed on "How to convert USB_Interrupt (USB_INT) to HID". Then apply the experience to the HID endpoints to extend them.

If you don't like this focused approach and request more detailed examples, sorry, it's beyond my personal project.


"I cannot do everything from the InputReport and OutputReport calls - the USB HID spec says that to do that is bad.

Huh?
Do you confuse interrupt endpoints with class specific requests?
I don't see any violation of HID spec on my implementation at this point.

Tsuneo

IP: Logged

egawtry
Member
posted October 17, 2008 11:29 AM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Tsuneo,

Your code is something like this:
===============================
EUSB0_save = EIE1 & 0x02; // save USB interrupt enable bit
EIE1 &= ~0x02; // disable USB interrupt temporarily

OUT3_FIFO_loaded = FALSE;
IN3_FIFO_empty = FALSE;

POLL_WRITE_BYTE( INDEX, 3 ); // loop back the data from OUT EP to IN EP
// unload packet from OUT FIFO
FIFO_Read_xdata( FIFO_EP3, EP3_PACKET_SIZE, HID_InOut_Packet );
POLL_WRITE_BYTE( EOUTCSRL, 0 ); // Clear Out Packet ready bit
// load packet to IN FIFO
FIFO_Write_xdata( FIFO_EP3, EP3_PACKET_SIZE, HID_InOut_Packet );
POLL_WRITE_BYTE( EINCSRL, rbInINPRDY ); // set FIFO ready flag

EIE1 |= EUSB0_save; // restore USB interrupt
===============================

That is great for loopback, but where do you handle the read and write of the basic data to the Host? In the "HID from INT" (good job there, btw) code, it is in the handler, but all you do in this handler is echo the data back to the host. There is no way to change it in the 34x. If I change the HID_InOut_Packet, it gets erased by the read before the write back to the host even occurs.

-Erik

IP: Logged

Tsuneo
Member
posted October 17, 2008 01:31 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
OK, this is the separated version, without any cutting corner

Tsuneo


USB_Main.h
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------

extern BYTE xdata HID_Out_Packet[ HID_OUT_REPORT_SIZE ]; // Last packet received from host
extern BYTE xdata HID_In_Packet[ HID_IN_REPORT_SIZE ]; // packet to send to host


USB_Main.c

// HID loopback support
BYTE xdata HID_Out_Packet[ HID_OUT_REPORT_SIZE ]; // Last packet received from host
BYTE xdata HID_In_Packet[ HID_IN_REPORT_SIZE ]; // packet to send to host

void main(void)
{
...
{ // task2: USB EP3 handling - HID support
// loopback from OUT to IN
unsigned char EUSB0_save;
unsigned char idx;

// Read out from HID OUT EP
if ( (Ep_StatusOUT3 != EP_HALT) && OUT3_FIFO_loaded ) {
// To prevent conflict with USB interrupt
EUSB0_save = EIE1 & 0x02; // save USB interrupt enable bit
EIE1 &= ~0x02; // disable USB interrupt temporarily

OUT3_FIFO_loaded = FALSE;

POLL_WRITE_BYTE( INDEX, 3 ); // unload packet from OUT FIFO
FIFO_Read_xdata( FIFO_EP3, HID_OUT_REPORT_SIZE, HID_Out_Packet );
POLL_WRITE_BYTE( EOUTCSRL, 0 ); // Clear Out Packet ready bit

EIE1 |= EUSB0_save; // restore USB interrupt
}

// Write to HID IN EP
if ( (Ep_StatusIN3 != EP_HALT) && IN3_FIFO_empty ) {
// copy data for loopback
for ( idx = 0; idx < HID_OUT_REPORT_SIZE; idx++ )
HID_In_Packet[idx] = HID_Out_Packet[idx];

// To prevent conflict with USB interrupt
EUSB0_save = EIE1 & 0x02; // save USB interrupt enable bit
EIE1 &= ~0x02; // disable USB interrupt temporarily

IN3_FIFO_empty = FALSE;

POLL_WRITE_BYTE( INDEX, 3 ); // load packet to IN FIFO
FIFO_Write_xdata( FIFO_EP3, HID_IN_REPORT_SIZE, HID_In_Packet );
POLL_WRITE_BYTE( EINCSRL, rbInINPRDY ); // set FIFO ready flag

EIE1 |= EUSB0_save; // restore USB interrupt
}
}
}
}


USB_Class_Request.c
//-----------------------------------------------------------------------------
// Get_Report
//-----------------------------------------------------------------------------

static void Get_Report( void )
{
if ( (Setup.bmRequestType == IN_CL_INTERFACE)
&& (Setup.wValue.c[LSB] == 0) ) // Report ID
{
switch ( Setup.wValue.c[MSB] )
{
case HID_REPORT_TYPE_INPUT: // Input report
DataPtr = (BYTE *)HID_In_Packet; // <------- modified
DataSize = HID_IN_REPORT_SIZE;
setup_handled = TRUE;
break;

[This message has been edited by Tsuneo (edited October 17, 2008).]

IP: Logged

egawtry
Member
posted October 17, 2008 02:12 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Wow! That is exactly what I did to make it work! Great minds think alike, eh? :-)

Thank you for the code.

-Erik

IP: Logged

jeremy
Member
posted November 05, 2008 04:49 PM     Click Here to See the Profile for jeremy     Edit/Delete Message
In Usb_Reset(), the status of each EP is set to EP_HALT:

Ep_StatusIN1 = EP_HALT;

Why is this necessary? The EP is only set to EP_IDLE on another SET_CONFIG. I'm finding Windows is issuing a USB reset, and my firmware then stops responding because the EP is "halted".

IP: Logged

Tsuneo
Member
posted November 05, 2008 07:02 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
In Usb_Reset(), the status of each EP is set to EP_HALT:
Ep_StatusIN1 = EP_HALT;

Why is this necessary? The EP is only set to EP_IDLE on another SET_CONFIG.

I don't think this implementation has any problem.

When the device receives bus reset, the device state moves to the DEFAULT state. EP1-3 should not respond to any access from the host side until the device state moves to CONFIGURED by Set_Configuration.

In other word, to access the EPs other than the default EP, the host should issue Set_Address and Set_Configuration after bus reset - ie. re-enumeration.


"I'm finding Windows is issuing a USB reset, and my firmware then stops responding because the EP is "halted".

Windows often put bus reset, unnecessarily.
But as long as I know, Windows always does re-enumeration after bus reset.

If it doesn't, it's a bug of Windows.
Please show the details when it occurs.
it's worth to report the bug to MS.

Tsuneo

IP: Logged

egawtry
Member
posted November 10, 2008 12:34 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Tsuneo,

Any idea on how to get the pair of connections from Windows? (HID+CDC) I can easily find all the 342's HID and CDC connections, but there isn't any way I have found to pair them up.

I am currently pairing them assuming that they are enumerated in order, eg. the first HID is the first CDC, the second HID is the second CDC, etc. - but I don't trust that algorythm. Windows has to have a call or a registry entry for Multi interfaces.

Thanks for any ideas.

-Erik

IP: Logged

Tsuneo
Member
posted November 11, 2008 07:59 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
Hi Erik,

"Any idea on how to get the pair of connections from Windows? (HID+CDC) I can easily find all the 342's HID and CDC connections, but there isn't any way I have found to pair them up."

Do you mean,
You have several composite devices (HID + CDC) of same VID/PID, connected to single PC. You want to match the device handles of HID and CDC in pair from the same device.


Match the pair using the serial number on the device.

a) HID device path and serial number

HID device is counted up using SetupDi- API, as usual.
You'll see a typical example in this file.

C:\SiLabs\MCU\Examples\C8051F34x\USB\USB_HID\BlinkyExample\Host\HIDDevice.cpp
CHIDDevice::GetHidDevicePath()

After opening the device handle using CreatFile, serial number of the HID device is retrieved using this API,

HidD_GetSerialNumberString()
http://msdn.microsoft.com/en-us/library/ms790939.aspx


b) COM port and serial number

In this topic, I posted a short snippet that lists up COM port and serial number for CP210x. Actually, this snippet is applied to CDC virtual COM port, too, just by changing the VID/PID.

"CP2102 & Vista registry"
http://www.cygnal.org/ubb/Forum9/HTML/001659.html

For your composite device,

CString deviceID( _T("USB\\VID_10C4&PID_EA60\\") ); // device ID of CP210x VCP

Modify above line like,

CString deviceID( _T("USB\\VID_vvvv&PID_pppp&MI_mm\\") );

where,
vvvv, pppp: 4 digit hex number of the VID/PID of your device
mm: 2 digit hex number for CDC communication interface

Then, you can retrieve COM port and serial number in a pair.
Using this COM port number, you'll get the device handle for the COM port.


Combine a) and b).
For example,
- Search a HID device, open it and get the serial number, first
- Then, search a COM port of this serial number, using b)
- Repeat for all HID device

Tsuneo

[This message has been edited by Tsuneo (edited November 11, 2008).]

IP: Logged

Myst1uk
New Member
posted November 12, 2008 05:52 AM     Click Here to See the Profile for Myst1uk     Edit/Delete Message
I have a simple question.. is it possible to modify one of the silicon labs HID examples to use an isochronous endpoint?

IP: Logged

Tsuneo
Member
posted November 13, 2008 04:39 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
"is it possible to modify one of the silicon labs HID examples to use an isochronous endpoint?"

It's possible, but USB_Interrupt example is better.
HID examples has HID specific request handlers.

Tsuneo

IP: Logged

egawtry
Member
posted November 17, 2008 09:15 AM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Tsuneo,

I have already tried all you have suggested except for the serial number idea. I will try that. If I get it to work I will post it.

One note, the MI_mm does NOT match between HID and CDC devices, in fact, the CDC device string does not include the MI_mm string. Also the MI_mm for the HID gets changed from the string in the INF to a random number.

-Erik

P.S. I tried your CDC serial number routine. It doesn't work. The DeviceID stuff on the right is junk.

[This message has been edited by egawtry (edited November 17, 2008).]

IP: Logged

egawtry
Member
posted November 17, 2008 01:39 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Figured it out:


// Get the address of the selected device
BOOL GetSerialNumberForCDC(LPCWSTR lpDevPath, LPWSTR lpAddress, UINT cbAddress)
{
// Check the VID PID
WCHAR *ptrVID, *ptrPID, *ptrMI, *ptrCode;
WORD wVID, wPID, wMI;


if( cbAddress == 0 ) return FALSE;

// Initialize
*lpAddress = NULL;
wVID = wPID = wMI = 0;

// Get the VID and PID for the enum search
ptrVID = wcsstr(lpDevPath, L"vid_");
ptrPID = wcsstr(lpDevPath, L"pid_");
ptrMI = wcsstr(lpDevPath, L"mi_");
if( ptrVID ) wVID = (WORD)_xtoi(ptrVID+4);
if( ptrPID ) wPID = (WORD)_xtoi(ptrPID+4);
// Get the MI and the CODE pointer
if( ptrMI )
{
wMI = (WORD)_xtoi(ptrMI+3);
ptrMI += 3;
while( *ptrMI && (*ptrMI != '#') ) ++ptrMI;
if( *ptrMI == '#' )
ptrCode = ++ptrMI;
else
ptrCode = NULL;
}
else
return FALSE;

// found the code?
if( ptrCode )
{
// Find the USB enumed entry
WCHAR wszKey[256];
swprintf_s(wszKey, _countof(wszKey), L"SYSTEM\\ControlSet001\\Enum\\USB\\VID_%04X&PID_%04X", wVID, wPID);
HKEY hKeyEnum, hKeyItem;
if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, wszKey, 0, KEY_READ, &hKeyEnum) == ERROR_SUCCESS )
{
// Search the sub-keys
WCHAR wszName[256];
UINT iIndex = 0;
while( RegEnumKey(hKeyEnum, iIndex++, wszName, _countof(wszName)) == ERROR_SUCCESS )
{
// Open the sub-key
if( RegOpenKeyEx(hKeyEnum, wszName, 0, KEY_READ, &hKeyItem) == ERROR_SUCCESS )
{
WCHAR wszData[256];
DWORD lData = _countof(wszData)*sizeof(WCHAR);
DWORD dwType = REG_SZ;

// Check the ParentIdPrefix for a match
if( RegQueryValueEx(hKeyItem, L"ParentIdPrefix", NULL, &dwType, (LPBYTE)wszData, &lData) == ERROR_SUCCESS )
{
if( !wcsncmp(wszData, ptrCode, 10) )
{
// Found the address!
wcscpy_s(lpAddress, cbAddress, wszName);
RegCloseKey(hKeyItem);
break;
}
}
RegCloseKey(hKeyItem);
}
}
RegCloseKey(hKeyEnum);
}
}
if( *lpAddress )
return TRUE;

return FALSE;
}

Note: _xtoi() just converts a Hex string

Note2: Fixed 11/19/2008: Change compare to only 10 chars to make it XP compatible.


[This message has been edited by egawtry (edited November 19, 2008).]

[This message has been edited by egawtry (edited December 07, 2008).]

IP: Logged

Tsuneo
Member
posted November 17, 2008 04:37 PM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
"I tried your CDC serial number routine. It doesn't work. The DeviceID stuff on the right is junk."

I see.
It works when the device is not a composite device.
Usually, InstaceID derives from serial number. However, the InstaceID of each interface of composite device isn't serial number, but a location ID. Just the composite parent has the serial number.


I found a good answer on this issue,


"Re: SetupDiGetDeviceRegistryProperty - Usb - Address - Busnumber"

"Bernhard"
To find the hid device I used the HID Guid, but I want also to find the CDC
device on the same composite device. Is it possible to readout the parent-id
of both devices?

From: "Doron Holan [MSFT]"
you can use the CM APIs to find the parent DEVINST of both the HID and the CDC device and see if it returns the same DEVINST

To get the parent DevInst,

For HID,
In the course of the count up of the HID device using SetupDi-APIs,
- get SP _DEVINFO_DATA DeviceInfoData by SetupDiGetDeviceInterfaceDetail
- Feed DeviceInfoData.DevInst to CM_Get_Parent, and get the parent's DevInst

For CDC,
In the course of the snippet on "CP2102 & Vista registry"
- SP _DEVINFO_DATA devInfo is returned by SetupDiEnumDeviceInfo
- Feed devInfo.DevInst to CM_Get_Parent, and get the parent's DevInst


CM_Get_Parent
http://msdn.microsoft.com/en-us/library/ms791198.aspx

Tsuneo

IP: Logged

egawtry
Member
posted November 18, 2008 07:52 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
"I found a good answer on this issue"


I get wildly different numbers from CM_Get_Parent(). I have tried going up the tree with no success.

I am also getting "OK" as my serial number from HidD_GetSerialNumberString() - looks like a parsing error. Of course, this messes up my matching by Serial Number. Now I have the CDC serial number, but not the HID!

-Erik

P.S. Figured out the "OK". Mia culpa. The Serial Number method works again.

[This message has been edited by egawtry (edited November 19, 2008).]

IP: Logged

egawtry
Member
posted December 10, 2008 08:00 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Tsuneo,

I have an implementation of the HID/CDC going. The problem is that if I send CDC serial data from the PC to the 340 in a steady stream, it stops receiving after 384 characters (my buffer is 240 chars). The funny thing is that it will still transmit to the PC unerringly.

Any ideas? Should I post a zip of my code?

Thanks,
-Erik

P.S. More details - if I send chumks of less than 384 chars it will send forever, but the second I use a 384 char chunk it dies.

[This message has been edited by egawtry (edited December 12, 2008).]

IP: Logged

egawtry
Member
posted December 12, 2008 04:22 PM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Found it! It was a bug in the Handle_Out3.

There needs to be two changes:
1. The Ep_StatusOUT2 can be EP_HALT or EP_STALL, so check for not EP_IDLE:


if ( Ep_StatusOUT2 != EP_IDLE ) return; // If endpoint is ready

2. The fifo will fill, and then jam unless there is a check for size:


if ( OUT2_FIFO_loaded && (TXcount < (TXBUFSIZE-EP2_OUT_PACKET_SIZE)) ) // FIFO has data?
{
OUT2_FIFO_loaded = FALSE;

#2 also is a bug in the standard CDC implementation.

-Erik

IP: Logged

egawtry
Member
posted December 30, 2008 09:22 AM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Question:

How is stall handled? The reason I ask is I am having serious FIFO overruns on the USB. If the packet is not retrieved from the 34x's FIFO in time, it seems like another is stuffed by the host into the FIFO and lost. If I enable RTS/CTS on the host end, then it doesn't lose anything, but it also destablizes the host serial port within a few hundred bytes and starts randomly jumping around in the FIFO.

HID works great.

Thanks,
-Erik

IP: Logged

egawtry
Member
posted January 03, 2009 11:45 AM     Click Here to See the Profile for egawtry   Click Here to Email egawtry     Edit/Delete Message
Well, got it fixed.

I moved the loaded flag to inside the size check so that the routine will call again if the size is too small, and I also added an else to send a stall.


void CDC_Handle_Bulk_HostOUT( void )
{
static BYTE FIFO_Cnt, first_cnt, second_cnt;
static Ttxcnt pos;
bit turnover;
static BYTE ControlReg; // Temporary storage for EP control register

if ( (Ep_StatusOUT2 == EP_IDLE) ) // If endpoint is ready
{
if ( OUT2_FIFO_loaded ) // FIFO has packet?
{
EIE1 &= ~0x02; // disable USB interrupt
POLL_WRITE_BYTE(INDEX, 2); // Set index to endpoint 2 registers
POLL_READ_BYTE(EOUTCNTL, FIFO_Cnt); // read out number of bytes on the FIFO

pos = (TXBUFSIZE - TXcount);
if( pos > 8 ) pos -= 8;
if( pos >= FIFO_Cnt ) // if any room on the buffer to read out the FIFO
{
OUT2_FIFO_loaded = FALSE;
// total - offset
pos = TXBUFSIZE - TXWTIdx; // consider on wrap around of ring buffer
if ( FIFO_Cnt < pos )
{
first_cnt = FIFO_Cnt;
second_cnt = 0;
turnover = FALSE;
}
else
{
first_cnt = (BYTE)pos;
second_cnt = FIFO_Cnt - first_cnt;
turnover = TRUE;
}

FIFO_READ_FUNC( FIFO_EP2, first_cnt, &TXBuffer[ TXWTIdx ] ); // read bytes from FIFO
if ( second_cnt != 0 )
FIFO_READ_FUNC( FIFO_EP2, second_cnt, TXBuffer );
POLL_WRITE_BYTE(EOUTCSRL, 0); // Clear Out Packet ready and stalled bits

if ( turnover ) // maintainance of buffer parameters
TXWTIdx = second_cnt;
else
TXWTIdx += FIFO_Cnt;

TXcount += FIFO_Cnt;
TXReady = (TXcount > 0);
}
// Not enough space to remove packet from hardware FIFO
else
{
POLL_READ_BYTE(EOUTCSRL, ControlReg); // Read control register
// stalled?
if( !(ControlReg&rbOutSDSTL) )
{
// Set the stall to prevent extra packets
ControlReg |= rbOutSDSTL;
}
// Clear the Stall int flag
ControlReg &= ~rbOutSTSTL;
POLL_WRITE_BYTE(EOUTCSRL, ControlReg);
}

TXFull = (TXcount >= TXBUFSIZE-1);

EIE1 |= 0x02; // enable USB interrupt
}
}
}

-Erik

[This message has been edited by egawtry (edited January 05, 2009).]

IP: Logged

All times are CT (US)

next newest topic | next oldest topic

Administrative Options: Close Topic | Archive/Move | Delete Topic
Post New Topic  Post A Reply
Hop to:

Contact Us | MCU User Forum

Have you seen our MCU Knowledge Base?


Ultimate Bulletin Board 5.47b