OverView
SiRF USB OTG Driver Architecture:
USB OTG Driver is a buid-in driver,which is loaded by device manager during system booting up. USB OTG driver is responsible for loading USB Host Controller Driver and USB Function Controller Driver.
USB Host Driver Architecture:
USB Function Driver Architecture:
USB Host Driver:
Interfaces of each layer:
USB Host Client Driver—>USB Host Client Common Layer(Client driver should link this lib)--->USB Host Drivr (USBD)—>USB HCI layer.
1. USB Client Driver should implement below three functions for USBD call.
USBDeviceAttach | This function is a USB device attach routine. USB host client drivers must implement this function. |
USBInstallDriver | This function installs a USB client driver. USB host client drivers must implement this function. |
USBUnInstallDriver | This function uninstalls a USB client driver. USB host client drivers must implement this function. |
2. Interface export by "USB Host Client Common Layer” to USB client driver. To use these functions please include Usbclient.h file.
Programming element | Description |
AbortTransfer | This function aborts an active transfer. |
AcquireRemoveLock | This function acquires a remove lock. It attempts to call InterlockedIncrement on Lock. |
ClearOrSetFeature | This function sends a CLEAR_FEATURE or SET_FEATURE request to a USB device. |
CloseTransferHandle | This function closes a USB transfer handle. |
DefaultTransferComplete | This function signals the event passed in when USB signals that a transfer has completed. |
GetSetKeyValues | This function gets or sets values under the HKEY_LOCAL_MACHINE/KeyName registry key. |
GetStatus | This function sends a GET_STATUS request to a USB device. |
GetTransferStatus | This function gets the status of an active transfer. |
InitializeRemoveLock | This function creates a remove lock. |
IssueBulkTransfer | This function initiates a bulk transfer to a USB device on the specified endpoint. |
IssueInterruptTransfer | This function initiates an interrupt transfer with a USB device on the specified endpoint. |
IssueVendorTransfer | This function sends a vendor-specific control transfer to a USB device. |
ReleaseRemoveLock | This function releases the removal lock, decrements the lock count with InterlockedDecrement, and notifies the system that the device is safe to be removed with SetEvent. |
ReleaseRemoveLockAndWait | This function closes the lock event handle so the same lock cannot be reentered. This is the final function called on the remove lock. |
ResetBulkEndpoint | This function resets the pipe, and then checks the endpoint status on the device. If the endpoint is halted, this function sends a clear feature request through ClearOrSetFeature. |
ResetDefaultEndpoint | This function attempts to reset the default endpoint zero. |
ResetPipe | This function resets an open USB pipe. |
3. Interfaces export to upper layer by USBD layer. These interfaces definition at Usbd.cpp as following.
static USB_FUNCS gc_UsbFuncs =
{
sizeof(USB_FUNCS), //DWORD dwCount;
&GetUSBDVersion, // LPGET_USBD_VERSION
&OpenClientRegistryKey, // LPOPEN_CLIENT_REGISTRY_KEY
&RegisterNotificationRoutine, // LPREGISTER_NOTIFICATION_ROUTINE
&UnRegisterNotificationRoutine, // LPUN_REGISTER_NOTIFICATION_ROUTINE
&LoadGenericInterfaceDriver, // LPLOAD_GENERIC_INTERFACE_DRIVER
&TranslateStringDescr, // LPTRANSLATE_STRING_DESCR
&FindInterface, // LPFIND_INTERFACE
&GetFrameNumber, // LPGET_FRAME_NUMBER
&GetFrameLength, // LPGET_FRAME_LENGTH
&TakeFrameLengthControl, // LPTAKE_FRAME_LENGTH_CONTROL
&ReleaseFrameLengthControl, // LPRELEASE_FRAME_LENGTH_CONTROL
&SetFrameLength, // LPSET_FRAME_LENGTH
&GetDeviceInfo, // LPGET_DEVICE_INFO
&IssueVendorTransfer, // LPISSUE_VENDOR_TRANSFER
&GetInterface, // LPGET_INTERFACE
&SetInterface, // LPSET_INTERFACE
&GetDescriptor, // LPGET_DESCRIPTOR
&SetDescriptor, // LPSET_DESCRIPTOR
&SetFeature, // LPSET_FEATURE
&ClearFeature, // LPCLEAR_FEATURE
&GetStatus, // LPGET_STATUS
&SyncFrame, // LPSYNC_FRAME
&OpenPipe, // LPOPEN_PIPE
&AbortPipeTransfers, // LPABORT_PIPE_TRANSFERS
&ResetPipe, // LPRESET_PIPE
&ClosePipe, // LPCLOSE_PIPE
&IsPipeHalted, // LPIS_PIPE_HALTED
&IssueControlTransfer, // LPISSUE_CONTROL_TRANSFER
&IssueBulkTransfer, // LPISSUE_BULK_TRANSFER
&IssueInterruptTransfer, // LPISSUE_INTERRUPT_TRANSFER
&IssueIsochTransfer, // LPISSUE_ISOCH_TRANSFER
&IsTransferComplete, // LPIS_TRANSFER_COMPLETE
&GetTransferStatus, // LPGET_TRANSFER_STATUS
&GetIsochResults, // LPGET_ISOCH_RESULTS
&AbortTransfer, // LPABORT_TRANSFER
&CloseTransfer, // LPCLOSE_TRANSFER
// These functions were added with USBDI version 1.1
&ResetDefaultPipe, // LPRESET_DEFAULT_PIPE
&IsDefaultPipeHalted, // LPIS_DEFAULT_PIPE_HALTED
// This Function were added with USBDI version 1.2
&DisableDevice, //LPDISABLE_DEVICE
&SuspendDevice, //LPSUSPEND_DEVICE
&ResumeDevice, //LPRESUME_DEVICE
// This Function were added with USBDI version 1.3
&GetClientRegistryPath // LPGET_CLIENT_REGISTRY_PATH
};
Programming element | Description |
GetTransferError | This function returns an error value associated with a USB transfer. |
LPABORT_PIPE_TRANSFERS | This function aborts all transfers on an open USB pipe. |
LPABORT_TRANSFER | This function aborts an active transfer. |
LPCLEAR_FEATURE | This function sends a CLEAR_FEATURE request to a USB device. |
LPCLOSE_PIPE | This function closes an open pipe handle. |
LPCLOSE_TRANSFER | This function closes a USB transfer handle. |
LPDEVICE_NOTIFY_ROUTINE | This function receives device notifications. Client drivers register this function with the USBD to recieve device notifications. |
LPDISABLE_DEVICE | This function disables an attached device by disabling the port on the USB hub. After the attached device is disabled, it can be optionally re-enabled by the USB host controller. |
LPFIND_INTERFACE | This function searches for a specific interface on a USB device. |
LPGET_DESCRIPTOR | This function sends a GET_DESCRIPTOR request to a USB device. |
LPGET_DEVICE_INFO | This function gets a pointer to a device information structure. |
LPGET_FRAME_LENGTH | This function gets a current USB frame length. |
LPGET_FRAME_NUMBER | This function gets a current USB frame number. |
LPGET_INTERFACE | This function sends a request to a USB device for information about alternate device settings. |
LPGET_ISOCH_RESULTS | This function gets the status of an active isochronous transfer. |
LPGET_STATUS | This function sends a GET_STATUS request to a USB device. |
LPGET_TRANSFER_STATUS | This function gets the status of an active transfer. |
LPGET_USBD_VERSION | This function retrieves the version number of the current USB driver interface. |
LPIS_DEFAULT_PIPE_HALTED | This function is deprecated. It always returns FALSE. The default pipe never halts. |
LPIS_PIPE_HALTED | This function checks if a USB pipe is in a halted state. |
LPIS_TRANSFER_COMPLETE | This function checks whether a transfer has completed. |
LPISSUE_BULK_TRANSFER | This function initiates a bulk transfer to a USB device on the specified endpoint. |
LPISSUE_CONTROL_TRANSFER | This function initiates a control transfer with a USB device on the specified endpoint. |
LPISSUE_INTERRUPT_TRANSFER | This function initiates an interrupt transfer with a USB device on the specified endpoint. |
LPISSUE_ISOCH_TRANSFER | This function initiates an isochronous transfer with a USB device. |
LPISSUE_VENDOR_TRANSFER | This function sends a vendor-specific control transfer to a USB device. |
LPLOAD_GENERIC_INTERFACE_DRIVER | This function load drivers for other interfaces on a device. USB drivers call this function. |
LPOPEN_CLIENT_REGISTRY_KEY | This function opens a registry key associated with a USB client driver. |
LPOPEN_PIPE | This function opens a pipe for communication with a USB device. |
LPREGISTER_CLIENT_DRIVER_ID | This function registers a unique string to identify a USB client driver. |
LPREGISTER_CLIENT_SETTINGS | This function registers settings for loading a USB client driver. |
LPREGISTER_NOTIFICATION_ROUTINE | This function registers a callback function for device notifications. |
LPRELEASE_FRAME_LENGTH_CONTROL | This function releases exclusive access to USB frame-length control. |
LPRESET_DEFAULT_PIPE | This function resets the default pipe to a USB device. |
LPRESET_PIPE | This function resets an open USB pipe. |
LPRESUME_DEVICE | This function resumes the attached device by resuming the port on the USB hub. |
LPSET_DESCRIPTOR | This function sends a SET_DESCRIPTOR request to a USB device. |
LPSET_FEATURE | This function sends a SET_FEATURE request to a USB device. |
LPSET_FRAME_LENGTH | This function changes the USB frame length. |
LPSET_INTERFACE | This function sends a SET_INTERFACE request to a USB device to change the device's settings. |
LPSUSPEND_DEVICE | This function suspends an attached device by suspending the port on the USB hub. After being suspended, the device can be resumed by the LPRESUME_DEVICE function or by a global resume sent from the USB bus. |
LPSYNC_FRAME | This function sends a SYNCH_FRAME request to a USB device. |
LPTAKE_FRAME_LENGTH_CONTROL | This function registers for exclusive access to control the USB frame length. |
LPTRANSFER_NOTIFY_ROUTINE | This function executes when a transfer completes. |
LPTRANSLATE_STRING_DESCR | This function translates a USB string descriptor into a null-terminated string. |
LPUN_REGISTER_CLIENT_DRIVER_ID | This function unregisters a client driver's unique driver identifier. |
LPUN_REGISTER_CLIENT_SETTINGS | This function deregisters USB device driver settings. |
LPUN_REGISTER_NOTIFICATION_ROUTINE | This function removes a device notification callback function. |
4. Interfaces export by USBD layer to USB HCI layer
Programming element | Description |
HcdAttach | This function will be called when USB HCI driver loading.It uses to pass USB HCI interface functions and USB HCI object pointer to USBD. |
HcdDetach | This function will be called when USB HCI driver unloading. It uses to tell USBD layer to release resource which allocated in HcdAttach. |
HcdDeviceAttached | This function will be called by USB HCI layer when detect a device insertion. It uses to load a client driver for the inserted device. |
HcdDeviceDetached | This function will be called by USB HCI layer when a device removed. It uses to unload a client driver for the removed device. |
5. Interfaces export by USB HCI layer to USBD layer.
extern HCD_FUNCS gc_HcdFuncs =
{
sizeof(HCD_FUNCS), //DWORD dwCount;
&HcdGetFrameNumber, //LPHCD_GET_FRAME_NUMBER lpGetFrameNumber;
&HcdGetFrameLength, //LPHCD_GET_FRAME_LENGTH lpGetFrameLength;
&HcdSetFrameLength, //LPHCD_SET_FRAME_LENGTH lpSetFrameLength;
&HcdStopAdjustingFrame, //LPHCD_STOP_ADJUSTING_FRAME lpStopAdjustingFrame;
&HcdOpenPipe, //LPHCD_OPEN_PIPE lpOpenPipe;
&HcdClosePipe, //LPHCD_CLOSE_PIPE lpClosePipe;
&HcdResetPipe, //LPHCD_RESET_PIPE lpResetPipe;
&HcdIsPipeHalted, //LPHCD_IS_PIPE_HALTED lpIsPipeHalted;
&HcdIssueTransfer, //LPHCD_ISSUE_TRANSFER lpIssueTransfer;
&HcdAbortTransfer, //LPHCD_ABORT_TRANSFER lpAbortTransfer;
&HcdDisableDevice, //LPHCD_DISABLE_DEVICE lpDisableDevice;
&HcdSuspendResume //LPHCD_SUSPEND_RESUME lpSuspendResume;
};
USB HCI Driver Analyse:
USB EHCI Driver Archetecture:
In our system we use a similar enhanced host controller interface (EHCI) controller.So we developed our USB HCI driver based on EHCI driver.
The enhanced host controller interface (EHCI) driver simultaneously supports USB 2.0 and USB 1.1 protocols. The EHCI driver supports existing class drivers. The USB 2.0 common code uses the USB 1.1 common code as a base, with necessary changes to support USB 2.0. The EHCI driver attaches the same USB driver interface as the open host controller interface (OHCI) and the universal host controller interface (UHCI) do.
The USB 2.0 implementation includes some code that is unique to the EHCI driver and some code that is common for all USB 2.0 drivers. It also includes code that is specific to the USB host controller.Microsoft has provided the EHCI driver implement,the source code locate at %_PUBLICROOT%/Common/OAK/Drivers/USB/HCD/USB20 directory.They are divided into three components as below.
Component | Directory |
USB 2.0 Common Code Implemented by the EHCI Driver | USB20COM |
EHCI-specific Code | EHCI |
USB Host Controller-specific Code | EHCIPDD |
USB 2.0 Common Code:
The USB 2.0 common code implements the hub, the interface to the USB driver interface, device attachment and removal, physical memory management with CPhysMem, and bandwidth allocation. USB 1.1 is a base for the USB 2.0 common code, except for extended hub support for USB 2.0 devices and bandwidth allocation.
Except for the root hub, the USB device module operates the hub and device with USB transfers. That means the USB device module(USBD) uses the CPipeAbs abstract class to send and receive transfers with pipes. For the root hub, the USB device uses the root hub abstract function in the host controller driver,do not need pips. The USB device module (USBD) detects device attachment and removal, assigns USB addresses, and gets device descriptors.
There are serval components in USB 2.0 common code,show as below table.
Component | Description |
USB device | This component allows other host software to communicate with devices, hubs, and other USB devices. This component is implemented by CDevice, CFunction, CHub, CRootHub, and CExternalHub. CDevice connects to CFunction. The CDevice abstract class is hierarchically above CFunction and CHub, which are parallel to each other. CHub is an abstract class. CHub is hierarchically above CRootHub and CExternalHub, which are parallel to each other.
|
Physical memory management | This component allocates, tracks, and frees memory.This component is implemented by CPhysMem. |
HCD interface class | This component abstracts the hardware details of the host controller.This component is implemented by CHcd. CHcd, is the interface between the USB device module and the USB driver interface. The CHcd class carries out USB driver interface requests. CHcd contains the reference pointer for the root hub. It propagates USB driver interface requests to the root hub. The hub uses recursion to locate the device that initialized the USB driver interface request, and then propagates the USBD request to the device.
|
USB 2.0 library | This component handles scheduling of USB transactions.This component is implemented in USB2lib.cpp.USB2lib.cpp contains bandwidth information that relates to the bus. It also contains transaction translation information and the related bandwidth information. |
EHCI-specific Code:
EHCI-specific code and USB 2.0 common code interface show as below table.
USB 2.0 common code requires all host controller specific code to implement the virtual functions exposed by the HCD class.
Component | Description and hierarchy |
HCD | HCD implements the host controller driver interface. This abstract class passes requests to other objects. Above CHW and connects to CHW.
|
CHW | CHW implements all of the HCD virtual functions and interfaces with the hardware. There are two reference pointers in hardware that point to the structure to manage. Below HCD and connects to HCD. Above CEhcd and connects to CEhcd.
|
USB2lib | USB2lib handles scheduling of USB transactions. Parallel to CHW and connects to CEhcd.
|
CEhcd | CEhcd contains USB2lib code that the pipe class utilizes. Below CHW and connects to CHW. Below USB2lib and connects to USB2lib.
|
EHCI-specific pipe clases:
The relationship of below classes shows like following picture.
Class | Description and hierarchy |
CPipeAbs | The CPipeAbs abstract class connects to the CPipe abstract class. CPipeAbs is at the top of the class hierarchy.
|
CPipe | The cPipe abstract class implements the common code between the queue pipe and the isochronous pipe. This class includes a split mask and a complete mask for a full speed endpoint. It also holds the transaction translation address and the speed of the pipe. The CPipe abstract class is below and connects to the CPipeAbs abstract class. The CPipe abstract class is above and connects to the CQueuedPipe abstract class. The CPipe abstract class is above and connects to the CIsochronousPipe class.
|
CQueuedPipe | The CQueuedPipe abstract class is used for queue-type pipes, control, bulk, and interrupt common code. It holds the queue header class instance it used. It also holds the currently processing transfer instance and the outstanding queued transfer instance. A transfer class such as CIoschTransfer and CQTransfer manage the transfer. CQueuedPipe handles queued transfers to the queue header. It also handles transfers to the queue header that are not queued. It also controls the state of the queue header through an instance of CQH, the queue header class. CQueuedPipe abstract class is below and connects to the CPipe abstract class. The CQueuedPipe abstract class is above and connects to the CControlPipe, CInterruptPipe, and CBulkPipe classes.
|
CIsochronousPipe | The CIsochronousPipe class is below and connects to the CPipe abstract class. CIsochronousPipe cannot use CQueuePipe because CIsochronousPipe is not a queue based transfer. Instead, CQueuePipe extends CPipe. CQueuePipe has multiple transfers queued into the periodic schedule table to support the continuation of a transfer. CIsochronousPipe references only the header of those transfer lists. Those transfers might all have transfer descriptors inserted into the periodic schedule list table.
|
CControlPipe | The CControlPipe abstract class extends CQueuePipe for control pipes. It sets up the queue header according to the control type and it queues this queue header into the hardware asynchronous queue header list. It provides parameters and the ability to change the packet size at least once for this queue header. The CControlPipe class is below and connects to the CQueuedPipe abstract class.
|
CInterruptPipe | The CInterruptPipe abstract class calls AllocateBusTime in the USB20 library for this endpoint and uses GetSMASK and GetCMASK with the bus bandwidth information as parameters to get the split and complete mask. This class processes high-speed and full-speed interrupt endpoints. It also queues this queue header into the periodic schedule list table. CInterruptPipe extends CQueuePipe for interrupt pipes. It sets up the queue header according to the interrupt type. It also sets up the split and complete mask for its queue header. The CInterruptPipe class is below and connects to the CQueuedPipe abstract class.
|
CBulkPipe | The CBulkPipe abstract class extends CQueuePipe for bulk pipes. It sets up the queue header according to the bulk type, and it queues this queue header into the hardware asynchronous queue header list. It also provides parameter checking functions for IssueTransfer. The CBulkPipe class is below and connects to the CQueuedPipe abstract class.
|
EHCI-specific transfer clases
The relationship of below classes show like following picture.
Class | Description and hierarchy |
CTransfer | The CTransfer abstract class allocates memory for the client, initializes transfer buffers for the client, and performs a callback when it is finished. CTransfer is above CQTransfer and CIsochTransfer and connects to both.
|
CQTransfer | The CQTransfer abstract class implements the transfer descriptor list initialization with AddTransfer. It also implements checking for completion and transfer descriptor completion actions, and implements aborting actions if a transfer must terminate. CQueuedPipe uses CQTransfer for queued pipe endpoints, control transfers, and bulk interrupt transfers. CQTransfer manages the queue transfer descriptor list and references it with the m_pCQTDList member. CQTransfer is below and connects to CTransfer. CQTransfer is parallel to CIsochTransfer.
|
CIsochTransfer | The CIsochTransfer abstract class is the common interface between CITransfer and CSITransfer. With few exceptions, the CIsochronous class interfaces only with CIsochTransfer. CITransfer handles high-speed USB isochronous transfers. CSITransfer, which handles split isochronous transfers, handles full-speed isochronous transfers. CITransfer creates the isochronous transfer descriptors and CSITransfer creates the split isochronous transfer descriptors. CIsochTransfer is below and connects to CTransfer. CIsochTransfer is above CITransfer and CSITransfer. CIsochTransfer is parallel to CQTransfer.
|
CITransfer | The CITransfer abstract class manages isochronous transfers. The CITransfer abstract class is below and connects to CIsochTransfer. CITransfer is parallel to CSITransfer.
|
CSITransfer | The CSITransfer abstract class manages high-speed isochronous transfers. CSITransfer abstract class is below and connects to CIsochTransfer. CSITransfer is parallel to CITransfer.
|
Partable Process Flow:
1. USB EHCI driver load process:
OTG_Init—>Call HCD_Init with host setting parameters,which get from registry.
Below figure shows the function call process.
2. USB Device Attachment/Removal process
RootHub HubStatusChange monitor thread monitor USB port change interrupt and load client driver. HubStatusChange monitor thread—>(WaitForPortStatusChange belongs to roothub class—>WaitForPortStatusChange belongs CHW class)—>Check port status and do relevant process,such as load client driver (call AttachDevice) when USB device inserted. The port change event trigger by HostInterruptHandler belongs CHW class,HostInterruptHandler trigger by physical USB controller interrupt.
AttachDevice process flow:(Note USB device dettach operation just is a reversal process.)
EnterOperationalState function in CFunction class: