|
Author
|
Topic: USB Composite Device
|
Tsuneo Member
|
posted October 23, 2006 01:22 AM
USB composite deviceExamples 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#approvedWindows 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.
- The class field of the device descriptor equals to zero: (bDeviceClass) = (0x00)
- Single Configuration
- 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
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
Added an example, USB_HID_composite See the first post.Tsuneo
IP: Logged |
MikeB New Member
|
posted November 02, 2007 06:29 AM
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
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
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 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
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
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
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
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
As discussed previously, you need two hot fixes for Windows XP SP2. http://www.cygnal.org/ubb/Forum9/HTML/001572.htmlIt 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
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, ThanksRay
IP: Logged |
Tsuneo Member
|
posted May 15, 2008 11:49 PM
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
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
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
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
Hi TsuneoFirstly 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
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
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
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
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
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 treeACPI- 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
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
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
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
"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
"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
"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
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
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
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
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
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
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
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
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
"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
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
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
"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
"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
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
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
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
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 |