123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149 |
- /**
- * \file
- *
- * \brief USB Device Controller (UDC)
- *
- * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
- *
- * \asf_license_start
- *
- * \page License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. The name of Atmel may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * 4. This software may only be redistributed and used in connection with an
- * Atmel microcontroller product.
- *
- * 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
- * EXPRESSLY AND SPECIFICALLY 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.
- *
- * \asf_license_stop
- *
- */
- /*
- * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
- */
-
- #ifdef ARDUINO_ARCH_SAM
-
- #include "conf_usb.h"
- #include "usb_protocol.h"
- #include "udd.h"
- #include "udc_desc.h"
- #include "udi.h"
- #include "udc.h"
-
- /**
- * \ingroup udc_group
- * \defgroup udc_group_interne Implementation of UDC
- *
- * Internal implementation
- * @{
- */
-
- //! \name Internal variables to manage the USB device
- //! @{
-
- //! Device status state (see enum usb_device_status in usb_protocol.h)
- static le16_t udc_device_status;
-
- COMPILER_WORD_ALIGNED
- //! Device interface setting value
- static uint8_t udc_iface_setting = 0;
-
- //! Device Configuration number selected by the USB host
- COMPILER_WORD_ALIGNED
- static uint8_t udc_num_configuration = 0;
-
- //! Pointer on the selected speed device configuration
- static udc_config_speed_t UDC_DESC_STORAGE *udc_ptr_conf;
-
- //! Pointer on interface descriptor used by SETUP request.
- static usb_iface_desc_t UDC_DESC_STORAGE *udc_ptr_iface;
-
- //! @}
-
-
- //! \name Internal structure to store the USB device main strings
- //! @{
-
- /**
- * \brief Language ID of USB device (US ID by default)
- */
- COMPILER_WORD_ALIGNED
- static UDC_DESC_STORAGE usb_str_lgid_desc_t udc_string_desc_languageid = {
- .desc.bLength = sizeof(usb_str_lgid_desc_t),
- .desc.bDescriptorType = USB_DT_STRING,
- .string = {LE16(USB_LANGID_EN_US)}
- };
-
- /**
- * \brief USB device manufacture name storage
- * String is allocated only if USB_DEVICE_MANUFACTURE_NAME is declared
- * by usb application configuration
- */
- #ifdef USB_DEVICE_MANUFACTURE_NAME
- static uint8_t udc_string_manufacturer_name[] = USB_DEVICE_MANUFACTURE_NAME;
- # define USB_DEVICE_MANUFACTURE_NAME_SIZE \
- (sizeof(udc_string_manufacturer_name)-1)
- #else
- # define USB_DEVICE_MANUFACTURE_NAME_SIZE 0
- #endif
-
- /**
- * \brief USB device product name storage
- * String is allocated only if USB_DEVICE_PRODUCT_NAME is declared
- * by usb application configuration
- */
- #ifdef USB_DEVICE_PRODUCT_NAME
- static uint8_t udc_string_product_name[] = USB_DEVICE_PRODUCT_NAME;
- # define USB_DEVICE_PRODUCT_NAME_SIZE (sizeof(udc_string_product_name)-1)
- #else
- # define USB_DEVICE_PRODUCT_NAME_SIZE 0
- #endif
-
- /**
- * \brief Get USB device serial number
- *
- * Use the define USB_DEVICE_SERIAL_NAME to set static serial number.
- *
- * For dynamic serial number set the define USB_DEVICE_GET_SERIAL_NAME_POINTER
- * to a suitable pointer. This will also require the serial number length
- * define USB_DEVICE_GET_SERIAL_NAME_LENGTH.
- */
- #if defined USB_DEVICE_GET_SERIAL_NAME_POINTER
- static const uint8_t *udc_get_string_serial_name(void)
- {
- return (const uint8_t *)USB_DEVICE_GET_SERIAL_NAME_POINTER;
- }
- # define USB_DEVICE_SERIAL_NAME_SIZE \
- USB_DEVICE_GET_SERIAL_NAME_LENGTH
- #elif defined USB_DEVICE_SERIAL_NAME
- static const uint8_t *udc_get_string_serial_name(void)
- {
- return (const uint8_t *)USB_DEVICE_SERIAL_NAME;
- }
- # define USB_DEVICE_SERIAL_NAME_SIZE \
- (sizeof(USB_DEVICE_SERIAL_NAME)-1)
- #else
- # define USB_DEVICE_SERIAL_NAME_SIZE 0
- #endif
-
- /**
- * \brief USB device string descriptor
- * Structure used to transfer ASCII strings to USB String descriptor structure.
- */
- struct udc_string_desc_t {
- usb_str_desc_t header;
- le16_t string[Max(Max(USB_DEVICE_MANUFACTURE_NAME_SIZE, \
- USB_DEVICE_PRODUCT_NAME_SIZE), USB_DEVICE_SERIAL_NAME_SIZE)];
- };
- COMPILER_WORD_ALIGNED
- static UDC_DESC_STORAGE struct udc_string_desc_t udc_string_desc = {
- .header.bDescriptorType = USB_DT_STRING
- };
- //! @}
-
- usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void)
- {
- return udc_ptr_iface;
- }
-
- /**
- * \brief Returns a value to check the end of USB Configuration descriptor
- *
- * \return address after the last byte of USB Configuration descriptor
- */
- static usb_conf_desc_t UDC_DESC_STORAGE *udc_get_eof_conf(void)
- {
- return (UDC_DESC_STORAGE usb_conf_desc_t *) ((uint8_t *)
- udc_ptr_conf->desc +
- le16_to_cpu(udc_ptr_conf->desc->wTotalLength));
- }
-
- #if (0!=USB_DEVICE_MAX_EP)
- /**
- * \brief Search specific descriptor in global interface descriptor
- *
- * \param desc Address of interface descriptor
- * or previous specific descriptor found
- * \param desc_id Descriptor ID to search
- *
- * \return address of specific descriptor found
- * \return NULL if it is the end of global interface descriptor
- */
- static usb_conf_desc_t UDC_DESC_STORAGE *udc_next_desc_in_iface(usb_conf_desc_t
- UDC_DESC_STORAGE * desc, uint8_t desc_id)
- {
- usb_conf_desc_t UDC_DESC_STORAGE *ptr_eof_desc;
-
- ptr_eof_desc = udc_get_eof_conf();
- // Go to next descriptor
- desc = (UDC_DESC_STORAGE usb_conf_desc_t *) ((uint8_t *) desc +
- desc->bLength);
- // Check the end of configuration descriptor
- while (ptr_eof_desc > desc) {
- // If new interface descriptor is found,
- // then it is the end of the current global interface descriptor
- if (USB_DT_INTERFACE == desc->bDescriptorType) {
- break; // End of global interface descriptor
- }
- if (desc_id == desc->bDescriptorType) {
- return desc; // Specific descriptor found
- }
- // Go to next descriptor
- desc = (UDC_DESC_STORAGE usb_conf_desc_t *) ((uint8_t *) desc +
- desc->bLength);
- }
- return NULL; // No specific descriptor found
- }
- #endif
-
- /**
- * \brief Search an interface descriptor
- * This routine updates the internal pointer udc_ptr_iface.
- *
- * \param iface_num Interface number to find in Configuration Descriptor
- * \param setting_num Setting number of interface to find
- *
- * \return 1 if found or 0 if not found
- */
- static bool udc_update_iface_desc(uint8_t iface_num, uint8_t setting_num)
- {
- usb_conf_desc_t UDC_DESC_STORAGE *ptr_end_desc;
-
- if (0 == udc_num_configuration) {
- return false;
- }
-
- if (iface_num >= udc_ptr_conf->desc->bNumInterfaces) {
- return false;
- }
-
- // Start at the beginning of configuration descriptor
- udc_ptr_iface = (UDC_DESC_STORAGE usb_iface_desc_t *)
- udc_ptr_conf->desc;
-
- // Check the end of configuration descriptor
- ptr_end_desc = udc_get_eof_conf();
- while (ptr_end_desc >
- (UDC_DESC_STORAGE usb_conf_desc_t *) udc_ptr_iface) {
- if (USB_DT_INTERFACE == udc_ptr_iface->bDescriptorType) {
- // A interface descriptor is found
- // Check interface and alternate setting number
- if ((iface_num == udc_ptr_iface->bInterfaceNumber) &&
- (setting_num ==
- udc_ptr_iface->bAlternateSetting)) {
- return true; // Interface found
- }
- }
- // Go to next descriptor
- udc_ptr_iface = (UDC_DESC_STORAGE usb_iface_desc_t *) (
- (uint8_t *) udc_ptr_iface +
- udc_ptr_iface->bLength);
- }
- return false; // Interface not found
- }
-
- /**
- * \brief Disables an usb device interface (UDI)
- * This routine call the UDI corresponding to interface number
- *
- * \param iface_num Interface number to disable
- *
- * \return 1 if it is done or 0 if interface is not found
- */
- static bool udc_iface_disable(uint8_t iface_num)
- {
- udi_api_t UDC_DESC_STORAGE *udi_api;
-
- // Select first alternate setting of the interface
- // to update udc_ptr_iface before call iface->getsetting()
- if (!udc_update_iface_desc(iface_num, 0)) {
- return false;
- }
-
- // Select the interface with the current alternate setting
- udi_api = udc_ptr_conf->udi_apis[iface_num];
-
- #if (0!=USB_DEVICE_MAX_EP)
- if (!udc_update_iface_desc(iface_num, udi_api->getsetting())) {
- return false;
- }
-
- // Start at the beginning of interface descriptor
- {
- usb_ep_desc_t UDC_DESC_STORAGE *ep_desc;
- ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *) udc_ptr_iface;
- while (1) {
- // Search Endpoint descriptor included in global interface descriptor
- ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *)
- udc_next_desc_in_iface((UDC_DESC_STORAGE
- usb_conf_desc_t *)
- ep_desc, USB_DT_ENDPOINT);
- if (NULL == ep_desc) {
- break;
- }
- // Free the endpoint used by the interface
- udd_ep_free(ep_desc->bEndpointAddress);
- }
- }
- #endif
-
- // Disable interface
- udi_api->disable();
- return true;
- }
-
- /**
- * \brief Enables an usb device interface (UDI)
- * This routine calls the UDI corresponding
- * to the interface and setting number.
- *
- * \param iface_num Interface number to enable
- * \param setting_num Setting number to enable
- *
- * \return 1 if it is done or 0 if interface is not found
- */
- static bool udc_iface_enable(uint8_t iface_num, uint8_t setting_num)
- {
- // Select the interface descriptor
- if (!udc_update_iface_desc(iface_num, setting_num)) {
- return false;
- }
-
- #if (0!=USB_DEVICE_MAX_EP)
- usb_ep_desc_t UDC_DESC_STORAGE *ep_desc;
-
- // Start at the beginning of the global interface descriptor
- ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *) udc_ptr_iface;
- while (1) {
- // Search Endpoint descriptor included in the global interface descriptor
- ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *)
- udc_next_desc_in_iface((UDC_DESC_STORAGE
- usb_conf_desc_t *) ep_desc,
- USB_DT_ENDPOINT);
- if (NULL == ep_desc)
- break;
- // Alloc the endpoint used by the interface
- if (!udd_ep_alloc(ep_desc->bEndpointAddress,
- ep_desc->bmAttributes,
- le16_to_cpu
- (ep_desc->wMaxPacketSize))) {
- return false;
- }
- }
- #endif
- // Enable the interface
- return udc_ptr_conf->udi_apis[iface_num]->enable();
- }
-
- /*! \brief Start the USB Device stack
- */
- void udc_start(void)
- {
- udd_enable();
- }
-
- /*! \brief Stop the USB Device stack
- */
- void udc_stop(void)
- {
- udd_disable();
- udc_reset();
- }
-
- /**
- * \brief Reset the current configuration of the USB device,
- * This routines can be called by UDD when a RESET on the USB line occurs.
- */
- void udc_reset(void)
- {
- uint8_t iface_num;
-
- if (udc_num_configuration) {
- for (iface_num = 0;
- iface_num < udc_ptr_conf->desc->bNumInterfaces;
- iface_num++) {
- udc_iface_disable(iface_num);
- }
- }
- udc_num_configuration = 0;
- #if (USB_CONFIG_ATTR_REMOTE_WAKEUP \
- == (USB_DEVICE_ATTR & USB_CONFIG_ATTR_REMOTE_WAKEUP))
- if (CPU_TO_LE16(USB_DEV_STATUS_REMOTEWAKEUP) & udc_device_status) {
- // Remote wakeup is enabled then disable it
- UDC_REMOTEWAKEUP_DISABLE();
- }
- #endif
- udc_device_status =
- #if (USB_DEVICE_ATTR & USB_CONFIG_ATTR_SELF_POWERED)
- CPU_TO_LE16(USB_DEV_STATUS_SELF_POWERED);
- #else
- CPU_TO_LE16(USB_DEV_STATUS_BUS_POWERED);
- #endif
- }
-
- void udc_sof_notify(void)
- {
- uint8_t iface_num;
-
- if (udc_num_configuration) {
- for (iface_num = 0;
- iface_num < udc_ptr_conf->desc->bNumInterfaces;
- iface_num++) {
- if (udc_ptr_conf->udi_apis[iface_num]->sof_notify != NULL) {
- udc_ptr_conf->udi_apis[iface_num]->sof_notify();
- }
- }
- }
- }
-
- /**
- * \brief Standard device request to get device status
- *
- * \return true if success
- */
- static bool udc_req_std_dev_get_status(void)
- {
- if (udd_g_ctrlreq.req.wLength != sizeof(udc_device_status)) {
- return false;
- }
-
- udd_set_setup_payload( (uint8_t *) & udc_device_status,
- sizeof(udc_device_status));
- return true;
- }
-
- #if (0!=USB_DEVICE_MAX_EP)
- /**
- * \brief Standard endpoint request to get endpoint status
- *
- * \return true if success
- */
- static bool udc_req_std_ep_get_status(void)
- {
- static le16_t udc_ep_status;
-
- if (udd_g_ctrlreq.req.wLength != sizeof(udc_ep_status)) {
- return false;
- }
-
- udc_ep_status = udd_ep_is_halted(udd_g_ctrlreq.req.
- wIndex & 0xFF) ? CPU_TO_LE16(USB_EP_STATUS_HALTED) : 0;
-
- udd_set_setup_payload( (uint8_t *) & udc_ep_status,
- sizeof(udc_ep_status));
- return true;
- }
- #endif
-
- /**
- * \brief Standard device request to change device status
- *
- * \return true if success
- */
- static bool udc_req_std_dev_clear_feature(void)
- {
- if (udd_g_ctrlreq.req.wLength) {
- return false;
- }
-
- if (udd_g_ctrlreq.req.wValue == USB_DEV_FEATURE_REMOTE_WAKEUP) {
- udc_device_status &= CPU_TO_LE16(~(uint32_t)USB_DEV_STATUS_REMOTEWAKEUP);
- #if (USB_CONFIG_ATTR_REMOTE_WAKEUP \
- == (USB_DEVICE_ATTR & USB_CONFIG_ATTR_REMOTE_WAKEUP))
- UDC_REMOTEWAKEUP_DISABLE();
- #endif
- return true;
- }
- return false;
- }
-
- #if (0!=USB_DEVICE_MAX_EP)
- /**
- * \brief Standard endpoint request to clear endpoint feature
- *
- * \return true if success
- */
- static bool udc_req_std_ep_clear_feature(void)
- {
- if (udd_g_ctrlreq.req.wLength) {
- return false;
- }
-
- if (udd_g_ctrlreq.req.wValue == USB_EP_FEATURE_HALT) {
- return udd_ep_clear_halt(udd_g_ctrlreq.req.wIndex & 0xFF);
- }
- return false;
- }
- #endif
-
- /**
- * \brief Standard device request to set a feature
- *
- * \return true if success
- */
- static bool udc_req_std_dev_set_feature(void)
- {
- if (udd_g_ctrlreq.req.wLength) {
- return false;
- }
-
- switch (udd_g_ctrlreq.req.wValue) {
-
- case USB_DEV_FEATURE_REMOTE_WAKEUP:
- #if (USB_CONFIG_ATTR_REMOTE_WAKEUP \
- == (USB_DEVICE_ATTR & USB_CONFIG_ATTR_REMOTE_WAKEUP))
- udc_device_status |= CPU_TO_LE16(USB_DEV_STATUS_REMOTEWAKEUP);
- UDC_REMOTEWAKEUP_ENABLE();
- return true;
- #else
- return false;
- #endif
-
- #ifdef USB_DEVICE_HS_SUPPORT
- case USB_DEV_FEATURE_TEST_MODE:
- if (!udd_is_high_speed()) {
- break;
- }
- if (udd_g_ctrlreq.req.wIndex & 0xFF) {
- break;
- }
- // Unconfigure the device, terminating all ongoing requests
- udc_reset();
- switch ((udd_g_ctrlreq.req.wIndex >> 8) & 0xFF) {
- case USB_DEV_TEST_MODE_J:
- udd_g_ctrlreq.callback = udd_test_mode_j;
- return true;
-
- case USB_DEV_TEST_MODE_K:
- udd_g_ctrlreq.callback = udd_test_mode_k;
- return true;
-
- case USB_DEV_TEST_MODE_SE0_NAK:
- udd_g_ctrlreq.callback = udd_test_mode_se0_nak;
- return true;
-
- case USB_DEV_TEST_MODE_PACKET:
- udd_g_ctrlreq.callback = udd_test_mode_packet;
- return true;
-
- case USB_DEV_TEST_MODE_FORCE_ENABLE: // Only for downstream facing hub ports
- default:
- break;
- }
- break;
- #endif
- default:
- break;
- }
- return false;
- }
-
- /**
- * \brief Standard endpoint request to halt an endpoint
- *
- * \return true if success
- */
- #if (0!=USB_DEVICE_MAX_EP)
- static bool udc_req_std_ep_set_feature(void)
- {
- if (udd_g_ctrlreq.req.wLength) {
- return false;
- }
- if (udd_g_ctrlreq.req.wValue == USB_EP_FEATURE_HALT) {
- udd_ep_abort(udd_g_ctrlreq.req.wIndex & 0xFF);
- return udd_ep_set_halt(udd_g_ctrlreq.req.wIndex & 0xFF);
- }
- return false;
- }
- #endif
-
- /**
- * \brief Change the address of device
- * Callback called at the end of request set address
- */
- static void udc_valid_address(void)
- {
- udd_set_address(udd_g_ctrlreq.req.wValue & 0x7F);
- }
-
- /**
- * \brief Standard device request to set device address
- *
- * \return true if success
- */
- static bool udc_req_std_dev_set_address(void)
- {
- if (udd_g_ctrlreq.req.wLength) {
- return false;
- }
-
- // The address must be changed at the end of setup request after the handshake
- // then we use a callback to change address
- udd_g_ctrlreq.callback = udc_valid_address;
- return true;
- }
-
- /**
- * \brief Standard device request to get device string descriptor
- *
- * \return true if success
- */
- static bool udc_req_std_dev_get_str_desc(void)
- {
- uint8_t i;
- const uint8_t *str;
- uint8_t str_length = 0;
-
- // Link payload pointer to the string corresponding at request
- switch (udd_g_ctrlreq.req.wValue & 0xFF) {
- case 0:
- udd_set_setup_payload((uint8_t *) &udc_string_desc_languageid,
- sizeof(udc_string_desc_languageid));
- break;
-
- #ifdef USB_DEVICE_MANUFACTURE_NAME
- case 1:
- str_length = USB_DEVICE_MANUFACTURE_NAME_SIZE;
- str = udc_string_manufacturer_name;
- break;
- #endif
- #ifdef USB_DEVICE_PRODUCT_NAME
- case 2:
- str_length = USB_DEVICE_PRODUCT_NAME_SIZE;
- str = udc_string_product_name;
- break;
- #endif
- #if defined USB_DEVICE_SERIAL_NAME || defined USB_DEVICE_GET_SERIAL_NAME_POINTER
- case 3:
- str_length = USB_DEVICE_SERIAL_NAME_SIZE;
- str = udc_get_string_serial_name();
- break;
- #endif
- default:
- #ifdef UDC_GET_EXTRA_STRING
- if (UDC_GET_EXTRA_STRING()) {
- break;
- }
- #endif
- return false;
- }
-
- if (str_length) {
- for(i = 0; i < str_length; i++) {
- udc_string_desc.string[i] = cpu_to_le16((le16_t)str[i]);
- }
-
- udc_string_desc.header.bLength = 2 + (str_length) * 2;
- udd_set_setup_payload(
- (uint8_t *) &udc_string_desc,
- udc_string_desc.header.bLength);
- }
-
- return true;
- }
-
- /**
- * \brief Standard device request to get descriptors about USB device
- *
- * \return true if success
- */
- static bool udc_req_std_dev_get_descriptor(void)
- {
- uint8_t conf_num;
-
- conf_num = udd_g_ctrlreq.req.wValue & 0xFF;
-
- // Check descriptor ID
- switch ((uint8_t) (udd_g_ctrlreq.req.wValue >> 8)) {
- case USB_DT_DEVICE:
- // Device descriptor requested
- #ifdef USB_DEVICE_HS_SUPPORT
- if (!udd_is_high_speed()) {
- udd_set_setup_payload(
- (uint8_t *) udc_config.confdev_hs,
- udc_config.confdev_hs->bLength);
- } else
- #endif
- {
- udd_set_setup_payload(
- (uint8_t *) udc_config.confdev_lsfs,
- udc_config.confdev_lsfs->bLength);
- }
- break;
-
- case USB_DT_CONFIGURATION:
- // Configuration descriptor requested
- #ifdef USB_DEVICE_HS_SUPPORT
- if (udd_is_high_speed()) {
- // HS descriptor
- if (conf_num >= udc_config.confdev_hs->
- bNumConfigurations) {
- return false;
- }
- udd_set_setup_payload(
- (uint8_t *)udc_config.conf_hs[conf_num].desc,
- le16_to_cpu(udc_config.conf_hs[conf_num].desc->wTotalLength));
- } else
- #endif
- {
- // FS descriptor
- if (conf_num >= udc_config.confdev_lsfs->
- bNumConfigurations) {
- return false;
- }
- udd_set_setup_payload(
- (uint8_t *)udc_config.conf_lsfs[conf_num].desc,
- le16_to_cpu(udc_config.conf_lsfs[conf_num].desc->wTotalLength));
- }
- ((usb_conf_desc_t *) udd_g_ctrlreq.payload)->bDescriptorType =
- USB_DT_CONFIGURATION;
- break;
-
- #ifdef USB_DEVICE_HS_SUPPORT
- case USB_DT_DEVICE_QUALIFIER:
- // Device qualifier descriptor requested
- udd_set_setup_payload( (uint8_t *) udc_config.qualifier,
- udc_config.qualifier->bLength);
- break;
-
- case USB_DT_OTHER_SPEED_CONFIGURATION:
- // Other configuration descriptor requested
- if (!udd_is_high_speed()) {
- // HS descriptor
- if (conf_num >= udc_config.confdev_hs->
- bNumConfigurations) {
- return false;
- }
- udd_set_setup_payload(
- (uint8_t *)udc_config.conf_hs[conf_num].desc,
- le16_to_cpu(udc_config.conf_hs[conf_num].desc->wTotalLength));
- } else {
- // FS descriptor
- if (conf_num >= udc_config.confdev_lsfs->
- bNumConfigurations) {
- return false;
- }
- udd_set_setup_payload(
- (uint8_t *)udc_config.conf_lsfs[conf_num].desc,
- le16_to_cpu(udc_config.conf_lsfs[conf_num].desc->wTotalLength));
- }
- ((usb_conf_desc_t *) udd_g_ctrlreq.payload)->bDescriptorType =
- USB_DT_OTHER_SPEED_CONFIGURATION;
- break;
- #endif
-
- case USB_DT_BOS:
- // Device BOS descriptor requested
- if (udc_config.conf_bos == NULL) {
- return false;
- }
- udd_set_setup_payload( (uint8_t *) udc_config.conf_bos,
- udc_config.conf_bos->wTotalLength);
- break;
-
- case USB_DT_STRING:
- // String descriptor requested
- if (!udc_req_std_dev_get_str_desc()) {
- return false;
- }
- break;
-
- default:
- // Unknown descriptor requested
- return false;
- }
- // if the descriptor is larger than length requested, then reduce it
- if (udd_g_ctrlreq.req.wLength < udd_g_ctrlreq.payload_size) {
- udd_g_ctrlreq.payload_size = udd_g_ctrlreq.req.wLength;
- }
- return true;
- }
-
- /**
- * \brief Standard device request to get configuration number
- *
- * \return true if success
- */
- static bool udc_req_std_dev_get_configuration(void)
- {
- if (udd_g_ctrlreq.req.wLength != 1) {
- return false;
- }
-
- udd_set_setup_payload(&udc_num_configuration,1);
- return true;
- }
-
- /**
- * \brief Standard device request to enable a configuration
- *
- * \return true if success
- */
- static bool udc_req_std_dev_set_configuration(void)
- {
- uint8_t iface_num;
-
- // Check request length
- if (udd_g_ctrlreq.req.wLength) {
- return false;
- }
- // Authorize configuration only if the address is valid
- if (!udd_getaddress()) {
- return false;
- }
- // Check the configuration number requested
- #ifdef USB_DEVICE_HS_SUPPORT
- if (udd_is_high_speed()) {
- // HS descriptor
- if ((udd_g_ctrlreq.req.wValue & 0xFF) >
- udc_config.confdev_hs->bNumConfigurations) {
- return false;
- }
- } else
- #endif
- {
- // FS descriptor
- if ((udd_g_ctrlreq.req.wValue & 0xFF) >
- udc_config.confdev_lsfs->bNumConfigurations) {
- return false;
- }
- }
-
- // Reset current configuration
- udc_reset();
-
- // Enable new configuration
- udc_num_configuration = udd_g_ctrlreq.req.wValue & 0xFF;
- if (udc_num_configuration == 0) {
- return true; // Default empty configuration requested
- }
- // Update pointer of the configuration descriptor
- #ifdef USB_DEVICE_HS_SUPPORT
- if (udd_is_high_speed()) {
- // HS descriptor
- udc_ptr_conf = &udc_config.conf_hs[udc_num_configuration - 1];
- } else
- #endif
- {
- // FS descriptor
- udc_ptr_conf = &udc_config.conf_lsfs[udc_num_configuration - 1];
- }
- // Enable all interfaces of the selected configuration
- for (iface_num = 0; iface_num < udc_ptr_conf->desc->bNumInterfaces;
- iface_num++) {
- if (!udc_iface_enable(iface_num, 0)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * \brief Standard interface request
- * to get the alternate setting number of an interface
- *
- * \return true if success
- */
- static bool udc_req_std_iface_get_setting(void)
- {
- uint8_t iface_num;
- udi_api_t UDC_DESC_STORAGE *udi_api;
-
- if (udd_g_ctrlreq.req.wLength != 1) {
- return false; // Error in request
- }
- if (!udc_num_configuration) {
- return false; // The device is not is configured state yet
- }
-
- // Check the interface number included in the request
- iface_num = udd_g_ctrlreq.req.wIndex & 0xFF;
- if (iface_num >= udc_ptr_conf->desc->bNumInterfaces) {
- return false;
- }
-
- // Select first alternate setting of the interface to update udc_ptr_iface
- // before call iface->getsetting()
- if (!udc_update_iface_desc(iface_num, 0)) {
- return false;
- }
- // Get alternate setting from UDI
- udi_api = udc_ptr_conf->udi_apis[iface_num];
- udc_iface_setting = udi_api->getsetting();
-
- // Link value to payload pointer of request
- udd_set_setup_payload(&udc_iface_setting,1);
- return true;
- }
-
- /**
- * \brief Standard interface request
- * to set an alternate setting of an interface
- *
- * \return true if success
- */
- static bool udc_req_std_iface_set_setting(void)
- {
- uint8_t iface_num, setting_num;
-
- if (udd_g_ctrlreq.req.wLength) {
- return false; // Error in request
- }
- if (!udc_num_configuration) {
- return false; // The device is not is configured state yet
- }
-
- iface_num = udd_g_ctrlreq.req.wIndex & 0xFF;
- setting_num = udd_g_ctrlreq.req.wValue & 0xFF;
-
- // Disable current setting
- if (!udc_iface_disable(iface_num)) {
- return false;
- }
-
- // Enable new setting
- return udc_iface_enable(iface_num, setting_num);
- }
-
- /**
- * \brief Main routine to manage the standard USB SETUP request
- *
- * \return true if the request is supported
- */
- static bool udc_reqstd(void)
- {
- if (Udd_setup_is_in()) {
- // GET Standard Requests
- if (udd_g_ctrlreq.req.wLength == 0) {
- return false; // Error for USB host
- }
-
- if (USB_REQ_RECIP_DEVICE == Udd_setup_recipient()) {
- // Standard Get Device request
- switch (udd_g_ctrlreq.req.bRequest) {
- case USB_REQ_GET_STATUS:
- return udc_req_std_dev_get_status();
- case USB_REQ_GET_DESCRIPTOR:
- return udc_req_std_dev_get_descriptor();
- case USB_REQ_GET_CONFIGURATION:
- return udc_req_std_dev_get_configuration();
- default:
- break;
- }
- }
-
- if (USB_REQ_RECIP_INTERFACE == Udd_setup_recipient()) {
- // Standard Get Interface request
- switch (udd_g_ctrlreq.req.bRequest) {
- case USB_REQ_GET_INTERFACE:
- return udc_req_std_iface_get_setting();
- default:
- break;
- }
- }
- #if (0!=USB_DEVICE_MAX_EP)
- if (USB_REQ_RECIP_ENDPOINT == Udd_setup_recipient()) {
- // Standard Get Endpoint request
- switch (udd_g_ctrlreq.req.bRequest) {
- case USB_REQ_GET_STATUS:
- return udc_req_std_ep_get_status();
- default:
- break;
- }
- }
- #endif
- } else {
- // SET Standard Requests
- if (USB_REQ_RECIP_DEVICE == Udd_setup_recipient()) {
- // Standard Set Device request
- switch (udd_g_ctrlreq.req.bRequest) {
- case USB_REQ_SET_ADDRESS:
- return udc_req_std_dev_set_address();
- case USB_REQ_CLEAR_FEATURE:
- return udc_req_std_dev_clear_feature();
- case USB_REQ_SET_FEATURE:
- return udc_req_std_dev_set_feature();
- case USB_REQ_SET_CONFIGURATION:
- return udc_req_std_dev_set_configuration();
- case USB_REQ_SET_DESCRIPTOR:
- /* Not supported (defined as optional by the USB 2.0 spec) */
- break;
- default:
- break;
- }
- }
-
- if (USB_REQ_RECIP_INTERFACE == Udd_setup_recipient()) {
- // Standard Set Interface request
- switch (udd_g_ctrlreq.req.bRequest) {
- case USB_REQ_SET_INTERFACE:
- return udc_req_std_iface_set_setting();
- default:
- break;
- }
- }
- #if (0!=USB_DEVICE_MAX_EP)
- if (USB_REQ_RECIP_ENDPOINT == Udd_setup_recipient()) {
- // Standard Set Endpoint request
- switch (udd_g_ctrlreq.req.bRequest) {
- case USB_REQ_CLEAR_FEATURE:
- return udc_req_std_ep_clear_feature();
- case USB_REQ_SET_FEATURE:
- return udc_req_std_ep_set_feature();
- default:
- break;
- }
- }
- #endif
- }
- return false;
- }
-
- /**
- * \brief Send the SETUP interface request to UDI
- *
- * \return true if the request is supported
- */
- static bool udc_req_iface(void)
- {
- uint8_t iface_num;
- udi_api_t UDC_DESC_STORAGE *udi_api;
-
- if (0 == udc_num_configuration) {
- return false; // The device is not is configured state yet
- }
- // Check interface number
- iface_num = udd_g_ctrlreq.req.wIndex & 0xFF;
- if (iface_num >= udc_ptr_conf->desc->bNumInterfaces) {
- return false;
- }
-
- //* To update udc_ptr_iface with the selected interface in request
- // Select first alternate setting of interface to update udc_ptr_iface
- // before calling udi_api->getsetting()
- if (!udc_update_iface_desc(iface_num, 0)) {
- return false;
- }
- // Select the interface with the current alternate setting
- udi_api = udc_ptr_conf->udi_apis[iface_num];
- if (!udc_update_iface_desc(iface_num, udi_api->getsetting())) {
- return false;
- }
-
- // Send the SETUP request to the UDI corresponding to the interface number
- return udi_api->setup();
- }
-
- /**
- * \brief Send the SETUP interface request to UDI
- *
- * \return true if the request is supported
- */
- static bool udc_req_ep(void)
- {
- uint8_t iface_num;
- udi_api_t UDC_DESC_STORAGE *udi_api;
-
- if (0 == udc_num_configuration) {
- return false; // The device is not is configured state yet
- }
- // Send this request on all enabled interfaces
- iface_num = udd_g_ctrlreq.req.wIndex & 0xFF;
- for (iface_num = 0; iface_num < udc_ptr_conf->desc->bNumInterfaces;
- iface_num++) {
- // Select the interface with the current alternate setting
- udi_api = udc_ptr_conf->udi_apis[iface_num];
- if (!udc_update_iface_desc(iface_num, udi_api->getsetting())) {
- return false;
- }
-
- // Send the SETUP request to the UDI
- if (udi_api->setup()) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * \brief Main routine to manage the USB SETUP request.
- *
- * This function parses a USB SETUP request and submits an appropriate
- * response back to the host or, in the case of SETUP OUT requests
- * with data, sets up a buffer for receiving the data payload.
- *
- * The main standard requests defined by the USB 2.0 standard are handled
- * internally. The interface requests are sent to UDI, and the specific request
- * sent to a specific application callback.
- *
- * \return true if the request is supported, else the request is stalled by UDD
- */
- bool udc_process_setup(void)
- {
- // By default no data (receive/send) and no callbacks registered
- udd_g_ctrlreq.payload_size = 0;
- udd_g_ctrlreq.callback = NULL;
- udd_g_ctrlreq.over_under_run = NULL;
-
- if (Udd_setup_is_in()) {
- if (udd_g_ctrlreq.req.wLength == 0) {
- return false; // Error from USB host
- }
- }
-
- // If standard request then try to decode it in UDC
- if (Udd_setup_type() == USB_REQ_TYPE_STANDARD) {
- if (udc_reqstd()) {
- return true;
- }
- }
-
- // If interface request then try to decode it in UDI
- if (Udd_setup_recipient() == USB_REQ_RECIP_INTERFACE) {
- if (udc_req_iface()) {
- return true;
- }
- }
-
- // If endpoint request then try to decode it in UDI
- if (Udd_setup_recipient() == USB_REQ_RECIP_ENDPOINT) {
- if (udc_req_ep()) {
- return true;
- }
- }
-
- // Here SETUP request unknown by UDC and UDIs
- #ifdef USB_DEVICE_SPECIFIC_REQUEST
- // Try to decode it in specific callback
- return USB_DEVICE_SPECIFIC_REQUEST(); // Ex: Vendor request,...
- #else
- return false;
- #endif
- }
-
- //! @}
-
- #endif // ARDUINO_ARCH_SAM
|