USBDev_API

The Windows host application communicates with a vendor device through USBDev_API. The latter is a wrapper developed by Micrium allowing the application to access the WinUSB functionalities to manage a USB device. Windows USB (WinUSB) is a generic driver for USB devices. The WinUSB architecture consists of a kernel-mode driver (winusb.sys) and a user-mode dynamic link library (winusb.dll) that exposes WinUSB functions. USBDev_API eases the use of WinUSB by providing a comprehensive API (refer to the USBDev_API Functions Reference for the complete list). Figure - USBDev_API and WinUSB shows the USBDev_API library and WinUSB.

Figure - USBDev_API and WinUSB

USBDev_API and WinUSB


For more about WinUSB architecture, refer to Microsoft’s MSDN online documentation at:  http://msdn.microsoft.com/en-us/library/ff540207(v=VS.85).aspx

Management

USBDev_API offers the following functions to manage a device and its function’s pipes.

Table - USBDev_API Device and Pipe Management API
Function nameOperation
USBDev_DevQtyGet Gets number of devices belonging to a specified Globally Unique IDentifier (GUID) and connected to the host. Refer to the GUID section for more details about the GUID.
USBDev_Open Opens a device.
USBDev_Close Closes a device.
USBDev_BulkIn_Open Opens a bulk IN pipe.
USBDev_BulkOut_Open Opens a bulk OUT pipe.
USBDev_IntrIn_Open Opens an interrupt IN pipe.
USBDev_IntrOut_Open Opens an interrupt OUT pipe.
USBDev_PipeClose Closes a pipe.


Listing - USBDev_API Device and Pipe Management Example shows an example of device and pipe management. The steps to manage a device typically consist in:

  • Opening the vendor device connected to the host.
  • Opening required pipes for this device.
  • Communicating with the device via the open pipes.
  • Closing pipes.
  • Closing the device.

Listing - USBDev_API Device and Pipe Management Example
HANDLE  dev_handle;
HANDLE  bulk_in_handle;
HANDLE  bulk_out_handle;
DWORD   err;
DWORD   nbr_dev;


nbr_dev = USBDev_DevQtyGet(USBDev_GUID, &err);                                (1)
if (err != ERROR_SUCCESS) {
    /* $$$$ Handle the error. */
}
 
dev_handle = USBDev_Open(USBDev_GUID, 1, &err);                               (2)
if (dev_handle == INVALID_HANDLE_VALUE) {
    /* $$$$ Handle the error. */
}
 
bulk_in_handle = USBDev_BulkIn_Open(dev_handle, 0, 0, &err);                  (3)
if (bulk_in_handle == INVALID_HANDLE_VALUE) {
    /* $$$$ Handle the error. */
}
 
bulk_out_handle = USBDev_BulkOut_Open(dev_handle, 0, 0, &err);                (3)
if (bulk_out_handle == INVALID_HANDLE_VALUE) {
    /* $$$$ Handle the error. */
}  
 
/* Communicate with the device. */                                            (4)

USBDev_PipeClose(bulk_in_handle, &err);                                       (5)
if (err != ERROR_SUCCESS) {
    /* $$$$ Handle the error. */
}
 
USBDev_PipeClose(bulk_out_handle, &err);
if (err != ERROR_SUCCESS) {
    /* $$$$ Handle the error. */
}
 
USBDev_Close(dev_handle, &err);                                               (6)
if (err != ERROR_SUCCESS) {
    /* $$$$ Handle the error. */
}

(1) Get the number of devices connected to the host under the specified GUID. A GUID provides a mechanism for applications to communicate with a driver assigned to devices in a class. The number of devices could be used in a loop to open at once all the devices. In this example, one device is assumed.

(2) Open the device by retrieving a general device handle. This handle will be used for pipe management and communication.

(3) Open a bulk pipe by retrieving a pipe handle. In the example, a bulk IN and a bulk OUT pipes are open. If the pipe does not exist for this device, an error is returned. When opening a pipe, the interface number and alternate setting number are specified. In the example, bulk IN and OUT pipes are part of the default interface. Opening an interrupt IN and OUT pipes with USBDev_IntIn_Open() or USBDev_IntOut_Open() is similar to bulk IN and OUT pipes.

