This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi,
This is regarding the custom board having TM4C1294KCPDT on it. There is some issue with the USB COM Port drivers. Windows 10 detecting the COM as "USB Composite Device" and If i tried to update the drivers it shows error "The best drivers for your device are already installed".
Kindly suggest how to resolve this issue, so that I can have proper COM port in device manager.
Below are the screenshots for your reference:
Hi,
Are you trying to enumerate an USB CDC class device? Do you have the same problem running the same code with the LaunchPad? Have you tried a different Windows 10 machine? Please clarify your application.
Hi,
Please see the below post and download the Windows 10 driver patch as suggest and see if it makes a difference.
Hi,
Tried with the new patch files on above link as per the instruction mentioned in Readme file. But still same problem.
Regards,
Rajneesh
Hello Rajneesh,
The usblib function which handles the creation of the composite descriptor had a logic flaw that causes the enumeration to fail on Windows 10 as it tries to enumerate Endpoint 1 twice.
In order to resolve this, you will need to update your usblib with the fixed function that address that problem. Please follow the below steps.
Replace your usbdcomp.c file with this attached file (make sure it is still named usbdcomp.c as E2E will usually add some extra characters to the file name):
//**************************************************************************** // // usbdcomp.c - USB composite device class driver. // // Copyright (c) 2010-2017 Texas Instruments Incorporated. All rights reserved. // Software License Agreement // // Texas Instruments (TI) is supplying this software for use solely and // exclusively on TI's microcontroller products. The software is owned by // TI and/or its suppliers, and is protected under applicable copyright // laws. You may not combine this software with "viral" open-source // software in order to form a larger program. // // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL // DAMAGES, FOR ANY REASON WHATSOEVER. // // This is part of revision 2.1.4.178 of the Tiva USB Library. // //**************************************************************************** #include <stdbool.h> #include <stdint.h> #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "driverlib/debug.h" #include "driverlib/sysctl.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/usb.h" #include "usblib/usblib.h" #include "usblib/usblibpriv.h" #include "usblib/usb-ids.h" #include "usblib/usbcdc.h" #include "usblib/device/usbdevice.h" #include "usblib/device/usbdcdc.h" #include "usblib/device/usbdcomp.h" //**************************************************************************** // //! \addtogroup composite_device_class_api //! @{ // //**************************************************************************** //**************************************************************************** // // Device Descriptor. This is stored in RAM to allow several fields to be // changed at runtime based on the client's requirements. // //**************************************************************************** static uint8_t g_pui8CompDeviceDescriptor[] = { 18, // Size of this structure. USB_DTYPE_DEVICE, // Type of this structure. USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume // high-speed - see USB 2.0 spec 9.2.6.6) USB_CLASS_MISC, // USB Device Class (spec 5.1.1) USB_MISC_SUBCLASS_COMMON, // USB Device Sub-class (spec 5.1.1) USB_MISC_PROTOCOL_IAD, // USB Device protocol (spec 5.1.1) 64, // Maximum packet size for default pipe. USBShort(0), // Vendor ID (filled in during USBDCompositeInit). USBShort(0), // Product ID (filled in during USBDCompositeInit). USBShort(0x100), // Device Version BCD. 1, // Manufacturer string identifier. 2, // Product string identifier. 3, // Product serial number. 1 // Number of configurations. }; //**************************************************************************** // // Composite class device configuration descriptor. // // It is vital that the configuration descriptor bConfigurationValue field // (byte 6) is 1 for the first configuration and increments by 1 for each // additional configuration defined here. This relationship is assumed in the // device stack for simplicity even though the USB 2.0 specification imposes // no such restriction on the bConfigurationValue values. // // Note that this structure is deliberately located in RAM since we need to // be able to patch some values in it based on client requirements. // //**************************************************************************** static const uint8_t g_pui8CompConfigDescriptor[] = { // // Configuration descriptor header. // 9, // Size of the configuration descriptor. USB_DTYPE_CONFIGURATION, // Type of this descriptor. USBShort(0), // The total size of this full structure. 0, // The number of interfaces in this // configuration, this will be filled by // the class as it discovers all classes // supported. 1, // The unique value for this configuration. 0, // The string identifier that describes this // configuration. USB_CONF_ATTR_BUS_PWR, // . 250, // The maximum power in 2mA increments. }; //**************************************************************************** // // Byte offsets used to access various fields in our index/interface/endpoint // lookup table (tUSBDCompositeDevice.pui32DeviceWorkspace). This workspace // contains one 4 byte entry per device. The LSB is the device index, next byte // is the number of the first interface not within this device, next byte is // the number of the first IN endpoint not within this device and the final // byte is the number of the first OUT endpoint not within this device. Using // this simple table we can reasonably quickly cross-reference index with // interface and endpoint numbers. // //**************************************************************************** #define LOOKUP_INDEX_BYTE 0 #define LOOKUP_INTERFACE_BYTE 1 #define LOOKUP_IN_END_BYTE 2 #define LOOKUP_OUT_END_BYTE 3 //**************************************************************************** // // A marker used to indicate an invalid index into the device table. // //**************************************************************************** #define INVALID_DEVICE_INDEX 0xFFFFFFFF //**************************************************************************** // // Various internal handlers needed by this class. // //**************************************************************************** static void HandleDisconnect(void *pvCompositeInstance); static void InterfaceChange(void *pvCompositeInstance, uint8_t ui8InterfaceNum, uint8_t ui8AlternateSetting); static void ConfigChangeHandler(void *pvCompositeInstance, uint32_t ui32Value); static void DataSent(void *pvCompositeInstance, uint32_t ui32Info); static void DataReceived(void *pvCompositeInstance, uint32_t ui32Info); static void HandleEndpoints(void *pvCompositeInstance, uint32_t ui32Status); static void HandleRequests(void *pvCompositeInstance, tUSBRequest *psUSBRequest); static void SuspendHandler(void *pvCompositeInstance); static void ResumeHandler(void *pvCompositeInstance); static void ResetHandler(void *pvCompositeInstance); static void HandleDevice(void *pvCompositeInstance, uint32_t ui32Request, void *pvRequestData); static void GetDescriptor(void *pvCompositeInstance, tUSBRequest *psUSBRequest); //**************************************************************************** // // Configuration Descriptor. // //**************************************************************************** tConfigHeader *g_ppCompConfigDescriptors[1]; //**************************************************************************** // // The device information structure for the USB Composite device. // //**************************************************************************** const tCustomHandlers g_sCompHandlers = { // // GetDescriptor // GetDescriptor, // // RequestHandler // HandleRequests, // // InterfaceChange // InterfaceChange, // // ConfigChange // ConfigChangeHandler, // // DataReceived // DataReceived, // // DataSentCallback // DataSent, // // ResetHandler // ResetHandler, // // SuspendHandler // SuspendHandler, // // ResumeHandler // ResumeHandler, // // DisconnectHandler // HandleDisconnect, // // EndpointHandler // HandleEndpoints, // // DeviceHandler // HandleDevice, }; //**************************************************************************** // // Use the lookup table from the field pui32DeviceWorkspace in the // tUSBDCompositeDevice structure to determine which device to call given a // particular composite device interface number. // // The returned value is the index into psDevice->tCompositeEntry indicating // the device which contains this interface or INVALID_DEVICE_INDEX if no // device contains the passed interface number. // //**************************************************************************** static uint32_t InterfaceToIndex(tUSBDCompositeDevice *psDevice, uint32_t ui32Interface) { uint32_t ui32Loop; uint32_t ui32Lookup; // // Check each lookup entry in turn. // for(ui32Loop = 0; ui32Loop < psDevice->ui32NumDevices; ui32Loop++) { // // Get the look up value from the device. // ui32Lookup = psDevice->psDevices[ui32Loop].ui32DeviceWorkspace; ui32Lookup = (ui32Lookup >> (8 * LOOKUP_INTERFACE_BYTE)) & 0xff; // // If the desired interface number is lower than the value in the // current lookup table entry, we have found the desired device so // return its index. // if(ui32Interface < ui32Lookup) { return(ui32Loop); } } // // If we get here, an invalid interface number was passed so return a // marker to indicate this. // return(INVALID_DEVICE_INDEX); } //**************************************************************************** // // Use the lookup table from the field pui32DeviceWorkspace in the // tUSBDCompositeDevice structure to determine which device to call given a // particular composite device endpoint number. // // The returned value is the index into psDevice->tCompositeEntry indicating // the device which contains this endpoint or INVALID_DEVICE_INDEX if no // device contains the passed endpoint number. // //**************************************************************************** static uint32_t EndpointToIndex(tUSBDCompositeDevice *psDevice, uint32_t ui32Endpoint, bool bInEndpoint) { uint32_t ui32Loop, ui32EndpointByte, ui32Lookup; // // Are we considering an IN or OUT endpoint? // ui32EndpointByte = bInEndpoint ? LOOKUP_IN_END_BYTE : LOOKUP_OUT_END_BYTE; // // Check each lookup entry in turn. // for(ui32Loop = 0; ui32Loop < psDevice->ui32NumDevices; ui32Loop++) { // // Get the look up byte from the device. // ui32Lookup = psDevice->psDevices[ui32Loop].ui32DeviceWorkspace; ui32Lookup = (ui32Lookup >> (ui32EndpointByte * 8)) & 0xff; // // If the desired endpoint number is lower than the value in the // current lookup table entry, we have found the desired device so // return its index. // if(ui32Endpoint < ui32Lookup) { return(ui32Loop); } } // // If we get here, an invalid endpoint number was passed so return a // marker to indicate this. // return(INVALID_DEVICE_INDEX); } //**************************************************************************** // // This function will check if any device classes need a get descriptor // handler called. // //**************************************************************************** static void GetDescriptor(void *pvCompositeInstance, tUSBRequest *psUSBRequest) { uint32_t ui32Idx; const tDeviceInfo *psDeviceInfo; tUSBDCompositeDevice *psCompDevice; // // Create the composite device pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; // // Determine which device this request is intended for. We have to be // careful here to send this to the callback for the correct device // depending upon whether it is a request sent to the device, the interface // or the endpoint. // switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M) { case USB_RTYPE_INTERFACE: { ui32Idx = InterfaceToIndex(psCompDevice, (psUSBRequest->wIndex & 0xFF)); break; } case USB_RTYPE_ENDPOINT: { ui32Idx = EndpointToIndex(psCompDevice, (psUSBRequest->wIndex & 0x0F), (psUSBRequest->wIndex & 0x80) ? true : false); break; } // // Requests sent to the device or any other recipient can't be // handled here since we have no way of telling where they are // supposed to be handled. As a result, we just stall them. // // If your composite device has some device-specific descriptors, // you should add code here to handle them. // case USB_RTYPE_DEVICE: case USB_RTYPE_OTHER: default: { ui32Idx = INVALID_DEVICE_INDEX; break; } } // // Did we find a device class to pass the request to? // if(ui32Idx != INVALID_DEVICE_INDEX) { // // Get a pointer to the individual device instance. // psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; // // Does this device have a GetDescriptor callback? // if(psDeviceInfo->psCallbacks->pfnGetDescriptor) { // // Remember this device index so that we can correctly route any // data notification callbacks to it. // psCompDevice->sPrivateData.ui32EP0Owner = ui32Idx; // // Call the device to retrieve the descriptor. // psDeviceInfo->psCallbacks->pfnGetDescriptor( psCompDevice->psDevices[ui32Idx].pvInstance, psUSBRequest); } else { // // Oops - we can't satisfy the request so stall EP0 to indicate // an error. // USBDCDStallEP0(USBBaseToIndex( psCompDevice->sPrivateData.ui32USBBase)); } } else { // // We are unable to satisfy the descriptor request so stall EP0 to // indicate an error. // USBDCDStallEP0(USBBaseToIndex( psCompDevice->sPrivateData.ui32USBBase)); } } //**************************************************************************** // // This function will check if any device classes need an suspend handler // called. // //**************************************************************************** static void SuspendHandler(void *pvCompositeInstance) { uint32_t ui32Idx; tUSBDCompositeDevice *psCompDevice; const tDeviceInfo *psDeviceInfo; void *pvDeviceInst; ASSERT(pvCompositeInstance != 0); // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; // // Inform the application that the device has resumed. // if(psCompDevice->pfnCallback) { psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_SUSPEND, 0, 0); } for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++) { psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance; if(psDeviceInfo->psCallbacks->pfnSuspendHandler) { psDeviceInfo->psCallbacks->pfnSuspendHandler(pvDeviceInst); } } } //**************************************************************************** // // This function will check if any device classes need an resume handler // called. // //**************************************************************************** static void ResumeHandler(void *pvCompositeInstance) { uint32_t ui32Idx; tUSBDCompositeDevice *psCompDevice; const tDeviceInfo *psDeviceInfo; void *pvDeviceInst; ASSERT(pvCompositeInstance != 0); // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; // // Inform the application that the device has resumed. // if(psCompDevice->pfnCallback) { psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_RESUME, 0, 0); } for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++) { psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance; if(psDeviceInfo->psCallbacks->pfnResumeHandler) { psDeviceInfo->psCallbacks->pfnResumeHandler(pvDeviceInst); } } } //**************************************************************************** // // This function will check if any device classes need an reset handler // called. // //**************************************************************************** static void ResetHandler(void *pvCompositeInstance) { uint32_t ui32Idx; tUSBDCompositeDevice *psCompDevice; const tDeviceInfo *psDeviceInfo; void *pvDeviceInst; ASSERT(pvCompositeInstance != 0); // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; // // Inform the application that the device has been connected. // if(psCompDevice->pfnCallback) { psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_CONNECTED, 0, 0); } for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++) { psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance; if(psDeviceInfo->psCallbacks->pfnResetHandler) { psDeviceInfo->psCallbacks->pfnResetHandler(pvDeviceInst); } } } //**************************************************************************** // // This function is called to handle data being set to the host so that the // application callback can be called when the data has been transferred. // //**************************************************************************** static void DataSent(void *pvCompositeInstance, uint32_t ui32Info) { uint32_t ui32Idx; const tDeviceInfo *psDeviceInfo; tUSBDCompositeDevice *psCompDevice; // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; // // Pass this notification on to the device which last handled a // transaction on endpoint 0 (assuming we know who that was). // ui32Idx = psCompDevice->sPrivateData.ui32EP0Owner; if(ui32Idx != INVALID_DEVICE_INDEX) { psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; if(psDeviceInfo->psCallbacks->pfnDataSent) { psDeviceInfo->psCallbacks->pfnDataSent( psCompDevice->psDevices[ui32Idx].pvInstance, ui32Info); } } } //**************************************************************************** // // This function is called to handle data being received back from the host so // that the application callback can be called when the new data is ready. // //**************************************************************************** static void DataReceived(void *pvCompositeInstance, uint32_t ui32Info) { uint32_t ui32Idx; const tDeviceInfo *psDeviceInfo; tUSBDCompositeDevice *psCompDevice; // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; // // Pass this notification on to the device which last handled a // transaction on endpoint 0 (assuming we know who that was). // ui32Idx = psCompDevice->sPrivateData.ui32EP0Owner; if(ui32Idx != INVALID_DEVICE_INDEX) { psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; if(psDeviceInfo->psCallbacks->pfnDataReceived) { psDeviceInfo->psCallbacks->pfnDataReceived( psCompDevice->psDevices[ui32Idx].pvInstance, ui32Info); } } } //**************************************************************************** // // This function will check if any device classes need an endpoint handler // called. // //**************************************************************************** static void HandleEndpoints(void *pvCompositeInstance, uint32_t ui32Status) { uint32_t ui32Idx; const tDeviceInfo *psDeviceInfo; tUSBDCompositeDevice *psCompDevice; ASSERT(pvCompositeInstance != 0); // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; // // Call each of the endpoint handlers. This may seem odd since we should // only call the handler whose endpoint needs service. Unfortunately, if // the device class driver is using uDMA, we have no way of knowing which // handler to call (since ui32Status will be 0). Since the handlers are // set up to ignore any callback that is not for them, this is safe. // for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++) { psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; if(psDeviceInfo->psCallbacks->pfnEndpointHandler) { psDeviceInfo->psCallbacks->pfnEndpointHandler( psCompDevice->psDevices[ui32Idx].pvInstance, ui32Status); } } } //***************************************************************************** // // Device instance specific handler. // //***************************************************************************** static void HandleDevice(void *pvCompositeInstance, uint32_t ui32Request, void *pvRequestData) { uint32_t ui32Idx; tUSBDCompositeDevice *psCompDevice; const tDeviceInfo *psDeviceInfo; ASSERT(pvCompositeInstance != 0); // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++) { psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; if(psDeviceInfo->psCallbacks->pfnDeviceHandler) { psDeviceInfo->psCallbacks->pfnDeviceHandler( psCompDevice->psDevices[ui32Idx].pvInstance, ui32Request, pvRequestData); } } if(psCompDevice->pfnCallback) { switch(ui32Request) { case USB_EVENT_LPM_RESUME: { // // Pass the LPM resume event to the client. // psCompDevice->pfnCallback(0, USB_EVENT_LPM_RESUME, 0, (void *)0); break; } case USB_EVENT_LPM_SLEEP: { // // Pass the LPM sleep event to the client. // psCompDevice->pfnCallback(0, USB_EVENT_LPM_SLEEP, 0, (void *)0); break; } case USB_EVENT_LPM_ERROR: { // // Pass the LPM error event to the client. // psCompDevice->pfnCallback(0, USB_EVENT_LPM_ERROR, 0, (void *)0); break; } default: { break; } } } } //**************************************************************************** // // This function is called by the USB device stack whenever the device is // disconnected from the host. // //**************************************************************************** static void HandleDisconnect(void *pvCompositeInstance) { uint32_t ui32Idx; const tDeviceInfo *psDeviceInfo; tUSBDCompositeDevice *psCompDevice; ASSERT(pvCompositeInstance != 0); // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; // // Inform the application that the device has been disconnected. // if(psCompDevice->pfnCallback) { psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_DISCONNECTED, 0, 0); } for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++) { psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; if(psDeviceInfo->psCallbacks->pfnDisconnectHandler) { psDeviceInfo->psCallbacks->pfnDisconnectHandler( psCompDevice->psDevices[ui32Idx].pvInstance); } } } //**************************************************************************** // // This function is called by the USB device stack whenever the device // interface changes. It will be passed on to the device classes if they have // a handler for this function. // //**************************************************************************** static void InterfaceChange(void *pvCompositeInstance, uint8_t ui8InterfaceNum, uint8_t ui8AlternateSetting) { uint32_t ui32Idx; const tDeviceInfo *psDeviceInfo; tUSBDCompositeDevice *psCompDevice; ASSERT(pvCompositeInstance != 0); // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++) { psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; if(psDeviceInfo->psCallbacks->pfnInterfaceChange) { psDeviceInfo->psCallbacks->pfnInterfaceChange( psCompDevice->psDevices[ui32Idx].pvInstance, ui8InterfaceNum, ui8AlternateSetting); } } } //**************************************************************************** // // This function is called by the USB device stack whenever the device // configuration changes. It will be passed on to the device classes if they // have a handler for this function. // //**************************************************************************** static void ConfigChangeHandler(void *pvCompositeInstance, uint32_t ui32Value) { uint32_t ui32Idx; const tDeviceInfo *psDeviceInfo; tUSBDCompositeDevice *psCompDevice; ASSERT(pvCompositeInstance != 0); // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; // // Inform the application that the device configuration has changed. // if(psCompDevice->pfnCallback) { psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_CONFIG_CHANGE, ui32Value, 0); } for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++) { psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; if(psDeviceInfo->psCallbacks->pfnConfigChange) { psDeviceInfo->psCallbacks->pfnConfigChange( psCompDevice->psDevices[ui32Idx].pvInstance, ui32Value); } } } //**************************************************************************** // // This function is called by the USB device stack whenever a non-standard // request is received. // // \param pvCompositeInstance // \param psUSBRequest points to the request received. // // This call will be passed on to the device classes if they have a handler // for this function. // // \return None. // //**************************************************************************** static void HandleRequests(void *pvCompositeInstance, tUSBRequest *psUSBRequest) { uint32_t ui32Idx; const tDeviceInfo *psDeviceInfo; tUSBDCompositeDevice *psCompDevice; // // Create the device instance pointer. // psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance; // // Determine which device this request is intended for. We have to be // careful here to send this to the callback for the correct device // depending upon whether it is a request sent to the device, the interface // or the endpoint. // switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M) { case USB_RTYPE_INTERFACE: { ui32Idx = InterfaceToIndex(psCompDevice, (psUSBRequest->wIndex & 0xFF)); break; } case USB_RTYPE_ENDPOINT: { ui32Idx = EndpointToIndex(psCompDevice, (psUSBRequest->wIndex & 0x0F), (psUSBRequest->wIndex & 0x80) ? true : false); break; } // // Requests sent to the device or any other recipient can't be // handled here since we have no way of telling where they are // supposed to be handled. As a result, we just stall them. // // If your composite device has some device-specific requests that need // to be handled at the device (rather than interface or endpoint) // level, you should add code here to handle them. // case USB_RTYPE_DEVICE: case USB_RTYPE_OTHER: default: { ui32Idx = INVALID_DEVICE_INDEX; break; } } // // Did we find a device class to pass the request to? // if(ui32Idx != INVALID_DEVICE_INDEX) { // // Get a pointer to the individual device instance. // psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo; // // Does this device have a RequestHandler callback? // if(psDeviceInfo->psCallbacks->pfnRequestHandler) { // // Remember this device index so that we can correctly route any // data notification callbacks to it. // psCompDevice->sPrivateData.ui32EP0Owner = ui32Idx; // // Yes - call the device to retrieve the descriptor. // psDeviceInfo->psCallbacks->pfnRequestHandler( psCompDevice->psDevices[ui32Idx].pvInstance, psUSBRequest); } else { // // Oops - we can't satisfy the request so stall EP0 to indicate // an error. // USBDCDStallEP0(USBBaseToIndex( psCompDevice->sPrivateData.ui32USBBase)); } } else { // // We are unable to satisfy the descriptor request so stall EP0 to // indicate an error. // USBDCDStallEP0(USBBaseToIndex( psCompDevice->sPrivateData.ui32USBBase)); } } //**************************************************************************** // // This function handles sending interface number changes to device instances. // //**************************************************************************** static void CompositeIfaceChange(tCompositeEntry *psCompDevice, uint8_t ui8Old, uint8_t ui8New) { uint8_t pui8Interfaces[2]; if(psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler) { // // Create the data to pass to the device handler. // pui8Interfaces[0] = ui8Old; pui8Interfaces[1] = ui8New; // // Call the device handler to inform the class of the interface number // change. // psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler( psCompDevice->pvInstance, USB_EVENT_COMP_IFACE_CHANGE, (void *)pui8Interfaces); } } //**************************************************************************** // // This function handles sending endpoint number changes to device instances. // //**************************************************************************** static void CompositeEPChange(tCompositeEntry *psCompDevice, uint8_t ui8Old, uint8_t ui8New) { uint8_t pui8Interfaces[2]; if(psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler) { // // Create the data to pass to the device handler. // pui8Interfaces[0] = ui8Old; pui8Interfaces[1] = ui8New; ui8New--; // // Call the device handler to inform the class of the interface number // change. // psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler( psCompDevice->pvInstance, USB_EVENT_COMP_EP_CHANGE, (void *)pui8Interfaces); } } //**************************************************************************** // // This function merges the configuration descriptors into a single multiple // instance device. // //**************************************************************************** uint32_t BuildCompositeDescriptor(tUSBDCompositeDevice *psCompDevice) { uint32_t ui32Idx, ui32Offset, ui32CPIdx, ui32FixINT, ui32Dev; uint16_t ui16TotalLength, ui16Bytes; uint8_t ui8Interface, ui8INEndpoint, ui8OUTEndpoint; uint8_t *pui8Data, *pui8Config; const tConfigHeader *psConfigHeader; tDescriptorHeader *psHeader; const uint8_t *pui8Descriptor; tInterfaceDescriptor *psInterface; tEndpointDescriptor *psEndpoint; const tDeviceInfo *psDevice; bool bINEndpointSet = false; bool bOUTEndpointSet = false; // // Save the number of devices to look through. // ui32Dev = 0; ui32Idx = 0; ui8Interface = 0; ui8INEndpoint = 1; ui8OUTEndpoint = 1; ui32Offset = 0; ui32FixINT = 0; bINEndpointSet = false; bOUTEndpointSet = false; // // This puts the first section pointer in the first entry in the list // of sections. // psCompDevice->sPrivateData.ppsCompSections[0] = &psCompDevice->sPrivateData.psCompSections[0]; // // Put the pointer to this instances configuration descriptor into the // front of the list. // psCompDevice->sPrivateData.ppsCompSections[0]->pui8Data = (uint8_t *)&psCompDevice->sPrivateData.sConfigDescriptor; psCompDevice->sPrivateData.ppsCompSections[0]->ui16Size = psCompDevice->sPrivateData.sConfigDescriptor.bLength; // // The configuration descriptor is 9 bytes so initialize the total length // to 9 bytes. // ui16TotalLength = 9; // // Copy the section pointer into the section array for the composite // device. This is awkward but is required given the definition // of the structures. // psCompDevice->sPrivateData.ppsCompSections[1] = &psCompDevice->sPrivateData.psCompSections[1]; // // Copy the pointer to the application supplied space into the section // list. // psCompDevice->sPrivateData.ppsCompSections[1]->ui16Size = 0; psCompDevice->sPrivateData.ppsCompSections[1]->pui8Data = psCompDevice->sPrivateData.pui8Data; // // Create a local pointer to the data that is used to copy data from // the other devices into the composite descriptor. // pui8Data = psCompDevice->sPrivateData.pui8Data; // // Consider each device in turn. // while(ui32Dev < psCompDevice->ui32NumDevices) { // // Save the current starting address of this descriptor. // pui8Config = pui8Data + ui32Offset; // // Create a local pointer to the configuration header. // psDevice = psCompDevice->psDevices[ui32Dev].psDevInfo; psConfigHeader = psDevice->ppsConfigDescriptors[0]; // // Loop through each of the sections in this device's configuration // descriptor. // for(ui32Idx = 0; ui32Idx < psConfigHeader->ui8NumSections; ui32Idx++) { // // Initialize the local offset in this descriptor. We include // a special case here to ignore the initial 9 byte configuration // descriptor since this has already been handled. // if(ui32Idx) { // // This is not the first section so we handle everything in // it. // ui16Bytes = 0; } else { // // This is the first section for this device so skip the 9 // byte configuration descriptor since we've already handled // this. // ui16Bytes = 9; // // If this section includes only the configuration descriptor, // skip it entirely. // if(psConfigHeader->psSections[ui32Idx]->ui16Size <= ui16Bytes) { continue; } } // // Get a pointer to the configuration descriptor. // pui8Descriptor = psConfigHeader->psSections[ui32Idx]->pui8Data; // // Bounds check the allocated space and return if there is not // enough space. // if(ui32Offset > psCompDevice->sPrivateData.ui32DataSize) { return(1); } // // Copy the descriptor from the device into the descriptor list. // for(ui32CPIdx = 0; ui32CPIdx < psConfigHeader->psSections[ui32Idx]->ui16Size; ui32CPIdx++) { pui8Data[ui32CPIdx + ui32Offset] = pui8Descriptor[ui32CPIdx]; } bINEndpointSet = false; bOUTEndpointSet = false; // // Read out the descriptors in this section. // while(ui16Bytes < psConfigHeader->psSections[ui32Idx]->ui16Size) { // // Create a descriptor header pointer. // psHeader = (tDescriptorHeader *)&pui8Data[ui32Offset + ui16Bytes]; // // Check for interface descriptors and modify the numbering to // match the composite device. // if(psHeader->bDescriptorType == USB_DTYPE_INTERFACE) { psInterface = (tInterfaceDescriptor *)psHeader; // // See if this is an alternate setting or the initial // setting. // if(psInterface->bAlternateSetting != 0) { // // If this is an alternate setting then use the // previous interface number because the current one // has already been incremented. // psInterface->bInterfaceNumber = ui8Interface - 1; } else { // // Notify the class that it's interface number has // changed. // CompositeIfaceChange( &psCompDevice->psDevices[ui32Dev], psInterface->bInterfaceNumber, ui8Interface); // // This was the non-alternate setting so save the // value and move to the next interface number. // psInterface->bInterfaceNumber = ui8Interface; // // No strings allowed on interface descriptors for // composite devices. // psInterface->iInterface = 0; ui8Interface++; } } // // Check for endpoint descriptors and modify the numbering to // match the composite device. // else if(psHeader->bDescriptorType == USB_DTYPE_ENDPOINT) { psEndpoint = (tEndpointDescriptor *)psHeader; // // Check if this is an IN or OUT endpoint. // if(psEndpoint->bEndpointAddress & USB_RTYPE_DIR_IN) { // // TivaWare Update 2.2.x - Removed check for Fixed Interrupt // class which caused multiple Windows 10 issues with USB // composite device enumeration. // // Check if an OUT Endpoint was set during this loop if (bOUTEndpointSet) { // Set IN Endpoint Number to be one less than the OUT endpoint // since it was incremented when setting the IN Endpoint. ui8INEndpoint = ui8OUTEndpoint-1; } // // Notify the class that it's interface number has // changed. // CompositeEPChange( &psCompDevice->psDevices[ui32Dev], psEndpoint->bEndpointAddress, ui8INEndpoint); psEndpoint->bEndpointAddress = ui8INEndpoint++ | USB_RTYPE_DIR_IN; // Check if a BULK Endpoint for Data transfer is being set. if(((psEndpoint->bmAttributes & USB_EP_ATTR_TYPE_M) == USB_EP_ATTR_BULK) && (psCompDevice->ui16PID == USB_PID_COMP_SERIAL)) { // Set the boolean that an IN Endpoint for Data transfer is set. bINEndpointSet = true; } } else { // Check if an IN Endpoint was set during this loop if (bINEndpointSet) { // Set OUT Endpoint Number to be one less than the IN endpoint // since it was incremented when setting the IN Endpoint. ui8OUTEndpoint = ui8INEndpoint-1; } // // Notify the class that it's interface number has // changed. // CompositeEPChange(&psCompDevice->psDevices[ui32Dev], psEndpoint->bEndpointAddress, ui8OUTEndpoint); psEndpoint->bEndpointAddress = ui8OUTEndpoint++; // Check if a BULK Endpoint for Data transfer is being set. if(((psEndpoint->bmAttributes & USB_EP_ATTR_TYPE_M) == USB_EP_ATTR_BULK) && (psCompDevice->ui16PID == USB_PID_COMP_SERIAL)) { // Set the boolean that an OUT Endpoint for Data transfer is set. bOUTEndpointSet = true; } } } // // Move on to the next descriptor. // ui16Bytes += psHeader->bLength; } ui32Offset += psConfigHeader->psSections[ui32Idx]->ui16Size; ui16TotalLength += ui16Bytes; } // // Allow the device class to make adjustments to the configuration // descriptor. // psCompDevice->psDevices[ui32Dev].psDevInfo->psCallbacks->pfnDeviceHandler( psCompDevice->psDevices[ui32Dev].pvInstance, USB_EVENT_COMP_CONFIG, (void *)pui8Config); // // Add an entry into the device workspace array to allow us to quickly // map interface and endpoint numbers to device instances later. // psCompDevice->psDevices[ui32Dev].ui32DeviceWorkspace = (ui32Dev << (LOOKUP_INDEX_BYTE * 8)) | (ui8Interface << (LOOKUP_INTERFACE_BYTE * 8)) | (ui8OUTEndpoint << (LOOKUP_OUT_END_BYTE * 8)) | (ui8INEndpoint << (LOOKUP_IN_END_BYTE * 8)); // // Move on to the next device. // ui32Dev++; } // // Modify the configuration descriptor to match the number of interfaces // and the new total size. // psCompDevice->sPrivateData.sCompConfigHeader.ui8NumSections = 2; psCompDevice->sPrivateData.ppsCompSections[1]->ui16Size = ui32Offset; psCompDevice->sPrivateData.sConfigDescriptor.bNumInterfaces = ui8Interface; psCompDevice->sPrivateData.sConfigDescriptor.wTotalLength = ui16TotalLength; return(0); } //**************************************************************************** // //! This function should be called once for the composite class device to //! initialize basic operation and prepare for enumeration. //! //! \param ui32Index is the index of the USB controller to initialize for //! composite device operation. //! \param psDevice points to a structure containing parameters customizing //! the operation of the composite device. //! \param ui32Size is the size in bytes of the data pointed to by the //! \e pui8Data parameter. //! \param pui8Data is the data area that the composite class can use to build //! up descriptors. //! //! In order for an application to initialize the USB composite device class, //! it must first call this function with the a valid composite device class //! structure in the \e psDevice parameter. This allows this function to //! initialize the USB controller and device code to be prepared to enumerate //! and function as a USB composite device. The \e ui32Size and \e pui8Data //! parameters should be large enough to hold all of the class instances //! passed in via the \e psDevice structure. This is typically the full size //! of the configuration descriptor for a device minus its configuration //! header(9 bytes). //! //! This function returns a void pointer that must be passed in to all other //! APIs used by the composite class. //! //! See the documentation on the tUSBDCompositeDevice structure for more //! information on how to properly fill the structure members. //! //! \return This function returns 0 on failure or a non-zero void pointer on //! success. // //**************************************************************************** void * USBDCompositeInit(uint32_t ui32Index, tUSBDCompositeDevice *psDevice, uint32_t ui32Size, uint8_t *pui8Data) { tCompositeInstance *psInst; int32_t i32Idx; uint8_t *pui8Temp; // // Check parameter validity. // ASSERT(ui32Index == 0); ASSERT(psDevice); ASSERT(psDevice->ppui8StringDescriptors); // // Initialize the work space in the passed instance structure. // psInst = &psDevice->sPrivateData; psInst->ui32DataSize = ui32Size; psInst->pui8Data = pui8Data; // // Save the base address of the USB controller. // psInst->ui32USBBase = USBIndexToBase(ui32Index); // // No device is currently transferring data on EP0. // psInst->ui32EP0Owner = INVALID_DEVICE_INDEX; // // Initialize the device information structure. // psInst->sDevInfo.psCallbacks = &g_sCompHandlers; psInst->sDevInfo.pui8DeviceDescriptor = g_pui8CompDeviceDescriptor; psInst->sDevInfo.ppsConfigDescriptors = (const tConfigHeader * const *)g_ppCompConfigDescriptors; psInst->sDevInfo.ppui8StringDescriptors = 0; psInst->sDevInfo.ui32NumStringDescriptors = 0; // // Initialize the device info structure for the composite device. // USBDCDDeviceInfoInit(0, &psInst->sDevInfo); g_ppCompConfigDescriptors[0] = &psInst->sCompConfigHeader; g_ppCompConfigDescriptors[0]->ui8NumSections = 0; g_ppCompConfigDescriptors[0]->psSections = (const tConfigSection * const *)psDevice->sPrivateData.ppsCompSections; // // Create a byte pointer to use with the copy. // pui8Temp = (uint8_t *)&psInst->sConfigDescriptor; // // Copy the default configuration descriptor into the instance data. // for(i32Idx = 0; i32Idx < g_pui8CompConfigDescriptor[0]; i32Idx++) { pui8Temp[i32Idx] = g_pui8CompConfigDescriptor[i32Idx]; } // // Create a byte pointer to use with the copy. // pui8Temp = (uint8_t *)&psInst->sDeviceDescriptor; // // Copy the default configuration descriptor into the instance data. // for(i32Idx = 0; i32Idx < g_pui8CompDeviceDescriptor[0]; i32Idx++) { pui8Temp[i32Idx] = g_pui8CompDeviceDescriptor[i32Idx]; } // // Fix up the device descriptor with the client-supplied values. // psInst->sDeviceDescriptor.idVendor = psDevice->ui16VID; psInst->sDeviceDescriptor.idProduct = psDevice->ui16PID; // // Fix up the configuration descriptor with client-supplied values. // psInst->sConfigDescriptor.bmAttributes = psDevice->ui8PwrAttributes; psInst->sConfigDescriptor.bMaxPower = (uint8_t)(psDevice->ui16MaxPowermA>>1); psInst->sDevInfo.pui8DeviceDescriptor = (const uint8_t *)&psInst->sDeviceDescriptor; // // Plug in the client's string table to the device information // structure. // psInst->sDevInfo.ppui8StringDescriptors = psDevice->ppui8StringDescriptors; psInst->sDevInfo.ui32NumStringDescriptors = psDevice->ui32NumStringDescriptors; // // Enable Clocking to the USB controller so that changes to the USB // controller can be made in the BuildCompositeDescriptor() function. // MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0); // // Create the combined descriptors. // if(BuildCompositeDescriptor(psDevice)) { return(0); } // // All is well so now pass the descriptors to the lower layer and put // the bulk device on the bus. // USBDCDInit(ui32Index, &psInst->sDevInfo, (void *)psDevice); // // Return the pointer to the instance indicating that everything went // well. // return((void *)psDevice); } //**************************************************************************** // //! Shuts down the composite device. //! //! \param pvCompositeInstance is the pointer to the device instance structure //! as returned by USBDCompositeInit(). //! //! This function terminates composite device interface for the instance //! not me supplied. Following this call, the \e pvCompositeInstance instance //! should not be used in any other calls. //! //! \return None. // //**************************************************************************** void USBDCompositeTerm(void *pvCompositeInstance) { ASSERT(pvCompositeInstance != 0); } //**************************************************************************** // // Close the Doxygen group. //! @} // //****************************************************************************
From there, you need to import usblib to your CCS to rebuild it. It is very important for this step that you do not copy the usblib project into your workspace. If you copy it into your workspace, the usblib.lib that is generated will not be pointed to your project.
Once you have the usblib imported, all you need to do is build the project for the new file to be incorporated as part of the .lib output.
To verify you have done this correctly, go to [Install Path]\TivaWare_C_Series-2.1.4.178\usblib\ccs\Debug and check that the usblib.lib file has today's date for date modified.
After this is done, re-build the usb_dev_cserial project and re-flash your device and you should get the composite device ports enumerating correctly.
Hello Rajneesh,
You rejected my proposed solution but offered no details afterwards, can you explain the issue you are facing?
Hi Ralph,
That was done by mistake. Somehow I received the feedback mail first and your solution later on.
I will check your suggested solution tomorrow and update you tomorrow as today is national holiday here.
Regards,
Rajneesh
Hello Rajneesh,
Okay, no problem. I'm going to mark it as a suggestion again as there's a decent chance we'll be referencing that post for future questions on the topic until the change is pushed out on TivaWare :)
Rajneesh Verma said:Kindly suggest why there are 2 COM ports and how to correct it to make only one COM Port.
Windows often caches USB virtual Com ports especially for multiple launch pads being plugged in. Putty or other terminal emulator should be able to determine the active one.
Hello Rajneesh,
That is the intended result of the cserial example. It is an example for Composite devices. If you read the header comments at the top of the project you will see it describes that the project is supposed to enumerate two separate virtual ports.
If you want a single CDC port, then I can help with that as we have an example of that developed which will be released with the next TivaWare, see the attached project: 3580.usb_dev_cdcserial.zip
Hello BP101,
Unfortunately I don't have much ability to do that, though I think there's a Win 7 machine that hasn't been updated which I can quickly check with.
That said, I have high confidence it is solved properly because in my personal opinion, the current composite device descriptors should have never worked to begin with. Why Windows 7 ignores the same endpoint being enumerated twice is beyond me. I carefully coded the enumeration sequence and validated with a USB analyzer so that each endpoint is enumerated with the correct number.
Hello BP101,
Just to follow up, I did test the bug fix on a Windows 7 PC and everything enumerates correctly. I don't anticipate any backwards compatibility issues.
Hi Rajneesh,
I recently encountered the same issue with the USB driver and after following the steps laid out earlier in this post I was able to fix the issue, it seems you were too. Just for clarification, did you use the usb_dev_cserial example to help setup the serial USB? If so that's probably the reason why you are seeing two com ports. The code is setup so that you could have two terminal programs each on their own com port communicate back and forth with each other using the launchpad as the medium.
-Daryl