Name
Class Drivers — Structure and Interface
Synopsis
#include <cyg/io/usb.h>
int usb_class_driver_register(
usb_class_driver *class_driver)
;
int usb_class_driver_deregister(
usb_class_driver *class_driver)
;
usb_descriptor *usb_descriptor_find(
usb_descriptor *desc, usb_uint8 type)
;
usb_descriptor *usb_device_class_find(
usb_device *dev, int class, int subclass, int protocol, usb_descriptor *configuration, usb_descriptor *interface)
;
int usb_device_configure(
usb_device *dev, usb_descriptor *config, usb_tfr_callback *callback, void *callback_data)
;
Description
A class driver translates between operations on a standard eCos device interface and operations on a USB device. For example the USB mass storage class driver translates between disk driver operations and USB mass storage operations.
USB Class Object
A class driver interfaces initially to the USB stack through a usb_class_driver object:
struct usb_class_driver { usb_node node; // Link in class driver list int priority; // Priority in list int (*attach)( usb_class_driver *class_driver, usb_device *device ); int (*detach)( usb_class_driver *class_driver, usb_device *device ); void (*poll)( usb_class_driver *class_driver, usb_uint32 interval ); };
The fields in this structure are as follows:
- node
-
A list node, which is used to link this object into a
prioritized list of class drivers. This is initialized by
usb_class_driver_register()
so does not need to be initialized by the class driver. - priority
- The priority of this class driver. This should be a positive integer. When looking for a class driver to handle a newly attached device, the list is scanned in increasing priority order. So lower values are handled first.
- attach
Whenever a new device is attached to a hub, the USB stack assigns it an address, fetches any descriptors, and then tried to find a class driver for it. It does this by calling the
attach()
functions of all registered class drivers until one indicates that it is willing to handle this device. Theattach()
function indicates acceptance by returningUSB_OK
, it indicates non-acceptance by returning an error code, preferablyUSB_ERR_NO_SUPPORT
.If the
attach()
function returnsUSB_OK
then it should also set the device'sdevice.class_driver
field to point to the usb_class_driver object. It should callusb_device_ref()
on the USB device to ensure that it remains valid. It must also callusb_device_select_interface
.- detach
-
This function is called when the USB device detaches. In
addition to cleaning up its own data structures, the main thing
this function should do it arrange for the reference to the USB
device taken in the attach function to be released by calling
usb_device_unref()
, directly or otherwise. - poll
-
This function is called periodically from the USB
subsystem. The
interval
parameter indicates the number of milliseconds since the last call to this function. It can be used by the class driver to operate timeouts and retries. The exact interval between calls will depend on the level of activity of the USB stack and the resolution of the main system timer. Class drivers should therefore not depend on this for accurate timing operation and may need to make their own arrangements for such things.
USB Class API
The USB stack exports a number of functions that are intended for use by class drivers.
The function usb_class_driver_register()
is
used by a class driver to register itself with the USB
stack. Typically a class driver is initialized as an instance of
the driver type that it is intending to serve (e.g. disk, network,
serial etc.) and during the initialization function for that driver
will call usb_class_driver_register()
. If the
driver ever needs to detach itself from the USB stack then it can
call usb_class_driver_deregister()
.
Within the attach()
function, the class driver
can call some USB stack functions to help it decide whether a
device is one that it can support. The most important of these is
usb_device_class_find()
which scans the
descriptors attached to a a device for an interface that implements
the given class
,
subclass
and protocol
types. A value of -1 for subclass
and
protocol
acts as a wildcard. If successful
it returns pointers to the configuration and interface found. The
function usb_descriptor_find()
can be used on
dev->desc_chain
, or any other descriptor
pointer, to find the next descriptor of a given type. The class
driver can also just inspect the device and parse the descriptor
chain itself if necessary.
Before returning, the attach()
function should
call usb_device_configure()
. Which will
configure the device to use the configuration descriptor is
supplied. The class driver must also supply a callback which will
be called when the configuration has been done, or has
failed. Further device setup can then be done in the callback.
Putting all that together, the functions of a class driver should have the following approximate form:
//----------------------------------------------------------------------------- // Attach device call static int mydev_attach( usb_class_driver *class_driver, usb_device *dev ) { int result = USB_OK; mydev_data *mydev; // Look for configuration and interface. Here we assume that the // first configuration is the one we want to use and that we are // not worried about the function type, hence the wildcard. usb_descriptor *cdesc, *idesc; usb_device_class_find( dev, USB_CLASS_MYCLASS, USB_SUBCLASS_MYSUBCLASS, -1, &cdesc, &idesc ); if( cdesc == NULL || idesc == NULL ) return USB_ERR_NO_SUPPORT; // Set up device data structures here... mydev = mydev_alloc(); mydev->dev = dev; // Extract any useful information from the interface descriptor // chain, such as endpoint addresses... // Reference the device usb_device_ref( dev ); // Send off a command to select the configuration // we have found. result = usb_device_configure( dev, cdesc, mydev_attach_tfr_done, mydev ); // If it all worked, set the device's class driver to point to us. if( result == USB_OK ) dev->device.class_driver = class_driver; return result; } //----------------------------------------------------------------------------- // Configuration callback static int mydev_attach_tfr_done( usb_tfr *tfr ) { int result = tfr->status; mydev_data *mydev = tfr->callback_data; usb_device *dev = tfr->dev; // Release tfr object usb_tfr_unref( tfr ); if( result != USB_OK ) { // Handle configuration error by detaching from USB device and // freeing local resources. mydev_free( mydev ); usb_device_unref( dev ); return result; } // Continue device initialization... return result; } //----------------------------------------------------------------------------- // Device detach call static int mydev_detach( usb_class_driver *class_driver, usb_device *dev ) { int result = USB_OK; // Find my device data from device pointer. mydev_data *mydev = mydev_find( dev ); // Shut down device... // Free device data structure mydev_free( mydev ); // Release reference to device usb_device_unref( dev ); return result; } //----------------------------------------------------------------------------- // Device poll call static void mydev_poll( usb_class_driver *class_driver, usb_uint32 interval ) { // Handle timeouts and delays in active devices... }
2024-12-10 | eCosPro Non-Commercial Public License |