(4) Transferring data on the open pipes can take place now. The pipe communication is described in the USBDev_API#Communication section.

(5) Close a pipe by passing the associated handle. The closing operation aborts any transfer in progress for the pipe and frees any allocated resources.

(6) Close the device by passing the associated handle. The operation frees any allocated resources for this device. If a pipe has not been closed by the application, this function will close any forgotten open pipes.


Communication

Synchronous

Synchronous communication means that the transfer is blocking. Upon function call, the application blocks until the end of transfer is completed with or without an error. A timeout can be specified to avoid waiting forever. Listing - USBDev_API Synchronous Read and Write Example presents a read and write example using a bulk IN pipe and a bulk OUT pipe.

Listing - USBDev_API Synchronous Read and Write Example
UCHAR  rx_buf[2];
UCHAR  tx_buf[2];
DWORD  err;


(void)USBDev_PipeRd(bulk_in_handle,                                           (1)
                   &rx_buf[0],                                                (2)
                    2u,
                    5000u,                                                    (3)
                   &err);
if (err != ERROR_SUCCESS) {
    /* $$$$ Handle the error. */
}
 
(void)USBDev_PipeWr(bulk_out_handle,                                          (1)
                   &tx_buf[0],                                                (4)
                    2u,
                    5000u,                                                    (3)
                   &err);
if (err != ERROR_SUCCESS) {
    /* $$$$ Handle the error. */
}

(1) The pipe handle gotten with USBDev_BulkIn_Open() or USBDev_BulkOut_Open() is passed to the function to schedule the transfer for the desired pipe.

(2) The application provides a receive buffer to store the data sent by the device.

(3) In order to avoid an infinite blocking situation, a timeout expressed in milliseconds can be specified. A value of ‘0’ makes the application thread wait forever. In the example, a timeout of 5 seconds is set.

(4) The application provides the transmit buffer that contains the data for the device.


Asynchronous

Asynchronous communication means that the transfer is non-blocking. Upon function call, the application passes the transfer information to the device stack and does not block. Other application processing can be done while the transfer is in progress over the USB bus. Once the transfer has completed, a callback is called by USBDev_API to inform the application about the transfer completion.

Listing - USBDev_API Asynchronous Read Example presents a read example. The asynchronous write is not offered by USBDev_API.

Listing - USBDev_API Asynchronous Read Example
UCHAR  rx_buf[2];
DWORD  err;


USBDev_PipeRdAsync(        bulk_in_handle,                                    (1)
                          &rx_buf[0],                                         (2)
                           2u,
                           App_PipeRdAsyncComplete,                           (3)
                   (void *)0u,                                                (4)
                          &err);
if (err != ERROR_SUCCESS) {
    /* $$$$ Handle the error. */
}

static  void  App_PipeRdAsyncComplete(void   *p_buf,                          (3)
                                      DWORD   buf_len,
                                      DWORD   xfer_len,
                                      void   *p_callback_arg,
                                      DWORD   err)
{
    (void)p_buf;
    (void)buf_len;
    (void)xfer_len;
    (void)p_callback_arg;                                                     (4)
 
    if (err == ERROR_SUCCESS) {
        /* $$$$ Process the received data. */
    } else {
        /* $$$$ Handle the error. */
    }
}

(1) The pipe handle gotten with USBDev_BulkIn_Open() is passed to the function to schedule the transfer for the desired pipe.

(2) The application provides a receive buffer to store the data sent by the device.

(3) The application provides a callback passed as a parameter. Upon completion of the transfer, USBDev_API calls this callback so that the application can finalize the transfer by analyzing the transfer result. For instance, upon read operation completion, the application may do a certain processing with the received data.

(4) An argument associated to the callback can also be passed. Then, in the callback context, some private information can be retrieved.


Control Transfer

You can communicate with the device through the default control endpoint by using the function  USBDev_CtrlReq() . You will be able to define the three types of requests (standard, class or vendor) and to use the data stage or not of a control transfer to move data. More details about control transfers can be found in “Universal Serial Bus Specification, Revision 2.0, April 27, 2000”, section 5.5 and 9.3.