SAMV71 Xplained Ultra Software Package 1.5

USB Composite Devices Drivers

This page describes how to use the usbd_framework to produce a USB Composite Device Driver, which appears as two USB Functions on host.

Details about the USB can be found in the USB specification 2.0, respectively.

References

Composite Basics

See USB Composite Basics

Architecture

The Composite driver is based on USB Device Framework Architecture.

UsbCompositeSWArch.png

Software Architecture Using the AT91 USB Framework

Descriptors

Device Descriptor

The Device descriptor of a composite device is very basic according to the definition in section 9.6.1, Universal Serial Bus Specification, Revision 2.0, but some of the fields may have different values based on if there is multi-interface function in the device: bDeviceClass, bDeviceSubClass, bDeviceProtocol set to zero for a device without multi-interface function inside; bDeviceClass, bDeviceSubClass, bDeviceProtocol set to EFH, 02H, 01H for a device with multi-interface function inside, such as CDC or Audio class function, as shown below:

        // Composite Device Descriptor
        const USBDeviceDescriptor deviceDescriptor = {
                sizeof(USBDeviceDescriptor),
                USBGenericDescriptor_DEVICE,
                USBDeviceDescriptor_USB2_00,
              #if defined(usb_HIDMSD)
                0x00,
                0x00,
                0x00,
              #else
                0xEF,// MI
                0x02,//
                0x01,//
              #endif
                BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0),
                COMPOSITEDDriverDescriptors_VENDORID,
                COMPOSITEDDriverDescriptors_PRODUCTID,
                COMPOSITEDDriverDescriptors_RELEASE,
                0, // No string descriptor for manufacturer
                1, // Index of product string descriptor is #1
                0, // No string descriptor for serial number
                1 // Device has 1 possible configuration
        };

Note that the Vendor ID is a special value attributed by the USB-IF organization. The product ID can be chosen freely by the vendor. The HID and MSD class functions are all single-interface functions, so the corresponding fields are set to zeros.

Configuration Descriptor

It's just standard one as defined in section 9.6.3, Universal Serial Bus Specification, Revision 2.0, with wTotalLength set to the total length of all standard and function specific descriptors followed, bNumInterface set to the summary number of interfaces of all functions used.

        // Composite Configuration Descriptor
        {
                sizeof(USBConfigurationDescriptor),
                USBGenericDescriptor_CONFIGURATION,
                sizeof(CompositeDriverConfigurationDescriptors),
                COMPOSITEDDriverDescriptors_NUMINTERFACE,
                1, // This is configuration #1
                0, // No string descriptor for this configuration
                BOARD_USB_BMATTRIBUTES,
                USBConfigurationDescriptor_POWER(100)
        },

When the Configuration descriptor is requested by the host (by using the GET_DESCRIPTOR command), the device must also send all the related descriptors, i.e. IAD, Interface, Endpoint and Class-specific descriptors. It is convenient to create a single structure to hold all this data, for sending everything in one trunk.

IAD

See Interface Association Descriptor.

Interface, Class-Specific & Endpoint Descriptors

All these descriptors are almost the same as their definitions in a single USB device, except the interface index related or endpoint addresses related settings. Please refer to the following projects:

String Descriptors

Several descriptors can be commented with a String Descriptor. The latter is completely optional and does not have any effect on the detection of the device by the operating system. Whether or not to include them is entirely up to the programmer.

There is one exception to this rule when using the MSD class. According to the specification, there must be a Serial Number string. It must contains at least 12 characters, and these character must only be either letters (a-z, A-Z) or numbers (0-9). This cause no problem for the driver in practice, but this is a strict requirement for certification. Also please remember that string descriptors use the Unicode format.

Requests

The composite itself does not define any special requests, but the device functions do.

Each function in the device has its own requests handler. The device invokes one of the function requests handler first, when the return value of the handler indicates the request is handled by the device function, then the device request handler return directly, but if it is not handled, the device request handler calls next function request handler to check it. It will be forwarded to the standard request handler if there is no valid handler for this request.

In the device function request handlers, wIndex of the request is checked first to confirm that the request is accepted by the function (interface). Then check if it is a standard request and handle it in two different way.

UsbCompositeRequestHandler.png

General Request Handler for Composite Device

For class-specific request, refer to their related documents:

Notifications

Notifications are supported only if CDC serial port device function is included, please refer to USB Device CDC Serial Driver.

management

The function in the device may need some callbacks to handle the USB events, such as configured or changed interface.

HID Keybard Function Callbacks

