# The USB Device Framework

The USB Device framework consists of the following components:

- USB Device Controller Interface (include/usb/udc.h)
- The USB Device Controller Library (drivers/usb/udc_lib.c)
- The USB Function Driver Core (drivers/usb/function/usb_function_core.c)

## USB Device Controller Interface

The UDC driver provides a low-level abstraction of the hardware. Most events originate from the hardware in the form of interrupts, which may cause the UDC driver to call into the UDC library or the function driver. These may in turn call back into the driver in order to send an appropriate response to the host.

### Initialization

UDC initialization is driver-specific and not covered by this API. Some drivers may provide an initialization function for the controller as a whole, which may in turn initialize the UDC, host and transceiver parts depending on the configuration as well as controller-wide state changes (Vbus detection, ID pin state, etc.)

### Endpoint Management

These functions allow drivers to create and destroy endpoints, as well as set, clear and query their "halted" state:

- udc_ep_create(): Create a new endpoint.
- udc_ep_destroy(): Destroy a previously created endpoint.
- udc_ep_set_halt(): Set the halted state of an endpoint.
- udc_ep_clear_halt(): Clear the halted state of an endpoint.
- udc_ep_is_halted(): Check if a given endpoint is halted.

Sometimes, when encountering errors that need some sort of error recovery procedure to be performed by the host, an endpoint must be halted and the host must be prevented from clearing the halted state through the standard ClearFeature(HALT) request. The following functions can be used to "wedge" an endpoint in this manner:

- udc_ep_set_wedge(): Set the wedged state of an endpoint.
- udc_ep_clear_wedge(): Clear the wedged state of an endpoint.
- udc_ep_is_wedged(): Check if a given endpoint is wedged.

Finally, the following function will terminate all queued requests and flush the endpoint FIFO. The data toggle sequencing and halted/wedged states will not be affected.

- udc_ep_flush(): Terminate all pending requests on an endpoint.

### Control Transfers

These functions are used to send and receive packets over the default control endpoint, ep0. The following functions are asynchronous and will call a callback function after the transfer is done. They must be used for all OUT transfers, and should be used for most IN transfers.

- udc_ep0_submit_out_req(): Submit an OUT request on the default control endpoint.
- udc_ep0_submit_in_req(): Submit an IN request on the default control endpoint.

The following functions are synchronous and should be avoided. However, they can sometimes be useful for sending very small packets.

- udc_ep0_write_sync(): Transmit IN data on the default control data synchronously.
- udc_ep0_send_status(): Send a status packet on the default control endpoint.

The function driver should notify the driver when to expect a status OUT packet from the host by calling the following function:

- udc_ep0_expect_status(): Signal that a status packet is expected on the default control endpoint.

### Data Transfer

These functions are used to do non-control transfers, i.e. bulk, interrupt and isochronous transfers. Note that no synchronous functions are available -- the caller must always provide a callback if needed.

- udc_ep_submit_out_req(): Submit an OUT request on a non-control endpoint.
- udc_ep_submit_in_req(): Submit an IN request on a non-control endpoint.

## The USB Device Controller Library

The UDC Library contains common helper functions for USB Device drivers. Currently, only a single function is available:

- udc_lib_process_setup_request(): Handle a USB SETUP request.

This function may be called by the UDC driver to handle a SETUP request received on the default control endpoint (ep0). It will either handle the request directly or pass it on to a higher layer.

The following function is called by the UDC Library when a SET ADDRESS request is received from the host:

- udc_set_address(): Signal that the UDC is to change its USB address after the status IN phase is complete.

## The USB Function Driver Core

The USB Function Driver Core keeps track of configurations, interfaces and settings, and switches between them based on requests received from the host.

A USB device can have one or more configurations, which the host can choose between using the standard SET_CONFIGURATION request. The host can also choose not to enable any configuration by selecting the special configuration ID 0. Each configuration can have one or more interfaces, which are all active at the same time. Each interface can have one or more alternate settings which the host can choose between using the standard SET_INTERFACE request.

### The Device Descriptor

The USB Function Driver Core also provides a Device Descriptor for the device. The contents of this can be specified by defining the following macros in app/config_usb.h. Please see the USB Specification for more information about the meaning of the fields.

- `CONFIG_USB_FUNC_DEVICE_CLASS:` bDeviceClass
- `CONFIG_USB_FUNC_DEVICE_SUBCLASS:` bDeviceSubClass
- `CONFIG_USB_FUNC_DEVICE_PROTOCOL:` bDeviceProtocol
- `CONFIG_USB_FUNC_MAXPACKETSIZE0:` bMaxPacketSize0
- `CONFIG_USB_FUNC_VENDOR_ID:` idVendor
- `CONFIG_USB_FUNC_PRODUCT_ID:` idProduct
- `CONFIG_USB_FUNC_MAJOR_VERSION` / `CONFIG_USB_FUNC_MINOR_VERSION:` bcdDevice
- `CONFIG_USB_FUNC_NR_CONFIGURATIONS:` bNumConfigurations

### Creating Configurations and Interfaces

The following functions are called by the application to create configurations and associate interfaces with them. The interface objects are typically returned by the initialization function of a Function Driver.

- usb_func_add_config(): Add a device configuration.
- usb_func_add_interface(): Add an interface to a configuration.

usb_func_add_config() returns a configuration object which can be passed as a parameter to usb_func_add_interface(). The application is responsible for creating a configuration descriptor for each configuration, and it must never add more configurations than specified by the CONFIG_USB_FUNC_NR_CONFIGURATIONS macro, or more interfaces than specified by the configuration descriptor's bNumInterfaces field.

### Function Driver Interface

A USB Function Driver instance is represented by a struct usb_func_iface object. Each such object contains one or more struct usb_func_iface_setting objects, which in turn is associated with a set of interface operations (struct usb_func_iface_ops). These operations are called by the Function Driver Core in response to certain requests from the host:

- usb_func_iface_ops::enable(): Called when the host selects this interface setting using SET_INTERFACE, and for interface setting 0 when the host selects the configuration to which this interface belongs using SET_CONFIGURATION.
- usb_func_iface_ops::disable(): Called when this interface setting is enabled, and a SET_INTERFACE request with this interface as the target or a SET_CONFIGURATION request is sent by the host.
- usb_func_iface_ops::setup(): Called when this interface setting is enabled, and a vendor- or class-specific request with this interface as the target is sent by the host.

When an interface setting has been enabled, the driver may interact directly with the UDC driver, managing endpoints and submitting requests on them. The function driver may only submit control transfers when it is processing a SETUP request directed at its interface.

Note that the function driver must never keep any endpoints active after usb_func_iface_ops::disable() has been called. When the host re-selects the currently active interface setting using SET_INTERFACE, the Function Core will disable and re-enable the setting. This ensures that the endpoints associated with the interface are properly reset.

### Functions called by the UDC driver

The following functions are called by the USB Device Controller driver or the UDC library in response to USB bus events and control requests from the host:

- usb_func_reset(): Reset the USB function driver.
- usb_func_get_descriptor(): Handle a standard GET_DESCRIPTOR request.
- usb_func_set_configuration(): Set the active configuration.
- usb_func_set_interface(): Select an alternate setting for an interface.
- usb_func_get_interface(): Get the currently active alternate setting of an interface.
- usb_func_process_setup_request(): Handle a class- or vendor-defined setup request.