/* ---------------------------------------------------------------------------- * ATMEL Microcontroller Software Support * ---------------------------------------------------------------------------- * Copyright (c) 2008, Atmel Corporation * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Atmel's name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ---------------------------------------------------------------------------- */ //------------------------------------------------------------------------------ /// \dir /// !!!Purpose /// /// This directory provides definitions, structs and functions for USB %device /// applications with Atmel AT91 microcontrollers and USB %device framework. /// /// You can develop your own USB %device products based on the class-specific /// driver code provided, or just take them as a refference. /// /// !!!Contents /// There are two groups for the implement: /// -# The hardware interface driver for USB peripheral on AT91 /// microcontrollers (UDP or UDPHS), this is a part of the "AT91 USB /// framework". /// - "core": hardware interface driver for AT91 USB peripheral /// -# The %device class driver to class-specific %device. /// - "audio-speaker" /// - "ccid" /// - "cdc-serial" /// - "hid-keyboard" /// - "massstorage" /// /// For more information about what a particular group contains, please refer to /// its documentation page. /// /// \note /// Depending on the project, not all the subdirectories will be available /// (i.e. the #ccid# directory will not be in projects without USB CCID /// function). //------------------------------------------------------------------------------ /** \page "USBD API" See "USBD API Structures" and "USBD API Methods".\n !!!USBD API Structures Several specific structures are used by the USBD API to perform various operations, such as invoking callbacks or accessing the USBD controller. There are two %main structures: - USBDDriver: It is the %main structure of the USB API. It should be instanciated in class-specific USB %device driver or user application. - USBDDriverDescriptors: It is a list of all descriptors used by a USB %device driver. It should be instanciated in class-specific USB %device driver or user application and passed to USBD by USBDDriver_Initialize. !!!USBD API Methods The USB API provides serveral methods to perform the following operations: - Changing the %device state - USBD_Init - USBD_Connect, USBD_Disconnect - USBD_SetAddress - USBD_SetConfiguration - USBD_GetState - "USB Device State Diagram" - Handling events coming from the USB controller - USBD_IrqHandler - Modifying the behavior of an endpoint - USBD_ConfigureEndpoint - USBD_Stall - USBD_Halt - USBD_Unhalt - USBD_IsHalted - Transferring data - USBD_Write - USBD_Read - USBD_IsoWrite - Special functions - USBD_RemoteWakeUp See "USBD API Methods" for detailed informations. */ /** \page "USBD API Structures" !!!USBD API Structures Several specific structures are used by the USBD API to perform various operations, such as invoking callbacks or accessing the USBD controller. There are two %main structures: - USBDDriver: It is the %main structure of the USB API. It should be instanciated in class-specific USB %device driver or user application. - USBDDriverDescriptors: It is a list of all descriptors used by a USB %device driver. It should be instanciated in class-specific USB %device driver or user application and passed to USBD by USBDDriver_Initialize. */ /** \page "USBD API Methods" !!!USB API methods The USB API provides serveral methods to perform the following operations: - Changing the %device state - USBD_Init - USBD_Connect, USBD_Disconnect - USBD_SetAddress - USBD_SetConfiguration - USBD_GetState - "USB Device State Diagram" - Handling events coming from the USB controller - USBD_IrqHandler - Modifying the behavior of an endpoint - USBD_ConfigureEndpoint - USBD_Stall - USBD_Halt - USBD_Unhalt - USBD_IsHalted - Transferring data - USBD_Write - USBD_Read - USBD_IsoWrite - Special functions - USBD_RemoteWakeUp !!!Controlling the Device State Chapter 9 of the USB specification 2.0 describes the various states a %device can be in. Most of the methods of this API are used to change between those states. !!USBD_Init USBD_Init is the first method to call in a user application. Technically, it must occur just before entering the Attached state. It performs the following actions: - USB Device driver and endpoint state initialization - D+ pull-up configuration and disabling - UDP hardware initialization (Peripheral and clock init) A USB %device uses a pull-up on the D+ line to signal its connection to the host. Depending on the USB controller present on the chip, either an internal or external pull-up is used. In both cases, its configuration is performed directly by this method. Please refer to the documentation of a particular controller for more information about the D+ pull-up. The ini callback has to perform several mandatory operations at this point. You can find the default operations in USBDCallbacks_Initialized. !!USBD_Connect, USBD_Disconnect These two methods control the state of the D+ upll-up. This makes it possible to connect of disconnect the %device by software when needed. USBD_Connect changes the %device state from Powered to Default, while USBD_Disconnect changes from either Default, Address or Configured to Powered. !!USBD_SetAddress USBD_SetAddress extracts the information from the last received SETUP packet to either change the %device state from Default to Address or from Address to Default. The difference is made depending on the value of the wValue field of the request. This method must only be called right after the SET_ADDRESS request is received. !!USBD_SetConfiguration This function operates in a way similar to USBD_SetAddress. When the SETUP packet containing a SET_CONFIGURATION request is received, USBD_SetConfiguration should be called to extract the new configuration value to adopt. If the wValue field of the request is non-zero, then the %device must adopt the new configuration and enter the Configuration state; otherwise, it returns (or stays) in the Address state. !!USBD_GetState As its name implies, USBD_GetState simply returns the current state of the USB driver. See state definitions on "USB %device states". - USBD_STATE_SUSPENDED - USBD_STATE_ATTACHED - USBD_STATE_POWERED - USBD_STATE_DEFAULT - USBD_STATE_ADDRESS - USBD_STATE_CONFIGURED !!Device State Diagram See "USB Device State Diagram" !!!Event Handling (USBD_IrqHandler) Several events can occur at the USB controller level: - End of bus reset - Reception of a SETUP packet - Change of bus activity (active -> idle -> active ..) - Completin of an endpoint operation - ... Whenever such an event occurs, it must be forwarded to the USBD API to be handled in an appropriate way. The USBD_IrqHandler performs this functionality, so the controller interrupt must be configured to call it. Several #callbacks# can be triggered depending on the event notified by the controller: - Suspend, when the bus is idle - Resume, when the bus becomes active again - NewRequest, when a setup packet is received on a control endpoint - StartOfFrame, every 1 ms (for full-speed controllers) or 125us (for high- speed controllers) More information about these callbacks and their expected behavior can be found in "USBD Callback API". !!!Endpoint Behavior Modification The USBD API offers following functions to control how an endpoint operates. - USBD_ConfigureEndpoint - USBD_Stall - USBD_Halt - USBD_Unhalt - USBD_IsHalted !!USBD_ConfigureEndpoint USBD_ConfigureEndpoint is used to configure an endpoint at the USB controller level. An appropriate endpoint descriptor must be provided to do that. The descriptor is used to configure the endpoint type (either Control, Bulk, Interrupt or Isochronous), direction (IN or OUT) and address. Control endpoint 0 is automatically configured by the USBD API when the End of bus reset event is signalled by the USB controller. Therefore, there is no need to do it manually. !!USBD_Stall The USBD_Stall method causes and endpoint to acknowledge its next received packet with a STALL handshake. Further packets are then handled normally. Most of the time, this method should be used with endpoint 0 to signal the host that the %device cannot process a command. !!USBD_Halt, USBD_Unhalt, USBD_IsHalted USBD_Halt sets the Halt status of an endpoint. When in Halt mode, every received packet is acknowledged with a STALL handshake instead of being handled normally. #}USB_Halt#} can be called either with the USB_SET_FEATURE, USB_CLEAR_FEATURE or USB_GET_STATUS parameter to modify the endpoint Halt state. USBD_Unhalt clears the Halt status of an endpoint. USBD_IsHalted gets the Halt status of an endpoint. !!!Data Transfer Data transfer (IN or OUT) on an endpoint can be performed by calling two methods, USBD_Write and USBD_Read. !!USBD_Write The USBD_Write function sends a data payload on a specific endpoint. If the data payload equals or exceeds the maximum packet size of the endpoint, then several IN transactions are necessary. This method should only be called on an IN or Control endpoint. The write is performed #asynchronously#, i.e., the function returns immediately without waiting for the transfer to finish. When the transfer is complete, an optional user-provided callback function is called. This makes it possible to create an #OS-friendly synchronous function# by locking and unlocking a semaphore before and after each write. This function handles double-buffering, if it is supported by the USB controller and if it has been enabled for the endpoint. Do not forget that using double-buffering is mandatory for isochronous transactions. - #Note# The double-buffering this function supported is only in period of each write action. That is, when the function is invoked to start transfer trunk of data, the data is automatically splitted to several IN transactions and ping-pong is started on the 2nd transaction. But when all the data of the trunk is finished the ping-pong is stopped. So it can not process the list of buffer that should use double-buffering all the time. See USBD_IsoWrite for such kind of operations. !!USBD_Read The USBD_Read reads incoming data on an endpoint. The transfer stops either when the provided buffer is full, or a short packet (size inferior to the endpoint maximum packet size) is received. This method must only be called on an OUT or Control endpoint. The read is performed #asynchronously#, i.e., the function returns immediately without waiting for the transfer to finish. When the transfer is complete, an optional user-provided callback function is called. This makes it possible to create an #OS-friendly synchronous function# by locking and unlocking a semaphore before and after each read. This function handles #double-buffering#, if it is supported by the USB controller and if it has been enabled for the endpoint. Do not forget that using double-buffering is mandatory for isochronous transactions. !!USBD_IsoWrite The USBD_IsoWrite function sends a buffer list on a specific endpoint. The each buffer's payload should be equals or less than the maximum packet size of the endpoint. The transfer ends when all buffera are sent out. And the buffer is previously sent can be filled with new data before the transfer ends. To maitain a ring buffer for the outgoing stream. This method should only be called on an ISO IN endpoint. The write is performed #asynchronously#, i.e., the function returns immediately without waiting for the transfer to finish. When the transfer is complete, an optional user-provided callback function is called. This makes it possible to create an #OS-friendly synchronous function# by locking and unlocking a semaphore before and after each write. This function handles double-buffering, if it is supported by the USB controller and if it has been enabled for the endpoint. Do not forget that using double-buffering is mandatory for isochronous transactions. !!!Special Functions - USBD_RemoteWakeUp: This method starts a remote wakeup procedure. This makes it possible for a suspended %device to wake a host with may itself be suspended. */ /** \page "USB Device State Diagram" \image USBDeviceStateDiagram.png "Changing the Device State" */ /* (Image Link Backup) USBDeviceStateDiagram.png USBDCallbackInvocationFlowchart.png */ /** \page "USBD Callback API" !!!Callback API The callback API is a means of communication between the user application and the USBD API. When particular operations must be performed, the USB driver calls serveral external functions, refferred to as #callbacks#. They can also be invoked to notify the user application of pending events. Defining all callbacks is not mandatory. For example, if the %device shall not enter low-power mode, then it is appropriate not to provide a Suspend callback. If a callback is mandatory, this is notified in its description. See USBDCallbacks.h for callback definitions. !!!Callback Invocation The following events can trigger a callback: - USB initialization: USBDCallbacks_Initialized - End of bus reset: USBDCallbacks_Reset - Device suspend: USBDCallbacks_Suspended - Device resume: USBDCallbacks_Resumed - SETUP request received: USBDCallbacks_RequestReceived - Start of a new USB frame \image USBDCallbackInvocationFlowchart.png "Callback Invocation Flowchart" !!Init The USBDCallbacks_Initialized callback is invoked when the USBD_Init method is called. It has to perform several mandatory steps to make it possible to use the API: - If an OS is used, perform any specific operation to install the driver - Configure USB controller interrupt - Configure Vbus monitoring PIO and interrupt ( but it's in app layer now ) The USB controller interrupt must be configured to #call the USBD_IrqHandler# API function when triggered. This is necessary to have events happening at the USB controller level handled appropriately by the API. If a PIO pin is connected to VBus, it is possible to monitor it by configuring the pin as an input and enabling the PIO interrupt. The interrupt service routine should simply check the Vbus status and then %call the USBD_Connect and USBD_Disconnect$ function to put %device into right state. Finally, if an OS is being used, then the driver should probably be installed prior to use. Interrupt configuration may also be done differently. Please refer to the documentation of the OS for more information. This callback is #mandatory#. !!Reset When an End of bus reset has been detected, the USBDCallbacks_Reset callback is triggered. The callback should perform #initialization# or #re- initialization# of the user-level application. For example, a class driver like MSD should re-initialize its internal state when a USB reset is performed. !!Suspend When the USB %device enters the Suspended state, the USB API notifies this state change by invoking the USBDCallbacks_Suspended callback. This can happen either when the bus is idle or when the %device is disconnected from the USB. If the %device should enter low-power mode when suspended, then this callback must perform the required operations to do so, e.g., switching to a slow clock, disabling PLLs, etc. - }Note: The electrical specification of the USB 2.0 defines a maximum current consumption of 500uA for suspended %device. This includes the current passing through pull-ups and upll-downs.} !!Resume The USBDCallbacks_Resumed callback is invoked when the USB %device leaves the Suspended state and returns to its previous state (either Powered, Default, Address or Configured). This may happen when activity is detected on the USB, or when the %device gets connected. If the %device was in low-power mode because of the Suspend callback, then this callback must perform the necessary poerations to return the %device into a normal operation mode, e.g., switching to a fast clock. !!NewRequest When a SETUP request is received on a control endpoint, the USBD API layer triggers the USBDCallbacks_RequestReceived callback to notify the user application. The received request can then be accessed through the corresponding USBGenericRequest structure. SETUP packets are used for class-specific requests (e.g. }GetMaxLUN} in MSD) as well as standard USB requests (e.g. }SetConfiguration}). The former are described in }USB Device Class Documents}, such as the }Mass Storage Bulk Only 1.0}, the latter are defined in the USB Specification 2.0. - }Note: that SETUP requests which are not understood by the %device should be acknowledged with a STALL handshake. This notifies the host that the %device cannot process the command.} This callback is #mandatory#. !!StartOfFrame Every 1ms (for a full-speed %device) or 125us (for a high-speed %device) a new USB frame starts. A callback can be invoked whenever this occurs. Because the start-of-frame interrupt %puts some stress on the processor (since it is called a lot), it is only activated the corresponding callback is defined (#now it's NOT defined in current framework#). */ /** \page "USBD Standard Request Handler" !!!Standard Request Handler Chapter 9 of the USB specification 2.0 defines a set of standard requests which have to be implemented by all devices. Since most class drivers treat those requests in the standard way, the USB framework provides a way to easily do that. !!!USBDDriver_RequestHandler USBDDriver_RequestHandler handles the standard requests in an appropriate way. It can answer the following commands: - GET_DESCRIPTOR - SET_ADDRESS - SET_CONFIGURATION - GET_CONFIGURATION - CLEAR_FEATURE - SET_FEATURE - GET_STATUS Simply using this standard request handler enables a %device to be enumerated correctly. !!Get Descriptor The GET_DESCRIPTOR request is used by the host to retrieve information about the %device by means of several descriptors. The standard request handler simply sends the corresponding descriptor to the host. How these descriptors are provided to the function is discussed in Structures. !!Set Address Whenever the host wants to change the %device state from Default to Address, or vice-versa, it sends a SET_ADDRESS request. The wValue field contains the new address of the %device; if it is null, then the %device returns to the Default state. The USBD_SetAddress function is called to perform this operation. Note that a zero-length packet must be sent prior to doing that, to acknowledge the SETUP transfer. !!Set Configuration & GetConfiguration The SET_CONFIGURATION request makes it possible for the host to select between one or more configurations for the %device. GET_CONFIGURATION is used to retrieve the currently selected one. Those two requests are handled in a very basic way by USBDDriver_RequestHandler: it assumes that the %device has only one configuration. Therefore, the SET_CONFIGURATION request is simply acknowledged with a zero-length packet, and GET_CONFIGURATION is answered with either 0 or 1. If the user application needs more than one configuration, it will be the duty of the class driver handler to service those requests. In addition, when the SET_CONFIGURATION request causes the %device to enter the Configured state, the standard request handler calls the USBD_ConfigureEndpoint method for each endpoint used by the %device; !!Clear Feature, Set Feature & Get Status Several features of a %device can either be activated or deactivated by the USB host: - Remote wakeup - Endpoint Halt state Three requests can be used to either set, clear or get the status of these two features: SET_FEATURE, CLEAR_FEATURE and GET_STATUS. The USBDDriver_RequestHandler method answers a Halt state operation by calling the USBD_Halt method on the endpoint with the request. !!!Structures Several pieces of information must be known to the USBDDriver_RequestHandler to be able to process some SETUP commands. For example, all the descriptors (configuration, etc.) used by the %device are needed since they must be sent to the host when a GET_DESCRIPTOR is received. The USBGenericRequest structure is a "standard USB class driver" object used to hold the required information. It must be passed as an argument to the USBDDriver_RequestHandler method. Another structure, USBDDriverDescriptors, is used to store the descriptors list. !!!Usage The NewRequest callback is used to notify the user application that a new SETUP request has been received. SETUP request can either be class-specific or standard. The correct way to handle incoming requests is to first process class-specific requests using a class handler. For example, a Mass Storage implementation will define the NewRequest callback to call MSDDriver_RequestHandler. This function will handle the necessary requests, and forward the rest to USBDDriver_RequestHandler. If a request cannot be processed, USBDDriver_RequestHandler will STALL control endpoint 0. */ /** \page "VID, PID, SN & Strings" This page collects the definition for USB %device to indicate the Vendor and Product information. If you need only the functions in demo %driver, you can easily modify these definitions to change your device's Identification and Display strings. They are defined in the driver c code file that suffixed with "DriverDescriptors" under the driver directory. !!!VID, PID & SN in Device Descriptor Defined as const and used in USBDeviceDescriptor instance initialization. Gives identivication to the USB %device by VID and PID. The INF installation file should mach the VID & PID so that the %device can be installed. \code const USBDeviceDescriptor deviceDescriptor = {...}; \endcode - "audio-speaker": "Audio Speaker Device Codes" - ccid: "CCID Device IDs" - "cdc-serial": "CDC Serial Device IDs" - "hid-keyboard": "HID Device Descriptor IDs" - massstorage: "MSD Device Descriptor IDs" !!!Strings The strings gives additional information on the USB %device, normally string description about the vendor, product and serial number. The strings are defined as a list to initialize the driver's USBDDriverDescriptors instance: - "audio-speaker": auddSpeakerDriverDescriptors - ccid: ccidDriverDescriptors - "cdc-serial": cdcdSerialDriverDescriptors - "hid-keyboard": hiddKeyboardDriverDescriptors - massstorage: msdDriverDescriptors \code // String descriptors const unsigned char *stringDescriptors[] = { languageIdDescriptor, manufacturerDescriptor, productDescriptor, serialNumberDescriptor, }; \endcode */