123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834 |
- /*!
- \file usbh_std.c
- \brief USB 2.0 standard function definition
- \version 2014-12-26, V1.0.0, firmware for GD32F10x
- \version 2017-06-20, V2.0.0, firmware for GD32F10x
- \version 2018-07-31, V2.1.0, firmware for GD32F10x
- */
- /*
- Copyright (c) 2018, GigaDevice Semiconductor Inc.
- All rights reserved.
- 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. Neither the name of the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software without
- specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
- */
- #include "usbh_core.h"
- #include "usbh_usr.h"
- #include "usbh_std.h"
- #include "usbh_ctrl.h"
- uint8_t local_buffer[64U];
- uint8_t usbh_cfg_desc[512U];
- uint8_t enum_polling_handle_flag = 0U;
- static void enum_idle_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate);
- static void enum_get_full_dev_desc_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate);
- static void enum_set_addr_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate);
- static void enum_get_cfg_desc_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate);
- static void enum_get_full_cfg_desc_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate);
- static void enum_get_mfc_string_desc_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate);
- static void enum_get_product_string_desc_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate);
- static void enum_get_serialnum_string_desc_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate);
- static void enum_set_configuration_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate);
- static void enum_dev_configured_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate);
- /* the enumeration state handle function array */
- void (*enum_state_handle[]) (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate) =
- {
- enum_idle_handle,
- enum_set_addr_handle,
- enum_get_full_dev_desc_handle,
- enum_get_cfg_desc_handle,
- enum_get_full_cfg_desc_handle,
- enum_get_mfc_string_desc_handle,
- enum_get_product_string_desc_handle,
- enum_get_serialnum_string_desc_handle,
- enum_set_configuration_handle,
- enum_dev_configured_handle,
- };
- /* the enumeration state handle table */
- state_table_struct enum_handle_table[ENUM_HANDLE_TABLE_SIZE] =
- {
- /* the current state the current event the next state the event function */
- {ENUM_IDLE, ENUM_EVENT_SET_ADDR, ENUM_SET_ADDR, only_state_move },
- {ENUM_SET_ADDR, ENUN_EVENT_GET_FULL_DEV_DESC, ENUM_GET_FULL_DEV_DESC, only_state_move },
- {ENUM_GET_FULL_DEV_DESC, ENUN_EVENT_GET_CFG_DESC, ENUM_GET_CFG_DESC, only_state_move },
- {ENUM_GET_CFG_DESC, ENUN_EVENT_GET_FULL_CFG_DESC, ENUM_GET_FULL_CFG_DESC, only_state_move },
- {ENUM_GET_FULL_CFG_DESC, ENUN_EVENT_GET_MFC_STRING_DESC, ENUM_GET_MFC_STRING_DESC, only_state_move },
- {ENUM_GET_MFC_STRING_DESC, ENUN_EVENT_GET_PRODUCT_STRING_DESC, ENUM_GET_PRODUCT_STRING_DESC, only_state_move },
- {ENUM_GET_PRODUCT_STRING_DESC, ENUN_EVENT_GET_SERIALNUM_STRING_DESC, ENUM_GET_SERIALNUM_STRING_DESC, only_state_move },
- {ENUM_GET_SERIALNUM_STRING_DESC, ENUN_EVENT_SET_CONFIGURATION, ENUM_SET_CONFIGURATION, only_state_move },
- {ENUM_SET_CONFIGURATION, ENUN_EVENT_DEV_CONFIGURED, ENUM_DEV_CONFIGURED, only_state_move },
- {ENUM_DEV_CONFIGURED, GO_TO_UP_STATE_EVENT, UP_STATE, goto_up_state_fun },
- };
- /*!
- \brief the polling function of enumeration state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval usb host status
- */
- usbh_status_enum enum_state_polling_fun (usb_core_handle_struct *pudev, usbh_host_struct *puhost, void *pustate)
- {
- usbh_status_enum exe_state = USBH_BUSY;
- usbh_state_handle_struct *p_state;
- p_state = (usbh_state_handle_struct *)pustate;
- if (0U == enum_polling_handle_flag) {
- enum_polling_handle_flag = 1U;
- scd_table_push(p_state);
- scd_state_move(p_state, ENUM_IDLE);
- }
- /* start the enumeration state handle */
- scd_begin(p_state,ENUM_FSM_ID);
- if (0U == p_state->usbh_current_state_stack_top) {
- enum_state_handle[p_state->usbh_current_state](pudev, puhost, p_state);
- } else {
- enum_state_handle[p_state->stack[1].state](pudev, puhost, p_state);
- }
- /* determine the enumeration whether to complete */
- if (ENUM_DEV_CONFIGURED == puhost->usbh_backup_state.enum_backup_state) {
- puhost->usbh_backup_state.enum_backup_state = ENUM_IDLE;
- enum_polling_handle_flag = 0U;
- exe_state = USBH_OK;
- }
- return exe_state;
- }
- /*!
- \brief the handle function of ENUM_IDLE state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval none
- */
- static void enum_idle_handle (usb_core_handle_struct *pudev, usbh_host_struct *puhost, usbh_state_handle_struct *pustate)
- {
- puhost->usbh_backup_state.enum_backup_state = ENUM_IDLE;
- if (CTRL_IDLE == puhost->usbh_backup_state.ctrl_backup_state) {
- usbh_enum_desc_get(pudev,
- puhost,
- pudev->host.rx_buffer,
- USB_REQTYPE_DEVICE | USB_STANDARD_REQ,
- USB_DEVDESC,
- 8U);
- if ((void *)0 != pudev->mdelay) {
- pudev->mdelay(100U);
- }
- }
- if (USBH_OK == ctrl_state_polling_fun(pudev, puhost, pustate)) {
- usbh_device_desc_parse(&puhost->device.dev_desc, pudev->host.rx_buffer, 8U);
- puhost->control.ep0_size = puhost->device.dev_desc.bMaxPacketSize0;
- /* issue reset */
- usb_port_reset(pudev);
- /* modify control channels configuration for maxpacket size */
- usbh_channel_modify (pudev,
- puhost->control.hc_out_num,
- 0U,
- 0U,
- 0U,
- (uint16_t)puhost->control.ep0_size);
- usbh_channel_modify (pudev,
- puhost->control.hc_in_num,
- 0U,
- 0U,
- 0U,
- (uint16_t)puhost->control.ep0_size);
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUM_EVENT_SET_ADDR,
- pustate->usbh_current_state);
- }
- }
- /*!
- \brief the handle function of ENUM_GET_FULL_DEV_DESC state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval none
- */
- static void enum_get_full_dev_desc_handle (usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- usbh_state_handle_struct *pustate)
- {
- puhost->usbh_backup_state.enum_backup_state = ENUM_GET_FULL_DEV_DESC;
- if (CTRL_IDLE == puhost->usbh_backup_state.ctrl_backup_state) {
- usbh_enum_desc_get(pudev,
- puhost,
- pudev->host.rx_buffer,
- USB_REQTYPE_DEVICE | USB_STANDARD_REQ,
- USB_DEVDESC,
- USB_DEVDESC_SIZE);
- }
- if(USBH_OK == ctrl_state_polling_fun(pudev, puhost, pustate)){
- usbh_device_desc_parse(&puhost->device.dev_desc, pudev->host.rx_buffer, USB_DEVDESC_SIZE);
- puhost->usr_cb->device_desc_available(&puhost->device.dev_desc);
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUN_EVENT_GET_CFG_DESC,
- pustate->usbh_current_state);
- }
- }
- /*!
- \brief the handle function of ENUM_SET_ADDR state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval none
- */
- static void enum_set_addr_handle (usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- usbh_state_handle_struct *pustate)
- {
- puhost->usbh_backup_state.enum_backup_state = ENUM_SET_ADDR;
- if (CTRL_IDLE == puhost->usbh_backup_state.ctrl_backup_state) {
- usbh_enum_addr_set(pudev, puhost,USBH_DEVICE_ADDRESS);
- if ((void *)0 != pudev->mdelay) {
- pudev->mdelay(100U);
- }
- }
- if (USBH_OK == ctrl_state_polling_fun(pudev, puhost, pustate)) {
- if ((void *)0 != pudev->mdelay) {
- pudev->mdelay(2U);
- }
- puhost->device.address = USBH_DEVICE_ADDRESS;
- /* user callback for device address assigned */
- puhost->usr_cb->device_address_set();
- /* modify control channels to update device address */
- usbh_channel_modify (pudev,
- puhost->control.hc_in_num,
- puhost->device.address,
- 0U,
- 0U,
- 0U);
- usbh_channel_modify (pudev,
- puhost->control.hc_out_num,
- puhost->device.address,
- 0U,
- 0U,
- 0U);
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUN_EVENT_GET_FULL_DEV_DESC,
- pustate->usbh_current_state);
- }
- }
- /*!
- \brief the handle function of ENUM_GET_CFG_DESC state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval none
- */
- static void enum_get_cfg_desc_handle (usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- usbh_state_handle_struct *pustate)
- {
- uint16_t index = 0U;
- puhost->usbh_backup_state.enum_backup_state = ENUM_GET_CFG_DESC;
- if (CTRL_IDLE == puhost->usbh_backup_state.ctrl_backup_state) {
- usbh_enum_desc_get(pudev,
- puhost,
- pudev->host.rx_buffer,
- USB_REQTYPE_DEVICE | USB_STANDARD_REQ,
- USB_CFGDESC,
- USB_CFGDESC_SIZE);
- }
- if (USBH_OK == ctrl_state_polling_fun(pudev, puhost, pustate)) {
- /* save configuration descriptor for class parsing usage */
- for (; index < USB_CFGDESC_SIZE; index ++) {
- usbh_cfg_desc[index] = pudev->host.rx_buffer[index];
- }
- /* commands successfully sent and response received */
- usbh_cfg_desc_parse (&puhost->device.cfg_desc,
- puhost->device.itf_desc,
- puhost->device.ep_desc,
- pudev->host.rx_buffer,
- USB_CFGDESC_SIZE);
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUN_EVENT_GET_FULL_CFG_DESC,
- pustate->usbh_current_state);
- }
- }
- /*!
- \brief the handle function of ENUM_GET_FULL_CFG_DESC state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval none
- */
- static void enum_get_full_cfg_desc_handle (usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- usbh_state_handle_struct *pustate)
- {
- uint16_t index = 0U;
- puhost->usbh_backup_state.enum_backup_state = ENUM_GET_FULL_CFG_DESC;
- if (CTRL_IDLE == puhost->usbh_backup_state.ctrl_backup_state) {
- usbh_enum_desc_get (pudev, puhost, pudev->host.rx_buffer,
- USB_REQTYPE_DEVICE | USB_STANDARD_REQ,
- USB_CFGDESC, puhost->device.cfg_desc.wTotalLength);
- }
- if (USBH_OK == ctrl_state_polling_fun(pudev, puhost, pustate)) {
- /* save configuration descriptor for class parsing usage */
- for (; index < puhost->device.cfg_desc.wTotalLength; index ++) {
- usbh_cfg_desc[index] = pudev->host.rx_buffer[index];
- }
- /* commands successfully sent and response received */
- usbh_cfg_desc_parse (&puhost->device.cfg_desc,
- puhost->device.itf_desc,
- puhost->device.ep_desc,
- pudev->host.rx_buffer,
- puhost->device.cfg_desc.wTotalLength);
- /* User callback for configuration descriptors available */
- puhost->usr_cb->configuration_desc_available(&puhost->device.cfg_desc,
- puhost->device.itf_desc,
- puhost->device.ep_desc[0]);
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUN_EVENT_GET_MFC_STRING_DESC,
- pustate->usbh_current_state);
- }
- }
- /*!
- \brief the handle function of ENUM_GET_MFC_STRING_DESC state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval none
- */
- static void enum_get_mfc_string_desc_handle (usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- usbh_state_handle_struct *pustate)
- {
- puhost->usbh_backup_state.enum_backup_state = ENUM_GET_MFC_STRING_DESC;
- if (0U != puhost->device.dev_desc.iManufacturer) {
- if(CTRL_IDLE == puhost->usbh_backup_state.ctrl_backup_state) {
- usbh_enum_desc_get(pudev,
- puhost,
- pudev->host.rx_buffer,
- USB_REQTYPE_DEVICE | USB_STANDARD_REQ,
- USB_STRDESC | puhost->device.dev_desc.iManufacturer,
- 0xffU);
- }
- if (USBH_OK == ctrl_state_polling_fun(pudev, puhost, pustate)) {
- usbh_string_desc_parse(pudev->host.rx_buffer, local_buffer, 0xffU);
- puhost->usr_cb->manufacturer_string(local_buffer);
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUN_EVENT_GET_PRODUCT_STRING_DESC,
- pustate->usbh_current_state);
- }
- } else {
- puhost->usr_cb->manufacturer_string("N/A");
- scd_state_move((usbh_state_handle_struct *)pustate, ENUM_GET_PRODUCT_STRING_DESC);
- }
- }
- /*!
- \brief the handle function of ENUM_GET_PRODUCT_STRING_DESC state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval none
- */
- static void enum_get_product_string_desc_handle (usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- usbh_state_handle_struct *pustate)
- {
- puhost->usbh_backup_state.enum_backup_state = ENUM_GET_PRODUCT_STRING_DESC;
- if (0U != puhost->device.dev_desc.iProduct) {
- if (CTRL_IDLE == puhost->usbh_backup_state.ctrl_backup_state) {
- usbh_enum_desc_get(pudev,
- puhost,
- pudev->host.rx_buffer,
- USB_REQTYPE_DEVICE | USB_STANDARD_REQ,
- USB_STRDESC | puhost->device.dev_desc.iProduct,
- 0xffU);
- }
- if (USBH_OK == ctrl_state_polling_fun(pudev, puhost, pustate)) {
- usbh_string_desc_parse(pudev->host.rx_buffer, local_buffer, 0xffU);
- /* user callback for product string */
- puhost->usr_cb->product_string(local_buffer);
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUN_EVENT_GET_SERIALNUM_STRING_DESC,
- pustate->usbh_current_state);
- }
- } else {
- puhost->usr_cb->product_string("N/A");
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUN_EVENT_GET_SERIALNUM_STRING_DESC,
- pustate->usbh_current_state);
- }
- }
- /*!
- \brief the handle function of ENUM_GET_SERIALNUM_STRING_DESC state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval none
- */
- static void enum_get_serialnum_string_desc_handle (usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- usbh_state_handle_struct *pustate)
- {
- puhost->usbh_backup_state.enum_backup_state = ENUM_GET_SERIALNUM_STRING_DESC;
- if (0U != puhost->device.dev_desc.iSerialNumber) {
- if (CTRL_IDLE == puhost->usbh_backup_state.ctrl_backup_state) {
- usbh_enum_desc_get(pudev,
- puhost,
- pudev->host.rx_buffer,
- USB_REQTYPE_DEVICE | USB_STANDARD_REQ,
- USB_STRDESC | puhost->device.dev_desc.iSerialNumber,
- 0xffU);
- }
- if (USBH_OK == ctrl_state_polling_fun(pudev, puhost, pustate)){
- usbh_string_desc_parse(pudev->host.rx_buffer, local_buffer, 0xffU);
- /* user callback for product string */
- puhost->usr_cb->serial_num_string(local_buffer);
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUN_EVENT_SET_CONFIGURATION,
- pustate->usbh_current_state);
- }
- } else {
- puhost->usr_cb->serial_num_string("N/A");
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUN_EVENT_SET_CONFIGURATION,
- pustate->usbh_current_state);
- }
- }
- /*!
- \brief the handle function of ENUM_SET_CONFIGURATION state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval none
- */
- static void enum_set_configuration_handle (usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- usbh_state_handle_struct *pustate)
- {
- puhost->usbh_backup_state.enum_backup_state = ENUM_SET_CONFIGURATION;
- if (CTRL_IDLE == puhost->usbh_backup_state.ctrl_backup_state ) {
- usbh_enum_cfg_set(pudev, puhost, (uint16_t)puhost->device.cfg_desc.bConfigurationValue);
- }
- if (USBH_OK == ctrl_state_polling_fun(pudev, puhost, pustate)) {
- scd_event_handle(pudev,
- puhost,
- pustate,
- ENUN_EVENT_DEV_CONFIGURED,
- pustate->usbh_current_state);
- }
- }
- /*!
- \brief the handle function of ENUM_DEV_CONFIGURED state
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] pustate: pointer to USB state driver
- \param[out] none
- \retval none
- */
- static void enum_dev_configured_handle (usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- usbh_state_handle_struct *pustate)
- {
- puhost->usbh_backup_state.enum_backup_state = ENUM_DEV_CONFIGURED;
- scd_event_handle(pudev, puhost, pustate, GO_TO_UP_STATE_EVENT, pustate->usbh_current_state);
- }
- /*!
- \brief get descriptor in usb host enumeration stage
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] buf: buffer to store the descriptor
- \param[in] ReqType: descriptor type
- \param[in] ValueIdx: wValue for the GetDescriptr request
- \param[in] Len: length of the descriptor
- \param[out] none
- \retval none
- */
- void usbh_enum_desc_get(usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- uint8_t *buf,
- uint8_t req_type,
- uint16_t value_idx,
- uint16_t len)
- {
- usb_setup_union *pSetup = &(puhost->control.setup);
- pSetup->b.bmRequestType = USB_DIR_IN | req_type;
- pSetup->b.bRequest = USBREQ_GET_DESCRIPTOR;
- pSetup->b.wValue = value_idx;
- if (USB_STRDESC == (value_idx & 0xff00U)){
- pSetup->b.wIndex = 0x0409U;
- } else {
- pSetup->b.wIndex = 0U;
- }
- pSetup->b.wLength = len;
- puhost->control.buff = buf;
- puhost->control.length = len;
- }
- /*!
- \brief set address in usb host enumeration stage
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] device_address: the device address
- \param[out] none
- \retval none
- */
- void usbh_enum_addr_set(usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- uint8_t device_address)
- {
- usb_setup_union *p_setup = &(puhost->control.setup);
- p_setup->b.bmRequestType = USB_DIR_OUT | USB_REQTYPE_DEVICE | USB_STANDARD_REQ;
- p_setup->b.bRequest = USBREQ_SET_ADDRESS;
- p_setup->b.wValue = (uint16_t)device_address;
- p_setup->b.wIndex = 0U;
- p_setup->b.wLength = 0U;
- puhost->control.buff = 0U;
- puhost->control.length = 0U;
- }
- /*!
- \brief set configuration in usb host enumeration stage
- \param[in] pudev: pointer to USB device
- \param[in] puhost: pointer to USB host
- \param[in] cfg_idx: the index of the configuration
- \param[out] none
- \retval none
- */
- void usbh_enum_cfg_set(usb_core_handle_struct *pudev,
- usbh_host_struct *puhost,
- uint16_t cfg_idx)
- {
- usb_setup_union *p_setup = &(puhost->control.setup);
- p_setup->b.bmRequestType = USB_DIR_OUT | USB_REQTYPE_DEVICE | USB_STANDARD_REQ;
- p_setup->b.bRequest = USBREQ_SET_CONFIGURATION;
- p_setup->b.wValue = cfg_idx;
- p_setup->b.wIndex = 0U;
- p_setup->b.wLength = 0U;
- puhost->control.buff = 0;
- puhost->control.length = 0U;
- }
- /*!
- \brief parse the device descriptor
- \param[in] dev_desc: device_descriptor destinaton address
- \param[in] buf: buffer where the source descriptor is available
- \param[in] len: length of the descriptor
- \param[out] none
- \retval none
- */
- void usbh_device_desc_parse (usb_descriptor_device_struct *dev_desc, uint8_t *buf, uint16_t len)
- {
- dev_desc->Header.bLength = *(uint8_t *)(buf + 0U);
- dev_desc->Header.bDescriptorType = *(uint8_t *)(buf + 1U);
- dev_desc->bcdUSB = SWAPBYTE(buf + 2U);
- dev_desc->bDeviceClass = *(uint8_t *)(buf + 4U);
- dev_desc->bDeviceSubClass = *(uint8_t *)(buf + 5U);
- dev_desc->bDeviceProtocol = *(uint8_t *)(buf + 6U);
- dev_desc->bMaxPacketSize0 = *(uint8_t *)(buf + 7U);
- if (len > 8U){
- /* for 1st time after device connection, host may issue only 8 bytes for device descriptor length */
- dev_desc->idVendor = SWAPBYTE(buf + 8U);
- dev_desc->idProduct = SWAPBYTE(buf + 10U);
- dev_desc->bcdDevice = SWAPBYTE(buf + 12U);
- dev_desc->iManufacturer = *(uint8_t *)(buf + 14U);
- dev_desc->iProduct = *(uint8_t *)(buf + 15U);
- dev_desc->iSerialNumber = *(uint8_t *)(buf + 16U);
- dev_desc->bNumberConfigurations = *(uint8_t *)(buf + 17U);
- }
- }
- /*!
- \brief parse the configuration descriptor
- \param[in] cfg_desc: configuration descriptor address
- \param[in] itf_desc: interface descriptor address
- \param[in] ep_desc: endpoint descriptor address
- \param[in] buf: buffer where the source descriptor is available
- \param[in] len: length of the descriptor
- \param[out] none
- \retval none
- */
- void usbh_cfg_desc_parse (usb_descriptor_configuration_struct *cfg_desc,
- usb_descriptor_interface_struct *itf_desc,
- usb_descriptor_endpoint_struct ep_desc[][USBH_MAX_EP_NUM],
- uint8_t *buf,
- uint16_t len)
- {
- usb_descriptor_interface_struct *pitf = NULL;
- usb_descriptor_interface_struct temp_pitf;
- usb_descriptor_endpoint_struct *pep = NULL;
- usb_descriptor_header_struct *pdesc = (usb_descriptor_header_struct *)buf;
- uint8_t itf_ix = 0U;
- uint8_t ep_ix = 0U;
- uint16_t ptr = 0U;
- static uint8_t prev_itf = 0U;
- static uint16_t prev_ep_size = 0U;
- /* parse configuration descriptor */
- cfg_desc->Header.bLength = *(uint8_t *)(buf + 0U);
- cfg_desc->Header.bDescriptorType = *(uint8_t *)(buf + 1U);
- cfg_desc->wTotalLength = SWAPBYTE(buf + 2U);
- cfg_desc->bNumInterfaces = *(uint8_t *)(buf + 4U);
- cfg_desc->bConfigurationValue = *(uint8_t *)(buf + 5U);
- cfg_desc->iConfiguration = *(uint8_t *)(buf + 6U);
- cfg_desc->bmAttributes = *(uint8_t *)(buf + 7U);
- cfg_desc->bMaxPower = *(uint8_t *)(buf + 8U);
- if (len > USB_CFGDESC_SIZE) {
- ptr = USB_CFG_DESC_LEN;
- if (cfg_desc->bNumInterfaces <= USBH_MAX_INTERFACES_NUM) {
- pitf = (usb_descriptor_interface_struct *)0U;
- for (; ptr < cfg_desc->wTotalLength; ) {
- pdesc = usbh_next_desc_get((uint8_t *)pdesc, &ptr);
- if (USB_DESCTYPE_INTERFACE == pdesc->bDescriptorType) {
- itf_ix = *((uint8_t *)pdesc + 2U);
- pitf = &itf_desc[itf_ix];
- if (*((uint8_t *)pdesc + 3U) < 3U) {
- usbh_interface_desc_parse (&temp_pitf, (uint8_t *)pdesc);
- /* parse endpoint descriptors relative to the current interface */
- if (temp_pitf.bNumEndpoints <= USBH_MAX_EP_NUM) {
- for (ep_ix = 0U; ep_ix < temp_pitf.bNumEndpoints;) {
- pdesc = usbh_next_desc_get((void* )pdesc, &ptr);
- if (USB_DESCTYPE_ENDPOINT == pdesc->bDescriptorType) {
- pep = &ep_desc[itf_ix][ep_ix];
- if (prev_itf != itf_ix) {
- prev_itf = itf_ix;
- usbh_interface_desc_parse (pitf, (uint8_t *)&temp_pitf);
- } else {
- if (prev_ep_size > SWAPBYTE((uint8_t *)pdesc + 4)) {
- break;
- } else {
- usbh_interface_desc_parse (pitf, (uint8_t *)&temp_pitf);
- }
- }
- usbh_endpoint_desc_parse (pep, (uint8_t *)pdesc);
- prev_ep_size = SWAPBYTE((uint8_t *)pdesc + 4);
- ep_ix++;
- }
- }
- }
- }
- }
- }
- }
- prev_ep_size = 0U;
- prev_itf = 0U;
- }
- }
- /*!
- \brief parse the interface descriptor
- \param[in] itf_desc: interface descriptor destination
- \param[in] buf: buffer where the descriptor data is available
- \param[out] none
- \retval none
- */
- void usbh_interface_desc_parse (usb_descriptor_interface_struct *itf_desc, uint8_t *buf)
- {
- itf_desc->Header.bLength = *(uint8_t *)(buf + 0U);
- itf_desc->Header.bDescriptorType = *(uint8_t *)(buf + 1U);
- itf_desc->bInterfaceNumber = *(uint8_t *)(buf + 2U);
- itf_desc->bAlternateSetting = *(uint8_t *)(buf + 3U);
- itf_desc->bNumEndpoints = *(uint8_t *)(buf + 4U);
- itf_desc->bInterfaceClass = *(uint8_t *)(buf + 5U);
- itf_desc->bInterfaceSubClass = *(uint8_t *)(buf + 6U);
- itf_desc->bInterfaceProtocol = *(uint8_t *)(buf + 7U);
- itf_desc->iInterface = *(uint8_t *)(buf + 8U);
- }
- /*!
- \brief parse the endpoint descriptor
- \param[in] ep_desc: endpoint descriptor destination address
- \param[in] buf: buffer where the parsed descriptor stored
- \param[out] none
- \retval none
- */
- void usbh_endpoint_desc_parse (usb_descriptor_endpoint_struct *ep_desc, uint8_t *buf)
- {
- ep_desc->Header.bLength = *(uint8_t *)(buf + 0U);
- ep_desc->Header.bDescriptorType = *(uint8_t *)(buf + 1U);
- ep_desc->bEndpointAddress = *(uint8_t *)(buf + 2U);
- ep_desc->bmAttributes = *(uint8_t *)(buf + 3U);
- ep_desc->wMaxPacketSize = SWAPBYTE(buf + 4U);
- ep_desc->bInterval = *(uint8_t *)(buf + 6U);
- }
- /*!
- \brief parse the string descriptor
- \param[in] psrc: source pointer containing the descriptor data
- \param[in] pdest: destination address pointer
- \param[in] len: length of the descriptor
- \param[out] none
- \retval none
- */
- void usbh_string_desc_parse (uint8_t* psrc, uint8_t* pdest, uint16_t len)
- {
- uint16_t strlength;
- uint16_t idx;
- /* the unicode string descriptor is not null-terminated. the string length is
- computed by substracting two from the value of the first byte of the descriptor.
- */
- /* check which is lower size, the size of string or the length of bytes read from the device */
- if (USB_DESCTYPE_STRING == psrc[1]){
- /* make sure the descriptor is string type */
- /* psrc[0] contains size of descriptor, subtract 2 to get the length of string */
- strlength = ((((uint16_t)psrc[0] - 2U) <= len) ? ((uint16_t)psrc[0] - 2U) : len);
- psrc += 2; /* adjust the offset ignoring the string len and descriptor type */
- for (idx = 0U; idx < strlength; idx += 2U) {
- /* copy only the string and ignore the unicode id, hence add the src */
- *pdest = psrc[idx];
- pdest++;
- }
- *pdest = 0U; /* mark end of string */
- }
- }
- /*!
- \brief get the next descriptor header
- \param[in] pbuf: pointer to buffer where the cfg descriptor is available
- \param[in] ptr: data popinter inside the configuration descriptor
- \param[out] none
- \retval next descriptor header
- */
- usb_descriptor_header_struct *usbh_next_desc_get (uint8_t *pbuf, uint16_t *ptr)
- {
- uint8_t len = ((usb_descriptor_header_struct *)pbuf)->bLength;
- usb_descriptor_header_struct *pnext;
- *ptr += len;
- pnext = (usb_descriptor_header_struct *)((uint8_t *)pbuf + len);
- return(pnext);
- }
|