From b71ffe3d5a7b97010b7ac2096271e03dcb35c2dd Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 24 Oct 2013 15:32:54 +0700 Subject: change TUSB_CFG_CONTROLLER0/1_MODE to TUSB_CFG_CONTROLLER_0/1_MODE for clearance adding configuration docs for tinyusb_config.h document HID mouse & keyboard API --- tinyusb/class/cdc.h | 686 ++++++------ tinyusb/class/hid.h | 1010 +++++++++--------- tinyusb/class/hid_host.c | 608 +++++------ tinyusb/class/hid_host.h | 332 +++--- tinyusb/doxygen/configuration.h | 39 + tinyusb/doxygen/overview.md | 3 - tinyusb/hal/hal_lpc43xx.c | 246 ++--- tinyusb/host/ehci/ehci.c | 2196 +++++++++++++++++++-------------------- tinyusb/mcu_capacity.h | 196 ++-- tinyusb/osal/osal.h | 413 ++++---- tinyusb/tusb_option.h | 387 +++---- 11 files changed, 3127 insertions(+), 2989 deletions(-) create mode 100644 tinyusb/doxygen/configuration.h delete mode 100644 tinyusb/doxygen/overview.md (limited to 'tinyusb') diff --git a/tinyusb/class/cdc.h b/tinyusb/class/cdc.h index faa6310fa..7bbeb714f 100644 --- a/tinyusb/class/cdc.h +++ b/tinyusb/class/cdc.h @@ -1,343 +1,343 @@ -/**************************************************************************/ -/*! - @file cdc.h - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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 holders 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 ''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 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 tinyusb stack. -*/ -/**************************************************************************/ - -/** \file - * \brief CDC Class Driver - * - * \note TBD - */ - -/** - * \addtogroup Group_ClassDriver Class Driver - * @{ - * \defgroup Group_CDC Communication Device Class - * @{ - */ - -#ifndef _TUSB_CDC_H__ -#define _TUSB_CDC_H__ - -#include "common/common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// CDC COMMUNICATION INTERFACE CLASS -//--------------------------------------------------------------------+ -enum { - CDC_COMM_SUBCLASS_DIRECT_LINE_CONTROL_MODEL = 0x01 , - CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL , - CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL , - CDC_COMM_SUBCLASS_MULTICHANNEL_CONTROL_MODEL , - CDC_COMM_SUBCLASS_CAPI_CONTROL_MODEL , - CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL , - CDC_COMM_SUBCLASS_ATM_NETWORKING_CONTROL_MODEL , - CDC_COMM_SUBCLASS_WIRELESS_HANDSET_CONTROL_MODEL , - CDC_COMM_SUBCLASS_DEVICE_MANAGEMENT , - CDC_COMM_SUBCLASS_MOBILE_DIRECT_LINE_MODEL , - CDC_COMM_SUBCLASS_OBEX , - CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL -}; - -enum { - CDC_COMM_PROTOCOL_ATCOMMAND = 0x01 , // ITU-T V2.50 - CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101 , - CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO , - CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707 , - CDC_COMM_PROTOCOL_ATCOMMAND_3GPP_27007 , - CDC_COMM_PROTOCOL_ATCOMMAND_CDMA , // defined by TIA - CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL -}; - -//------------- SubType Descriptor in COMM Functional Descriptor -------------// -enum { - CDC_FUNC_DESC_HEADER = 0x00 , - CDC_FUNC_DESC_CALL_MANAGEMENT = 0x01 , - CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT = 0x02 , - CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT = 0x03 , - CDC_FUNC_DESC_TELEPHONE_RINGER = 0x04 , - CDC_FUNC_DESC_TELEPHONE_CALL_AND_LINE_STATE_REPORTING_CAPACITY = 0x05 , - CDC_FUNC_DESC_UNION = 0x06 , - CDC_FUNC_DESC_COUNTRY_SELECTION = 0x07 , - CDC_FUNC_DESC_TELEPHONE_OPERATIONAL_MODES = 0x08 , - CDC_FUNC_DESC_USB_TERMINAL = 0x09 , - CDC_FUNC_DESC_NETWORK_CHANNEL_TERMINAL = 0x0A , - CDC_FUNC_DESC_PROTOCOL_UNIT = 0x0B , - CDC_FUNC_DESC_EXTENSION_UNIT = 0x0C , - CDC_FUNC_DESC_MULTICHANEL_MANAGEMENT = 0x0D , - CDC_FUNC_DESC_CAPI_CONTROL_MANAGEMENT = 0x0E , - CDC_FUNC_DESC_ETHERNET_NETWORKING = 0x0F , - CDC_FUNC_DESC_ATM_NETWORKING = 0x10 , - CDC_FUNC_DESC_WIRELESS_HANDSET_CONTROL_MODEL = 0x11 , - CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL = 0x12 , - CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL_DETAIL = 0x13 , - CDC_FUNC_DESC_DEVICE_MANAGEMENT_MODEL = 0x14 , - CDC_FUNC_DESC_OBEX = 0x15 , - CDC_FUNC_DESC_COMMAND_SET = 0x16 , - CDC_FUNC_DESC_COMMAND_SET_DETAIL = 0x17 , - CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL = 0x18 , - CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER = 0x19 -}; - -//--------------------------------------------------------------------+ -// CDC DATA INTERFACE CLASS -//--------------------------------------------------------------------+ - -// SUBCLASS code of Data Interface is not used and should/must be zero - -enum{ - CDC_DATA_PROTOCOL_ISDN_BRI = 0x30, - CDC_DATA_PROTOCOL_HDLC = 0x31, - CDC_DATA_PROTOCOL_TRANSPARENT = 0x32, - CDC_DATA_PROTOCOL_Q921_MANAGEMENT = 0x50, - CDC_DATA_PROTOCOL_Q921_DATA_LINK = 0x51, - CDC_DATA_PROTOCOL_Q921_TEI_MULTIPLEXOR = 0x52, - CDC_DATA_PROTOCOL_V42BIS_DATA_COMPRESSION = 0x90, - CDC_DATA_PROTOCOL_EURO_ISDN = 0x91, - CDC_DATA_PROTOCOL_V24_RATE_ADAPTION_TO_ISDN = 0x92, - CDC_DATA_PROTOCOL_CAPI_COMMAND = 0x93, - CDC_DATA_PROTOCOL_HOST_BASED_DRIVER = 0xFD, - CDC_DATA_PROTOCOL_IN_PROTOCOL_UNIT_FUNCTIONAL_DESCRIPTOR = 0xFE -}; - -//--------------------------------------------------------------------+ -// MANAGEMENT ELEMENT REQUEST (CONTROL ENDPOINT) -//--------------------------------------------------------------------+ -typedef enum { - SEND_ENCAPSULATED_COMMAND = 0x00, - GET_ENCAPSULATED_RESPONSE = 0x01, - - SET_COMM_FEATURE = 0x02, - GET_COMM_FEATURE = 0x03, - CLEAR_COMM_FEATURE = 0x04, - - SET_AUX_LINE_STATE = 0x10, - SET_HOOK_STATE = 0x11, - PULSE_SETUP = 0x12, - SEND_PULSE = 0x13, - SET_PULSE_TIME = 0x14, - RING_AUX_JACK = 0x15, - - SET_LINE_CODING = 0x20, - GET_LINE_CODING = 0x21, - SET_CONTROL_LINE_STATE = 0x22, - SEND_BREAK = 0x23, - - SET_RINGER_PARMS = 0x30, - GET_RINGER_PARMS = 0x31, - SET_OPERATION_PARMS = 0x32, - GET_OPERATION_PARMS = 0x33, - SET_LINE_PARMS = 0x34, - GET_LINE_PARMS = 0x35, - DIAL_DIGITS = 0x36, - SET_UNIT_PARAMETER = 0x37, - GET_UNIT_PARAMETER = 0x38, - CLEAR_UNIT_PARAMETER = 0x39, - GET_PROFILE = 0x3A, - - SET_ETHERNET_MULTICAST_FILTERS = 0x40, - SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, - GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, - SET_ETHERNET_PACKET_FILTER = 0x43, - GET_ETHERNET_STATISTIC = 0x44, - - SET_ATM_DATA_FORMAT = 0x50, - GET_ATM_DEVICE_STATISTICS = 0x51, - SET_ATM_DEFAULT_VC = 0x52, - GET_ATM_VC_STATISTICS = 0x53, - - MDLM_SEMANTIC_MODEL = 0x60, -}cdc_management_request_t; - -//--------------------------------------------------------------------+ -// MANAGEMENT ELEMENENT NOTIFICATION (NOTIFICATION ENDPOINT) -//--------------------------------------------------------------------+ -typedef enum { - NETWORK_CONNECTION = 0x00, - RESPONSE_AVAILABLE = 0x01, - - AUX_JACK_HOOK_STATE = 0x08, - RING_DETECT = 0x09, - - SERIAL_STATE = 0x20, - - CALL_STATE_CHANGE = 0x28, - LINE_STATE_CHANGE = 0x29, - CONNECTION_SPEED_CHANGE = 0x2A, - MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, -}cdc_notification_request_t; - -//--------------------------------------------------------------------+ -// FUNCTIONAL DESCRIPTOR -//--------------------------------------------------------------------+ -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - uint16_t bcdCDC ; ///< CDC release number in Binary-Coded Decimal -}cdc_desc_func_header_t; - -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - uint8_t bControlInterface ; ///< Interface number of Communication Interface - uint8_t bSubordinateInterface ; ///< Array of Interface number of Data Interface -}cdc_desc_func_union_t; - -#define cdc_desc_func_union_n_t(no_slave)\ - ATTR_PACKED_STRUCT(struct) { \ - uint8_t bLength ;\ - uint8_t bDescriptorType ;\ - uint8_t bDescriptorSubType ;\ - uint8_t bControlInterface ;\ - uint8_t bSubordinateInterface[no_slave] ;\ -} - -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - uint8_t iCountryCodeRelDate ; ///< Index of a string giving the release date for the implemented ISO 3166 Country Codes. - uint16_t wCountryCode[] ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country. -}cdc_desc_func_country_selection_t; - -#define cdc_desc_func_country_selection_n_t(no_country) \ - ATTR_PACKED_STRUCT(struct) {\ - uint8_t bLength ;\ - uint8_t bDescriptorType ;\ - uint8_t bDescriptorSubType ;\ - uint8_t iCountryCodeRelDate ;\ - uint16_t wCountryCode[no_country] ;\ -} - -//--------------------------------------------------------------------+ -// PUBLIC SWITCHED TELEPHONE NETWORK (PSTN) SUBCLASS -//--------------------------------------------------------------------+ -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - - struct { - uint8_t handle_call : 1; ///< 0 - Device sends/receives call management information only over the Communications Class interface. 1 - Device can send/receive call management information over a Data Class interface. - uint8_t send_recv_call : 1; ///< 0 - Device does not handle call management itself. 1 - Device handles call management itself. - uint8_t : 0; - } bmCapabilities; - - uint8_t bDataInterface; -}cdc_desc_func_call_management_t; - -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t support_comm_request : 1; ///< Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature. - uint8_t support_line_request : 1; ///< Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State. - uint8_t support_send_break : 1; ///< Device supports the request Send_Break - uint8_t support_notification_network_connection : 1; ///< Device supports the notification Network_Connection. - uint8_t : 0; -}cdc_acm_capability_t; - -STATIC_ASSERT(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compiler"); - -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - cdc_acm_capability_t bmCapabilities ; -}cdc_desc_func_abstract_control_management_t; - -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - struct { - uint8_t require_pulse_setup : 1; ///< Device requires extra Pulse_Setup request during pulse dialing sequence to disengage holding circuit. - uint8_t support_aux_request : 1; ///< Device supports the request combination of Set_Aux_Line_State, Ring_Aux_Jack, and notification Aux_Jack_Hook_State. - uint8_t support_pulse_request : 1; ///< Device supports the request combination of Pulse_Setup, Send_Pulse, and Set_Pulse_Time. - uint8_t : 0; - } bmCapabilities; -}cdc_desc_func_direct_line_management_t; - -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - uint8_t bRingerVolSteps ; - uint8_t bNumRingerPatterns ; -}cdc_desc_func_telephone_ringer_t; - -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - struct { - uint8_t simple_mode : 1; - uint8_t standalone_mode : 1; - uint8_t computer_centric_mode : 1; - uint8_t : 0; - } bmCapabilities; -}cdc_desc_func_telephone_operational_modes_t; - -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ - struct { - uint32_t interrupted_dialtone : 1; ///< 0 : Reports only dialtone (does not differentiate between normal and interrupted dialtone). 1 : Reports interrupted dialtone in addition to normal dialtone - uint32_t ringback_busy_fastbusy : 1; ///< 0 : Reports only dialing state. 1 : Reports ringback, busy, and fast busy states. - uint32_t caller_id : 1; ///< 0 : Does not report caller ID. 1 : Reports caller ID information. - uint32_t incoming_distinctive : 1; ///< 0 : Reports only incoming ringing. 1 : Reports incoming distinctive ringing patterns. - uint32_t dual_tone_multi_freq : 1; ///< 0 : Cannot report dual tone multi-frequency (DTMF) digits input remotely over the telephone line. 1 : Can report DTMF digits input remotely over the telephone line. - uint32_t line_state_change : 1; ///< 0 : Does not support line state change notification. 1 : Does support line state change notification - uint32_t : 0; - } bmCapabilities; -}cdc_desc_func_telephone_call_state_reporting_capabilities_t; - -static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) ATTR_PURE ATTR_ALWAYS_INLINE; -static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) -{ - return p_desc[2]; -} - - -#ifdef __cplusplus - } -#endif - -#endif +/**************************************************************************/ +/*! + @file cdc.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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 holders 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 ''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 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 tinyusb stack. +*/ +/**************************************************************************/ + +/** \file + * \brief CDC Class Driver + * + * \note TBD + */ + +/** + * \addtogroup ClassDriver Class Driver + * @{ + * \defgroup ClassDriver_CDC Communication Device Class + * @{ + */ + +#ifndef _TUSB_CDC_H__ +#define _TUSB_CDC_H__ + +#include "common/common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// CDC COMMUNICATION INTERFACE CLASS +//--------------------------------------------------------------------+ +enum { + CDC_COMM_SUBCLASS_DIRECT_LINE_CONTROL_MODEL = 0x01 , + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL , + CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL , + CDC_COMM_SUBCLASS_MULTICHANNEL_CONTROL_MODEL , + CDC_COMM_SUBCLASS_CAPI_CONTROL_MODEL , + CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL , + CDC_COMM_SUBCLASS_ATM_NETWORKING_CONTROL_MODEL , + CDC_COMM_SUBCLASS_WIRELESS_HANDSET_CONTROL_MODEL , + CDC_COMM_SUBCLASS_DEVICE_MANAGEMENT , + CDC_COMM_SUBCLASS_MOBILE_DIRECT_LINE_MODEL , + CDC_COMM_SUBCLASS_OBEX , + CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL +}; + +enum { + CDC_COMM_PROTOCOL_ATCOMMAND = 0x01 , // ITU-T V2.50 + CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101 , + CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO , + CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707 , + CDC_COMM_PROTOCOL_ATCOMMAND_3GPP_27007 , + CDC_COMM_PROTOCOL_ATCOMMAND_CDMA , // defined by TIA + CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL +}; + +//------------- SubType Descriptor in COMM Functional Descriptor -------------// +enum { + CDC_FUNC_DESC_HEADER = 0x00 , + CDC_FUNC_DESC_CALL_MANAGEMENT = 0x01 , + CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT = 0x02 , + CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT = 0x03 , + CDC_FUNC_DESC_TELEPHONE_RINGER = 0x04 , + CDC_FUNC_DESC_TELEPHONE_CALL_AND_LINE_STATE_REPORTING_CAPACITY = 0x05 , + CDC_FUNC_DESC_UNION = 0x06 , + CDC_FUNC_DESC_COUNTRY_SELECTION = 0x07 , + CDC_FUNC_DESC_TELEPHONE_OPERATIONAL_MODES = 0x08 , + CDC_FUNC_DESC_USB_TERMINAL = 0x09 , + CDC_FUNC_DESC_NETWORK_CHANNEL_TERMINAL = 0x0A , + CDC_FUNC_DESC_PROTOCOL_UNIT = 0x0B , + CDC_FUNC_DESC_EXTENSION_UNIT = 0x0C , + CDC_FUNC_DESC_MULTICHANEL_MANAGEMENT = 0x0D , + CDC_FUNC_DESC_CAPI_CONTROL_MANAGEMENT = 0x0E , + CDC_FUNC_DESC_ETHERNET_NETWORKING = 0x0F , + CDC_FUNC_DESC_ATM_NETWORKING = 0x10 , + CDC_FUNC_DESC_WIRELESS_HANDSET_CONTROL_MODEL = 0x11 , + CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL = 0x12 , + CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL_DETAIL = 0x13 , + CDC_FUNC_DESC_DEVICE_MANAGEMENT_MODEL = 0x14 , + CDC_FUNC_DESC_OBEX = 0x15 , + CDC_FUNC_DESC_COMMAND_SET = 0x16 , + CDC_FUNC_DESC_COMMAND_SET_DETAIL = 0x17 , + CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL = 0x18 , + CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER = 0x19 +}; + +//--------------------------------------------------------------------+ +// CDC DATA INTERFACE CLASS +//--------------------------------------------------------------------+ + +// SUBCLASS code of Data Interface is not used and should/must be zero + +enum{ + CDC_DATA_PROTOCOL_ISDN_BRI = 0x30, + CDC_DATA_PROTOCOL_HDLC = 0x31, + CDC_DATA_PROTOCOL_TRANSPARENT = 0x32, + CDC_DATA_PROTOCOL_Q921_MANAGEMENT = 0x50, + CDC_DATA_PROTOCOL_Q921_DATA_LINK = 0x51, + CDC_DATA_PROTOCOL_Q921_TEI_MULTIPLEXOR = 0x52, + CDC_DATA_PROTOCOL_V42BIS_DATA_COMPRESSION = 0x90, + CDC_DATA_PROTOCOL_EURO_ISDN = 0x91, + CDC_DATA_PROTOCOL_V24_RATE_ADAPTION_TO_ISDN = 0x92, + CDC_DATA_PROTOCOL_CAPI_COMMAND = 0x93, + CDC_DATA_PROTOCOL_HOST_BASED_DRIVER = 0xFD, + CDC_DATA_PROTOCOL_IN_PROTOCOL_UNIT_FUNCTIONAL_DESCRIPTOR = 0xFE +}; + +//--------------------------------------------------------------------+ +// MANAGEMENT ELEMENT REQUEST (CONTROL ENDPOINT) +//--------------------------------------------------------------------+ +typedef enum { + SEND_ENCAPSULATED_COMMAND = 0x00, + GET_ENCAPSULATED_RESPONSE = 0x01, + + SET_COMM_FEATURE = 0x02, + GET_COMM_FEATURE = 0x03, + CLEAR_COMM_FEATURE = 0x04, + + SET_AUX_LINE_STATE = 0x10, + SET_HOOK_STATE = 0x11, + PULSE_SETUP = 0x12, + SEND_PULSE = 0x13, + SET_PULSE_TIME = 0x14, + RING_AUX_JACK = 0x15, + + SET_LINE_CODING = 0x20, + GET_LINE_CODING = 0x21, + SET_CONTROL_LINE_STATE = 0x22, + SEND_BREAK = 0x23, + + SET_RINGER_PARMS = 0x30, + GET_RINGER_PARMS = 0x31, + SET_OPERATION_PARMS = 0x32, + GET_OPERATION_PARMS = 0x33, + SET_LINE_PARMS = 0x34, + GET_LINE_PARMS = 0x35, + DIAL_DIGITS = 0x36, + SET_UNIT_PARAMETER = 0x37, + GET_UNIT_PARAMETER = 0x38, + CLEAR_UNIT_PARAMETER = 0x39, + GET_PROFILE = 0x3A, + + SET_ETHERNET_MULTICAST_FILTERS = 0x40, + SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, + GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, + SET_ETHERNET_PACKET_FILTER = 0x43, + GET_ETHERNET_STATISTIC = 0x44, + + SET_ATM_DATA_FORMAT = 0x50, + GET_ATM_DEVICE_STATISTICS = 0x51, + SET_ATM_DEFAULT_VC = 0x52, + GET_ATM_VC_STATISTICS = 0x53, + + MDLM_SEMANTIC_MODEL = 0x60, +}cdc_management_request_t; + +//--------------------------------------------------------------------+ +// MANAGEMENT ELEMENENT NOTIFICATION (NOTIFICATION ENDPOINT) +//--------------------------------------------------------------------+ +typedef enum { + NETWORK_CONNECTION = 0x00, + RESPONSE_AVAILABLE = 0x01, + + AUX_JACK_HOOK_STATE = 0x08, + RING_DETECT = 0x09, + + SERIAL_STATE = 0x20, + + CALL_STATE_CHANGE = 0x28, + LINE_STATE_CHANGE = 0x29, + CONNECTION_SPEED_CHANGE = 0x2A, + MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, +}cdc_notification_request_t; + +//--------------------------------------------------------------------+ +// FUNCTIONAL DESCRIPTOR +//--------------------------------------------------------------------+ +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + uint16_t bcdCDC ; ///< CDC release number in Binary-Coded Decimal +}cdc_desc_func_header_t; + +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + uint8_t bControlInterface ; ///< Interface number of Communication Interface + uint8_t bSubordinateInterface ; ///< Array of Interface number of Data Interface +}cdc_desc_func_union_t; + +#define cdc_desc_func_union_n_t(no_slave)\ + ATTR_PACKED_STRUCT(struct) { \ + uint8_t bLength ;\ + uint8_t bDescriptorType ;\ + uint8_t bDescriptorSubType ;\ + uint8_t bControlInterface ;\ + uint8_t bSubordinateInterface[no_slave] ;\ +} + +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + uint8_t iCountryCodeRelDate ; ///< Index of a string giving the release date for the implemented ISO 3166 Country Codes. + uint16_t wCountryCode[] ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country. +}cdc_desc_func_country_selection_t; + +#define cdc_desc_func_country_selection_n_t(no_country) \ + ATTR_PACKED_STRUCT(struct) {\ + uint8_t bLength ;\ + uint8_t bDescriptorType ;\ + uint8_t bDescriptorSubType ;\ + uint8_t iCountryCodeRelDate ;\ + uint16_t wCountryCode[no_country] ;\ +} + +//--------------------------------------------------------------------+ +// PUBLIC SWITCHED TELEPHONE NETWORK (PSTN) SUBCLASS +//--------------------------------------------------------------------+ +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + + struct { + uint8_t handle_call : 1; ///< 0 - Device sends/receives call management information only over the Communications Class interface. 1 - Device can send/receive call management information over a Data Class interface. + uint8_t send_recv_call : 1; ///< 0 - Device does not handle call management itself. 1 - Device handles call management itself. + uint8_t : 0; + } bmCapabilities; + + uint8_t bDataInterface; +}cdc_desc_func_call_management_t; + +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t support_comm_request : 1; ///< Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature. + uint8_t support_line_request : 1; ///< Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State. + uint8_t support_send_break : 1; ///< Device supports the request Send_Break + uint8_t support_notification_network_connection : 1; ///< Device supports the notification Network_Connection. + uint8_t : 0; +}cdc_acm_capability_t; + +STATIC_ASSERT(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compiler"); + +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + cdc_acm_capability_t bmCapabilities ; +}cdc_desc_func_abstract_control_management_t; + +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + struct { + uint8_t require_pulse_setup : 1; ///< Device requires extra Pulse_Setup request during pulse dialing sequence to disengage holding circuit. + uint8_t support_aux_request : 1; ///< Device supports the request combination of Set_Aux_Line_State, Ring_Aux_Jack, and notification Aux_Jack_Hook_State. + uint8_t support_pulse_request : 1; ///< Device supports the request combination of Pulse_Setup, Send_Pulse, and Set_Pulse_Time. + uint8_t : 0; + } bmCapabilities; +}cdc_desc_func_direct_line_management_t; + +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + uint8_t bRingerVolSteps ; + uint8_t bNumRingerPatterns ; +}cdc_desc_func_telephone_ringer_t; + +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + struct { + uint8_t simple_mode : 1; + uint8_t standalone_mode : 1; + uint8_t computer_centric_mode : 1; + uint8_t : 0; + } bmCapabilities; +}cdc_desc_func_telephone_operational_modes_t; + +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t bLength ; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ + struct { + uint32_t interrupted_dialtone : 1; ///< 0 : Reports only dialtone (does not differentiate between normal and interrupted dialtone). 1 : Reports interrupted dialtone in addition to normal dialtone + uint32_t ringback_busy_fastbusy : 1; ///< 0 : Reports only dialing state. 1 : Reports ringback, busy, and fast busy states. + uint32_t caller_id : 1; ///< 0 : Does not report caller ID. 1 : Reports caller ID information. + uint32_t incoming_distinctive : 1; ///< 0 : Reports only incoming ringing. 1 : Reports incoming distinctive ringing patterns. + uint32_t dual_tone_multi_freq : 1; ///< 0 : Cannot report dual tone multi-frequency (DTMF) digits input remotely over the telephone line. 1 : Can report DTMF digits input remotely over the telephone line. + uint32_t line_state_change : 1; ///< 0 : Does not support line state change notification. 1 : Does support line state change notification + uint32_t : 0; + } bmCapabilities; +}cdc_desc_func_telephone_call_state_reporting_capabilities_t; + +static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) ATTR_PURE ATTR_ALWAYS_INLINE; +static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) +{ + return p_desc[2]; +} + + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/tinyusb/class/hid.h b/tinyusb/class/hid.h index 6a983648b..636cdac8b 100644 --- a/tinyusb/class/hid.h +++ b/tinyusb/class/hid.h @@ -1,505 +1,505 @@ -/**************************************************************************/ -/*! - @file hid.h - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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 holders 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 ''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 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 tinyusb stack. -*/ -/**************************************************************************/ - -/** - * \addtogroup Group_ClassDriver Class Driver - * @{ - * \defgroup Group_HID Human Interface Device - * @{ - */ - -#ifndef _TUSB_HID_H_ -#define _TUSB_HID_H_ - -#include "common/common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -enum { - HID_SUBCLASS_NONE = 0, - HID_SUBCLASS_BOOT = 1 -}; - -enum { - HID_PROTOCOL_NONE = 0, - HID_PROTOCOL_KEYBOARD = 1, - HID_PROTOCOL_MOUSE = 2 -}; - -enum { - HID_DESC_TYPE_HID = 0x21, - HID_DESC_TYPE_REPORT = 0x22, - HID_DESC_TYPE_PHYSICAL = 0x23 -}; - -enum { - HID_REQUEST_REPORT_INPUT = 1, - HID_REQUEST_REPORT_OUTPUT, - HID_REQUEST_REPORT_FEATURE -}; - -enum { - HID_REQUEST_CONTROL_GET_REPORT = 0x01, - HID_REQUEST_CONTROL_GET_IDLE = 0x02, - HID_REQUEST_CONTROL_GET_PROTOCOL = 0x03, - HID_REQUEST_CONTROL_SET_REPORT = 0x09, - HID_REQUEST_CONTROL_SET_IDLE = 0x0a, - HID_REQUEST_CONTROL_SET_PROTOCOL = 0x0b -}; - -typedef ATTR_PACKED_STRUCT(struct) { - uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */ - uint8_t bDescriptorType; /**< Constant name specifying type of HID descriptor. */ - - uint16_t bcdHID; /**< Numeric expression identifying the HID Class Specification release */ - uint8_t bCountryCode; /**< Numeric expression identifying country code of the localized hardware. */ - uint8_t bNumDescriptors; /**< Numeric expression specifying the number of class descriptors */ - - uint8_t bReportType; /**< Type of HID class report. */ - uint16_t wReportLength; /**< the total size of the Report descriptor. */ -} tusb_hid_descriptor_hid_t; - -/** - * \brief Standard HID Boot Protocol Mouse Report. - * - * Type define for a standard Boot Protocol Mouse report - */ -typedef ATTR_PACKED_STRUCT(struct) -{ - uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */ - int8_t x; /**< Current delta x movement of the mouse. */ - int8_t y; /**< Current delta y movement on the mouse. */ - int8_t wheel; /**< Current delta wheel movement on the mouse. */ -} tusb_mouse_report_t; - -/** - * \brief Standard HID Boot Protocol Keyboard Report. - * - * Type define for a standard Boot Protocol Keyboard report - */ -typedef ATTR_PACKED_STRUCT(struct) -{ - uint8_t modifier; /**< Keyboard modifier byte, indicating pressed modifier keys (a combination of HID_KEYBOARD_MODIFER_* masks). */ - uint8_t reserved; /**< Reserved for OEM use, always set to 0. */ - uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */ -} tusb_keyboard_report_t; - -/** - * \brief buttons codes for HID mouse - */ -enum { - MOUSE_BUTTON_LEFT = BIT_(0), - MOUSE_BUTTON_RIGHT = BIT_(1), - MOUSE_BUTTON_MIDDLE = BIT_(2) -}; - -/** - * \brief KB modifier codes for HID KB - */ -enum { - KEYBOARD_MODIFIER_LEFTCTRL = BIT_(0), - KEYBOARD_MODIFIER_LEFTSHIFT = BIT_(1), - KEYBOARD_MODIFIER_LEFTALT = BIT_(2), - KEYBOARD_MODIFIER_LEFTGUI = BIT_(3), - KEYBOARD_MODIFIER_RIGHTCTRL = BIT_(4), - KEYBOARD_MODIFIER_RIGHTSHIFT = BIT_(5), - KEYBOARD_MODIFIER_RIGHTALT = BIT_(6), - KEYBOARD_MODIFIER_RIGHTGUI = BIT_(7) -}; - -#define HID_KEYCODE_TABLE(ENTRY) \ - ENTRY( 0x04, 'a', 'A' )\ - ENTRY( 0x05, 'b', 'B' )\ - ENTRY( 0x06, 'c', 'C' )\ - ENTRY( 0x07, 'd', 'D' )\ - ENTRY( 0x08, 'e', 'E' )\ - ENTRY( 0x09, 'f', 'F' )\ - ENTRY( 0x0a, 'g', 'G' )\ - ENTRY( 0x0b, 'h', 'H' )\ - ENTRY( 0x0c, 'i', 'I' )\ - ENTRY( 0x0d, 'j', 'J' )\ - ENTRY( 0x0e, 'k', 'K' )\ - ENTRY( 0x0f, 'l', 'L' )\ - \ - ENTRY( 0x10, 'm', 'M' )\ - ENTRY( 0x11, 'n', 'N' )\ - ENTRY( 0x12, 'o', 'O' )\ - ENTRY( 0x13, 'p', 'P' )\ - ENTRY( 0x14, 'q', 'Q' )\ - ENTRY( 0x15, 'r', 'R' )\ - ENTRY( 0x16, 's', 'S' )\ - ENTRY( 0x17, 't', 'T' )\ - ENTRY( 0x18, 'u', 'U' )\ - ENTRY( 0x19, 'v', 'V' )\ - ENTRY( 0x1a, 'w', 'W' )\ - ENTRY( 0x1b, 'x', 'X' )\ - ENTRY( 0x1c, 'y', 'Y' )\ - ENTRY( 0x1d, 'z', 'Z' )\ - ENTRY( 0x1e, '1', '!' )\ - ENTRY( 0x1f, '2', '@' )\ - \ - ENTRY( 0x20, '3', '#' )\ - ENTRY( 0x21, '4', '$' )\ - ENTRY( 0x22, '5', '%' )\ - ENTRY( 0x23, '6', '^' )\ - ENTRY( 0x24, '7', '&' )\ - ENTRY( 0x25, '8', '*' )\ - ENTRY( 0x26, '9', '(' )\ - ENTRY( 0x27, '0', ')' )\ - ENTRY( 0x28, '\r', '\r' )\ - ENTRY( 0x29, '\e', '\e' )\ - ENTRY( 0x2a, '\b', '\b' )\ - ENTRY( 0x2b, '\t', '\t' )\ - ENTRY( 0x2c, ' ', ' ' )\ - ENTRY( 0x2d, '-', '_' )\ - ENTRY( 0x2e, '=', '+' )\ - ENTRY( 0x2f, '[', '{' )\ - \ - ENTRY( 0x30, ']', '}' )\ - ENTRY( 0x31, '\\', '|' )\ - ENTRY( 0x32, '#', '~' ) /* TODO non-US keyboard */ \ - ENTRY( 0x33, ';', ':' )\ - ENTRY( 0x34, '\'', '\"' )\ - ENTRY( 0x35, 0, 0 )\ - ENTRY( 0x36, ',', '<' )\ - ENTRY( 0x37, '.', '>' )\ - ENTRY( 0x38, '/', '?' )\ - ENTRY( 0x39, 0, 0 ) /* TODO CapsLock, non-locking key implementation*/ \ - \ - ENTRY( 0x54, '/', '/' )\ - ENTRY( 0x55, '*', '*' )\ - ENTRY( 0x56, '-', '-' )\ - ENTRY( 0x57, '+', '+' )\ - ENTRY( 0x58, '\r', '\r' )\ - ENTRY( 0x59, '1', 0 ) /* numpad1 & end */ \ - ENTRY( 0x5a, '2', 0 )\ - ENTRY( 0x5b, '3', 0 )\ - ENTRY( 0x5c, '4', 0 )\ - ENTRY( 0x5d, '5', '5' )\ - ENTRY( 0x5e, '6', 0 )\ - ENTRY( 0x5f, '7', 0 )\ - ENTRY( 0x60, '8', 0 )\ - ENTRY( 0x61, '9', 0 )\ - ENTRY( 0x62, '0', 0 )\ - ENTRY( 0x63, '0', 0 )\ - \ - ENTRY( 0x67, '=', '=' )\ - -// TODO HID complete keycode table - -//enum -//{ -// KEYBOARD_KEYCODE_A = 0x04, -// KEYBOARD_KEYCODE_Z = 0x1d, -// -// KEYBOARD_KEYCODE_1 = 0x1e, -// KEYBOARD_KEYCODE_0 = 0x27, -// -// KEYBOARD_KEYCODE_ENTER = 0x28, -// KEYBOARD_KEYCODE_ESCAPE = 0x29, -// KEYBOARD_KEYCODE_BACKSPACE = 0x2a, -// KEYBOARD_KEYCODE_TAB = 0x2b, -// KEYBOARD_KEYCODE_SPACEBAR = 0x2c, -// -//}; - -/** - * \brief Local Country code for HID - */ -enum USB_HID_LOCAL_CODE -{ - HID_Local_NotSupported = 0, - HID_Local_Arabic, - HID_Local_Belgian, - HID_Local_Canadian_Bilingual, - HID_Local_Canadian_French, - HID_Local_Czech_Republic, - HID_Local_Danish, - HID_Local_Finnish, - HID_Local_French, - HID_Local_German, - HID_Local_Greek, - HID_Local_Hebrew, - HID_Local_Hungary, - HID_Local_International, - HID_Local_Italian, - HID_Local_Japan_Katakana, - HID_Local_Korean, - HID_Local_Latin_American, - HID_Local_Netherlands_Dutch, - HID_Local_Norwegian, - HID_Local_Persian_Farsi, - HID_Local_Poland, - HID_Local_Portuguese, - HID_Local_Russia, - HID_Local_Slovakia, - HID_Local_Spanish, - HID_Local_Swedish, - HID_Local_Swiss_French, - HID_Local_Swiss_German, - HID_Local_Switzerland, - HID_Local_Taiwan, - HID_Local_Turkish_Q, - HID_Local_UK, - HID_Local_US, - HID_Local_Yugoslavia, - HID_Local_Turkish_F -}; - -//--------------------------------------------------------------------+ -// REPORT DESCRIPTOR -//--------------------------------------------------------------------+ -//------------- ITEM & TAG -------------// -#define HID_REPORT_DATA_0(data) -#define HID_REPORT_DATA_1(data) , data -#define HID_REPORT_DATA_2(data) , U16_TO_U8S_LE(data) -#define HID_REPORT_DATA_3(data) , U32_TO_U8S_LE(data) - -#define HID_REPORT_ITEM(data, tag, type, size) \ - (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data) - -#define RI_TYPE_MAIN 0 -#define RI_TYPE_GLOBAL 1 -#define RI_TYPE_LOCAL 2 - -//------------- MAIN ITEMS 6.2.2.4 -------------// -#define HID_INPUT(x) HID_REPORT_ITEM(x, 8, RI_TYPE_MAIN, 1) -#define HID_OUTPUT(x) HID_REPORT_ITEM(x, 9, RI_TYPE_MAIN, 1) -#define HID_COLLECTION(x) HID_REPORT_ITEM(x, 10, RI_TYPE_MAIN, 1) -#define HID_FEATURE(x) HID_REPORT_ITEM(x, 11, RI_TYPE_MAIN, 1) -#define HID_COLLECTION_END HID_REPORT_ITEM(x, 12, RI_TYPE_MAIN, 0) - -//------------- INPUT, OUTPUT, FEATURE 6.2.2.5 -------------// -#define HID_DATA (0<<0) -#define HID_CONSTANT (1<<0) - -#define HID_ARRAY (0<<1) -#define HID_VARIABLE (1<<1) - -#define HID_ABSOLUTE (0<<2) -#define HID_RELATIVE (1<<2) - -#define HID_WRAP_NO (0<<3) -#define HID_WRAP (1<<3) - -#define HID_LINEAR (0<<4) -#define HID_NONLINEAR (1<<4) - -#define HID_PREFERRED_STATE (0<<5) -#define HID_PREFERRED_NO (1<<5) - -#define HID_NO_NULL_POSITION (0<<6) -#define HID_NULL_STATE (1<<6) - -#define HID_NON_VOLATILE (0<<7) -#define HID_VOLATILE (1<<7) - -#define HID_BITFIELD (0<<8) -#define HID_BUFFERED_BYTES (1<<8) - -//------------- COLLECTION ITEM 6.2.2.6 -------------// -enum { - HID_COLLECTION_PHYSICAL = 0, - HID_COLLECTION_APPLICATION, - HID_COLLECTION_LOGICAL, - HID_COLLECTION_REPORT, - HID_COLLECTION_NAMED_ARRAY, - HID_COLLECTION_USAGE_SWITCH, - HID_COLLECTION_USAGE_MODIFIER -}; - -//------------- GLOBAL ITEMS 6.2.2.7 -------------// -#define HID_USAGE_PAGE(x) HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, 1) -#define HID_USAGE_PAGE_N(x, n) HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, n) - -#define HID_LOGICAL_MIN(x) HID_REPORT_ITEM(x, 1, RI_TYPE_GLOBAL, 1) -#define HID_LOGICAL_MIN_N(x, n) HID_REPORT_ITEM(x, 1, RI_TYPE_GLOBAL, n) - -#define HID_LOGICAL_MAX(x) HID_REPORT_ITEM(x, 2, RI_TYPE_GLOBAL, 1) -#define HID_LOGICAL_MAX_N(x, n) HID_REPORT_ITEM(x, 2, RI_TYPE_GLOBAL, n) - -#define HID_PHYSICAL_MIN(x) HID_REPORT_ITEM(x, 3, RI_TYPE_GLOBAL, 1) -#define HID_PHYSICAL_MIN_N(x, n) HID_REPORT_ITEM(x, 3, RI_TYPE_GLOBAL, n) - -#define HID_PHYSICAL_MAX(x) HID_REPORT_ITEM(x, 4, RI_TYPE_GLOBAL, 1) -#define HID_PHYSICAL_MAX_N(x, n) HID_REPORT_ITEM(x, 4, RI_TYPE_GLOBAL, n) - -#define HID_UNIT_EXPONENT(x) HID_REPORT_ITEM(x, 5, RI_TYPE_GLOBAL, 1) -#define HID_UNIT_EXPONENT_N(x, n) HID_REPORT_ITEM(x, 5, RI_TYPE_GLOBAL, n) - -#define HID_UNIT(x) HID_REPORT_ITEM(x, 6, RI_TYPE_GLOBAL, 1) -#define HID_UNIT_N(x, n) HID_REPORT_ITEM(x, 6, RI_TYPE_GLOBAL, n) - -#define HID_REPORT_SIZE(x) HID_REPORT_ITEM(x, 7, RI_TYPE_GLOBAL, 1) -#define HID_REPORT_SIZE_N(x, n) HID_REPORT_ITEM(x, 7, RI_TYPE_GLOBAL, n) - -#define HID_REPORT_ID(x) HID_REPORT_ITEM(x, 8, RI_TYPE_GLOBAL, 1) -#define HID_REPORT_ID_N(x) HID_REPORT_ITEM(x, 8, RI_TYPE_GLOBAL, n) - -#define HID_REPORT_COUNT(x) HID_REPORT_ITEM(x, 9, RI_TYPE_GLOBAL, 1) -#define HID_REPORT_COUNT_N(x, n) HID_REPORT_ITEM(x, 9, RI_TYPE_GLOBAL, n) - -#define HID_PUSH HID_REPORT_ITEM(x, 10, RI_TYPE_GLOBAL, 0) -#define HID_POP HID_REPORT_ITEM(x, 11, RI_TYPE_GLOBAL, 0) - -//------------- LOCAL ITEMS 6.2.2.8 -------------// -#define HID_USAGE(x) HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, 1) -#define HID_USAGE_N(x, n) HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, n) - -#define HID_USAGE_MIN(x) HID_REPORT_ITEM(x, 1, RI_TYPE_LOCAL, 1) -#define HID_USAGE_MIN_N(x, n) HID_REPORT_ITEM(x, 1, RI_TYPE_LOCAL, n) - -#define HID_USAGE_MAX(x) HID_REPORT_ITEM(x, 2, RI_TYPE_LOCAL, 1) -#define HID_USAGE_MAX_N(x, n) HID_REPORT_ITEM(x, 2, RI_TYPE_LOCAL, n) - -//--------------------------------------------------------------------+ -// Usage Table -//--------------------------------------------------------------------+ - -/// HID Usage Table - Table 1: Usage Page Summary -enum { - HID_USAGE_PAGE_DESKTOP = 0x01, - HID_USAGE_PAGE_SIMULATE = 0x02, - HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03, - HID_USAGE_PAGE_SPORT = 0x04, - HID_USAGE_PAGE_GAME = 0x05, - HID_USAGE_PAGE_GENERIC_DEVICE = 0x06, - HID_USAGE_PAGE_KEYBOARD = 0x07, - HID_USAGE_PAGE_LED = 0x08, - HID_USAGE_PAGE_BUTTON = 0x09, - HID_USAGE_PAGE_ORDINAL = 0x0a, - HID_USAGE_PAGE_TELEPHONY = 0x0b, - HID_USAGE_PAGE_CONSUMER = 0x0c, - HID_USAGE_PAGE_DIGITIZER = 0x0d, - HID_USAGE_PAGE_PID = 0x0f, - HID_USAGE_PAGE_UNICODE = 0x10, - HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14, - HID_USAGE_PAGE_MEDICAL = 0x40, - HID_USAGE_PAGE_MONITOR = 0x80, //0x80 - 0x83 - HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87 - HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, - HID_USAGE_PAGE_SCALE = 0x8d, - HID_USAGE_PAGE_MSR = 0x8e, - HID_USAGE_PAGE_CAMERA = 0x90, - HID_USAGE_PAGE_ARCADE = 0x91, - HID_USAGE_PAGE_VENDOR = 0xFFFF // 0xFF00 - 0xFFFF -}; - -/// HID Usage Table - Table 6: Generic Desktop Page -enum { - HID_USAGE_DESKTOP_POINTER = 0x01, - HID_USAGE_DESKTOP_MOUSE = 0x02, - HID_USAGE_DESKTOP_JOYSTICK = 0x04, - HID_USAGE_DESKTOP_GAMEPAD = 0x05, - HID_USAGE_DESKTOP_KEYBOARD = 0x06, - HID_USAGE_DESKTOP_KEYPAD = 0x07, - HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 0x08, - HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09, - HID_USAGE_DESKTOP_X = 0x30, - HID_USAGE_DESKTOP_Y = 0x31, - HID_USAGE_DESKTOP_Z = 0x32, - HID_USAGE_DESKTOP_RX = 0x33, - HID_USAGE_DESKTOP_RY = 0x34, - HID_USAGE_DESKTOP_RZ = 0x35, - HID_USAGE_DESKTOP_SLIDER = 0x36, - HID_USAGE_DESKTOP_DIAL = 0x37, - HID_USAGE_DESKTOP_WHEEL = 0x38, - HID_USAGE_DESKTOP_HAT_SWITCH = 0x39, - HID_USAGE_DESKTOP_COUNTED_BUFFER = 0x3a, - HID_USAGE_DESKTOP_BYTE_COUNT = 0x3b, - HID_USAGE_DESKTOP_MOTION_WAKEUP = 0x3c, - HID_USAGE_DESKTOP_START = 0x3d, - HID_USAGE_DESKTOP_SELECT = 0x3e, - HID_USAGE_DESKTOP_VX = 0x40, - HID_USAGE_DESKTOP_VY = 0x41, - HID_USAGE_DESKTOP_VZ = 0x42, - HID_USAGE_DESKTOP_VBRX = 0x43, - HID_USAGE_DESKTOP_VBRY = 0x44, - HID_USAGE_DESKTOP_VBRZ = 0x45, - HID_USAGE_DESKTOP_VNO = 0x46, - HID_USAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47, - HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48, - HID_USAGE_DESKTOP_SYSTEM_CONTROL = 0x80, - HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN = 0x81, - HID_USAGE_DESKTOP_SYSTEM_SLEEP = 0x82, - HID_USAGE_DESKTOP_SYSTEM_WAKE_UP = 0x83, - HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU = 0x84, - HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU = 0x85, - HID_USAGE_DESKTOP_SYSTEM_APP_MENU = 0x86, - HID_USAGE_DESKTOP_SYSTEM_MENU_HELP = 0x87, - HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT = 0x88, - HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT = 0x89, - HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT = 0x8A, - HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT = 0x8B, - HID_USAGE_DESKTOP_SYSTEM_MENU_UP = 0x8C, - HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN = 0x8D, - HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART = 0x8E, - HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART = 0x8F, - HID_USAGE_DESKTOP_DPAD_UP = 0x90, - HID_USAGE_DESKTOP_DPAD_DOWN = 0x91, - HID_USAGE_DESKTOP_DPAD_RIGHT = 0x92, - HID_USAGE_DESKTOP_DPAD_LEFT = 0x93, - HID_USAGE_DESKTOP_SYSTEM_DOCK = 0xA0, - HID_USAGE_DESKTOP_SYSTEM_UNDOCK = 0xA1, - HID_USAGE_DESKTOP_SYSTEM_SETUP = 0xA2, - HID_USAGE_DESKTOP_SYSTEM_BREAK = 0xA3, - HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK = 0xA4, - HID_USAGE_DESKTOP_APPLICATION_BREAK = 0xA5, - HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK = 0xA6, - HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE = 0xA7, - HID_USAGE_DESKTOP_SYSTEM_HIBERNATE = 0xA8, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT = 0xB0, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL = 0xB1, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL = 0xB2, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH = 0xB3, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL = 0xB4, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6, - HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7 -}; - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_HID_H__ */ - -/// @} -/// @} +/**************************************************************************/ +/*! + @file hid.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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 holders 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 ''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 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 tinyusb stack. +*/ +/**************************************************************************/ + +/** + * \addtogroup ClassDriver Class Driver + * @{ + * \defgroup ClassDriver_HID Human Interface Device (HID) + * @{ + */ + +#ifndef _TUSB_HID_H_ +#define _TUSB_HID_H_ + +#include "common/common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +enum { + HID_SUBCLASS_NONE = 0, + HID_SUBCLASS_BOOT = 1 +}; + +enum { + HID_PROTOCOL_NONE = 0, + HID_PROTOCOL_KEYBOARD = 1, + HID_PROTOCOL_MOUSE = 2 +}; + +enum { + HID_DESC_TYPE_HID = 0x21, + HID_DESC_TYPE_REPORT = 0x22, + HID_DESC_TYPE_PHYSICAL = 0x23 +}; + +enum { + HID_REQUEST_REPORT_INPUT = 1, + HID_REQUEST_REPORT_OUTPUT, + HID_REQUEST_REPORT_FEATURE +}; + +enum { + HID_REQUEST_CONTROL_GET_REPORT = 0x01, + HID_REQUEST_CONTROL_GET_IDLE = 0x02, + HID_REQUEST_CONTROL_GET_PROTOCOL = 0x03, + HID_REQUEST_CONTROL_SET_REPORT = 0x09, + HID_REQUEST_CONTROL_SET_IDLE = 0x0a, + HID_REQUEST_CONTROL_SET_PROTOCOL = 0x0b +}; + +typedef ATTR_PACKED_STRUCT(struct) { + uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */ + uint8_t bDescriptorType; /**< Constant name specifying type of HID descriptor. */ + + uint16_t bcdHID; /**< Numeric expression identifying the HID Class Specification release */ + uint8_t bCountryCode; /**< Numeric expression identifying country code of the localized hardware. */ + uint8_t bNumDescriptors; /**< Numeric expression specifying the number of class descriptors */ + + uint8_t bReportType; /**< Type of HID class report. */ + uint16_t wReportLength; /**< the total size of the Report descriptor. */ +} tusb_hid_descriptor_hid_t; + +/** + * \brief Standard HID Boot Protocol Mouse Report. + * + * Type define for a standard Boot Protocol Mouse report + */ +typedef ATTR_PACKED_STRUCT(struct) +{ + uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */ + int8_t x; /**< Current delta x movement of the mouse. */ + int8_t y; /**< Current delta y movement on the mouse. */ + int8_t wheel; /**< Current delta wheel movement on the mouse. */ +} tusb_mouse_report_t; + +/** + * \brief Standard HID Boot Protocol Keyboard Report. + * + * Type define for a standard Boot Protocol Keyboard report + */ +typedef ATTR_PACKED_STRUCT(struct) +{ + uint8_t modifier; /**< Keyboard modifier byte, indicating pressed modifier keys (a combination of HID_KEYBOARD_MODIFER_* masks). */ + uint8_t reserved; /**< Reserved for OEM use, always set to 0. */ + uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */ +} tusb_keyboard_report_t; + +/** + * \brief buttons codes for HID mouse + */ +enum { + MOUSE_BUTTON_LEFT = BIT_(0), + MOUSE_BUTTON_RIGHT = BIT_(1), + MOUSE_BUTTON_MIDDLE = BIT_(2) +}; + +/** + * \brief KB modifier codes for HID KB + */ +enum { + KEYBOARD_MODIFIER_LEFTCTRL = BIT_(0), + KEYBOARD_MODIFIER_LEFTSHIFT = BIT_(1), + KEYBOARD_MODIFIER_LEFTALT = BIT_(2), + KEYBOARD_MODIFIER_LEFTGUI = BIT_(3), + KEYBOARD_MODIFIER_RIGHTCTRL = BIT_(4), + KEYBOARD_MODIFIER_RIGHTSHIFT = BIT_(5), + KEYBOARD_MODIFIER_RIGHTALT = BIT_(6), + KEYBOARD_MODIFIER_RIGHTGUI = BIT_(7) +}; + +#define HID_KEYCODE_TABLE(ENTRY) \ + ENTRY( 0x04, 'a', 'A' )\ + ENTRY( 0x05, 'b', 'B' )\ + ENTRY( 0x06, 'c', 'C' )\ + ENTRY( 0x07, 'd', 'D' )\ + ENTRY( 0x08, 'e', 'E' )\ + ENTRY( 0x09, 'f', 'F' )\ + ENTRY( 0x0a, 'g', 'G' )\ + ENTRY( 0x0b, 'h', 'H' )\ + ENTRY( 0x0c, 'i', 'I' )\ + ENTRY( 0x0d, 'j', 'J' )\ + ENTRY( 0x0e, 'k', 'K' )\ + ENTRY( 0x0f, 'l', 'L' )\ + \ + ENTRY( 0x10, 'm', 'M' )\ + ENTRY( 0x11, 'n', 'N' )\ + ENTRY( 0x12, 'o', 'O' )\ + ENTRY( 0x13, 'p', 'P' )\ + ENTRY( 0x14, 'q', 'Q' )\ + ENTRY( 0x15, 'r', 'R' )\ + ENTRY( 0x16, 's', 'S' )\ + ENTRY( 0x17, 't', 'T' )\ + ENTRY( 0x18, 'u', 'U' )\ + ENTRY( 0x19, 'v', 'V' )\ + ENTRY( 0x1a, 'w', 'W' )\ + ENTRY( 0x1b, 'x', 'X' )\ + ENTRY( 0x1c, 'y', 'Y' )\ + ENTRY( 0x1d, 'z', 'Z' )\ + ENTRY( 0x1e, '1', '!' )\ + ENTRY( 0x1f, '2', '@' )\ + \ + ENTRY( 0x20, '3', '#' )\ + ENTRY( 0x21, '4', '$' )\ + ENTRY( 0x22, '5', '%' )\ + ENTRY( 0x23, '6', '^' )\ + ENTRY( 0x24, '7', '&' )\ + ENTRY( 0x25, '8', '*' )\ + ENTRY( 0x26, '9', '(' )\ + ENTRY( 0x27, '0', ')' )\ + ENTRY( 0x28, '\r', '\r' )\ + ENTRY( 0x29, '\e', '\e' )\ + ENTRY( 0x2a, '\b', '\b' )\ + ENTRY( 0x2b, '\t', '\t' )\ + ENTRY( 0x2c, ' ', ' ' )\ + ENTRY( 0x2d, '-', '_' )\ + ENTRY( 0x2e, '=', '+' )\ + ENTRY( 0x2f, '[', '{' )\ + \ + ENTRY( 0x30, ']', '}' )\ + ENTRY( 0x31, '\\', '|' )\ + ENTRY( 0x32, '#', '~' ) /* TODO non-US keyboard */ \ + ENTRY( 0x33, ';', ':' )\ + ENTRY( 0x34, '\'', '\"' )\ + ENTRY( 0x35, 0, 0 )\ + ENTRY( 0x36, ',', '<' )\ + ENTRY( 0x37, '.', '>' )\ + ENTRY( 0x38, '/', '?' )\ + ENTRY( 0x39, 0, 0 ) /* TODO CapsLock, non-locking key implementation*/ \ + \ + ENTRY( 0x54, '/', '/' )\ + ENTRY( 0x55, '*', '*' )\ + ENTRY( 0x56, '-', '-' )\ + ENTRY( 0x57, '+', '+' )\ + ENTRY( 0x58, '\r', '\r' )\ + ENTRY( 0x59, '1', 0 ) /* numpad1 & end */ \ + ENTRY( 0x5a, '2', 0 )\ + ENTRY( 0x5b, '3', 0 )\ + ENTRY( 0x5c, '4', 0 )\ + ENTRY( 0x5d, '5', '5' )\ + ENTRY( 0x5e, '6', 0 )\ + ENTRY( 0x5f, '7', 0 )\ + ENTRY( 0x60, '8', 0 )\ + ENTRY( 0x61, '9', 0 )\ + ENTRY( 0x62, '0', 0 )\ + ENTRY( 0x63, '0', 0 )\ + \ + ENTRY( 0x67, '=', '=' )\ + +// TODO HID complete keycode table + +//enum +//{ +// KEYBOARD_KEYCODE_A = 0x04, +// KEYBOARD_KEYCODE_Z = 0x1d, +// +// KEYBOARD_KEYCODE_1 = 0x1e, +// KEYBOARD_KEYCODE_0 = 0x27, +// +// KEYBOARD_KEYCODE_ENTER = 0x28, +// KEYBOARD_KEYCODE_ESCAPE = 0x29, +// KEYBOARD_KEYCODE_BACKSPACE = 0x2a, +// KEYBOARD_KEYCODE_TAB = 0x2b, +// KEYBOARD_KEYCODE_SPACEBAR = 0x2c, +// +//}; + +/** + * \brief Local Country code for HID + */ +enum USB_HID_LOCAL_CODE +{ + HID_Local_NotSupported = 0, + HID_Local_Arabic, + HID_Local_Belgian, + HID_Local_Canadian_Bilingual, + HID_Local_Canadian_French, + HID_Local_Czech_Republic, + HID_Local_Danish, + HID_Local_Finnish, + HID_Local_French, + HID_Local_German, + HID_Local_Greek, + HID_Local_Hebrew, + HID_Local_Hungary, + HID_Local_International, + HID_Local_Italian, + HID_Local_Japan_Katakana, + HID_Local_Korean, + HID_Local_Latin_American, + HID_Local_Netherlands_Dutch, + HID_Local_Norwegian, + HID_Local_Persian_Farsi, + HID_Local_Poland, + HID_Local_Portuguese, + HID_Local_Russia, + HID_Local_Slovakia, + HID_Local_Spanish, + HID_Local_Swedish, + HID_Local_Swiss_French, + HID_Local_Swiss_German, + HID_Local_Switzerland, + HID_Local_Taiwan, + HID_Local_Turkish_Q, + HID_Local_UK, + HID_Local_US, + HID_Local_Yugoslavia, + HID_Local_Turkish_F +}; + +//--------------------------------------------------------------------+ +// REPORT DESCRIPTOR +//--------------------------------------------------------------------+ +//------------- ITEM & TAG -------------// +#define HID_REPORT_DATA_0(data) +#define HID_REPORT_DATA_1(data) , data +#define HID_REPORT_DATA_2(data) , U16_TO_U8S_LE(data) +#define HID_REPORT_DATA_3(data) , U32_TO_U8S_LE(data) + +#define HID_REPORT_ITEM(data, tag, type, size) \ + (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data) + +#define RI_TYPE_MAIN 0 +#define RI_TYPE_GLOBAL 1 +#define RI_TYPE_LOCAL 2 + +//------------- MAIN ITEMS 6.2.2.4 -------------// +#define HID_INPUT(x) HID_REPORT_ITEM(x, 8, RI_TYPE_MAIN, 1) +#define HID_OUTPUT(x) HID_REPORT_ITEM(x, 9, RI_TYPE_MAIN, 1) +#define HID_COLLECTION(x) HID_REPORT_ITEM(x, 10, RI_TYPE_MAIN, 1) +#define HID_FEATURE(x) HID_REPORT_ITEM(x, 11, RI_TYPE_MAIN, 1) +#define HID_COLLECTION_END HID_REPORT_ITEM(x, 12, RI_TYPE_MAIN, 0) + +//------------- INPUT, OUTPUT, FEATURE 6.2.2.5 -------------// +#define HID_DATA (0<<0) +#define HID_CONSTANT (1<<0) + +#define HID_ARRAY (0<<1) +#define HID_VARIABLE (1<<1) + +#define HID_ABSOLUTE (0<<2) +#define HID_RELATIVE (1<<2) + +#define HID_WRAP_NO (0<<3) +#define HID_WRAP (1<<3) + +#define HID_LINEAR (0<<4) +#define HID_NONLINEAR (1<<4) + +#define HID_PREFERRED_STATE (0<<5) +#define HID_PREFERRED_NO (1<<5) + +#define HID_NO_NULL_POSITION (0<<6) +#define HID_NULL_STATE (1<<6) + +#define HID_NON_VOLATILE (0<<7) +#define HID_VOLATILE (1<<7) + +#define HID_BITFIELD (0<<8) +#define HID_BUFFERED_BYTES (1<<8) + +//------------- COLLECTION ITEM 6.2.2.6 -------------// +enum { + HID_COLLECTION_PHYSICAL = 0, + HID_COLLECTION_APPLICATION, + HID_COLLECTION_LOGICAL, + HID_COLLECTION_REPORT, + HID_COLLECTION_NAMED_ARRAY, + HID_COLLECTION_USAGE_SWITCH, + HID_COLLECTION_USAGE_MODIFIER +}; + +//------------- GLOBAL ITEMS 6.2.2.7 -------------// +#define HID_USAGE_PAGE(x) HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, 1) +#define HID_USAGE_PAGE_N(x, n) HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, n) + +#define HID_LOGICAL_MIN(x) HID_REPORT_ITEM(x, 1, RI_TYPE_GLOBAL, 1) +#define HID_LOGICAL_MIN_N(x, n) HID_REPORT_ITEM(x, 1, RI_TYPE_GLOBAL, n) + +#define HID_LOGICAL_MAX(x) HID_REPORT_ITEM(x, 2, RI_TYPE_GLOBAL, 1) +#define HID_LOGICAL_MAX_N(x, n) HID_REPORT_ITEM(x, 2, RI_TYPE_GLOBAL, n) + +#define HID_PHYSICAL_MIN(x) HID_REPORT_ITEM(x, 3, RI_TYPE_GLOBAL, 1) +#define HID_PHYSICAL_MIN_N(x, n) HID_REPORT_ITEM(x, 3, RI_TYPE_GLOBAL, n) + +#define HID_PHYSICAL_MAX(x) HID_REPORT_ITEM(x, 4, RI_TYPE_GLOBAL, 1) +#define HID_PHYSICAL_MAX_N(x, n) HID_REPORT_ITEM(x, 4, RI_TYPE_GLOBAL, n) + +#define HID_UNIT_EXPONENT(x) HID_REPORT_ITEM(x, 5, RI_TYPE_GLOBAL, 1) +#define HID_UNIT_EXPONENT_N(x, n) HID_REPORT_ITEM(x, 5, RI_TYPE_GLOBAL, n) + +#define HID_UNIT(x) HID_REPORT_ITEM(x, 6, RI_TYPE_GLOBAL, 1) +#define HID_UNIT_N(x, n) HID_REPORT_ITEM(x, 6, RI_TYPE_GLOBAL, n) + +#define HID_REPORT_SIZE(x) HID_REPORT_ITEM(x, 7, RI_TYPE_GLOBAL, 1) +#define HID_REPORT_SIZE_N(x, n) HID_REPORT_ITEM(x, 7, RI_TYPE_GLOBAL, n) + +#define HID_REPORT_ID(x) HID_REPORT_ITEM(x, 8, RI_TYPE_GLOBAL, 1) +#define HID_REPORT_ID_N(x) HID_REPORT_ITEM(x, 8, RI_TYPE_GLOBAL, n) + +#define HID_REPORT_COUNT(x) HID_REPORT_ITEM(x, 9, RI_TYPE_GLOBAL, 1) +#define HID_REPORT_COUNT_N(x, n) HID_REPORT_ITEM(x, 9, RI_TYPE_GLOBAL, n) + +#define HID_PUSH HID_REPORT_ITEM(x, 10, RI_TYPE_GLOBAL, 0) +#define HID_POP HID_REPORT_ITEM(x, 11, RI_TYPE_GLOBAL, 0) + +//------------- LOCAL ITEMS 6.2.2.8 -------------// +#define HID_USAGE(x) HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, 1) +#define HID_USAGE_N(x, n) HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, n) + +#define HID_USAGE_MIN(x) HID_REPORT_ITEM(x, 1, RI_TYPE_LOCAL, 1) +#define HID_USAGE_MIN_N(x, n) HID_REPORT_ITEM(x, 1, RI_TYPE_LOCAL, n) + +#define HID_USAGE_MAX(x) HID_REPORT_ITEM(x, 2, RI_TYPE_LOCAL, 1) +#define HID_USAGE_MAX_N(x, n) HID_REPORT_ITEM(x, 2, RI_TYPE_LOCAL, n) + +//--------------------------------------------------------------------+ +// Usage Table +//--------------------------------------------------------------------+ + +/// HID Usage Table - Table 1: Usage Page Summary +enum { + HID_USAGE_PAGE_DESKTOP = 0x01, + HID_USAGE_PAGE_SIMULATE = 0x02, + HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03, + HID_USAGE_PAGE_SPORT = 0x04, + HID_USAGE_PAGE_GAME = 0x05, + HID_USAGE_PAGE_GENERIC_DEVICE = 0x06, + HID_USAGE_PAGE_KEYBOARD = 0x07, + HID_USAGE_PAGE_LED = 0x08, + HID_USAGE_PAGE_BUTTON = 0x09, + HID_USAGE_PAGE_ORDINAL = 0x0a, + HID_USAGE_PAGE_TELEPHONY = 0x0b, + HID_USAGE_PAGE_CONSUMER = 0x0c, + HID_USAGE_PAGE_DIGITIZER = 0x0d, + HID_USAGE_PAGE_PID = 0x0f, + HID_USAGE_PAGE_UNICODE = 0x10, + HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14, + HID_USAGE_PAGE_MEDICAL = 0x40, + HID_USAGE_PAGE_MONITOR = 0x80, //0x80 - 0x83 + HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87 + HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, + HID_USAGE_PAGE_SCALE = 0x8d, + HID_USAGE_PAGE_MSR = 0x8e, + HID_USAGE_PAGE_CAMERA = 0x90, + HID_USAGE_PAGE_ARCADE = 0x91, + HID_USAGE_PAGE_VENDOR = 0xFFFF // 0xFF00 - 0xFFFF +}; + +/// HID Usage Table - Table 6: Generic Desktop Page +enum { + HID_USAGE_DESKTOP_POINTER = 0x01, + HID_USAGE_DESKTOP_MOUSE = 0x02, + HID_USAGE_DESKTOP_JOYSTICK = 0x04, + HID_USAGE_DESKTOP_GAMEPAD = 0x05, + HID_USAGE_DESKTOP_KEYBOARD = 0x06, + HID_USAGE_DESKTOP_KEYPAD = 0x07, + HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 0x08, + HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09, + HID_USAGE_DESKTOP_X = 0x30, + HID_USAGE_DESKTOP_Y = 0x31, + HID_USAGE_DESKTOP_Z = 0x32, + HID_USAGE_DESKTOP_RX = 0x33, + HID_USAGE_DESKTOP_RY = 0x34, + HID_USAGE_DESKTOP_RZ = 0x35, + HID_USAGE_DESKTOP_SLIDER = 0x36, + HID_USAGE_DESKTOP_DIAL = 0x37, + HID_USAGE_DESKTOP_WHEEL = 0x38, + HID_USAGE_DESKTOP_HAT_SWITCH = 0x39, + HID_USAGE_DESKTOP_COUNTED_BUFFER = 0x3a, + HID_USAGE_DESKTOP_BYTE_COUNT = 0x3b, + HID_USAGE_DESKTOP_MOTION_WAKEUP = 0x3c, + HID_USAGE_DESKTOP_START = 0x3d, + HID_USAGE_DESKTOP_SELECT = 0x3e, + HID_USAGE_DESKTOP_VX = 0x40, + HID_USAGE_DESKTOP_VY = 0x41, + HID_USAGE_DESKTOP_VZ = 0x42, + HID_USAGE_DESKTOP_VBRX = 0x43, + HID_USAGE_DESKTOP_VBRY = 0x44, + HID_USAGE_DESKTOP_VBRZ = 0x45, + HID_USAGE_DESKTOP_VNO = 0x46, + HID_USAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47, + HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48, + HID_USAGE_DESKTOP_SYSTEM_CONTROL = 0x80, + HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN = 0x81, + HID_USAGE_DESKTOP_SYSTEM_SLEEP = 0x82, + HID_USAGE_DESKTOP_SYSTEM_WAKE_UP = 0x83, + HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU = 0x84, + HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU = 0x85, + HID_USAGE_DESKTOP_SYSTEM_APP_MENU = 0x86, + HID_USAGE_DESKTOP_SYSTEM_MENU_HELP = 0x87, + HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT = 0x88, + HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT = 0x89, + HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT = 0x8A, + HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT = 0x8B, + HID_USAGE_DESKTOP_SYSTEM_MENU_UP = 0x8C, + HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN = 0x8D, + HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART = 0x8E, + HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART = 0x8F, + HID_USAGE_DESKTOP_DPAD_UP = 0x90, + HID_USAGE_DESKTOP_DPAD_DOWN = 0x91, + HID_USAGE_DESKTOP_DPAD_RIGHT = 0x92, + HID_USAGE_DESKTOP_DPAD_LEFT = 0x93, + HID_USAGE_DESKTOP_SYSTEM_DOCK = 0xA0, + HID_USAGE_DESKTOP_SYSTEM_UNDOCK = 0xA1, + HID_USAGE_DESKTOP_SYSTEM_SETUP = 0xA2, + HID_USAGE_DESKTOP_SYSTEM_BREAK = 0xA3, + HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK = 0xA4, + HID_USAGE_DESKTOP_APPLICATION_BREAK = 0xA5, + HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK = 0xA6, + HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE = 0xA7, + HID_USAGE_DESKTOP_SYSTEM_HIBERNATE = 0xA8, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT = 0xB0, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL = 0xB1, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL = 0xB2, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH = 0xB3, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL = 0xB4, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7 +}; + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_HID_H__ */ + +/// @} +/// @} diff --git a/tinyusb/class/hid_host.c b/tinyusb/class/hid_host.c index 0c7d4dc0a..e61590eab 100644 --- a/tinyusb/class/hid_host.c +++ b/tinyusb/class/hid_host.c @@ -1,304 +1,304 @@ -/**************************************************************************/ -/*! - @file hid_host.c - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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 holders 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 ''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 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 tinyusb stack. -*/ -/**************************************************************************/ - -#include "tusb_option.h" - -#if (MODE_HOST_SUPPORTED && HOST_CLASS_HID) - -#define _TINY_USB_SOURCE_FILE_ -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "common/common.h" -#include "hid_host.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// HID Interface common functions -//--------------------------------------------------------------------+ -static inline tusb_error_t hidh_interface_open(uint8_t dev_addr, uint8_t interface_number, tusb_descriptor_endpoint_t const *p_endpoint_desc, hidh_interface_info_t *p_hid) ATTR_ALWAYS_INLINE; -static inline tusb_error_t hidh_interface_open(uint8_t dev_addr, uint8_t interface_number, tusb_descriptor_endpoint_t const *p_endpoint_desc, hidh_interface_info_t *p_hid) -{ - p_hid->pipe_hdl = hcd_pipe_open(dev_addr, p_endpoint_desc, TUSB_CLASS_HID); - p_hid->report_size = p_endpoint_desc->wMaxPacketSize.size; // TODO get size from report descriptor - p_hid->interface_number = interface_number; - - ASSERT (pipehandle_is_valid(p_hid->pipe_hdl), TUSB_ERROR_HCD_FAILED); - - return TUSB_ERROR_NONE; -} - -static inline void hidh_interface_close(uint8_t dev_addr, hidh_interface_info_t *p_hid) ATTR_ALWAYS_INLINE; -static inline void hidh_interface_close(uint8_t dev_addr, hidh_interface_info_t *p_hid) -{ - (void) hcd_pipe_close(p_hid->pipe_hdl); - memclr_(p_hid, sizeof(hidh_interface_info_t)); -} - -// called from public API need to validate parameters -tusb_error_t hidh_interface_get_report(uint8_t dev_addr, void * report, hidh_interface_info_t *p_hid) ATTR_ALWAYS_INLINE; -tusb_error_t hidh_interface_get_report(uint8_t dev_addr, void * report, hidh_interface_info_t *p_hid) -{ - //------------- parameters validation -------------// - // TODO change to use is configured function - ASSERT_INT (TUSB_DEVICE_STATE_CONFIGURED, tusbh_device_get_state(dev_addr), TUSB_ERROR_DEVICE_NOT_READY); - ASSERT_PTR (report, TUSB_ERROR_INVALID_PARA); - ASSERT_FALSE(hcd_pipe_is_busy(p_hid->pipe_hdl), TUSB_ERROR_INTERFACE_IS_BUSY); - - ASSERT_STATUS( hcd_pipe_xfer(p_hid->pipe_hdl, report, p_hid->report_size, true) ) ; - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// KEYBOARD -//--------------------------------------------------------------------+ -#if TUSB_CFG_HOST_HID_KEYBOARD - -#define EXPAND_KEYCODE_TO_ASCII(keycode, ascii, shift_modified) \ - [0][keycode] = ascii,\ - [1][keycode] = shift_modified,\ - -// TODO size of table should be a macro for application to check boundary -uint8_t const hid_keycode_to_ascii_tbl[2][128] = -{ - HID_KEYCODE_TABLE(EXPAND_KEYCODE_TO_ASCII) -}; - -STATIC_VAR hidh_interface_info_t keyboardh_data[TUSB_CFG_HOST_DEVICE_MAX]; // does not have addr0, index = dev_address-1 - -//------------- KEYBOARD PUBLIC API (parameter validation required) -------------// -bool tusbh_hid_keyboard_is_mounted(uint8_t dev_addr) -{ - return tusbh_device_is_configured(dev_addr) && pipehandle_is_valid(keyboardh_data[dev_addr-1].pipe_hdl); -} - -tusb_error_t tusbh_hid_keyboard_get_report(uint8_t dev_addr, void* report) -{ - return hidh_interface_get_report(dev_addr, report, &keyboardh_data[dev_addr-1]); -} - -bool tusbh_hid_keyboard_is_busy(uint8_t dev_addr) -{ - return tusbh_hid_keyboard_is_mounted(dev_addr) && - hcd_pipe_is_busy( keyboardh_data[dev_addr-1].pipe_hdl ); -} - -#endif - -//--------------------------------------------------------------------+ -// MOUSE -//--------------------------------------------------------------------+ -#if TUSB_CFG_HOST_HID_MOUSE - -STATIC_VAR hidh_interface_info_t mouseh_data[TUSB_CFG_HOST_DEVICE_MAX]; // does not have addr0, index = dev_address-1 - -//------------- Public API -------------// -bool tusbh_hid_mouse_is_mounted(uint8_t dev_addr) -{ - return tusbh_device_is_configured(dev_addr) && pipehandle_is_valid(mouseh_data[dev_addr-1].pipe_hdl); -} - -bool tusbh_hid_mouse_is_busy(uint8_t dev_addr) -{ - return tusbh_hid_mouse_is_mounted(dev_addr) && - hcd_pipe_is_busy( mouseh_data[dev_addr-1].pipe_hdl ); -} - -tusb_error_t tusbh_hid_mouse_get_report(uint8_t dev_addr, void * report) -{ - return hidh_interface_get_report(dev_addr, report, &mouseh_data[dev_addr-1]); -} - -#endif - -//--------------------------------------------------------------------+ -// GENERIC -//--------------------------------------------------------------------+ -#if TUSB_CFG_HOST_HID_GENERIC - -//STATIC_ struct { -// hidh_interface_info_t -//} generic_data[TUSB_CFG_HOST_DEVICE_MAX]; - -#endif - -//--------------------------------------------------------------------+ -// CLASS-USBH API (don't require to verify parameters) -//--------------------------------------------------------------------+ -void hidh_init(void) -{ -#if TUSB_CFG_HOST_HID_KEYBOARD - memclr_(&keyboardh_data, sizeof(hidh_interface_info_t)*TUSB_CFG_HOST_DEVICE_MAX); -#endif - -#if TUSB_CFG_HOST_HID_MOUSE - memclr_(&mouseh_data, sizeof(hidh_interface_info_t)*TUSB_CFG_HOST_DEVICE_MAX); -#endif - -#if TUSB_CFG_HOST_HID_GENERIC - hidh_generic_init(); -#endif -} - -#if 0 -uint8_t report_descriptor[256] TUSB_CFG_ATTR_USBRAM; -#endif - -tusb_error_t hidh_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t const *p_interface_desc, uint16_t *p_length) -{ - tusb_error_t error; - uint8_t const *p_desc = (uint8_t const *) p_interface_desc; - - //------------- HID descriptor -------------// - p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; - tusb_hid_descriptor_hid_t const *p_desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; - ASSERT_INT(HID_DESC_TYPE_HID, p_desc_hid->bDescriptorType, TUSB_ERROR_INVALID_PARA); - - //------------- Endpoint Descriptor -------------// - p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; - tusb_descriptor_endpoint_t const * p_endpoint_desc = (tusb_descriptor_endpoint_t const *) p_desc; - ASSERT_INT(TUSB_DESC_TYPE_ENDPOINT, p_endpoint_desc->bDescriptorType, TUSB_ERROR_INVALID_PARA); - - OSAL_SUBTASK_BEGIN - - //------------- SET IDLE (0) request -------------// - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE), - HID_REQUEST_CONTROL_SET_IDLE, 0, p_interface_desc->bInterfaceNumber, - 0, NULL ), - error - ); - -#if 0 - //------------- Get Report Descriptor TODO HID parser -------------// - if ( p_desc_hid->bNumDescriptors ) - { - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_INTERFACE), - TUSB_REQUEST_GET_DESCRIPTOR, (p_desc_hid->bReportType << 8), 0, - p_desc_hid->wReportLength, report_descriptor ), - error - ); - // if error in getting report descriptor --> treating like there is none - } -#endif - - if ( HID_SUBCLASS_BOOT == p_interface_desc->bInterfaceSubClass ) - { - #if TUSB_CFG_HOST_HID_KEYBOARD - if ( HID_PROTOCOL_KEYBOARD == p_interface_desc->bInterfaceProtocol) - { - SUBTASK_ASSERT_STATUS ( hidh_interface_open(dev_addr, p_interface_desc->bInterfaceNumber, p_endpoint_desc, &keyboardh_data[dev_addr-1]) ); - tusbh_hid_keyboard_mounted_cb(dev_addr); - } else - #endif - - #if TUSB_CFG_HOST_HID_MOUSE - if ( HID_PROTOCOL_MOUSE == p_interface_desc->bInterfaceProtocol) - { - SUBTASK_ASSERT_STATUS ( hidh_interface_open(dev_addr, p_interface_desc->bInterfaceNumber, p_endpoint_desc, &mouseh_data[dev_addr-1]) ); - tusbh_hid_mouse_mounted_cb(dev_addr); - } else - #endif - - { - SUBTASK_EXIT(TUSB_ERROR_HIDH_NOT_SUPPORTED_PROTOCOL); // exit & restart task - } - }else - { - SUBTASK_EXIT(TUSB_ERROR_HIDH_NOT_SUPPORTED_SUBCLASS); // exit & restart task - } - - *p_length = sizeof(tusb_descriptor_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + sizeof(tusb_descriptor_endpoint_t); - - OSAL_SUBTASK_END -} - -void hidh_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes) -{ -#if TUSB_CFG_HOST_HID_KEYBOARD - if ( pipehandle_is_equal(pipe_hdl, keyboardh_data[pipe_hdl.dev_addr-1].pipe_hdl) ) - { - tusbh_hid_keyboard_isr(pipe_hdl.dev_addr, event); - return; - } -#endif - -#if TUSB_CFG_HOST_HID_MOUSE - if ( pipehandle_is_equal(pipe_hdl, mouseh_data[pipe_hdl.dev_addr-1].pipe_hdl) ) - { - tusbh_hid_mouse_isr(pipe_hdl.dev_addr, event); - return; - } -#endif - -#if TUSB_CFG_HOST_HID_GENERIC - -#endif -} - -void hidh_close(uint8_t dev_addr) -{ -#if TUSB_CFG_HOST_HID_KEYBOARD - if ( pipehandle_is_valid( keyboardh_data[dev_addr-1].pipe_hdl ) ) - { - hidh_interface_close(dev_addr, &keyboardh_data[dev_addr-1]); - tusbh_hid_keyboard_unmounted_cb(dev_addr); - } -#endif - -#if TUSB_CFG_HOST_HID_MOUSE - if( pipehandle_is_valid( mouseh_data[dev_addr-1].pipe_hdl ) ) - { - hidh_interface_close(dev_addr, &mouseh_data[dev_addr-1]); - tusbh_hid_mouse_unmounted_cb( dev_addr ); - } -#endif - -#if TUSB_CFG_HOST_HID_GENERIC - hidh_generic_close(dev_addr); -#endif -} - - - -#endif +/**************************************************************************/ +/*! + @file hid_host.c + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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 holders 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 ''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 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 tinyusb stack. +*/ +/**************************************************************************/ + +#include "tusb_option.h" + +#if (MODE_HOST_SUPPORTED && HOST_CLASS_HID) + +#define _TINY_USB_SOURCE_FILE_ +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "common/common.h" +#include "hid_host.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// HID Interface common functions +//--------------------------------------------------------------------+ +static inline tusb_error_t hidh_interface_open(uint8_t dev_addr, uint8_t interface_number, tusb_descriptor_endpoint_t const *p_endpoint_desc, hidh_interface_info_t *p_hid) ATTR_ALWAYS_INLINE; +static inline tusb_error_t hidh_interface_open(uint8_t dev_addr, uint8_t interface_number, tusb_descriptor_endpoint_t const *p_endpoint_desc, hidh_interface_info_t *p_hid) +{ + p_hid->pipe_hdl = hcd_pipe_open(dev_addr, p_endpoint_desc, TUSB_CLASS_HID); + p_hid->report_size = p_endpoint_desc->wMaxPacketSize.size; // TODO get size from report descriptor + p_hid->interface_number = interface_number; + + ASSERT (pipehandle_is_valid(p_hid->pipe_hdl), TUSB_ERROR_HCD_FAILED); + + return TUSB_ERROR_NONE; +} + +static inline void hidh_interface_close(uint8_t dev_addr, hidh_interface_info_t *p_hid) ATTR_ALWAYS_INLINE; +static inline void hidh_interface_close(uint8_t dev_addr, hidh_interface_info_t *p_hid) +{ + (void) hcd_pipe_close(p_hid->pipe_hdl); + memclr_(p_hid, sizeof(hidh_interface_info_t)); +} + +// called from public API need to validate parameters +tusb_error_t hidh_interface_get_report(uint8_t dev_addr, void * report, hidh_interface_info_t *p_hid) ATTR_ALWAYS_INLINE; +tusb_error_t hidh_interface_get_report(uint8_t dev_addr, void * report, hidh_interface_info_t *p_hid) +{ + //------------- parameters validation -------------// + // TODO change to use is configured function + ASSERT_INT (TUSB_DEVICE_STATE_CONFIGURED, tusbh_device_get_state(dev_addr), TUSB_ERROR_DEVICE_NOT_READY); + ASSERT_PTR (report, TUSB_ERROR_INVALID_PARA); + ASSERT_FALSE(hcd_pipe_is_busy(p_hid->pipe_hdl), TUSB_ERROR_INTERFACE_IS_BUSY); + + ASSERT_STATUS( hcd_pipe_xfer(p_hid->pipe_hdl, report, p_hid->report_size, true) ) ; + + return TUSB_ERROR_NONE; +} + +//--------------------------------------------------------------------+ +// KEYBOARD +//--------------------------------------------------------------------+ +#if TUSB_CFG_HOST_HID_KEYBOARD + +#define EXPAND_KEYCODE_TO_ASCII(keycode, ascii, shift_modified) \ + [0][keycode] = ascii,\ + [1][keycode] = shift_modified,\ + +// TODO size of table should be a macro for application to check boundary +uint8_t const hid_keycode_to_ascii_tbl[2][128] = +{ + HID_KEYCODE_TABLE(EXPAND_KEYCODE_TO_ASCII) +}; + +STATIC_VAR hidh_interface_info_t keyboardh_data[TUSB_CFG_HOST_DEVICE_MAX]; // does not have addr0, index = dev_address-1 + +//------------- KEYBOARD PUBLIC API (parameter validation required) -------------// +bool tusbh_hid_keyboard_is_mounted(uint8_t dev_addr) +{ + return tusbh_device_is_configured(dev_addr) && pipehandle_is_valid(keyboardh_data[dev_addr-1].pipe_hdl); +} + +tusb_error_t tusbh_hid_keyboard_get_report(uint8_t dev_addr, void* p_report) +{ + return hidh_interface_get_report(dev_addr, p_report, &keyboardh_data[dev_addr-1]); +} + +bool tusbh_hid_keyboard_is_busy(uint8_t dev_addr) +{ + return tusbh_hid_keyboard_is_mounted(dev_addr) && + hcd_pipe_is_busy( keyboardh_data[dev_addr-1].pipe_hdl ); +} + +#endif + +//--------------------------------------------------------------------+ +// MOUSE +//--------------------------------------------------------------------+ +#if TUSB_CFG_HOST_HID_MOUSE + +STATIC_VAR hidh_interface_info_t mouseh_data[TUSB_CFG_HOST_DEVICE_MAX]; // does not have addr0, index = dev_address-1 + +//------------- Public API -------------// +bool tusbh_hid_mouse_is_mounted(uint8_t dev_addr) +{ + return tusbh_device_is_configured(dev_addr) && pipehandle_is_valid(mouseh_data[dev_addr-1].pipe_hdl); +} + +bool tusbh_hid_mouse_is_busy(uint8_t dev_addr) +{ + return tusbh_hid_mouse_is_mounted(dev_addr) && + hcd_pipe_is_busy( mouseh_data[dev_addr-1].pipe_hdl ); +} + +tusb_error_t tusbh_hid_mouse_get_report(uint8_t dev_addr, void * report) +{ + return hidh_interface_get_report(dev_addr, report, &mouseh_data[dev_addr-1]); +} + +#endif + +//--------------------------------------------------------------------+ +// GENERIC +//--------------------------------------------------------------------+ +#if TUSB_CFG_HOST_HID_GENERIC + +//STATIC_ struct { +// hidh_interface_info_t +//} generic_data[TUSB_CFG_HOST_DEVICE_MAX]; + +#endif + +//--------------------------------------------------------------------+ +// CLASS-USBH API (don't require to verify parameters) +//--------------------------------------------------------------------+ +void hidh_init(void) +{ +#if TUSB_CFG_HOST_HID_KEYBOARD + memclr_(&keyboardh_data, sizeof(hidh_interface_info_t)*TUSB_CFG_HOST_DEVICE_MAX); +#endif + +#if TUSB_CFG_HOST_HID_MOUSE + memclr_(&mouseh_data, sizeof(hidh_interface_info_t)*TUSB_CFG_HOST_DEVICE_MAX); +#endif + +#if TUSB_CFG_HOST_HID_GENERIC + hidh_generic_init(); +#endif +} + +#if 0 +uint8_t report_descriptor[256] TUSB_CFG_ATTR_USBRAM; +#endif + +tusb_error_t hidh_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t const *p_interface_desc, uint16_t *p_length) +{ + tusb_error_t error; + uint8_t const *p_desc = (uint8_t const *) p_interface_desc; + + //------------- HID descriptor -------------// + p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; + tusb_hid_descriptor_hid_t const *p_desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; + ASSERT_INT(HID_DESC_TYPE_HID, p_desc_hid->bDescriptorType, TUSB_ERROR_INVALID_PARA); + + //------------- Endpoint Descriptor -------------// + p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; + tusb_descriptor_endpoint_t const * p_endpoint_desc = (tusb_descriptor_endpoint_t const *) p_desc; + ASSERT_INT(TUSB_DESC_TYPE_ENDPOINT, p_endpoint_desc->bDescriptorType, TUSB_ERROR_INVALID_PARA); + + OSAL_SUBTASK_BEGIN + + //------------- SET IDLE (0) request -------------// + OSAL_SUBTASK_INVOKED_AND_WAIT( + usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE), + HID_REQUEST_CONTROL_SET_IDLE, 0, p_interface_desc->bInterfaceNumber, + 0, NULL ), + error + ); + +#if 0 + //------------- Get Report Descriptor TODO HID parser -------------// + if ( p_desc_hid->bNumDescriptors ) + { + OSAL_SUBTASK_INVOKED_AND_WAIT( + usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_INTERFACE), + TUSB_REQUEST_GET_DESCRIPTOR, (p_desc_hid->bReportType << 8), 0, + p_desc_hid->wReportLength, report_descriptor ), + error + ); + // if error in getting report descriptor --> treating like there is none + } +#endif + + if ( HID_SUBCLASS_BOOT == p_interface_desc->bInterfaceSubClass ) + { + #if TUSB_CFG_HOST_HID_KEYBOARD + if ( HID_PROTOCOL_KEYBOARD == p_interface_desc->bInterfaceProtocol) + { + SUBTASK_ASSERT_STATUS ( hidh_interface_open(dev_addr, p_interface_desc->bInterfaceNumber, p_endpoint_desc, &keyboardh_data[dev_addr-1]) ); + tusbh_hid_keyboard_mounted_cb(dev_addr); + } else + #endif + + #if TUSB_CFG_HOST_HID_MOUSE + if ( HID_PROTOCOL_MOUSE == p_interface_desc->bInterfaceProtocol) + { + SUBTASK_ASSERT_STATUS ( hidh_interface_open(dev_addr, p_interface_desc->bInterfaceNumber, p_endpoint_desc, &mouseh_data[dev_addr-1]) ); + tusbh_hid_mouse_mounted_cb(dev_addr); + } else + #endif + + { + SUBTASK_EXIT(TUSB_ERROR_HIDH_NOT_SUPPORTED_PROTOCOL); // exit & restart task + } + }else + { + SUBTASK_EXIT(TUSB_ERROR_HIDH_NOT_SUPPORTED_SUBCLASS); // exit & restart task + } + + *p_length = sizeof(tusb_descriptor_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + sizeof(tusb_descriptor_endpoint_t); + + OSAL_SUBTASK_END +} + +void hidh_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes) +{ +#if TUSB_CFG_HOST_HID_KEYBOARD + if ( pipehandle_is_equal(pipe_hdl, keyboardh_data[pipe_hdl.dev_addr-1].pipe_hdl) ) + { + tusbh_hid_keyboard_isr(pipe_hdl.dev_addr, event); + return; + } +#endif + +#if TUSB_CFG_HOST_HID_MOUSE + if ( pipehandle_is_equal(pipe_hdl, mouseh_data[pipe_hdl.dev_addr-1].pipe_hdl) ) + { + tusbh_hid_mouse_isr(pipe_hdl.dev_addr, event); + return; + } +#endif + +#if TUSB_CFG_HOST_HID_GENERIC + +#endif +} + +void hidh_close(uint8_t dev_addr) +{ +#if TUSB_CFG_HOST_HID_KEYBOARD + if ( pipehandle_is_valid( keyboardh_data[dev_addr-1].pipe_hdl ) ) + { + hidh_interface_close(dev_addr, &keyboardh_data[dev_addr-1]); + tusbh_hid_keyboard_unmounted_cb(dev_addr); + } +#endif + +#if TUSB_CFG_HOST_HID_MOUSE + if( pipehandle_is_valid( mouseh_data[dev_addr-1].pipe_hdl ) ) + { + hidh_interface_close(dev_addr, &mouseh_data[dev_addr-1]); + tusbh_hid_mouse_unmounted_cb( dev_addr ); + } +#endif + +#if TUSB_CFG_HOST_HID_GENERIC + hidh_generic_close(dev_addr); +#endif +} + + + +#endif diff --git a/tinyusb/class/hid_host.h b/tinyusb/class/hid_host.h index 0c84bfbc3..f282621e9 100644 --- a/tinyusb/class/hid_host.h +++ b/tinyusb/class/hid_host.h @@ -1,119 +1,213 @@ -/**************************************************************************/ -/*! - @file hid_host.h - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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 holders 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 ''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 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 tinyusb stack. -*/ -/**************************************************************************/ - -/** \ingroup TBD - * \defgroup TBD - * \brief TBD - * - * @{ - */ - -#ifndef _TUSB_HID_HOST_H_ -#define _TUSB_HID_HOST_H_ - -#include "common/common.h" -#include "host/usbh.h" -#include "hid.h" - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// KEYBOARD Application API -//--------------------------------------------------------------------+ -extern uint8_t const hid_keycode_to_ascii_tbl[2][128]; // TODO used weak attr if build failed without KEYBOARD enabled - -bool tusbh_hid_keyboard_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; -bool tusbh_hid_keyboard_is_busy(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; -tusb_error_t tusbh_hid_keyboard_get_report(uint8_t dev_addr, void * report) /*ATTR_WARN_UNUSED_RESULT*/; - -//------------- Application Callback -------------// -void tusbh_hid_keyboard_isr(uint8_t dev_addr, tusb_event_t event); -void tusbh_hid_keyboard_mounted_cb(uint8_t dev_addr); -void tusbh_hid_keyboard_unmounted_cb(uint8_t dev_addr); - -//--------------------------------------------------------------------+ -// MOUSE Application API -//--------------------------------------------------------------------+ -bool tusbh_hid_mouse_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; -bool tusbh_hid_mouse_is_busy(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; -tusb_error_t tusbh_hid_mouse_get_report(uint8_t dev_addr, void* report) /*ATTR_WARN_UNUSED_RESULT*/; - -//------------- Application Callback -------------// -void tusbh_hid_mouse_isr(uint8_t dev_addr, tusb_event_t event); -void tusbh_hid_mouse_mounted_cb(uint8_t dev_addr); -void tusbh_hid_mouse_unmounted_cb(uint8_t dev_addr); - -//--------------------------------------------------------------------+ -// GENERIC Application API -//--------------------------------------------------------------------+ -bool tusbh_hid_generic_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; -tusb_error_t tusbh_hid_generic_get_report(uint8_t dev_addr, void* report, bool int_on_complete) ATTR_WARN_UNUSED_RESULT; -tusb_error_t tusbh_hid_generic_set_report(uint8_t dev_addr, void* report, bool int_on_complete) ATTR_WARN_UNUSED_RESULT; -tusb_interface_status_t tusbh_hid_generic_get_status(uint8_t dev_addr) ATTR_WARN_UNUSED_RESULT; -tusb_interface_status_t tusbh_hid_generic_set_status(uint8_t dev_addr) ATTR_WARN_UNUSED_RESULT; - -//------------- Application Callback -------------// -void tusbh_hid_generic_isr(uint8_t dev_addr, tusb_event_t event); - -//--------------------------------------------------------------------+ -// USBH-CLASS DRIVER API -//--------------------------------------------------------------------+ -#ifdef _TINY_USB_SOURCE_FILE_ - -typedef struct { - pipe_handle_t pipe_hdl; - uint16_t report_size; - uint8_t interface_number; -}hidh_interface_info_t; - -void hidh_init(void); -tusb_error_t hidh_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t const *p_interface_desc, uint16_t *p_length) ATTR_WARN_UNUSED_RESULT; -void hidh_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes); -void hidh_close(uint8_t dev_addr); - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _TUSB_HID_HOST_H_ */ - -/** @} */ +/**************************************************************************/ +/*! + @file hid_host.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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 holders 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 ''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 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 tinyusb stack. +*/ +/**************************************************************************/ + +/** \addtogroup ClassDriver_HID + * @{ */ + +#ifndef _TUSB_HID_HOST_H_ +#define _TUSB_HID_HOST_H_ + +#include "common/common.h" +#include "host/usbh.h" +#include "hid.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** \defgroup hid_keyboard Keyboard + * The interface API includes status checking function, data transferring function and callback functions + * @{ */ +//--------------------------------------------------------------------+ +// KEYBOARD Application API +//--------------------------------------------------------------------+ +extern uint8_t const hid_keycode_to_ascii_tbl[2][128]; // TODO used weak attr if build failed without KEYBOARD enabled + +/** \brief Check if device supports Keyboard interface or not + * \param[in] dev_addr device address + * \retval true if device supports Keyboard interface + * \retval false if device does not support Keyboard interface or is not mounted + */ +bool tusbh_hid_keyboard_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; + +/** \brief Check if the interface is currently busy or not + * \param[in] dev_addr device address + * \retval true if the interface is busy meaning the stack is still transferring/waiting data from/to device + * \retval false if the interface is not busy meaning the stack successfully transferred data from/to device + * \note This function is primarily used for polling/waiting result after \ref tusbh_hid_keyboard_get_report. + * Alternatively, asynchronous event API can be used + */ +bool tusbh_hid_keyboard_is_busy(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; + +/** \brief Perform a get report from Keyboard interface + * \param[in] dev_addr device address + * \param[in,out] p_report address that is used to store data from device. Must be accessible by usb controller (see \ref TUSB_CFG_ATTR_USBRAM) + * \returns \ref tusb_error_t type to indicate success or error condition. + * \retval TUSB_ERROR_NONE on success + * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device + * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) + * \retval TUSB_ERROR_INVALID_PARA if inputs parameter are not correct + * \note This function is non-blocking and returns immediately. The result of usb transfer will be reported by the interface's callback function + */ +tusb_error_t tusbh_hid_keyboard_get_report(uint8_t dev_addr, void * p_report) /*ATTR_WARN_UNUSED_RESULT*/; + +//------------- Application Callback -------------// +/** \brief Callback function that is invoked when an transferring event occurred + * \param[in] dev_addr Address of device + * \param[in] event an value from \ref tusb_event_t + * \note event can be one of following + * - TUSB_EVENT_XFER_COMPLETE : previously scheduled transfer completes successfully. + * - TUSB_EVENT_XFER_ERROR : previously scheduled transfer encountered a transaction error. + * - TUSB_EVENT_XFER_STALLED : previously scheduled transfer is stalled by device. + * \note Application should schedule the next report by calling \ref tusbh_hid_keyboard_get_report within this callback + */ +void tusbh_hid_keyboard_isr(uint8_t dev_addr, tusb_event_t event); + +/** \brief Callback function that will be invoked when a device with Keyboard interface is mounted + * \param[in] dev_addr Address of newly mounted device + * \note This callback should be used by Application to set-up interface-related data + */ +void tusbh_hid_keyboard_mounted_cb(uint8_t dev_addr); + +/** \brief Callback function that will be invoked when a device with Keyboard interface is unmounted + * \param[in] dev_addr Address of newly unmounted device + * \note This callback should be used by Application to tear-down interface-related data + */ +void tusbh_hid_keyboard_unmounted_cb(uint8_t dev_addr); +/** @} */ + +/** \defgroup hid_mouse Mouse + * The interface API includes status checking function, data transferring function and callback functions + * @{ */ +//--------------------------------------------------------------------+ +// MOUSE Application API +//--------------------------------------------------------------------+ +/** \brief Check if device supports Mouse interface or not + * \param[in] dev_addr device address + * \retval true if device supports Mouse interface + * \retval false if device does not support Mouse interface or is not mounted + */ +bool tusbh_hid_mouse_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; + +/** \brief Check if the interface is currently busy or not + * \param[in] dev_addr device address + * \retval true if the interface is busy meaning the stack is still transferring/waiting data from/to device + * \retval false if the interface is not busy meaning the stack successfully transferred data from/to device + * \note This function is primarily used for polling/waiting result after \ref tusbh_hid_mouse_get_report. + * Alternatively, asynchronous event API can be used + */ +bool tusbh_hid_mouse_is_busy(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; + +/** \brief Perform a get report from Mouse interface + * \param[in] dev_addr device address + * \param[in,out] p_report address that is used to store data from device. Must be accessible by usb controller (see \ref TUSB_CFG_ATTR_USBRAM) + * \returns \ref tusb_error_t type to indicate success or error condition. + * \retval TUSB_ERROR_NONE on success + * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device + * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) + * \retval TUSB_ERROR_INVALID_PARA if inputs parameter are not correct + * \note This function is non-blocking and returns immediately. The result of usb transfer will be reported by the interface's callback function + */ +tusb_error_t tusbh_hid_mouse_get_report(uint8_t dev_addr, void* p_report) /*ATTR_WARN_UNUSED_RESULT*/; + +//------------- Application Callback -------------// +/** \brief Callback function that is invoked when an transferring event occurred + * \param[in] dev_addr Address of device + * \param[in] event an value from \ref tusb_event_t + * \note event can be one of following + * - TUSB_EVENT_XFER_COMPLETE : previously scheduled transfer completes successfully. + * - TUSB_EVENT_XFER_ERROR : previously scheduled transfer encountered a transaction error. + * - TUSB_EVENT_XFER_STALLED : previously scheduled transfer is stalled by device. + * \note Application should schedule the next report by calling \ref tusbh_hid_mouse_get_report within this callback + */ +void tusbh_hid_mouse_isr(uint8_t dev_addr, tusb_event_t event); + +/** \brief Callback function that will be invoked when a device with Mouse interface is mounted + * \param[in] dev_addr Address of newly mounted device + * \note This callback should be used by Application to set-up interface-related data + */ +void tusbh_hid_mouse_mounted_cb(uint8_t dev_addr); + +/** \brief Callback function that will be invoked when a device with Mouse interface is unmounted + * \param[in] dev_addr Address of newly unmounted device + * \note This callback should be used by Application to tear-down interface-related data + */ +void tusbh_hid_mouse_unmounted_cb(uint8_t dev_addr); +/** @} */ + +/** \defgroup hid_generic Generic (not supported yet) + * The interface API includes status checking function, data transferring function and callback functions + * @{ */ +//--------------------------------------------------------------------+ +// GENERIC Application API +//--------------------------------------------------------------------+ +bool tusbh_hid_generic_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT; +tusb_error_t tusbh_hid_generic_get_report(uint8_t dev_addr, void* p_report, bool int_on_complete) ATTR_WARN_UNUSED_RESULT; +tusb_error_t tusbh_hid_generic_set_report(uint8_t dev_addr, void* p_report, bool int_on_complete) ATTR_WARN_UNUSED_RESULT; +tusb_interface_status_t tusbh_hid_generic_get_status(uint8_t dev_addr) ATTR_WARN_UNUSED_RESULT; +tusb_interface_status_t tusbh_hid_generic_set_status(uint8_t dev_addr) ATTR_WARN_UNUSED_RESULT; + +//------------- Application Callback -------------// +void tusbh_hid_generic_isr(uint8_t dev_addr, tusb_event_t event); +/** @} */ + +//--------------------------------------------------------------------+ +// USBH-CLASS DRIVER API +//--------------------------------------------------------------------+ +#ifdef _TINY_USB_SOURCE_FILE_ + +typedef struct { + pipe_handle_t pipe_hdl; + uint16_t report_size; + uint8_t interface_number; +}hidh_interface_info_t; + +void hidh_init(void); +tusb_error_t hidh_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t const *p_interface_desc, uint16_t *p_length) ATTR_WARN_UNUSED_RESULT; +void hidh_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes); +void hidh_close(uint8_t dev_addr); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_HID_HOST_H_ */ + +/** @} */ diff --git a/tinyusb/doxygen/configuration.h b/tinyusb/doxygen/configuration.h new file mode 100644 index 000000000..8f2d8bd34 --- /dev/null +++ b/tinyusb/doxygen/configuration.h @@ -0,0 +1,39 @@ +/** \addtogroup group_configuration + * @{ */ + +/** + USB controller in MCU often has limited access to specific RAM section. The Stack will use this macro to place internal variables + into the USB RAM section as follows. if your mcu's usb controller has no such limit, define TUSB_CFG_ATTR_USBRAM as empty macro. + + @code + uint8_t tinyusb_data[10] TUSB_CFG_ATTR_USBRAM; + @endcode + */ +#define TUSB_CFG_ATTR_USBRAM + + +/** \defgroup TUSB_CFG_HOST Host + * @{ */ + +/// Maximum number of device host stack can manage +/// - If hub class is not enabled, set this equal to number of controllers in host mode +/// - if hub class is enabled, make sure hub is also counted +#define TUSB_CFG_HOST_DEVICE_MAX + +/// Buffer size used for getting device configuration descriptor. You may want to increase this from default +/// to support lengthy composite device especially with Audio or Video class +#define TUSB_CFG_HOST_ENUM_BUFFER_SIZE + +#define TUSB_CFG_HOST_HUB ///< Enable Hub Class +#define TUSB_CFG_HOST_HID_KEYBOARD ///< Enable HID Class for Keyboard +#define TUSB_CFG_HOST_HID_MOUSE ///< Enable HID Class for Mouse +#define TUSB_CFG_HOST_HID_GENERIC ///< Enable HID Class for Generic (not supported yet) +#define TUSB_CFG_HOST_MSC ///< Enable Mass Storage Class (SCSI subclass only) +#define TUSB_CFG_HOST_CDC ///< Enable Virtual Serial (Communication Device Class) +#define TUSB_CFG_HOST_CDC_RNDIS ///< Enable Remote Network Device (require TUSB_CFG_HOST_CDC to be enabled) + +/** @} */ // group Host + + + +/** @} */ diff --git a/tinyusb/doxygen/overview.md b/tinyusb/doxygen/overview.md deleted file mode 100644 index 695690143..000000000 --- a/tinyusb/doxygen/overview.md +++ /dev/null @@ -1,3 +0,0 @@ -# What is tinyUSB - -![tinyUSB diagram](overview.png) diff --git a/tinyusb/hal/hal_lpc43xx.c b/tinyusb/hal/hal_lpc43xx.c index 6b23ca9a2..2fe019d09 100644 --- a/tinyusb/hal/hal_lpc43xx.c +++ b/tinyusb/hal/hal_lpc43xx.c @@ -1,123 +1,123 @@ -/**************************************************************************/ -/*! - @file hal_lpc43xx.c - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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 holders 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 ''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 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 tinyusb stack. -*/ -/**************************************************************************/ - -#include "common/common.h" -#include "hal.h" - -#if MCU == MCU_LPC43XX - -#include "lpc43xx_cgu.h" -#include "lpc43xx_scu.h" - -enum { - LPC43XX_USBMODE_DEVICE = 2, - LPC43XX_USBMODE_HOST = 3 -}; - -enum { - LPC43XX_USBMODE_VBUS_LOW = 0, - LPC43XX_USBMODE_VBUS_HIGH = 1 -}; - -tusb_error_t hal_init(void) -{ - //------------- USB0 Clock -------------// -#if TUSB_CFG_CONTROLLER0_MODE - CGU_EnableEntity(CGU_CLKSRC_PLL0, DISABLE); /* Disable PLL first */ - ASSERT_INT( CGU_ERROR_SUCCESS, CGU_SetPLL0(), TUSB_ERROR_FAILED); /* the usb core require output clock = 480MHz */ - CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_CLKSRC_PLL0); - CGU_EnableEntity(CGU_CLKSRC_PLL0, ENABLE); /* Enable PLL after all setting is done */ - LPC_CREG->CREG0 &= ~(1<<5); /* Turn on the phy */ - - // reset controller & set role - #if TUSB_CFG_CONTROLLER0_MODE & TUSB_MODE_HOST - hcd_controller_reset(0); // TODO where to place prototype - LPC_USB0->USBMODE_H = LPC43XX_USBMODE_HOST | (LPC43XX_USBMODE_VBUS_HIGH << 5); - #else // TODO OTG -// dcd_controller_reset(0); -// LPC_USB0->USBMODE_D = LPC43XX_USBMODE_DEVICE; -// LPC_USB0->OTGSC = (1<<3) | (1<<0) /*| (1<<16)| (1<<24)| (1<<25)| (1<<26)| (1<<27)| (1<<28)| (1<<29)| (1<<30)*/; -// LPC_USB0->PORTSC1_D |= (1<<24); // force full speed -// dcd_controller_connect(0); - #endif - - hal_interrupt_enable(0); -#endif - - //------------- USB1 Clock, only use on-chip FS PHY -------------// -#if TUSB_CFG_CONTROLLER1_MODE - // TODO confirm whether device mode require P2_5 or not - scu_pinmux(0x2, 5, MD_PLN | MD_EZI | MD_ZI, FUNC2); // USB1_VBUS monitor presence, must be high for bus reset occur - - /* connect CLK_USB1 to 60 MHz clock */ - CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_USB1); /* FIXME Run base BASE_USB1_CLK clock from PLL1 (assume PLL1 is 60 MHz, no division required) */ - //LPC_CREG->CREG0 &= ~(1<<5); /* Turn on the phy */ - LPC_SCU->SFSUSB = (TUSB_CFG_CONTROLLER1_MODE & TUSB_MODE_HOST) ? 0x16 : 0x12; // enable USB1 with on-chip FS PHY - - #if TUSB_CFG_CONTROLLER1_MODE & TUSB_MODE_HOST - hcd_controller_reset(1); // TODO where to place prototype - LPC_USB1->USBMODE_H = LPC43XX_USBMODE_HOST | (LPC43XX_USBMODE_VBUS_HIGH << 5); - #else // TODO OTG -// dcd_controller_reset(1); - LPC_USB0->USBMODE_D = LPC43XX_USBMODE_DEVICE; - dcd_controller_connect(1); - #endif - - LPC_USB1->PORTSC1_D |= (1<<24); // TODO abtract, force port to fullspeed - - hal_interrupt_enable(1); -#endif - - return TUSB_ERROR_NONE; -} - -#if TUSB_CFG_CONTROLLER0_MODE -void USB0_IRQHandler(void) -{ - tusb_isr(0); -} -#endif - -#if TUSB_CFG_CONTROLLER1_MODE -void USB1_IRQHandler(void) -{ - tusb_isr(1); -} -#endif - -#endif +/**************************************************************************/ +/*! + @file hal_lpc43xx.c + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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 holders 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 ''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 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 tinyusb stack. +*/ +/**************************************************************************/ + +#include "common/common.h" +#include "hal.h" + +#if MCU == MCU_LPC43XX + +#include "lpc43xx_cgu.h" +#include "lpc43xx_scu.h" + +enum { + LPC43XX_USBMODE_DEVICE = 2, + LPC43XX_USBMODE_HOST = 3 +}; + +enum { + LPC43XX_USBMODE_VBUS_LOW = 0, + LPC43XX_USBMODE_VBUS_HIGH = 1 +}; + +tusb_error_t hal_init(void) +{ + //------------- USB0 Clock -------------// +#if TUSB_CFG_CONTROLLER_0_MODE + CGU_EnableEntity(CGU_CLKSRC_PLL0, DISABLE); /* Disable PLL first */ + ASSERT_INT( CGU_ERROR_SUCCESS, CGU_SetPLL0(), TUSB_ERROR_FAILED); /* the usb core require output clock = 480MHz */ + CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_CLKSRC_PLL0); + CGU_EnableEntity(CGU_CLKSRC_PLL0, ENABLE); /* Enable PLL after all setting is done */ + LPC_CREG->CREG0 &= ~(1<<5); /* Turn on the phy */ + + // reset controller & set role + #if TUSB_CFG_CONTROLLER_0_MODE & TUSB_MODE_HOST + hcd_controller_reset(0); // TODO where to place prototype + LPC_USB0->USBMODE_H = LPC43XX_USBMODE_HOST | (LPC43XX_USBMODE_VBUS_HIGH << 5); + #else // TODO OTG +// dcd_controller_reset(0); +// LPC_USB0->USBMODE_D = LPC43XX_USBMODE_DEVICE; +// LPC_USB0->OTGSC = (1<<3) | (1<<0) /*| (1<<16)| (1<<24)| (1<<25)| (1<<26)| (1<<27)| (1<<28)| (1<<29)| (1<<30)*/; +// LPC_USB0->PORTSC1_D |= (1<<24); // force full speed +// dcd_controller_connect(0); + #endif + + hal_interrupt_enable(0); +#endif + + //------------- USB1 Clock, only use on-chip FS PHY -------------// +#if TUSB_CFG_CONTROLLER_1_MODE + // TODO confirm whether device mode require P2_5 or not + scu_pinmux(0x2, 5, MD_PLN | MD_EZI | MD_ZI, FUNC2); // USB1_VBUS monitor presence, must be high for bus reset occur + + /* connect CLK_USB1 to 60 MHz clock */ + CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_USB1); /* FIXME Run base BASE_USB1_CLK clock from PLL1 (assume PLL1 is 60 MHz, no division required) */ + //LPC_CREG->CREG0 &= ~(1<<5); /* Turn on the phy */ + LPC_SCU->SFSUSB = (TUSB_CFG_CONTROLLER_1_MODE & TUSB_MODE_HOST) ? 0x16 : 0x12; // enable USB1 with on-chip FS PHY + + #if TUSB_CFG_CONTROLLER_1_MODE & TUSB_MODE_HOST + hcd_controller_reset(1); // TODO where to place prototype + LPC_USB1->USBMODE_H = LPC43XX_USBMODE_HOST | (LPC43XX_USBMODE_VBUS_HIGH << 5); + #else // TODO OTG +// dcd_controller_reset(1); + LPC_USB0->USBMODE_D = LPC43XX_USBMODE_DEVICE; + dcd_controller_connect(1); + #endif + + LPC_USB1->PORTSC1_D |= (1<<24); // TODO abtract, force port to fullspeed + + hal_interrupt_enable(1); +#endif + + return TUSB_ERROR_NONE; +} + +#if TUSB_CFG_CONTROLLER_0_MODE +void USB0_IRQHandler(void) +{ + tusb_isr(0); +} +#endif + +#if TUSB_CFG_CONTROLLER_1_MODE +void USB1_IRQHandler(void) +{ + tusb_isr(1); +} +#endif + +#endif diff --git a/tinyusb/host/ehci/ehci.c b/tinyusb/host/ehci/ehci.c index 378e5f736..428c2636f 100644 --- a/tinyusb/host/ehci/ehci.c +++ b/tinyusb/host/ehci/ehci.c @@ -1,1098 +1,1098 @@ -/**************************************************************************/ -/*! - @file ehci.c - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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 holders 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 ''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 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 tinyusb stack. -*/ -/**************************************************************************/ - -#include "common/common.h" - -#if MODE_HOST_SUPPORTED && (MCU == MCU_LPC43XX || MCU == MCU_LPC18XX) -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "hal/hal.h" -#include "osal/osal.h" -#include "common/timeout_timer.h" - -#include "../hcd.h" -#include "../usbh_hcd.h" -#include "ehci.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -STATIC_VAR ehci_data_t ehci_data TUSB_CFG_ATTR_USBRAM; - -#if EHCI_PERIODIC_LIST - - #if (TUSB_CFG_CONTROLLER0_MODE & TUSB_MODE_HOST) - ATTR_ALIGNED(4096) STATIC_VAR ehci_link_t period_frame_list0[EHCI_FRAMELIST_SIZE] TUSB_CFG_ATTR_USBRAM; - - #ifndef __ICCARM__ // IAR cannot able to determine the alignment with datalignment pragma - STATIC_ASSERT( ALIGN_OF(period_frame_list0) == 4096, "Period Framelist must be 4k alginment"); // validation - #endif - #endif - - #if (TUSB_CFG_CONTROLLER1_MODE & TUSB_MODE_HOST) - STATIC_VAR ehci_link_t period_frame_list1[EHCI_FRAMELIST_SIZE] ATTR_ALIGNED(4096) TUSB_CFG_ATTR_USBRAM; - - #ifndef __ICCARM__ // IAR cannot able to determine the alignment with datalignment pragma - STATIC_ASSERT( ALIGN_OF(period_frame_list1) == 4096, "Period Framelist must be 4k alginment"); // validation - #endif - #endif -#endif - -//------------- Validation -------------// -// TODO static assert for memory placement on some known MCU such as lpc43xx - -//--------------------------------------------------------------------+ -// PROTOTYPE -//--------------------------------------------------------------------+ -STATIC_ INLINE_ ehci_registers_t* get_operational_register(uint8_t hostid) ATTR_PURE ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT; -STATIC_ INLINE_ ehci_link_t* get_period_frame_list(uint8_t hostid) ATTR_PURE ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT; -STATIC_ INLINE_ uint8_t hostid_to_data_idx(uint8_t hostid) ATTR_ALWAYS_INLINE ATTR_CONST ATTR_WARN_UNUSED_RESULT; - -STATIC_ INLINE_ ehci_qhd_t* get_async_head(uint8_t hostid) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT; -STATIC_ INLINE_ ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT; - -STATIC_ INLINE_ ehci_qhd_t* get_control_qhd(uint8_t dev_addr) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT; -STATIC_ INLINE_ ehci_qtd_t* get_control_qtds(uint8_t dev_addr) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT; - -static inline uint8_t qhd_get_index(ehci_qhd_t const * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE; -static inline ehci_qhd_t* qhd_next(ehci_qhd_t const * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE; -static inline ehci_qhd_t* qhd_find_free (uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE; -static inline tusb_xfer_type_t qhd_get_xfer_type(ehci_qhd_t const * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE; -STATIC_ INLINE_ ehci_qhd_t* qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl) ATTR_PURE ATTR_ALWAYS_INLINE; -static inline pipe_handle_t qhd_create_pipe_handle(ehci_qhd_t const * p_qhd, tusb_xfer_type_t xfer_type) ATTR_PURE ATTR_ALWAYS_INLINE; -// determine if a queue head has bus-related error -static inline bool qhd_has_xact_error(ehci_qhd_t * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE; -static inline bool qhd_has_xact_error(ehci_qhd_t * p_qhd) -{ - return ( p_qhd->qtd_overlay.buffer_err ||p_qhd->qtd_overlay.babble_err || p_qhd->qtd_overlay.xact_err ); - //p_qhd->qtd_overlay.non_hs_period_missed_uframe || p_qhd->qtd_overlay.pingstate_err TODO split transaction error -} - -static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type, uint8_t interval); - - -STATIC_ INLINE_ ehci_qtd_t* qtd_find_free(uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE; -static inline ehci_qtd_t* qtd_next(ehci_qtd_t const * p_qtd ) ATTR_PURE ATTR_ALWAYS_INLINE; -static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) ATTR_ALWAYS_INLINE; -static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd) ATTR_ALWAYS_INLINE; -static void qtd_init(ehci_qtd_t* p_qtd, uint32_t data_ptr, uint16_t total_bytes); - -static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type) ATTR_ALWAYS_INLINE; -static inline ehci_link_t* list_next(ehci_link_t *p_link_pointer) ATTR_PURE ATTR_ALWAYS_INLINE; -static ehci_link_t* list_find_previous_item(ehci_link_t* p_head, ehci_link_t* p_current); -static tusb_error_t list_remove_qhd(ehci_link_t* p_head, ehci_link_t* p_remove); - -static tusb_error_t hcd_controller_init(uint8_t hostid) ATTR_WARN_UNUSED_RESULT; -static tusb_error_t hcd_controller_stop(uint8_t hostid) ATTR_WARN_UNUSED_RESULT; - -//--------------------------------------------------------------------+ -// USBH-HCD API -//--------------------------------------------------------------------+ -tusb_error_t hcd_init(void) -{ - //------------- Data Structure init -------------// - memclr_(&ehci_data, sizeof(ehci_data_t)); - - #if (TUSB_CFG_CONTROLLER0_MODE & TUSB_MODE_HOST) - ASSERT_STATUS (hcd_controller_init(0)); - #endif - - #if (TUSB_CFG_CONTROLLER1_MODE & TUSB_MODE_HOST) - ASSERT_STATUS (hcd_controller_init(1)); - #endif - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// PORT API -//--------------------------------------------------------------------+ -void hcd_port_reset(uint8_t hostid) -{ - ehci_registers_t* const regs = get_operational_register(hostid); - - regs->portsc_bit.port_enable = 0; // disable port before reset - regs->portsc_bit.port_reset = 1; - -#ifndef _TEST_ - // NXP specific, port reset will automatically be 0 when reset sequence complete - // there is chance device is unplugged while reset sequence is not complete - while( regs->portsc_bit.port_reset) {} // TODO use task delay to remove blocking -#endif -} - -bool hcd_port_connect_status(uint8_t hostid) -{ - return get_operational_register(hostid)->portsc_bit.current_connect_status; -} - -tusb_speed_t hcd_port_speed_get(uint8_t hostid) -{ - return (tusb_speed_t) get_operational_register(hostid)->portsc_bit.nxp_port_speed; // NXP specific port speed -} - -//--------------------------------------------------------------------+ -// Controller API -//--------------------------------------------------------------------+ -static tusb_error_t hcd_controller_init(uint8_t hostid) -{ - ehci_registers_t* const regs = get_operational_register(hostid); - - //------------- CTRLDSSEGMENT Register (skip) -------------// - //------------- USB INT Register -------------// - regs->usb_int_enable = 0; // 1. disable all the interrupt -#ifndef _TEST_ // the fake controller does not have write-to-clear behavior - regs->usb_sts = EHCI_INT_MASK_ALL; // 2. clear all status -#endif - regs->usb_int_enable = EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE | -#if EHCI_PERIODIC_LIST - EHCI_INT_MASK_NXP_PERIODIC | -#endif - EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_ASYNC; - - //------------- Asynchronous List -------------// - ehci_qhd_t * const async_head = get_async_head(hostid); - memclr_(async_head, sizeof(ehci_qhd_t)); - - async_head->next.address = (uint32_t) async_head; // circular list, next is itself - async_head->next.type = EHCI_QUEUE_ELEMENT_QHD; - async_head->head_list_flag = 1; - async_head->qtd_overlay.halted = 1; // inactive most of time - async_head->qtd_overlay.next.terminate = 1; // TODO removed if verified - - regs->async_list_base = (uint32_t) async_head; - -#if EHCI_PERIODIC_LIST - //------------- Periodic List -------------// - // Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only - - for(uint32_t i=0; i<4; i++) - { - ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ][i].interrupt_smask = 1; // queue head in period list must have smask non-zero - ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ][i].qtd_overlay.halted = 1; // dummy node, always inactive - } - - ehci_link_t * const framelist = get_period_frame_list(hostid); - ehci_link_t * const period_1ms = get_period_head(hostid, 1); - // all links --> period_head_arr[0] (1ms) - // 0, 2, 4, 6 etc --> period_head_arr[1] (2ms) - // 1, 5 --> period_head_arr[2] (4ms) - // 3 --> period_head_arr[3] (8ms) - - // TODO EHCI_FRAMELIST_SIZE with other size than 8 - for(uint32_t i=0; iterminate = 1; - - regs->periodic_list_base = (uint32_t) framelist; -#else - regs->periodic_list_base = 0; -#endif - - //------------- TT Control (NXP only) -------------// - regs->tt_control = 0; - - //------------- USB CMD Register -------------// - - regs->usb_cmd |= BIT_(EHCI_USBCMD_POS_RUN_STOP) | BIT_(EHCI_USBCMD_POS_ASYNC_ENABLE) -#if EHCI_PERIODIC_LIST - | BIT_(EHCI_USBCMD_POS_PERIOD_ENABLE) // TODO enable period list only there is int/iso endpoint -#endif - | ((EHCI_CFG_FRAMELIST_SIZE_BITS & BIN8(011)) << EHCI_USBCMD_POS_FRAMELIST_SZIE) - | ((EHCI_CFG_FRAMELIST_SIZE_BITS >> 2) << EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB); - - //------------- ConfigFlag Register (skip) -------------// - - regs->portsc_bit.port_power = 1; // enable port power - - return TUSB_ERROR_NONE; -} - -static tusb_error_t hcd_controller_stop(uint8_t hostid) -{ - ehci_registers_t* const regs = get_operational_register(hostid); - timeout_timer_t timeout; - - regs->usb_cmd_bit.run_stop = 0; - - timeout_set(&timeout, 2); // USB Spec: controller has to stop within 16 uframe = 2 frames - while( regs->usb_sts_bit.hc_halted == 0 && !timeout_expired(&timeout)) {} - - return timeout_expired(&timeout) ? TUSB_ERROR_OSAL_TIMEOUT : TUSB_ERROR_NONE; -} - -tusb_error_t hcd_controller_reset(uint8_t hostid) -{ - ehci_registers_t* const regs = get_operational_register(hostid); - timeout_timer_t timeout; - -// NXP chip powered with non-host mode --> sts bit is not correctly reflected - regs->usb_cmd_bit.reset = 1; - - timeout_set(&timeout, 2); // should not take longer the time to stop controller - while( regs->usb_cmd_bit.reset && !timeout_expired(&timeout)) {} - - return timeout_expired(&timeout) ? TUSB_ERROR_OSAL_TIMEOUT : TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// CONTROL PIPE API -//--------------------------------------------------------------------+ -tusb_error_t hcd_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) -{ - ehci_qhd_t * const p_qhd = get_control_qhd(dev_addr); - - qhd_init(p_qhd, dev_addr, max_packet_size, 0, TUSB_XFER_CONTROL, 1); // TODO binterval of control is ignored - - if (dev_addr != 0) - { - //------------- insert to async list -------------// - // TODO might need to to disable async list first - list_insert( (ehci_link_t*) get_async_head(usbh_devices[dev_addr].core_id), - (ehci_link_t*) p_qhd, EHCI_QUEUE_ELEMENT_QHD); - } - - return TUSB_ERROR_NONE; -} - -tusb_error_t hcd_pipe_control_xfer(uint8_t dev_addr, tusb_control_request_t const * p_request, uint8_t data[]) -{ - ehci_qhd_t * const p_qhd = get_control_qhd(dev_addr); - - ehci_qtd_t *p_setup = get_control_qtds(dev_addr); - ehci_qtd_t *p_data = p_setup + 1; - ehci_qtd_t *p_status = p_setup + 2; - - //------------- SETUP Phase -------------// - qtd_init(p_setup, (uint32_t) p_request, 8); - p_setup->pid = EHCI_PID_SETUP; - p_setup->next.address = (uint32_t) p_data; - - //------------- DATA Phase -------------// - if (p_request->wLength > 0) - { - qtd_init(p_data, (uint32_t) data, p_request->wLength); - p_data->data_toggle = 1; - p_data->pid = p_request->bmRequestType_bit.direction ? EHCI_PID_IN : EHCI_PID_OUT; - }else - { - p_data = p_setup; - } - p_data->next.address = (uint32_t) p_status; - - //------------- STATUS Phase -------------// - qtd_init(p_status, 0, 0); // zero-length data - p_status->int_on_complete = 1; - p_status->data_toggle = 1; - p_status->pid = p_request->bmRequestType_bit.direction ? EHCI_PID_OUT : EHCI_PID_IN; // reverse direction of data phase - p_status->next.terminate = 1; - - //------------- Attach TDs list to Control Endpoint -------------// - p_qhd->p_qtd_list_head = p_setup; - p_qhd->p_qtd_list_tail = p_status; - - p_qhd->qtd_overlay.next.address = (uint32_t) p_setup; - - return TUSB_ERROR_NONE; -} - -tusb_error_t hcd_pipe_control_close(uint8_t dev_addr) -{ - //------------- TODO pipe handle validate -------------// - ehci_qhd_t * const p_qhd = get_control_qhd(dev_addr); - - p_qhd->is_removing = 1; - - if (dev_addr != 0) - { - ASSERT_STATUS( list_remove_qhd( (ehci_link_t*) get_async_head( usbh_devices[dev_addr].core_id ), - (ehci_link_t*) p_qhd) ); - } - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// BULK/INT/ISO PIPE API -//--------------------------------------------------------------------+ -pipe_handle_t hcd_pipe_open(uint8_t dev_addr, tusb_descriptor_endpoint_t const * p_endpoint_desc, uint8_t class_code) -{ - pipe_handle_t const null_handle = { .dev_addr = 0, .xfer_type = 0, .index = 0 }; - - ASSERT(dev_addr > 0, null_handle); - - if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) - return null_handle; // TODO not support ISO yet - - //------------- Prepare Queue Head -------------// - ehci_qhd_t * const p_qhd = qhd_find_free(dev_addr); - ASSERT_PTR(p_qhd, null_handle); - - qhd_init( p_qhd, dev_addr, p_endpoint_desc->wMaxPacketSize.size, p_endpoint_desc->bEndpointAddress, - p_endpoint_desc->bmAttributes.xfer, p_endpoint_desc->bInterval ); - p_qhd->class_code = class_code; - - //------------- Insert to Async List -------------// - ehci_link_t * list_head; - - if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_BULK) - { - list_head = (ehci_link_t*) get_async_head(usbh_devices[dev_addr].core_id); - } - #if EHCI_PERIODIC_LIST // TODO refractor/group this together - else if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_INTERRUPT) - { - list_head = get_period_head(usbh_devices[dev_addr].core_id, p_qhd->interval_ms); - } - #endif - - //------------- insert to async/period list TODO might need to disable async/period list -------------// - list_insert( list_head, - (ehci_link_t*) p_qhd, EHCI_QUEUE_ELEMENT_QHD); - - return (pipe_handle_t) { .dev_addr = dev_addr, .xfer_type = p_endpoint_desc->bmAttributes.xfer, .index = qhd_get_index(p_qhd) }; -} - -tusb_error_t hcd_pipe_queue_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes) -{ - //------------- TODO pipe handle validate -------------// - - //------------- set up QTD -------------// - ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle(pipe_hdl); - ehci_qtd_t *p_qtd = qtd_find_free(pipe_hdl.dev_addr); - - ASSERT_PTR(p_qtd, TUSB_ERROR_EHCI_NOT_ENOUGH_QTD); - - qtd_init(p_qtd, (uint32_t) buffer, total_bytes); - p_qtd->pid = p_qhd->pid_non_control; - - //------------- insert TD to TD list -------------// - qtd_insert_to_qhd(p_qhd, p_qtd); - - return TUSB_ERROR_NONE; -} - -tusb_error_t hcd_pipe_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete) -{ - ASSERT_STATUS ( hcd_pipe_queue_xfer(pipe_hdl, buffer, total_bytes) ); - - ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle(pipe_hdl); - - if ( int_on_complete ) - { // the just added qtd is pointed by list_tail - p_qhd->p_qtd_list_tail->int_on_complete = 1; - } - p_qhd->qtd_overlay.next.address = (uint32_t) p_qhd->p_qtd_list_head; // attach to queue head to start transferring - - return TUSB_ERROR_NONE; -} - -/// pipe_close should only be called as a part of unmount/safe-remove process -tusb_error_t hcd_pipe_close(pipe_handle_t pipe_hdl) -{ - ASSERT(pipe_hdl.dev_addr > 0, TUSB_ERROR_INVALID_PARA); - - ASSERT(pipe_hdl.xfer_type != TUSB_XFER_ISOCHRONOUS, TUSB_ERROR_INVALID_PARA); - - ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); - - // async list needs async advance handshake to make sure host controller has released cached data - // non-control does not use async advance, it will eventually free by control pipe close - // period list queue element is guarantee to be free in the next frame (1 ms) - p_qhd->is_removing = 1; // TODO redundant, only apply to control queue head - - if ( pipe_hdl.xfer_type == TUSB_XFER_BULK ) - { - ASSERT_STATUS( list_remove_qhd( - (ehci_link_t*) get_async_head( usbh_devices[pipe_hdl.dev_addr].core_id ), - (ehci_link_t*) p_qhd) ); - } - #if EHCI_PERIODIC_LIST // TODO refractor/group this together - else - { - ASSERT_STATUS( list_remove_qhd( - get_period_head( usbh_devices[pipe_hdl.dev_addr].core_id, p_qhd->interval_ms ), - (ehci_link_t*) p_qhd) ); - } - #endif - - return TUSB_ERROR_NONE; -} - -bool hcd_pipe_is_busy(pipe_handle_t pipe_hdl) -{ - ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); - return !p_qhd->qtd_overlay.halted && (p_qhd->p_qtd_list_head != NULL); -} - -bool hcd_pipe_is_error(pipe_handle_t pipe_hdl) -{ - ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); - return p_qhd->qtd_overlay.halted; -} - -bool hcd_pipe_is_idle(pipe_handle_t pipe_hdl) -{ // TODO to be remove - ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); - return (p_qhd->p_qtd_list_head == NULL); -} - -bool hcd_pipe_is_stalled(pipe_handle_t pipe_hdl) -{ - ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); - return p_qhd->qtd_overlay.halted && !qhd_has_xact_error(p_qhd); -} - -uint8_t hcd_pipe_get_endpoint_addr(pipe_handle_t pipe_hdl) -{ - ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); - return p_qhd->endpoint_number + ( (p_qhd->pid_non_control == EHCI_PID_IN) ? 0x80 : 0); -} - -tusb_error_t hcd_pipe_clear_stall(pipe_handle_t pipe_hdl) -{ - ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); - p_qhd->qtd_overlay.halted = 0; - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// EHCI Interrupt Handler -//--------------------------------------------------------------------+ - -// async_advance is handshake between sw stack & ehci controller where ehci free all memory from an deleted queue head. -// In tinyusb, queue head is only removed when device is unplugged. So only control queue head is checked if removing -static void async_advance_isr(ehci_qhd_t * const async_head) -{ - // TODO do we need to close addr0 - if (async_head->is_removing) // closing control pipe of addr0 - { - async_head->is_removing = 0; - async_head->p_qtd_list_head = async_head->p_qtd_list_tail = NULL; - async_head->qtd_overlay.halted = 1; - - usbh_devices[0].state = TUSB_DEVICE_STATE_UNPLUG; - } - - for(uint8_t relative_dev_addr=0; relative_dev_addr < TUSB_CFG_HOST_DEVICE_MAX; relative_dev_addr++) - { - // check if control endpoint is removing - ehci_qhd_t *p_control_qhd = &ehci_data.device[relative_dev_addr].control.qhd; - if ( p_control_qhd->is_removing ) - { - p_control_qhd->is_removing = 0; - p_control_qhd->used = 0; - - // Host Controller has cleaned up its cached data for this device, set state to unplug - usbh_devices[relative_dev_addr+1].state = TUSB_DEVICE_STATE_UNPLUG; - - for (uint8_t i=0; iunplug->…..-> plug if device is powering with pre-plugged device - if (regs->portsc_bit.current_connect_status) - { - usbh_hcd_rhport_plugged_isr(hostid); - }else // device unplugged - { - usbh_hcd_rhport_unplugged_isr(hostid); -// regs->usb_cmd_bit.advacne_async = 1; // Async doorbell check EHCI 4.8.2 for operational details - } -} - -// TODO refractor abtract later -void hcd_port_unplug(uint8_t hostid) -{ - ehci_registers_t* const regs = get_operational_register(hostid); - regs->usb_cmd_bit.advacne_async = 1; // Async doorbell check EHCI 4.8.2 for operational details -} - -static void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd) -{ - uint8_t max_loop = 0; - tusb_xfer_type_t const xfer_type = qhd_get_xfer_type(p_qhd); - - // free all TDs from the head td to the first active TD - while(p_qhd->p_qtd_list_head != NULL && !p_qhd->p_qtd_list_head->active - && max_loop < EHCI_MAX_QTD) - { - // TD need to be freed and removed from qhd, before invoking callback - bool is_ioc = (p_qhd->p_qtd_list_head->int_on_complete != 0); - p_qhd->total_xferred_bytes += p_qhd->p_qtd_list_head->expected_bytes - p_qhd->p_qtd_list_head->total_bytes; - - p_qhd->p_qtd_list_head->used = 0; // free QTD - qtd_remove_1st_from_qhd(p_qhd); - - if (is_ioc) // end of request - { // call USBH callback - usbh_xfer_isr( qhd_create_pipe_handle(p_qhd, xfer_type), - p_qhd->class_code, TUSB_EVENT_XFER_COMPLETE, - p_qhd->total_xferred_bytes - (xfer_type == TUSB_XFER_CONTROL ? 8 : 0) ); // subtract setup packet size if control, - p_qhd->total_xferred_bytes = 0; - } - - max_loop++; - } -} - -static void async_list_xfer_complete_isr(ehci_qhd_t * const async_head) -{ - uint8_t max_loop = 0; - ehci_qhd_t *p_qhd = async_head; - do - { - if ( !p_qhd->qtd_overlay.halted ) // halted or error is processed in error isr - { - qhd_xfer_complete_isr(p_qhd); - } - p_qhd = qhd_next(p_qhd); - max_loop++; - }while(p_qhd != async_head && max_loop < EHCI_MAX_QHD); // async list traversal, stop if loop around - // TODO abstract max loop guard for async -} - -#if EHCI_PERIODIC_LIST // TODO refractor/group this together -static void period_list_xfer_complete_isr(uint8_t hostid, uint8_t interval_ms) -{ - uint8_t max_loop = 0; - uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1); - ehci_link_t next_item = * get_period_head(hostid, interval_ms); - - // TODO abstract max loop guard for period - while( !next_item.terminate && - !(interval_ms > 1 && period_1ms_addr == align32(next_item.address)) && - max_loop < (EHCI_MAX_QHD + EHCI_MAX_ITD + EHCI_MAX_SITD)) - { - switch ( next_item.type ) - { - case EHCI_QUEUE_ELEMENT_QHD: - { - ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) align32(next_item.address); - if ( !p_qhd_int->qtd_overlay.halted ) - { - qhd_xfer_complete_isr(p_qhd_int); - } - } - break; - - case EHCI_QUEUE_ELEMENT_ITD: - case EHCI_QUEUE_ELEMENT_SITD: - case EHCI_QUEUE_ELEMENT_FSTN: - default: - ASSERT (false, VOID_RETURN); // TODO support hs/fs ISO - break; - } - - next_item = *list_next(&next_item); - max_loop++; - } -} -#endif - -static void qhd_xfer_error_isr(ehci_qhd_t * p_qhd) -{ - if ( (p_qhd->device_address != 0 && p_qhd->qtd_overlay.halted) || // addr0 cannot be protocol STALL - qhd_has_xact_error(p_qhd) ) - { // current qhd has error in transaction - tusb_xfer_type_t const xfer_type = qhd_get_xfer_type(p_qhd); - tusb_event_t error_event; - - // no error bits are set, endpoint is halted due to STALL - error_event = qhd_has_xact_error(p_qhd) ? TUSB_EVENT_XFER_ERROR : TUSB_EVENT_XFER_STALLED; - - p_qhd->total_xferred_bytes += p_qhd->p_qtd_list_head->expected_bytes - p_qhd->p_qtd_list_head->total_bytes; - - // TODO skip unplugged device - if ( TUSB_EVENT_XFER_ERROR == error_event ) hal_debugger_breakpoint(); - - p_qhd->p_qtd_list_head->used = 0; // free QTD - qtd_remove_1st_from_qhd(p_qhd); - - if ( TUSB_XFER_CONTROL == xfer_type ) - { - p_qhd->total_xferred_bytes -= min8_of(8, p_qhd->total_xferred_bytes); // subtract setup size - - // control cannot be halted --> clear all qtd list - p_qhd->p_qtd_list_head = NULL; - p_qhd->p_qtd_list_tail = NULL; - - p_qhd->qtd_overlay.next.terminate = 1; - p_qhd->qtd_overlay.alternate.terminate = 1; - p_qhd->qtd_overlay.halted = 0; - - ehci_qtd_t *p_setup = get_control_qtds(p_qhd->device_address); - ehci_qtd_t *p_data = p_setup + 1; - ehci_qtd_t *p_status = p_setup + 2; - - p_setup->used = p_data->used = p_status->used = 0; - } - - // call USBH callback - usbh_xfer_isr( qhd_create_pipe_handle(p_qhd, xfer_type), - p_qhd->class_code, error_event, - p_qhd->total_xferred_bytes); - - p_qhd->total_xferred_bytes = 0; - } -} - -static void xfer_error_isr(uint8_t hostid) -{ - //------------- async list -------------// - uint8_t max_loop = 0; - ehci_qhd_t * const async_head = get_async_head(hostid); - ehci_qhd_t *p_qhd = async_head; - do - { - qhd_xfer_error_isr( p_qhd ); - p_qhd = qhd_next(p_qhd); - max_loop++; - }while(p_qhd != async_head && max_loop < EHCI_MAX_QHD); // async list traversal, stop if loop around - - #if EHCI_PERIODIC_LIST - //------------- TODO refractor period list -------------// - uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1); - for (uint8_t interval_ms=1; interval_ms <= EHCI_FRAMELIST_SIZE; interval_ms *= 2) - { - uint8_t period_max_loop = 0; - ehci_link_t next_item = * get_period_head(hostid, interval_ms); - - // TODO abstract max loop guard for period - while( !next_item.terminate && - !(interval_ms > 1 && period_1ms_addr == align32(next_item.address)) && - period_max_loop < (EHCI_MAX_QHD + EHCI_MAX_ITD + EHCI_MAX_SITD)) - { - switch ( next_item.type ) - { - case EHCI_QUEUE_ELEMENT_QHD: - { - ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) align32(next_item.address); - qhd_xfer_error_isr(p_qhd_int); - } - break; - - case EHCI_QUEUE_ELEMENT_ITD: - case EHCI_QUEUE_ELEMENT_SITD: - case EHCI_QUEUE_ELEMENT_FSTN: - default: - ASSERT (false, VOID_RETURN); // TODO support hs/fs ISO - break; - } - - next_item = *list_next(&next_item); - period_max_loop++; - } - } - #endif -} - -//------------- Host Controller Driver's Interrupt Handler -------------// -void hcd_isr(uint8_t hostid) -{ - ehci_registers_t* const regs = get_operational_register(hostid); - - uint32_t int_status = regs->usb_sts; - int_status &= regs->usb_int_enable; - - regs->usb_sts |= int_status; // Acknowledge handled interrupt - - if (int_status == 0) - return; - - if (int_status & EHCI_INT_MASK_PORT_CHANGE) - { - uint32_t port_status = regs->portsc & EHCI_PORTSC_MASK_ALL; - - if (regs->portsc_bit.connect_status_change) - { - port_connect_status_change_isr(hostid); - } - - regs->portsc |= port_status; // Acknowledge change bits in portsc - } - - if (int_status & EHCI_INT_MASK_ERROR) - { - xfer_error_isr(hostid); - } - - //------------- some QTD/SITD/ITD with IOC set is completed -------------// - if (int_status & EHCI_INT_MASK_NXP_ASYNC) - { - async_list_xfer_complete_isr( get_async_head(hostid) ); - } - -#if EHCI_PERIODIC_LIST // TODO refractor/group this together - if (int_status & EHCI_INT_MASK_NXP_PERIODIC) - { - for (uint8_t i=1; i <= EHCI_FRAMELIST_SIZE; i *= 2) - { - period_list_xfer_complete_isr( hostid, i ); - } - } -#endif - - //------------- There is some removed async previously -------------// - if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) // need to place after EHCI_INT_MASK_NXP_ASYNC - { - async_advance_isr( get_async_head(hostid) ); - } -} - -//--------------------------------------------------------------------+ -// HELPER -//--------------------------------------------------------------------+ -STATIC_ INLINE_ ehci_registers_t* get_operational_register(uint8_t hostid) -{ - return (ehci_registers_t*) (hostid ? (&LPC_USB1->USBCMD_H) : (&LPC_USB0->USBCMD_H) ); -} - -#if EHCI_PERIODIC_LIST // TODO refractor/group this together -STATIC_ INLINE_ ehci_link_t* get_period_frame_list(uint8_t hostid) -{ - switch(hostid) - { -#if (TUSB_CFG_CONTROLLER0_MODE & TUSB_MODE_HOST) - case 0: - return period_frame_list0; -#endif - -#if (TUSB_CFG_CONTROLLER1_MODE & TUSB_MODE_HOST) - case 1: - return period_frame_list1; -#endif - - default: return NULL; - } -} -#endif - -STATIC_ INLINE_ uint8_t hostid_to_data_idx(uint8_t hostid) -{ - #if (CONTROLLER_HOST_NUMBER == 1) && (TUSB_CFG_CONTROLLER1_MODE & TUSB_MODE_HOST) - (void) hostid; - return 0; - #else - return hostid; - #endif -} - -//------------- queue head helper -------------// -STATIC_ INLINE_ ehci_qhd_t* get_async_head(uint8_t hostid) -{ - return &ehci_data.async_head[ hostid_to_data_idx(hostid) ]; -} - -#if EHCI_PERIODIC_LIST // TODO refractor/group this together -STATIC_ INLINE_ ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms) -{ - return (ehci_link_t*) (&ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ] - [ log2_of( min8_of(EHCI_FRAMELIST_SIZE, interval_ms) ) ] ); -} -#endif - -STATIC_ INLINE_ ehci_qhd_t* get_control_qhd(uint8_t dev_addr) -{ - return (dev_addr == 0) ? - get_async_head( usbh_devices[dev_addr].core_id ) : - &ehci_data.device[dev_addr-1].control.qhd; -} -STATIC_ INLINE_ ehci_qtd_t* get_control_qtds(uint8_t dev_addr) -{ - return (dev_addr == 0) ? - ehci_data.addr0_qtd : - ehci_data.device[ dev_addr-1 ].control.qtd; - -} - -static inline ehci_qhd_t* qhd_find_free (uint8_t dev_addr) -{ - uint8_t relative_address = dev_addr-1; - uint8_t index=0; - while( indexdevice_address-1].qhd; -} -static inline tusb_xfer_type_t qhd_get_xfer_type(ehci_qhd_t const * p_qhd) -{ - return ( p_qhd->endpoint_number == 0 ) ? TUSB_XFER_CONTROL : - ( p_qhd->interrupt_smask != 0 ) ? TUSB_XFER_INTERRUPT : TUSB_XFER_BULK; -} - -static inline ehci_qhd_t* qhd_next(ehci_qhd_t const * p_qhd) -{ - return (ehci_qhd_t*) align32(p_qhd->next.address); -} - -STATIC_ INLINE_ ehci_qhd_t* qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl) -{ - return &ehci_data.device[ pipe_hdl.dev_addr-1 ].qhd[ pipe_hdl.index ]; -} - -static inline pipe_handle_t qhd_create_pipe_handle(ehci_qhd_t const * p_qhd, tusb_xfer_type_t xfer_type) -{ - pipe_handle_t pipe_hdl = { - .dev_addr = p_qhd->device_address, - .xfer_type = xfer_type - }; - - // TODO Isochronous transfer support - if (TUSB_XFER_CONTROL != xfer_type) // qhd index for control is meaningless - { - pipe_hdl.index = qhd_get_index(p_qhd); - } - - return pipe_hdl; -} - -//------------- TD helper -------------// -STATIC_ INLINE_ ehci_qtd_t* qtd_find_free(uint8_t dev_addr) -{ - uint8_t index=0; - while( indexnext.address); -} - -static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd) -{ - if (p_qhd->p_qtd_list_head == p_qhd->p_qtd_list_tail) // last TD --> make it NULL - { - p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = NULL; - }else - { - p_qhd->p_qtd_list_head = qtd_next( p_qhd->p_qtd_list_head ); - } -} - -static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) -{ - if (p_qhd->p_qtd_list_head == NULL) // empty list - { - p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = p_qtd_new; - }else - { - p_qhd->p_qtd_list_tail->next.address = (uint32_t) p_qtd_new; - p_qhd->p_qtd_list_tail = p_qtd_new; - } -} - -static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type, uint8_t interval) -{ - // address 0 uses async head, which always on the list --> cannot be cleared (ehci halted otherwise) - if (dev_addr != 0) - { - memclr_(p_qhd, sizeof(ehci_qhd_t)); - } - - p_qhd->device_address = dev_addr; - p_qhd->non_hs_period_inactive_next_xact = 0; - p_qhd->endpoint_number = endpoint_addr & 0x0F; - p_qhd->endpoint_speed = usbh_devices[dev_addr].speed; - p_qhd->data_toggle_control = (xfer_type == TUSB_XFER_CONTROL) ? 1 : 0; - p_qhd->head_list_flag = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static asyn list head - p_qhd->max_package_size = max_packet_size; - p_qhd->non_hs_control_endpoint = ((TUSB_XFER_CONTROL == xfer_type) && (p_qhd->endpoint_speed != TUSB_SPEED_HIGH)) ? 1 : 0; - p_qhd->nak_count_reload = 0; - - // Bulk/Control -> smask = cmask = 0 - // TODO Isochronous - if (TUSB_XFER_INTERRUPT == xfer_type) - { - if (TUSB_SPEED_HIGH == p_qhd->endpoint_speed) - { - ASSERT_INT_WITHIN(1, 16, interval, VOID_RETURN); - if ( interval < 4) // sub milisecond interval - { - p_qhd->interval_ms = 0; - p_qhd->interrupt_smask = (interval == 1) ? BIN8(11111111) : - (interval == 2) ? BIN8(10101010) : BIN8(01000100); - }else - { - p_qhd->interval_ms = (uint8_t) min16_of( 1 << (interval-4), 255 ); - p_qhd->interrupt_smask = BIT_(interval % 8); - } - }else - { - ASSERT( 0 != interval, VOID_RETURN); - // Full/Low: 4.12.2.1 (EHCI) case 1 schedule start split at 1 us & complete split at 2,3,4 uframes - p_qhd->interrupt_smask = 0x01; - p_qhd->non_hs_interrupt_cmask = BIN8(11100); - p_qhd->interval_ms = interval; - } - }else - { - p_qhd->interrupt_smask = p_qhd->non_hs_interrupt_cmask = 0; - } - - p_qhd->hub_address = usbh_devices[dev_addr].hub_addr; - p_qhd->hub_port = usbh_devices[dev_addr].hub_port; - p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet - - //------------- HCD Management Data -------------// - p_qhd->used = 1; - p_qhd->is_removing = 0; - p_qhd->p_qtd_list_head = NULL; - p_qhd->p_qtd_list_tail = NULL; - p_qhd->pid_non_control = (endpoint_addr & 0x80) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint - - //------------- active, but no TD list -------------// - p_qhd->qtd_overlay.halted = 0; - p_qhd->qtd_overlay.next.terminate = 1; - p_qhd->qtd_overlay.alternate.terminate = 1; - if (TUSB_XFER_BULK == xfer_type && p_qhd->endpoint_speed == TUSB_SPEED_HIGH && p_qhd->pid_non_control == EHCI_PID_OUT) - { - p_qhd->qtd_overlay.pingstate_err = 1; // do PING for Highspeed Bulk OUT, EHCI section 4.11 - } -} - -static void qtd_init(ehci_qtd_t* p_qtd, uint32_t data_ptr, uint16_t total_bytes) -{ - memclr_(p_qtd, sizeof(ehci_qtd_t)); - - p_qtd->used = 1; - - p_qtd->next.terminate = 1; // init to null - p_qtd->alternate.terminate = 1; // not used, always set to terminated - p_qtd->active = 1; - p_qtd->cerr = 3; // TODO 3 consecutive errors tolerance - p_qtd->data_toggle = 0; - p_qtd->total_bytes = total_bytes; - p_qtd->expected_bytes = total_bytes; - - p_qtd->buffer[0] = data_ptr; - for(uint8_t i=1; i<5; i++) - { - p_qtd->buffer[i] |= align4k( p_qtd->buffer[i-1] ) + 4096; - } -} - -//------------- List Managing Helper -------------// -static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type) -{ - new->address = current->address; - current->address = ((uint32_t) new) | (new_type << 1); -} - -static inline ehci_link_t* list_next(ehci_link_t *p_link_pointer) -{ - return (ehci_link_t*) align32(p_link_pointer->address); -} - -static ehci_link_t* list_find_previous_item(ehci_link_t* p_head, ehci_link_t* p_current) -{ - ehci_link_t *p_prev = p_head; - uint32_t max_loop = 0; - while( (align32(p_prev->address) != (uint32_t) p_head) && // not loop around - (align32(p_prev->address) != (uint32_t) p_current) && // not found yet - !p_prev->terminate && // not advanceable - max_loop < EHCI_MAX_QHD) - { - p_prev = list_next(p_prev); - max_loop++; - } - - return (align32(p_prev->address) != (uint32_t) p_head) ? p_prev : NULL; -} - -static tusb_error_t list_remove_qhd(ehci_link_t* p_head, ehci_link_t* p_remove) -{ - ehci_link_t *p_prev = list_find_previous_item(p_head, p_remove); - - ASSERT_PTR(p_prev, TUSB_ERROR_INVALID_PARA); - - p_prev->address = p_remove->address; - // EHCI 4.8.2 link the removing queue head to async/period head (which always reachable by Host Controller) - p_remove->address = ((uint32_t) p_head) | (EHCI_QUEUE_ELEMENT_QHD << 1); - - return TUSB_ERROR_NONE; -} - -#endif +/**************************************************************************/ +/*! + @file ehci.c + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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 holders 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 ''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 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 tinyusb stack. +*/ +/**************************************************************************/ + +#include "common/common.h" + +#if MODE_HOST_SUPPORTED && (MCU == MCU_LPC43XX || MCU == MCU_LPC18XX) +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "hal/hal.h" +#include "osal/osal.h" +#include "common/timeout_timer.h" + +#include "../hcd.h" +#include "../usbh_hcd.h" +#include "ehci.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +STATIC_VAR ehci_data_t ehci_data TUSB_CFG_ATTR_USBRAM; + +#if EHCI_PERIODIC_LIST + + #if (TUSB_CFG_CONTROLLER_0_MODE & TUSB_MODE_HOST) + ATTR_ALIGNED(4096) STATIC_VAR ehci_link_t period_frame_list0[EHCI_FRAMELIST_SIZE] TUSB_CFG_ATTR_USBRAM; + + #ifndef __ICCARM__ // IAR cannot able to determine the alignment with datalignment pragma + STATIC_ASSERT( ALIGN_OF(period_frame_list0) == 4096, "Period Framelist must be 4k alginment"); // validation + #endif + #endif + + #if (TUSB_CFG_CONTROLLER_1_MODE & TUSB_MODE_HOST) + STATIC_VAR ehci_link_t period_frame_list1[EHCI_FRAMELIST_SIZE] ATTR_ALIGNED(4096) TUSB_CFG_ATTR_USBRAM; + + #ifndef __ICCARM__ // IAR cannot able to determine the alignment with datalignment pragma + STATIC_ASSERT( ALIGN_OF(period_frame_list1) == 4096, "Period Framelist must be 4k alginment"); // validation + #endif + #endif +#endif + +//------------- Validation -------------// +// TODO static assert for memory placement on some known MCU such as lpc43xx + +//--------------------------------------------------------------------+ +// PROTOTYPE +//--------------------------------------------------------------------+ +STATIC_ INLINE_ ehci_registers_t* get_operational_register(uint8_t hostid) ATTR_PURE ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT; +STATIC_ INLINE_ ehci_link_t* get_period_frame_list(uint8_t hostid) ATTR_PURE ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT; +STATIC_ INLINE_ uint8_t hostid_to_data_idx(uint8_t hostid) ATTR_ALWAYS_INLINE ATTR_CONST ATTR_WARN_UNUSED_RESULT; + +STATIC_ INLINE_ ehci_qhd_t* get_async_head(uint8_t hostid) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT; +STATIC_ INLINE_ ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT; + +STATIC_ INLINE_ ehci_qhd_t* get_control_qhd(uint8_t dev_addr) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT; +STATIC_ INLINE_ ehci_qtd_t* get_control_qtds(uint8_t dev_addr) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT; + +static inline uint8_t qhd_get_index(ehci_qhd_t const * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE; +static inline ehci_qhd_t* qhd_next(ehci_qhd_t const * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE; +static inline ehci_qhd_t* qhd_find_free (uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE; +static inline tusb_xfer_type_t qhd_get_xfer_type(ehci_qhd_t const * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE; +STATIC_ INLINE_ ehci_qhd_t* qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl) ATTR_PURE ATTR_ALWAYS_INLINE; +static inline pipe_handle_t qhd_create_pipe_handle(ehci_qhd_t const * p_qhd, tusb_xfer_type_t xfer_type) ATTR_PURE ATTR_ALWAYS_INLINE; +// determine if a queue head has bus-related error +static inline bool qhd_has_xact_error(ehci_qhd_t * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE; +static inline bool qhd_has_xact_error(ehci_qhd_t * p_qhd) +{ + return ( p_qhd->qtd_overlay.buffer_err ||p_qhd->qtd_overlay.babble_err || p_qhd->qtd_overlay.xact_err ); + //p_qhd->qtd_overlay.non_hs_period_missed_uframe || p_qhd->qtd_overlay.pingstate_err TODO split transaction error +} + +static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type, uint8_t interval); + + +STATIC_ INLINE_ ehci_qtd_t* qtd_find_free(uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE; +static inline ehci_qtd_t* qtd_next(ehci_qtd_t const * p_qtd ) ATTR_PURE ATTR_ALWAYS_INLINE; +static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) ATTR_ALWAYS_INLINE; +static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd) ATTR_ALWAYS_INLINE; +static void qtd_init(ehci_qtd_t* p_qtd, uint32_t data_ptr, uint16_t total_bytes); + +static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type) ATTR_ALWAYS_INLINE; +static inline ehci_link_t* list_next(ehci_link_t *p_link_pointer) ATTR_PURE ATTR_ALWAYS_INLINE; +static ehci_link_t* list_find_previous_item(ehci_link_t* p_head, ehci_link_t* p_current); +static tusb_error_t list_remove_qhd(ehci_link_t* p_head, ehci_link_t* p_remove); + +static tusb_error_t hcd_controller_init(uint8_t hostid) ATTR_WARN_UNUSED_RESULT; +static tusb_error_t hcd_controller_stop(uint8_t hostid) ATTR_WARN_UNUSED_RESULT; + +//--------------------------------------------------------------------+ +// USBH-HCD API +//--------------------------------------------------------------------+ +tusb_error_t hcd_init(void) +{ + //------------- Data Structure init -------------// + memclr_(&ehci_data, sizeof(ehci_data_t)); + + #if (TUSB_CFG_CONTROLLER_0_MODE & TUSB_MODE_HOST) + ASSERT_STATUS (hcd_controller_init(0)); + #endif + + #if (TUSB_CFG_CONTROLLER_1_MODE & TUSB_MODE_HOST) + ASSERT_STATUS (hcd_controller_init(1)); + #endif + + return TUSB_ERROR_NONE; +} + +//--------------------------------------------------------------------+ +// PORT API +//--------------------------------------------------------------------+ +void hcd_port_reset(uint8_t hostid) +{ + ehci_registers_t* const regs = get_operational_register(hostid); + + regs->portsc_bit.port_enable = 0; // disable port before reset + regs->portsc_bit.port_reset = 1; + +#ifndef _TEST_ + // NXP specific, port reset will automatically be 0 when reset sequence complete + // there is chance device is unplugged while reset sequence is not complete + while( regs->portsc_bit.port_reset) {} // TODO use task delay to remove blocking +#endif +} + +bool hcd_port_connect_status(uint8_t hostid) +{ + return get_operational_register(hostid)->portsc_bit.current_connect_status; +} + +tusb_speed_t hcd_port_speed_get(uint8_t hostid) +{ + return (tusb_speed_t) get_operational_register(hostid)->portsc_bit.nxp_port_speed; // NXP specific port speed +} + +//--------------------------------------------------------------------+ +// Controller API +//--------------------------------------------------------------------+ +static tusb_error_t hcd_controller_init(uint8_t hostid) +{ + ehci_registers_t* const regs = get_operational_register(hostid); + + //------------- CTRLDSSEGMENT Register (skip) -------------// + //------------- USB INT Register -------------// + regs->usb_int_enable = 0; // 1. disable all the interrupt +#ifndef _TEST_ // the fake controller does not have write-to-clear behavior + regs->usb_sts = EHCI_INT_MASK_ALL; // 2. clear all status +#endif + regs->usb_int_enable = EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE | +#if EHCI_PERIODIC_LIST + EHCI_INT_MASK_NXP_PERIODIC | +#endif + EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_ASYNC; + + //------------- Asynchronous List -------------// + ehci_qhd_t * const async_head = get_async_head(hostid); + memclr_(async_head, sizeof(ehci_qhd_t)); + + async_head->next.address = (uint32_t) async_head; // circular list, next is itself + async_head->next.type = EHCI_QUEUE_ELEMENT_QHD; + async_head->head_list_flag = 1; + async_head->qtd_overlay.halted = 1; // inactive most of time + async_head->qtd_overlay.next.terminate = 1; // TODO removed if verified + + regs->async_list_base = (uint32_t) async_head; + +#if EHCI_PERIODIC_LIST + //------------- Periodic List -------------// + // Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only + + for(uint32_t i=0; i<4; i++) + { + ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ][i].interrupt_smask = 1; // queue head in period list must have smask non-zero + ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ][i].qtd_overlay.halted = 1; // dummy node, always inactive + } + + ehci_link_t * const framelist = get_period_frame_list(hostid); + ehci_link_t * const period_1ms = get_period_head(hostid, 1); + // all links --> period_head_arr[0] (1ms) + // 0, 2, 4, 6 etc --> period_head_arr[1] (2ms) + // 1, 5 --> period_head_arr[2] (4ms) + // 3 --> period_head_arr[3] (8ms) + + // TODO EHCI_FRAMELIST_SIZE with other size than 8 + for(uint32_t i=0; iterminate = 1; + + regs->periodic_list_base = (uint32_t) framelist; +#else + regs->periodic_list_base = 0; +#endif + + //------------- TT Control (NXP only) -------------// + regs->tt_control = 0; + + //------------- USB CMD Register -------------// + + regs->usb_cmd |= BIT_(EHCI_USBCMD_POS_RUN_STOP) | BIT_(EHCI_USBCMD_POS_ASYNC_ENABLE) +#if EHCI_PERIODIC_LIST + | BIT_(EHCI_USBCMD_POS_PERIOD_ENABLE) // TODO enable period list only there is int/iso endpoint +#endif + | ((EHCI_CFG_FRAMELIST_SIZE_BITS & BIN8(011)) << EHCI_USBCMD_POS_FRAMELIST_SZIE) + | ((EHCI_CFG_FRAMELIST_SIZE_BITS >> 2) << EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB); + + //------------- ConfigFlag Register (skip) -------------// + + regs->portsc_bit.port_power = 1; // enable port power + + return TUSB_ERROR_NONE; +} + +static tusb_error_t hcd_controller_stop(uint8_t hostid) +{ + ehci_registers_t* const regs = get_operational_register(hostid); + timeout_timer_t timeout; + + regs->usb_cmd_bit.run_stop = 0; + + timeout_set(&timeout, 2); // USB Spec: controller has to stop within 16 uframe = 2 frames + while( regs->usb_sts_bit.hc_halted == 0 && !timeout_expired(&timeout)) {} + + return timeout_expired(&timeout) ? TUSB_ERROR_OSAL_TIMEOUT : TUSB_ERROR_NONE; +} + +tusb_error_t hcd_controller_reset(uint8_t hostid) +{ + ehci_registers_t* const regs = get_operational_register(hostid); + timeout_timer_t timeout; + +// NXP chip powered with non-host mode --> sts bit is not correctly reflected + regs->usb_cmd_bit.reset = 1; + + timeout_set(&timeout, 2); // should not take longer the time to stop controller + while( regs->usb_cmd_bit.reset && !timeout_expired(&timeout)) {} + + return timeout_expired(&timeout) ? TUSB_ERROR_OSAL_TIMEOUT : TUSB_ERROR_NONE; +} + +//--------------------------------------------------------------------+ +// CONTROL PIPE API +//--------------------------------------------------------------------+ +tusb_error_t hcd_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) +{ + ehci_qhd_t * const p_qhd = get_control_qhd(dev_addr); + + qhd_init(p_qhd, dev_addr, max_packet_size, 0, TUSB_XFER_CONTROL, 1); // TODO binterval of control is ignored + + if (dev_addr != 0) + { + //------------- insert to async list -------------// + // TODO might need to to disable async list first + list_insert( (ehci_link_t*) get_async_head(usbh_devices[dev_addr].core_id), + (ehci_link_t*) p_qhd, EHCI_QUEUE_ELEMENT_QHD); + } + + return TUSB_ERROR_NONE; +} + +tusb_error_t hcd_pipe_control_xfer(uint8_t dev_addr, tusb_control_request_t const * p_request, uint8_t data[]) +{ + ehci_qhd_t * const p_qhd = get_control_qhd(dev_addr); + + ehci_qtd_t *p_setup = get_control_qtds(dev_addr); + ehci_qtd_t *p_data = p_setup + 1; + ehci_qtd_t *p_status = p_setup + 2; + + //------------- SETUP Phase -------------// + qtd_init(p_setup, (uint32_t) p_request, 8); + p_setup->pid = EHCI_PID_SETUP; + p_setup->next.address = (uint32_t) p_data; + + //------------- DATA Phase -------------// + if (p_request->wLength > 0) + { + qtd_init(p_data, (uint32_t) data, p_request->wLength); + p_data->data_toggle = 1; + p_data->pid = p_request->bmRequestType_bit.direction ? EHCI_PID_IN : EHCI_PID_OUT; + }else + { + p_data = p_setup; + } + p_data->next.address = (uint32_t) p_status; + + //------------- STATUS Phase -------------// + qtd_init(p_status, 0, 0); // zero-length data + p_status->int_on_complete = 1; + p_status->data_toggle = 1; + p_status->pid = p_request->bmRequestType_bit.direction ? EHCI_PID_OUT : EHCI_PID_IN; // reverse direction of data phase + p_status->next.terminate = 1; + + //------------- Attach TDs list to Control Endpoint -------------// + p_qhd->p_qtd_list_head = p_setup; + p_qhd->p_qtd_list_tail = p_status; + + p_qhd->qtd_overlay.next.address = (uint32_t) p_setup; + + return TUSB_ERROR_NONE; +} + +tusb_error_t hcd_pipe_control_close(uint8_t dev_addr) +{ + //------------- TODO pipe handle validate -------------// + ehci_qhd_t * const p_qhd = get_control_qhd(dev_addr); + + p_qhd->is_removing = 1; + + if (dev_addr != 0) + { + ASSERT_STATUS( list_remove_qhd( (ehci_link_t*) get_async_head( usbh_devices[dev_addr].core_id ), + (ehci_link_t*) p_qhd) ); + } + + return TUSB_ERROR_NONE; +} + +//--------------------------------------------------------------------+ +// BULK/INT/ISO PIPE API +//--------------------------------------------------------------------+ +pipe_handle_t hcd_pipe_open(uint8_t dev_addr, tusb_descriptor_endpoint_t const * p_endpoint_desc, uint8_t class_code) +{ + pipe_handle_t const null_handle = { .dev_addr = 0, .xfer_type = 0, .index = 0 }; + + ASSERT(dev_addr > 0, null_handle); + + if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) + return null_handle; // TODO not support ISO yet + + //------------- Prepare Queue Head -------------// + ehci_qhd_t * const p_qhd = qhd_find_free(dev_addr); + ASSERT_PTR(p_qhd, null_handle); + + qhd_init( p_qhd, dev_addr, p_endpoint_desc->wMaxPacketSize.size, p_endpoint_desc->bEndpointAddress, + p_endpoint_desc->bmAttributes.xfer, p_endpoint_desc->bInterval ); + p_qhd->class_code = class_code; + + //------------- Insert to Async List -------------// + ehci_link_t * list_head; + + if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_BULK) + { + list_head = (ehci_link_t*) get_async_head(usbh_devices[dev_addr].core_id); + } + #if EHCI_PERIODIC_LIST // TODO refractor/group this together + else if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_INTERRUPT) + { + list_head = get_period_head(usbh_devices[dev_addr].core_id, p_qhd->interval_ms); + } + #endif + + //------------- insert to async/period list TODO might need to disable async/period list -------------// + list_insert( list_head, + (ehci_link_t*) p_qhd, EHCI_QUEUE_ELEMENT_QHD); + + return (pipe_handle_t) { .dev_addr = dev_addr, .xfer_type = p_endpoint_desc->bmAttributes.xfer, .index = qhd_get_index(p_qhd) }; +} + +tusb_error_t hcd_pipe_queue_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes) +{ + //------------- TODO pipe handle validate -------------// + + //------------- set up QTD -------------// + ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle(pipe_hdl); + ehci_qtd_t *p_qtd = qtd_find_free(pipe_hdl.dev_addr); + + ASSERT_PTR(p_qtd, TUSB_ERROR_EHCI_NOT_ENOUGH_QTD); + + qtd_init(p_qtd, (uint32_t) buffer, total_bytes); + p_qtd->pid = p_qhd->pid_non_control; + + //------------- insert TD to TD list -------------// + qtd_insert_to_qhd(p_qhd, p_qtd); + + return TUSB_ERROR_NONE; +} + +tusb_error_t hcd_pipe_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete) +{ + ASSERT_STATUS ( hcd_pipe_queue_xfer(pipe_hdl, buffer, total_bytes) ); + + ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle(pipe_hdl); + + if ( int_on_complete ) + { // the just added qtd is pointed by list_tail + p_qhd->p_qtd_list_tail->int_on_complete = 1; + } + p_qhd->qtd_overlay.next.address = (uint32_t) p_qhd->p_qtd_list_head; // attach to queue head to start transferring + + return TUSB_ERROR_NONE; +} + +/// pipe_close should only be called as a part of unmount/safe-remove process +tusb_error_t hcd_pipe_close(pipe_handle_t pipe_hdl) +{ + ASSERT(pipe_hdl.dev_addr > 0, TUSB_ERROR_INVALID_PARA); + + ASSERT(pipe_hdl.xfer_type != TUSB_XFER_ISOCHRONOUS, TUSB_ERROR_INVALID_PARA); + + ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); + + // async list needs async advance handshake to make sure host controller has released cached data + // non-control does not use async advance, it will eventually free by control pipe close + // period list queue element is guarantee to be free in the next frame (1 ms) + p_qhd->is_removing = 1; // TODO redundant, only apply to control queue head + + if ( pipe_hdl.xfer_type == TUSB_XFER_BULK ) + { + ASSERT_STATUS( list_remove_qhd( + (ehci_link_t*) get_async_head( usbh_devices[pipe_hdl.dev_addr].core_id ), + (ehci_link_t*) p_qhd) ); + } + #if EHCI_PERIODIC_LIST // TODO refractor/group this together + else + { + ASSERT_STATUS( list_remove_qhd( + get_period_head( usbh_devices[pipe_hdl.dev_addr].core_id, p_qhd->interval_ms ), + (ehci_link_t*) p_qhd) ); + } + #endif + + return TUSB_ERROR_NONE; +} + +bool hcd_pipe_is_busy(pipe_handle_t pipe_hdl) +{ + ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); + return !p_qhd->qtd_overlay.halted && (p_qhd->p_qtd_list_head != NULL); +} + +bool hcd_pipe_is_error(pipe_handle_t pipe_hdl) +{ + ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); + return p_qhd->qtd_overlay.halted; +} + +bool hcd_pipe_is_idle(pipe_handle_t pipe_hdl) +{ // TODO to be remove + ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); + return (p_qhd->p_qtd_list_head == NULL); +} + +bool hcd_pipe_is_stalled(pipe_handle_t pipe_hdl) +{ + ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); + return p_qhd->qtd_overlay.halted && !qhd_has_xact_error(p_qhd); +} + +uint8_t hcd_pipe_get_endpoint_addr(pipe_handle_t pipe_hdl) +{ + ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); + return p_qhd->endpoint_number + ( (p_qhd->pid_non_control == EHCI_PID_IN) ? 0x80 : 0); +} + +tusb_error_t hcd_pipe_clear_stall(pipe_handle_t pipe_hdl) +{ + ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); + p_qhd->qtd_overlay.halted = 0; + + return TUSB_ERROR_NONE; +} + +//--------------------------------------------------------------------+ +// EHCI Interrupt Handler +//--------------------------------------------------------------------+ + +// async_advance is handshake between sw stack & ehci controller where ehci free all memory from an deleted queue head. +// In tinyusb, queue head is only removed when device is unplugged. So only control queue head is checked if removing +static void async_advance_isr(ehci_qhd_t * const async_head) +{ + // TODO do we need to close addr0 + if (async_head->is_removing) // closing control pipe of addr0 + { + async_head->is_removing = 0; + async_head->p_qtd_list_head = async_head->p_qtd_list_tail = NULL; + async_head->qtd_overlay.halted = 1; + + usbh_devices[0].state = TUSB_DEVICE_STATE_UNPLUG; + } + + for(uint8_t relative_dev_addr=0; relative_dev_addr < TUSB_CFG_HOST_DEVICE_MAX; relative_dev_addr++) + { + // check if control endpoint is removing + ehci_qhd_t *p_control_qhd = &ehci_data.device[relative_dev_addr].control.qhd; + if ( p_control_qhd->is_removing ) + { + p_control_qhd->is_removing = 0; + p_control_qhd->used = 0; + + // Host Controller has cleaned up its cached data for this device, set state to unplug + usbh_devices[relative_dev_addr+1].state = TUSB_DEVICE_STATE_UNPLUG; + + for (uint8_t i=0; iunplug->…..-> plug if device is powering with pre-plugged device + if (regs->portsc_bit.current_connect_status) + { + usbh_hcd_rhport_plugged_isr(hostid); + }else // device unplugged + { + usbh_hcd_rhport_unplugged_isr(hostid); +// regs->usb_cmd_bit.advacne_async = 1; // Async doorbell check EHCI 4.8.2 for operational details + } +} + +// TODO refractor abtract later +void hcd_port_unplug(uint8_t hostid) +{ + ehci_registers_t* const regs = get_operational_register(hostid); + regs->usb_cmd_bit.advacne_async = 1; // Async doorbell check EHCI 4.8.2 for operational details +} + +static void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd) +{ + uint8_t max_loop = 0; + tusb_xfer_type_t const xfer_type = qhd_get_xfer_type(p_qhd); + + // free all TDs from the head td to the first active TD + while(p_qhd->p_qtd_list_head != NULL && !p_qhd->p_qtd_list_head->active + && max_loop < EHCI_MAX_QTD) + { + // TD need to be freed and removed from qhd, before invoking callback + bool is_ioc = (p_qhd->p_qtd_list_head->int_on_complete != 0); + p_qhd->total_xferred_bytes += p_qhd->p_qtd_list_head->expected_bytes - p_qhd->p_qtd_list_head->total_bytes; + + p_qhd->p_qtd_list_head->used = 0; // free QTD + qtd_remove_1st_from_qhd(p_qhd); + + if (is_ioc) // end of request + { // call USBH callback + usbh_xfer_isr( qhd_create_pipe_handle(p_qhd, xfer_type), + p_qhd->class_code, TUSB_EVENT_XFER_COMPLETE, + p_qhd->total_xferred_bytes - (xfer_type == TUSB_XFER_CONTROL ? 8 : 0) ); // subtract setup packet size if control, + p_qhd->total_xferred_bytes = 0; + } + + max_loop++; + } +} + +static void async_list_xfer_complete_isr(ehci_qhd_t * const async_head) +{ + uint8_t max_loop = 0; + ehci_qhd_t *p_qhd = async_head; + do + { + if ( !p_qhd->qtd_overlay.halted ) // halted or error is processed in error isr + { + qhd_xfer_complete_isr(p_qhd); + } + p_qhd = qhd_next(p_qhd); + max_loop++; + }while(p_qhd != async_head && max_loop < EHCI_MAX_QHD); // async list traversal, stop if loop around + // TODO abstract max loop guard for async +} + +#if EHCI_PERIODIC_LIST // TODO refractor/group this together +static void period_list_xfer_complete_isr(uint8_t hostid, uint8_t interval_ms) +{ + uint8_t max_loop = 0; + uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1); + ehci_link_t next_item = * get_period_head(hostid, interval_ms); + + // TODO abstract max loop guard for period + while( !next_item.terminate && + !(interval_ms > 1 && period_1ms_addr == align32(next_item.address)) && + max_loop < (EHCI_MAX_QHD + EHCI_MAX_ITD + EHCI_MAX_SITD)) + { + switch ( next_item.type ) + { + case EHCI_QUEUE_ELEMENT_QHD: + { + ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) align32(next_item.address); + if ( !p_qhd_int->qtd_overlay.halted ) + { + qhd_xfer_complete_isr(p_qhd_int); + } + } + break; + + case EHCI_QUEUE_ELEMENT_ITD: + case EHCI_QUEUE_ELEMENT_SITD: + case EHCI_QUEUE_ELEMENT_FSTN: + default: + ASSERT (false, VOID_RETURN); // TODO support hs/fs ISO + break; + } + + next_item = *list_next(&next_item); + max_loop++; + } +} +#endif + +static void qhd_xfer_error_isr(ehci_qhd_t * p_qhd) +{ + if ( (p_qhd->device_address != 0 && p_qhd->qtd_overlay.halted) || // addr0 cannot be protocol STALL + qhd_has_xact_error(p_qhd) ) + { // current qhd has error in transaction + tusb_xfer_type_t const xfer_type = qhd_get_xfer_type(p_qhd); + tusb_event_t error_event; + + // no error bits are set, endpoint is halted due to STALL + error_event = qhd_has_xact_error(p_qhd) ? TUSB_EVENT_XFER_ERROR : TUSB_EVENT_XFER_STALLED; + + p_qhd->total_xferred_bytes += p_qhd->p_qtd_list_head->expected_bytes - p_qhd->p_qtd_list_head->total_bytes; + + // TODO skip unplugged device + if ( TUSB_EVENT_XFER_ERROR == error_event ) hal_debugger_breakpoint(); + + p_qhd->p_qtd_list_head->used = 0; // free QTD + qtd_remove_1st_from_qhd(p_qhd); + + if ( TUSB_XFER_CONTROL == xfer_type ) + { + p_qhd->total_xferred_bytes -= min8_of(8, p_qhd->total_xferred_bytes); // subtract setup size + + // control cannot be halted --> clear all qtd list + p_qhd->p_qtd_list_head = NULL; + p_qhd->p_qtd_list_tail = NULL; + + p_qhd->qtd_overlay.next.terminate = 1; + p_qhd->qtd_overlay.alternate.terminate = 1; + p_qhd->qtd_overlay.halted = 0; + + ehci_qtd_t *p_setup = get_control_qtds(p_qhd->device_address); + ehci_qtd_t *p_data = p_setup + 1; + ehci_qtd_t *p_status = p_setup + 2; + + p_setup->used = p_data->used = p_status->used = 0; + } + + // call USBH callback + usbh_xfer_isr( qhd_create_pipe_handle(p_qhd, xfer_type), + p_qhd->class_code, error_event, + p_qhd->total_xferred_bytes); + + p_qhd->total_xferred_bytes = 0; + } +} + +static void xfer_error_isr(uint8_t hostid) +{ + //------------- async list -------------// + uint8_t max_loop = 0; + ehci_qhd_t * const async_head = get_async_head(hostid); + ehci_qhd_t *p_qhd = async_head; + do + { + qhd_xfer_error_isr( p_qhd ); + p_qhd = qhd_next(p_qhd); + max_loop++; + }while(p_qhd != async_head && max_loop < EHCI_MAX_QHD); // async list traversal, stop if loop around + + #if EHCI_PERIODIC_LIST + //------------- TODO refractor period list -------------// + uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1); + for (uint8_t interval_ms=1; interval_ms <= EHCI_FRAMELIST_SIZE; interval_ms *= 2) + { + uint8_t period_max_loop = 0; + ehci_link_t next_item = * get_period_head(hostid, interval_ms); + + // TODO abstract max loop guard for period + while( !next_item.terminate && + !(interval_ms > 1 && period_1ms_addr == align32(next_item.address)) && + period_max_loop < (EHCI_MAX_QHD + EHCI_MAX_ITD + EHCI_MAX_SITD)) + { + switch ( next_item.type ) + { + case EHCI_QUEUE_ELEMENT_QHD: + { + ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) align32(next_item.address); + qhd_xfer_error_isr(p_qhd_int); + } + break; + + case EHCI_QUEUE_ELEMENT_ITD: + case EHCI_QUEUE_ELEMENT_SITD: + case EHCI_QUEUE_ELEMENT_FSTN: + default: + ASSERT (false, VOID_RETURN); // TODO support hs/fs ISO + break; + } + + next_item = *list_next(&next_item); + period_max_loop++; + } + } + #endif +} + +//------------- Host Controller Driver's Interrupt Handler -------------// +void hcd_isr(uint8_t hostid) +{ + ehci_registers_t* const regs = get_operational_register(hostid); + + uint32_t int_status = regs->usb_sts; + int_status &= regs->usb_int_enable; + + regs->usb_sts |= int_status; // Acknowledge handled interrupt + + if (int_status == 0) + return; + + if (int_status & EHCI_INT_MASK_PORT_CHANGE) + { + uint32_t port_status = regs->portsc & EHCI_PORTSC_MASK_ALL; + + if (regs->portsc_bit.connect_status_change) + { + port_connect_status_change_isr(hostid); + } + + regs->portsc |= port_status; // Acknowledge change bits in portsc + } + + if (int_status & EHCI_INT_MASK_ERROR) + { + xfer_error_isr(hostid); + } + + //------------- some QTD/SITD/ITD with IOC set is completed -------------// + if (int_status & EHCI_INT_MASK_NXP_ASYNC) + { + async_list_xfer_complete_isr( get_async_head(hostid) ); + } + +#if EHCI_PERIODIC_LIST // TODO refractor/group this together + if (int_status & EHCI_INT_MASK_NXP_PERIODIC) + { + for (uint8_t i=1; i <= EHCI_FRAMELIST_SIZE; i *= 2) + { + period_list_xfer_complete_isr( hostid, i ); + } + } +#endif + + //------------- There is some removed async previously -------------// + if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) // need to place after EHCI_INT_MASK_NXP_ASYNC + { + async_advance_isr( get_async_head(hostid) ); + } +} + +//--------------------------------------------------------------------+ +// HELPER +//--------------------------------------------------------------------+ +STATIC_ INLINE_ ehci_registers_t* get_operational_register(uint8_t hostid) +{ + return (ehci_registers_t*) (hostid ? (&LPC_USB1->USBCMD_H) : (&LPC_USB0->USBCMD_H) ); +} + +#if EHCI_PERIODIC_LIST // TODO refractor/group this together +STATIC_ INLINE_ ehci_link_t* get_period_frame_list(uint8_t hostid) +{ + switch(hostid) + { +#if (TUSB_CFG_CONTROLLER_0_MODE & TUSB_MODE_HOST) + case 0: + return period_frame_list0; +#endif + +#if (TUSB_CFG_CONTROLLER_1_MODE & TUSB_MODE_HOST) + case 1: + return period_frame_list1; +#endif + + default: return NULL; + } +} +#endif + +STATIC_ INLINE_ uint8_t hostid_to_data_idx(uint8_t hostid) +{ + #if (CONTROLLER_HOST_NUMBER == 1) && (TUSB_CFG_CONTROLLER_1_MODE & TUSB_MODE_HOST) + (void) hostid; + return 0; + #else + return hostid; + #endif +} + +//------------- queue head helper -------------// +STATIC_ INLINE_ ehci_qhd_t* get_async_head(uint8_t hostid) +{ + return &ehci_data.async_head[ hostid_to_data_idx(hostid) ]; +} + +#if EHCI_PERIODIC_LIST // TODO refractor/group this together +STATIC_ INLINE_ ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms) +{ + return (ehci_link_t*) (&ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ] + [ log2_of( min8_of(EHCI_FRAMELIST_SIZE, interval_ms) ) ] ); +} +#endif + +STATIC_ INLINE_ ehci_qhd_t* get_control_qhd(uint8_t dev_addr) +{ + return (dev_addr == 0) ? + get_async_head( usbh_devices[dev_addr].core_id ) : + &ehci_data.device[dev_addr-1].control.qhd; +} +STATIC_ INLINE_ ehci_qtd_t* get_control_qtds(uint8_t dev_addr) +{ + return (dev_addr == 0) ? + ehci_data.addr0_qtd : + ehci_data.device[ dev_addr-1 ].control.qtd; + +} + +static inline ehci_qhd_t* qhd_find_free (uint8_t dev_addr) +{ + uint8_t relative_address = dev_addr-1; + uint8_t index=0; + while( indexdevice_address-1].qhd; +} +static inline tusb_xfer_type_t qhd_get_xfer_type(ehci_qhd_t const * p_qhd) +{ + return ( p_qhd->endpoint_number == 0 ) ? TUSB_XFER_CONTROL : + ( p_qhd->interrupt_smask != 0 ) ? TUSB_XFER_INTERRUPT : TUSB_XFER_BULK; +} + +static inline ehci_qhd_t* qhd_next(ehci_qhd_t const * p_qhd) +{ + return (ehci_qhd_t*) align32(p_qhd->next.address); +} + +STATIC_ INLINE_ ehci_qhd_t* qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl) +{ + return &ehci_data.device[ pipe_hdl.dev_addr-1 ].qhd[ pipe_hdl.index ]; +} + +static inline pipe_handle_t qhd_create_pipe_handle(ehci_qhd_t const * p_qhd, tusb_xfer_type_t xfer_type) +{ + pipe_handle_t pipe_hdl = { + .dev_addr = p_qhd->device_address, + .xfer_type = xfer_type + }; + + // TODO Isochronous transfer support + if (TUSB_XFER_CONTROL != xfer_type) // qhd index for control is meaningless + { + pipe_hdl.index = qhd_get_index(p_qhd); + } + + return pipe_hdl; +} + +//------------- TD helper -------------// +STATIC_ INLINE_ ehci_qtd_t* qtd_find_free(uint8_t dev_addr) +{ + uint8_t index=0; + while( indexnext.address); +} + +static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd) +{ + if (p_qhd->p_qtd_list_head == p_qhd->p_qtd_list_tail) // last TD --> make it NULL + { + p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = NULL; + }else + { + p_qhd->p_qtd_list_head = qtd_next( p_qhd->p_qtd_list_head ); + } +} + +static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) +{ + if (p_qhd->p_qtd_list_head == NULL) // empty list + { + p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = p_qtd_new; + }else + { + p_qhd->p_qtd_list_tail->next.address = (uint32_t) p_qtd_new; + p_qhd->p_qtd_list_tail = p_qtd_new; + } +} + +static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type, uint8_t interval) +{ + // address 0 uses async head, which always on the list --> cannot be cleared (ehci halted otherwise) + if (dev_addr != 0) + { + memclr_(p_qhd, sizeof(ehci_qhd_t)); + } + + p_qhd->device_address = dev_addr; + p_qhd->non_hs_period_inactive_next_xact = 0; + p_qhd->endpoint_number = endpoint_addr & 0x0F; + p_qhd->endpoint_speed = usbh_devices[dev_addr].speed; + p_qhd->data_toggle_control = (xfer_type == TUSB_XFER_CONTROL) ? 1 : 0; + p_qhd->head_list_flag = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static asyn list head + p_qhd->max_package_size = max_packet_size; + p_qhd->non_hs_control_endpoint = ((TUSB_XFER_CONTROL == xfer_type) && (p_qhd->endpoint_speed != TUSB_SPEED_HIGH)) ? 1 : 0; + p_qhd->nak_count_reload = 0; + + // Bulk/Control -> smask = cmask = 0 + // TODO Isochronous + if (TUSB_XFER_INTERRUPT == xfer_type) + { + if (TUSB_SPEED_HIGH == p_qhd->endpoint_speed) + { + ASSERT_INT_WITHIN(1, 16, interval, VOID_RETURN); + if ( interval < 4) // sub milisecond interval + { + p_qhd->interval_ms = 0; + p_qhd->interrupt_smask = (interval == 1) ? BIN8(11111111) : + (interval == 2) ? BIN8(10101010) : BIN8(01000100); + }else + { + p_qhd->interval_ms = (uint8_t) min16_of( 1 << (interval-4), 255 ); + p_qhd->interrupt_smask = BIT_(interval % 8); + } + }else + { + ASSERT( 0 != interval, VOID_RETURN); + // Full/Low: 4.12.2.1 (EHCI) case 1 schedule start split at 1 us & complete split at 2,3,4 uframes + p_qhd->interrupt_smask = 0x01; + p_qhd->non_hs_interrupt_cmask = BIN8(11100); + p_qhd->interval_ms = interval; + } + }else + { + p_qhd->interrupt_smask = p_qhd->non_hs_interrupt_cmask = 0; + } + + p_qhd->hub_address = usbh_devices[dev_addr].hub_addr; + p_qhd->hub_port = usbh_devices[dev_addr].hub_port; + p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet + + //------------- HCD Management Data -------------// + p_qhd->used = 1; + p_qhd->is_removing = 0; + p_qhd->p_qtd_list_head = NULL; + p_qhd->p_qtd_list_tail = NULL; + p_qhd->pid_non_control = (endpoint_addr & 0x80) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint + + //------------- active, but no TD list -------------// + p_qhd->qtd_overlay.halted = 0; + p_qhd->qtd_overlay.next.terminate = 1; + p_qhd->qtd_overlay.alternate.terminate = 1; + if (TUSB_XFER_BULK == xfer_type && p_qhd->endpoint_speed == TUSB_SPEED_HIGH && p_qhd->pid_non_control == EHCI_PID_OUT) + { + p_qhd->qtd_overlay.pingstate_err = 1; // do PING for Highspeed Bulk OUT, EHCI section 4.11 + } +} + +static void qtd_init(ehci_qtd_t* p_qtd, uint32_t data_ptr, uint16_t total_bytes) +{ + memclr_(p_qtd, sizeof(ehci_qtd_t)); + + p_qtd->used = 1; + + p_qtd->next.terminate = 1; // init to null + p_qtd->alternate.terminate = 1; // not used, always set to terminated + p_qtd->active = 1; + p_qtd->cerr = 3; // TODO 3 consecutive errors tolerance + p_qtd->data_toggle = 0; + p_qtd->total_bytes = total_bytes; + p_qtd->expected_bytes = total_bytes; + + p_qtd->buffer[0] = data_ptr; + for(uint8_t i=1; i<5; i++) + { + p_qtd->buffer[i] |= align4k( p_qtd->buffer[i-1] ) + 4096; + } +} + +//------------- List Managing Helper -------------// +static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type) +{ + new->address = current->address; + current->address = ((uint32_t) new) | (new_type << 1); +} + +static inline ehci_link_t* list_next(ehci_link_t *p_link_pointer) +{ + return (ehci_link_t*) align32(p_link_pointer->address); +} + +static ehci_link_t* list_find_previous_item(ehci_link_t* p_head, ehci_link_t* p_current) +{ + ehci_link_t *p_prev = p_head; + uint32_t max_loop = 0; + while( (align32(p_prev->address) != (uint32_t) p_head) && // not loop around + (align32(p_prev->address) != (uint32_t) p_current) && // not found yet + !p_prev->terminate && // not advanceable + max_loop < EHCI_MAX_QHD) + { + p_prev = list_next(p_prev); + max_loop++; + } + + return (align32(p_prev->address) != (uint32_t) p_head) ? p_prev : NULL; +} + +static tusb_error_t list_remove_qhd(ehci_link_t* p_head, ehci_link_t* p_remove) +{ + ehci_link_t *p_prev = list_find_previous_item(p_head, p_remove); + + ASSERT_PTR(p_prev, TUSB_ERROR_INVALID_PARA); + + p_prev->address = p_remove->address; + // EHCI 4.8.2 link the removing queue head to async/period head (which always reachable by Host Controller) + p_remove->address = ((uint32_t) p_head) | (EHCI_QUEUE_ELEMENT_QHD << 1); + + return TUSB_ERROR_NONE; +} + +#endif diff --git a/tinyusb/mcu_capacity.h b/tinyusb/mcu_capacity.h index e287cf4b5..958a71f01 100644 --- a/tinyusb/mcu_capacity.h +++ b/tinyusb/mcu_capacity.h @@ -1,98 +1,98 @@ -/**************************************************************************/ -/*! - @file mcu_capacity.h - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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 holders 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 ''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 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 tinyusb stack. -*/ -/**************************************************************************/ - -/** \file - * \brief TBD - * - * \note TBD - */ - -/** \ingroup TBD - * \defgroup TBD - * \brief TBD - * - * @{ - */ - -#ifndef _TUSB_MCU_CAPACITY_H_ -#define _TUSB_MCU_CAPACITY_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -// CAP is abbreviation for Capacity - -//--------------------------------------------------------------------+ -// ARCHTECTURE -//--------------------------------------------------------------------+ - - - -//--------------------------------------------------------------------+ -// Controller -//--------------------------------------------------------------------+ -#if MCU == MCU_LPC43XX || MCU == MCU_LPC18XX - #define CAP_CONTROLLER_NUMBER 2 -#else - #define CAP_CONTROLLER_NUMBER 1 -#endif - -#define CAP_MODE_DEVICE -#if MCU == MCU_LPC43XX || MCU == MCU_LPC18XX || MCU == MCU_LPC175X_6X - #define CAP_MODE_HOST -#endif - -#if MCU == MCU_LPC43XX || MCU == MCU_LPC18XX || MCU == MCU_LPC11UXX || MCU == MCU_LPC13UXX - #define CAP_DEVICE_ROMDRIVER -#endif - -//--------------------------------------------------------------------+ -// Validation -//--------------------------------------------------------------------+ -#if (CAP_CONTROLLER_NUMBER == 1) && ( defined TUSB_CFG_CONTROLLER1_MODE) - #error current MCU does not have the required number of controllers -#endif - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_MCU_CAPACITY_H_ */ - -/** @} */ +/**************************************************************************/ +/*! + @file mcu_capacity.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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 holders 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 ''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 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 tinyusb stack. +*/ +/**************************************************************************/ + +/** \file + * \brief TBD + * + * \note TBD + */ + +/** \ingroup TBD + * \defgroup TBD + * \brief TBD + * + * @{ + */ + +#ifndef _TUSB_MCU_CAPACITY_H_ +#define _TUSB_MCU_CAPACITY_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +// CAP is abbreviation for Capacity + +//--------------------------------------------------------------------+ +// ARCHTECTURE +//--------------------------------------------------------------------+ + + + +//--------------------------------------------------------------------+ +// Controller +//--------------------------------------------------------------------+ +#if MCU == MCU_LPC43XX || MCU == MCU_LPC18XX + #define CAP_CONTROLLER_NUMBER 2 +#else + #define CAP_CONTROLLER_NUMBER 1 +#endif + +#define CAP_MODE_DEVICE +#if MCU == MCU_LPC43XX || MCU == MCU_LPC18XX || MCU == MCU_LPC175X_6X + #define CAP_MODE_HOST +#endif + +#if MCU == MCU_LPC43XX || MCU == MCU_LPC18XX || MCU == MCU_LPC11UXX || MCU == MCU_LPC13UXX + #define CAP_DEVICE_ROMDRIVER +#endif + +//--------------------------------------------------------------------+ +// Validation +//--------------------------------------------------------------------+ +#if (CAP_CONTROLLER_NUMBER == 1) && ( defined TUSB_CFG_CONTROLLER_1_MODE) + #error current MCU does not have the required number of controllers +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_MCU_CAPACITY_H_ */ + +/** @} */ diff --git a/tinyusb/osal/osal.h b/tinyusb/osal/osal.h index d23cb518c..4c45b0087 100644 --- a/tinyusb/osal/osal.h +++ b/tinyusb/osal/osal.h @@ -1,204 +1,209 @@ -/**************************************************************************/ -/*! - @file osal.h - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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 holders 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 ''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 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 tinyusb stack. -*/ -/**************************************************************************/ - -/** \file - * \brief TBD - * - * \note TBD - */ - -/** \ingroup TBD - * \defgroup TBD - * \brief TBD - * - * @{ - */ - -#ifndef _TUSB_OSAL_H_ -#define _TUSB_OSAL_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -#include "tusb_option.h" - -#define TUSB_OS_NONE 1 -#define TUSB_OS_FREERTOS 2 -#define TUSB_OS_CMSIS_RTX 3 -#define TUSB_OS_UCOS2 4 -#define TUSB_OS_UCOS3 5 - -#ifndef _TEST_ - -#if TUSB_CFG_OS == TUSB_OS_NONE - #include "osal_none.h" -#else - #define OSAL_VAR - #if TUSB_CFG_OS == TUSB_OS_FREERTOS - #include "osal_freeRTOS.h" - #elif TUSB_CFG_OS == TUSB_OS_CMSIS_RTX - #include "osal_cmsis_rtx.h" - #else - #error TUSB_CFG_OS is not defined or OS is not supported yet - #endif -#endif - -#else // OSAL API for cmock - -#define OSAL_VAR -#include "osal_common.h" - -//------------- Tick -------------// -uint32_t osal_tick_get(void); - -//--------------------------------------------------------------------+ -// TASK API -//--------------------------------------------------------------------+ -typedef uint32_t osal_task_t; -tusb_error_t osal_task_create(osal_task_t *task); - -#define OSAL_TASK_DEF(code, stack_depth, prio) \ - osal_task_t variable - -#define OSAL_TASK_REF(name) (&name) - -#define OSAL_TASK_FUNCTION(task_name) \ - void task_name - -void osal_task_delay(uint32_t msec); - -#define OSAL_TASK_LOOP_BEGIN -#define OSAL_TASK_LOOP_END - -#define SUBTASK_EXIT(error) return error; - -//------------- Sub Task -------------// -#define OSAL_SUBTASK_INVOKED_AND_WAIT(subtask, status) \ - status = subtask - -#define OSAL_SUBTASK_BEGIN -#define OSAL_SUBTASK_END \ - return TUSB_ERROR_NONE; - -//------------- Sub Task Assert -------------// -#define _SUBTASK_ASSERT_ERROR_HANDLER(error, func_call)\ - func_call; return error - -#define SUBTASK_ASSERT_STATUS(sts) ASSERT_STATUS(sts) - -#define SUBTASK_ASSERT_STATUS_WITH_HANDLER(sts, func_call) \ - ASSERT_DEFINE_WITH_HANDLER(_SUBTASK_ASSERT_ERROR_HANDLER, func_call, tusb_error_t status = (tusb_error_t)(sts),\ - TUSB_ERROR_NONE == status, status, "%s", TUSB_ErrorStr[status]) - -#define SUBTASK_ASSERT(condition) ASSERT(condition, TUSB_ERROR_OSAL_TASK_FAILED) - -#define SUBTASK_ASSERT_WITH_HANDLER(condition, func_call) \ - ASSERT_DEFINE_WITH_HANDLER(_SUBTASK_ASSERT_ERROR_HANDLER, func_call, ,\ - condition, TUSB_ERROR_OSAL_TASK_FAILED, "%s", "evaluated to false") - - -//--------------------------------------------------------------------+ -// Semaphore API -//--------------------------------------------------------------------+ -typedef volatile uint8_t osal_semaphore_t; -typedef osal_semaphore_t * osal_semaphore_handle_t; - -#define OSAL_SEM_DEF(name)\ - osal_semaphore_t name - -#define OSAL_SEM_REF(name)\ - &name - -osal_semaphore_handle_t osal_semaphore_create(osal_semaphore_t * p_sem); -void osal_semaphore_wait(osal_semaphore_handle_t sem_hdl, uint32_t msec, tusb_error_t *p_error); -tusb_error_t osal_semaphore_post(osal_semaphore_handle_t sem_hdl); -void osal_semaphore_reset(osal_semaphore_handle_t sem_hdl); - -//--------------------------------------------------------------------+ -// MUTEX API (priority inheritance) -//--------------------------------------------------------------------+ -#define OSAL_MUTEX_DEF(name)\ - osal_mutex_t name - -#define OSAL_MUTEX_REF(name)\ - &name - -typedef osal_semaphore_t osal_mutex_t; -typedef osal_semaphore_handle_t osal_mutex_handle_t; - -osal_mutex_handle_t osal_mutex_create(osal_mutex_t * p_mutex); -void osal_mutex_wait(osal_mutex_handle_t mutex_hdl, uint32_t msec, tusb_error_t *p_error); -tusb_error_t osal_mutex_release(osal_mutex_handle_t mutex_hdl); -void osal_mutex_reset(osal_mutex_handle_t mutex_hdl); -//--------------------------------------------------------------------+ -// QUEUE API -//--------------------------------------------------------------------+ -typedef struct{ - uint32_t * const buffer ; ///< buffer pointer - uint8_t const depth ; ///< buffer size - volatile uint8_t count ; ///< bytes in fifo - volatile uint8_t wr_idx ; ///< write pointer - volatile uint8_t rd_idx ; ///< read pointer -} osal_queue_t; - -typedef osal_queue_t * osal_queue_handle_t; - -#define OSAL_QUEUE_DEF(name, queue_depth, type) \ - osal_queue_t name - -#define OSAL_QUEUE_REF(name) (&name) - -osal_queue_handle_t osal_queue_create (osal_queue_t *p_queue); -void osal_queue_receive (osal_queue_handle_t const queue_hdl, void *p_data, uint32_t msec, tusb_error_t *p_error); -tusb_error_t osal_queue_send (osal_queue_handle_t const queue_hdl, const void * data); -void osal_queue_flush(osal_queue_handle_t const queue_hdl); - -//--------------------------------------------------------------------+ -// TICK API -//--------------------------------------------------------------------+ -uint32_t osal_tick_get(void); -#endif - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_OSAL_H_ */ - -/** @} */ +/**************************************************************************/ +/*! + @file osal.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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 holders 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 ''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 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 tinyusb stack. +*/ +/**************************************************************************/ + +/** \file + * \brief TBD + * + * \note TBD + */ + +/** \ingroup TBD + * \defgroup TBD + * \brief TBD + * + * @{ + */ + +#ifndef _TUSB_OSAL_H_ +#define _TUSB_OSAL_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "tusb_option.h" + +/** \ingroup group_configuration + * \defgroup TUSB_OS RTOS Integration Selection + * \brief TUSB_CFG_OS must be defined to one of these + * @{ */ +#define TUSB_OS_NONE 1 ///< No RTOS is used +#define TUSB_OS_FREERTOS 2 ///< FreeRTOS is used +#define TUSB_OS_CMSIS_RTX 3 ///< CMSIS RTX is used +#define TUSB_OS_UCOS2 4 ///< MicroC OS II is used (not supported yet) +#define TUSB_OS_UCOS3 5 ///< MicroC OS III is used (not supported yet) +/** @} */ + +#ifndef _TEST_ + +#if TUSB_CFG_OS == TUSB_OS_NONE + #include "osal_none.h" +#else + #define OSAL_VAR + #if TUSB_CFG_OS == TUSB_OS_FREERTOS + #include "osal_freeRTOS.h" + #elif TUSB_CFG_OS == TUSB_OS_CMSIS_RTX + #include "osal_cmsis_rtx.h" + #else + #error TUSB_CFG_OS is not defined or OS is not supported yet + #endif +#endif + +#else // OSAL API for cmock + +#define OSAL_VAR +#include "osal_common.h" + +//------------- Tick -------------// +uint32_t osal_tick_get(void); + +//--------------------------------------------------------------------+ +// TASK API +//--------------------------------------------------------------------+ +typedef uint32_t osal_task_t; +tusb_error_t osal_task_create(osal_task_t *task); + +#define OSAL_TASK_DEF(code, stack_depth, prio) \ + osal_task_t variable + +#define OSAL_TASK_REF(name) (&name) + +#define OSAL_TASK_FUNCTION(task_name) \ + void task_name + +void osal_task_delay(uint32_t msec); + +#define OSAL_TASK_LOOP_BEGIN +#define OSAL_TASK_LOOP_END + +#define SUBTASK_EXIT(error) return error; + +//------------- Sub Task -------------// +#define OSAL_SUBTASK_INVOKED_AND_WAIT(subtask, status) \ + status = subtask + +#define OSAL_SUBTASK_BEGIN +#define OSAL_SUBTASK_END \ + return TUSB_ERROR_NONE; + +//------------- Sub Task Assert -------------// +#define _SUBTASK_ASSERT_ERROR_HANDLER(error, func_call)\ + func_call; return error + +#define SUBTASK_ASSERT_STATUS(sts) ASSERT_STATUS(sts) + +#define SUBTASK_ASSERT_STATUS_WITH_HANDLER(sts, func_call) \ + ASSERT_DEFINE_WITH_HANDLER(_SUBTASK_ASSERT_ERROR_HANDLER, func_call, tusb_error_t status = (tusb_error_t)(sts),\ + TUSB_ERROR_NONE == status, status, "%s", TUSB_ErrorStr[status]) + +#define SUBTASK_ASSERT(condition) ASSERT(condition, TUSB_ERROR_OSAL_TASK_FAILED) + +#define SUBTASK_ASSERT_WITH_HANDLER(condition, func_call) \ + ASSERT_DEFINE_WITH_HANDLER(_SUBTASK_ASSERT_ERROR_HANDLER, func_call, ,\ + condition, TUSB_ERROR_OSAL_TASK_FAILED, "%s", "evaluated to false") + + +//--------------------------------------------------------------------+ +// Semaphore API +//--------------------------------------------------------------------+ +typedef volatile uint8_t osal_semaphore_t; +typedef osal_semaphore_t * osal_semaphore_handle_t; + +#define OSAL_SEM_DEF(name)\ + osal_semaphore_t name + +#define OSAL_SEM_REF(name)\ + &name + +osal_semaphore_handle_t osal_semaphore_create(osal_semaphore_t * p_sem); +void osal_semaphore_wait(osal_semaphore_handle_t sem_hdl, uint32_t msec, tusb_error_t *p_error); +tusb_error_t osal_semaphore_post(osal_semaphore_handle_t sem_hdl); +void osal_semaphore_reset(osal_semaphore_handle_t sem_hdl); + +//--------------------------------------------------------------------+ +// MUTEX API (priority inheritance) +//--------------------------------------------------------------------+ +#define OSAL_MUTEX_DEF(name)\ + osal_mutex_t name + +#define OSAL_MUTEX_REF(name)\ + &name + +typedef osal_semaphore_t osal_mutex_t; +typedef osal_semaphore_handle_t osal_mutex_handle_t; + +osal_mutex_handle_t osal_mutex_create(osal_mutex_t * p_mutex); +void osal_mutex_wait(osal_mutex_handle_t mutex_hdl, uint32_t msec, tusb_error_t *p_error); +tusb_error_t osal_mutex_release(osal_mutex_handle_t mutex_hdl); +void osal_mutex_reset(osal_mutex_handle_t mutex_hdl); +//--------------------------------------------------------------------+ +// QUEUE API +//--------------------------------------------------------------------+ +typedef struct{ + uint32_t * const buffer ; ///< buffer pointer + uint8_t const depth ; ///< buffer size + volatile uint8_t count ; ///< bytes in fifo + volatile uint8_t wr_idx ; ///< write pointer + volatile uint8_t rd_idx ; ///< read pointer +} osal_queue_t; + +typedef osal_queue_t * osal_queue_handle_t; + +#define OSAL_QUEUE_DEF(name, queue_depth, type) \ + osal_queue_t name + +#define OSAL_QUEUE_REF(name) (&name) + +osal_queue_handle_t osal_queue_create (osal_queue_t *p_queue); +void osal_queue_receive (osal_queue_handle_t const queue_hdl, void *p_data, uint32_t msec, tusb_error_t *p_error); +tusb_error_t osal_queue_send (osal_queue_handle_t const queue_hdl, const void * data); +void osal_queue_flush(osal_queue_handle_t const queue_hdl); + +//--------------------------------------------------------------------+ +// TICK API +//--------------------------------------------------------------------+ +uint32_t osal_tick_get(void); +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_OSAL_H_ */ + +/** @} */ diff --git a/tinyusb/tusb_option.h b/tinyusb/tusb_option.h index f479d0a79..2330835d8 100644 --- a/tinyusb/tusb_option.h +++ b/tinyusb/tusb_option.h @@ -1,192 +1,195 @@ -/**************************************************************************/ -/*! - @file tusb_option.h - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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 holders 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 ''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 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 tinyusb stack. -*/ -/**************************************************************************/ - -/** \file - * \brief Configure File - * - * \note TBD - */ - -/** - * \defgroup Group_TinyUSB_Configure Configuration tusb_option.h - * @{ - */ - -#ifndef _TUSB_TUSB_OPTION_H_ -#define _TUSB_TUSB_OPTION_H_ - -#define TUSB_VERSION_YEAR 00 -#define TUSB_VERSION_MONTH 00 -#define TUSB_VERSION_WEEK 0 -#define TUSB_VERSION_NAME "alpha" -#define TUSB_VERSION XSTRING_(TUSB_VERSION_YEAR) "." XSTRING_(TUSB_VERSION_MONTH) - -#define MCU_LPC13UXX 1 -#define MCU_LPC11UXX 2 -#define MCU_LPC43XX 3 -#define MCU_LPC18XX 4 -#define MCU_LPC175X_6X 5 -#define MCU_LPC177X_8X 6 - -/// define this symbol will make tinyusb look for external configure file -#include "mcu_capacity.h" - -#ifdef TUSB_CFG_CONFIG_FILE - #include TUSB_CFG_CONFIG_FILE -#else - #include "tusb_config.h" -#endif - -//--------------------------------------------------------------------+ -// CONTROLLER -//--------------------------------------------------------------------+ -#define TUSB_MODE_HOST 0x02 -#define TUSB_MODE_DEVICE 0x01 -#define TUSB_MODE_NONE 0x00 - -#define CONTROLLER_HOST_NUMBER (\ - ((TUSB_CFG_CONTROLLER0_MODE & TUSB_MODE_HOST) ? 1 : 0) + \ - ((TUSB_CFG_CONTROLLER1_MODE & TUSB_MODE_HOST) ? 1 : 0)) - -#define CONTROLLER_DEVICE_NUMBER (\ - ((TUSB_CFG_CONTROLLER0_MODE & TUSB_MODE_DEVICE) ? 1 : 0) + \ - ((TUSB_CFG_CONTROLLER1_MODE & TUSB_MODE_DEVICE) ? 1 : 0)) - -#define MODE_HOST_SUPPORTED (CONTROLLER_HOST_NUMBER > 0) -#define MODE_DEVICE_SUPPORTED (CONTROLLER_DEVICE_NUMBER > 0) - -#if !MODE_HOST_SUPPORTED && !MODE_DEVICE_SUPPORTED - #error please configure at least 1 TUSB_CFG_CONTROLLERn_MODE to TUSB_MODE_HOST and/or TUSB_MODE_DEVICE -#endif - -//--------------------------------------------------------------------+ -// COMMON OPTIONS -//--------------------------------------------------------------------+ - -// level 3: ATTR_ALWAYS_INLINE is null, ASSERT has text, Error has its String, STATIC_VAR is NULL -// level 2: ATTR_ALWAYS_INLINE is attribute, ASSERT has no text, Error has no strings -/// 0: no debug information 3: most debug information provided -#ifndef TUSB_CFG_DEBUG - #define TUSB_CFG_DEBUG 2 - #warning TUSB_CFG_DEBUG is not defined, default value is 3 -#endif - -/// USB RAM Section Placement, MCU's usb controller often has limited access to specific RAM region. This will be used to declare internal variables as follow: -/// uint8_t tinyusb_data[10] TUSB_CFG_ATTR_USBRAM; -/// if your mcu's usb controller has no such limit, define TUSB_CFG_ATTR_USBRAM as empty macro. -#ifndef TUSB_CFG_ATTR_USBRAM - #error TUSB_CFG_ATTR_USBRAM is not defined, please help me know how to place data in accessible RAM for usb controller -#endif - -#if TUSB_CFG_OS == TUSB_OS_NONE - #ifndef TUSB_CFG_OS_TICKS_PER_SECOND - #error TUSB_CFG_OS_TICKS_PER_SECOND is required to use with OS_NONE - #endif -#else - #ifndef TUSB_CFG_OS_TASK_PRIO - #error TUSB_CFG_OS_TASK_PRIO need to be defined (hint: use the highest if possible) - #endif -#endif - -#ifndef TUSB_CFG_CONFIGURATION_MAX - #define TUSB_CFG_CONFIGURATION_MAX 1 - #warning TUSB_CFG_CONFIGURATION_MAX is not defined, default value is 1 -#endif - -//--------------------------------------------------------------------+ -// HOST OPTIONS -//--------------------------------------------------------------------+ -#if MODE_HOST_SUPPORTED - #ifndef TUSB_CFG_HOST_DEVICE_MAX - #define TUSB_CFG_HOST_DEVICE_MAX 1 - #warning TUSB_CFG_HOST_DEVICE_MAX is not defined, default value is 1 - #endif - - //------------- HUB CLASS -------------// - #if TUSB_CFG_HOST_HUB && (TUSB_CFG_HOST_DEVICE_MAX == 1) - #error there is no benefit enable hub with max device is 1. Please disable hub or increase TUSB_CFG_HOST_DEVICE_MAX - #endif - - //------------- HID CLASS -------------// - #define HOST_CLASS_HID ( TUSB_CFG_HOST_HID_KEYBOARD + TUSB_CFG_HOST_HID_MOUSE + TUSB_CFG_HOST_HID_GENERIC ) - #if HOST_CLASS_HID - #define HOST_HCD_XFER_INTERRUPT - #endif - - #ifndef TUSB_CFG_HOST_ENUM_BUFFER_SIZE - #define TUSB_CFG_HOST_ENUM_BUFFER_SIZE 256 - #warning TUSB_CFG_HOST_ENUM_BUFFER_SIZE is not defined, default value is 256 - #endif - - //------------- CLASS -------------// -#endif // end TUSB_CFG_HOST - -//--------------------------------------------------------------------+ -// DEVICE OPTIONS -//--------------------------------------------------------------------+ -#if MODE_DEVICE_SUPPORTED - -#if defined(CAP_DEVICE_ROMDRIVER) && !TUSB_CFG_DEVICE_USE_ROM_DRIVER - #error only rom driver for these mcu are supported now -#endif - -#define DEVICE_CLASS_HID ( TUSB_CFG_DEVICE_HID_KEYBOARD + TUSB_CFG_DEVICE_HID_MOUSE + TUSB_CFG_DEVICE_HID_GENERIC ) - - -#endif - - - -#define USB_FS_MAX_BULK_PACKET 64 -#define USB_HS_MAX_BULK_PACKET USB_FS_MAX_BULK_PACKET /* Full speed device only */ - -/* HID In/Out Endpoint Address */ -#define HID_KEYBOARD_EP_IN ENDPOINT_IN_LOGICAL_TO_PHYSICAL(1) -#define HID_MOUSE_EP_IN ENDPOINT_IN_LOGICAL_TO_PHYSICAL(4) - -/* CDC Endpoint Address */ -#define CDC_NOTIFICATION_EP ENDPOINT_IN_LOGICAL_TO_PHYSICAL(2) -#define CDC_DATA_EP_OUT ENDPOINT_OUT_LOGICAL_TO_PHYSICAL(3) -#define CDC_DATA_EP_IN ENDPOINT_IN_LOGICAL_TO_PHYSICAL(3) - -#define CDC_NOTIFICATION_EP_MAXPACKETSIZE 8 -#define CDC_DATA_EP_MAXPACKET_SIZE 16 - -#endif /* _TUSB_TUSB_OPTION_H_ */ - -/** @} */ +/**************************************************************************/ +/*! + @file tusb_option.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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 holders 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 ''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 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 tinyusb stack. +*/ +/**************************************************************************/ + +#ifndef _TUSB_TUSB_OPTION_H_ +#define _TUSB_TUSB_OPTION_H_ + +/** \defgroup group_configuration Configuration tusb_config.h + * @{ */ + +#define TUSB_VERSION_YEAR 00 +#define TUSB_VERSION_MONTH 00 +#define TUSB_VERSION_WEEK 0 +#define TUSB_VERSION_NAME "alpha" +#define TUSB_VERSION XSTRING_(TUSB_VERSION_YEAR) "." XSTRING_(TUSB_VERSION_MONTH) + +/** \defgroup MCU_ MCU Selection + * \brief TUSB_CFG_MCU must be defined to one of these + * @{ */ +#define MCU_LPC13XX_12ADC 1 ///< NXP LPC13xx 12 bit ADC family with USB on-chip Rom Driver (not supported yet) +#define MCU_LPC13XX_10ADC 2 ///< NXP LPC13xx 10 bit ADC family (not supported yet) +#define MCU_LPC11UXX 3 ///< NXP LPC11Uxx family (not supported yet) +#define MCU_LPC43XX 4 ///< NXP LPC43xx family +#define MCU_LPC18XX 5 ///< NXP LPC18xx family (not supported yet) +#define MCU_LPC175X_6X 6 ///< NXP LPC175x, LPC176x family (not supported yet) +#define MCU_LPC177X_8X 7 ///< NXP LPC177x, LPC178x family (not supported yet) +/** @} */ + +#include "mcu_capacity.h" + +#ifdef TUSB_CFG_CONFIG_FILE + #include TUSB_CFG_CONFIG_FILE +#else + #include "tusb_config.h" +#endif + +//--------------------------------------------------------------------+ +// CONTROLLER +//--------------------------------------------------------------------+ +/** \defgroup TUSB_MODE Host/Device Mode Selection + * \brief TUSB_CFG_CONTROLLER_N_MODE must be defined with these + * @{ */ +#define TUSB_MODE_HOST 0x02 ///< Host Mode +#define TUSB_MODE_DEVICE 0x01 ///< Device Mode +#define TUSB_MODE_NONE 0x00 ///< Disabled +/** @} */ + +#define CONTROLLER_HOST_NUMBER (\ + ((TUSB_CFG_CONTROLLER_0_MODE & TUSB_MODE_HOST) ? 1 : 0) + \ + ((TUSB_CFG_CONTROLLER_1_MODE & TUSB_MODE_HOST) ? 1 : 0)) + +#define CONTROLLER_DEVICE_NUMBER (\ + ((TUSB_CFG_CONTROLLER_0_MODE & TUSB_MODE_DEVICE) ? 1 : 0) + \ + ((TUSB_CFG_CONTROLLER_1_MODE & TUSB_MODE_DEVICE) ? 1 : 0)) + +#define MODE_HOST_SUPPORTED (CONTROLLER_HOST_NUMBER > 0) +#define MODE_DEVICE_SUPPORTED (CONTROLLER_DEVICE_NUMBER > 0) + +#if !MODE_HOST_SUPPORTED && !MODE_DEVICE_SUPPORTED + #error please configure at least 1 TUSB_CFG_CONTROLLER_N_MODE to TUSB_MODE_HOST and/or TUSB_MODE_DEVICE +#endif + +//--------------------------------------------------------------------+ +// COMMON OPTIONS +//--------------------------------------------------------------------+ +/** + determines the debug level for the stack + - Level 3: ATTR_ALWAYS_INLINE is null, ASSERT has text, Error has its String, STATIC_VAR is NULL + - Level 2: ATTR_ALWAYS_INLINE is attribute, ASSERT has no text, Error has no strings + - Level 1: TBD + - Level 0: no debug information is generated +*/ +#ifndef TUSB_CFG_DEBUG + #define TUSB_CFG_DEBUG 2 + #warning TUSB_CFG_DEBUG is not defined, default value is 3 +#endif + +#ifndef TUSB_CFG_ATTR_USBRAM + #error TUSB_CFG_ATTR_USBRAM is not defined, please help me know how to place data in accessible RAM for usb controller +#endif + +#if TUSB_CFG_OS == TUSB_OS_NONE + #ifndef TUSB_CFG_OS_TICKS_PER_SECOND + #error TUSB_CFG_OS_TICKS_PER_SECOND is required to use with OS_NONE + #endif +#else + #ifndef TUSB_CFG_OS_TASK_PRIO + #error TUSB_CFG_OS_TASK_PRIO need to be defined (hint: use the highest if possible) + #endif +#endif + +/** + * Maximum number of supported USB's configuration (currently only support only 1) + */ +#ifndef TUSB_CFG_CONFIGURATION_MAX + #define TUSB_CFG_CONFIGURATION_MAX 1 + #warning TUSB_CFG_CONFIGURATION_MAX is not defined, default value is 1 +#endif + +//--------------------------------------------------------------------+ +// HOST OPTIONS +//--------------------------------------------------------------------+ +#if MODE_HOST_SUPPORTED + #ifndef TUSB_CFG_HOST_DEVICE_MAX + #define TUSB_CFG_HOST_DEVICE_MAX 1 + #warning TUSB_CFG_HOST_DEVICE_MAX is not defined, default value is 1 + #endif + + //------------- HUB CLASS -------------// + #if TUSB_CFG_HOST_HUB && (TUSB_CFG_HOST_DEVICE_MAX == 1) + #error there is no benefit enable hub with max device is 1. Please disable hub or increase TUSB_CFG_HOST_DEVICE_MAX + #endif + + //------------- HID CLASS -------------// + #define HOST_CLASS_HID ( TUSB_CFG_HOST_HID_KEYBOARD + TUSB_CFG_HOST_HID_MOUSE + TUSB_CFG_HOST_HID_GENERIC ) + #if HOST_CLASS_HID + #define HOST_HCD_XFER_INTERRUPT + #endif + + #ifndef TUSB_CFG_HOST_ENUM_BUFFER_SIZE + #define TUSB_CFG_HOST_ENUM_BUFFER_SIZE 256 + #warning TUSB_CFG_HOST_ENUM_BUFFER_SIZE is not defined, default value is 256 + #endif + + //------------- CLASS -------------// +#endif // MODE_HOST_SUPPORTED + +//--------------------------------------------------------------------+ +// DEVICE OPTIONS +//--------------------------------------------------------------------+ +#if MODE_DEVICE_SUPPORTED + +#if defined(CAP_DEVICE_ROMDRIVER) && !TUSB_CFG_DEVICE_USE_ROM_DRIVER + #error only rom driver for these mcu are supported now +#endif + +#define DEVICE_CLASS_HID ( TUSB_CFG_DEVICE_HID_KEYBOARD + TUSB_CFG_DEVICE_HID_MOUSE + TUSB_CFG_DEVICE_HID_GENERIC ) + + +#endif // MODE_DEVICE_SUPPORTED + + + +#define USB_FS_MAX_BULK_PACKET 64 +#define USB_HS_MAX_BULK_PACKET USB_FS_MAX_BULK_PACKET /* Full speed device only */ + +/* HID In/Out Endpoint Address */ +#define HID_KEYBOARD_EP_IN ENDPOINT_IN_LOGICAL_TO_PHYSICAL(1) +#define HID_MOUSE_EP_IN ENDPOINT_IN_LOGICAL_TO_PHYSICAL(4) + +/* CDC Endpoint Address */ +#define CDC_NOTIFICATION_EP ENDPOINT_IN_LOGICAL_TO_PHYSICAL(2) +#define CDC_DATA_EP_OUT ENDPOINT_OUT_LOGICAL_TO_PHYSICAL(3) +#define CDC_DATA_EP_IN ENDPOINT_IN_LOGICAL_TO_PHYSICAL(3) + +#define CDC_NOTIFICATION_EP_MAXPACKETSIZE 8 +#define CDC_DATA_EP_MAXPACKET_SIZE 16 + +#endif /* _TUSB_TUSB_OPTION_H_ */ + +/** @} */ -- cgit v1.3.1