/* * usbd_host.c * * Created on: Jan 19, 2013 * Author: hathach */ /* * Software License Agreement (BSD License) * Copyright (c) 2013, hathach (tinyusb.net) * 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * This file is part of the tiny usb stack. */ #include "tusb_option.h" #ifdef TUSB_CFG_HOST #define _TINY_USB_SOURCE_FILE_ //--------------------------------------------------------------------+ // INCLUDE //--------------------------------------------------------------------+ #include "common/common.h" #include "osal/osal.h" #include "usbh_hcd.h" //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ #define ENUM_QUEUE_DEPTH 5 //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ STATIC_ usbh_device_info_t usbh_device_info_pool[TUSB_CFG_HOST_DEVICE_MAX+1]; // including zero-address //------------- Enumeration Task Data -------------// OSAL_TASK_DEF(enum_task, usbh_enumeration_task, 128, OSAL_PRIO_HIGH); OSAL_QUEUE_DEF(enum_queue, ENUM_QUEUE_DEPTH, uin32_t); osal_queue_handle_t enum_queue_hdl; STATIC_ uint8_t enum_data_buffer[TUSB_CFG_HOST_ENUM_BUFFER_SIZE] TUSB_CFG_ATTR_USBRAM; //------------- Reporter Task Data -------------// //------------- Helper Function Prototypes -------------// static inline uint8_t get_new_address(void) ATTR_ALWAYS_INLINE; //--------------------------------------------------------------------+ // PUBLIC API (Parameter Verification is required) //--------------------------------------------------------------------+ tusbh_device_status_t tusbh_device_status_get (tusb_handle_device_t const device_hdl) { ASSERT(device_hdl <= TUSB_CFG_HOST_DEVICE_MAX, 0); return usbh_device_info_pool[device_hdl].status; } //--------------------------------------------------------------------+ // CLASS-USBD API (don't require to verify parameters) //--------------------------------------------------------------------+ tusb_error_t usbh_init(void) { uint32_t i; memclr_(usbh_device_info_pool, sizeof(usbh_device_info_t)*(TUSB_CFG_HOST_DEVICE_MAX+1)); for(i=0; ibMaxPacketSize0 ) ); //------------- Get full device descriptor -------------// (void) hcd_pipe_control_xfer( new_addr, &(tusb_std_request_t) { .bmRequestType = { .direction = TUSB_DIR_DEV_TO_HOST, .type = TUSB_REQUEST_TYPE_STANDARD, .recipient = TUSB_REQUEST_RECIPIENT_DEVICE }, .bRequest = TUSB_REQUEST_GET_DESCRIPTOR, .wValue = (TUSB_DESC_DEVICE << 8), .wLength = 18 }, enum_data_buffer ); osal_semaphore_wait(usbh_device_info_pool[new_addr].sem_hdl, OSAL_TIMEOUT_NORMAL, &error); // careful of local variable without static TASK_ASSERT_STATUS_HANDLER(error, tusbh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_DEVICE_NOT_RESPOND, NULL) ); usbh_device_info_pool[new_addr].vendor_id = ((tusb_descriptor_device_t*) enum_data_buffer)->idVendor; usbh_device_info_pool[new_addr].product_id = ((tusb_descriptor_device_t*) enum_data_buffer)->idProduct; usbh_device_info_pool[new_addr].configure_count = ((tusb_descriptor_device_t*) enum_data_buffer)->bNumConfigurations; //------------- update device info and invoke callback to ask user which configuration to select -------------// if (tusbh_device_attached_cb) { configure_selected = min8_of(1, tusbh_device_attached_cb( (tusb_descriptor_device_t*) enum_data_buffer) ); }else { configure_selected = 1; } //------------- Get 9 bytes of configuration descriptor -------------// (void) hcd_pipe_control_xfer( new_addr, &(tusb_std_request_t) { .bmRequestType = { .direction = TUSB_DIR_DEV_TO_HOST, .type = TUSB_REQUEST_TYPE_STANDARD, .recipient = TUSB_REQUEST_RECIPIENT_DEVICE }, .bRequest = TUSB_REQUEST_GET_DESCRIPTOR, .wValue = (TUSB_DESC_CONFIGURATION << 8) | (configure_selected - 1), .wLength = 9 }, enum_data_buffer ); osal_semaphore_wait(usbh_device_info_pool[new_addr].sem_hdl, OSAL_TIMEOUT_NORMAL, &error); // careful of local variable without static TASK_ASSERT_STATUS_HANDLER(error, tusbh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_DEVICE_NOT_RESPOND, NULL) ); TASK_ASSERT_HANDLER( TUSB_CFG_HOST_ENUM_BUFFER_SIZE > ((tusb_descriptor_configuration_t*)enum_data_buffer)->wTotalLength, tusbh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_CONFIG_DESC_TOO_LONG, NULL) ); //------------- Get full configuration descriptor -------------// (void) hcd_pipe_control_xfer( new_addr, &(tusb_std_request_t) { .bmRequestType = { .direction = TUSB_DIR_DEV_TO_HOST, .type = TUSB_REQUEST_TYPE_STANDARD, .recipient = TUSB_REQUEST_RECIPIENT_DEVICE }, .bRequest = TUSB_REQUEST_GET_DESCRIPTOR, .wValue = (TUSB_DESC_CONFIGURATION << 8) | (configure_selected - 1), .wLength = ((tusb_descriptor_configuration_t*)enum_data_buffer)->wTotalLength }, enum_data_buffer ); osal_semaphore_wait(usbh_device_info_pool[new_addr].sem_hdl, OSAL_TIMEOUT_NORMAL, &error); // careful of local variable without static TASK_ASSERT_STATUS_HANDLER(error, tusbh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_DEVICE_NOT_RESPOND, NULL) ); //------------- Set Configure -------------// (void) hcd_pipe_control_xfer( new_addr, &(tusb_std_request_t) { .bmRequestType = { .direction = TUSB_DIR_HOST_TO_DEV, .type = TUSB_REQUEST_TYPE_STANDARD, .recipient = TUSB_REQUEST_RECIPIENT_DEVICE }, .bRequest = TUSB_REQUEST_SET_CONFIGURATION, .wValue = configure_selected }, NULL ); osal_semaphore_wait(usbh_device_info_pool[new_addr].sem_hdl, OSAL_TIMEOUT_NORMAL, &error); // careful of local variable without static TASK_ASSERT_STATUS_HANDLER(error, tusbh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_DEVICE_NOT_RESPOND, NULL) ); // TODO invoke mounted callback OSAL_TASK_LOOP_END } //--------------------------------------------------------------------+ // REPORTER TASK & ITS DATA //--------------------------------------------------------------------+ #endif //--------------------------------------------------------------------+ // INTERNAL HELPER //--------------------------------------------------------------------+ static inline uint8_t get_new_address(void) { uint8_t addr; for (addr=1; addr <= TUSB_CFG_HOST_DEVICE_MAX; addr++) { if (usbh_device_info_pool[addr].status == TUSB_DEVICE_STATUS_UNPLUG) break; } return addr; }