For a HID Keyboard, the device function should start reporting to host through interrupt endpoint as soon as the device is configured, so USBDDriverCallbacks_ConfigurationChanged() should be re-implement to monitor the configured status of the device, and then forward the event to the device function to handle it. For more details, see USB Device HID Keyboard Driver.

Audio Speaker Function Callbacks

The USB Audio Speaker defines alternative interfaces to control the USB bandwidth, so there is a callback defined to handle the event of AT91 USB Device Framework. The function is USBDDriverCallbacks_InterfaceSettingChanged(), which should be re-implemented to replace the original one. AUDDFunctionCallbacks_InterfaceSettingChanged() is invoked and then let the Audio Device Function to handle the event. For more details, see USB Device Audio Speaker Driver.

Composite Device Examples

UsbCompositeHidMsdArch.png

HID MSD Composite Driver Architecture

Device descriptors:

        typedef struct {
                // Standard configuration descriptor.
                USBConfigurationDescriptor configuration;
                // --- HID
                USBInterfaceDescriptor hidInterface;
                HIDDescriptor hid;
                USBEndpointDescriptor hidInterruptIn;
                USBEndpointDescriptor hidInterruptOut;
                // --- MSD
                // Mass storage interface descriptor.
                USBInterfaceDescriptor msdInterface;
                // Bulk-out endpoint descriptor.
                USBEndpointDescriptor msdBulkOut;
                // Bulk-in endpoint descriptor.
                USBEndpointDescriptor msdBulkIn;
        } __attribute__ ((packed)) CompositeDriverConfigurationDescriptors;

UsbCompositeHidAudioArch.png

HID Audio Composite Device Architecture

Device descriptors:

        typedef struct {
                // Standard configuration descriptor.
                USBConfigurationDescriptor configuration;
                // --- HID
                USBInterfaceDescriptor hidInterface;
                HIDDescriptor hid;
                USBEndpointDescriptor hidInterruptIn;
                USBEndpointDescriptor hidInterruptOut;
                // --- AUDIO
                // IAD 1
                USBInterfaceAssociationDescriptor audIAD;
                // Audio control interface.
                USBInterfaceDescriptor audInterface;
                // Descriptors for the audio control interface.
                AUDDSpeakerDriverAudioControlDescriptors audControl;
                // -- AUDIO out
                // Streaming out interface descriptor (with no endpoint, required).
                USBInterfaceDescriptor audStreamingOutNoIsochronous;
                // Streaming out interface descriptor.
                USBInterfaceDescriptor audStreamingOut;
                // Audio class descriptor for the streaming out interface.
                AUDStreamingInterfaceDescriptor audStreamingOutClass;
                // Stream format descriptor.
                AUDFormatTypeOneDescriptor1 audStreamingOutFormatType;
                // Streaming out endpoint descriptor.
                AUDEndpointDescriptor audStreamingOutEndpoint;
                // Audio class descriptor for the streaming out endpoint.
                AUDDataEndpointDescriptor audStreamingOutDataEndpoint;
        } __attribute__ ((packed)) CompositeDriverConfigurationDescriptors;

UsbCompositeCdcHidArch.png

CDC HID Composite Device Architecture

Device descriptors:

        typedef struct {
                // Standard configuration descriptor.
                USBConfigurationDescriptor configuration;
                // --- CDC 0
                // IAD 0
                USBInterfaceAssociationDescriptor cdcIAD0;
                // Communication interface descriptor
                USBInterfaceDescriptor cdcCommunication0;
                // CDC header functional descriptor.
                CDCHeaderDescriptor cdcHeader0;
                // CDC call management functional descriptor.
                CDCCallManagementDescriptor cdcCallManagement0;
                // CDC abstract control management functional descriptor.
                CDCAbstractControlManagementDescriptor cdcAbstractControlManagement0;
                // CDC union functional descriptor (with one slave interface).
                CDCUnionDescriptor cdcUnion0;
                // Notification endpoint descriptor.
                USBEndpointDescriptor cdcNotification0;
                // Data interface descriptor.
                USBInterfaceDescriptor cdcData0;
                // Data OUT endpoint descriptor.
                USBEndpointDescriptor cdcDataOut0;
                // Data IN endpoint descriptor.
                USBEndpointDescriptor cdcDataIn0;
                // --- HID
                USBInterfaceDescriptor hidInterface;
                HIDDescriptor hid;
                USBEndpointDescriptor hidInterruptIn;
                USBEndpointDescriptor hidInterruptOut;
        } __attribute__ ((packed)) CompositeDriverConfigurationDescriptors;

