Manual

Writing a USB Device Driver
Name
Writing a USB Device Driver — USB Device Driver Porting Guide
Introduction
Often the best way to write a USB device driver will be to start with an existing one and modify it as necessary.
The information given here is intended primarily as an outline rather than as a complete guide.
Note: At the time of writing only one USB device driver has been implemented. Hence it is possible, perhaps
probable, that some portability issues have not yet been addressed. One issue involves the different types
of transfer, for example the initial target hardware had no support for isochronous or interrupt transfers, so
additional functionality may be needed to switch between transfer types. Another issue would be hardware
where a given endpoint number, say endpoint 1, could be used for either receiving or transmitting data, but
not both because a single fifo is used. Issues like these will have to be resolved as and when additional USB
device drivers are written.
The Control Endpoint
A USB device driver should provide a single usbs_control_endpoint data structure for every USB device. Typical
peripherals will have only one USB port so there will be just one such data structure in the entire system, but
theoretically it is possible to have multiple USB devices. These may all involve the same chip, in which case a
single device driver should support multiple device instances, or they may involve different chips. The name or
names of these data structures are determined by the device driver, but appropriate care should be taken to avoid
name clashes.
A USB device cannot be used unless the control endpoint data structure exists. However, the presence of USB
hardware in the target processor or board does not guarantee that the application will necessarily want to use
that hardware. To avoid unwanted code or data overheads, the device driver can provide a configuration op-
tion to determine whether or not the endpoint 0 data structure is actually provided. A default value of CY-
GINT_IO_USB_SLAVE_CLIENTS ensures that the USB driver will be enabled automatically if higher-level code
does require USB support, while leaving ultimate control to the user.
The USB device driver is responsible for filling in the start_fn, poll_fn and interrupt_vector fields.
Usually this can be achieved by static initialization. The driver is also largely responsible for maintaining the
state field. The control_buffer array should be used to hold the first packet of a control message. The
buffer and other fields related to data transfers will be managed jointly by higher-level code and the device
driver. The remaining fields are generally filled in by higher-level code, although the driver should initialize them
to NULL values.
Hardware permitting, the USB device should be inactive until the start_fn is invoked, for example by tristating
the appropriate pins. This prevents the host from interacting with the peripheral before all other parts of the system
have initialized. It is expected that the start_fn will only be invoked once, shortly after power-up.
Where possible the device driver should detect state changes, such as when the connection between host and
peripheral is established, and report these to higher-level code via the state_change_fn callback, if any. The
607