4.1.6.1 General Device Mode Operations

This section describes the USBCD operations such as setting event handlers and attaching and detaching the device.

Handling Device Mode Driver Events

The Device Layer will call the USBCD eventHandlerSet function to register the Device mode event handling function. The USBCD generates various events that indicate different states of the USB. These events are defined by the DRV_USB_EVENT enumeration. The following code example shows how the Device Layer registers the driver event handling function.

/* This code example shows the implementation of the USB_DEVICE_Attach and the
 * USB_DEVICE_Detach function. These functions are actually macro that map
 * directly deviceAttach and the deviceDetach function of the driverInterface
 * member of the deviceClient Object (which is the macro parameter) */
#define USB_DEVICE_Attach( x )  ((USB_DEVICE_OBJ *)x)->driverInterface->deviceAttach
                                ( ((USB_DEVICE_OBJ *)(x))->usbCDHandle)
#define USB_DEVICE_Detach( x )  ((USB_DEVICE_OBJ *)x)->driverInterface->deviceDetach
                                ( ((USB_DEVICE_OBJ *)x)->usbCDHandle)

If the driver is operating in interrupt mode, the client event handling function will execute in an interrupt context. The client should not call interrupt unsafe, computationally intensive or blocking functions in the event handler. The following code shows a small example of the Device Layer USBCD Event Handler:

/* This code example shows a partial implementation of the USB Device Layer
 * event handler. Note how the code type casts the referenceHandle parameter to
 * a USB_DEVICE_OBJ type. This referenceHandle is the same value that the Device
 * Layer passed when the event handler was set. This now easily allows one
 * implementation of the event handling code to be used by multiple Device
 * Layer instances. */
void _USB_DEVICE_EventHandler
(
    uintptr_t referenceHandle,
    DRV_USB_EVENT eventType,
    void * eventData
)
{
    USB_DEVICE_OBJ* usbDeviceThisInstance;
    USB_DEVICE_MASTER_DESCRIPTOR * ptrMasterDescTable;
    USB_DEVICE_EVENT_DATA_SOF SOFFrameNumber;

    usbDeviceThisInstance = (USB_DEVICE_OBJ *)referenceHandle;

    /* Handle events, only if this instance is in initialized state */
    if( usbDeviceThisInstance->usbDeviceInstanceState <= SYS_STATUS_UNINITIALIZED )
    {
        /* The device should anyway not be attached when the Device Layer is
         * not initialized. If we receive driver event when the Device Layer is
         * not initialized, there is nothing we can do but ignore them. */
        return;
    }

    switch(eventType)
    {
        case DRV_USB_EVENT_RESET_DETECT:

            /* Clear the suspended state */
            usbDeviceThisInstance->usbDeviceStatusStruct.isSuspended = false;

            /* Cancel any IRP already submitted in the RX direction. */
            DRV_USB_DEVICE_IRPCancelAll( usbDeviceThisInstance->usbCDHandle,
                    controlEndpointRx );

            /* Code not shown for the sake of brevity. */

    }
}

In the previous code example, the Device Layer (the Driver Client) sets the hReferenceData parameter, of the Event Handler Set function, to point to a local object. This pointer is returned to the Device Layer, in the event handler when an event occurs. For multiple instances of USB drivers in one application, this allows the Device Layer to easily associate a Device Layer specific context to the driver instance, thus simplifying implementation of the event handler.

Attaching and Detaching the Device

The USB Device Layer calls the USBCD deviceAttach and deviceDetach functions to attach and detach the device on the USB. The USB Device Layer should be ready to handle events which would occur when the device is attached on the bus. Hence the USB Device Layer should register the USBCD event handler before the attach function is called. The deviceAttach and deviceDetach functions can be called in an interrupt context. These functions are respectively called when the USB Device application detects a valid VBUS voltage and when the VBUS voltage is not valid.

Setting the Device Address

The USB Device Layer will call the USBCD deviceAddressSet function to set the USB address of the device. The Device Layer will do this when it receives the Set Address control request from the Host. The USBCD will reset the device address to '0' when it has received reset signaling from the root hub. The following code example shows how the USB Device Layer calls this function.

/* The following code example shows how the USB Device Layer calls the
 * DRV_USB_DEVICE_AddressSet function to set the address. The
 * DRV_USB_DEVICE_AddressSet function is actually a macro that calls the
 * deviceAddressSet function of the driverInterface of usbDeviceThisInstance
 * object. The usbDeviceThisInstance is Device Layer object.
 *
 * As seen in this code, the Device Layer calls the address set function when
 * the it a pending set address control request from the Host has completed. */
void _USB_DEVICE_Ep0TransmitCompleteCallback(USB_DEVICE_IRP * handle)
{
    USB_DEVICE_IRP * irpHandle = (USB_DEVICE_IRP *)handle;
    USB_DEVICE_OBJ * usbDeviceThisInstance;
    USB_DEVICE_CONTROL_TRANSFER_STRUCT * controlTransfer;

    usbDeviceThisInstance = (USB_DEVICE_OBJ *)irpHandle->userData;
    controlTransfer = &(usbDeviceThisInstance->controlTransfer);

    if(irpHandle->status == USB_DEVICE_IRP_STATUS_ABORTED)
    {
        return;
    }

    if(usbDeviceThisInstance->usbDeviceStatusStruct.setAddressPending)
    {
        DRV_USB_DEVICE_AddressSet(usbDeviceThisInstance->usbCDHandle,
                                  usbDeviceThisInstance->deviceAddress);
        usbDeviceThisInstance->usbDeviceStatusStruct.setAddressPending = false;
    }

    /* Code not shown for the sake of brevity */

}

Device Current Speed and SOF Number

The USB Device Layer will call the USBCD deviceCurrentSpeedGet function to know the speed at which the device is attached to the USB. This allows the Device Layer to select the correct endpoint settings at the time of processing the Set Configuration request issued by the Host. The USB Device Layer will call the deviceSOFNumberGet function to return the SOF number at the time of the SOF event.

Device Remote Wake-up

The USB Device Layer will call the USBCD deviceRemoteWakeupStop and deviceRemoteWakeupStart functions to stop and start remote signaling. The Device layer application will call the USB Device Layer Stop and Start Remote Wakeup Signaling functions to remotely let the root hub know that the device is ready to be woken up. The timing of the remote signaling is controlled by the Device Layer. The client should call the remote wakeup function only when the device is suspended by the Host.