UsbCompositeCdcMsdArch.png

CDC MSD Composite Device Architecture

Device descriptors:

        typedef struct {
                // Standard configuration descriptor.
                USBConfigurationDescriptor configuration;
                // --- CDC 0
                // IAD 0
                USBInterfaceAssociationDescriptor cdcIAD0;
                // Communication interface descriptor
                USBInterfaceDescriptor cdcCommunication0;
                // CDC header functional descriptor.
                CDCHeaderDescriptor cdcHeader0;
                // CDC call management functional descriptor.
                CDCCallManagementDescriptor cdcCallManagement0;
                // CDC abstract control management functional descriptor.
                CDCAbstractControlManagementDescriptor cdcAbstractControlManag
                // CDC union functional descriptor (with one slave interface).
                CDCUnionDescriptor cdcUnion0;
                // Notification endpoint descriptor.
                USBEndpointDescriptor cdcNotification0;
                // Data interface descriptor.
                USBInterfaceDescriptor cdcData0;
                // Data OUT endpoint descriptor.
                USBEndpointDescriptor cdcDataOut0;
                // Data IN endpoint descriptor.
                USBEndpointDescriptor cdcDataIn0;
                // --- MSD
                // Mass storage interface descriptor.
                USBInterfaceDescriptor msdInterface;
                // Bulk-out endpoint descriptor.
                USBEndpointDescriptor msdBulkOut;
                // Bulk-in endpoint descriptor.
                USBEndpointDescriptor msdBulkIn;
        } __attribute__ ((packed)) CompositeDriverConfigurationDescriptors;

UsbCompositeCdcAudioArch.png

CDC Audio Composite Device Architecture

Device descriptors:

        typedef struct {
                // Standard configuration descriptor.
                USBConfigurationDescriptor configuration;
                // --- CDC 0
                // IAD 0
                USBInterfaceAssociationDescriptor cdcIAD0;
                // Communication interface descriptor
                USBInterfaceDescriptor cdcCommunication0;
                // CDC header functional descriptor.
                CDCHeaderDescriptor cdcHeader0;
                // CDC call management functional descriptor.
                CDCCallManagementDescriptor cdcCallManagement0;
                // CDC abstract control management functional descriptor.
                CDCAbstractControlManagementDescriptor cdcAbstractControlManagement0;
                // CDC union functional descriptor (with one slave interface).
                CDCUnionDescriptor cdcUnion0;
                // Notification endpoint descriptor.
                USBEndpointDescriptor cdcNotification0;
                // Data interface descriptor.
                USBInterfaceDescriptor cdcData0;
                // Data OUT endpoint descriptor.
                USBEndpointDescriptor cdcDataOut0;
                // Data IN endpoint descriptor.
                USBEndpointDescriptor cdcDataIn0;
                // --- AUDIO
                // IAD 1
                USBInterfaceAssociationDescriptor audIAD;
                // Audio control interface.
                USBInterfaceDescriptor audInterface;
                // Descriptors for the audio control interface.
                AUDDSpeakerDriverAudioControlDescriptors audControl;
                // -- AUDIO out
                // Streaming out interface descriptor (with no endpoint, required).
                USBInterfaceDescriptor audStreamingOutNoIsochronous;
                // Streaming out interface descriptor.
                USBInterfaceDescriptor audStreamingOut;
                // Audio class descriptor for the streaming out interface.
                AUDStreamingInterfaceDescriptor audStreamingOutClass;
                // Stream format descriptor.
                AUDFormatTypeOneDescriptor1 audStreamingOutFormatType;
                // Streaming out endpoint descriptor.
                AUDEndpointDescriptor audStreamingOutEndpoint;
                // Audio class descriptor for the streaming out endpoint.
                AUDDataEndpointDescriptor audStreamingOutDataEndpoint;
        } __attribute__ ((packed)) CompositeDriverConfigurationDescriptors;

UsbCompositeCdcCdcArch.png

Dual CDC Composite Device Architecture

