A short document that describes how to set the interface descriptors.
Before setting the interface descriptors, get the device and endpoint capabilities of the USB Device Controller (UDC) hardware.
Use RDevUsbcScClient::DeviceCaps() to get the device capabilities and RDevUsbcScClient::EndpointCaps() to get the endpoint capabilities.
TUsbDeviceCapsV01 is the structure used to return the device capabilities.
TUsbDeviceCaps d_caps; TInt r = gPort.DeviceCaps(d_caps);
RDevUsbcScClient::EndpointCaps() returns the object TUsbEndpointData which contains a TUsbEndpointCaps object and a boolean variable that indicates whether the endpoint is in use. TUsbEndpointCaps contains the endpoint capabilities as reported by the driver.
TUsbcEndpointData data[KUsbcMaxEndpoints]; TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data)); r = gPort.EndpointCaps(dataptr);
Note: Endpoint zero is only supported as a control endpoint. The capabilities of endpoint zero are not included in the list of endpoint cababilities returned.
Before calling RDevUsbcScClient::SetInterface(), the class, subclass and protocol must be defined in the TUsbcScInterfaceInfo object. TUsbcScInterfaceInfo is in the TUsbcScInterfaceInfoBuf package buffer.
In the example below we set the interface data in the TUsbcScInterfaceInfo object.
TUsbcScInterfaceInfoBuf ifc; // Endpoint zero ifc().iEndpointData[0].iType = KUsbEpTypeBulk; ifc().iEndpointData[0].iDir = KUsbEpDirIn; ifc().iEndpointData[0].iSize = KUsbEpSize64; //Endpoint 1 ifc().iEndpointData[1].iType = KUsbEpTypeBulk; ifc().iEndpointData[1].iDir = KUsbEpDirOut; ifc().iEndpointData[1].iSize = KUsbEpSize64; _LIT16(string, "T_USBCSC Interface"); ifc().iString = const_cast<TDesC16*>(&string); ifc().iTotalEndpointsUsed = 2; ifc().iClass.iClassNum = 0xff; ifc().iClass.iSubClassNum = 0xff; ifc().iClass.iProtocolNum = 0xff; // Tell the driver that this setting is interested in Ep0 requests: ifc().iFeatureWord |= 0;
TUsbcScInterfaceInfo contains the following data members:
iEndpointData is is an array of n TUsbcScEndpointInfo elements where n = iTotalEndpointsUsed,
For each endpoint the TUsbcScEndpointInfo object must, at the very least, contain:
The endpoint type (iType), direction (iDir) and maximum packet size (iSize) must be specified to claim each endpoint.
The members iBufferSize and iReadSize help with performance tuning and memory optimisation. For example, a capture of 64KB may be an optimal size to pull off the bus without incurring timeout penalties in the PSL. Some classes may benefit from having multiple captures in the endpoint buffer, so iBufferSize would be some multiple of iReadSize.
iExtra and iPairing allow for possible future support of classes that require pairing of endpoints by physical address and function. Note: This is not yet supported and any attempt to pair endpoints will result in failure to create the interface.
iString is a TDesC16,
A description string for the interface.
iTotalEndpointsUsed is a TUint,
This number is all the endpoints you wish to use excluding endpoint zero. For example, if you wish to use 4 endpoints and the control endpoint, this value is should be four.
Note: If you wish to implement a control-only interface then this value should be zero.
iClass is of type TUsbcClassInfo,
Sets the class type for this interface.
iFeatureWord is 32 flag bits used for specifying miscellaneous interface features.
To set the interface pass the initialised TUsbcScInterfaceInfoBuf to RDevUsbcScClient::SetInterface().
// Set up the interface. r = gPort.SetInterface(0, ifc);
The interface number passed to SetInterface() along with TUsbcScInterfaceInfoBuf distinguishes between alternate interfaces. If alternate interfaces are not used then this value is always zero. When used, the value must be one greater than that of the proceeding alternate interface.
Note: The whole Setting interface descriptors section up to this point should be repeated for the number of alternative settings required.
RDevUsbcScClient::RealizeInterface() is called after SetInterface() has been called for all alternative settings.
On success, a chunk handle is created and passed back through aChunk.
RChunk gChunk; r = gPort.RealizeInterface(gChunk);
If you are using the Buffer Interface Layer (BIL) then use FinalizeInterface() instead of RealizeInterface(). FinalizeInterface() has the same effect a calling RealizeInterface(), except that the BIL owns the RChunk handle. This function must be used if you want to use any other BIL method.
RChunk *tChunk = &gChunk; gPort.FinalizeInterface(tChunk);
Note: Calling RealizeInterface() or FinalizeInterface() invalidates all further calls to SetInterface(). All alternative settings must have been initialised before calling these functions.
After you have set the interface descriptors you could optionally Allocate Resources for Endpoints or go straight to Re-Enumerate.