Device descriptors:

        typedef struct {
                // Standard configuration descriptor.
                USBConfigurationDescriptor configuration;
                // --- CDC 0
                // IAD 0
                USBInterfaceAssociationDescriptor cdcIAD0;
                // Communication interface descriptor
                USBInterfaceDescriptor cdcCommunication0;
                // CDC header functional descriptor.
                CDCHeaderDescriptor cdcHeader0;
                // CDC call management functional descriptor.
                CDCCallManagementDescriptor cdcCallManagement0;
                // CDC abstract control management functional descriptor.
                CDCAbstractControlManagementDescriptor cdcAbstractControlManagement0;
                // CDC union functional descriptor (with one slave interface).
                CDCUnionDescriptor cdcUnion0;
                // Notification endpoint descriptor.
                USBEndpointDescriptor cdcNotification0;
                // Data interface descriptor.
                USBInterfaceDescriptor cdcData0;
                // Data OUT endpoint descriptor.
                USBEndpointDescriptor cdcDataOut0;
                // Data IN endpoint descriptor.
                USBEndpointDescriptor cdcDataIn0;
                // --- CDC 1
                // IAD 1
                USBInterfaceAssociationDescriptor cdcIAD1;
                // Communication interface descriptor
                USBInterfaceDescriptor cdcCommunication1;
                // CDC header functional descriptor.
                CDCHeaderDescriptor cdcHeader1;
                // CDC call management functional descriptor.
                CDCCallManagementDescriptor cdcCallManagement1;
                // CDC abstract control management functional descriptor.
                CDCAbstractControlManagementDescriptor cdcAbstractControlManagement1;
                // CDC union functional descriptor (with one slave interface).
                CDCUnionDescriptor cdcUnion1;
                // Notification endpoint descriptor.
                USBEndpointDescriptor cdcNotification1;
                // Data interface descriptor.
                USBInterfaceDescriptor cdcData1;
                // Data OUT endpoint descriptor.
                USBEndpointDescriptor cdcDataOut1;
                // Data IN endpoint descriptor.
                USBEndpointDescriptor cdcDataIn1;
        } __attribute__ ((packed)) CompositeDriverConfigurationDescriptors;

Main Application

Normally the main application code can be divided into four parts:

Initialization

This part initializes all peripherals and drivers, depending on the functions which are included. Normally there are following general initializations:

Interrupt Handlers

This part includes the necessary handler for Vbus detect, the media handler for MSD device function, USART handler for CDC serial port, and the SSC handler for Audio device function if needed. One extra handler may be needed for the timer or PIT or SYSTICK.

management

Some of the device function requires callback handler to execute the request from host, such as the mute state changed by the host, or data received or sent, so that another transfer can be started.

Main Loop

All driver function is non-blocked function, and many of them is called in the main loop, to receive data from the host, to scan the input keys and send report to host (for HID), to run the state machine (for MSD).

Using a Generic Host Driver

The device functions are generally supported by Microsoft Windows, but for composite device, some patches are needed. All the composite devices above are tested under windows XP (SP3) and works fine. For CDC serial port, additional windows driver file (.inf) is required.

Windows Patches

See Windows Driver Update For Composite.

Windows Driver Files for CDC Serial Function

In order to make windows recognize the CDC serial device correctly, it is necessary to write a .inf file. Please refer to USB Device CDC Serial Driver for detailed information. Only one thing should be modified to match the composite device function installation.

For composite devices, the hardware ID is made up of the Vender ID, the Product ID and (optionally) the Device Release Number and the start interface number of the function. Those values are extracted from the device descriptors provided during the enumeration phase, the following is the example of the modification for the dual-port CDC serial:

[AtmelMfg]
%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6119&MI_00 ; 1st 
COM device
%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6119&MI_02 ; 2nd COM device 

When a new device is plugged in for the first time, Windows looks for an appropriate specific or generic driver to use it. The composite device will be recognized as ˇ°USB Composite Deviceˇ±. Then Windows search the driver for the functions inside the composite device.

Please refer to the driver function related application notes for more details. The final installation file is as following:

[Version]
Signature="$Chicago$"
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%ATMEL%
DriverVer=09/12/2006,1.1.1.5
[DestinationDirs]
DefaultDestDir=12
[Manufacturer]
%ATMEL%=AtmelMfg
[AtmelMfg]
%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6127&MI_00
%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6128&MI_00
%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6129&MI_00
%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6119&MI_00
%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6119&MI_02
[USBtoSer.Install]
include=mdmcpq.inf
CopyFiles=FakeModemCopyFileSection
AddReg=USBtoSer.AddReg
[USBtoSer.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,usbser.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
[USBtoSer.Install.Services]
AddService=usbser,0x00000002,USBtoSer.AddService
[USBtoSer.AddService]
DisplayName=%USBSer%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=%12%\usbser.sys
[Strings]
ATMEL="ATMEL Corp."
USBtoSerialConverter="AT91 USB to Serial Converter"
USBSer="USB Serial Driver"
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines