rename subfolder source to src
This commit is contained in:
@@ -0,0 +1,412 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
/** \ingroup group_class
|
||||
* \defgroup ClassDriver_CDC Communication Device Class (CDC)
|
||||
* Currently only Abstract Control Model subclass is supported
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_CDC_H__
|
||||
#define _TUSB_CDC_H__
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup ClassDriver_CDC_Common Common Definitions
|
||||
* @{ */
|
||||
|
||||
|
||||
/// CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In)
|
||||
typedef enum
|
||||
{
|
||||
CDC_PIPE_NOTIFICATION , ///< Notification pipe
|
||||
CDC_PIPE_DATA_IN , ///< Data in pipe
|
||||
CDC_PIPE_DATA_OUT , ///< Data out pipe
|
||||
CDC_PIPE_ERROR , ///< Invalid Pipe ID
|
||||
}cdc_pipeid_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CDC COMMUNICATION INTERFACE CLASS
|
||||
//--------------------------------------------------------------------+
|
||||
/// Communication Interface Subclass Codes
|
||||
typedef enum
|
||||
{
|
||||
CDC_COMM_SUBCLASS_DIRECT_LINE_CONTROL_MODEL = 0x01 , ///< Direct Line Control Model [USBPSTN1.2]
|
||||
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL , ///< Abstract Control Model [USBPSTN1.2]
|
||||
CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL , ///< Telephone Control Model [USBPSTN1.2]
|
||||
CDC_COMM_SUBCLASS_MULTICHANNEL_CONTROL_MODEL , ///< Multi-Channel Control Model [USBISDN1.2]
|
||||
CDC_COMM_SUBCLASS_CAPI_CONTROL_MODEL , ///< CAPI Control Model [USBISDN1.2]
|
||||
CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL , ///< Ethernet Networking Control Model [USBECM1.2]
|
||||
CDC_COMM_SUBCLASS_ATM_NETWORKING_CONTROL_MODEL , ///< ATM Networking Control Model [USBATM1.2]
|
||||
CDC_COMM_SUBCLASS_WIRELESS_HANDSET_CONTROL_MODEL , ///< Wireless Handset Control Model [USBWMC1.1]
|
||||
CDC_COMM_SUBCLASS_DEVICE_MANAGEMENT , ///< Device Management [USBWMC1.1]
|
||||
CDC_COMM_SUBCLASS_MOBILE_DIRECT_LINE_MODEL , ///< Mobile Direct Line Model [USBWMC1.1]
|
||||
CDC_COMM_SUBCLASS_OBEX , ///< OBEX [USBWMC1.1]
|
||||
CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL ///< Ethernet Emulation Model [USBEEM1.0]
|
||||
} cdc_comm_sublcass_type_t;
|
||||
|
||||
/// Communication Interface Protocol Codes
|
||||
typedef enum
|
||||
{
|
||||
CDC_COMM_PROTOCOL_ATCOMMAND = 0x01 , ///< AT Commands: V.250 etc
|
||||
CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101 , ///< AT Commands defined by PCCA-101
|
||||
CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO , ///< AT Commands defined by PCCA-101 & Annex O
|
||||
CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707 , ///< AT Commands defined by GSM 07.07
|
||||
CDC_COMM_PROTOCOL_ATCOMMAND_3GPP_27007 , ///< AT Commands defined by 3GPP 27.007
|
||||
CDC_COMM_PROTOCOL_ATCOMMAND_CDMA , ///< AT Commands defined by TIA for CDMA
|
||||
CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL ///< Ethernet Emulation Model
|
||||
} cdc_comm_protocol_type_t;
|
||||
|
||||
//------------- SubType Descriptor in COMM Functional Descriptor -------------//
|
||||
/// Communication Interface SubType Descriptor
|
||||
typedef enum
|
||||
{
|
||||
CDC_FUNC_DESC_HEADER = 0x00 , ///< Header Functional Descriptor, which marks the beginning of the concatenated set of functional descriptors for the interface.
|
||||
CDC_FUNC_DESC_CALL_MANAGEMENT = 0x01 , ///< Call Management Functional Descriptor.
|
||||
CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT = 0x02 , ///< Abstract Control Management Functional Descriptor.
|
||||
CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT = 0x03 , ///< Direct Line Management Functional Descriptor.
|
||||
CDC_FUNC_DESC_TELEPHONE_RINGER = 0x04 , ///< Telephone Ringer Functional Descriptor.
|
||||
CDC_FUNC_DESC_TELEPHONE_CALL_AND_LINE_STATE_REPORTING_CAPACITY = 0x05 , ///< Telephone Call and Line State Reporting Capabilities Functional Descriptor.
|
||||
CDC_FUNC_DESC_UNION = 0x06 , ///< Union Functional Descriptor
|
||||
CDC_FUNC_DESC_COUNTRY_SELECTION = 0x07 , ///< Country Selection Functional Descriptor
|
||||
CDC_FUNC_DESC_TELEPHONE_OPERATIONAL_MODES = 0x08 , ///< Telephone Operational ModesFunctional Descriptor
|
||||
CDC_FUNC_DESC_USB_TERMINAL = 0x09 , ///< USB Terminal Functional Descriptor
|
||||
CDC_FUNC_DESC_NETWORK_CHANNEL_TERMINAL = 0x0A , ///< Network Channel Terminal Descriptor
|
||||
CDC_FUNC_DESC_PROTOCOL_UNIT = 0x0B , ///< Protocol Unit Functional Descriptor
|
||||
CDC_FUNC_DESC_EXTENSION_UNIT = 0x0C , ///< Extension Unit Functional Descriptor
|
||||
CDC_FUNC_DESC_MULTICHANEL_MANAGEMENT = 0x0D , ///< Multi-Channel Management Functional Descriptor
|
||||
CDC_FUNC_DESC_CAPI_CONTROL_MANAGEMENT = 0x0E , ///< CAPI Control Management Functional Descriptor
|
||||
CDC_FUNC_DESC_ETHERNET_NETWORKING = 0x0F , ///< Ethernet Networking Functional Descriptor
|
||||
CDC_FUNC_DESC_ATM_NETWORKING = 0x10 , ///< ATM Networking Functional Descriptor
|
||||
CDC_FUNC_DESC_WIRELESS_HANDSET_CONTROL_MODEL = 0x11 , ///< Wireless Handset Control Model Functional Descriptor
|
||||
CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL = 0x12 , ///< Mobile Direct Line Model Functional Descriptor
|
||||
CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL_DETAIL = 0x13 , ///< MDLM Detail Functional Descriptor
|
||||
CDC_FUNC_DESC_DEVICE_MANAGEMENT_MODEL = 0x14 , ///< Device Management Model Functional Descriptor
|
||||
CDC_FUNC_DESC_OBEX = 0x15 , ///< OBEX Functional Descriptor
|
||||
CDC_FUNC_DESC_COMMAND_SET = 0x16 , ///< Command Set Functional Descriptor
|
||||
CDC_FUNC_DESC_COMMAND_SET_DETAIL = 0x17 , ///< Command Set Detail Functional Descriptor
|
||||
CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL = 0x18 , ///< Telephone Control Model Functional Descriptor
|
||||
CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER = 0x19 ///< OBEX Service Identifier Functional Descriptor
|
||||
}cdc_func_desc_type_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CDC DATA INTERFACE CLASS
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// SUBCLASS code of Data Interface is not used and should/must be zero
|
||||
/// Data Interface Protocol Codes
|
||||
typedef enum{
|
||||
CDC_DATA_PROTOCOL_ISDN_BRI = 0x30, ///< Physical interface protocol for ISDN BRI
|
||||
CDC_DATA_PROTOCOL_HDLC = 0x31, ///< HDLC
|
||||
CDC_DATA_PROTOCOL_TRANSPARENT = 0x32, ///< Transparent
|
||||
CDC_DATA_PROTOCOL_Q921_MANAGEMENT = 0x50, ///< Management protocol for Q.921 data link protocol
|
||||
CDC_DATA_PROTOCOL_Q921_DATA_LINK = 0x51, ///< Data link protocol for Q.931
|
||||
CDC_DATA_PROTOCOL_Q921_TEI_MULTIPLEXOR = 0x52, ///< TEI-multiplexor for Q.921 data link protocol
|
||||
CDC_DATA_PROTOCOL_V42BIS_DATA_COMPRESSION = 0x90, ///< Data compression procedures
|
||||
CDC_DATA_PROTOCOL_EURO_ISDN = 0x91, ///< Euro-ISDN protocol control
|
||||
CDC_DATA_PROTOCOL_V24_RATE_ADAPTION_TO_ISDN = 0x92, ///< V.24 rate adaptation to ISDN
|
||||
CDC_DATA_PROTOCOL_CAPI_COMMAND = 0x93, ///< CAPI Commands
|
||||
CDC_DATA_PROTOCOL_HOST_BASED_DRIVER = 0xFD, ///< Host based driver. Note: This protocol code should only be used in messages between host and device to identify the host driver portion of a protocol stack.
|
||||
CDC_DATA_PROTOCOL_IN_PROTOCOL_UNIT_FUNCTIONAL_DESCRIPTOR = 0xFE ///< The protocol(s) are described using a ProtocolUnit Functional Descriptors on Communications Class Interface
|
||||
}cdc_data_protocol_type_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MANAGEMENT ELEMENT REQUEST (CONTROL ENDPOINT)
|
||||
//--------------------------------------------------------------------+
|
||||
/// Communication Interface Management Element Request Codes
|
||||
typedef enum
|
||||
{
|
||||
CDC_REQUEST_SEND_ENCAPSULATED_COMMAND = 0x00, ///< is used to issue a command in the format of the supported control protocol of the Communications Class interface
|
||||
CDC_REQUEST_GET_ENCAPSULATED_RESPONSE = 0x01, ///< is used to request a response in the format of the supported control protocol of the Communications Class interface.
|
||||
|
||||
CDC_REQUEST_SET_COMM_FEATURE = 0x02,
|
||||
CDC_REQUEST_GET_COMM_FEATURE = 0x03,
|
||||
CDC_REQUEST_CLEAR_COMM_FEATURE = 0x04,
|
||||
|
||||
CDC_REQUEST_SET_AUX_LINE_STATE = 0x10,
|
||||
CDC_REQUEST_SET_HOOK_STATE = 0x11,
|
||||
CDC_REQUEST_PULSE_SETUP = 0x12,
|
||||
CDC_REQUEST_SEND_PULSE = 0x13,
|
||||
CDC_REQUEST_SET_PULSE_TIME = 0x14,
|
||||
CDC_REQUEST_RING_AUX_JACK = 0x15,
|
||||
|
||||
CDC_REQUEST_SET_LINE_CODING = 0x20,
|
||||
CDC_REQUEST_GET_LINE_CODING = 0x21,
|
||||
CDC_REQUEST_SET_CONTROL_LINE_STATE = 0x22,
|
||||
CDC_REQUEST_SEND_BREAK = 0x23,
|
||||
|
||||
CDC_REQUEST_SET_RINGER_PARMS = 0x30,
|
||||
CDC_REQUEST_GET_RINGER_PARMS = 0x31,
|
||||
CDC_REQUEST_SET_OPERATION_PARMS = 0x32,
|
||||
CDC_REQUEST_GET_OPERATION_PARMS = 0x33,
|
||||
CDC_REQUEST_SET_LINE_PARMS = 0x34,
|
||||
CDC_REQUEST_GET_LINE_PARMS = 0x35,
|
||||
CDC_REQUEST_DIAL_DIGITS = 0x36,
|
||||
CDC_REQUEST_SET_UNIT_PARAMETER = 0x37,
|
||||
CDC_REQUEST_GET_UNIT_PARAMETER = 0x38,
|
||||
CDC_REQUEST_CLEAR_UNIT_PARAMETER = 0x39,
|
||||
CDC_REQUEST_GET_PROFILE = 0x3A,
|
||||
|
||||
CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS = 0x40,
|
||||
CDC_REQUEST_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41,
|
||||
CDC_REQUEST_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42,
|
||||
CDC_REQUEST_SET_ETHERNET_PACKET_FILTER = 0x43,
|
||||
CDC_REQUEST_GET_ETHERNET_STATISTIC = 0x44,
|
||||
|
||||
CDC_REQUEST_SET_ATM_DATA_FORMAT = 0x50,
|
||||
CDC_REQUEST_GET_ATM_DEVICE_STATISTICS = 0x51,
|
||||
CDC_REQUEST_SET_ATM_DEFAULT_VC = 0x52,
|
||||
CDC_REQUEST_GET_ATM_VC_STATISTICS = 0x53,
|
||||
|
||||
CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60,
|
||||
}cdc_management_request_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MANAGEMENT ELEMENENT NOTIFICATION (NOTIFICATION ENDPOINT)
|
||||
//--------------------------------------------------------------------+
|
||||
/// Communication Interface Management Element Notification Codes
|
||||
typedef enum
|
||||
{
|
||||
NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status.
|
||||
RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request.
|
||||
|
||||
AUX_JACK_HOOK_STATE = 0x08,
|
||||
RING_DETECT = 0x09,
|
||||
|
||||
SERIAL_STATE = 0x20,
|
||||
|
||||
CALL_STATE_CHANGE = 0x28,
|
||||
LINE_STATE_CHANGE = 0x29,
|
||||
CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred
|
||||
MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40,
|
||||
}cdc_notification_request_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// FUNCTIONAL DESCRIPTOR (COMMUNICATION INTERFACE)
|
||||
//--------------------------------------------------------------------+
|
||||
/// Header Functional Descriptor (Communication Interface)
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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;
|
||||
|
||||
/// Union Functional Descriptor (Communication Interface)
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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)\
|
||||
struct ATTR_PACKED { \
|
||||
uint8_t bLength ;\
|
||||
uint8_t bDescriptorType ;\
|
||||
uint8_t bDescriptorSubType ;\
|
||||
uint8_t bControlInterface ;\
|
||||
uint8_t bSubordinateInterface[no_slave] ;\
|
||||
}
|
||||
|
||||
/// Country Selection Functional Descriptor (Communication Interface)
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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) \
|
||||
struct ATTR_PACKED {\
|
||||
uint8_t bLength ;\
|
||||
uint8_t bDescriptorType ;\
|
||||
uint8_t bDescriptorSubType ;\
|
||||
uint8_t iCountryCodeRelDate ;\
|
||||
uint16_t wCountryCode[no_country] ;\
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PUBLIC SWITCHED TELEPHONE NETWORK (PSTN) SUBCLASS
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// \brief Call Management Functional Descriptor
|
||||
/// \details This functional descriptor describes the processing of calls for the Communications Class interface.
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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 struct ATTR_PACKED
|
||||
{
|
||||
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;
|
||||
|
||||
VERIFY_STATIC(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compiler");
|
||||
|
||||
/// \brief Abstract Control Management Functional Descriptor
|
||||
/// \details This functional descriptor describes the commands supported by by the Communications Class interface with SubClass code of \ref CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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_acm_t;
|
||||
|
||||
/// \brief Direct Line Management Functional Descriptor
|
||||
/// \details This functional descriptor describes the commands supported by the Communications Class interface with SubClass code of \ref CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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;
|
||||
|
||||
/// \brief Telephone Ringer Functional Descriptor
|
||||
/// \details The Telephone Ringer functional descriptor describes the ringer capabilities supported by the Communications Class interface,
|
||||
/// with the SubClass code of \ref CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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;
|
||||
|
||||
/// \brief Telephone Operational Modes Functional Descriptor
|
||||
/// \details The Telephone Operational Modes functional descriptor describes the operational modes supported by
|
||||
/// the Communications Class interface, with the SubClass code of \ref CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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;
|
||||
|
||||
/// \brief Telephone Call and Line State Reporting Capabilities Descriptor
|
||||
/// \details The Telephone Call and Line State Reporting Capabilities functional descriptor describes the abilities of a
|
||||
/// telephone device to report optional call and line states.
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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)
|
||||
{
|
||||
return p_desc[2];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Requests
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint32_t bit_rate;
|
||||
uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
|
||||
uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
|
||||
uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16
|
||||
} cdc_line_coding_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct");
|
||||
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint16_t dte_is_present : 1; ///< Indicates to DCE if DTE is presentor not. This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR.
|
||||
uint16_t half_duplex_carrier_control : 1;
|
||||
uint16_t : 14;
|
||||
} cdc_line_control_state_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct");
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,302 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file cdc_device.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_DEVICE_SUPPORTED && CFG_TUD_CDC)
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "cdc_device.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_ATTR_USBRAM STATIC_VAR cdc_line_coding_t cdcd_line_coding[CONTROLLER_DEVICE_NUMBER];
|
||||
|
||||
typedef struct {
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_notif;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
cdc_acm_capability_t acm_cap;
|
||||
|
||||
// Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
|
||||
uint8_t line_state;
|
||||
}cdcd_interface_t;
|
||||
|
||||
// TODO multiple rhport
|
||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN uint8_t _tmp_rx_buf[64];
|
||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN uint8_t _tmp_tx_buf[64];
|
||||
|
||||
FIFO_DEF(_rx_ff, CFG_TUD_CDC_BUFSIZE, uint8_t, true);
|
||||
FIFO_DEF(_tx_ff, CFG_TUD_CDC_BUFSIZE, uint8_t, false);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
STATIC_VAR cdcd_interface_t _cdcd_itf[CONTROLLER_DEVICE_NUMBER];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_n_cdc_connected(uint8_t rhport)
|
||||
{
|
||||
// DTR (bit 0) active isconsidered as connected
|
||||
return BIT_TEST_(_cdcd_itf[rhport].line_state, 0);
|
||||
}
|
||||
|
||||
uint8_t tud_n_cdc_get_line_state (uint8_t rhport)
|
||||
{
|
||||
return _cdcd_itf[rhport].line_state;
|
||||
}
|
||||
|
||||
void tud_n_cdc_get_line_coding (uint8_t rhport, cdc_line_coding_t* coding)
|
||||
{
|
||||
(*coding) = cdcd_line_coding[rhport];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// READ API
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t tud_n_cdc_available(uint8_t rhport)
|
||||
{
|
||||
return fifo_count(&_rx_ff);
|
||||
}
|
||||
|
||||
int8_t tud_n_cdc_read_char(uint8_t rhport)
|
||||
{
|
||||
int8_t ch;
|
||||
return fifo_read(&_rx_ff, &ch) ? ch : (-1);
|
||||
}
|
||||
|
||||
uint32_t tud_n_cdc_read(uint8_t rhport, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
return fifo_read_n(&_rx_ff, buffer, bufsize);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// WRITE API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
uint32_t tud_n_cdc_write_char(uint8_t rhport, char ch)
|
||||
{
|
||||
return fifo_write(&_tx_ff, &ch) ? 1 : 0;
|
||||
}
|
||||
|
||||
uint32_t tud_n_cdc_write(uint8_t rhport, void const* buffer, uint32_t bufsize)
|
||||
{
|
||||
return fifo_write_n(&_tx_ff, buffer, bufsize);
|
||||
}
|
||||
|
||||
bool tud_n_cdc_flush (uint8_t rhport)
|
||||
{
|
||||
uint8_t edpt = _cdcd_itf[rhport].ep_in;
|
||||
VERIFY( !dcd_edpt_busy(rhport, edpt) ); // skip if previous transfer not complete
|
||||
|
||||
uint16_t count = fifo_read_n(&_tx_ff, _tmp_tx_buf, sizeof(_tmp_tx_buf));
|
||||
|
||||
VERIFY( tud_n_cdc_connected(rhport) ); // fifo is empty if not connected
|
||||
|
||||
if ( count ) TU_ASSERT( dcd_edpt_xfer(rhport, edpt, _tmp_tx_buf, count) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdcd_init(void)
|
||||
{
|
||||
memclr_(_cdcd_itf, sizeof(cdcd_interface_t)*CONTROLLER_DEVICE_NUMBER);
|
||||
|
||||
// default line coding is : stop bit = 1, parity = none, data bits = 8
|
||||
memclr_(cdcd_line_coding, sizeof(cdc_line_coding_t)*CONTROLLER_DEVICE_NUMBER);
|
||||
for(uint8_t i=0; i<CONTROLLER_DEVICE_NUMBER; i++)
|
||||
{
|
||||
cdcd_line_coding[i].bit_rate = 115200;
|
||||
cdcd_line_coding[i].stop_bits = 0;
|
||||
cdcd_line_coding[i].parity = 0;
|
||||
cdcd_line_coding[i].data_bits = 8;
|
||||
}
|
||||
}
|
||||
|
||||
tusb_error_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length)
|
||||
{
|
||||
if ( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL != p_interface_desc->bInterfaceSubClass) return TUSB_ERROR_CDC_UNSUPPORTED_SUBCLASS;
|
||||
|
||||
if ( !(is_in_range(CDC_COMM_PROTOCOL_ATCOMMAND, p_interface_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
|
||||
0xff == p_interface_desc->bInterfaceProtocol) )
|
||||
{
|
||||
return TUSB_ERROR_CDC_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
|
||||
uint8_t const * p_desc = descriptor_next ( (uint8_t const *) p_interface_desc );
|
||||
cdcd_interface_t * p_cdc = &_cdcd_itf[rhport];
|
||||
|
||||
//------------- Communication Interface -------------//
|
||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||
|
||||
// Communication Functional Descriptors
|
||||
while( TUSB_DESC_CLASS_SPECIFIC == p_desc[DESCRIPTOR_OFFSET_TYPE] )
|
||||
{
|
||||
if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) )
|
||||
{ // save ACM bmCapabilities
|
||||
p_cdc->acm_cap = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
|
||||
}
|
||||
|
||||
(*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
|
||||
p_desc = descriptor_next(p_desc);
|
||||
}
|
||||
|
||||
if ( TUSB_DESC_ENDPOINT == p_desc[DESCRIPTOR_OFFSET_TYPE])
|
||||
{ // notification endpoint if any
|
||||
TU_ASSERT( dcd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), TUSB_ERROR_DCD_OPEN_PIPE_FAILED);
|
||||
|
||||
p_cdc->ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
|
||||
|
||||
(*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
|
||||
p_desc = descriptor_next(p_desc);
|
||||
}
|
||||
|
||||
//------------- Data Interface (if any) -------------//
|
||||
if ( (TUSB_DESC_INTERFACE == p_desc[DESCRIPTOR_OFFSET_TYPE]) &&
|
||||
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
|
||||
{
|
||||
(*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
|
||||
p_desc = descriptor_next(p_desc);
|
||||
|
||||
// Open endpoint pair with usbd helper
|
||||
tusb_desc_endpoint_t const *p_desc_ep = (tusb_desc_endpoint_t const *) p_desc;
|
||||
TU_ASSERT_ERR( usbd_open_edpt_pair(rhport, p_desc_ep, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in) );
|
||||
|
||||
(*p_length) += 2*sizeof(tusb_desc_endpoint_t);
|
||||
}
|
||||
|
||||
p_cdc->itf_num = p_interface_desc->bInterfaceNumber;
|
||||
|
||||
// Prepare for incoming data
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_cdc->ep_out, _tmp_rx_buf, sizeof(_tmp_rx_buf)), TUSB_ERROR_DCD_EDPT_XFER);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
void cdcd_close(uint8_t rhport)
|
||||
{
|
||||
// no need to close opened pipe, dcd bus reset will put controller's endpoints to default state
|
||||
memclr_(&_cdcd_itf[rhport], sizeof(cdcd_interface_t));
|
||||
|
||||
fifo_clear(&_rx_ff);
|
||||
fifo_clear(&_tx_ff);
|
||||
}
|
||||
|
||||
tusb_error_t cdcd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
//------------- Class Specific Request -------------//
|
||||
if (p_request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
|
||||
|
||||
if ( (CDC_REQUEST_GET_LINE_CODING == p_request->bRequest) || (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) )
|
||||
{
|
||||
uint16_t len = min16_of(sizeof(cdc_line_coding_t), p_request->wLength);
|
||||
usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, (uint8_t*) &cdcd_line_coding[rhport], len);
|
||||
|
||||
// Invoke callback
|
||||
if (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest)
|
||||
{
|
||||
if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(rhport, &cdcd_line_coding[rhport]);
|
||||
}
|
||||
}
|
||||
else if (CDC_REQUEST_SET_CONTROL_LINE_STATE == p_request->bRequest )
|
||||
{
|
||||
// CDC PSTN v1.2 section 6.3.12
|
||||
// Bit 0: Indicates if DTE is present or not.
|
||||
// This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready)
|
||||
// Bit 1: Carrier control for half-duplex modems.
|
||||
// This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send)
|
||||
cdcd_interface_t * p_cdc = &_cdcd_itf[rhport];
|
||||
|
||||
p_cdc->line_state = (uint8_t) p_request->wValue;
|
||||
|
||||
dcd_control_status(rhport, p_request->bmRequestType_bit.direction); // ACK control request
|
||||
|
||||
// Invoke callback
|
||||
if ( tud_cdc_line_state_cb) tud_cdc_line_state_cb(rhport, BIT_TEST_(p_request->wValue, 0), BIT_TEST_(p_request->wValue, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
dcd_control_stall(rhport); // stall unsupported request
|
||||
}
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
tusb_error_t cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
cdcd_interface_t const * p_cdc = &_cdcd_itf[rhport];
|
||||
|
||||
if ( ep_addr == p_cdc->ep_out )
|
||||
{
|
||||
fifo_write_n(&_rx_ff, _tmp_rx_buf, xferred_bytes);
|
||||
|
||||
// preparing for next
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_cdc->ep_out, _tmp_rx_buf, sizeof(_tmp_rx_buf)), TUSB_ERROR_DCD_EDPT_XFER );
|
||||
|
||||
// fire callback
|
||||
if (tud_cdc_rx_cb) tud_cdc_rx_cb(rhport);
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
#if CFG_TUD_CDC_FLUSH_ON_SOF
|
||||
void cdcd_sof(uint8_t rhport)
|
||||
{
|
||||
tud_n_cdc_flush(rhport);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,120 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file cdc_device.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_CDC_DEVICE_H_
|
||||
#define _TUSB_CDC_DEVICE_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "device/usbd.h"
|
||||
#include "cdc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \addtogroup CDC_Serial Serial
|
||||
* @{
|
||||
* \defgroup CDC_Serial_Device Device
|
||||
* @{ */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API (Multiple Root Ports)
|
||||
// Should be used only with MCU that support more than 1 ports
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_n_cdc_connected (uint8_t rhport);
|
||||
uint8_t tud_n_cdc_get_line_state (uint8_t rhport);
|
||||
void tud_n_cdc_get_line_coding (uint8_t rhport, cdc_line_coding_t* coding);
|
||||
|
||||
uint32_t tud_n_cdc_available (uint8_t rhport);
|
||||
int8_t tud_n_cdc_read_char (uint8_t rhport);
|
||||
uint32_t tud_n_cdc_read (uint8_t rhport, void* buffer, uint32_t bufsize);
|
||||
|
||||
uint32_t tud_n_cdc_write_char (uint8_t rhport, char ch);
|
||||
uint32_t tud_n_cdc_write (uint8_t rhport, void const* buffer, uint32_t bufsize);
|
||||
bool tud_n_cdc_flush (uint8_t rhport);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API (Single Port)
|
||||
// Should be used with MCU supporting only 1 USB port for code simplicity
|
||||
//--------------------------------------------------------------------+
|
||||
static inline bool tud_cdc_connected (void) { return tud_n_cdc_connected(0); }
|
||||
static inline uint8_t tud_cdc_get_line_state (uint8_t rhport) { return tud_n_cdc_get_line_state(0); }
|
||||
static inline void tud_cdc_get_line_coding (uint8_t rhport, cdc_line_coding_t* coding) { return tud_cdc_get_line_coding(0, coding); }
|
||||
|
||||
static inline uint32_t tud_cdc_available (void) { return tud_n_cdc_available(0); }
|
||||
static inline int8_t tud_cdc_read_char (void) { return tud_n_cdc_read_char(0); }
|
||||
static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize) { return tud_n_cdc_read(0, buffer, bufsize); }
|
||||
|
||||
static inline uint32_t tud_cdc_write_char (char ch) { return tud_n_cdc_write_char(0, ch); }
|
||||
static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize) { return tud_n_cdc_write(0, buffer, bufsize); }
|
||||
static inline bool tud_cdc_flush (void) { return tud_n_cdc_flush(0); }
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION CALLBACK API (WEAK is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
ATTR_WEAK void tud_cdc_rx_cb(uint8_t rhport);
|
||||
ATTR_WEAK void tud_cdc_line_state_cb(uint8_t rhport, bool dtr, bool rts);
|
||||
ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t rhport, cdc_line_coding_t const* p_line_coding);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef _TINY_USB_SOURCE_FILE_
|
||||
|
||||
void cdcd_init(void);
|
||||
tusb_error_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
|
||||
tusb_error_t cdcd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
tusb_error_t cdcd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void cdcd_close(uint8_t rhport);
|
||||
|
||||
#if CFG_TUD_CDC_FLUSH_ON_SOF
|
||||
void cdcd_sof(uint8_t rhport);
|
||||
#else
|
||||
#define cdcd_sof NULL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CDC_DEVICE_H_ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
@@ -0,0 +1,243 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file cdc_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 && CFG_TUSB_HOST_CDC)
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "cdc_host.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
STATIC_VAR cdch_data_t cdch_data[CFG_TUSB_HOST_DEVICE_MAX]; // TODO to be static
|
||||
|
||||
static inline cdc_pipeid_t get_app_pipeid(pipe_handle_t pipe_hdl)
|
||||
{
|
||||
cdch_data_t const * p_cdc = &cdch_data[pipe_hdl.dev_addr-1];
|
||||
|
||||
return pipehandle_is_equal( pipe_hdl, p_cdc->pipe_notification ) ? CDC_PIPE_NOTIFICATION :
|
||||
pipehandle_is_equal( pipe_hdl, p_cdc->pipe_in ) ? CDC_PIPE_DATA_IN :
|
||||
pipehandle_is_equal( pipe_hdl, p_cdc->pipe_out ) ? CDC_PIPE_DATA_OUT : CDC_PIPE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static inline bool tusbh_cdc_is_mounted(uint8_t dev_addr)
|
||||
{
|
||||
// FIXME cannot use mounted class flag as at the point _open_sublass is called, the flag is not set yet
|
||||
#ifdef _TEST_
|
||||
return (tusbh_device_get_mounted_class_flag(dev_addr) & BIT_(TUSB_CLASS_CDC)) != 0;
|
||||
#else
|
||||
return pipehandle_is_valid(cdch_data[dev_addr-1].pipe_in) &&
|
||||
pipehandle_is_valid(cdch_data[dev_addr-1].pipe_out);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid)
|
||||
{
|
||||
if ( !tusbh_cdc_is_mounted(dev_addr) ) return false;
|
||||
|
||||
cdch_data_t const * p_cdc = &cdch_data[dev_addr-1];
|
||||
|
||||
switch (pipeid)
|
||||
{
|
||||
case CDC_PIPE_NOTIFICATION:
|
||||
return hcd_pipe_is_busy( p_cdc->pipe_notification );
|
||||
|
||||
case CDC_PIPE_DATA_IN:
|
||||
return hcd_pipe_is_busy( p_cdc->pipe_in );
|
||||
|
||||
case CDC_PIPE_DATA_OUT:
|
||||
return hcd_pipe_is_busy( p_cdc->pipe_out );
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API (parameter validation needed)
|
||||
//--------------------------------------------------------------------+
|
||||
bool tuh_cdc_serial_is_mounted(uint8_t dev_addr)
|
||||
{
|
||||
// TODO consider all AT Command as serial candidate
|
||||
return tusbh_cdc_is_mounted(dev_addr) &&
|
||||
(CDC_COMM_PROTOCOL_ATCOMMAND <= cdch_data[dev_addr-1].interface_protocol) &&
|
||||
(cdch_data[dev_addr-1].interface_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA);
|
||||
}
|
||||
|
||||
tusb_error_t tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify)
|
||||
{
|
||||
TU_ASSERT( tusbh_cdc_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED);
|
||||
TU_ASSERT( p_data != NULL && length, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
pipe_handle_t pipe_out = cdch_data[dev_addr-1].pipe_out;
|
||||
if ( hcd_pipe_is_busy(pipe_out) ) return TUSB_ERROR_INTERFACE_IS_BUSY;
|
||||
|
||||
return hcd_pipe_xfer( pipe_out, (void *) p_data, length, is_notify);
|
||||
}
|
||||
|
||||
tusb_error_t tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify)
|
||||
{
|
||||
TU_ASSERT( tusbh_cdc_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED);
|
||||
TU_ASSERT( p_buffer != NULL && length, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
pipe_handle_t pipe_in = cdch_data[dev_addr-1].pipe_in;
|
||||
if ( hcd_pipe_is_busy(pipe_in) ) return TUSB_ERROR_INTERFACE_IS_BUSY;
|
||||
|
||||
return hcd_pipe_xfer( pipe_in, p_buffer, length, is_notify);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdch_init(void)
|
||||
{
|
||||
memclr_(cdch_data, sizeof(cdch_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
}
|
||||
|
||||
tusb_error_t cdch_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length)
|
||||
{
|
||||
OSAL_SUBTASK_BEGIN
|
||||
// TODO change following assert to subtask_assert
|
||||
|
||||
if ( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL != p_interface_desc->bInterfaceSubClass) return TUSB_ERROR_CDC_UNSUPPORTED_SUBCLASS;
|
||||
|
||||
if ( !(is_in_range(CDC_COMM_PROTOCOL_ATCOMMAND, p_interface_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
|
||||
0xff == p_interface_desc->bInterfaceProtocol) )
|
||||
{
|
||||
return TUSB_ERROR_CDC_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
|
||||
uint8_t const * p_desc;
|
||||
cdch_data_t * p_cdc;
|
||||
|
||||
p_desc = descriptor_next ( (uint8_t const *) p_interface_desc );
|
||||
p_cdc = &cdch_data[dev_addr-1]; // non-static variable cannot be used after OS service call
|
||||
|
||||
p_cdc->interface_number = p_interface_desc->bInterfaceNumber;
|
||||
p_cdc->interface_protocol = p_interface_desc->bInterfaceProtocol; // TODO 0xff is consider as rndis candidate, other is virtual Com
|
||||
|
||||
//------------- Communication Interface -------------//
|
||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||
|
||||
while( TUSB_DESC_CLASS_SPECIFIC == p_desc[DESCRIPTOR_OFFSET_TYPE] )
|
||||
{ // Communication Functional Descriptors
|
||||
if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) )
|
||||
{ // save ACM bmCapabilities
|
||||
p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
|
||||
}
|
||||
|
||||
(*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
|
||||
p_desc = descriptor_next(p_desc);
|
||||
}
|
||||
|
||||
if ( TUSB_DESC_ENDPOINT == p_desc[DESCRIPTOR_OFFSET_TYPE])
|
||||
{ // notification endpoint if any
|
||||
p_cdc->pipe_notification = hcd_pipe_open(dev_addr, (tusb_desc_endpoint_t const *) p_desc, TUSB_CLASS_CDC);
|
||||
|
||||
(*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
|
||||
p_desc = descriptor_next(p_desc);
|
||||
|
||||
TU_ASSERT(pipehandle_is_valid(p_cdc->pipe_notification), TUSB_ERROR_HCD_OPEN_PIPE_FAILED);
|
||||
}
|
||||
|
||||
//------------- Data Interface (if any) -------------//
|
||||
if ( (TUSB_DESC_INTERFACE == p_desc[DESCRIPTOR_OFFSET_TYPE]) &&
|
||||
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
|
||||
{
|
||||
(*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
|
||||
p_desc = descriptor_next(p_desc);
|
||||
|
||||
// data endpoints expected to be in pairs
|
||||
for(uint32_t i=0; i<2; i++)
|
||||
{
|
||||
tusb_desc_endpoint_t const *p_endpoint = (tusb_desc_endpoint_t const *) p_desc;
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_USBH_DESCRIPTOR_CORRUPTED);
|
||||
TU_ASSERT(TUSB_XFER_BULK == p_endpoint->bmAttributes.xfer, TUSB_ERROR_USBH_DESCRIPTOR_CORRUPTED);
|
||||
|
||||
pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_IN_MASK ) ?
|
||||
&p_cdc->pipe_in : &p_cdc->pipe_out;
|
||||
|
||||
(*p_pipe_hdl) = hcd_pipe_open(dev_addr, p_endpoint, TUSB_CLASS_CDC);
|
||||
TU_ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED );
|
||||
|
||||
(*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
|
||||
p_desc = descriptor_next( p_desc );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// FIXME mounted class flag is not set yet
|
||||
tuh_cdc_mounted_cb(dev_addr);
|
||||
}
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
void cdch_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
tuh_cdc_xfer_isr( pipe_hdl.dev_addr, event, get_app_pipeid(pipe_hdl), xferred_bytes );
|
||||
}
|
||||
|
||||
void cdch_close(uint8_t dev_addr)
|
||||
{
|
||||
cdch_data_t * p_cdc = &cdch_data[dev_addr-1];
|
||||
|
||||
(void) hcd_pipe_close(p_cdc->pipe_notification);
|
||||
(void) hcd_pipe_close(p_cdc->pipe_in);
|
||||
(void) hcd_pipe_close(p_cdc->pipe_out);
|
||||
|
||||
memclr_(p_cdc, sizeof(cdch_data_t));
|
||||
|
||||
tuh_cdc_unmounted_cb(dev_addr);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,163 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file cdc_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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
#ifndef _TUSB_CDC_HOST_H_
|
||||
#define _TUSB_CDC_HOST_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "host/usbh.h"
|
||||
#include "cdc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CDC APPLICATION PUBLIC API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \ingroup ClassDriver_CDC Communication Device Class (CDC)
|
||||
* \addtogroup CDC_Serial Serial
|
||||
* @{
|
||||
* \defgroup CDC_Serial_Host Host
|
||||
* @{ */
|
||||
|
||||
/** \brief Check if device support CDC Serial interface or not
|
||||
* \param[in] dev_addr device address
|
||||
* \retval true if device supports
|
||||
* \retval false if device does not support or is not mounted
|
||||
*/
|
||||
bool tuh_cdc_serial_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
|
||||
* \param[in] pipeid value from \ref cdc_pipeid_t to indicate target pipe.
|
||||
* \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 used to check if previous transfer is complete (success or error), so that the next transfer
|
||||
* can be scheduled. User needs to make sure the corresponding interface is mounted
|
||||
* (by \ref tuh_cdc_serial_is_mounted) before calling this function.
|
||||
*/
|
||||
bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) ATTR_PURE ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/** \brief Perform USB OUT transfer to device
|
||||
* \param[in] dev_addr device address
|
||||
* \param[in] p_data Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_ATTR_USBRAM)
|
||||
* \param[in] length Number of bytes to be transferred via USB bus
|
||||
* \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 input parameters 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. \a p_data must be declared with \ref CFG_TUSB_ATTR_USBRAM.
|
||||
*/
|
||||
tusb_error_t tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify);
|
||||
|
||||
/** \brief Perform USB IN transfer to get data from device
|
||||
* \param[in] dev_addr device address
|
||||
* \param[in] p_buffer Buffer containing received data. Must be accessible by USB controller (see \ref CFG_TUSB_ATTR_USBRAM)
|
||||
* \param[in] length Number of bytes to be transferred via USB bus
|
||||
* \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 input parameters 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. \a p_data must be declared with \ref CFG_TUSB_ATTR_USBRAM.
|
||||
*/
|
||||
tusb_error_t tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CDC APPLICATION CALLBACKS
|
||||
//--------------------------------------------------------------------+
|
||||
/** \brief Callback function that will be invoked when a device with CDC Abstract Control Model 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 tuh_cdc_mounted_cb(uint8_t dev_addr);
|
||||
|
||||
/** \brief Callback function that will be invoked when a device with CDC Abstract Control Model 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 tuh_cdc_unmounted_cb(uint8_t dev_addr);
|
||||
|
||||
/** \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
|
||||
* \param[in] pipe_id value from \ref cdc_pipeid_t indicate the pipe
|
||||
* \param[in] xferred_bytes Number of bytes transferred via USB bus
|
||||
* \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
|
||||
*/
|
||||
void tuh_cdc_xfer_isr(uint8_t dev_addr, tusb_event_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes);
|
||||
|
||||
/// @} // group CDC_Serial_Host
|
||||
/// @}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-CLASS API
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef _TINY_USB_SOURCE_FILE_
|
||||
|
||||
typedef struct {
|
||||
uint8_t interface_number;
|
||||
uint8_t interface_protocol;
|
||||
|
||||
cdc_acm_capability_t acm_capability;
|
||||
|
||||
pipe_handle_t pipe_notification, pipe_out, pipe_in;
|
||||
|
||||
} cdch_data_t;
|
||||
|
||||
extern cdch_data_t cdch_data[CFG_TUSB_HOST_DEVICE_MAX]; // TODO consider to move to cdch internal header file
|
||||
|
||||
void cdch_init(void);
|
||||
tusb_error_t cdch_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) ATTR_WARN_UNUSED_RESULT;
|
||||
void cdch_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void cdch_close(uint8_t dev_addr);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CDC_HOST_H_ */
|
||||
@@ -0,0 +1,313 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file cdc_rndis.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 ClassDriver_CDC Communication Device Class (CDC)
|
||||
* \defgroup CDC_RNDIS Remote Network Driver Interface Specification (RNDIS)
|
||||
* @{
|
||||
* \defgroup CDC_RNDIS_Common Common Definitions
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_CDC_RNDIS_H_
|
||||
#define _TUSB_CDC_RNDIS_H_
|
||||
|
||||
#include "cdc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __CC_ARM
|
||||
#pragma diag_suppress 66 // Suppress Keil warnings #66-D: enumeration value is out of "int" range
|
||||
#endif
|
||||
|
||||
/// RNDIS Message Types
|
||||
typedef enum
|
||||
{
|
||||
RNDIS_MSG_PACKET = 0x00000001UL, ///< The host and device use this to send network data to one another.
|
||||
|
||||
RNDIS_MSG_INITIALIZE = 0x00000002UL, ///< Sent by the host to initialize the device.
|
||||
RNDIS_MSG_INITIALIZE_CMPLT = 0x80000002UL, ///< Device response to an initialize message.
|
||||
|
||||
RNDIS_MSG_HALT = 0x00000003UL, ///< Sent by the host to halt the device. This does not have a response. It is optional for the device to send this message to the host.
|
||||
|
||||
RNDIS_MSG_QUERY = 0x00000004UL, ///< Sent by the host to send a query OID.
|
||||
RNDIS_MSG_QUERY_CMPLT = 0x80000004UL, ///< Device response to a query OID.
|
||||
|
||||
RNDIS_MSG_SET = 0x00000005UL, ///< Sent by the host to send a set OID.
|
||||
RNDIS_MSG_SET_CMPLT = 0x80000005UL, ///< Device response to a set OID.
|
||||
|
||||
RNDIS_MSG_RESET = 0x00000006UL, ///< Sent by the host to perform a soft reset on the device.
|
||||
RNDIS_MSG_RESET_CMPLT = 0x80000006UL, ///< Device response to reset message.
|
||||
|
||||
RNDIS_MSG_INDICATE_STATUS = 0x00000007UL, ///< Sent by the device to indicate its status or an error when an unrecognized message is received.
|
||||
|
||||
RNDIS_MSG_KEEP_ALIVE = 0x00000008UL, ///< During idle periods, sent every few seconds by the host to check that the device is still responsive. It is optional for the device to send this message to check if the host is active.
|
||||
RNDIS_MSG_KEEP_ALIVE_CMPLT = 0x80000008UL ///< The device response to a keepalivemessage. The host can respond with this message to a keepalive message from the device when the device implements the optional KeepAliveTimer.
|
||||
}rndis_msg_type_t;
|
||||
|
||||
/// RNDIS Message Status Values
|
||||
typedef enum
|
||||
{
|
||||
RNDIS_STATUS_SUCCESS = 0x00000000UL, ///< Success
|
||||
RNDIS_STATUS_FAILURE = 0xC0000001UL, ///< Unspecified error
|
||||
RNDIS_STATUS_INVALID_DATA = 0xC0010015UL, ///< Invalid data error
|
||||
RNDIS_STATUS_NOT_SUPPORTED = 0xC00000BBUL, ///< Unsupported request error
|
||||
RNDIS_STATUS_MEDIA_CONNECT = 0x4001000BUL, ///< Device is connected to a network medium.
|
||||
RNDIS_STATUS_MEDIA_DISCONNECT = 0x4001000CUL ///< Device is disconnected from the medium.
|
||||
}rndis_msg_status_t;
|
||||
|
||||
#ifdef __CC_ARM
|
||||
#pragma diag_default 66 // return Keil 66 to normal severity
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MESSAGE STRUCTURE
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//------------- Initialize -------------//
|
||||
/// \brief Initialize Message
|
||||
/// \details This message MUST be sent by the host to initialize the device.
|
||||
typedef struct {
|
||||
uint32_t type ; ///< Message type, must be \ref RNDIS_MSG_INITIALIZE
|
||||
uint32_t length ; ///< Message length in bytes, must be 0x18
|
||||
uint32_t request_id ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device.
|
||||
uint32_t major_version ; ///< The major version of the RNDIS Protocol implemented by the host.
|
||||
uint32_t minor_version ; ///< The minor version of the RNDIS Protocol implemented by the host
|
||||
uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the host expects to receive from the device.
|
||||
}rndis_msg_initialize_t;
|
||||
|
||||
/// \brief Initialize Complete Message
|
||||
/// \details This message MUST be sent by the device in response to an initialize message.
|
||||
typedef struct {
|
||||
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_INITIALIZE_CMPLT
|
||||
uint32_t length ; ///< Message length in bytes, must be 0x30
|
||||
uint32_t request_id ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_initialize_t to which this message is a response.
|
||||
uint32_t status ; ///< The initialization status of the device, has value from \ref rndis_msg_status_t
|
||||
uint32_t major_version ; ///< the highest-numbered RNDIS Protocol version supported by the device.
|
||||
uint32_t minor_version ; ///< the highest-numbered RNDIS Protocol version supported by the device.
|
||||
uint32_t device_flags ; ///< MUST be set to 0x000000010. Other values are reserved for future use.
|
||||
uint32_t medium ; ///< is 0x00 for RNDIS_MEDIUM_802_3
|
||||
uint32_t max_packet_per_xfer ; ///< The maximum number of concatenated \ref RNDIS_MSG_PACKET messages that the device can handle in a single bus transfer to it. This value MUST be at least 1.
|
||||
uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the device expects to receive from the host.
|
||||
uint32_t packet_alignment_factor ; ///< The byte alignment the device expects for each RNDIS message that is part of a multimessage transfer to it. The value is specified as an exponent of 2; for example, the host uses 2<SUP>{PacketAlignmentFactor}</SUP> as the alignment value.
|
||||
uint32_t reserved[2] ;
|
||||
} rndis_msg_initialize_cmplt_t;
|
||||
|
||||
//------------- Query -------------//
|
||||
/// \brief Query Message
|
||||
/// \details This message MUST be sent by the host to query an OID.
|
||||
typedef struct {
|
||||
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_QUERY
|
||||
uint32_t length ; ///< Message length in bytes, including the header and the \a oid_buffer
|
||||
uint32_t request_id ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device.
|
||||
uint32_t oid ; ///< The integer value of the host operating system-defined identifier, for the parameter of the device being queried for.
|
||||
uint32_t buffer_length ; ///< The length, in bytes, of the input data required for the OID query. This MUST be set to 0 when there is no input data associated with the OID.
|
||||
uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the input data for the query is located in the message. This value MUST be set to 0 when there is no input data associated with the OID.
|
||||
uint32_t reserved ;
|
||||
uint8_t oid_buffer[] ; ///< Flexible array contains the input data supplied by the host, required for the OID query request processing by the device, as per the host NDIS specification.
|
||||
} rndis_msg_query_t, rndis_msg_set_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(rndis_msg_query_t) == 28, "Make sure flexible array member does not affect layout");
|
||||
|
||||
/// \brief Query Complete Message
|
||||
/// \details This message MUST be sent by the device in response to a query OID message.
|
||||
typedef struct {
|
||||
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_QUERY_CMPLT
|
||||
uint32_t length ; ///< Message length in bytes, including the header and the \a oid_buffer
|
||||
uint32_t request_id ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_query_t to which this message is a response.
|
||||
uint32_t status ; ///< The status of processing for the query request, has value from \ref rndis_msg_status_t.
|
||||
uint32_t buffer_length ; ///< The length, in bytes, of the data in the response to the query. This MUST be set to 0 when there is no OIDInputBuffer.
|
||||
uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the response data for the query is located in the message. This MUST be set to 0 when there is no \ref oid_buffer.
|
||||
uint8_t oid_buffer[] ; ///< Flexible array member contains the response data to the OID query request as specified by the host.
|
||||
} rndis_msg_query_cmplt_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(rndis_msg_query_cmplt_t) == 24, "Make sure flexible array member does not affect layout");
|
||||
|
||||
//------------- Reset -------------//
|
||||
/// \brief Reset Message
|
||||
/// \details This message MUST be sent by the host to perform a soft reset on the device.
|
||||
typedef struct {
|
||||
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_RESET
|
||||
uint32_t length ; ///< Message length in bytes, MUST be 0x06
|
||||
uint32_t reserved ;
|
||||
} rndis_msg_reset_t;
|
||||
|
||||
/// \brief Reset Complete Message
|
||||
/// \details This message MUST be sent by the device in response to a reset message.
|
||||
typedef struct {
|
||||
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_RESET_CMPLT
|
||||
uint32_t length ; ///< Message length in bytes, MUST be 0x10
|
||||
uint32_t status ; ///< The status of processing for the \ref rndis_msg_reset_t, has value from \ref rndis_msg_status_t.
|
||||
uint32_t addressing_reset ; ///< This field indicates whether the addressing information, which is the multicast address list or packet filter, has been lost during the reset operation. This MUST be set to 0x00000001 if the device requires that the host to resend addressing information or MUST be set to zero otherwise.
|
||||
} rndis_msg_reset_cmplt_t;
|
||||
|
||||
//typedef struct {
|
||||
// uint32_t type;
|
||||
// uint32_t length;
|
||||
// uint32_t status;
|
||||
// uint32_t buffer_length;
|
||||
// uint32_t buffer_offset;
|
||||
// uint32_t diagnostic_status; // optional
|
||||
// uint32_t diagnostic_error_offset; // optional
|
||||
// uint32_t status_buffer[0]; // optional
|
||||
//} rndis_msg_indicate_status_t;
|
||||
|
||||
/// \brief Keep Alive Message
|
||||
/// \details This message MUST be sent by the host to check that device is still responsive. It is optional for the device to send this message to check if the host is active
|
||||
typedef struct {
|
||||
uint32_t type ; ///< Message Type
|
||||
uint32_t length ; ///< Message length in bytes, MUST be 0x10
|
||||
uint32_t request_id ;
|
||||
} rndis_msg_keep_alive_t, rndis_msg_halt_t;
|
||||
|
||||
/// \brief Set Complete Message
|
||||
/// \brief This message MUST be sent in response to a the request message
|
||||
typedef struct {
|
||||
uint32_t type ; ///< Message Type
|
||||
uint32_t length ; ///< Message length in bytes, MUST be 0x10
|
||||
uint32_t request_id ; ///< must be the same as requesting message
|
||||
uint32_t status ; ///< The status of processing for the request message request by the device to which this message is the response.
|
||||
} rndis_msg_set_cmplt_t, rndis_msg_keep_alive_cmplt_t;
|
||||
|
||||
/// \brief Packet Data Message
|
||||
/// \brief This message MUST be used by the host and the device to send network data to one another.
|
||||
typedef struct {
|
||||
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_PACKET
|
||||
uint32_t length ; ///< Message length in bytes, The total length of this RNDIS message including the header, payload, and padding.
|
||||
uint32_t data_offset ; ///< Specifies the offset, in bytes, from the start of this \a data_offset field of this message to the start of the data. This MUST be an integer multiple of 4.
|
||||
uint32_t data_length ; ///< Specifies the number of bytes in the payload of this message.
|
||||
uint32_t out_of_band_data_offet ; ///< Specifies the offset, in bytes, of the first out-of-band data record from the start of the DataOffset field in this message. MUST be an integer multiple of 4 when out-of-band data is present or set to 0 otherwise. When there are multiple out-ofband data records, each subsequent record MUST immediately follow the previous out-of-band data record.
|
||||
uint32_t out_of_band_data_length ; ///< Specifies, in bytes, the total length of the out-of-band data.
|
||||
uint32_t num_out_of_band_data_elements ; ///< Specifies the number of out-of-band records in this message.
|
||||
uint32_t per_packet_info_offset ; ///< Specifies the offset, in bytes, of the start of per-packet-info data record from the start of the \a data_offset field in this message. MUST be an integer multiple of 4 when per-packet-info data record is present or MUST be set to 0 otherwise. When there are multiple per-packet-info data records, each subsequent record MUST immediately follow the previous record.
|
||||
uint32_t per_packet_info_length ; ///< Specifies, in bytes, the total length of per-packetinformation contained in this message.
|
||||
uint32_t reserved[2] ;
|
||||
uint32_t payload[0] ; ///< Network data contained in this message.
|
||||
|
||||
// uint8_t padding[0]
|
||||
// Additional bytes of zeros added at the end of the message to comply with
|
||||
// the internal and external padding requirements. Internal padding SHOULD be as per the
|
||||
// specification of the out-of-band data record and per-packet-info data record. The external
|
||||
//padding size SHOULD be determined based on the PacketAlignmentFactor field specification
|
||||
//in REMOTE_NDIS_INITIALIZE_CMPLT message by the device, when multiple
|
||||
//REMOTE_NDIS_PACKET_MSG messages are bundled together in a single bus-native message.
|
||||
//In this case, all but the very last REMOTE_NDIS_PACKET_MSG MUST respect the
|
||||
//PacketAlignmentFactor field.
|
||||
|
||||
// rndis_msg_packet_t [0] : (optional) more packet if multiple packet per bus transaction is supported
|
||||
} rndis_msg_packet_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t size ; ///< Length, in bytes, of this header and appended data and padding. This value MUST be an integer multiple of 4.
|
||||
uint32_t type ; ///< MUST be as per host operating system specification.
|
||||
uint32_t offset ; ///< The byte offset from the beginning of this record to the beginning of data.
|
||||
uint32_t data[0] ; ///< Flexible array contains data
|
||||
} rndis_msg_out_of_band_data_t, rndis_msg_per_packet_info_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// NDIS Object ID
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// NDIS Object ID
|
||||
typedef enum
|
||||
{
|
||||
//------------- General Required OIDs -------------//
|
||||
RNDIS_OID_GEN_SUPPORTED_LIST = 0x00010101, ///< List of supported OIDs
|
||||
RNDIS_OID_GEN_HARDWARE_STATUS = 0x00010102, ///< Hardware status
|
||||
RNDIS_OID_GEN_MEDIA_SUPPORTED = 0x00010103, ///< Media types supported (encoded)
|
||||
RNDIS_OID_GEN_MEDIA_IN_USE = 0x00010104, ///< Media types in use (encoded)
|
||||
RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105, ///<
|
||||
RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106, ///< Maximum frame size in bytes
|
||||
RNDIS_OID_GEN_LINK_SPEED = 0x00010107, ///< Link speed in units of 100 bps
|
||||
RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108, ///< Transmit buffer space
|
||||
RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109, ///< Receive buffer space
|
||||
RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010A, ///< Minimum amount of storage, in bytes, that a single packet occupies in the transmit buffer space of the NIC
|
||||
RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010B, ///< Amount of storage, in bytes, that a single packet occupies in the receive buffer space of the NIC
|
||||
RNDIS_OID_GEN_VENDOR_ID = 0x0001010C, ///< Vendor NIC code
|
||||
RNDIS_OID_GEN_VENDOR_DESCRIPTION = 0x0001010D, ///< Vendor network card description
|
||||
RNDIS_OID_GEN_CURRENT_PACKET_FILTER = 0x0001010E, ///< Current packet filter (encoded)
|
||||
RNDIS_OID_GEN_CURRENT_LOOKAHEAD = 0x0001010F, ///< Current lookahead size in bytes
|
||||
RNDIS_OID_GEN_DRIVER_VERSION = 0x00010110, ///< NDIS version number used by the driver
|
||||
RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111, ///< Maximum total packet length in bytes
|
||||
RNDIS_OID_GEN_PROTOCOL_OPTIONS = 0x00010112, ///< Optional protocol flags (encoded)
|
||||
RNDIS_OID_GEN_MAC_OPTIONS = 0x00010113, ///< Optional NIC flags (encoded)
|
||||
RNDIS_OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114, ///< Whether the NIC is connected to the network
|
||||
RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115, ///< The maximum number of send packets the driver can accept per call to its MiniportSendPacketsfunction
|
||||
|
||||
//------------- General Optional OIDs -------------//
|
||||
RNDIS_OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116, ///< Vendor-assigned version number of the driver
|
||||
RNDIS_OID_GEN_SUPPORTED_GUIDS = 0x00010117, ///< The custom GUIDs (Globally Unique Identifier) supported by the miniport driver
|
||||
RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118, ///< List of network-layer addresses associated with the binding between a transport and the driver
|
||||
RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119, ///< Size of packets' additional headers
|
||||
RNDIS_OID_GEN_MEDIA_CAPABILITIES = 0x00010201, ///<
|
||||
RNDIS_OID_GEN_PHYSICAL_MEDIUM = 0x00010202, ///< Physical media supported by the miniport driver (encoded)
|
||||
|
||||
//------------- 802.3 Objects (Ethernet) -------------//
|
||||
RNDIS_OID_802_3_PERMANENT_ADDRESS = 0x01010101, ///< Permanent station address
|
||||
RNDIS_OID_802_3_CURRENT_ADDRESS = 0x01010102, ///< Current station address
|
||||
RNDIS_OID_802_3_MULTICAST_LIST = 0x01010103, ///< Current multicast address list
|
||||
RNDIS_OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104, ///< Maximum size of multicast address list
|
||||
} rndis_oid_type_t;
|
||||
|
||||
/// RNDIS Packet Filter Bits \ref RNDIS_OID_GEN_CURRENT_PACKET_FILTER.
|
||||
typedef enum
|
||||
{
|
||||
RNDIS_PACKET_TYPE_DIRECTED = 0x00000001, ///< Directed packets. Directed packets contain a destination address equal to the station address of the NIC.
|
||||
RNDIS_PACKET_TYPE_MULTICAST = 0x00000002, ///< Multicast address packets sent to addresses in the multicast address list.
|
||||
RNDIS_PACKET_TYPE_ALL_MULTICAST = 0x00000004, ///< All multicast address packets, not just the ones enumerated in the multicast address list.
|
||||
RNDIS_PACKET_TYPE_BROADCAST = 0x00000008, ///< Broadcast packets.
|
||||
RNDIS_PACKET_TYPE_SOURCE_ROUTING = 0x00000010, ///< All source routing packets. If the protocol driver sets this bit, the NDIS library attempts to act as a source routing bridge.
|
||||
RNDIS_PACKET_TYPE_PROMISCUOUS = 0x00000020, ///< Specifies all packets regardless of whether VLAN filtering is enabled or not and whether the VLAN identifier matches or not.
|
||||
RNDIS_PACKET_TYPE_SMT = 0x00000040, ///< SMT packets that an FDDI NIC receives.
|
||||
RNDIS_PACKET_TYPE_ALL_LOCAL = 0x00000080, ///< All packets sent by installed protocols and all packets indicated by the NIC that is identified by a given NdisBindingHandle.
|
||||
RNDIS_PACKET_TYPE_GROUP = 0x00001000, ///< Packets sent to the current group address.
|
||||
RNDIS_PACKET_TYPE_ALL_FUNCTIONAL = 0x00002000, ///< All functional address packets, not just the ones in the current functional address.
|
||||
RNDIS_PACKET_TYPE_FUNCTIONAL = 0x00004000, ///< Functional address packets sent to addresses included in the current functional address.
|
||||
RNDIS_PACKET_TYPE_MAC_FRAME = 0x00008000, ///< NIC driver frames that a Token Ring NIC receives.
|
||||
RNDIS_PACKET_TYPE_NO_LOCAL = 0x00010000,
|
||||
} rndis_packet_filter_type_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CDC_RNDIS_H_ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
@@ -0,0 +1,293 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file cdc_rndis_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 && CFG_TUSB_HOST_CDC && CFG_TUSB_HOST_CDC_RNDIS)
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "cdc_host.h"
|
||||
#include "cdc_rndis_host.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
#define RNDIS_MSG_PAYLOAD_MAX (1024*4)
|
||||
|
||||
CFG_TUSB_ATTR_USBRAM static uint8_t msg_notification[CFG_TUSB_HOST_DEVICE_MAX][8];
|
||||
CFG_TUSB_ATTR_USBRAM ATTR_ALIGNED(4) static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX];
|
||||
|
||||
STATIC_VAR rndish_data_t rndish_data[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
|
||||
// TODO Microsoft requires message length for any get command must be at least 4096 bytes
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
static tusb_error_t rndis_body_subtask(void);
|
||||
static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc,
|
||||
uint8_t * p_mess, uint32_t mess_length,
|
||||
uint8_t *p_response );
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_error_t tusbh_cdc_rndis_get_mac_addr(uint8_t dev_addr, uint8_t mac_address[6])
|
||||
{
|
||||
TU_ASSERT( tusbh_cdc_rndis_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED);
|
||||
VERIFY( mac_address, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
memcpy(mac_address, rndish_data[dev_addr-1].mac_address, 6);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// IMPLEMENTATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper
|
||||
// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with
|
||||
// forever loop cannot have any return at all.
|
||||
OSAL_TASK_FUNCTION(cdch_rndis_task) (void* param;)
|
||||
{
|
||||
OSAL_TASK_BEGIN
|
||||
rndis_body_subtask();
|
||||
OSAL_TASK_END
|
||||
}
|
||||
|
||||
static tusb_error_t rndis_body_subtask(void)
|
||||
{
|
||||
static uint8_t relative_addr;
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
for (relative_addr = 0; relative_addr < CFG_TUSB_HOST_DEVICE_MAX; relative_addr++)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
osal_task_delay(100);
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// RNDIS-CDC Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void rndish_init(void)
|
||||
{
|
||||
memclr_(rndish_data, sizeof(rndish_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
|
||||
//------------- Task creation -------------//
|
||||
|
||||
//------------- semaphore creation for notificaiton pipe -------------//
|
||||
for(uint8_t i=0; i<CFG_TUSB_HOST_DEVICE_MAX; i++)
|
||||
{
|
||||
rndish_data[i].sem_notification_hdl = osal_semaphore_create( OSAL_SEM_REF(rndish_data[i].semaphore_notification) );
|
||||
}
|
||||
}
|
||||
|
||||
void rndish_close(uint8_t dev_addr)
|
||||
{
|
||||
osal_semaphore_reset( rndish_data[dev_addr-1].sem_notification_hdl );
|
||||
// memclr_(&rndish_data[dev_addr-1], sizeof(rndish_data_t)); TODO need to move semaphore & its handle out before memclr
|
||||
}
|
||||
|
||||
|
||||
static rndis_msg_initialize_t const msg_init =
|
||||
{
|
||||
.type = RNDIS_MSG_INITIALIZE,
|
||||
.length = sizeof(rndis_msg_initialize_t),
|
||||
.request_id = 1, // TODO should use some magic number
|
||||
.major_version = 1,
|
||||
.minor_version = 0,
|
||||
.max_xfer_size = 0x4000 // TODO mimic windows
|
||||
};
|
||||
|
||||
static rndis_msg_query_t const msg_query_permanent_addr =
|
||||
{
|
||||
.type = RNDIS_MSG_QUERY,
|
||||
.length = sizeof(rndis_msg_query_t)+6,
|
||||
.request_id = 1,
|
||||
.oid = RNDIS_OID_802_3_PERMANENT_ADDRESS,
|
||||
.buffer_length = 6,
|
||||
.buffer_offset = 20,
|
||||
};
|
||||
|
||||
static rndis_msg_set_t const msg_set_packet_filter =
|
||||
{
|
||||
.type = RNDIS_MSG_SET,
|
||||
.length = sizeof(rndis_msg_set_t)+4,
|
||||
.request_id = 1,
|
||||
.oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
|
||||
.buffer_length = 4,
|
||||
.buffer_offset = 20,
|
||||
};
|
||||
|
||||
tusb_error_t rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc)
|
||||
{
|
||||
tusb_error_t error;
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
//------------- Message Initialize -------------//
|
||||
memcpy(msg_payload, &msg_init, sizeof(rndis_msg_initialize_t));
|
||||
STASK_INVOKE(
|
||||
send_message_get_response_subtask( dev_addr, p_cdc,
|
||||
msg_payload, sizeof(rndis_msg_initialize_t),
|
||||
msg_payload),
|
||||
error
|
||||
);
|
||||
if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
|
||||
|
||||
// TODO currently not support multiple data packets per xfer
|
||||
rndis_msg_initialize_cmplt_t * const p_init_cmpt = (rndis_msg_initialize_cmplt_t *) msg_payload;
|
||||
STASK_ASSERT(p_init_cmpt->type == RNDIS_MSG_INITIALIZE_CMPLT && p_init_cmpt->status == RNDIS_STATUS_SUCCESS &&
|
||||
p_init_cmpt->max_packet_per_xfer == 1 && p_init_cmpt->max_xfer_size <= RNDIS_MSG_PAYLOAD_MAX);
|
||||
rndish_data[dev_addr-1].max_xfer_size = p_init_cmpt->max_xfer_size;
|
||||
|
||||
//------------- Message Query 802.3 Permanent Address -------------//
|
||||
memcpy(msg_payload, &msg_query_permanent_addr, sizeof(rndis_msg_query_t));
|
||||
memclr_(msg_payload + sizeof(rndis_msg_query_t), 6); // 6 bytes for MAC address
|
||||
|
||||
STASK_INVOKE(
|
||||
send_message_get_response_subtask( dev_addr, p_cdc,
|
||||
msg_payload, sizeof(rndis_msg_query_t) + 6,
|
||||
msg_payload),
|
||||
error
|
||||
);
|
||||
if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
|
||||
|
||||
rndis_msg_query_cmplt_t * const p_query_cmpt = (rndis_msg_query_cmplt_t *) msg_payload;
|
||||
STASK_ASSERT(p_query_cmpt->type == RNDIS_MSG_QUERY_CMPLT && p_query_cmpt->status == RNDIS_STATUS_SUCCESS);
|
||||
memcpy(rndish_data[dev_addr-1].mac_address, msg_payload + 8 + p_query_cmpt->buffer_offset, 6);
|
||||
|
||||
//------------- Set OID_GEN_CURRENT_PACKET_FILTER to (DIRECTED | MULTICAST | BROADCAST) -------------//
|
||||
memcpy(msg_payload, &msg_set_packet_filter, sizeof(rndis_msg_set_t));
|
||||
memclr_(msg_payload + sizeof(rndis_msg_set_t), 4); // 4 bytes for filter flags
|
||||
((rndis_msg_set_t*) msg_payload)->oid_buffer[0] = (RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_MULTICAST | RNDIS_PACKET_TYPE_BROADCAST);
|
||||
|
||||
STASK_INVOKE(
|
||||
send_message_get_response_subtask( dev_addr, p_cdc,
|
||||
msg_payload, sizeof(rndis_msg_set_t) + 4,
|
||||
msg_payload),
|
||||
error
|
||||
);
|
||||
if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
|
||||
|
||||
rndis_msg_set_cmplt_t * const p_set_cmpt = (rndis_msg_set_cmplt_t *) msg_payload;
|
||||
STASK_ASSERT(p_set_cmpt->type == RNDIS_MSG_SET_CMPLT && p_set_cmpt->status == RNDIS_STATUS_SUCCESS);
|
||||
|
||||
tusbh_cdc_rndis_mounted_cb(dev_addr);
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
if ( pipehandle_is_equal(pipe_hdl, p_cdc->pipe_notification) )
|
||||
{
|
||||
osal_semaphore_post( rndish_data[pipe_hdl.dev_addr-1].sem_notification_hdl );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL & HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc,
|
||||
uint8_t * p_mess, uint32_t mess_length,
|
||||
uint8_t *p_response)
|
||||
{
|
||||
tusb_error_t error;
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
//------------- Send RNDIS Control Message -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE),
|
||||
CDC_REQUEST_SEND_ENCAPSULATED_COMMAND, 0, p_cdc->interface_number,
|
||||
mess_length, p_mess),
|
||||
error
|
||||
);
|
||||
if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
|
||||
|
||||
//------------- waiting for Response Available notification -------------//
|
||||
(void) hcd_pipe_xfer(p_cdc->pipe_notification, msg_notification[dev_addr-1], 8, true);
|
||||
osal_semaphore_wait(rndish_data[dev_addr-1].sem_notification_hdl, OSAL_TIMEOUT_NORMAL, &error);
|
||||
if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
|
||||
STASK_ASSERT(msg_notification[dev_addr-1][0] == 1);
|
||||
|
||||
//------------- Get RNDIS Message Initialize Complete -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE),
|
||||
CDC_REQUEST_GET_ENCAPSULATED_RESPONSE, 0, p_cdc->interface_number,
|
||||
RNDIS_MSG_PAYLOAD_MAX, p_response),
|
||||
error
|
||||
);
|
||||
if ( TUSB_ERROR_NONE != error ) STASK_RETURN(error);
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
//static tusb_error_t send_process_msg_initialize_subtask(uint8_t dev_addr, cdch_data_t *p_cdc)
|
||||
//{
|
||||
// tusb_error_t error;
|
||||
//
|
||||
// OSAL_SUBTASK_BEGIN
|
||||
//
|
||||
// *((rndis_msg_initialize_t*) msg_payload) = (rndis_msg_initialize_t)
|
||||
// {
|
||||
// .type = RNDIS_MSG_INITIALIZE,
|
||||
// .length = sizeof(rndis_msg_initialize_t),
|
||||
// .request_id = 1, // TODO should use some magic number
|
||||
// .major_version = 1,
|
||||
// .minor_version = 0,
|
||||
// .max_xfer_size = 0x4000 // TODO mimic windows
|
||||
// };
|
||||
//
|
||||
//
|
||||
//
|
||||
// OSAL_SUBTASK_END
|
||||
//}
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file cdc_rndis_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 CDC_RNDIS
|
||||
* \defgroup CDC_RNSID_Host Host
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_CDC_RNDIS_HOST_H_
|
||||
#define _TUSB_CDC_RNDIS_HOST_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "host/usbh.h"
|
||||
#include "cdc_rndis.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// RNDIS-CDC Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef _TINY_USB_SOURCE_FILE_
|
||||
|
||||
typedef struct {
|
||||
OSAL_SEM_DEF(semaphore_notification);
|
||||
osal_semaphore_handle_t sem_notification_hdl; // used to wait on notification pipe
|
||||
uint32_t max_xfer_size; // got from device's msg initialize complete
|
||||
uint8_t mac_address[6];
|
||||
}rndish_data_t;
|
||||
|
||||
void rndish_init(void);
|
||||
tusb_error_t rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc) ATTR_WARN_UNUSED_RESULT;
|
||||
void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void rndish_close(uint8_t dev_addr);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CDC_RNDIS_HOST_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,105 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file custom_device.c
|
||||
@author hathach (tinyusb.org)
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||
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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (MODE_DEVICE_SUPPORTED && CFG_TUD_CUSTOM_CLASS)
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "custom_device.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* MACRO TYPEDEF CONSTANT ENUM
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* VARIABLE DECLARATION
|
||||
*------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
uint8_t itf_num;
|
||||
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
} cusd_interface_t;
|
||||
|
||||
static cusd_interface_t _cusd_itf;
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* FUNCTION DECLARATION
|
||||
*------------------------------------------------------------------*/
|
||||
void cusd_init(void)
|
||||
{
|
||||
varclr_(&_cusd_itf);
|
||||
}
|
||||
|
||||
tusb_error_t cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf, uint16_t *p_len)
|
||||
{
|
||||
cusd_interface_t* p_itf = &_cusd_itf;
|
||||
|
||||
// Open endpoint pair with usbd helper
|
||||
tusb_desc_endpoint_t const *p_desc_ep = (tusb_desc_endpoint_t const *) descriptor_next( (uint8_t const*) p_desc_itf );
|
||||
TU_ASSERT_ERR( usbd_open_edpt_pair(rhport, p_desc_ep, TUSB_XFER_BULK, &p_itf->ep_out, &p_itf->ep_in) );
|
||||
|
||||
p_itf->itf_num = p_desc_itf->bInterfaceNumber;
|
||||
|
||||
(*p_len) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
// TODO Prepare for incoming data
|
||||
// TU_ASSERT( dcd_edpt_xfer(rhport, p_itf->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)), TUSB_ERROR_DCD_EDPT_XFER );
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
|
||||
}
|
||||
|
||||
tusb_error_t cusd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
void cusd_close(uint8_t rhport)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file custom_device.h
|
||||
@author hathach (tinyusb.org)
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||
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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef _TUSB_CUSTOM_DEVICE_H_
|
||||
#define _TUSB_CUSTOM_DEVICE_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "device/usbd.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API (Multiple Root Ports)
|
||||
// Should be used only with MCU that support more than 1 ports
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API (Single Port)
|
||||
// Should be used with MCU supporting only 1 USB port for code simplicity
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION CALLBACK API (WEAK is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef _TINY_USB_SOURCE_FILE_
|
||||
|
||||
void cusd_init(void);
|
||||
tusb_error_t cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
|
||||
tusb_error_t cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
tusb_error_t cusd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void cusd_close(uint8_t rhport);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _TUSB_CUSTOM_DEVICE_H_ */
|
||||
@@ -0,0 +1,160 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file custom_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 && CFG_TUSB_HOST_CUSTOM_CLASS)
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "custom_host.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
custom_interface_info_t custom_interface[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
|
||||
static tusb_error_t cush_validate_paras(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length)
|
||||
{
|
||||
if ( !tusbh_custom_is_mounted(dev_addr, vendor_id, product_id) )
|
||||
{
|
||||
return TUSB_ERROR_DEVICE_NOT_READY;
|
||||
}
|
||||
|
||||
TU_ASSERT( p_buffer != NULL && length != 0, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API (need to check parameters)
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length)
|
||||
{
|
||||
TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_buffer, length) );
|
||||
|
||||
if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_in) )
|
||||
{
|
||||
return TUSB_ERROR_INTERFACE_IS_BUSY;
|
||||
}
|
||||
|
||||
(void) hcd_pipe_xfer( custom_interface[dev_addr-1].pipe_in, p_buffer, length, true);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length)
|
||||
{
|
||||
TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_data, length) );
|
||||
|
||||
if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_out) )
|
||||
{
|
||||
return TUSB_ERROR_INTERFACE_IS_BUSY;
|
||||
}
|
||||
|
||||
(void) hcd_pipe_xfer( custom_interface[dev_addr-1].pipe_out, p_data, length, true);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-CLASS API
|
||||
//--------------------------------------------------------------------+
|
||||
void cush_init(void)
|
||||
{
|
||||
memclr_(&custom_interface, sizeof(custom_interface_info_t) * CFG_TUSB_HOST_DEVICE_MAX);
|
||||
}
|
||||
|
||||
tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length)
|
||||
{
|
||||
// FIXME quick hack to test lpc1k custom class with 2 bulk endpoints
|
||||
uint8_t const *p_desc = (uint8_t const *) p_interface_desc;
|
||||
p_desc = descriptor_next(p_desc);
|
||||
|
||||
//------------- Bulk Endpoints Descriptor -------------//
|
||||
for(uint32_t i=0; i<2; i++)
|
||||
{
|
||||
tusb_desc_endpoint_t const *p_endpoint = (tusb_desc_endpoint_t const *) p_desc;
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_IN_MASK ) ?
|
||||
&custom_interface[dev_addr-1].pipe_in : &custom_interface[dev_addr-1].pipe_out;
|
||||
*p_pipe_hdl = hcd_pipe_open(dev_addr, p_endpoint, TUSB_CLASS_VENDOR_SPECIFIC);
|
||||
TU_ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED );
|
||||
|
||||
p_desc = descriptor_next(p_desc);
|
||||
}
|
||||
|
||||
(*p_length) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
void cush_isr(pipe_handle_t pipe_hdl, tusb_event_t event)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void cush_close(uint8_t dev_addr)
|
||||
{
|
||||
tusb_error_t err1, err2;
|
||||
custom_interface_info_t * p_interface = &custom_interface[dev_addr-1];
|
||||
|
||||
// TODO re-consider to check pipe valid before calling pipe_close
|
||||
if( pipehandle_is_valid( p_interface->pipe_in ) )
|
||||
{
|
||||
err1 = hcd_pipe_close( p_interface->pipe_in );
|
||||
}
|
||||
|
||||
if ( pipehandle_is_valid( p_interface->pipe_out ) )
|
||||
{
|
||||
err2 = hcd_pipe_close( p_interface->pipe_out );
|
||||
}
|
||||
|
||||
memclr_(p_interface, sizeof(custom_interface_info_t));
|
||||
|
||||
TU_ASSERT(err1 == TUSB_ERROR_NONE && err2 == TUSB_ERROR_NONE, (void) 0 );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,87 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file custom_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 group_class
|
||||
* \defgroup Group_Custom Custom Class (not supported yet)
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_CUSTOM_HOST_H_
|
||||
#define _TUSB_CUSTOM_HOST_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "host/usbh.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
pipe_handle_t pipe_in;
|
||||
pipe_handle_t pipe_out;
|
||||
}custom_interface_info_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id)
|
||||
{
|
||||
(void) vendor_id; // TODO check this later
|
||||
(void) product_id;
|
||||
// return (tusbh_device_get_mounted_class_flag(dev_addr) & BIT_(TUSB_CLASS_MAPPED_INDEX_END-1) ) != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length);
|
||||
tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length);
|
||||
|
||||
#ifdef _TINY_USB_SOURCE_FILE_
|
||||
|
||||
void cush_init(void);
|
||||
tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) ATTR_WARN_UNUSED_RESULT;
|
||||
void cush_isr(pipe_handle_t pipe_hdl, tusb_event_t event);
|
||||
void cush_close(uint8_t dev_addr);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CUSTOM_HOST_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,595 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
/** \ingroup group_class
|
||||
* \defgroup ClassDriver_HID Human Interface Device (HID)
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_HID_H_
|
||||
#define _TUSB_HID_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Common Definitions
|
||||
//--------------------------------------------------------------------+
|
||||
/** \defgroup ClassDriver_HID_Common Common Definitions
|
||||
* @{ */
|
||||
|
||||
/// HID Subclass
|
||||
typedef enum
|
||||
{
|
||||
HID_SUBCLASS_NONE = 0, ///< No Subclass
|
||||
HID_SUBCLASS_BOOT = 1 ///< Boot Interface Subclass
|
||||
}hid_subclass_type_t;
|
||||
|
||||
/// HID Protocol
|
||||
typedef enum
|
||||
{
|
||||
HID_PROTOCOL_NONE = 0, ///< None
|
||||
HID_PROTOCOL_KEYBOARD = 1, ///< Keyboard
|
||||
HID_PROTOCOL_MOUSE = 2 ///< Mouse
|
||||
}hid_protocol_type_t;
|
||||
|
||||
/// HID Descriptor Type
|
||||
typedef enum
|
||||
{
|
||||
HID_DESC_TYPE_HID = 0x21, ///< HID Descriptor
|
||||
HID_DESC_TYPE_REPORT = 0x22, ///< Report Descriptor
|
||||
HID_DESC_TYPE_PHYSICAL = 0x23 ///< Physical Descriptor
|
||||
}hid_descriptor_type_t;
|
||||
|
||||
/// HID Request Report Type
|
||||
typedef enum
|
||||
{
|
||||
HID_REQUEST_REPORT_INPUT = 1, ///< Input
|
||||
HID_REQUEST_REPORT_OUTPUT, ///< Output
|
||||
HID_REQUEST_REPORT_FEATURE ///< Feature
|
||||
}hid_request_report_type_t;
|
||||
|
||||
/// HID Class Specific Control Request
|
||||
typedef enum
|
||||
{
|
||||
HID_REQUEST_CONTROL_GET_REPORT = 0x01, ///< Get Report
|
||||
HID_REQUEST_CONTROL_GET_IDLE = 0x02, ///< Get Idle
|
||||
HID_REQUEST_CONTROL_GET_PROTOCOL = 0x03, ///< Get Protocol
|
||||
HID_REQUEST_CONTROL_SET_REPORT = 0x09, ///< Set Report
|
||||
HID_REQUEST_CONTROL_SET_IDLE = 0x0a, ///< Set Idle
|
||||
HID_REQUEST_CONTROL_SET_PROTOCOL = 0x0b ///< Set Protocol
|
||||
}hid_request_type_t;
|
||||
|
||||
/// USB HID Descriptor
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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;
|
||||
|
||||
/// HID Country Code
|
||||
typedef enum
|
||||
{
|
||||
HID_Local_NotSupported = 0 , ///< NotSupported
|
||||
HID_Local_Arabic , ///< Arabic
|
||||
HID_Local_Belgian , ///< Belgian
|
||||
HID_Local_Canadian_Bilingual , ///< Canadian_Bilingual
|
||||
HID_Local_Canadian_French , ///< Canadian_French
|
||||
HID_Local_Czech_Republic , ///< Czech_Republic
|
||||
HID_Local_Danish , ///< Danish
|
||||
HID_Local_Finnish , ///< Finnish
|
||||
HID_Local_French , ///< French
|
||||
HID_Local_German , ///< German
|
||||
HID_Local_Greek , ///< Greek
|
||||
HID_Local_Hebrew , ///< Hebrew
|
||||
HID_Local_Hungary , ///< Hungary
|
||||
HID_Local_International , ///< International
|
||||
HID_Local_Italian , ///< Italian
|
||||
HID_Local_Japan_Katakana , ///< Japan_Katakana
|
||||
HID_Local_Korean , ///< Korean
|
||||
HID_Local_Latin_American , ///< Latin_American
|
||||
HID_Local_Netherlands_Dutch , ///< Netherlands/Dutch
|
||||
HID_Local_Norwegian , ///< Norwegian
|
||||
HID_Local_Persian_Farsi , ///< Persian (Farsi)
|
||||
HID_Local_Poland , ///< Poland
|
||||
HID_Local_Portuguese , ///< Portuguese
|
||||
HID_Local_Russia , ///< Russia
|
||||
HID_Local_Slovakia , ///< Slovakia
|
||||
HID_Local_Spanish , ///< Spanish
|
||||
HID_Local_Swedish , ///< Swedish
|
||||
HID_Local_Swiss_French , ///< Swiss/French
|
||||
HID_Local_Swiss_German , ///< Swiss/German
|
||||
HID_Local_Switzerland , ///< Switzerland
|
||||
HID_Local_Taiwan , ///< Taiwan
|
||||
HID_Local_Turkish_Q , ///< Turkish-Q
|
||||
HID_Local_UK , ///< UK
|
||||
HID_Local_US , ///< US
|
||||
HID_Local_Yugoslavia , ///< Yugoslavia
|
||||
HID_Local_Turkish_F ///< Turkish-F
|
||||
} hid_country_code_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MOUSE
|
||||
//--------------------------------------------------------------------+
|
||||
/** \addtogroup ClassDriver_HID_Mouse Mouse
|
||||
* @{ */
|
||||
|
||||
/// Standard HID Boot Protocol Mouse Report.
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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. */
|
||||
} hid_mouse_report_t;
|
||||
|
||||
/// Standard Mouse Buttons Bitmap
|
||||
typedef enum
|
||||
{
|
||||
MOUSE_BUTTON_LEFT = BIT_(0), ///< Left button
|
||||
MOUSE_BUTTON_RIGHT = BIT_(1), ///< Right button
|
||||
MOUSE_BUTTON_MIDDLE = BIT_(2) ///< Middle button
|
||||
}hid_mouse_button_bm_t;
|
||||
|
||||
/// @}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Keyboard
|
||||
//--------------------------------------------------------------------+
|
||||
/** \addtogroup ClassDriver_HID_Keyboard Keyboard
|
||||
* @{ */
|
||||
|
||||
/// Standard HID Boot Protocol Keyboard Report.
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
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. */
|
||||
} hid_keyboard_report_t;
|
||||
|
||||
/// Keyboard modifier codes bitmap
|
||||
typedef enum
|
||||
{
|
||||
KEYBOARD_MODIFIER_LEFTCTRL = BIT_(0), ///< Left Control
|
||||
KEYBOARD_MODIFIER_LEFTSHIFT = BIT_(1), ///< Left Shift
|
||||
KEYBOARD_MODIFIER_LEFTALT = BIT_(2), ///< Left Alt
|
||||
KEYBOARD_MODIFIER_LEFTGUI = BIT_(3), ///< Left Window
|
||||
KEYBOARD_MODIFIER_RIGHTCTRL = BIT_(4), ///< Right Control
|
||||
KEYBOARD_MODIFIER_RIGHTSHIFT = BIT_(5), ///< Right Shift
|
||||
KEYBOARD_MODIFIER_RIGHTALT = BIT_(6), ///< Right Alt
|
||||
KEYBOARD_MODIFIER_RIGHTGUI = BIT_(7) ///< Right Window
|
||||
}hid_keyboard_modifier_bm_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
KEYBOARD_LED_NUMLOCK = BIT_(0), ///< Num Lock LED
|
||||
KEYBOARD_LED_CAPSLOCK = BIT_(1), ///< Caps Lock LED
|
||||
KEYBOARD_LED_SCROLLLOCK = BIT_(2), ///< Scroll Lock LED
|
||||
KEYBOARD_LED_COMPOSE = BIT_(3), ///< Composition Mode
|
||||
KEYBOARD_LED_KANA = BIT_(4) ///< Kana mode
|
||||
}hid_keyboard_led_bm_t;
|
||||
|
||||
/// @}
|
||||
|
||||
#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, '\x1b', '\x1b' )\
|
||||
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,
|
||||
//
|
||||
//};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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
|
||||
};
|
||||
|
||||
|
||||
/// HID Usage Table: Consumer Page (0x0C)
|
||||
/// Only contains controls that supported by Windows (whole list is too long)
|
||||
enum
|
||||
{
|
||||
// Generic Control
|
||||
HID_USAGE_CONSUMER_CONTROL = 0x0001,
|
||||
|
||||
// Power Control
|
||||
HID_USAGE_CONSUMER_POWER = 0x0030,
|
||||
HID_USAGE_CONSUMER_RESET = 0x0031,
|
||||
HID_USAGE_CONSUMER_SLEEP = 0x0032,
|
||||
|
||||
// Screen Brightness
|
||||
HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F,
|
||||
HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070,
|
||||
|
||||
// These HID usages operate only on mobile systems (battery powered) and
|
||||
// require Windows 8 (build 8302 or greater).
|
||||
HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS = 0x000C,
|
||||
HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS = 0x00C6,
|
||||
HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7,
|
||||
HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8,
|
||||
|
||||
// Media Control
|
||||
HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD,
|
||||
HID_USAGE_CONSUMER_SCAN_NEXT = 0x00B5,
|
||||
HID_USAGE_CONSUMER_SCAN_PREVIOUS = 0x00B6,
|
||||
HID_USAGE_CONSUMER_STOP = 0x00B7,
|
||||
HID_USAGE_CONSUMER_VOLUME = 0x00E0,
|
||||
HID_USAGE_CONSUMER_MUTE = 0x00E2,
|
||||
HID_USAGE_CONSUMER_BASS = 0x00E3,
|
||||
HID_USAGE_CONSUMER_TREBLE = 0x00E4,
|
||||
HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5,
|
||||
HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9,
|
||||
HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA,
|
||||
HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152,
|
||||
HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153,
|
||||
HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154,
|
||||
HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155,
|
||||
|
||||
// Application Launcher
|
||||
HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183,
|
||||
HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A,
|
||||
HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192,
|
||||
HID_USAGE_CONSUMER_AL_LOCAL_BROWSER = 0x0194,
|
||||
|
||||
// Browser/Explorer Specific
|
||||
HID_USAGE_CONSUMER_AC_SEARCH = 0x0221,
|
||||
HID_USAGE_CONSUMER_AC_HOME = 0x0223,
|
||||
HID_USAGE_CONSUMER_AC_BACK = 0x0224,
|
||||
HID_USAGE_CONSUMER_AC_FORWARD = 0x0225,
|
||||
HID_USAGE_CONSUMER_AC_STOP = 0x0226,
|
||||
HID_USAGE_CONSUMER_AC_REFRESH = 0x0227,
|
||||
HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A,
|
||||
|
||||
// Mouse Horizontal scroll
|
||||
HID_USAGE_CONSUMER_AC_PAN = 0x0238,
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HID_H__ */
|
||||
|
||||
/// @}
|
||||
@@ -0,0 +1,322 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file hid_device.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_DEVICE_SUPPORTED && DEVICE_CLASS_HID)
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "hid_device.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
enum {
|
||||
HIDD_NUMBER_OF_SUBCLASS = 3,
|
||||
HIDD_BUFFER_SIZE = 128
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t const * p_report_desc;
|
||||
uint16_t report_length;
|
||||
|
||||
uint8_t edpt_addr;
|
||||
uint8_t interface_number;
|
||||
}hidd_interface_t;
|
||||
|
||||
typedef struct {
|
||||
hidd_interface_t * const p_interface;
|
||||
void (* const xfer_cb) (uint8_t, tusb_event_t, uint32_t);
|
||||
uint16_t (* const get_report_cb) (uint8_t, hid_request_report_type_t, void**, uint16_t );
|
||||
void (* const set_report_cb) (uint8_t, hid_request_report_type_t, uint8_t[], uint16_t);
|
||||
}hidd_class_driver_t;
|
||||
|
||||
extern ATTR_WEAK hidd_interface_t keyboardd_data;
|
||||
extern ATTR_WEAK hidd_interface_t moused_data;
|
||||
|
||||
static hidd_class_driver_t const hidd_class_driver[HIDD_NUMBER_OF_SUBCLASS] =
|
||||
{
|
||||
// [HID_PROTOCOL_NONE] = for HID Generic
|
||||
|
||||
#if CFG_TUD_HID_KEYBOARD
|
||||
[HID_PROTOCOL_KEYBOARD] =
|
||||
{
|
||||
.p_interface = &keyboardd_data,
|
||||
.xfer_cb = tud_hid_keyboard_cb,
|
||||
.get_report_cb = tud_hid_keyboard_get_report_cb,
|
||||
.set_report_cb = tud_hid_keyboard_set_report_cb
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_HID_MOUSE
|
||||
[HID_PROTOCOL_MOUSE] =
|
||||
{
|
||||
.p_interface = &moused_data,
|
||||
.xfer_cb = tud_hid_mouse_cb,
|
||||
.get_report_cb = tud_hid_mouse_get_report_cb,
|
||||
.set_report_cb = tud_hid_mouse_set_report_cb
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// internal buffer for transferring data
|
||||
CFG_TUSB_ATTR_USBRAM STATIC_VAR uint8_t m_hid_buffer[ HIDD_BUFFER_SIZE ];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// KEYBOARD APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUD_HID_KEYBOARD
|
||||
STATIC_VAR hidd_interface_t keyboardd_data;
|
||||
|
||||
bool tud_hid_keyboard_busy(uint8_t rhport)
|
||||
{
|
||||
return dcd_edpt_busy(rhport, keyboardd_data.edpt_addr);
|
||||
}
|
||||
|
||||
tusb_error_t tud_hid_keyboard_send(uint8_t rhport, hid_keyboard_report_t const *p_report)
|
||||
{
|
||||
VERIFY(tud_mounted(), TUSB_ERROR_USBD_DEVICE_NOT_CONFIGURED);
|
||||
|
||||
hidd_interface_t * p_kbd = &keyboardd_data; // TODO &keyboardd_data[rhport];
|
||||
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_kbd->edpt_addr, (void*) p_report, sizeof(hid_keyboard_report_t)), TUSB_ERROR_DCD_EDPT_XFER ) ;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MOUSE APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUD_HID_MOUSE
|
||||
STATIC_VAR hidd_interface_t moused_data;
|
||||
|
||||
bool tud_hid_mouse_is_busy(uint8_t rhport)
|
||||
{
|
||||
return dcd_edpt_busy(rhport, moused_data.edpt_addr);
|
||||
}
|
||||
|
||||
tusb_error_t tud_hid_mouse_send(uint8_t rhport, hid_mouse_report_t const *p_report)
|
||||
{
|
||||
VERIFY(tud_mounted(), TUSB_ERROR_USBD_DEVICE_NOT_CONFIGURED);
|
||||
|
||||
hidd_interface_t * p_mouse = &moused_data; // TODO &keyboardd_data[rhport];
|
||||
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_mouse->edpt_addr, (void*) p_report, sizeof(hid_mouse_report_t)), TUSB_ERROR_DCD_EDPT_XFER ) ;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-CLASS API
|
||||
//--------------------------------------------------------------------+
|
||||
static void interface_clear(hidd_interface_t * p_interface)
|
||||
{
|
||||
if ( p_interface != NULL )
|
||||
{
|
||||
memclr_(p_interface, sizeof(hidd_interface_t));
|
||||
p_interface->interface_number = INTERFACE_INVALID_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
void hidd_init(void)
|
||||
{
|
||||
for(uint8_t i=0; i<HIDD_NUMBER_OF_SUBCLASS; i++)
|
||||
{
|
||||
interface_clear( hidd_class_driver[i].p_interface );
|
||||
}
|
||||
}
|
||||
|
||||
void hidd_close(uint8_t rhport)
|
||||
{
|
||||
for(uint8_t i=0; i<HIDD_NUMBER_OF_SUBCLASS; i++)
|
||||
{
|
||||
interface_clear(hidd_class_driver[i].p_interface);
|
||||
}
|
||||
}
|
||||
|
||||
tusb_error_t hidd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
uint8_t subclass_idx;
|
||||
for(subclass_idx=0; subclass_idx<HIDD_NUMBER_OF_SUBCLASS; subclass_idx++)
|
||||
{
|
||||
hidd_interface_t * const p_interface = hidd_class_driver[subclass_idx].p_interface;
|
||||
if ( (p_interface != NULL) && (p_request->wIndex == p_interface->interface_number) ) break;
|
||||
}
|
||||
|
||||
TU_ASSERT(subclass_idx < HIDD_NUMBER_OF_SUBCLASS, TUSB_ERROR_FAILED);
|
||||
|
||||
hidd_class_driver_t const * const p_driver = &hidd_class_driver[subclass_idx];
|
||||
hidd_interface_t* const p_hid = p_driver->p_interface;
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
//------------- STD Request -------------//
|
||||
if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
|
||||
{
|
||||
uint8_t const desc_type = u16_high_u8(p_request->wValue);
|
||||
uint8_t const desc_index = u16_low_u8 (p_request->wValue);
|
||||
|
||||
(void) desc_index;
|
||||
|
||||
if (p_request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT)
|
||||
{
|
||||
STASK_ASSERT ( p_hid->report_length <= HIDD_BUFFER_SIZE );
|
||||
|
||||
// copy to allow report descriptor not to be in USBRAM
|
||||
memcpy(m_hid_buffer, p_hid->p_report_desc, p_hid->report_length);
|
||||
|
||||
usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, m_hid_buffer, p_hid->report_length);
|
||||
}else
|
||||
{
|
||||
dcd_control_stall(rhport);
|
||||
}
|
||||
}
|
||||
//------------- Class Specific Request -------------//
|
||||
else if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
|
||||
{
|
||||
if( (HID_REQUEST_CONTROL_GET_REPORT == p_request->bRequest) && (p_driver->get_report_cb != NULL) )
|
||||
{
|
||||
// wValue = Report Type | Report ID
|
||||
void* p_buffer = NULL;
|
||||
|
||||
uint16_t actual_length = p_driver->get_report_cb(rhport, (hid_request_report_type_t) u16_high_u8(p_request->wValue),
|
||||
&p_buffer, p_request->wLength);
|
||||
STASK_ASSERT( p_buffer != NULL && actual_length > 0 );
|
||||
|
||||
usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, p_buffer, actual_length);
|
||||
}
|
||||
else if ( (HID_REQUEST_CONTROL_SET_REPORT == p_request->bRequest) && (p_driver->set_report_cb != NULL) )
|
||||
{
|
||||
// return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; // TODO test STALL control out endpoint (with mouse+keyboard)
|
||||
// wValue = Report Type | Report ID
|
||||
usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, m_hid_buffer, p_request->wLength);
|
||||
|
||||
p_driver->set_report_cb(rhport, u16_high_u8(p_request->wValue), m_hid_buffer, p_request->wLength);
|
||||
}
|
||||
else if (HID_REQUEST_CONTROL_SET_IDLE == p_request->bRequest)
|
||||
{
|
||||
// uint8_t idle_rate = u16_high_u8(p_request->wValue);
|
||||
dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
|
||||
}else
|
||||
{
|
||||
// HID_REQUEST_CONTROL_GET_IDLE:
|
||||
// HID_REQUEST_CONTROL_GET_PROTOCOL:
|
||||
// HID_REQUEST_CONTROL_SET_PROTOCOL:
|
||||
dcd_control_stall(rhport);
|
||||
}
|
||||
}else
|
||||
{
|
||||
dcd_control_stall(rhport);
|
||||
}
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
tusb_error_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length)
|
||||
{
|
||||
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;
|
||||
TU_ASSERT(HID_DESC_TYPE_HID == p_desc_hid->bDescriptorType, TUSB_ERROR_HIDD_DESCRIPTOR_INTERFACE);
|
||||
|
||||
//------------- Endpoint Descriptor -------------//
|
||||
p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH];
|
||||
tusb_desc_endpoint_t const *p_desc_endpoint = (tusb_desc_endpoint_t const *) p_desc;
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == p_desc_endpoint->bDescriptorType, TUSB_ERROR_HIDD_DESCRIPTOR_INTERFACE);
|
||||
|
||||
if (p_interface_desc->bInterfaceSubClass == HID_SUBCLASS_BOOT)
|
||||
{
|
||||
switch(p_interface_desc->bInterfaceProtocol)
|
||||
{
|
||||
case HID_PROTOCOL_KEYBOARD:
|
||||
case HID_PROTOCOL_MOUSE:
|
||||
{
|
||||
hidd_class_driver_t const * const p_driver = &hidd_class_driver[p_interface_desc->bInterfaceProtocol];
|
||||
hidd_interface_t * const p_hid = p_driver->p_interface;
|
||||
|
||||
VERIFY(p_hid, TUSB_ERROR_FAILED);
|
||||
|
||||
VERIFY( dcd_edpt_open(rhport, p_desc_endpoint), TUSB_ERROR_DCD_FAILED );
|
||||
|
||||
p_hid->edpt_addr = p_desc_endpoint->bEndpointAddress;
|
||||
|
||||
p_hid->interface_number = p_interface_desc->bInterfaceNumber;
|
||||
p_hid->p_report_desc = (p_interface_desc->bInterfaceProtocol == HID_PROTOCOL_KEYBOARD) ? tusbd_descriptor_pointers.p_hid_keyboard_report : tusbd_descriptor_pointers.p_hid_mouse_report;
|
||||
p_hid->report_length = p_desc_hid->wReportLength;
|
||||
|
||||
VERIFY(p_hid->p_report_desc, TUSB_ERROR_DESCRIPTOR_CORRUPTED);
|
||||
}
|
||||
break;
|
||||
|
||||
default: // TODO unknown, unsupported protocol --> skip this interface
|
||||
return TUSB_ERROR_HIDD_DESCRIPTOR_INTERFACE;
|
||||
}
|
||||
*p_length = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + sizeof(tusb_desc_endpoint_t);
|
||||
}else
|
||||
{
|
||||
// open generic
|
||||
*p_length = 0;
|
||||
return TUSB_ERROR_HIDD_DESCRIPTOR_INTERFACE;
|
||||
}
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
for(uint8_t i=0; i<HIDD_NUMBER_OF_SUBCLASS; i++)
|
||||
{
|
||||
hidd_interface_t * const p_interface = hidd_class_driver[i].p_interface;
|
||||
if ( (p_interface != NULL) && (edpt_addr == p_interface->edpt_addr) )
|
||||
{
|
||||
hidd_class_driver[i].xfer_cb(rhport, event, xferred_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,217 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file hid_device.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_HID_DEVICE_H_
|
||||
#define _TUSB_HID_DEVICE_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "device/usbd.h"
|
||||
#include "hid.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// KEYBOARD APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \addtogroup ClassDriver_HID_Keyboard Keyboard
|
||||
* @{ */
|
||||
/** \defgroup Keyboard_Device Device
|
||||
* @{ */
|
||||
|
||||
/** \brief Check if the interface is currently busy or not
|
||||
* \param[in] rhport USB Controller ID
|
||||
* \retval true if the interface is busy meaning the stack is still transferring/waiting data from/to host
|
||||
* \retval false if the interface is not busy meaning the stack successfully transferred data from/to host
|
||||
* \note This function is primarily used for polling/waiting result after \ref tusbd_hid_keyboard_send.
|
||||
*/
|
||||
bool tud_hid_keyboard_busy(uint8_t rhport);
|
||||
|
||||
/** \brief Submit USB transfer
|
||||
* \param[in] rhport USB Controller ID
|
||||
* \param[in,out] p_report address that is used to store data from device. Must be accessible by usb controller (see \ref CFG_TUSB_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 input parameters are not correct
|
||||
* \note This function is non-blocking and returns immediately. Data will be transferred when USB Host work with this interface.
|
||||
* The result of usb transfer will be reported by the interface's callback function
|
||||
*/
|
||||
tusb_error_t tud_hid_keyboard_send(uint8_t rhport, hid_keyboard_report_t const *p_report);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION CALLBACK API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/** \brief Callback function that is invoked when an transferring event occurred
|
||||
* after invoking \ref tusbd_hid_keyboard_send
|
||||
* \param[in] rhport USB Controller ID
|
||||
* \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.
|
||||
*/
|
||||
void tud_hid_keyboard_cb(uint8_t rhport, tusb_event_t event, uint32_t xferred_bytes);
|
||||
|
||||
/** \brief Callback function that is invoked when USB host request \ref HID_REQUEST_CONTROL_GET_REPORT
|
||||
* via control endpoint.
|
||||
* \param[in] rhport USB Controller ID
|
||||
* \param[in] report_type specify which report (INPUT, OUTPUT, FEATURE) that host requests
|
||||
* \param[out] pp_report pointer to buffer that application need to update, value must be accessible by USB controller (see \ref CFG_TUSB_ATTR_USBRAM)
|
||||
* \param[in] requested_length number of bytes that host requested
|
||||
* \retval non-zero Actual number of bytes in the response's buffer.
|
||||
* \retval zero indicates the current request is not supported. Tinyusb device stack will reject the request by
|
||||
* sending STALL in the data phase.
|
||||
* \note After this callback, the request is silently executed by the tinyusb stack, thus
|
||||
* the completion of this control request will not be reported to application.
|
||||
* For Keyboard, USB host often uses this to turn on/off the LED for CAPLOCKS, NUMLOCK (\ref hid_keyboard_led_bm_t)
|
||||
*/
|
||||
uint16_t tud_hid_keyboard_get_report_cb(uint8_t rhport, hid_request_report_type_t report_type, void** pp_report, uint16_t requested_length);
|
||||
|
||||
/** \brief Callback function that is invoked when USB host request \ref HID_REQUEST_CONTROL_SET_REPORT
|
||||
* via control endpoint.
|
||||
* \param[in] rhport USB Controller ID
|
||||
* \param[in] report_type specify which report (INPUT, OUTPUT, FEATURE) that host requests
|
||||
* \param[in] p_report_data buffer containing the report's data
|
||||
* \param[in] length number of bytes in the \a p_report_data
|
||||
* \note By the time this callback is invoked, the USB control transfer is already completed in the hardware side.
|
||||
* Application are free to handle data at its own will.
|
||||
*/
|
||||
void tud_hid_keyboard_set_report_cb(uint8_t rhport, hid_request_report_type_t report_type, uint8_t p_report_data[], uint16_t length);
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MOUSE APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \addtogroup ClassDriver_HID_Mouse Mouse
|
||||
* @{ */
|
||||
/** \defgroup Mouse_Device Device
|
||||
* @{ */
|
||||
|
||||
/** \brief Check if the interface is currently busy or not
|
||||
* \param[in] rhport USB Controller ID
|
||||
* \retval true if the interface is busy meaning the stack is still transferring/waiting data from/to host
|
||||
* \retval false if the interface is not busy meaning the stack successfully transferred data from/to host
|
||||
* \note This function is primarily used for polling/waiting result after \ref tusbd_hid_mouse_send.
|
||||
*/
|
||||
bool tud_hid_mouse_is_busy(uint8_t rhport);
|
||||
|
||||
/** \brief Perform transfer queuing
|
||||
* \param[in] rhport USB Controller ID
|
||||
* \param[in,out] p_report address that is used to store data from device. Must be accessible by usb controller (see \ref CFG_TUSB_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 input parameters are not correct
|
||||
* \note This function is non-blocking and returns immediately. Data will be transferred when USB Host work with this interface.
|
||||
* The result of usb transfer will be reported by the interface's callback function
|
||||
*/
|
||||
tusb_error_t tud_hid_mouse_send(uint8_t rhport, hid_mouse_report_t const *p_report);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION CALLBACK API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/** \brief Callback function that is invoked when an transferring event occurred
|
||||
* after invoking \ref tusbd_hid_mouse_send
|
||||
* \param[in] rhport USB Controller ID
|
||||
* \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.
|
||||
*/
|
||||
void tud_hid_mouse_cb(uint8_t rhport, tusb_event_t event, uint32_t xferred_bytes);
|
||||
|
||||
/** \brief Callback function that is invoked when USB host request \ref HID_REQUEST_CONTROL_GET_REPORT
|
||||
* via control endpoint.
|
||||
* \param[in] rhport USB Controller ID
|
||||
* \param[in] report_type specify which report (INPUT, OUTPUT, FEATURE) that host requests
|
||||
* \param[out] pp_report pointer to buffer that application need to update, value must be accessible by USB controller (see \ref CFG_TUSB_ATTR_USBRAM)
|
||||
* \param[in] requested_length number of bytes that host requested
|
||||
* \retval non-zero Actual number of bytes in the response's buffer.
|
||||
* \retval zero indicates the current request is not supported. Tinyusb device stack will reject the request by
|
||||
* sending STALL in the data phase.
|
||||
* \note After this callback, the request is silently executed by the tinyusb stack, thus
|
||||
* the completion of this control request will not be reported to application
|
||||
*/
|
||||
uint16_t tud_hid_mouse_get_report_cb(uint8_t rhport, hid_request_report_type_t report_type, void** pp_report, uint16_t requested_length);
|
||||
|
||||
/** \brief Callback function that is invoked when USB host request \ref HID_REQUEST_CONTROL_SET_REPORT
|
||||
* via control endpoint.
|
||||
* \param[in] rhport USB Controller ID
|
||||
* \param[in] report_type specify which report (INPUT, OUTPUT, FEATURE) that host requests
|
||||
* \param[in] p_report_data buffer containing the report's data
|
||||
* \param[in] length number of bytes in the \a p_report_data
|
||||
* \note By the time this callback is invoked, the USB control transfer is already completed in the hardware side.
|
||||
* Application are free to handle data at its own will.
|
||||
*/
|
||||
void tud_hid_mouse_set_report_cb(uint8_t rhport, hid_request_report_type_t report_type, uint8_t p_report_data[], uint16_t length);
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef _TINY_USB_SOURCE_FILE_
|
||||
|
||||
void hidd_init(void);
|
||||
tusb_error_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
|
||||
tusb_error_t hidd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void hidd_close(uint8_t rhport);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HID_DEVICE_H_ */
|
||||
|
||||
|
||||
@@ -0,0 +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/tusb_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_desc_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;
|
||||
|
||||
TU_ASSERT (pipehandle_is_valid(p_hid->pipe_hdl), TUSB_ERROR_HCD_FAILED);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
static inline void hidh_interface_close(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)
|
||||
{
|
||||
//------------- parameters validation -------------//
|
||||
// TODO change to use is configured function
|
||||
TU_ASSERT (TUSB_DEVICE_STATE_CONFIGURED == tuh_device_get_state(dev_addr), TUSB_ERROR_DEVICE_NOT_READY);
|
||||
VERIFY (report, TUSB_ERROR_INVALID_PARA);
|
||||
TU_ASSSERT (!hcd_pipe_is_busy(p_hid->pipe_hdl), TUSB_ERROR_INTERFACE_IS_BUSY);
|
||||
|
||||
TU_ASSERT_ERR( hcd_pipe_xfer(p_hid->pipe_hdl, report, p_hid->report_size, true) ) ;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// KEYBOARD
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUSB_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[CFG_TUSB_HOST_DEVICE_MAX]; // does not have addr0, index = dev_address-1
|
||||
|
||||
//------------- KEYBOARD PUBLIC API (parameter validation required) -------------//
|
||||
bool tuh_hid_keyboard_is_mounted(uint8_t dev_addr)
|
||||
{
|
||||
return tuh_device_is_configured(dev_addr) && pipehandle_is_valid(keyboardh_data[dev_addr-1].pipe_hdl);
|
||||
}
|
||||
|
||||
tusb_error_t tuh_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 tuh_hid_keyboard_is_busy(uint8_t dev_addr)
|
||||
{
|
||||
return tuh_hid_keyboard_is_mounted(dev_addr) &&
|
||||
hcd_pipe_is_busy( keyboardh_data[dev_addr-1].pipe_hdl );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MOUSE
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUSB_HOST_HID_MOUSE
|
||||
|
||||
STATIC_VAR hidh_interface_info_t mouseh_data[CFG_TUSB_HOST_DEVICE_MAX]; // does not have addr0, index = dev_address-1
|
||||
|
||||
//------------- Public API -------------//
|
||||
bool tuh_hid_mouse_is_mounted(uint8_t dev_addr)
|
||||
{
|
||||
return tuh_device_is_configured(dev_addr) && pipehandle_is_valid(mouseh_data[dev_addr-1].pipe_hdl);
|
||||
}
|
||||
|
||||
bool tuh_hid_mouse_is_busy(uint8_t dev_addr)
|
||||
{
|
||||
return tuh_hid_mouse_is_mounted(dev_addr) &&
|
||||
hcd_pipe_is_busy( mouseh_data[dev_addr-1].pipe_hdl );
|
||||
}
|
||||
|
||||
tusb_error_t tuh_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 CFG_TUSB_HOST_HID_GENERIC
|
||||
|
||||
//STATIC_ struct {
|
||||
// hidh_interface_info_t
|
||||
//} generic_data[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CLASS-USBH API (don't require to verify parameters)
|
||||
//--------------------------------------------------------------------+
|
||||
void hidh_init(void)
|
||||
{
|
||||
#if CFG_TUSB_HOST_HID_KEYBOARD
|
||||
memclr_(&keyboardh_data, sizeof(hidh_interface_info_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_HID_MOUSE
|
||||
memclr_(&mouseh_data, sizeof(hidh_interface_info_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_HID_GENERIC
|
||||
hidh_generic_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
CFG_TUSB_ATTR_USBRAM uint8_t report_descriptor[256];
|
||||
#endif
|
||||
|
||||
tusb_error_t hidh_open_subtask(uint8_t dev_addr, tusb_desc_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;
|
||||
TU_ASSERT(HID_DESC_TYPE_HID == p_desc_hid->bDescriptorType, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
//------------- Endpoint Descriptor -------------//
|
||||
p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH];
|
||||
tusb_desc_endpoint_t const * p_endpoint_desc = (tusb_desc_endpoint_t const *) p_desc;
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint_desc->bDescriptorType, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
//------------- SET IDLE (0) request -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE),
|
||||
HID_REQUEST_CONTROL_SET_IDLE, 0, p_interface_desc->bInterfaceNumber,
|
||||
0, NULL ),
|
||||
error
|
||||
);
|
||||
(void) error; // skip if set idle is failed
|
||||
|
||||
#if 0
|
||||
//------------- Get Report Descriptor TODO HID parser -------------//
|
||||
if ( p_desc_hid->bNumDescriptors )
|
||||
{
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_STANDARD, TUSB_REQ_RCPT_INTERFACE),
|
||||
TUSB_REQ_GET_DESCRIPTOR, (p_desc_hid->bReportType << 8), 0,
|
||||
p_desc_hid->wReportLength, report_descriptor ),
|
||||
error
|
||||
);
|
||||
(void) error; // if error in getting report descriptor --> treating like there is none
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( HID_SUBCLASS_BOOT == p_interface_desc->bInterfaceSubClass )
|
||||
{
|
||||
#if CFG_TUSB_HOST_HID_KEYBOARD
|
||||
if ( HID_PROTOCOL_KEYBOARD == p_interface_desc->bInterfaceProtocol)
|
||||
{
|
||||
STASK_ASSERT_ERR ( hidh_interface_open(dev_addr, p_interface_desc->bInterfaceNumber, p_endpoint_desc, &keyboardh_data[dev_addr-1]) );
|
||||
tuh_hid_keyboard_mounted_cb(dev_addr);
|
||||
} else
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_HID_MOUSE
|
||||
if ( HID_PROTOCOL_MOUSE == p_interface_desc->bInterfaceProtocol)
|
||||
{
|
||||
STASK_ASSERT_ERR ( hidh_interface_open(dev_addr, p_interface_desc->bInterfaceNumber, p_endpoint_desc, &mouseh_data[dev_addr-1]) );
|
||||
tuh_hid_mouse_mounted_cb(dev_addr);
|
||||
} else
|
||||
#endif
|
||||
|
||||
{
|
||||
STASK_RETURN(TUSB_ERROR_HIDH_NOT_SUPPORTED_PROTOCOL); // exit & restart task
|
||||
}
|
||||
}else
|
||||
{
|
||||
STASK_RETURN(TUSB_ERROR_HIDH_NOT_SUPPORTED_SUBCLASS); // exit & restart task
|
||||
}
|
||||
|
||||
*p_length = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
void hidh_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) xferred_bytes; // TODO may need to use this para later
|
||||
|
||||
#if CFG_TUSB_HOST_HID_KEYBOARD
|
||||
if ( pipehandle_is_equal(pipe_hdl, keyboardh_data[pipe_hdl.dev_addr-1].pipe_hdl) )
|
||||
{
|
||||
tuh_hid_keyboard_isr(pipe_hdl.dev_addr, event);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_HID_MOUSE
|
||||
if ( pipehandle_is_equal(pipe_hdl, mouseh_data[pipe_hdl.dev_addr-1].pipe_hdl) )
|
||||
{
|
||||
tuh_hid_mouse_isr(pipe_hdl.dev_addr, event);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_HID_GENERIC
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void hidh_close(uint8_t dev_addr)
|
||||
{
|
||||
#if CFG_TUSB_HOST_HID_KEYBOARD
|
||||
if ( pipehandle_is_valid( keyboardh_data[dev_addr-1].pipe_hdl ) )
|
||||
{
|
||||
hidh_interface_close(&keyboardh_data[dev_addr-1]);
|
||||
tuh_hid_keyboard_unmounted_cb(dev_addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_HID_MOUSE
|
||||
if( pipehandle_is_valid( mouseh_data[dev_addr-1].pipe_hdl ) )
|
||||
{
|
||||
hidh_interface_close(&mouseh_data[dev_addr-1]);
|
||||
tuh_hid_mouse_unmounted_cb( dev_addr );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_HID_GENERIC
|
||||
hidh_generic_close(dev_addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,231 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@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/tusb_common.h"
|
||||
#include "host/usbh.h"
|
||||
#include "hid.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// KEYBOARD Application API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \addtogroup ClassDriver_HID_Keyboard Keyboard
|
||||
* @{ */
|
||||
|
||||
/** \defgroup Keyboard_Host Host
|
||||
* The interface API includes status checking function, data transferring function and callback functions
|
||||
* @{ */
|
||||
|
||||
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 tuh_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 tuh_hid_keyboard_get_report.
|
||||
* Alternatively, asynchronous event API can be used
|
||||
*/
|
||||
bool tuh_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 CFG_TUSB_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 input parameters 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 tuh_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 tuh_hid_keyboard_get_report within this callback
|
||||
*/
|
||||
void tuh_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 tuh_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 tuh_hid_keyboard_unmounted_cb(uint8_t dev_addr);
|
||||
|
||||
/** @} */ // Keyboard_Host
|
||||
/** @} */ // ClassDriver_HID_Keyboard
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MOUSE Application API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \addtogroup ClassDriver_HID_Mouse Mouse
|
||||
* @{ */
|
||||
|
||||
/** \defgroup Mouse_Host Host
|
||||
* The interface API includes status checking function, data transferring function and callback functions
|
||||
* @{ */
|
||||
|
||||
/** \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 tuh_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 tuh_hid_mouse_get_report.
|
||||
* Alternatively, asynchronous event API can be used
|
||||
*/
|
||||
bool tuh_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 CFG_TUSB_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 input parameters 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 tuh_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 tuh_hid_mouse_get_report within this callback
|
||||
*/
|
||||
void tuh_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 tuh_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 tuh_hid_mouse_unmounted_cb(uint8_t dev_addr);
|
||||
|
||||
/** @} */ // Mouse_Host
|
||||
/** @} */ // ClassDriver_HID_Mouse
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// GENERIC Application API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \addtogroup ClassDriver_HID_Generic Generic (not supported yet)
|
||||
* @{ */
|
||||
|
||||
/** \defgroup Generic_Host Host
|
||||
* The interface API includes status checking function, data transferring function and callback functions
|
||||
* @{ */
|
||||
|
||||
bool tuh_hid_generic_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT;
|
||||
tusb_error_t tuh_hid_generic_get_report(uint8_t dev_addr, void* p_report, bool int_on_complete) ATTR_WARN_UNUSED_RESULT;
|
||||
tusb_error_t tuh_hid_generic_set_report(uint8_t dev_addr, void* p_report, bool int_on_complete) ATTR_WARN_UNUSED_RESULT;
|
||||
tusb_interface_status_t tuh_hid_generic_get_status(uint8_t dev_addr) ATTR_WARN_UNUSED_RESULT;
|
||||
tusb_interface_status_t tuh_hid_generic_set_status(uint8_t dev_addr) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
//------------- Application Callback -------------//
|
||||
void tuh_hid_generic_isr(uint8_t dev_addr, tusb_event_t event);
|
||||
|
||||
/** @} */ // Generic_Host
|
||||
/** @} */ // ClassDriver_HID_Generic
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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_desc_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_ */
|
||||
|
||||
/** @} */ // ClassDriver_HID
|
||||
@@ -0,0 +1,376 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file msc.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 group_class
|
||||
* \defgroup ClassDriver_MSC MassStorage (MSC)
|
||||
* @{ */
|
||||
|
||||
/** \defgroup ClassDriver_MSC_Common Common Definitions
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_MSC_H_
|
||||
#define _TUSB_MSC_H_
|
||||
|
||||
#include <common/tusb_common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Mass Storage Class Constant
|
||||
//--------------------------------------------------------------------+
|
||||
/// MassStorage Subclass
|
||||
typedef enum
|
||||
{
|
||||
MSC_SUBCLASS_RBC = 1 , ///< Reduced Block Commands (RBC) T10 Project 1240-D
|
||||
MSC_SUBCLASS_SFF_MMC , ///< SFF-8020i, MMC-2 (ATAPI). Typically used by a CD/DVD device
|
||||
MSC_SUBCLASS_QIC , ///< QIC-157. Typically used by a tape device
|
||||
MSC_SUBCLASS_UFI , ///< UFI. Typically used by Floppy Disk Drive (FDD) device
|
||||
MSC_SUBCLASS_SFF , ///< SFF-8070i. Can be used by Floppy Disk Drive (FDD) device
|
||||
MSC_SUBCLASS_SCSI ///< SCSI transparent command set
|
||||
}msc_subclass_type_t;
|
||||
|
||||
enum {
|
||||
MSC_CBW_SIGNATURE = 0x43425355, ///< Constant value of 43425355h (little endian)
|
||||
MSC_CSW_SIGNATURE = 0x53425355 ///< Constant value of 53425355h (little endian)
|
||||
};
|
||||
|
||||
/// \brief MassStorage Protocol.
|
||||
/// \details CBI only approved to use with full-speed floopy disk & should not used with highspeed or device other than floopy
|
||||
typedef enum
|
||||
{
|
||||
MSC_PROTOCOL_CBI = 0 , ///< Control/Bulk/Interrupt protocol (with command completion interrupt)
|
||||
MSC_PROTOCOL_CBI_NO_INTERRUPT = 1 , ///< Control/Bulk/Interrupt protocol (without command completion interrupt)
|
||||
MSC_PROTOCOL_BOT = 0x50 ///< Bulk-Only Transport
|
||||
}msc_protocol_type_t;
|
||||
|
||||
/// MassStorage Class-Specific Control Request
|
||||
typedef enum
|
||||
{
|
||||
MSC_REQUEST_GET_MAX_LUN = 254, ///< The Get Max LUN device request is used to determine the number of logical units supported by the device. Logical Unit Numbers on the device shall be numbered contiguously starting from LUN 0 to a maximum LUN of 15
|
||||
MSC_REQUEST_RESET = 255 ///< This request is used to reset the mass storage device and its associated interface. This class-specific request shall ready the device for the next CBW from the host.
|
||||
}msc_request_type_t;
|
||||
|
||||
/// \brief Command Block Status Values
|
||||
/// \details Indicates the success or failure of the command. The device shall set this byte to zero if the command completed
|
||||
/// successfully. A non-zero value shall indicate a failure during command execution according to the following
|
||||
typedef enum
|
||||
{
|
||||
MSC_CSW_STATUS_PASSED = 0 , ///< MSC_CSW_STATUS_PASSED
|
||||
MSC_CSW_STATUS_FAILED , ///< MSC_CSW_STATUS_FAILED
|
||||
MSC_CSW_STATUS_PHASE_ERROR ///< MSC_CSW_STATUS_PHASE_ERROR
|
||||
}msc_csw_status_t;
|
||||
|
||||
/// Command Block Wrapper
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint32_t signature ; ///< Signature that helps identify this data packet as a CBW. The signature field shall contain the value 43425355h (little endian), indicating a CBW.
|
||||
uint32_t tag ; ///< Tag sent by the host. The device shall echo the contents of this field back to the host in the dCSWTagfield of the associated CSW. The dCSWTagpositively associates a CSW with the corresponding CBW.
|
||||
uint32_t xfer_bytes ; ///< The number of bytes of data that the host expects to transfer on the Bulk-In or Bulk-Out endpoint (as indicated by the Direction bit) during the execution of this command. If this field is zero, the device and the host shall transfer no data between the CBW and the associated CSW, and the device shall ignore the value of the Direction bit in bmCBWFlags.
|
||||
uint8_t dir ; ///< Bit 7 of this field define transfer direction \n - 0 : Data-Out from host to the device. \n - 1 : Data-In from the device to the host.
|
||||
uint8_t lun ; ///< The device Logical Unit Number (LUN) to which the command block is being sent. For devices that support multiple LUNs, the host shall place into this field the LUN to which this command block is addressed. Otherwise, the host shall set this field to zero.
|
||||
uint8_t cmd_len ; ///< The valid length of the CBWCBin bytes. This defines the valid length of the command block. The only legal values are 1 through 16
|
||||
uint8_t command[16] ; ///< The command block to be executed by the device. The device shall interpret the first cmd_len bytes in this field as a command block
|
||||
}msc_cbw_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(msc_cbw_t) == 31, "size is not correct");
|
||||
|
||||
/// Command Status Wrapper
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint32_t signature ; ///< Signature that helps identify this data packet as a CSW. The signature field shall contain the value 53425355h (little endian), indicating CSW.
|
||||
uint32_t tag ; ///< The device shall set this field to the value received in the dCBWTag of the associated CBW.
|
||||
uint32_t data_residue ; ///< For Data-Out the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLength, and the actual amount of data processed by the device. For Data-In the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLengthand the actual amount of relevant data sent by the device
|
||||
uint8_t status ; ///< indicates the success or failure of the command. Values from \ref msc_csw_status_t
|
||||
}msc_csw_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(msc_csw_t) == 13, "size is not correct");
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SCSI Constant
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// SCSI Command Operation Code
|
||||
typedef enum
|
||||
{
|
||||
SCSI_CMD_TEST_UNIT_READY = 0x00, ///< The SCSI Test Unit Ready command is used to determine if a device is ready to transfer data (read/write), i.e. if a disk has spun up, if a tape is loaded and ready etc. The device does not perform a self-test operation.
|
||||
SCSI_CMD_INQUIRY = 0x12, ///< The SCSI Inquiry command is used to obtain basic information from a target device.
|
||||
SCSI_CMD_MODE_SELECT_6 = 0x15, ///< provides a means for the application client to specify medium, logical unit, or peripheral device parameters to the device server. Device servers that implement the MODE SELECT(6) command shall also implement the MODE SENSE(6) command. Application clients should issue MODE SENSE(6) prior to each MODE SELECT(6) to determine supported mode pages, page lengths, and other parameters.
|
||||
SCSI_CMD_MODE_SENSE_6 = 0x1A, ///< provides a means for a device server to report parameters to an application client. It is a complementary command to the MODE SELECT(6) command. Device servers that implement the MODE SENSE(6) command shall also implement the MODE SELECT(6) command.
|
||||
SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E,
|
||||
SCSI_CMD_READ_CAPACITY_10 = 0x25, ///< The SCSI Read Capacity command is used to obtain data capacity information from a target device.
|
||||
SCSI_CMD_REQUEST_SENSE = 0x03, ///< The SCSI Request Sense command is part of the SCSI computer protocol standard. This command is used to obtain sense data -- status/error information -- from a target device.
|
||||
SCSI_CMD_READ_FORMAT_CAPACITY = 0x23, ///< The command allows the Host to request a list of the possible format capacities for an installed writable media. This command also has the capability to report the writable capacity for a media when it is installed
|
||||
SCSI_CMD_READ_10 = 0x28, ///< The READ (10) command requests that the device server read the specified logical block(s) and transfer them to the data-in buffer.
|
||||
SCSI_CMD_WRITE_10 = 0x2A, ///< The WRITE (10) command requests thatthe device server transfer the specified logical block(s) from the data-out buffer and write them.
|
||||
}scsi_cmd_type_t;
|
||||
|
||||
/// SCSI Sense Key
|
||||
typedef enum
|
||||
{
|
||||
SCSI_SENSEKEY_NONE = 0x00, ///< no specific Sense Key. This would be the case for a successful command
|
||||
SCSI_SENSEKEY_RECOVERED_ERROR = 0x01, ///< ndicates the last command completed successfully with some recovery action performed by the disc drive.
|
||||
SCSI_SENSEKEY_NOT_READY = 0x02, ///< Indicates the logical unit addressed cannot be accessed.
|
||||
SCSI_SENSEKEY_MEDIUM_ERROR = 0x03, ///< Indicates the command terminated with a non-recovered error condition.
|
||||
SCSI_SENSEKEY_HARDWARE_ERROR = 0x04, ///< Indicates the disc drive detected a nonrecoverable hardware failure while performing the command or during a self test.
|
||||
SCSI_SENSEKEY_ILLEGLA_REQUEST = 0x05, ///< Indicates an illegal parameter in the command descriptor block or in the additional parameters
|
||||
SCSI_SENSEKEY_UNIT_ATTENTION = 0x06, ///< Indicates the disc drive may have been reset.
|
||||
SCSI_SENSEKEY_DATA_PROTECT = 0x07, ///< Indicates that a command that reads or writes the medium was attempted on a block that is protected from this operation. The read or write operation is not performed.
|
||||
SCSI_SENSEKEY_FIRMWARE_ERROR = 0x08, ///< Vendor specific sense key.
|
||||
SCSI_SENSEKEY_ABORTED_COMMAND = 0x0b, ///< Indicates the disc drive aborted the command.
|
||||
SCSI_SENSEKEY_EQUAL = 0x0c, ///< Indicates a SEARCH DATA command has satisfied an equal comparison.
|
||||
SCSI_SENSEKEY_VOLUME_OVERFLOW = 0x0d, ///< Indicates a buffered peripheral device has reached the end of medium partition and data remains in the buffer that has not been written to the medium.
|
||||
SCSI_SENSEKEY_MISCOMPARE = 0x0e ///< ndicates that the source data did not match the data read from the medium.
|
||||
}scsi_sense_key_type_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SCSI Primary Command (SPC-4)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// SCSI Test Unit Ready Command
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_TEST_UNIT_READY
|
||||
uint8_t lun ; ///< Logical Unit
|
||||
uint8_t reserved[3] ;
|
||||
uint8_t control ;
|
||||
} scsi_test_unit_ready_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(scsi_test_unit_ready_t) == 6, "size is not correct");
|
||||
|
||||
/// SCSI Inquiry Command
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_INQUIRY
|
||||
uint8_t reserved1 ;
|
||||
uint8_t page_code ;
|
||||
uint8_t reserved2 ;
|
||||
uint8_t alloc_length ; ///< specifies the maximum number of bytes that USB host has allocated in the Data-In Buffer. An allocation length of zero specifies that no data shall be transferred.
|
||||
uint8_t control ;
|
||||
} scsi_inquiry_t, scsi_request_sense_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(scsi_inquiry_t) == 6, "size is not correct");
|
||||
|
||||
/// SCSI Inquiry Response Data
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t peripheral_device_type : 5;
|
||||
uint8_t peripheral_qualifier : 3;
|
||||
|
||||
uint8_t : 7;
|
||||
uint8_t is_removable : 1;
|
||||
|
||||
uint8_t version;
|
||||
|
||||
uint8_t response_data_format : 4;
|
||||
uint8_t hierarchical_support : 1;
|
||||
uint8_t normal_aca : 1;
|
||||
uint8_t : 2;
|
||||
|
||||
uint8_t additional_length;
|
||||
|
||||
uint8_t protect : 1;
|
||||
uint8_t : 2;
|
||||
uint8_t third_party_copy : 1;
|
||||
uint8_t target_port_group_support : 2;
|
||||
uint8_t access_control_coordinator : 1;
|
||||
uint8_t scc_support : 1;
|
||||
|
||||
uint8_t addr16 : 1;
|
||||
uint8_t : 3;
|
||||
uint8_t multi_port : 1;
|
||||
uint8_t : 1; // vendor specific
|
||||
uint8_t enclosure_service : 1;
|
||||
uint8_t : 1;
|
||||
|
||||
uint8_t : 1; // vendor specific
|
||||
uint8_t cmd_que : 1;
|
||||
uint8_t : 2;
|
||||
uint8_t sync : 1;
|
||||
uint8_t wbus16 : 1;
|
||||
uint8_t : 2;
|
||||
|
||||
uint8_t vendor_id[8] ; ///< 8 bytes of ASCII data identifying the vendor of the product. The T10 vendor identification shall be one assigned by INCITS. A list of assigned T10 vendor identifications is in Annex E and on the T10 web site (http://www.t10.org).
|
||||
uint8_t product_id[16] ; ///< 16 bytes of ASCII data defined by the vendor.
|
||||
uint8_t product_revision[4] ; ///< 4 bytes of ASCII data defined by the vendor.
|
||||
} scsi_inquiry_data_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(scsi_inquiry_data_t) == 36, "size is not correct");
|
||||
|
||||
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t response_code : 7; ///< 70h - current errors, Fixed Format 71h - deferred errors, Fixed Format
|
||||
uint8_t valid : 1;
|
||||
|
||||
uint8_t reserved; ///< Obsolete
|
||||
|
||||
uint8_t sense_key : 4;
|
||||
uint8_t : 1;
|
||||
uint8_t incorrect_len_idicatior : 1;
|
||||
uint8_t end_of_medium : 1;
|
||||
uint8_t filemark : 1;
|
||||
|
||||
uint32_t information;
|
||||
uint8_t additional_sense_len;
|
||||
uint32_t command_specific_info;
|
||||
uint8_t additional_sense_code;
|
||||
uint8_t additional_sense_qualifier;
|
||||
uint8_t field_replaceable_unit_code;
|
||||
|
||||
uint8_t sense_key_specific[3]; ///< sense key specific valid bit is bit 7 of key[0], aka MSB in Big Endian layout
|
||||
|
||||
} scsi_sense_fixed_data_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(scsi_sense_fixed_data_t) == 18, "size is not correct");
|
||||
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_MODE_SENSE_6
|
||||
|
||||
uint8_t : 3;
|
||||
uint8_t disable_block_descriptor : 1;
|
||||
uint8_t : 0;
|
||||
|
||||
uint8_t page_code : 6;
|
||||
uint8_t page_control : 2;
|
||||
|
||||
uint8_t subpage_code;
|
||||
uint8_t alloc_length;
|
||||
uint8_t control;
|
||||
} scsi_mode_sense_6_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(scsi_mode_sense_6_t) == 6, "size is not correct");
|
||||
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t mode_data_length;
|
||||
uint8_t medium_type;
|
||||
uint8_t device_specific_para;
|
||||
uint8_t block_descriptor_length;
|
||||
} scsi_mode_parameters_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(scsi_mode_parameters_t) == 4, "size is not correct");
|
||||
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code; ///< SCSI OpCode for \ref SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
|
||||
uint8_t reserved[3];
|
||||
uint8_t prohibit_removal;
|
||||
uint8_t control;
|
||||
} scsi_prevent_allow_medium_removal_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(scsi_prevent_allow_medium_removal_t) == 6, "size is not correct");
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SCSI MMC
|
||||
//--------------------------------------------------------------------+
|
||||
/// SCSI Read Format Capacity: Write Capacity
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code;
|
||||
uint8_t reserved[6];
|
||||
uint16_t alloc_length;
|
||||
uint8_t control;
|
||||
} scsi_read_format_capacity_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(scsi_read_format_capacity_t) == 10, "size is not correct");
|
||||
|
||||
typedef struct ATTR_PACKED{
|
||||
uint8_t reserved[3];
|
||||
uint8_t list_length; /// must be 8*n, length in bytes of formattable capacity descriptor followed it.
|
||||
|
||||
uint32_t block_num; /// Number of Logical Blocks
|
||||
uint8_t descriptor_type; // 00: reserved, 01 unformatted media , 10 Formatted media, 11 No media present
|
||||
|
||||
uint8_t reserved2;
|
||||
uint16_t block_size_u16;
|
||||
|
||||
} scsi_read_format_capacity_data_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(scsi_read_format_capacity_data_t) == 12, "size is not correct");
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SCSI Block Command (SBC-3)
|
||||
// NOTE: All data in SCSI command are in Big Endian
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// SCSI Read Capacity 10 Command: Read Capacity
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code ; ///< SCSI OpCode for \ref SCSI_CMD_READ_CAPACITY_10
|
||||
uint8_t reserved1 ;
|
||||
uint32_t lba ; ///< The first Logical Block Address (LBA) accessed by this command
|
||||
uint16_t reserved2 ;
|
||||
uint8_t partial_medium_indicator ;
|
||||
uint8_t control ;
|
||||
} scsi_read_capacity10_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(scsi_read_capacity10_t) == 10, "size is not correct");
|
||||
|
||||
/// SCSI Read Capacity 10 Response Data
|
||||
typedef struct {
|
||||
uint32_t last_lba ; ///< The last Logical Block Address of the device
|
||||
uint32_t block_size ; ///< Block size in bytes
|
||||
} scsi_read_capacity10_data_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(scsi_read_capacity10_data_t) == 8, "size is not correct");
|
||||
|
||||
/// SCSI Read 10 Command
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code ; ///< SCSI OpCode
|
||||
uint8_t reserved ; // has LUN according to wiki
|
||||
uint32_t lba ; ///< The first Logical Block Address (LBA) accessed by this command
|
||||
uint8_t reserved2 ;
|
||||
uint16_t block_count ; ///< Number of Blocks used by this command
|
||||
uint8_t control ;
|
||||
} scsi_read10_t, scsi_write10_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(scsi_read10_t) == 10, "size is not correct");
|
||||
VERIFY_STATIC(sizeof(scsi_write10_t) == 10, "size is not correct");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MSC_H_ */
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
@@ -0,0 +1,396 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file msc_device.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_DEVICE_SUPPORTED && CFG_TUD_MSC)
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "msc_device.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
enum
|
||||
{
|
||||
MSC_STAGE_CMD = 0,
|
||||
MSC_STAGE_DATA,
|
||||
MSC_STAGE_STATUS
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
CFG_TUSB_MEM_ALIGN msc_cbw_t cbw;
|
||||
|
||||
#if defined (__ICCARM__) && (CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13UXX)
|
||||
uint8_t padding1[64-sizeof(msc_cbw_t)]; // IAR cannot align struct's member
|
||||
#endif
|
||||
|
||||
CFG_TUSB_MEM_ALIGN msc_csw_t csw;
|
||||
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
uint8_t stage;
|
||||
uint16_t data_len;
|
||||
uint16_t xferred_len; // numbered of bytes transferred so far in the Data Stage
|
||||
}mscd_interface_t;
|
||||
|
||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf;
|
||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_BUFSIZE];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
|
||||
static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
|
||||
|
||||
static inline uint32_t rdwr10_get_lba(uint8_t const command[])
|
||||
{
|
||||
// read10 & write10 has the same format
|
||||
scsi_write10_t* p_rdwr10 = (scsi_write10_t*) command;
|
||||
|
||||
// copy first to prevent mis-aligned access
|
||||
uint32_t lba;
|
||||
memcpy(&lba, &p_rdwr10->lba, 4);
|
||||
|
||||
return __be2n(lba);
|
||||
}
|
||||
|
||||
static inline uint16_t rdwr10_get_blockcount(uint8_t const command[])
|
||||
{
|
||||
// read10 & write10 has the same format
|
||||
scsi_write10_t* p_rdwr10 = (scsi_write10_t*) command;
|
||||
|
||||
// copy first to prevent mis-aligned access
|
||||
uint16_t block_count;
|
||||
memcpy(&block_count, &p_rdwr10->block_count, 2);
|
||||
|
||||
return __be2n(block_count);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-CLASS API
|
||||
//--------------------------------------------------------------------+
|
||||
void mscd_init(void)
|
||||
{
|
||||
memclr_(&_mscd_itf, sizeof(mscd_interface_t));
|
||||
}
|
||||
|
||||
void mscd_close(uint8_t rhport)
|
||||
{
|
||||
memclr_(&_mscd_itf, sizeof(mscd_interface_t));
|
||||
}
|
||||
|
||||
tusb_error_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf, uint16_t *p_len)
|
||||
{
|
||||
// only support SCSI's BOT protocol
|
||||
VERIFY( ( MSC_SUBCLASS_SCSI == p_desc_itf->bInterfaceSubClass &&
|
||||
MSC_PROTOCOL_BOT == p_desc_itf->bInterfaceProtocol ), TUSB_ERROR_MSC_UNSUPPORTED_PROTOCOL );
|
||||
|
||||
mscd_interface_t * p_msc = &_mscd_itf;
|
||||
|
||||
// Open endpoint pair with usbd helper
|
||||
tusb_desc_endpoint_t const *p_desc_ep = (tusb_desc_endpoint_t const *) descriptor_next( (uint8_t const*) p_desc_itf );
|
||||
TU_ASSERT_ERR( usbd_open_edpt_pair(rhport, p_desc_ep, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in) );
|
||||
|
||||
p_msc->itf_num = p_desc_itf->bInterfaceNumber;
|
||||
(*p_len) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
//------------- Queue Endpoint OUT for Command Block Wrapper -------------//
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)), TUSB_ERROR_DCD_EDPT_XFER );
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t mscd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
TU_ASSERT(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS, TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT);
|
||||
|
||||
if(MSC_REQUEST_RESET == p_request->bRequest)
|
||||
{
|
||||
dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
|
||||
}
|
||||
else if (MSC_REQUEST_GET_MAX_LUN == p_request->bRequest)
|
||||
{
|
||||
// returned MAX LUN is minus 1 by specs
|
||||
_mscd_buf[0] = CFG_TUD_MSC_MAXLUN-1;
|
||||
usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, _mscd_buf, 1);
|
||||
}else
|
||||
{
|
||||
dcd_control_stall(rhport); // stall unsupported request
|
||||
}
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
mscd_interface_t* p_msc = &_mscd_itf;
|
||||
msc_cbw_t const * p_cbw = &p_msc->cbw;
|
||||
msc_csw_t * p_csw = &p_msc->csw;
|
||||
|
||||
VERIFY( (ep_addr == p_msc->ep_out) || (ep_addr == p_msc->ep_in), TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
switch (p_msc->stage)
|
||||
{
|
||||
case MSC_STAGE_CMD:
|
||||
//------------- new CBW received -------------//
|
||||
|
||||
// Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it
|
||||
if(ep_addr != p_msc->ep_out) return TUSB_ERROR_NONE;
|
||||
|
||||
TU_ASSERT( event == TUSB_EVENT_XFER_COMPLETE &&
|
||||
xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE, TUSB_ERROR_INVALID_PARA );
|
||||
|
||||
p_csw->signature = MSC_CSW_SIGNATURE;
|
||||
p_csw->tag = p_cbw->tag;
|
||||
p_csw->data_residue = 0;
|
||||
|
||||
/*------------- Parse command and prepare DATA -------------*/
|
||||
p_msc->stage = MSC_STAGE_DATA;
|
||||
p_msc->data_len = p_cbw->xfer_bytes;
|
||||
p_msc->xferred_len = 0;
|
||||
|
||||
if (SCSI_CMD_READ_10 == p_cbw->command[0])
|
||||
{
|
||||
proc_read10_cmd(rhport, p_msc);
|
||||
}
|
||||
else if (SCSI_CMD_WRITE_10 == p_cbw->command[0])
|
||||
{
|
||||
proc_write10_cmd(rhport, p_msc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For other SCSI commands
|
||||
// 1. Zero : Invoke app callback, skip DATA and move to STATUS stage
|
||||
// 2. OUT : queue transfer (invoke app callback after done)
|
||||
// 3. IN : invoke app callback to get response
|
||||
|
||||
if ( p_cbw->xfer_bytes == 0)
|
||||
{
|
||||
p_msc->data_len = tud_msc_scsi_cb(rhport, p_cbw->lun, p_cbw->command, NULL, 0);
|
||||
p_csw->status = (p_msc->data_len == 0) ? MSC_CSW_STATUS_PASSED : MSC_CSW_STATUS_FAILED;
|
||||
p_msc->stage = MSC_STAGE_STATUS;
|
||||
|
||||
TU_ASSERT( p_msc->data_len == 0, TUSB_ERROR_INVALID_PARA);
|
||||
}
|
||||
else if ( !BIT_TEST_(p_cbw->dir, 7) )
|
||||
{
|
||||
// OUT transfer
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, p_msc->data_len), TUSB_ERROR_DCD_EDPT_XFER );
|
||||
}
|
||||
else
|
||||
{
|
||||
p_msc->data_len = tud_msc_scsi_cb(rhport, p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->data_len);
|
||||
p_csw->status = (p_msc->data_len >= 0) ? MSC_CSW_STATUS_PASSED : MSC_CSW_STATUS_FAILED;
|
||||
|
||||
TU_ASSERT( p_cbw->xfer_bytes >= p_msc->data_len, TUSB_ERROR_INVALID_PARA ); // cannot return more than host expect
|
||||
|
||||
if ( p_msc->data_len )
|
||||
{
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->data_len), TUSB_ERROR_DCD_EDPT_XFER );
|
||||
}else
|
||||
{
|
||||
// application does not provide data to response --> possibly unsupported SCSI command
|
||||
dcd_edpt_stall(rhport, p_msc->ep_in);
|
||||
|
||||
p_csw->status = MSC_CSW_STATUS_FAILED;
|
||||
p_msc->stage = MSC_STAGE_STATUS;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MSC_STAGE_DATA:
|
||||
// OUT transfer, invoke callback if needed
|
||||
if ( !BIT_TEST_(p_cbw->dir, 7) )
|
||||
{
|
||||
if ( SCSI_CMD_WRITE_10 != p_cbw->command[0] )
|
||||
{
|
||||
p_csw->status = (tud_msc_scsi_cb(rhport, p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->data_len) >= 0 ) ? MSC_CSW_STATUS_PASSED : MSC_CSW_STATUS_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t lba = rdwr10_get_lba(p_cbw->command);
|
||||
|
||||
// Application can consume smaller bytes
|
||||
int32_t nbytes = tud_msc_write10_cb(rhport, p_cbw->lun, lba, p_msc->xferred_len, _mscd_buf, xferred_bytes);
|
||||
|
||||
if ( nbytes < 0 )
|
||||
{
|
||||
// negative means error -> skip to status phase, status in CSW set to failed
|
||||
p_csw->data_residue = p_cbw->xfer_bytes - p_msc->xferred_len;
|
||||
p_csw->status = MSC_CSW_STATUS_FAILED;
|
||||
|
||||
p_msc->stage = MSC_STAGE_STATUS;
|
||||
break;
|
||||
}else
|
||||
{
|
||||
// Application consume less than what we got (including zero)
|
||||
if ( nbytes < xferred_bytes )
|
||||
{
|
||||
if ( nbytes > 0 )
|
||||
{
|
||||
p_msc->xferred_len += nbytes;
|
||||
memmove(_mscd_buf, _mscd_buf+nbytes, xferred_bytes-nbytes);
|
||||
}
|
||||
|
||||
// simulate an transfer complete with adjusted params
|
||||
dcd_xfer_complete(rhport, p_msc->ep_out, xferred_bytes-nbytes, true);
|
||||
|
||||
return TUSB_ERROR_NONE; // skip the rest
|
||||
}
|
||||
else
|
||||
{
|
||||
// Application consume all bytes in our buffer
|
||||
// Nothing to do, process with normal flow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulate data so far
|
||||
p_msc->xferred_len += xferred_bytes;
|
||||
|
||||
if ( p_msc->xferred_len >= p_msc->data_len )
|
||||
{
|
||||
// Data Stage is complete
|
||||
p_msc->stage = MSC_STAGE_STATUS;
|
||||
}
|
||||
else
|
||||
{
|
||||
// READ10 & WRITE10 Can be executed with large bulk of data e.g write 8K bytes (several flash write)
|
||||
// We break it into multiple smaller command whose data size is up to CFG_TUD_MSC_BUFSIZE
|
||||
if (SCSI_CMD_READ_10 == p_cbw->command[0])
|
||||
{
|
||||
proc_read10_cmd(rhport, p_msc);
|
||||
}
|
||||
else if (SCSI_CMD_WRITE_10 == p_cbw->command[0])
|
||||
{
|
||||
proc_write10_cmd(rhport, p_msc);
|
||||
}else
|
||||
{
|
||||
// No other command take more than one transfer yet -> unlikely error
|
||||
verify_breakpoint();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MSC_STAGE_STATUS: break; // processed immediately after this switch
|
||||
default : break;
|
||||
}
|
||||
|
||||
if ( p_msc->stage == MSC_STAGE_STATUS )
|
||||
{
|
||||
// Invoke Complete Callback if defined
|
||||
if ( SCSI_CMD_READ_10 == p_cbw->command[0])
|
||||
{
|
||||
if ( tud_msc_read10_complete_cb ) tud_msc_read10_complete_cb(rhport, p_cbw->lun);
|
||||
}else if ( SCSI_CMD_WRITE_10 == p_cbw->command[0] )
|
||||
{
|
||||
if ( tud_msc_write10_complete_cb ) tud_msc_write10_complete_cb(rhport, p_cbw->lun);
|
||||
}else
|
||||
{
|
||||
if ( tud_msc_scsi_complete_cb ) tud_msc_scsi_complete_cb(rhport, p_cbw->lun, p_cbw->command);
|
||||
}
|
||||
|
||||
// Move to default CMD stage after sending status
|
||||
p_msc->stage = MSC_STAGE_CMD;
|
||||
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)) );
|
||||
|
||||
//------------- Queue the next CBW -------------//
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)) );
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
|
||||
{
|
||||
msc_cbw_t const * p_cbw = &p_msc->cbw;
|
||||
msc_csw_t * p_csw = &p_msc->csw;
|
||||
|
||||
uint32_t lba = rdwr10_get_lba(p_cbw->command);
|
||||
|
||||
// remaining bytes capped at class buffer
|
||||
int32_t nbytes = (int32_t) min32_of(sizeof(_mscd_buf), p_cbw->xfer_bytes-p_msc->xferred_len);
|
||||
|
||||
// Application can consume smaller bytes
|
||||
nbytes = tud_msc_read10_cb (rhport, p_cbw->lun, lba, p_msc->xferred_len, _mscd_buf, (uint32_t) nbytes);
|
||||
|
||||
if ( nbytes < 0 )
|
||||
{
|
||||
// negative means error -> pipe is stalled & status in CSW set to failed
|
||||
p_csw->data_residue = p_cbw->xfer_bytes - p_msc->xferred_len;
|
||||
p_csw->status = MSC_CSW_STATUS_FAILED;
|
||||
|
||||
dcd_edpt_stall(rhport, p_msc->ep_in);
|
||||
}
|
||||
else if ( nbytes == 0 )
|
||||
{
|
||||
// zero means not ready -> try again later by simulate an transfer complete
|
||||
dcd_xfer_complete(rhport, p_msc->ep_in, 0, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, nbytes), );
|
||||
}
|
||||
}
|
||||
|
||||
static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
|
||||
{
|
||||
msc_cbw_t const * p_cbw = &p_msc->cbw;
|
||||
|
||||
// remaining bytes capped at class buffer
|
||||
int32_t nbytes = (int32_t) min32_of(sizeof(_mscd_buf), p_cbw->xfer_bytes-p_msc->xferred_len);
|
||||
|
||||
// Write10 callback will be called later when usb transfer complete
|
||||
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,158 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file msc_device.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_MSC_DEVICE_H_
|
||||
#define _TUSB_MSC_DEVICE_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "device/usbd.h"
|
||||
#include "msc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \addtogroup ClassDriver_MSC
|
||||
* @{
|
||||
* \defgroup MSC_Device Device
|
||||
* @{ */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API (Multiple Root Hub Ports)
|
||||
// Should be used only with MCU that support more than 1 ports
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION CALLBACK API (WEAK is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
/** \brief Callback invoked when received \ref SCSI_CMD_READ_10 command
|
||||
* \param[in] \rhport Root hub port
|
||||
* \param[in] lun Targeted Logical Unit
|
||||
* Must be accessible by USB controller (see \ref CFG_TUSB_ATTR_USBRAM)
|
||||
* \param[in] lba Starting Logical Block Address to be read
|
||||
* \param[in] offset Byte offset from LBA for reading
|
||||
* \param[out] buffer Buffer which application need to update with the response data.
|
||||
* \param[in] bufsize Max bytes can be copied. Application must not return more than this value.
|
||||
*
|
||||
* \retval positive Actual bytes returned, must not be more than \a \b bufsize.
|
||||
* If value less than bufsize is returned, Tinyusb will transfer this amount and afterwards
|
||||
* invoke this callback again with adjusted offset.
|
||||
*
|
||||
* \retval zero Indicate application is not ready yet to response e.g disk I/O is not complete.
|
||||
* Tinyusb will invoke this callback with the same params again some time later.
|
||||
*
|
||||
* \retval negative Indicate error reading disk I/O. Tinyusb will \b STALL the corresponding
|
||||
* endpoint and return failed status in command status wrapper phase.
|
||||
*
|
||||
* \note Host can request dozens of Kbytes in one command e.g \a \b block_count = 128, it is insufficient to require
|
||||
* application to have that much of buffer. Instead, application can return the number of blocks it can processed,
|
||||
* the stack after transferred that amount of data will continue to invoke this callback with adjusted \a \b lba and \a \b block_count.
|
||||
* \n\n Although this callback is called by tinyusb device task (non-isr context), however as all the classes share
|
||||
* the same task (to save resource), any delay in this callback will cause delay in response on other classes.
|
||||
*/
|
||||
int32_t tud_msc_read10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
|
||||
|
||||
/** \brief Callback invoked when received \ref SCSI_CMD_WRITE_10 command
|
||||
* \param[in] rhport Root hub port
|
||||
* \param[in] lun Targeted Logical Unit
|
||||
* Must be accessible by USB controller (see \ref CFG_TUSB_ATTR_USBRAM)
|
||||
* \param[in] lba Starting Logical Block Address to be write
|
||||
* \param[out] buffer Buffer which holds written data.
|
||||
* \param[in] bufsize Max bytes in buffer. Application must not return more than this value.
|
||||
*
|
||||
* \retval positive Actual bytes written, must not be more than \a \b bufsize.
|
||||
* If value less than bufsize is returned, Tinyusb will trim off this amount and
|
||||
* invoke this callback again with adjusted offset some time later.
|
||||
*
|
||||
* \retval zero Indicate application is not ready yet e.g disk I/O is not complete.
|
||||
* Tinyusb will invoke this callback with the same params again some time later.
|
||||
*
|
||||
* \retval negative Indicate error writing disk I/O. Tinyusb will \b STALL the corresponding
|
||||
* endpoint and return failed status in command status wrapper phase.
|
||||
*
|
||||
* \note Host can request dozens of Kbytes in one command e.g \a \b block_count = 128, it is insufficient to require
|
||||
* application to have that much of buffer. Instead, application can return the number of blocks it can processed,
|
||||
* the stack after transferred that amount of data will continue to invoke this callback with adjusted \a \b lba and \a \b block_count.
|
||||
* \n\n Although this callback is called by tinyusb device task (non-isr context), however as all the classes share
|
||||
* the same task (to save resource), any delay in this callback will cause delay in response on other classes.
|
||||
*/
|
||||
int32_t tud_msc_write10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
|
||||
|
||||
|
||||
/** \brief Callback invoked when received an SCSI command other than \ref SCSI_CMD_WRITE_10 and \ref SCSI_CMD_READ_10
|
||||
* \param[in] rhport Root hub port
|
||||
* \param[in] lun Targeted Logical Unit
|
||||
* \param[in] scsi_cmd SCSI command contents, application should examine this command block to know which command host requested
|
||||
* \param[out] buffer Buffer for SCSI Data Stage.
|
||||
* - For INPUT: application must fill this with response.
|
||||
* - For OUTPUT it holds the Data from host
|
||||
* \param[in] bufsize Buffer's length.
|
||||
*
|
||||
* \retval negative Indicate error e.g accessing disk I/O. Tinyusb will \b STALL the corresponding
|
||||
* endpoint and return failed status in command status wrapper phase.
|
||||
* \retval otherwise Actual bytes processed, must not be more than \a \b bufsize. Can be zero for no-data command.
|
||||
*/
|
||||
int32_t tud_msc_scsi_cb (uint8_t rhport, uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize);
|
||||
|
||||
/*------------- Optional callbacks : Could be used by application to free up resources -------------*/
|
||||
ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t rhport, uint8_t lun);
|
||||
ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t rhport, uint8_t lun);
|
||||
ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t rhport, uint8_t lun, uint8_t const scsi_cmd[16]);
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef _TINY_USB_SOURCE_FILE_
|
||||
|
||||
void mscd_init(void);
|
||||
tusb_error_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
|
||||
tusb_error_t mscd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void mscd_close(uint8_t rhport);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MSC_DEVICE_H_ */
|
||||
|
||||
@@ -0,0 +1,430 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file msc_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 & CFG_TUSB_HOST_MSC
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "msc_host.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_ATTR_USBRAM STATIC_VAR msch_interface_t msch_data[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
|
||||
//------------- Initalization Data -------------//
|
||||
static osal_semaphore_t msch_sem_hdl;
|
||||
|
||||
// buffer used to read scsi information when mounted, largest response data currently is inquiry
|
||||
CFG_TUSB_ATTR_USBRAM ATTR_ALIGNED(4) STATIC_VAR uint8_t msch_buffer[sizeof(scsi_inquiry_data_t)];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PUBLIC API
|
||||
//--------------------------------------------------------------------+
|
||||
bool tuh_msc_is_mounted(uint8_t dev_addr)
|
||||
{
|
||||
return tuh_device_is_configured(dev_addr) && // is configured can be omitted
|
||||
msch_data[dev_addr-1].is_initialized;
|
||||
}
|
||||
|
||||
bool tuh_msc_is_busy(uint8_t dev_addr)
|
||||
{
|
||||
return msch_data[dev_addr-1].is_initialized &&
|
||||
hcd_pipe_is_busy(msch_data[dev_addr-1].bulk_in);
|
||||
}
|
||||
|
||||
uint8_t const* tuh_msc_get_vendor_name(uint8_t dev_addr)
|
||||
{
|
||||
return msch_data[dev_addr-1].is_initialized ? msch_data[dev_addr-1].vendor_id : NULL;
|
||||
}
|
||||
|
||||
uint8_t const* tuh_msc_get_product_name(uint8_t dev_addr)
|
||||
{
|
||||
return msch_data[dev_addr-1].is_initialized ? msch_data[dev_addr-1].product_id : NULL;
|
||||
}
|
||||
|
||||
tusb_error_t tuh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size)
|
||||
{
|
||||
if ( !msch_data[dev_addr-1].is_initialized ) return TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED;
|
||||
TU_ASSERT(p_last_lba != NULL && p_block_size != NULL, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
(*p_last_lba) = msch_data[dev_addr-1].last_lba;
|
||||
(*p_block_size) = (uint32_t) msch_data[dev_addr-1].block_size;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PUBLIC API: SCSI COMMAND
|
||||
//--------------------------------------------------------------------+
|
||||
static inline void msc_cbw_add_signature(msc_cbw_t *p_cbw, uint8_t lun)
|
||||
{
|
||||
p_cbw->signature = MSC_CBW_SIGNATURE;
|
||||
p_cbw->tag = 0xCAFECAFE;
|
||||
p_cbw->lun = lun;
|
||||
}
|
||||
|
||||
static tusb_error_t msch_command_xfer(msch_interface_t * p_msch, void* p_buffer) ATTR_WARN_UNUSED_RESULT;
|
||||
static tusb_error_t msch_command_xfer(msch_interface_t * p_msch, void* p_buffer)
|
||||
{
|
||||
if ( NULL != p_buffer)
|
||||
{ // there is data phase
|
||||
if (p_msch->cbw.dir & TUSB_DIR_IN_MASK)
|
||||
{
|
||||
TU_ASSERT_ERR( hcd_pipe_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t), false) );
|
||||
TU_ASSERT_ERR( hcd_pipe_queue_xfer(p_msch->bulk_in , p_buffer, p_msch->cbw.xfer_bytes) );
|
||||
}else
|
||||
{
|
||||
TU_ASSERT_ERR( hcd_pipe_queue_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t)) );
|
||||
TU_ASSERT_ERR( hcd_pipe_xfer(p_msch->bulk_out , p_buffer, p_msch->cbw.xfer_bytes, false) );
|
||||
}
|
||||
}
|
||||
|
||||
TU_ASSERT_ERR( hcd_pipe_xfer(p_msch->bulk_in , (uint8_t*) &p_msch->csw, sizeof(msc_csw_t), true) );
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, uint8_t lun, uint8_t *p_data)
|
||||
{
|
||||
msch_interface_t* p_msch = &msch_data[dev_addr-1];
|
||||
|
||||
//------------- Command Block Wrapper -------------//
|
||||
msc_cbw_add_signature(&p_msch->cbw, lun);
|
||||
p_msch->cbw.xfer_bytes = sizeof(scsi_inquiry_data_t);
|
||||
p_msch->cbw.dir = TUSB_DIR_IN_MASK;
|
||||
p_msch->cbw.cmd_len = sizeof(scsi_inquiry_t);
|
||||
|
||||
//------------- SCSI command -------------//
|
||||
scsi_inquiry_t cmd_inquiry =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_INQUIRY,
|
||||
.alloc_length = sizeof(scsi_inquiry_data_t)
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_inquiry, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(p_msch, p_data) );
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t tusbh_msc_read_capacity10(uint8_t dev_addr, uint8_t lun, uint8_t *p_data)
|
||||
{
|
||||
msch_interface_t* p_msch = &msch_data[dev_addr-1];
|
||||
|
||||
//------------- Command Block Wrapper -------------//
|
||||
msc_cbw_add_signature(&p_msch->cbw, lun);
|
||||
p_msch->cbw.xfer_bytes = sizeof(scsi_read_capacity10_data_t);
|
||||
p_msch->cbw.dir = TUSB_DIR_IN_MASK;
|
||||
p_msch->cbw.cmd_len = sizeof(scsi_read_capacity10_t);
|
||||
|
||||
//------------- SCSI command -------------//
|
||||
scsi_read_capacity10_t cmd_read_capacity10 =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_READ_CAPACITY_10,
|
||||
.lba = 0,
|
||||
.partial_medium_indicator = 0
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_read_capacity10, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(p_msch, p_data) );
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, uint8_t *p_data)
|
||||
{
|
||||
(void) lun; // TODO [MSCH] multiple lun support
|
||||
|
||||
msch_interface_t* p_msch = &msch_data[dev_addr-1];
|
||||
|
||||
//------------- Command Block Wrapper -------------//
|
||||
p_msch->cbw.xfer_bytes = 18;
|
||||
p_msch->cbw.dir = TUSB_DIR_IN_MASK;
|
||||
p_msch->cbw.cmd_len = sizeof(scsi_request_sense_t);
|
||||
|
||||
//------------- SCSI command -------------//
|
||||
scsi_request_sense_t cmd_request_sense =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_REQUEST_SENSE,
|
||||
.alloc_length = 18
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_request_sense, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(p_msch, p_data) );
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, msc_csw_t * p_csw)
|
||||
{
|
||||
msch_interface_t* p_msch = &msch_data[dev_addr-1];
|
||||
|
||||
//------------- Command Block Wrapper -------------//
|
||||
msc_cbw_add_signature(&p_msch->cbw, lun);
|
||||
|
||||
p_msch->cbw.xfer_bytes = 0; // Number of bytes
|
||||
p_msch->cbw.dir = TUSB_DIR_OUT;
|
||||
p_msch->cbw.cmd_len = sizeof(scsi_test_unit_ready_t);
|
||||
|
||||
//------------- SCSI command -------------//
|
||||
scsi_test_unit_ready_t cmd_test_unit_ready =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_TEST_UNIT_READY,
|
||||
.lun = lun // according to wiki
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_test_unit_ready, p_msch->cbw.cmd_len);
|
||||
|
||||
// TODO MSCH refractor test uinit ready
|
||||
TU_ASSERT_ERR( hcd_pipe_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t), false) );
|
||||
TU_ASSERT_ERR( hcd_pipe_xfer(p_msch->bulk_in , (uint8_t*) p_csw, sizeof(msc_csw_t), true) );
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * p_buffer, uint32_t lba, uint16_t block_count)
|
||||
{
|
||||
msch_interface_t* p_msch = &msch_data[dev_addr-1];
|
||||
|
||||
//------------- Command Block Wrapper -------------//
|
||||
msc_cbw_add_signature(&p_msch->cbw, lun);
|
||||
|
||||
p_msch->cbw.xfer_bytes = p_msch->block_size*block_count; // Number of bytes
|
||||
p_msch->cbw.dir = TUSB_DIR_IN_MASK;
|
||||
p_msch->cbw.cmd_len = sizeof(scsi_read10_t);
|
||||
|
||||
//------------- SCSI command -------------//
|
||||
scsi_read10_t cmd_read10 =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_READ_10,
|
||||
.lba = __n2be(lba),
|
||||
.block_count = u16_le2be(block_count)
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_read10, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(p_msch, p_buffer));
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffer, uint32_t lba, uint16_t block_count)
|
||||
{
|
||||
msch_interface_t* p_msch = &msch_data[dev_addr-1];
|
||||
|
||||
//------------- Command Block Wrapper -------------//
|
||||
msc_cbw_add_signature(&p_msch->cbw, lun);
|
||||
|
||||
p_msch->cbw.xfer_bytes = p_msch->block_size*block_count; // Number of bytes
|
||||
p_msch->cbw.dir = TUSB_DIR_OUT;
|
||||
p_msch->cbw.cmd_len = sizeof(scsi_write10_t);
|
||||
|
||||
//------------- SCSI command -------------//
|
||||
scsi_write10_t cmd_write10 =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_WRITE_10,
|
||||
.lba = __n2be(lba),
|
||||
.block_count = u16_le2be(block_count)
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_write10, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(p_msch, (void*) p_buffer));
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CLASS-USBH API (don't require to verify parameters)
|
||||
//--------------------------------------------------------------------+
|
||||
void msch_init(void)
|
||||
{
|
||||
memclr_(msch_data, sizeof(msch_interface_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
msch_sem_hdl = osal_semaphore_create(1, 0);
|
||||
}
|
||||
|
||||
tusb_error_t msch_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length)
|
||||
{
|
||||
tusb_error_t error;
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
if (! ( MSC_SUBCLASS_SCSI == p_interface_desc->bInterfaceSubClass &&
|
||||
MSC_PROTOCOL_BOT == p_interface_desc->bInterfaceProtocol ) )
|
||||
{
|
||||
return TUSB_ERROR_MSC_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
|
||||
//------------- Open Data Pipe -------------//
|
||||
tusb_desc_endpoint_t const *p_endpoint;
|
||||
p_endpoint = (tusb_desc_endpoint_t const *) descriptor_next( (uint8_t const*) p_interface_desc );
|
||||
|
||||
for(uint32_t i=0; i<2; i++)
|
||||
{
|
||||
STASK_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType);
|
||||
STASK_ASSERT(TUSB_XFER_BULK == p_endpoint->bmAttributes.xfer);
|
||||
|
||||
pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_IN_MASK ) ?
|
||||
&msch_data[dev_addr-1].bulk_in : &msch_data[dev_addr-1].bulk_out;
|
||||
|
||||
(*p_pipe_hdl) = hcd_pipe_open(dev_addr, p_endpoint, TUSB_CLASS_MSC);
|
||||
STASK_ASSERT( pipehandle_is_valid(*p_pipe_hdl) );
|
||||
|
||||
p_endpoint = (tusb_desc_endpoint_t const *) descriptor_next( (uint8_t const*) p_endpoint );
|
||||
}
|
||||
|
||||
msch_data[dev_addr-1].interface_number = p_interface_desc->bInterfaceNumber;
|
||||
(*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
|
||||
//------------- Get Max Lun -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE),
|
||||
MSC_REQUEST_GET_MAX_LUN, 0, msch_data[dev_addr-1].interface_number,
|
||||
1, msch_buffer ),
|
||||
error
|
||||
);
|
||||
|
||||
STASK_ASSERT( TUSB_ERROR_NONE == error /* && TODO STALL means zero */);
|
||||
msch_data[dev_addr-1].max_lun = msch_buffer[0];
|
||||
|
||||
#if 0
|
||||
//------------- Reset -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE),
|
||||
MSC_REQUEST_RESET, 0, msch_data[dev_addr-1].interface_number,
|
||||
0, NULL ),
|
||||
error
|
||||
);
|
||||
#endif
|
||||
|
||||
enum { SCSI_XFER_TIMEOUT = 2000 };
|
||||
//------------- SCSI Inquiry -------------//
|
||||
tusbh_msc_inquiry(dev_addr, 0, msch_buffer);
|
||||
osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
memcpy(msch_data[dev_addr-1].vendor_id , ((scsi_inquiry_data_t*) msch_buffer)->vendor_id , 8);
|
||||
memcpy(msch_data[dev_addr-1].product_id, ((scsi_inquiry_data_t*) msch_buffer)->product_id, 16);
|
||||
|
||||
//------------- SCSI Read Capacity 10 -------------//
|
||||
tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer);
|
||||
osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
// NOTE: my toshiba thumb-drive stall the first Read Capacity and require the sequence
|
||||
// Read Capacity --> Stalled --> Clear Stall --> Request Sense --> Read Capacity (2) to work
|
||||
if ( hcd_pipe_is_stalled(msch_data[dev_addr-1].bulk_in) )
|
||||
{ // clear stall TODO abstract clear stall function
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_STANDARD, TUSB_REQ_RCPT_ENDPOINT),
|
||||
TUSB_REQ_CLEAR_FEATURE, 0, hcd_pipe_get_endpoint_addr(msch_data[dev_addr-1].bulk_in),
|
||||
0, NULL ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
hcd_pipe_clear_stall(msch_data[dev_addr-1].bulk_in);
|
||||
osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error); // wait for SCSI status
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
//------------- SCSI Request Sense -------------//
|
||||
(void) tuh_msc_request_sense(dev_addr, 0, msch_buffer);
|
||||
osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
//------------- Re-read SCSI Read Capactity -------------//
|
||||
tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer);
|
||||
osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
|
||||
STASK_ASSERT_ERR(error);
|
||||
}
|
||||
|
||||
msch_data[dev_addr-1].last_lba = __be2n( ((scsi_read_capacity10_data_t*)msch_buffer)->last_lba );
|
||||
msch_data[dev_addr-1].block_size = (uint16_t) __be2n( ((scsi_read_capacity10_data_t*)msch_buffer)->block_size );
|
||||
|
||||
msch_data[dev_addr-1].is_initialized = true;
|
||||
tuh_msc_mounted_cb(dev_addr);
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
void msch_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
if ( pipehandle_is_equal(pipe_hdl, msch_data[pipe_hdl.dev_addr-1].bulk_in) )
|
||||
{
|
||||
if (msch_data[pipe_hdl.dev_addr-1].is_initialized)
|
||||
{
|
||||
tuh_msc_isr(pipe_hdl.dev_addr, event, xferred_bytes);
|
||||
}else
|
||||
{ // still initializing under open subtask
|
||||
osal_semaphore_post(msch_sem_hdl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void msch_close(uint8_t dev_addr)
|
||||
{
|
||||
(void) hcd_pipe_close(msch_data[dev_addr-1].bulk_in);
|
||||
(void) hcd_pipe_close(msch_data[dev_addr-1].bulk_out);
|
||||
|
||||
memclr_(&msch_data[dev_addr-1], sizeof(msch_interface_t));
|
||||
osal_semaphore_reset(msch_sem_hdl);
|
||||
|
||||
tuh_msc_unmounted_cb(dev_addr); // invoke Application Callback
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL & HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,219 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file msc_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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef _TUSB_MSC_HOST_H_
|
||||
#define _TUSB_MSC_HOST_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "host/usbh.h"
|
||||
#include "msc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \addtogroup ClassDriver_MSC
|
||||
* @{
|
||||
* \defgroup MSC_Host Host
|
||||
* The interface API includes status checking function, data transferring function and callback functions
|
||||
* @{ */
|
||||
//--------------------------------------------------------------------+
|
||||
// MASS STORAGE Application API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \brief Check if device supports MassStorage interface or not
|
||||
* \param[in] dev_addr device address
|
||||
* \retval true if device supports
|
||||
* \retval false if device does not support or is not mounted
|
||||
*/
|
||||
bool tuh_msc_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 used to check if previous transfer is complete (success or error), so that the next transfer
|
||||
* can be scheduled. User needs to make sure the corresponding interface is mounted (by \ref tuh_msc_is_mounted)
|
||||
* before calling this function
|
||||
*/
|
||||
bool tuh_msc_is_busy(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/** \brief Get SCSI vendor's name of MassStorage device
|
||||
* \param[in] dev_addr device address
|
||||
* \return pointer to vendor's name or NULL if specified device does not support MassStorage
|
||||
* \note SCSI vendor's name is 8-byte length field in \ref scsi_inquiry_data_t. During enumeration, the stack has already
|
||||
* retrieved (via SCSI INQUIRY) and store this information internally. There is no need for application to re-send SCSI INQUIRY
|
||||
* command or allocate buffer for this.
|
||||
*/
|
||||
uint8_t const* tuh_msc_get_vendor_name(uint8_t dev_addr);
|
||||
|
||||
/** \brief Get SCSI product's name of MassStorage device
|
||||
* \param[in] dev_addr device address
|
||||
* \return pointer to product's name or NULL if specified device does not support MassStorage
|
||||
* \note SCSI product's name is 16-byte length field in \ref scsi_inquiry_data_t. During enumeration, the stack has already
|
||||
* retrieved (via SCSI INQUIRY) and store this information internally. There is no need for application to re-send SCSI INQUIRY
|
||||
* command or allocate buffer for this.
|
||||
*/
|
||||
uint8_t const* tuh_msc_get_product_name(uint8_t dev_addr);
|
||||
|
||||
/** \brief Get SCSI Capacity of MassStorage device
|
||||
* \param[in] dev_addr device address
|
||||
* \param[out] p_last_lba Last Logical Block Address of device
|
||||
* \param[out] p_block_size Block Size of device in bytes
|
||||
* \retval pointer to product's name or NULL if specified device does not support MassStorage
|
||||
* \note MassStorage's capacity can be computed by last LBA x block size (in bytes). During enumeration, the stack has already
|
||||
* retrieved (via SCSI READ CAPACITY 10) and store this information internally. There is no need for application
|
||||
* to re-send SCSI READ CAPACITY 10 command
|
||||
*/
|
||||
tusb_error_t tuh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size);
|
||||
|
||||
/** \brief Perform SCSI READ 10 command to read data from MassStorage device
|
||||
* \param[in] dev_addr device address
|
||||
* \param[in] lun Targeted Logical Unit
|
||||
* \param[out] p_buffer Buffer used to store data read from device. Must be accessible by USB controller (see \ref CFG_TUSB_ATTR_USBRAM)
|
||||
* \param[in] lba Starting Logical Block Address to be read
|
||||
* \param[in] block_count Number of Block to be read
|
||||
* \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 input parameters 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 tuh_msc_read10 (uint8_t dev_addr, uint8_t lun, void * p_buffer, uint32_t lba, uint16_t block_count) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/** \brief Perform SCSI WRITE 10 command to write data to MassStorage device
|
||||
* \param[in] dev_addr device address
|
||||
* \param[in] lun Targeted Logical Unit
|
||||
* \param[in] p_buffer Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_ATTR_USBRAM)
|
||||
* \param[in] lba Starting Logical Block Address to be written
|
||||
* \param[in] block_count Number of Block to be written
|
||||
* \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 input parameters 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 tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffer, uint32_t lba, uint16_t block_count) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/** \brief Perform SCSI REQUEST SENSE command, used to retrieve sense data from MassStorage device
|
||||
* \param[in] dev_addr device address
|
||||
* \param[in] lun Targeted Logical Unit
|
||||
* \param[in] p_data Buffer to store response's data from device. Must be accessible by USB controller (see \ref CFG_TUSB_ATTR_USBRAM)
|
||||
* \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 input parameters 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 tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, uint8_t *p_data);
|
||||
|
||||
/** \brief Perform SCSI TEST UNIT READY command to test if MassStorage device is ready
|
||||
* \param[in] dev_addr device address
|
||||
* \param[in] lun Targeted Logical Unit
|
||||
* \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 input parameters 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 tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, msc_csw_t * p_csw) ATTR_WARN_UNUSED_RESULT; // TODO to be refractor
|
||||
|
||||
//tusb_error_t tusbh_msc_scsi_send(uint8_t dev_addr, uint8_t lun, bool is_direction_in,
|
||||
// uint8_t const * p_command, uint8_t cmd_len,
|
||||
// uint8_t * p_response, uint32_t resp_len) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
//------------- Application Callback -------------//
|
||||
/** \brief Callback function that will be invoked when a device with MassStorage 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 tuh_msc_mounted_cb(uint8_t dev_addr);
|
||||
|
||||
/** \brief Callback function that will be invoked when a device with MassStorage 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 tuh_msc_unmounted_cb(uint8_t dev_addr);
|
||||
|
||||
/** \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
|
||||
* \param[in] xferred_bytes Number of bytes transferred via USB bus
|
||||
* \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
|
||||
*/
|
||||
void tuh_msc_isr(uint8_t dev_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef _TINY_USB_SOURCE_FILE_
|
||||
|
||||
typedef struct {
|
||||
pipe_handle_t bulk_in, bulk_out;
|
||||
uint8_t interface_number;
|
||||
|
||||
uint8_t max_lun;
|
||||
uint16_t block_size;
|
||||
uint32_t last_lba; // last logical block address
|
||||
|
||||
volatile bool is_initialized;
|
||||
uint8_t vendor_id[8];
|
||||
uint8_t product_id[16];
|
||||
|
||||
msc_cbw_t cbw;
|
||||
msc_csw_t csw;
|
||||
}msch_interface_t;
|
||||
|
||||
void msch_init(void);
|
||||
tusb_error_t msch_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) ATTR_WARN_UNUSED_RESULT;
|
||||
void msch_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void msch_close(uint8_t dev_addr);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MSC_HOST_H_ */
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
@@ -0,0 +1,132 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file binary.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 Group_Common
|
||||
* \defgroup Group_Binary Binary
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_BINARY_H_
|
||||
#define _TUSB_BINARY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "tusb_compiler.h"
|
||||
|
||||
//------------- Bit manipulation -------------//
|
||||
#define BIT_(n) (1U << (n)) ///< n-th Bit
|
||||
#define BIT_SET_(x, n) ( (x) | BIT_(n) ) ///< set n-th bit of x to 1
|
||||
#define BIT_CLR_(x, n) ( (x) & (~BIT_(n)) ) ///< clear n-th bit of x
|
||||
#define BIT_TEST_(x, n) ( ((x) & BIT_(n)) ? true : false ) ///< check if n-th bit of x is 1
|
||||
|
||||
static inline uint32_t bit_set(uint32_t value, uint8_t n) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint32_t bit_set(uint32_t value, uint8_t n)
|
||||
{
|
||||
return value | BIT_(n);
|
||||
}
|
||||
|
||||
static inline uint32_t bit_clear(uint32_t value, uint8_t n) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint32_t bit_clear(uint32_t value, uint8_t n)
|
||||
{
|
||||
return value & (~BIT_(n));
|
||||
}
|
||||
|
||||
static inline bool bit_test(uint32_t value, uint8_t n) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline bool bit_test(uint32_t value, uint8_t n)
|
||||
{
|
||||
return (value & BIT_(n)) ? true : false;
|
||||
}
|
||||
|
||||
///< create a mask with n-bit lsb set to 1
|
||||
static inline uint32_t bit_mask(uint8_t n) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint32_t bit_mask(uint8_t n)
|
||||
{
|
||||
return (n < 32) ? ( BIT_(n) - 1 ) : UINT32_MAX;
|
||||
}
|
||||
|
||||
static inline uint32_t bit_mask_range(uint8_t start, uint32_t end) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint32_t bit_mask_range(uint8_t start, uint32_t end)
|
||||
{
|
||||
return bit_mask(end+1) & ~ bit_mask(start);
|
||||
}
|
||||
|
||||
static inline uint32_t bit_set_range(uint32_t value, uint8_t start, uint8_t end, uint32_t pattern) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint32_t bit_set_range(uint32_t value, uint8_t start, uint8_t end, uint32_t pattern)
|
||||
{
|
||||
return ( value & ~bit_mask_range(start, end) ) | (pattern << start);
|
||||
}
|
||||
|
||||
|
||||
//------------- Binary Constant -------------//
|
||||
#if defined(__GNUC__) && !defined(__CC_ARM)
|
||||
|
||||
#define BIN8(x) ((uint8_t) (0b##x))
|
||||
#define BIN16(b1, b2) ((uint16_t) (0b##b1##b2))
|
||||
#define BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4))
|
||||
|
||||
#else
|
||||
|
||||
// internal macro of B8, B16, B32
|
||||
#define _B8__(x) (((x&0x0000000FUL)?1:0) \
|
||||
+((x&0x000000F0UL)?2:0) \
|
||||
+((x&0x00000F00UL)?4:0) \
|
||||
+((x&0x0000F000UL)?8:0) \
|
||||
+((x&0x000F0000UL)?16:0) \
|
||||
+((x&0x00F00000UL)?32:0) \
|
||||
+((x&0x0F000000UL)?64:0) \
|
||||
+((x&0xF0000000UL)?128:0))
|
||||
|
||||
#define BIN8(d) ((uint8_t) _B8__(0x##d##UL))
|
||||
#define BIN16(dmsb,dlsb) (((uint16_t)BIN8(dmsb)<<8) + BIN8(dlsb))
|
||||
#define BIN32(dmsb,db2,db3,dlsb) \
|
||||
(((uint32_t)BIN8(dmsb)<<24) \
|
||||
+ ((uint32_t)BIN8(db2)<<16) \
|
||||
+ ((uint32_t)BIN8(db3)<<8) \
|
||||
+ BIN8(dlsb))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_BINARY_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,137 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file compiler_gcc.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 Group_Compiler
|
||||
* \defgroup Group_GCC GNU GCC
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_COMPILER_GCC_H_
|
||||
#define _TUSB_COMPILER_GCC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ALIGN_OF(x) __alignof__(x)
|
||||
|
||||
/// Normally, the compiler places the objects it generates in sections like data or bss & function in text. Sometimes, however, you need additional sections, or you need certain particular variables to appear in special sections, for example to map to special hardware. The section attribute specifies that a variable (or function) lives in a particular section
|
||||
#define ATTR_SECTION(sec_name) __attribute__ (( section(#sec_name) ))
|
||||
|
||||
/// If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, an error that includes message is diagnosed. This is useful for compile-time checking
|
||||
#define ATTR_ERROR(Message) __attribute__ ((error(Message)))
|
||||
|
||||
/// If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, a warning that includes message is diagnosed. This is useful for compile-time checking
|
||||
#define ATTR_WARNING(Message) __attribute__ ((warning(Message)))
|
||||
|
||||
/** \defgroup Group_VariableAttr Variable Attributes
|
||||
* @{ */
|
||||
|
||||
/// This attribute specifies a minimum alignment for the variable or structure field, measured in bytes
|
||||
#define ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
|
||||
|
||||
/// The packed attribute specifies that a variable or structure field should have the smallest possible alignment—one byte for a variable, and one bit for a field, unless you specify a larger value with the aligned attribute
|
||||
#define ATTR_PACKED __attribute__ ((packed))
|
||||
|
||||
#define ATTR_PREPACKED
|
||||
|
||||
#define ATTR_PACKED_STRUCT(x) x __attribute__ ((packed))
|
||||
/** @} */
|
||||
|
||||
/** \defgroup Group_FuncAttr Function Attributes
|
||||
* @{ */
|
||||
|
||||
/// Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level is specified
|
||||
#define ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
|
||||
|
||||
/// The nonnull attribute specifies that some function parameters should be non-null pointers. f the compiler determines that a null pointer is passed in an argument slot marked as non-null, and the -Wnonnull option is enabled, a warning is issued. All pointer arguments are marked as non-null
|
||||
#define ATTR_NON_NULL __attribute__ ((nonull))
|
||||
|
||||
/// Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute pure
|
||||
#define ATTR_PURE __attribute__ ((pure))
|
||||
|
||||
/// \brief Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the pure attribute below, since function is not allowed to read global memory.
|
||||
/// Note that a function that has pointer arguments and examines the data pointed to must not be declared const. Likewise, a function that calls a non-const function usually must not be const. It does not make sense for a const function to return void
|
||||
#define ATTR_CONST __attribute__ ((const))
|
||||
|
||||
/// The deprecated attribute results in a warning if the function is used anywhere in the source file. This is useful when identifying functions that are expected to be removed in a future version of a program. The warning also includes the location of the declaration of the deprecated function, to enable users to easily find further information about why the function is deprecated, or what they should do instead. Note that the warnings only occurs for uses
|
||||
#define ATTR_DEPRECATED __attribute__ ((deprecated))
|
||||
|
||||
/// Same as the deprecated attribute with optional message in the warning
|
||||
#define ATTR_DEPRECATED_MESS(mess) __attribute__ ((deprecated(mess)))
|
||||
|
||||
/// The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions that can be overridden in user code
|
||||
#define ATTR_WEAK __attribute__ ((weak))
|
||||
|
||||
/// The alias attribute causes the declaration to be emitted as an alias for another symbol, which must be specified
|
||||
#define ATTR_ALIAS(func) __attribute__ ((alias(#func)))
|
||||
|
||||
/// The weakref attribute marks a declaration as a weak reference. It is equivalent with weak + alias attribute, but require function is static
|
||||
#define ATTR_WEAKREF(func) __attribute__ ((weakref(#func)))
|
||||
|
||||
/// The warn_unused_result attribute causes a warning to be emitted if a caller of the function with this attribute does not use its return value. This is useful for functions where not checking the result is either a security problem or always a bug
|
||||
#define ATTR_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
|
||||
|
||||
/// This attribute, attached to a function, means that code must be emitted for the function even if it appears that the function is not referenced. This is useful, for example, when the function is referenced only in inline assembly.
|
||||
#define ATTR_USED __attribute__ ((used))
|
||||
|
||||
/// This attribute, attached to a function, means that the function is meant to be possibly unused. GCC does not produce a warning for this function.
|
||||
#define ATTR_UNUSED __attribute__ ((unused))
|
||||
|
||||
/** @} */
|
||||
|
||||
/** \defgroup Group_BuiltinFunc Built-in Functions
|
||||
* @{ */
|
||||
|
||||
// TODO mcu specific
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define __n2be(x) __builtin_bswap32(x) ///< built-in function to convert 32-bit from native to Big Endian
|
||||
#define __be2n(x) __n2be(x) ///< built-in function to convert 32-bit from Big Endian to native
|
||||
|
||||
#define __n2be_16(u16) __builtin_bswap16(u16)
|
||||
#define __be2n_16(u16) __n2be_16(u16)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_COMPILER_GCC_H_ */
|
||||
|
||||
/// @}
|
||||
@@ -0,0 +1,91 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file compiler_iar.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 IAR Compiler
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Compiler
|
||||
* \defgroup Group_IAR IAR ARM
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_COMPILER_IAR_H_
|
||||
#define _TUSB_COMPILER_IAR_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ALIGN_OF(x) __ALIGNOF__(x)
|
||||
|
||||
#define ATTR_PACKED_STRUCT(x) __packed x
|
||||
#define ATTR_PREPACKED __packed
|
||||
#define ATTR_PACKED
|
||||
//#define ATTR_SECTION(section) _Pragma((#section))
|
||||
|
||||
#define ATTR_ALIGNED(bytes) _Pragma(XSTRING_(data_alignment=##bytes))
|
||||
|
||||
#ifndef ATTR_ALWAYS_INLINE
|
||||
/// Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level is specified
|
||||
#define ATTR_ALWAYS_INLINE error
|
||||
#endif
|
||||
|
||||
#define ATTR_PURE // TODO IAR pure function attribute
|
||||
#define ATTR_CONST // TODO IAR const function attribute
|
||||
#define ATTR_WEAK __weak
|
||||
|
||||
#define ATTR_WARN_UNUSED_RESULT
|
||||
#define ATTR_USED
|
||||
#define ATTR_UNUSED
|
||||
|
||||
// built-in function to convert 32-bit Big-Endian to Little-Endian
|
||||
//#if __LITTLE_ENDIAN__
|
||||
#define __be2n __REV
|
||||
#define __n2be __be2n
|
||||
|
||||
#define __n2be_16(u16) ((uint16_t) __REV16(u16))
|
||||
#define __be2n_16(u16) __n2be_16(u16)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_COMPILER_IAR_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,76 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file timeout_timer.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 Group_Common Common Files
|
||||
* \defgroup Group_TimeoutTimer timeout timer
|
||||
* @{ */
|
||||
|
||||
|
||||
#ifndef _TUSB_TIMEOUT_TTIMER_H_
|
||||
#define _TUSB_TIMEOUT_TTIMER_H_
|
||||
|
||||
#include "tusb_compiler.h"
|
||||
#include "tusb_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t start;
|
||||
uint32_t interval;
|
||||
}timeout_timer_t;
|
||||
|
||||
static inline void timeout_set(timeout_timer_t* tt, uint32_t msec)
|
||||
{
|
||||
tt->interval = msec;
|
||||
tt->start = tusb_hal_millis();
|
||||
}
|
||||
|
||||
static inline bool timeout_expired(timeout_timer_t* tt)
|
||||
{
|
||||
return ( tusb_hal_millis() - tt->start ) >= tt->interval;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_TIMEOUT_TTIMER_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,273 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file tusb_common.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 Group_Common
|
||||
* \defgroup Group_CommonH common.h
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_COMMON_H_
|
||||
#define _TUSB_COMMON_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDES
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//------------- Standard Header -------------//
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//------------- TUSB Option Header -------------//
|
||||
#include "tusb_option.h"
|
||||
|
||||
//------------- General Header -------------//
|
||||
#include "tusb_compiler.h"
|
||||
#include "tusb_verify.h"
|
||||
#include "binary.h"
|
||||
#include "tusb_error.h"
|
||||
#include "tusb_hal.h"
|
||||
#include "tusb_fifo.h"
|
||||
|
||||
//------------- TUSB Header -------------//
|
||||
#include "tusb_types.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACROS
|
||||
//--------------------------------------------------------------------+
|
||||
#define MAX_OF(a, b) ( (a) > (b) ? (a) : (b) )
|
||||
#define MIN_OF(a, b) ( (a) < (b) ? (a) : (b) )
|
||||
|
||||
#define U16_HIGH_U8(u16) ((uint8_t) (((u16) >> 8) & 0x00ff))
|
||||
#define U16_LOW_U8(u16) ((uint8_t) ((u16) & 0x00ff))
|
||||
#define U16_TO_U8S_BE(u16) U16_HIGH_U8(u16), U16_LOW_U8(u16)
|
||||
#define U16_TO_U8S_LE(u16) U16_LOW_U8(u16), U16_HIGH_U8(u16)
|
||||
|
||||
#define U32_B1_U8(u32) ((uint8_t) (((u32) >> 24) & 0x000000ff)) // MSB
|
||||
#define U32_B2_U8(u32) ((uint8_t) (((u32) >> 16) & 0x000000ff))
|
||||
#define U32_B3_U8(u32) ((uint8_t) (((u32) >> 8) & 0x000000ff))
|
||||
#define U32_B4_U8(u32) ((uint8_t) ((u32) & 0x000000ff)) // LSB
|
||||
|
||||
#define U32_TO_U8S_BE(u32) U32_B1_U8(u32), U32_B2_U8(u32), U32_B3_U8(u32), U32_B4_U8(u32)
|
||||
#define U32_TO_U8S_LE(u32) U32_B4_U8(u32), U32_B3_U8(u32), U32_B2_U8(u32), U32_B1_U8(u32)
|
||||
|
||||
//------------- Endian Conversion -------------//
|
||||
#define ENDIAN_BE(u32) \
|
||||
(uint32_t) ( (((u32) & 0xFF) << 24) | (((u32) & 0xFF00) << 8) | (((u32) >> 8) & 0xFF00) | (((u32) >> 24) & 0xFF) )
|
||||
|
||||
#define ENDIAN_BE16(le16) ((uint16_t) ((U16_LOW_U8(le16) << 8) | U16_HIGH_U8(le16)) )
|
||||
|
||||
#ifndef __n2be_16
|
||||
#define __n2be_16(u16) ((uint16_t) ((U16_LOW_U8(u16) << 8) | U16_HIGH_U8(u16)) )
|
||||
#define __be2n_16(u16) __n2be_16(u16)
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INLINE FUNCTION
|
||||
//--------------------------------------------------------------------+
|
||||
#define memclr_(buffer, size) memset((buffer), 0, (size))
|
||||
#define varclr_(_var) memclr_(_var, sizeof(*(_var)))
|
||||
#define arrclr_(_arr) memclr_(_arr, sizeof(_arr))
|
||||
|
||||
#define arrcount_(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
|
||||
|
||||
static inline uint8_t const * descriptor_next(uint8_t const p_desc[])
|
||||
{
|
||||
return p_desc + p_desc[DESCRIPTOR_OFFSET_LENGTH];
|
||||
}
|
||||
|
||||
static inline uint8_t descriptor_typeof(uint8_t const p_desc[])
|
||||
{
|
||||
return p_desc[DESCRIPTOR_OFFSET_TYPE];
|
||||
}
|
||||
|
||||
//------------- Conversion -------------//
|
||||
/// form an uint32_t from 4 x uint8_t
|
||||
static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4)
|
||||
{
|
||||
return ( ((uint32_t) b1) << 24) + ( ((uint32_t) b2) << 16) + ( ((uint32_t) b3) << 8) + b4;
|
||||
}
|
||||
|
||||
static inline uint8_t u16_high_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint8_t u16_high_u8(uint16_t u16)
|
||||
{
|
||||
return (uint8_t) ( ((uint16_t) (u16 >> 8)) & 0x00ff);
|
||||
}
|
||||
|
||||
static inline uint8_t u16_low_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint8_t u16_low_u8(uint16_t u16)
|
||||
{
|
||||
return (uint8_t) (u16 & 0x00ff);
|
||||
}
|
||||
|
||||
static inline uint16_t u16_le2be(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint16_t u16_le2be(uint16_t u16)
|
||||
{
|
||||
return ((uint16_t)(u16_low_u8(u16) << 8)) | u16_high_u8(u16);
|
||||
}
|
||||
|
||||
//------------- Min -------------//
|
||||
static inline uint8_t min8_of(uint8_t x, uint8_t y) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint8_t min8_of(uint8_t x, uint8_t y)
|
||||
{
|
||||
return (x < y) ? x : y;
|
||||
}
|
||||
|
||||
static inline uint16_t min16_of(uint16_t x, uint16_t y) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint16_t min16_of(uint16_t x, uint16_t y)
|
||||
{
|
||||
return (x < y) ? x : y;
|
||||
}
|
||||
|
||||
static inline uint32_t min32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint32_t min32_of(uint32_t x, uint32_t y)
|
||||
{
|
||||
return (x < y) ? x : y;
|
||||
}
|
||||
|
||||
//------------- Max -------------//
|
||||
static inline uint32_t max32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint32_t max32_of(uint32_t x, uint32_t y)
|
||||
{
|
||||
return (x > y) ? x : y;
|
||||
}
|
||||
|
||||
static inline uint16_t max16_of(uint16_t x, uint16_t y) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint16_t max16_of(uint16_t x, uint16_t y)
|
||||
{
|
||||
return (x > y) ? x : y;
|
||||
}
|
||||
|
||||
//------------- Align -------------//
|
||||
static inline uint32_t align32 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint32_t align32 (uint32_t value)
|
||||
{
|
||||
return (value & 0xFFFFFFE0UL);
|
||||
}
|
||||
|
||||
static inline uint32_t align16 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint32_t align16 (uint32_t value)
|
||||
{
|
||||
return (value & 0xFFFFFFF0UL);
|
||||
}
|
||||
|
||||
static inline uint32_t align_n (uint32_t alignment, uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint32_t align_n (uint32_t alignment, uint32_t value)
|
||||
{
|
||||
return value & ((uint32_t) ~(alignment-1));
|
||||
}
|
||||
|
||||
static inline uint32_t align4k (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint32_t align4k (uint32_t value)
|
||||
{
|
||||
return (value & 0xFFFFF000UL);
|
||||
}
|
||||
|
||||
static inline uint32_t offset4k(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint32_t offset4k(uint32_t value)
|
||||
{
|
||||
return (value & 0xFFFUL);
|
||||
}
|
||||
|
||||
//------------- Mathematics -------------//
|
||||
static inline uint32_t abs_of(int32_t value) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint32_t abs_of(int32_t value)
|
||||
{
|
||||
return (value < 0) ? (-value) : value;
|
||||
}
|
||||
|
||||
|
||||
/// inclusive range checking
|
||||
static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper)
|
||||
{
|
||||
return (lower <= value) && (value <= upper);
|
||||
}
|
||||
|
||||
/// exclusive range checking
|
||||
static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper)
|
||||
{
|
||||
return (lower < value) && (value < upper);
|
||||
}
|
||||
|
||||
// TODO use clz
|
||||
static inline uint8_t log2_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint8_t log2_of(uint32_t value)
|
||||
{
|
||||
uint8_t result = 0; // log2 of a value is its MSB's position
|
||||
|
||||
while (value >>= 1)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// return the number of set bits in value
|
||||
static inline uint8_t cardinality_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint8_t cardinality_of(uint32_t value)
|
||||
{
|
||||
// Brian Kernighan's method goes through as many iterations as there are set bits. So if we have a 32-bit word with only
|
||||
// the high bit set, then it will only go once through the loop
|
||||
// Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan and Dennis M. Ritchie)
|
||||
// mentions this in exercise 2-9. On April 19, 2006 Don Knuth pointed out to me that this method
|
||||
// "was first published by Peter Wegner in CACM 3 (1960), 322. (Also discovered independently by Derrick Lehmer and
|
||||
// published in 1964 in a book edited by Beckenbach.)"
|
||||
uint8_t count;
|
||||
for (count = 0; value; count++)
|
||||
{
|
||||
value &= value - 1; // clear the least significant bit set
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_COMMON_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,83 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file compiler.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 Group_Common
|
||||
* \defgroup Group_Compiler Compiler
|
||||
* \brief Group_Compiler brief
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_COMPILER_H_
|
||||
#define _TUSB_COMPILER_H_
|
||||
|
||||
#define STRING_(x) #x ///< stringify without expand
|
||||
#define XSTRING_(x) STRING_(x) ///< expand then stringify
|
||||
#define STRING_CONCAT_(a, b) a##b ///< concat without expand
|
||||
#define XSTRING_CONCAT_(a, b) STRING_CONCAT_(a, b) ///< expand then concat
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Compile-time Assert (use VERIFY_STATIC to avoid name conflict)
|
||||
//--------------------------------------------------------------------+
|
||||
#if defined(__ICCARM__) || (__STDC_VERSION__ >= 201112L )
|
||||
#define VERIFY_STATIC static_assert
|
||||
#else
|
||||
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
|
||||
#define _VERIFY_COUNTER __COUNTER__
|
||||
#else
|
||||
#define _VERIFY_COUNTER __LINE__
|
||||
#endif
|
||||
|
||||
#define VERIFY_STATIC(const_expr, _mess) enum { XSTRING_CONCAT_(_verify_static_, _VERIFY_COUNTER) = 1/(!!(const_expr)) }
|
||||
#endif
|
||||
|
||||
// allow debugger to watch any module-wide variables anywhere
|
||||
#if CFG_TUSB_DEBUG
|
||||
#define STATIC_VAR
|
||||
#else
|
||||
#define STATIC_VAR static
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#include "compiler/tusb_compiler_gcc.h"
|
||||
#elif defined __ICCARM__
|
||||
#include "compiler/tusb_compiler_iar.h"
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_COMPILER_H_ */
|
||||
|
||||
/// @}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file tusb_error.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 Group_Common
|
||||
* \defgroup Group_Error Error Codes
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_ERRORS_H_
|
||||
#define _TUSB_ERRORS_H_
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ERROR_ENUM(x) x,
|
||||
#define ERROR_STRING(x) #x,
|
||||
|
||||
#define ERROR_TABLE(ENTRY) \
|
||||
ENTRY(TUSB_ERROR_NONE )\
|
||||
ENTRY(TUSB_ERROR_INVALID_PARA )\
|
||||
ENTRY(TUSB_ERROR_DEVICE_NOT_READY )\
|
||||
ENTRY(TUSB_ERROR_INTERFACE_IS_BUSY )\
|
||||
ENTRY(TUSB_ERROR_HCD_FAILED )\
|
||||
ENTRY(TUSB_ERROR_HCD_OPEN_PIPE_FAILED )\
|
||||
ENTRY(TUSB_ERROR_USBH_MOUNT_DEVICE_NOT_RESPOND )\
|
||||
ENTRY(TUSB_ERROR_USBH_MOUNT_CONFIG_DESC_TOO_LONG )\
|
||||
ENTRY(TUSB_ERROR_USBH_DESCRIPTOR_CORRUPTED )\
|
||||
ENTRY(TUSB_ERROR_USBH_XFER_STALLED )\
|
||||
ENTRY(TUSB_ERROR_USBH_XFER_FAILED )\
|
||||
ENTRY(TUSB_ERROR_OSAL_TIMEOUT )\
|
||||
ENTRY(TUSB_ERROR_OSAL_WAITING ) /* only used by OSAL_NONE in the subtask */ \
|
||||
ENTRY(TUSB_ERROR_OSAL_TASK_FAILED )\
|
||||
ENTRY(TUSB_ERROR_OSAL_QUEUE_FAILED )\
|
||||
ENTRY(TUSB_ERROR_OSAL_SEMAPHORE_FAILED )\
|
||||
ENTRY(TUSB_ERROR_OSAL_MUTEX_FAILED )\
|
||||
ENTRY(TUSB_ERROR_EHCI_NOT_ENOUGH_QTD )\
|
||||
ENTRY(TUSB_ERROR_HIDD_DESCRIPTOR_INTERFACE )\
|
||||
ENTRY(TUSB_ERROR_HIDH_NOT_SUPPORTED_PROTOCOL )\
|
||||
ENTRY(TUSB_ERROR_HIDH_NOT_SUPPORTED_SUBCLASS )\
|
||||
ENTRY(TUSB_ERROR_CDC_UNSUPPORTED_SUBCLASS )\
|
||||
ENTRY(TUSB_ERROR_CDC_UNSUPPORTED_PROTOCOL )\
|
||||
ENTRY(TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED )\
|
||||
ENTRY(TUSB_ERROR_MSC_UNSUPPORTED_PROTOCOL )\
|
||||
ENTRY(TUSB_ERROR_MSCH_UNKNOWN_SCSI_COMMAND )\
|
||||
ENTRY(TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED )\
|
||||
ENTRY(TUSB_ERROR_HUB_FEATURE_NOT_SUPPORTED )\
|
||||
ENTRY(TUSB_ERROR_DESCRIPTOR_CORRUPTED )\
|
||||
ENTRY(TUSB_ERROR_DCD_FAILED )\
|
||||
ENTRY(TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT )\
|
||||
ENTRY(TUSB_ERROR_DCD_NOT_ENOUGH_QTD )\
|
||||
ENTRY(TUSB_ERROR_DCD_OPEN_PIPE_FAILED )\
|
||||
ENTRY(TUSB_ERROR_DCD_EDPT_XFER )\
|
||||
ENTRY(TUSB_ERROR_NOT_SUPPORTED_YET )\
|
||||
ENTRY(TUSB_ERROR_USBD_DEVICE_NOT_CONFIGURED )\
|
||||
ENTRY(TUSB_ERROR_NOT_ENOUGH_MEMORY )\
|
||||
ENTRY(TUSB_ERROR_FAILED )\
|
||||
|
||||
|
||||
/// \brief Error Code returned
|
||||
typedef enum
|
||||
{
|
||||
ERROR_TABLE(ERROR_ENUM)
|
||||
TUSB_ERROR_COUNT
|
||||
}tusb_error_t;
|
||||
|
||||
#if CFG_TUSB_DEBUG
|
||||
/// Enum to String for debugging purposes. Only available if \ref CFG_TUSB_DEBUG > 0
|
||||
extern char const* const tusb_strerr[TUSB_ERROR_COUNT];
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_ERRORS_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,280 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file fifo.c
|
||||
@author hathach (tinyusb.org)
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, 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_fifo.h"
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
*------------------------------------------------------------------*/
|
||||
#if CFG_FIFO_MUTEX
|
||||
|
||||
#define mutex_lock_if_needed(_ff) if (_ff->mutex) fifo_mutex_lock(_ff->mutex)
|
||||
#define mutex_unlock_if_needed(_ff) if (_ff->mutex) fifo_mutex_unlock(_ff->mutex)
|
||||
|
||||
#else
|
||||
|
||||
#define mutex_lock_if_needed(_ff)
|
||||
#define mutex_unlock_if_needed(_ff)
|
||||
|
||||
#endif
|
||||
|
||||
static inline uint16_t min16_of(uint16_t x, uint16_t y)
|
||||
{
|
||||
return (x < y) ? x : y;
|
||||
}
|
||||
|
||||
static inline bool fifo_initalized(fifo_t* f)
|
||||
{
|
||||
return (f->buffer != NULL) && (f->depth > 0) && (f->item_size > 0);
|
||||
}
|
||||
|
||||
|
||||
void fifo_config(fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable)
|
||||
{
|
||||
mutex_lock_if_needed(f);
|
||||
|
||||
f->buffer = (uint8_t*) buffer;
|
||||
f->depth = depth;
|
||||
f->item_size = item_size;
|
||||
f->overwritable = overwritable;
|
||||
|
||||
f->rd_idx = f->wr_idx = f->count = 0;
|
||||
|
||||
mutex_unlock_if_needed(f);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Read one byte out of the RX buffer.
|
||||
|
||||
This function will return the byte located at the array index of the
|
||||
read pointer, and then increment the read pointer index. If the read
|
||||
pointer exceeds the maximum buffer size, it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] p_buffer
|
||||
Pointer to the place holder for data read from the buffer
|
||||
|
||||
@returns TRUE if the queue is not empty
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool fifo_read(fifo_t* f, void * p_buffer)
|
||||
{
|
||||
if( !fifo_initalized(f) ) return false;
|
||||
if( fifo_empty(f) ) return false;
|
||||
|
||||
mutex_lock_if_needed(f);
|
||||
|
||||
memcpy(p_buffer,
|
||||
f->buffer + (f->rd_idx * f->item_size),
|
||||
f->item_size);
|
||||
f->rd_idx = (f->rd_idx + 1) % f->depth;
|
||||
f->count--;
|
||||
|
||||
mutex_unlock_if_needed(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief This function will read n elements into the array index specified by
|
||||
the write pointer and increment the write index. If the write index
|
||||
exceeds the max buffer size, then it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] p_data
|
||||
The pointer to data location
|
||||
@param[in] count
|
||||
Number of element that buffer can afford
|
||||
|
||||
@returns number of items read from the FIFO
|
||||
*/
|
||||
/******************************************************************************/
|
||||
uint16_t fifo_read_n (fifo_t* f, void * p_buffer, uint16_t count)
|
||||
{
|
||||
if( !fifo_initalized(f) ) return 0;
|
||||
if( fifo_empty(f) ) return 0;
|
||||
|
||||
/* Limit up to fifo's count */
|
||||
count = min16_of(count, f->count);
|
||||
if( count == 0 ) return 0;
|
||||
|
||||
mutex_lock_if_needed(f);
|
||||
|
||||
/* Could copy up to 2 portions marked as 'x' if queue is wrapped around
|
||||
* case 1: ....RxxxxW.......
|
||||
* case 2: xxxxxW....Rxxxxxx
|
||||
*/
|
||||
// uint16_t index2upper = min16_of(count, f->count-f->rd_idx);
|
||||
|
||||
uint8_t* p_buf = (uint8_t*) p_buffer;
|
||||
uint16_t len = 0;
|
||||
while( (len < count) && fifo_read(f, p_buf) )
|
||||
{
|
||||
len++;
|
||||
p_buf += f->item_size;
|
||||
}
|
||||
|
||||
mutex_unlock_if_needed(f);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Reads one item without removing it from the FIFO
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] position
|
||||
Position to read from in the FIFO buffer
|
||||
@param[in] p_buffer
|
||||
Pointer to the place holder for data read from the buffer
|
||||
|
||||
@returns TRUE if the queue is not empty
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool fifo_peek_at(fifo_t* f, uint16_t position, void * p_buffer)
|
||||
{
|
||||
if ( !fifo_initalized(f) ) return false;
|
||||
if ( position >= f->count ) return false;
|
||||
|
||||
// rd_idx is position=0
|
||||
uint16_t index = (f->rd_idx + position) % f->depth;
|
||||
memcpy(p_buffer,
|
||||
f->buffer + (index * f->item_size),
|
||||
f->item_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Write one element into the RX buffer.
|
||||
|
||||
This function will write one element into the array index specified by
|
||||
the write pointer and increment the write index. If the write index
|
||||
exceeds the max buffer size, then it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] p_data
|
||||
The byte to add to the FIFO
|
||||
|
||||
@returns TRUE if the data was written to the FIFO (overwrittable
|
||||
FIFO will always return TRUE)
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool fifo_write(fifo_t* f, void const * p_data)
|
||||
{
|
||||
if ( !fifo_initalized(f) ) return false;
|
||||
if ( fifo_full(f) && !f->overwritable ) return false;
|
||||
|
||||
mutex_lock_if_needed(f);
|
||||
|
||||
memcpy( f->buffer + (f->wr_idx * f->item_size),
|
||||
p_data,
|
||||
f->item_size);
|
||||
|
||||
f->wr_idx = (f->wr_idx + 1) % f->depth;
|
||||
|
||||
if (fifo_full(f))
|
||||
{
|
||||
f->rd_idx = f->wr_idx; // keep the full state (rd == wr && len = size)
|
||||
}
|
||||
else
|
||||
{
|
||||
f->count++;
|
||||
}
|
||||
|
||||
mutex_unlock_if_needed(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief This function will write n elements into the array index specified by
|
||||
the write pointer and increment the write index. If the write index
|
||||
exceeds the max buffer size, then it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] p_data
|
||||
The pointer to data to add to the FIFO
|
||||
@param[in] count
|
||||
Number of element
|
||||
@return Number of written elements
|
||||
*/
|
||||
/******************************************************************************/
|
||||
uint16_t fifo_write_n(fifo_t* f, void const * p_data, uint16_t count)
|
||||
{
|
||||
if ( count == 0 ) return 0;
|
||||
|
||||
uint8_t* p_buf = (uint8_t*) p_data;
|
||||
|
||||
uint16_t len = 0;
|
||||
while( (len < count) && fifo_write(f, p_buf) )
|
||||
{
|
||||
len++;
|
||||
p_buf += f->item_size;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Clear the fifo read and write pointers and set length to zero
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
*/
|
||||
/******************************************************************************/
|
||||
void fifo_clear(fifo_t *f)
|
||||
{
|
||||
mutex_lock_if_needed(f);
|
||||
|
||||
f->rd_idx = f->wr_idx = f->count = 0;
|
||||
|
||||
mutex_unlock_if_needed(f);
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file fifo.h
|
||||
@author hathach (tinyusb.org)
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, 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 Group_Common
|
||||
* \defgroup group_fifo fifo
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_FIFO_H_
|
||||
#define _TUSB_FIFO_H_
|
||||
|
||||
#define CFG_FIFO_MUTEX 0
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
|
||||
#include "osal/osal.h"
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
// Since all fifo read/write is done in thread mode, there should be
|
||||
// no conflict except for osal queue which will be address seperatedly.
|
||||
// Therefore there may be no need for mutex with internal use of fifo
|
||||
|
||||
#define _ff_mutex_def(mutex)
|
||||
|
||||
#else
|
||||
#define fifo_mutex_t struct os_mutex
|
||||
|
||||
#define fifo_mutex_lock(m) os_mutex_pend(m, OS_TIMEOUT_NEVER)
|
||||
#define fifo_mutex_unlock(m) os_mutex_release(m)
|
||||
|
||||
/* Internal use only */
|
||||
#define _mutex_declare(m) .mutex = m
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define _mutex_declare(m)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** \struct fifo_t
|
||||
* \brief Simple Circular FIFO
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t* buffer ; ///< buffer pointer
|
||||
uint16_t depth ; ///< max items
|
||||
uint16_t item_size ; ///< size of each item
|
||||
|
||||
volatile uint16_t count ; ///< number of items in queue
|
||||
volatile uint16_t wr_idx ; ///< write pointer
|
||||
volatile uint16_t rd_idx ; ///< read pointer
|
||||
|
||||
bool overwritable ;
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
fifo_mutex_t * const mutex;
|
||||
#endif
|
||||
|
||||
} fifo_t;
|
||||
|
||||
#define FIFO_DEF(name, ff_depth, type, is_overwritable) /*, irq_mutex)*/ \
|
||||
uint8_t name##_buffer[ff_depth*sizeof(type)];\
|
||||
fifo_t name = {\
|
||||
.buffer = name##_buffer,\
|
||||
.depth = ff_depth,\
|
||||
.item_size = sizeof(type),\
|
||||
.overwritable = is_overwritable,\
|
||||
/*.irq = irq_mutex*/\
|
||||
_mutex_declare(_mutex)\
|
||||
}
|
||||
|
||||
void fifo_clear(fifo_t *f);
|
||||
void fifo_config(fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);
|
||||
|
||||
bool fifo_write (fifo_t* f, void const * p_data);
|
||||
uint16_t fifo_write_n (fifo_t* f, void const * p_data, uint16_t count);
|
||||
|
||||
bool fifo_read (fifo_t* f, void * p_buffer);
|
||||
uint16_t fifo_read_n (fifo_t* f, void * p_buffer, uint16_t count);
|
||||
|
||||
bool fifo_peek_at (fifo_t* f, uint16_t position, void * p_buffer);
|
||||
|
||||
static inline bool fifo_peek(fifo_t* f, void * p_buffer)
|
||||
{
|
||||
return fifo_peek_at(f, 0, p_buffer);
|
||||
}
|
||||
|
||||
static inline bool fifo_empty(fifo_t* f)
|
||||
{
|
||||
return (f->count == 0);
|
||||
}
|
||||
|
||||
static inline bool fifo_full(fifo_t* f)
|
||||
{
|
||||
return (f->count == f->depth);
|
||||
}
|
||||
|
||||
static inline uint16_t fifo_count(fifo_t* f)
|
||||
{
|
||||
return f->count;
|
||||
}
|
||||
|
||||
static inline uint16_t fifo_remaining(fifo_t* f)
|
||||
{
|
||||
return f->depth - f->count;
|
||||
}
|
||||
|
||||
static inline uint16_t fifo_depth(fifo_t* f)
|
||||
{
|
||||
return f->depth;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_FIFO_H_ */
|
||||
@@ -0,0 +1,414 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file tusb_types.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 group_usb_definitions
|
||||
* \defgroup USBDef_Type USB Types
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_TYPES_H_
|
||||
#define _TUSB_TYPES_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "tusb_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* CONSTANTS
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
/// defined base on EHCI specs value for Endpoint Speed
|
||||
typedef enum
|
||||
{
|
||||
TUSB_SPEED_FULL = 0,
|
||||
TUSB_SPEED_LOW ,
|
||||
TUSB_SPEED_HIGH
|
||||
}tusb_speed_t;
|
||||
|
||||
/// defined base on USB Specs Endpoint's bmAttributes
|
||||
typedef enum
|
||||
{
|
||||
TUSB_XFER_CONTROL = 0 ,
|
||||
TUSB_XFER_ISOCHRONOUS ,
|
||||
TUSB_XFER_BULK ,
|
||||
TUSB_XFER_INTERRUPT
|
||||
}tusb_xfer_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_DIR_OUT = 0,
|
||||
TUSB_DIR_IN = 1,
|
||||
|
||||
TUSB_DIR_IN_MASK = 0x80
|
||||
}tusb_dir_t;
|
||||
|
||||
|
||||
/// USB Descriptor Types (section 9.4 table 9-5)
|
||||
typedef enum
|
||||
{
|
||||
TUSB_DESC_DEVICE = 0x01 ,
|
||||
TUSB_DESC_CONFIGURATION = 0x02 ,
|
||||
TUSB_DESC_STRING = 0x03 ,
|
||||
TUSB_DESC_INTERFACE = 0x04 ,
|
||||
TUSB_DESC_ENDPOINT = 0x05 ,
|
||||
TUSB_DESC_DEVICE_QUALIFIER = 0x06 ,
|
||||
TUSB_DESC_OTHER_SPEED_CONFIG = 0x07 ,
|
||||
TUSB_DESC_INTERFACE_POWER = 0x08 ,
|
||||
TUSB_DESC_OTG = 0x09 ,
|
||||
TUSB_DESC_DEBUG = 0x0A ,
|
||||
TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B ,
|
||||
TUSB_DESC_CLASS_SPECIFIC = 0x24
|
||||
}tusb_desc_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_GET_STATUS =0 , ///< 0
|
||||
TUSB_REQ_CLEAR_FEATURE , ///< 1
|
||||
TUSB_REQ_RESERVED , ///< 2
|
||||
TUSB_REQ_SET_FEATURE , ///< 3
|
||||
TUSB_REQ_RESERVED2 , ///< 4
|
||||
TUSB_REQ_SET_ADDRESS , ///< 5
|
||||
TUSB_REQ_GET_DESCRIPTOR , ///< 6
|
||||
TUSB_REQ_SET_DESCRIPTOR , ///< 7
|
||||
TUSB_REQ_GET_CONFIGURATION , ///< 8
|
||||
TUSB_REQ_SET_CONFIGURATION , ///< 9
|
||||
TUSB_REQ_GET_INTERFACE , ///< 10
|
||||
TUSB_REQ_SET_INTERFACE , ///< 11
|
||||
TUSB_REQ_SYNCH_FRAME ///< 12
|
||||
}tusb_request_code_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_TYPE_STANDARD = 0,
|
||||
TUSB_REQ_TYPE_CLASS,
|
||||
TUSB_REQ_TYPE_VENDOR
|
||||
} tusb_request_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_RCPT_DEVICE =0,
|
||||
TUSB_REQ_RCPT_INTERFACE,
|
||||
TUSB_REQ_RCPT_ENDPOINT,
|
||||
TUSB_REQ_RCPT_OTHER
|
||||
} tusb_request_recipient_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_CLASS_UNSPECIFIED = 0 , ///< 0
|
||||
TUSB_CLASS_AUDIO = 1 , ///< 1
|
||||
TUSB_CLASS_CDC = 2 , ///< 2
|
||||
TUSB_CLASS_HID = 3 , ///< 3
|
||||
TUSB_CLASS_RESERVED_4 = 4 , ///< 4
|
||||
TUSB_CLASS_PHYSICAL = 5 , ///< 5
|
||||
TUSB_CLASS_IMAGE = 6 , ///< 6
|
||||
TUSB_CLASS_PRINTER = 7 , ///< 7
|
||||
TUSB_CLASS_MSC = 8 , ///< 8
|
||||
TUSB_CLASS_HUB = 9 , ///< 9
|
||||
TUSB_CLASS_CDC_DATA = 10 , ///< 10
|
||||
TUSB_CLASS_SMART_CARD = 11 , ///< 11
|
||||
TUSB_CLASS_RESERVED_12 = 12 , ///< 12
|
||||
TUSB_CLASS_CONTENT_SECURITY = 13 , ///< 13
|
||||
TUSB_CLASS_VIDEO = 14 , ///< 14
|
||||
TUSB_CLASS_PERSONAL_HEALTHCARE = 15 , ///< 15
|
||||
TUSB_CLASS_AUDIO_VIDEO = 16 , ///< 16
|
||||
|
||||
TUSB_CLASS_MAPPED_INDEX_START = 17 , // TODO Map DIAGNOSTIC, WIRELESS_CONTROLLER, MISC, VENDOR_SPECIFIC to this to minimize the array
|
||||
|
||||
TUSB_CLASS_DIAGNOSTIC = 0xDC ,
|
||||
TUSB_CLASS_WIRELESS_CONTROLLER = 0xE0 ,
|
||||
TUSB_CLASS_MISC = 0xEF ,
|
||||
TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE ,
|
||||
TUSB_CLASS_VENDOR_SPECIFIC = 0xFF
|
||||
}tusb_class_code_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MISC_SUBCLASS_COMMON = 2
|
||||
}misc_subclass_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MISC_PROTOCOL_IAD = 1
|
||||
}misc_protocol_type_t;
|
||||
|
||||
enum {
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = BIT_(5),
|
||||
TUSB_DESC_CONFIG_ATT_SELF_POWER = BIT_(6),
|
||||
TUSB_DESC_CONFIG_ATT_BUS_POWER = BIT_(7)
|
||||
};
|
||||
|
||||
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
|
||||
|
||||
/// Device State
|
||||
typedef enum
|
||||
{
|
||||
TUSB_DEVICE_STATE_UNPLUG = 0 ,
|
||||
TUSB_DEVICE_STATE_ADDRESSED ,
|
||||
TUSB_DEVICE_STATE_CONFIGURED ,
|
||||
TUSB_DEVICE_STATE_SUSPENDED ,
|
||||
|
||||
TUSB_DEVICE_STATE_REMOVING ,
|
||||
TUSB_DEVICE_STATE_SAFE_REMOVE ,
|
||||
|
||||
TUSB_DEVICE_STATE_INVALID_PARAMETER
|
||||
}tusb_device_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_EVENT_NONE = 0,
|
||||
TUSB_EVENT_XFER_COMPLETE,
|
||||
TUSB_EVENT_XFER_ERROR,
|
||||
TUSB_EVENT_XFER_STALLED,
|
||||
|
||||
TUSB_EVENT_BUS_RESET, // TODO refractor
|
||||
TUSB_EVENT_SETUP_RECEIVED,
|
||||
}tusb_event_t;
|
||||
|
||||
enum {
|
||||
DESCRIPTOR_OFFSET_LENGTH = 0,
|
||||
DESCRIPTOR_OFFSET_TYPE = 1
|
||||
};
|
||||
|
||||
enum {
|
||||
INTERFACE_INVALID_NUMBER = 0xff
|
||||
};
|
||||
|
||||
static inline uint8_t std_class_code_to_index(uint8_t std_class_code)
|
||||
{
|
||||
return (std_class_code <= TUSB_CLASS_AUDIO_VIDEO ) ? std_class_code :
|
||||
(std_class_code == TUSB_CLASS_DIAGNOSTIC ) ? TUSB_CLASS_MAPPED_INDEX_START :
|
||||
(std_class_code == TUSB_CLASS_WIRELESS_CONTROLLER ) ? TUSB_CLASS_MAPPED_INDEX_START + 1 :
|
||||
(std_class_code == TUSB_CLASS_MISC ) ? TUSB_CLASS_MAPPED_INDEX_START + 2 :
|
||||
(std_class_code == TUSB_CLASS_APPLICATION_SPECIFIC ) ? TUSB_CLASS_MAPPED_INDEX_START + 3 :
|
||||
(std_class_code == TUSB_CLASS_VENDOR_SPECIFIC ) ? TUSB_CLASS_MAPPED_INDEX_START + 4 : 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// STANDARD DESCRIPTORS
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// USB Standard Device Descriptor (section 9.6.1, table 9-8)
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes.
|
||||
uint8_t bDescriptorType ; ///< DEVICE Descriptor Type.
|
||||
uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant.
|
||||
|
||||
uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific.
|
||||
uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
|
||||
uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis.
|
||||
uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64.
|
||||
|
||||
uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF).
|
||||
uint16_t idProduct ; ///< Product ID (assigned by the manufacturer).
|
||||
uint16_t bcdDevice ; ///< Device release number in binary-coded decimal.
|
||||
uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer.
|
||||
uint8_t iProduct ; ///< Index of string descriptor describing product.
|
||||
uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number.
|
||||
|
||||
uint8_t bNumConfigurations ; ///< Number of possible configurations.
|
||||
} tusb_desc_device_t;
|
||||
|
||||
/// USB Standard Configuration Descriptor (section 9.6.1 table 9-10) */
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type
|
||||
uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration.
|
||||
|
||||
uint8_t bNumInterfaces ; ///< Number of interfaces supported by this configuration
|
||||
uint8_t bConfigurationValue ; ///< Value to use as an argument to the SetConfiguration() request to select this configuration.
|
||||
uint8_t iConfiguration ; ///< Index of string descriptor describing this configuration
|
||||
uint8_t bmAttributes ; ///< Configuration characteristics \n D7: Reserved (set to one)\n D6: Self-powered \n D5: Remote Wakeup \n D4...0: Reserved (reset to zero) \n D7 is reserved and must be set to one for historical reasons. \n A device configuration that uses power from the bus and a local source reports a non-zero value in bMaxPower to indicate the amount of bus power required and sets D6. The actual power source at runtime may be determined using the GetStatus(DEVICE) request (see USB 2.0 spec Section 9.4.5). \n If a device configuration supports remote wakeup, D5 is set to one.
|
||||
uint8_t bMaxPower ; ///< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (i.e., 50 = 100 mA).
|
||||
} tusb_desc_configuration_t;
|
||||
|
||||
/// USB Standard Interface Descriptor (section 9.6.1 table 9-12)
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type
|
||||
|
||||
uint8_t bInterfaceNumber ; ///< Number of this interface. Zero-based value identifying the index in the array of concurrent interfaces supported by this configuration.
|
||||
uint8_t bAlternateSetting ; ///< Value used to select this alternate setting for the interface identified in the prior field
|
||||
uint8_t bNumEndpoints ; ///< Number of endpoints used by this interface (excluding endpoint zero). If this value is zero, this interface only uses the Default Control Pipe.
|
||||
uint8_t bInterfaceClass ; ///< Class code (assigned by the USB-IF). \li A value of zero is reserved for future standardization. \li If this field is set to FFH, the interface class is vendor-specific. \li All other values are reserved for assignment by the USB-IF.
|
||||
uint8_t bInterfaceSubClass ; ///< Subclass code (assigned by the USB-IF). \n These codes are qualified by the value of the bInterfaceClass field. \li If the bInterfaceClass field is reset to zero, this field must also be reset to zero. \li If the bInterfaceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
|
||||
uint8_t bInterfaceProtocol ; ///< Protocol code (assigned by the USB). \n These codes are qualified by the value of the bInterfaceClass and the bInterfaceSubClass fields. If an interface supports class-specific requests, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use a class-specific protocol on this interface. \li If this field is set to FFH, the device uses a vendor-specific protocol for this interface.
|
||||
uint8_t iInterface ; ///< Index of string descriptor describing this interface
|
||||
} tusb_desc_interface_t;
|
||||
|
||||
/// USB Standard Endpoint Descriptor (section 9.6.1 table 9-13)
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< ENDPOINT Descriptor Type
|
||||
|
||||
uint8_t bEndpointAddress ; ///< The address of the endpoint on the USB device described by this descriptor. The address is encoded as follows: \n Bit 3...0: The endpoint number \n Bit 6...4: Reserved, reset to zero \n Bit 7: Direction, ignored for control endpoints 0 = OUT endpoint 1 = IN endpoint.
|
||||
|
||||
struct ATTR_PACKED {
|
||||
uint8_t xfer : 2;
|
||||
uint8_t sync : 2;
|
||||
uint8_t usage : 2;
|
||||
uint8_t : 2;
|
||||
} bmAttributes ; ///< This field describes the endpoint's attributes when it is configured using the bConfigurationValue. \n Bits 1..0: Transfer Type \n- 00 = Control \n- 01 = Isochronous \n- 10 = Bulk \n- 11 = Interrupt \n If not an isochronous endpoint, bits 5..2 are reserved and must be set to zero. If isochronous, they are defined as follows: \n Bits 3..2: Synchronization Type \n- 00 = No Synchronization \n- 01 = Asynchronous \n- 10 = Adaptive \n- 11 = Synchronous \n Bits 5..4: Usage Type \n- 00 = Data endpoint \n- 01 = Feedback endpoint \n- 10 = Implicit feedback Data endpoint \n- 11 = Reserved \n Refer to Chapter 5 of USB 2.0 specification for more information. \n All other bits are reserved and must be reset to zero. Reserved bits must be ignored by the host.
|
||||
|
||||
struct ATTR_PACKED {
|
||||
uint16_t size : 11; ///< Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. \n For isochronous endpoints, this value is used to reserve the bus time in the schedule, required for the per-(micro)frame data payloads. The pipe may, on an ongoing basis, actually use less bandwidth than that reserved. The device reports, if necessary, the actual bandwidth used via its normal, non-USB defined mechanisms. \n For all endpoints, bits 10..0 specify the maximum packet size (in bytes). \n For high-speed isochronous and interrupt endpoints: \n Bits 12..11 specify the number of additional transaction opportunities per microframe: \n- 00 = None (1 transaction per microframe) \n- 01 = 1 additional (2 per microframe) \n- 10 = 2 additional (3 per microframe) \n- 11 = Reserved \n Bits 15..13 are reserved and must be set to zero.
|
||||
uint16_t hs_period_mult : 2;
|
||||
uint16_t : 0;
|
||||
}wMaxPacketSize;
|
||||
|
||||
uint8_t bInterval ; ///< Interval for polling endpoint for data transfers. Expressed in frames or microframes depending on the device operating speed (i.e., either 1 millisecond or 125 us units). \n- For full-/high-speed isochronous endpoints, this value must be in the range from 1 to 16. The bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$). \n- For full-/low-speed interrupt endpoints, the value of this field may be from 1 to 255. \n- For high-speed interrupt endpoints, the bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$) . This value must be from 1 to 16. \n- For high-speed bulk/control OUT endpoints, the bInterval must specify the maximum NAK rate of the endpoint. A value of 0 indicates the endpoint never NAKs. Other values indicate at most 1 NAK each bInterval number of microframes. This value must be in the range from 0 to 255. \n Refer to Chapter 5 of USB 2.0 specification for more information.
|
||||
} tusb_desc_endpoint_t;
|
||||
|
||||
/// USB Other Speed Configuration Descriptor (section 9.6.1 table 9-11)
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
uint16_t wTotalLength ; ///< Total length of data returned
|
||||
|
||||
uint8_t bNumInterfaces ; ///< Number of interfaces supported by this speed configuration
|
||||
uint8_t bConfigurationValue ; ///< Value to use to select configuration
|
||||
uint8_t IConfiguration ; ///< Index of string descriptor
|
||||
uint8_t bmAttributes ; ///< Same as Configuration descriptor
|
||||
uint8_t bMaxPower ; ///< Same as Configuration descriptor
|
||||
} tusb_desc_other_speed_t;
|
||||
|
||||
/// USB Device Qualifier Descriptor (section 9.6.1 table 9-9)
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Device Qualifier Type
|
||||
uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00)
|
||||
|
||||
uint8_t bDeviceClass ; ///< Class Code
|
||||
uint8_t bDeviceSubClass ; ///< SubClass Code
|
||||
uint8_t bDeviceProtocol ; ///< Protocol Code
|
||||
uint8_t bMaxPacketSize0 ; ///< Maximum packet size for other speed
|
||||
uint8_t bNumConfigurations ; ///< Number of Other-speed Configurations
|
||||
uint8_t bReserved ; ///< Reserved for future use, must be zero
|
||||
} tusb_desc_device_qualifier_t;
|
||||
|
||||
/// USB Interface Association Descriptor (IAD ECN)
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
|
||||
uint8_t bFirstInterface ; ///< Index of the first associated interface.
|
||||
uint8_t bInterfaceCount ; ///< Total number of associated interfaces.
|
||||
|
||||
uint8_t bFunctionClass ; ///< Interface class ID.
|
||||
uint8_t bFunctionSubClass ; ///< Interface subclass ID.
|
||||
uint8_t bFunctionProtocol ; ///< Interface protocol ID.
|
||||
|
||||
uint8_t iFunction ; ///< Index of the string descriptor describing the interface association.
|
||||
} tusb_desc_interface_assoc_t;
|
||||
|
||||
/// USB Header Descriptor
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< Descriptor Type
|
||||
} tusb_desc_header_t;
|
||||
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< Descriptor Type
|
||||
uint16_t unicode_string[];
|
||||
} tusb_desc_string_t;
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Types
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
typedef struct ATTR_PACKED{
|
||||
union {
|
||||
struct ATTR_PACKED {
|
||||
uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
|
||||
uint8_t type : 2; ///< Request type tusb_request_type_t.
|
||||
uint8_t direction : 1; ///< Direction type. tusb_dir_t
|
||||
} bmRequestType_bit;
|
||||
uint8_t bmRequestType;
|
||||
};
|
||||
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} tusb_control_request_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "mostly compiler option issue");
|
||||
|
||||
// TODO move to somewhere suitable
|
||||
static inline uint8_t bm_request_type(uint8_t direction, uint8_t type, uint8_t recipient)
|
||||
{
|
||||
return ((uint8_t) (direction << 7)) | ((uint8_t) (type << 5)) | (recipient);
|
||||
}
|
||||
|
||||
// Get direction from Endpoint address
|
||||
static inline tusb_dir_t edpt_dir(uint8_t addr)
|
||||
{
|
||||
return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
|
||||
}
|
||||
|
||||
// Get Endpoint number from address
|
||||
static inline uint8_t edpt_number(uint8_t addr)
|
||||
{
|
||||
return addr & (~TUSB_DIR_IN_MASK);
|
||||
}
|
||||
|
||||
static inline uint8_t edpt_addr(uint8_t num, tusb_dir_t dir)
|
||||
{
|
||||
return num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_TYPES_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,183 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file verify.h
|
||||
@author hathach
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, 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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#ifndef TUSB_VERIFY_H_
|
||||
#define TUSB_VERIFY_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "tusb_option.h"
|
||||
#include "tusb_compiler.h"
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* This file use an advanced macro technique to mimic the default parameter
|
||||
* as C++ for the sake of code simplicity. Beware of a headache macro
|
||||
* manipulation that you are told to stay away.
|
||||
*
|
||||
* e.g
|
||||
*
|
||||
* - VERIFY( cond ) will return false if cond is false
|
||||
* - VERIFY( cond, err) will return err instead if cond is false
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// VERIFY Helper
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUSB_DEBUG >= 1
|
||||
#define _MESS_ERR(_err) printf("%s: %d: failed, error = %s\n", __func__, __LINE__, tusb_strerr[_err])
|
||||
#define _MESS_FAILED() printf("%s: %d: failed\n", __func__, __LINE__)
|
||||
#else
|
||||
#define _MESS_ERR(_err)
|
||||
#define _MESS_FAILED()
|
||||
#endif
|
||||
|
||||
// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
|
||||
#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
|
||||
|
||||
#define verify_breakpoint() \
|
||||
do {\
|
||||
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
|
||||
if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */\
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
#define verify_breakpoint()
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Macro Generator
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
// Helper to implement optional parameter for VERIFY Macro family
|
||||
#define GET_3RD_ARG(arg1, arg2, arg3, ...) arg3
|
||||
#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
|
||||
|
||||
/*------------- Generator for VERIFY and VERIFY_HDLR -------------*/
|
||||
#define VERIFY_DEFINE(_cond, _handler, _ret) do { if ( !(_cond) ) { _handler; return _ret; } } while(0)
|
||||
|
||||
/*------------- Generator for VERIFY_ERR and VERIFY_ERR_HDLR -------------*/
|
||||
#define VERIFY_ERR_DEF2(_error, _handler) \
|
||||
do { \
|
||||
uint32_t _err = (uint32_t)(_error); \
|
||||
if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _err; }\
|
||||
} while(0)
|
||||
|
||||
#define VERIFY_ERR_DEF3(_error, _handler, _ret) \
|
||||
do { \
|
||||
uint32_t _err = (uint32_t)(_error); \
|
||||
if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _ret; }\
|
||||
} while(0)
|
||||
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* VERIFY
|
||||
* - VERIFY_1ARGS : return false if failed
|
||||
* - VERIFY_2ARGS : return provided value if failed
|
||||
*------------------------------------------------------------------*/
|
||||
#define VERIFY_1ARGS(_cond) VERIFY_DEFINE(_cond, , false)
|
||||
#define VERIFY_2ARGS(_cond, _ret) VERIFY_DEFINE(_cond, , _ret)
|
||||
|
||||
#define VERIFY(...) GET_3RD_ARG(__VA_ARGS__, VERIFY_2ARGS, VERIFY_1ARGS)(__VA_ARGS__)
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* VERIFY WITH HANDLER
|
||||
* - VERIFY_HDLR_2ARGS : execute handler, return false if failed
|
||||
* - VERIFY_HDLR_3ARGS : execute handler, return provided error if failed
|
||||
*------------------------------------------------------------------*/
|
||||
#define VERIFY_HDLR_2ARGS(_cond, _handler) VERIFY_DEFINE(_cond, _handler, false)
|
||||
#define VERIFY_HDLR_3ARGS(_cond, _handler, _ret) VERIFY_DEFINE(_cond, _handler, _ret)
|
||||
|
||||
#define VERIFY_HDLR(...) GET_4TH_ARG(__VA_ARGS__, VERIFY_HDLR_3ARGS, VERIFY_HDLR_2ARGS)(__VA_ARGS__)
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* VERIFY STATUS
|
||||
* - VERIFY_ERR_1ARGS : return status of condition if failed
|
||||
* - VERIFY_ERR_2ARGS : return provided status code if failed
|
||||
*------------------------------------------------------------------*/
|
||||
#define VERIFY_ERR_1ARGS(_error) VERIFY_ERR_DEF2(_error, )
|
||||
#define VERIFY_ERR_2ARGS(_error, _ret) VERIFY_ERR_DEF3(_error, ,_ret)
|
||||
|
||||
#define VERIFY_ERR(...) GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__)
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* VERIFY STATUS WITH HANDLER
|
||||
* - VERIFY_ERR_HDLR_2ARGS : execute handler, return status if failed
|
||||
* - VERIFY_ERR_HDLR_3ARGS : execute handler, return provided error if failed
|
||||
*------------------------------------------------------------------*/
|
||||
#define VERIFY_ERR_HDLR_2ARGS(_error, _handler) VERIFY_ERR_DEF2(_error, _handler)
|
||||
#define VERIFY_ERR_HDLR_3ARGS(_error, _handler, _ret) VERIFY_ERR_DEF3(_error, _handler, _ret)
|
||||
|
||||
#define VERIFY_ERR_HDLR(...) GET_4TH_ARG(__VA_ARGS__, VERIFY_ERR_HDLR_3ARGS, VERIFY_ERR_HDLR_2ARGS)(__VA_ARGS__)
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* ASSERT
|
||||
* basically VERIFY with verify_breakpoint() as handler
|
||||
* - 1 arg : return false if failed
|
||||
* - 2 arg : return error if failed
|
||||
*------------------------------------------------------------------*/
|
||||
#define ASSERT_1ARGS(_cond) VERIFY_DEFINE(_cond, _MESS_FAILED(); verify_breakpoint(), false)
|
||||
#define ASSERT_2ARGS(_cond, _ret) VERIFY_DEFINE(_cond, _MESS_FAILED(); verify_breakpoint(), _ret)
|
||||
|
||||
#define TU_ASSERT(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS)(__VA_ARGS__)
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* ASSERT Error
|
||||
* basically VERIFY Error with verify_breakpoint() as handler
|
||||
*------------------------------------------------------------------*/
|
||||
#define ASERT_ERR_1ARGS(_error) VERIFY_ERR_DEF2(_error, verify_breakpoint())
|
||||
#define ASERT_ERR_2ARGS(_error, _ret) VERIFY_ERR_DEF3(_error, verify_breakpoint(), _ret)
|
||||
|
||||
#define TU_ASSERT_ERR(...) GET_3RD_ARG(__VA_ARGS__, ASERT_ERR_2ARGS, ASERT_ERR_1ARGS)(__VA_ARGS__)
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* ASSERT HDLR
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TUSB_VERIFY_H_ */
|
||||
@@ -0,0 +1,118 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file dcd.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 group_usbd
|
||||
* \defgroup group_dcd Device Controller Driver (DCD)
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_DCD_H_
|
||||
#define _TUSB_DCD_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USBD_BUS_EVENT_RESET = 1,
|
||||
USBD_BUS_EVENT_UNPLUGGED,
|
||||
USBD_BUS_EVENT_SOF,
|
||||
USBD_BUS_EVENT_SUSPENDED,
|
||||
USBD_BUS_EVENT_RESUME
|
||||
}usbd_bus_event_type_t;
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Device API (Weak is optional)
|
||||
*------------------------------------------------------------------*/
|
||||
bool dcd_init (uint8_t rhport);
|
||||
void dcd_set_address (uint8_t rhport, uint8_t dev_addr);
|
||||
void dcd_set_config (uint8_t rhport, uint8_t config_num);
|
||||
|
||||
void dcd_connect (uint8_t rhport) ATTR_WEAK;
|
||||
void dcd_disconnect (uint8_t rhport) ATTR_WEAK;
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Event Function
|
||||
* Called by DCD to notify USBD
|
||||
*------------------------------------------------------------------*/
|
||||
void dcd_bus_event (uint8_t rhport, usbd_bus_event_type_t bus_event);
|
||||
void dcd_setup_received (uint8_t rhport, uint8_t const* p_request);
|
||||
void dcd_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, bool succeeded);
|
||||
|
||||
static inline void dcd_control_complete(uint8_t rhport, uint32_t xferred_bytes)
|
||||
{
|
||||
// all control complete is successful !!
|
||||
dcd_xfer_complete(rhport, 0, xferred_bytes, true);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Endpoint API
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
//------------- Non-control Endpoints -------------//
|
||||
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
|
||||
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
|
||||
bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr);
|
||||
|
||||
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr);
|
||||
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
|
||||
|
||||
//------------- Control Endpoint -------------//
|
||||
bool dcd_control_xfer (uint8_t rhport, tusb_dir_t dir, uint8_t * buffer, uint16_t length);
|
||||
|
||||
// Note input dir is value of direction bit in setup packet (i.e DATA stage direction)
|
||||
static inline bool dcd_control_status(uint8_t rhport, tusb_dir_t dir)
|
||||
{
|
||||
// status direction is reversed to one in the setup packet
|
||||
return dcd_control_xfer(rhport, 1-dir, NULL, 0);
|
||||
}
|
||||
|
||||
static inline void dcd_control_stall(uint8_t rhport)
|
||||
{
|
||||
dcd_edpt_stall(rhport, 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_DCD_H_ */
|
||||
|
||||
/// @}
|
||||
@@ -0,0 +1,624 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file usbd.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_DEVICE_SUPPORTED
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
#include "tusb.h"
|
||||
#include "usbd.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
#define USBD_TASK_QUEUE_DEPTH 16
|
||||
|
||||
#ifndef CFG_TUD_TASK_STACKSIZE
|
||||
#define CFG_TUD_TASK_STACKSIZE 150
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_TASK_PRIO
|
||||
#define CFG_TUD_TASK_PRIO 0
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
uint8_t class_code;
|
||||
|
||||
void (* init ) (void);
|
||||
tusb_error_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t* p_length);
|
||||
tusb_error_t (* control_req_st ) (uint8_t rhport, tusb_control_request_t const *);
|
||||
tusb_error_t (* xfer_cb ) (uint8_t rhport, uint8_t ep_addr, tusb_event_t, uint32_t);
|
||||
void (* sof ) (uint8_t rhport);
|
||||
void (* close ) (uint8_t);
|
||||
} usbd_class_driver_t;
|
||||
|
||||
|
||||
enum {
|
||||
USBD_INTERFACE_NUM_MAX = 16 // USB specs specify up to 16 endpoints per device
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
volatile uint8_t state;
|
||||
uint8_t config_num;
|
||||
|
||||
uint8_t interface2class[USBD_INTERFACE_NUM_MAX]; // determine interface number belongs to which class
|
||||
}usbd_device_info_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class & Device Driver
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN uint8_t usbd_enum_buffer[CFG_TUD_ENUM_BUFFER_SIZE];
|
||||
|
||||
tud_desc_init_t _usbd_descs[CONTROLLER_DEVICE_NUMBER];
|
||||
usbd_device_info_t usbd_devices[CONTROLLER_DEVICE_NUMBER];
|
||||
|
||||
static usbd_class_driver_t const usbd_class_drivers[] =
|
||||
{
|
||||
#if CFG_TUD_CDC
|
||||
{
|
||||
.class_code = TUSB_CLASS_CDC,
|
||||
.init = cdcd_init,
|
||||
.open = cdcd_open,
|
||||
.control_req_st = cdcd_control_request_st,
|
||||
.xfer_cb = cdcd_xfer_cb,
|
||||
.sof = cdcd_sof,
|
||||
.close = cdcd_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if DEVICE_CLASS_HID
|
||||
{
|
||||
.class_code = TUSB_CLASS_HID,
|
||||
.init = hidd_init,
|
||||
.open = hidd_open,
|
||||
.control_req_st = hidd_control_request_st,
|
||||
.xfer_cb = hidd_xfer_cb,
|
||||
.sof = NULL,
|
||||
.close = hidd_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_MSC
|
||||
{
|
||||
.class_code = TUSB_CLASS_MSC,
|
||||
.init = mscd_init,
|
||||
.open = mscd_open,
|
||||
.control_req_st = mscd_control_request_st,
|
||||
.xfer_cb = mscd_xfer_cb,
|
||||
.sof = NULL,
|
||||
.close = mscd_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_CUSTOM_CLASS
|
||||
{
|
||||
.class_code = TUSB_CLASS_VENDOR_SPECIFIC,
|
||||
.init = cusd_init,
|
||||
.open = cusd_open,
|
||||
.control_req_st = cusd_control_request_st,
|
||||
.xfer_cb = cusd_xfer_cb,
|
||||
.sof = NULL,
|
||||
.close = cusd_close
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
enum { USBD_CLASS_DRIVER_COUNT = sizeof(usbd_class_drivers) / sizeof(usbd_class_driver_t) };
|
||||
|
||||
//tusb_desc_device_qualifier_t _device_qual =
|
||||
//{
|
||||
// .bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
// .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
// .bcdUSB = 0x0200,
|
||||
// .bDeviceClass =
|
||||
//};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// DCD Event
|
||||
//--------------------------------------------------------------------+
|
||||
typedef enum
|
||||
{
|
||||
USBD_EVENTID_SETUP_RECEIVED = 1,
|
||||
USBD_EVENTID_XFER_DONE,
|
||||
USBD_EVENTID_SOF
|
||||
}usbd_eventid_t;
|
||||
|
||||
typedef struct ATTR_ALIGNED(4)
|
||||
{
|
||||
uint8_t rhport;
|
||||
uint8_t event_id;
|
||||
uint8_t sub_event_id;
|
||||
uint8_t reserved;
|
||||
|
||||
union {
|
||||
tusb_control_request_t setup_received;
|
||||
|
||||
struct { // USBD_EVENTID_XFER_DONE
|
||||
uint8_t ep_addr;
|
||||
uint32_t xferred_byte;
|
||||
}xfer_done;
|
||||
};
|
||||
} usbd_task_event_t;
|
||||
|
||||
VERIFY_STATIC(sizeof(usbd_task_event_t) <= 12, "size is not correct");
|
||||
|
||||
OSAL_TASK_DEF(_usbd_task_def, "usbd", usbd_task, CFG_TUD_TASK_PRIO, CFG_TUD_TASK_STACKSIZE);
|
||||
|
||||
/*------------- event queue -------------*/
|
||||
OSAL_QUEUE_DEF(_usbd_qdef, USBD_TASK_QUEUE_DEPTH, usbd_task_event_t);
|
||||
static osal_queue_t _usbd_q;
|
||||
|
||||
/*------------- control transfer semaphore -------------*/
|
||||
static osal_semaphore_def_t _usbd_sem_def;
|
||||
/*static*/ osal_semaphore_t _usbd_ctrl_sem;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL FUNCTION
|
||||
//--------------------------------------------------------------------+
|
||||
static tusb_error_t proc_set_config_req(uint8_t rhport, uint8_t config_number);
|
||||
static uint16_t get_descriptor(uint8_t rhport, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_n_mounted(uint8_t rhport)
|
||||
{
|
||||
return usbd_devices[rhport].state == TUSB_DEVICE_STATE_CONFIGURED;
|
||||
}
|
||||
|
||||
bool tud_n_set_descriptors(uint8_t rhport, tud_desc_init_t const* desc_cfg)
|
||||
{
|
||||
_usbd_descs[rhport] = *desc_cfg;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// IMPLEMENTATION
|
||||
//--------------------------------------------------------------------+
|
||||
static tusb_error_t proc_control_request_st(uint8_t rhport, tusb_control_request_t const * const p_request);
|
||||
static tusb_error_t usbd_main_st(void);
|
||||
|
||||
tusb_error_t usbd_init (void)
|
||||
{
|
||||
#if (CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE)
|
||||
dcd_init(0);
|
||||
#endif
|
||||
|
||||
#if (CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE)
|
||||
dcd_init(1);
|
||||
#endif
|
||||
|
||||
//------------- Task init -------------//
|
||||
_usbd_q = osal_queue_create(&_usbd_qdef);
|
||||
VERIFY(_usbd_q, TUSB_ERROR_OSAL_QUEUE_FAILED);
|
||||
|
||||
_usbd_ctrl_sem = osal_semaphore_create(&_usbd_sem_def);
|
||||
VERIFY(_usbd_q, TUSB_ERROR_OSAL_SEMAPHORE_FAILED);
|
||||
|
||||
osal_task_create(&_usbd_task_def);
|
||||
|
||||
//------------- Core init -------------//
|
||||
arrclr_( _usbd_descs );
|
||||
|
||||
//------------- class init -------------//
|
||||
for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++)
|
||||
{
|
||||
usbd_class_drivers[i].init();
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper
|
||||
// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with
|
||||
// forever loop cannot have any return at all.
|
||||
void usbd_task( void* param)
|
||||
{
|
||||
(void) param;
|
||||
|
||||
OSAL_TASK_BEGIN
|
||||
usbd_main_st();
|
||||
OSAL_TASK_END
|
||||
}
|
||||
|
||||
static tusb_error_t usbd_main_st(void)
|
||||
{
|
||||
static usbd_task_event_t event;
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
tusb_error_t err;
|
||||
err = TUSB_ERROR_NONE;
|
||||
|
||||
memclr_(&event, sizeof(usbd_task_event_t));
|
||||
|
||||
osal_queue_receive(_usbd_q, &event, OSAL_TIMEOUT_WAIT_FOREVER, &err);
|
||||
|
||||
if ( USBD_EVENTID_SETUP_RECEIVED == event.event_id )
|
||||
{
|
||||
STASK_INVOKE( proc_control_request_st(event.rhport, &event.setup_received), err );
|
||||
}
|
||||
else if (USBD_EVENTID_XFER_DONE == event.event_id)
|
||||
{
|
||||
// TODO only call respective interface callback
|
||||
// Call class handling function. Those does not own the endpoint should check and return
|
||||
for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++)
|
||||
{
|
||||
if ( usbd_class_drivers[i].xfer_cb )
|
||||
{
|
||||
usbd_class_drivers[i].xfer_cb( event.rhport, event.xfer_done.ep_addr, (tusb_event_t) event.sub_event_id, event.xfer_done.xferred_byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (USBD_EVENTID_SOF == event.event_id)
|
||||
{
|
||||
for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++)
|
||||
{
|
||||
if ( usbd_class_drivers[i].sof )
|
||||
{
|
||||
usbd_class_drivers[i].sof( event.rhport );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
STASK_ASSERT(false);
|
||||
}
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROL REQUEST
|
||||
//--------------------------------------------------------------------+
|
||||
static tusb_error_t proc_control_request_st(uint8_t rhport, tusb_control_request_t const * const p_request)
|
||||
{
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
tusb_error_t error;
|
||||
error = TUSB_ERROR_NONE;
|
||||
|
||||
//------------- Standard Request e.g in enumeration -------------//
|
||||
if( TUSB_REQ_RCPT_DEVICE == p_request->bmRequestType_bit.recipient &&
|
||||
TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type )
|
||||
{
|
||||
if ( TUSB_REQ_GET_DESCRIPTOR == p_request->bRequest )
|
||||
{
|
||||
uint8_t const * buffer = NULL;
|
||||
uint16_t const len = get_descriptor(rhport, p_request, &buffer);
|
||||
|
||||
if ( len )
|
||||
{
|
||||
usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, (uint8_t*) buffer, len );
|
||||
}else
|
||||
{
|
||||
dcd_control_stall(rhport); // stall unsupported descriptor
|
||||
}
|
||||
}
|
||||
else if (TUSB_REQ_GET_CONFIGURATION == p_request->bRequest )
|
||||
{
|
||||
memcpy(usbd_enum_buffer, &usbd_devices[rhport].config_num, 1);
|
||||
usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, (uint8_t*) usbd_enum_buffer, 1);
|
||||
}
|
||||
else if ( TUSB_REQ_SET_ADDRESS == p_request->bRequest )
|
||||
{
|
||||
dcd_set_address(rhport, (uint8_t) p_request->wValue);
|
||||
usbd_devices[rhport].state = TUSB_DEVICE_STATE_ADDRESSED;
|
||||
|
||||
#if CFG_TUSB_MCU != OPT_MCU_NRF5X // nrf5x auto handle set address, we must not return status
|
||||
dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
|
||||
#endif
|
||||
}
|
||||
else if ( TUSB_REQ_SET_CONFIGURATION == p_request->bRequest )
|
||||
{
|
||||
proc_set_config_req(rhport, (uint8_t) p_request->wValue);
|
||||
dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
|
||||
}
|
||||
else
|
||||
{
|
||||
dcd_control_stall(rhport); // Stall unsupported request
|
||||
}
|
||||
}
|
||||
|
||||
//------------- Class/Interface Specific Request -------------//
|
||||
else if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient)
|
||||
{
|
||||
static uint8_t drid;
|
||||
uint8_t const class_code = usbd_devices[rhport].interface2class[ u16_low_u8(p_request->wIndex) ];
|
||||
|
||||
for (drid = 0; drid < USBD_CLASS_DRIVER_COUNT; drid++)
|
||||
{
|
||||
if ( usbd_class_drivers[drid].class_code == class_code ) break;
|
||||
}
|
||||
|
||||
if ( (drid < USBD_CLASS_DRIVER_COUNT) && usbd_class_drivers[drid].control_req_st )
|
||||
{
|
||||
STASK_INVOKE( usbd_class_drivers[drid].control_req_st(rhport, p_request), error );
|
||||
}else
|
||||
{
|
||||
dcd_control_stall(rhport); // Stall unsupported request
|
||||
}
|
||||
}
|
||||
|
||||
//------------- Endpoint Request -------------//
|
||||
else if ( TUSB_REQ_RCPT_ENDPOINT == p_request->bmRequestType_bit.recipient &&
|
||||
TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type)
|
||||
{
|
||||
if (TUSB_REQ_CLEAR_FEATURE == p_request->bRequest )
|
||||
{
|
||||
dcd_edpt_clear_stall(rhport, u16_low_u8(p_request->wIndex) );
|
||||
dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
|
||||
} else
|
||||
{
|
||||
dcd_control_stall(rhport); // Stall unsupported request
|
||||
}
|
||||
}
|
||||
|
||||
//------------- Unsupported Request -------------//
|
||||
else
|
||||
{
|
||||
dcd_control_stall(rhport); // Stall unsupported request
|
||||
}
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
// TODO Host (windows) can get HID report descriptor before set configured
|
||||
// may need to open interface before set configured
|
||||
static tusb_error_t proc_set_config_req(uint8_t rhport, uint8_t config_number)
|
||||
{
|
||||
dcd_set_config(rhport, config_number);
|
||||
|
||||
usbd_devices[rhport].state = TUSB_DEVICE_STATE_CONFIGURED;
|
||||
usbd_devices[rhport].config_num = config_number;
|
||||
|
||||
//------------- parse configuration & open drivers -------------//
|
||||
uint8_t const * p_desc_config = _usbd_descs[rhport].configuration;
|
||||
TU_ASSERT(p_desc_config != NULL, TUSB_ERROR_DESCRIPTOR_CORRUPTED);
|
||||
|
||||
uint8_t const * p_desc = p_desc_config + sizeof(tusb_desc_configuration_t);
|
||||
|
||||
uint16_t const config_len = ((tusb_desc_configuration_t*)p_desc_config)->wTotalLength;
|
||||
|
||||
while( p_desc < p_desc_config + config_len )
|
||||
{
|
||||
if ( TUSB_DESC_INTERFACE_ASSOCIATION == p_desc[DESCRIPTOR_OFFSET_TYPE])
|
||||
{
|
||||
p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // ignore Interface Association
|
||||
}else
|
||||
{
|
||||
TU_ASSERT( TUSB_DESC_INTERFACE == p_desc[DESCRIPTOR_OFFSET_TYPE], TUSB_ERROR_NOT_SUPPORTED_YET );
|
||||
|
||||
tusb_desc_interface_t* p_desc_itf = (tusb_desc_interface_t*) p_desc;
|
||||
uint8_t const class_code = p_desc_itf->bInterfaceClass;
|
||||
|
||||
// Check if class is supported
|
||||
uint8_t drid;
|
||||
for (drid = 0; drid < USBD_CLASS_DRIVER_COUNT; drid++)
|
||||
{
|
||||
if ( usbd_class_drivers[drid].class_code == class_code ) break;
|
||||
}
|
||||
TU_ASSERT( drid < USBD_CLASS_DRIVER_COUNT, TUSB_ERROR_NOT_SUPPORTED_YET );
|
||||
|
||||
// Check duplicate interface number TODO support alternate setting
|
||||
TU_ASSERT( 0 == usbd_devices[rhport].interface2class[p_desc_itf->bInterfaceNumber], TUSB_ERROR_FAILED);
|
||||
usbd_devices[rhport].interface2class[p_desc_itf->bInterfaceNumber] = class_code;
|
||||
|
||||
uint16_t length=0;
|
||||
TU_ASSERT_ERR( usbd_class_drivers[drid].open( rhport, p_desc_itf, &length ) );
|
||||
|
||||
TU_ASSERT( length >= sizeof(tusb_desc_interface_t), TUSB_ERROR_FAILED );
|
||||
p_desc += length;
|
||||
}
|
||||
}
|
||||
|
||||
// invoke callback
|
||||
tud_mount_cb(rhport);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
static uint16_t get_descriptor(uint8_t rhport, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer)
|
||||
{
|
||||
tusb_desc_type_t const desc_type = (tusb_desc_type_t) u16_high_u8(p_request->wValue);
|
||||
uint8_t const desc_index = u16_low_u8( p_request->wValue );
|
||||
|
||||
uint8_t const * desc_data = NULL ;
|
||||
uint16_t len = 0;
|
||||
|
||||
//------------- Descriptor Check -------------//
|
||||
tud_desc_init_t const* descs = &_usbd_descs[rhport];
|
||||
|
||||
switch(desc_type)
|
||||
{
|
||||
case TUSB_DESC_DEVICE:
|
||||
desc_data = descs->device;
|
||||
len = sizeof(tusb_desc_device_t);
|
||||
break;
|
||||
|
||||
case TUSB_DESC_CONFIGURATION:
|
||||
desc_data = descs->configuration;
|
||||
len = ((tusb_desc_configuration_t*)descs->configuration)->wTotalLength;
|
||||
break;
|
||||
|
||||
case TUSB_DESC_STRING:
|
||||
// windows sometimes ask for string at index 238 !!!
|
||||
if ( !(desc_index < 100) ) return 0;
|
||||
|
||||
desc_data = descs->string_arr[desc_index];
|
||||
VERIFY( desc_data != NULL, 0 );
|
||||
|
||||
len = desc_data[0]; // first byte of descriptor is its size
|
||||
break;
|
||||
|
||||
case TUSB_DESC_DEVICE_QUALIFIER:
|
||||
// TODO If not highspeed capable stall this request otherwise
|
||||
// return the descriptor that could work in highspeed
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
TU_ASSERT( desc_data != NULL, 0);
|
||||
|
||||
// up to Host's length
|
||||
len = min16_of(p_request->wLength, len );
|
||||
TU_ASSERT( len <= CFG_TUD_ENUM_BUFFER_SIZE, 0);
|
||||
|
||||
// FIXME copy data to enum buffer
|
||||
memcpy(usbd_enum_buffer, desc_data, len);
|
||||
(*pp_buffer) = usbd_enum_buffer;
|
||||
|
||||
return len;
|
||||
}
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-CLASS API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-DCD Callback API
|
||||
//--------------------------------------------------------------------+
|
||||
void dcd_bus_event(uint8_t rhport, usbd_bus_event_type_t bus_event)
|
||||
{
|
||||
switch(bus_event)
|
||||
{
|
||||
case USBD_BUS_EVENT_RESET :
|
||||
memclr_(&usbd_devices[rhport], sizeof(usbd_device_info_t));
|
||||
osal_queue_flush(_usbd_q);
|
||||
osal_semaphore_reset_isr(_usbd_ctrl_sem);
|
||||
for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++)
|
||||
{
|
||||
if ( usbd_class_drivers[i].close ) usbd_class_drivers[i].close( rhport );
|
||||
}
|
||||
break;
|
||||
|
||||
case USBD_BUS_EVENT_SOF:
|
||||
{
|
||||
usbd_task_event_t task_event =
|
||||
{
|
||||
.rhport = rhport,
|
||||
.event_id = USBD_EVENTID_SOF,
|
||||
};
|
||||
osal_queue_send_isr(_usbd_q, &task_event);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBD_BUS_EVENT_UNPLUGGED:
|
||||
// invoke callback
|
||||
tud_umount_cb(rhport);
|
||||
break;
|
||||
|
||||
case USBD_BUS_EVENT_SUSPENDED:
|
||||
usbd_devices[rhport].state = TUSB_DEVICE_STATE_SUSPENDED;
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void dcd_setup_received(uint8_t rhport, uint8_t const* p_request)
|
||||
{
|
||||
usbd_task_event_t task_event =
|
||||
{
|
||||
.rhport = rhport,
|
||||
.event_id = USBD_EVENTID_SETUP_RECEIVED,
|
||||
};
|
||||
|
||||
memcpy(&task_event.setup_received, p_request, sizeof(tusb_control_request_t));
|
||||
osal_queue_send_isr(_usbd_q, &task_event);
|
||||
}
|
||||
|
||||
void dcd_xfer_complete(uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, bool succeeded)
|
||||
{
|
||||
if (ep_addr == 0 )
|
||||
{
|
||||
// Control Transfer
|
||||
(void) rhport;
|
||||
(void) succeeded;
|
||||
|
||||
// only signal data stage, skip status (zero byte)
|
||||
if (xferred_bytes) osal_semaphore_post_isr( _usbd_ctrl_sem );
|
||||
}else
|
||||
{
|
||||
usbd_task_event_t task_event =
|
||||
{
|
||||
.rhport = rhport,
|
||||
.event_id = USBD_EVENTID_XFER_DONE,
|
||||
.sub_event_id = succeeded ? TUSB_EVENT_XFER_COMPLETE : TUSB_EVENT_XFER_ERROR
|
||||
};
|
||||
|
||||
task_event.xfer_done.ep_addr = ep_addr;
|
||||
task_event.xfer_done.xferred_byte = xferred_bytes;
|
||||
|
||||
osal_queue_send_isr(_usbd_q, &task_event);
|
||||
}
|
||||
|
||||
TU_ASSERT(succeeded, );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_error_t usbd_open_edpt_pair(uint8_t rhport, tusb_desc_endpoint_t const* p_desc_ep, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in)
|
||||
{
|
||||
for(int i=0; i<2; i++)
|
||||
{
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == p_desc_ep->bDescriptorType &&
|
||||
xfer_type == p_desc_ep->bmAttributes.xfer, TUSB_ERROR_DESCRIPTOR_CORRUPTED);
|
||||
|
||||
TU_ASSERT( dcd_edpt_open(rhport, p_desc_ep), TUSB_ERROR_DCD_OPEN_PIPE_FAILED );
|
||||
|
||||
if ( p_desc_ep->bEndpointAddress & TUSB_DIR_IN_MASK )
|
||||
{
|
||||
(*ep_in) = p_desc_ep->bEndpointAddress;
|
||||
}else
|
||||
{
|
||||
(*ep_out) = p_desc_ep->bEndpointAddress;
|
||||
}
|
||||
|
||||
p_desc_ep = (tusb_desc_endpoint_t const *) descriptor_next( (uint8_t const*) p_desc_ep );
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,114 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file usbd.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 group_usbd
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_USBD_H_
|
||||
#define _TUSB_USBD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include <common/tusb_common.h>
|
||||
#include "osal/osal.h"
|
||||
#include "device/dcd.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// \brief Descriptor pointer collector to all the needed.
|
||||
typedef struct {
|
||||
uint8_t const * device; ///< pointer to device descriptor \ref tusb_desc_device_t
|
||||
uint8_t const * configuration; ///< pointer to the whole configuration descriptor, starting by \ref tusb_desc_configuration_t
|
||||
uint8_t const** string_arr; ///< a array of pointers to string descriptors
|
||||
|
||||
uint8_t const * p_hid_keyboard_report; ///< pointer to HID report descriptor of Keyboard interface. Only needed if CFG_TUD_HID_KEYBOARD is enabled
|
||||
uint8_t const * p_hid_mouse_report; ///< pointer to HID report descriptor of Mouse interface. Only needed if CFG_TUD_HID_MOUSE is enabled
|
||||
}tud_desc_init_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API (Multiple Root Ports)
|
||||
// Should be used only with MCU that support more than 1 ports
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_n_mounted(uint8_t rhport);
|
||||
bool tud_n_set_descriptors(uint8_t rhport, tud_desc_init_t const* desc_cfg);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API (Single Port)
|
||||
// Should be used with MCU supporting only 1 USB port for code simplicity
|
||||
//--------------------------------------------------------------------+
|
||||
static inline bool tud_mounted(void)
|
||||
{
|
||||
return tud_n_mounted(0);
|
||||
}
|
||||
|
||||
static inline bool tud_set_descriptors(tud_desc_init_t const* desc_cfg)
|
||||
{
|
||||
return tud_n_set_descriptors(0, desc_cfg);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION CALLBACK
|
||||
//--------------------------------------------------------------------+
|
||||
/** \brief Callback function that will be invoked device is mounted (configured) by USB host
|
||||
* \param[in] rhport USB Controller ID of the interface
|
||||
* \note This callback should be used by Application to \b set-up application data
|
||||
*/
|
||||
void tud_mount_cb(uint8_t rhport);
|
||||
|
||||
/** \brief Callback function that will be invoked when device is unmounted (bus reset/unplugged)
|
||||
* \param[in] rhport USB Controller ID of the interface
|
||||
* \note This callback should be used by Application to \b tear-down application data
|
||||
*/
|
||||
void tud_umount_cb(uint8_t rhport);
|
||||
|
||||
//void tud_device_suspended_cb(uint8_t rhport);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_USBD_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,81 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file usbd_pvt.h
|
||||
@author hathach
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, 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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#ifndef USBD_PVT_H_
|
||||
#define USBD_PVT_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// for used by usbd_control_xfer_st() only, must not be used directly
|
||||
extern osal_semaphore_t _usbd_ctrl_sem;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL API
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_error_t usbd_init(void);
|
||||
void usbd_task( void* param);
|
||||
|
||||
// helper to parse an pair of In and Out endpoint descriptors. They must be consecutive
|
||||
tusb_error_t usbd_open_edpt_pair(uint8_t rhport, tusb_desc_endpoint_t const* p_desc_ep, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in);
|
||||
|
||||
// Carry out Data and Status stage of control transfer
|
||||
//tusb_error_t usbd_control_xfer_st(uint8_t rhport, tusb_dir_t dir, uint8_t * buffer, uint16_t length);
|
||||
|
||||
// Carry out Data and Status stage of control transfer
|
||||
// Must be call in a subtask (_st) function
|
||||
#define usbd_control_xfer_st(_rhport, _dir, _buffer, _len) \
|
||||
do {\
|
||||
if (_len) { \
|
||||
tusb_error_t err;\
|
||||
dcd_control_xfer(_rhport, _dir, _buffer, _len);\
|
||||
osal_semaphore_wait( _usbd_ctrl_sem, OSAL_TIMEOUT_CONTROL_XFER, &err );\
|
||||
STASK_ASSERT_ERR( err );\
|
||||
}\
|
||||
/* No need to wait for status to complete therefore */ \
|
||||
/* status phase must not call dcd_control_complete/dcd_xfer_complete*/ \
|
||||
dcd_control_status(_rhport, _dir);\
|
||||
}while(0)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBD_PVT_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,485 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file ehci.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 Group_HCD
|
||||
* @{
|
||||
* \defgroup EHCI
|
||||
* \brief EHCI driver. All documents sources mentioned here (eg section 3.5) is referring to EHCI Specs unless state otherwise
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_EHCI_H_
|
||||
#define _TUSB_EHCI_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "../hcd.h"
|
||||
|
||||
/* Abbreviation
|
||||
* HC: Host Controller
|
||||
* HCD: Host Controller Driver
|
||||
* QHD: Queue Head for non-ISO transfer
|
||||
* QTD: Queue Transfer Descriptor for non-ISO transfer
|
||||
* ITD: Iso Transfer Descriptor for highspeed
|
||||
* SITD: Split ISO Transfer Descriptor for full-speed
|
||||
* SMASK: Start Split mask for Slipt Transaction
|
||||
* CMASK: Complete Split mask for Slipt Transaction
|
||||
* RO: Read Only
|
||||
* R/WC: Read, Write to Clear
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// EHCI CONFIGURATION & CONSTANTS
|
||||
//--------------------------------------------------------------------+
|
||||
#define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enalbed
|
||||
#define EHCI_PERIODIC_LIST (defined HOST_HCD_XFER_INTERRUPT || defined HOST_HCD_XFER_ISOCHRONOUS)
|
||||
|
||||
#define EHCI_CFG_FRAMELIST_SIZE_BITS 7 /// Framelist Size (NXP specific) (0:1024) - (1:512) - (2:256) - (3:128) - (4:64) - (5:32) - (6:16) - (7:8)
|
||||
#define EHCI_FRAMELIST_SIZE (1024 >> EHCI_CFG_FRAMELIST_SIZE_BITS)
|
||||
|
||||
// TODO merge OHCI with EHCI
|
||||
enum {
|
||||
EHCI_MAX_ITD = 4,
|
||||
EHCI_MAX_SITD = 16
|
||||
};
|
||||
|
||||
//------------- Validation -------------//
|
||||
VERIFY_STATIC(EHCI_CFG_FRAMELIST_SIZE_BITS <= 7, "incorrect value");
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// EHCI Data Structure
|
||||
//--------------------------------------------------------------------+
|
||||
enum ehci_queue_element_type_{
|
||||
EHCI_QUEUE_ELEMENT_ITD = 0 , ///< 0
|
||||
EHCI_QUEUE_ELEMENT_QHD , ///< 1
|
||||
EHCI_QUEUE_ELEMENT_SITD , ///< 2
|
||||
EHCI_QUEUE_ELEMENT_FSTN ///< 3
|
||||
};
|
||||
|
||||
/// EHCI PID
|
||||
enum tusb_pid_{
|
||||
EHCI_PID_OUT = 0 ,
|
||||
EHCI_PID_IN ,
|
||||
EHCI_PID_SETUP
|
||||
};
|
||||
|
||||
/// Link pointer
|
||||
typedef union {
|
||||
uint32_t address;
|
||||
struct {
|
||||
uint32_t terminate : 1;
|
||||
uint32_t type : 2;
|
||||
};
|
||||
}ehci_link_t;
|
||||
|
||||
/// Queue Element Transfer Descriptor (section 3.5)
|
||||
typedef struct {
|
||||
|
||||
/// Word 0: Next QTD Pointer
|
||||
ehci_link_t next;
|
||||
|
||||
/// Word 1: Alternate Next QTD Pointer (not used)
|
||||
union{
|
||||
ehci_link_t alternate;
|
||||
struct {
|
||||
uint32_t : 5;
|
||||
uint32_t used : 1;
|
||||
uint32_t : 10;
|
||||
uint32_t expected_bytes : 16;
|
||||
};
|
||||
};
|
||||
|
||||
/// Word 2: qTQ Token
|
||||
volatile uint32_t pingstate_err : 1 ; ///< If the QH.EPSfield indicates a High-speed device and the PID_Codeindicates an OUT endpoint, then this is the state bit for the Ping protocol. 0b=OUT 1b=PING
|
||||
volatile uint32_t non_hs_split_state : 1 ; ///< This bit is ignored by the host controller unless the QH.EPSfield indicates a full- or low-speed endpoint. When a Full- or Low-speed device, the host controller uses this bit to track the state of the split-transaction. The functional requirements of the host controller for managing this state bit and the split transaction protocol depends on whether the endpoint is in the periodic or asynchronous schedule. 0b=Start Split 1b=Complete Split
|
||||
volatile uint32_t non_hs_period_missed_uframe : 1 ; ///< This bit is ignored unless the QH.EPSfield indicates a full- or low-speed endpoint and the queue head is in the periodic list. This bit is set when the host controller detected that a host-induced hold-off caused the host controller to miss a required complete-split transaction. If the host controller sets this bit to a one, then it remains a one for the duration of the transfer.
|
||||
volatile uint32_t xact_err : 1 ; ///< Set to a one by the Host Controller during status update in the case where the host did not receive a valid response from the device (Timeout, CRC, Bad PID, etc.)
|
||||
volatile uint32_t babble_err : 1 ; ///< Set to a 1 by the Host Controller during status update when a babble is detected during the transaction. In addition to setting this bit, the Host Controller also sets the Haltedbit to a 1
|
||||
volatile uint32_t buffer_err : 1 ; ///< Set to a 1 by the Host Controller during status update to indicate that the Host Controller is unable to keep up with the reception of incoming data (overrun) or is unable to supply data fast enough during transmission (underrun)
|
||||
volatile uint32_t halted : 1 ; ///< Set to a 1 by the Host Controller during status updates to indicate that a serious error has occurred at the device/endpoint addressed by this qTD. This can be caused by babble, the error counter counting down to zero, or reception of the STALL handshake from the device during a transaction. Any time that a transaction results in the Halted bit being set to a one, the Active bit is also set to 0
|
||||
volatile uint32_t active : 1 ; ///< Set to 1 by software to enable the execution of transactions by the Host Controller
|
||||
|
||||
uint32_t pid : 2 ; ///< This field is an encoding of the token which should be used for transactions associated with this transfer descriptor. 00=OUT 01=IN 10=SETUP
|
||||
volatile uint32_t cerr : 2 ; ///< Error Counter, This field is a 2-bit down counter that keeps track of the number of consecutive Errors detected while executing this qTD
|
||||
volatile uint32_t current_page : 3 ; ///< This field is used as an index into the qTD buffer pointer list
|
||||
uint32_t int_on_complete : 1 ; ///< If this bit is set to a one, it specifies that when this qTD is completed, the Host Controller should issue an interrupt at the next interrupt threshold
|
||||
|
||||
volatile uint32_t total_bytes : 15 ; ///< This field specifies the total number of bytes to be moved with this transfer descriptor
|
||||
volatile uint32_t data_toggle : 1 ; ///< This is the data toggle sequence bit
|
||||
uint32_t : 0 ; // padding to the end of current storage unit
|
||||
// End of Word 2
|
||||
|
||||
/// Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
|
||||
uint32_t buffer[5];
|
||||
} ehci_qtd_t; // XXX qtd is used to declare overlay in ehci_qhd_t -> cannot be declared with ATTR_ALIGNED(32)
|
||||
|
||||
VERIFY_STATIC( sizeof(ehci_qtd_t) == 32, "size is not correct" );
|
||||
|
||||
/// Queue Head (section 3.6)
|
||||
typedef struct ATTR_ALIGNED(32) {
|
||||
/// Word 0: Queue Head Horizontal Link Pointer
|
||||
ehci_link_t next;
|
||||
|
||||
/// Word 1 : Endpoint Characteristics
|
||||
uint32_t device_address : 7 ; ///< This field selects the specific device serving as the data source or sink
|
||||
uint32_t non_hs_period_inactive_next_xact : 1 ; ///< This bit is used by system software to request that the host controller set the Active bit to zero. See Section 4.12.2.5 for full operational details
|
||||
uint32_t endpoint_number : 4 ; ///< This 4-bit field selects the particular endpoint number on the device serving as the data source or sink.
|
||||
uint32_t endpoint_speed : 2 ; ///< This is the speed of the associated endpoint 00b=Full 01b=Low 10b=High 11b=Reserved
|
||||
uint32_t data_toggle_control : 1 ; ///< This bit specifies where the host controller should get the initial data toggle on an overlay transition. 0b=Ignore DT bit of qTD, 1b=Use DT bit of qTD
|
||||
uint32_t head_list_flag : 1 ; ///< This bit is set by System Software to mark a queue head as being the head of the reclamation list. See Section 4.8 for operational model
|
||||
uint32_t max_package_size : 11 ; ///< This directly corresponds to the maximum packet size of the associated endpoint (wMaxPacketSize)
|
||||
uint32_t non_hs_control_endpoint : 1 ; ///< If the QH.EPSfield indicates the endpoint is not a high-speed device, and the endpoint is an control endpoint, then software must set this bit to a one. Otherwise it should always set this bit to a zero.
|
||||
uint32_t nak_count_reload : 4 ; ///< This field contains a value, which is used by the host controller to reload the Nak Counter field.
|
||||
uint32_t : 0 ; // padding to the end of current storage unit
|
||||
// End of Word 1
|
||||
|
||||
/// Word 2 : Endpoint Capabilities
|
||||
uint32_t interrupt_smask : 8 ; ///< This field is used for all endpoint speeds. Software should set this field to a zero when the queue head is on the asynchronous schedule. A non-zero value in this field indicates an interrupt endpoint
|
||||
uint32_t non_hs_interrupt_cmask : 8 ; ///< This field is ignored by the host controller unless the EPSfield indicates this device is a low- or full-speed device and this queue head is in the periodic list. This field (along with the Activeand SplitX-statefields) is used to determine during which micro-frames the host controller should execute a complete-split transaction
|
||||
uint32_t hub_address : 7 ; ///< This field is ignored by the host controller unless the EPSfield indicates a full- or low-speed device. The value is the USB device address of the USB 2.0 Hub below which the full- or low-speed device associated with this endpoint is attached. This field is used in the split-transaction protocol. See Section 4.12.
|
||||
uint32_t hub_port : 7 ; ///< This field is ignored by the host controller unless the EPSfield indicates a full- or low-speed device. The value is the port number identifier on the USB 2.0 Hub (for hub at device address Hub Addrbelow), below which the full- or low-speed device associated with this endpoint is attached. This information is used in the split-transaction protocol. See Section 4.12.
|
||||
uint32_t mult : 2 ; ///< This field is a multiplier used to key the host controller as the number of successive packets the host controller may submit to the endpoint in the current execution. 00b=Reserved 01b,10b,11b= 1 (2, 3) Transaction for this endpoint/micro frame
|
||||
uint32_t : 0 ; // padding to the end of current storage unit
|
||||
// End of Word 2
|
||||
|
||||
/// Word 3: Current qTD Pointer
|
||||
volatile uint32_t qtd_addr;
|
||||
|
||||
/// Word 4-11: Transfer Overlay
|
||||
volatile ehci_qtd_t qtd_overlay;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
/// Due to the fact QHD is 32 bytes aligned but occupies only 48 bytes
|
||||
/// thus there are 16 bytes padding free that we can make use of.
|
||||
//--------------------------------------------------------------------+
|
||||
uint8_t used;
|
||||
uint8_t is_removing;
|
||||
uint8_t pid_non_control;
|
||||
uint8_t class_code;
|
||||
|
||||
uint16_t total_xferred_bytes; // number of bytes xferred until a qtd with ioc bit set
|
||||
uint8_t interval_ms; // polling interval in frames (or milisecond)
|
||||
uint8_t reserved;
|
||||
|
||||
ehci_qtd_t * volatile p_qtd_list_head; // head of the scheduled TD list
|
||||
ehci_qtd_t * volatile p_qtd_list_tail; // tail of the scheduled TD list
|
||||
} ehci_qhd_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(ehci_qhd_t) == 64, "size is not correct" );
|
||||
|
||||
/// Highspeed Isochronous Transfer Descriptor (section 3.3)
|
||||
typedef struct ATTR_ALIGNED(32) {
|
||||
/// Word 0: Next Link Pointer
|
||||
ehci_link_t next;
|
||||
|
||||
/// Word 1-8: iTD Transaction Status and Control List
|
||||
struct {
|
||||
// iTD Control
|
||||
volatile uint32_t offset : 12 ; ///< This field is a value that is an offset, expressed in bytes, from the beginning of a buffer.
|
||||
volatile uint32_t page_select : 3 ; ///< These bits are set by software to indicate which of the buffer page pointers the offset field in this slot should be concatenated to produce the starting memory address for this transaction. The valid range of values for this field is 0 to 6
|
||||
uint32_t int_on_complete : 1 ; ///< If this bit is set to a one, it specifies that when this transaction completes, the Host Controller should issue an interrupt at the next interrupt threshold
|
||||
volatile uint32_t length : 12 ; ///< For an OUT, this field is the number of data bytes the host controller will send during the transaction. The host controller is not required to update this field to reflect the actual number of bytes transferred during the transfer
|
||||
///< For an IN, the initial value of the field is the number of bytes the host expects the endpoint to deliver. During the status update, the host controller writes back the number of bytes successfully received. The value in this register is the actual byte count
|
||||
// iTD Status
|
||||
volatile uint32_t error : 1 ; ///< Set to a one by the Host Controller during status update in the case where the host did not receive a valid response from the device (Timeout, CRC, Bad PID, etc.). This bit may only be set for isochronous IN transactions.
|
||||
volatile uint32_t babble_err : 1 ; ///< Set to a 1 by the Host Controller during status update when a babble is detected during the transaction
|
||||
volatile uint32_t buffer_err : 1 ; ///< Set to a 1 by the Host Controller during status update to indicate that the Host Controller is unable to keep up with the reception of incoming data (overrun) or is unable to supply data fast enough during transmission (underrun).
|
||||
volatile uint32_t active : 1 ; ///< Set to 1 by software to enable the execution of an isochronous transaction by the Host Controller
|
||||
} xact[8];
|
||||
|
||||
///Word 9-15 Buffer Page Pointer List (Plus)
|
||||
uint32_t BufferPointer[7];
|
||||
|
||||
// // FIXME: Store meta data into buffer pointer reserved for saving memory
|
||||
// /*---------- HCD Area ----------*/
|
||||
// uint32_t used;
|
||||
// uint32_t IhdIdx;
|
||||
// uint32_t reserved[6];
|
||||
} ehci_itd_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(ehci_itd_t) == 64, "size is not correct" );
|
||||
|
||||
/// Split (Full-Speed) Isochronous Transfer Descriptor
|
||||
typedef struct ATTR_ALIGNED(32) {
|
||||
/// Word 0: Next Link Pointer
|
||||
ehci_link_t next;
|
||||
|
||||
/// Word 1: siTD Endpoint Characteristics
|
||||
uint32_t device_address : 7; ///< This field selects the specific device serving as the data source or sink.
|
||||
uint32_t : 1; ///< reserved
|
||||
uint32_t endpoint_number : 4; ///< This 4-bit field selects the particular endpoint number on the device serving as the data source or sink.
|
||||
uint32_t : 4; ///< This field is reserved and should be set to zero.
|
||||
uint32_t hub_address : 7; ///< This field holds the device address of the transaction translators’ hub.
|
||||
uint32_t : 1; ///< reserved
|
||||
uint32_t port_number : 7; ///< This field is the port number of the recipient transaction translator.
|
||||
uint32_t direction : 1; ///< 0 = OUT; 1 = IN. This field encodes whether the full-speed transaction should be an IN or OUT.
|
||||
uint32_t : 0; // padding to the end of current storage unit
|
||||
// End of Word 1
|
||||
|
||||
/// Word 2: Micro-frame Schedule Control
|
||||
uint8_t interrupt_smask ; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute complete-split transactions
|
||||
uint8_t non_hs_interrupt_cmask ; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute start-split transactions.
|
||||
uint16_t reserved ; ///< reserved
|
||||
// End of Word 2
|
||||
|
||||
/// Word 3: siTD Transfer Status and Control
|
||||
// Status [7:0] TODO indentical to qTD Token'status --> refractor later
|
||||
volatile uint32_t : 1 ; // reserved
|
||||
volatile uint32_t split_state : 1 ;
|
||||
volatile uint32_t missed_uframe : 1 ;
|
||||
volatile uint32_t xact_err : 1 ;
|
||||
volatile uint32_t babble_err : 1 ;
|
||||
volatile uint32_t buffer_err : 1 ;
|
||||
volatile uint32_t error : 1 ;
|
||||
volatile uint32_t active : 1 ;
|
||||
// Micro-frame Schedule Control
|
||||
volatile uint32_t cmask_progress : 8 ; ///< This field is used by the host controller to record which split-completes have been executed. See Section 4.12.3.3.2 for behavioral requirements.
|
||||
volatile uint32_t total_bytes : 10 ; ///< This field is initialized by software to the total number of bytes expected in this transfer. Maximum value is 1023
|
||||
volatile uint32_t : 4 ; ///< reserved
|
||||
volatile uint32_t page_select : 1 ; ///< Used to indicate which data page pointer should be concatenated with the CurrentOffsetfield to construct a data buffer pointer
|
||||
uint32_t int_on_complete : 1 ; ///< Do not interrupt when transaction is complete. 1 = Do interrupt when transaction is complete
|
||||
uint32_t : 0 ; // padding to the end of current storage unit
|
||||
// End of Word 3
|
||||
|
||||
/// Word 4-5: Buffer Pointer List
|
||||
uint32_t buffer[2]; // buffer[1] TP: Transaction Position - T-Count: Transaction Count
|
||||
|
||||
// union{
|
||||
// uint32_t BufferPointer1;
|
||||
// struct {
|
||||
// volatile uint32_t TCount : 3;
|
||||
// volatile uint32_t TPosition : 2;
|
||||
// };
|
||||
// };
|
||||
|
||||
/*---------- Word 6 ----------*/
|
||||
ehci_link_t back;
|
||||
|
||||
/// SITD is 32-byte aligned but occupies only 28 --> 4 bytes for storing extra data
|
||||
uint8_t used;
|
||||
uint8_t ihd_idx;
|
||||
uint8_t reserved2[2];
|
||||
} ehci_sitd_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(ehci_sitd_t) == 32, "size is not correct" );
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// EHCI Operational Register
|
||||
//--------------------------------------------------------------------+
|
||||
enum ehci_interrupt_mask_{
|
||||
EHCI_INT_MASK_USB = BIT_(0),
|
||||
EHCI_INT_MASK_ERROR = BIT_(1),
|
||||
EHCI_INT_MASK_PORT_CHANGE = BIT_(2),
|
||||
|
||||
EHCI_INT_MASK_FRAMELIST_ROLLOVER = BIT_(3),
|
||||
EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR = BIT_(4),
|
||||
EHCI_INT_MASK_ASYNC_ADVANCE = BIT_(5),
|
||||
EHCI_INT_MASK_NXP_SOF = BIT_(7),
|
||||
|
||||
EHCI_INT_MASK_NXP_ASYNC = BIT_(18),
|
||||
EHCI_INT_MASK_NXP_PERIODIC = BIT_(19),
|
||||
|
||||
EHCI_INT_MASK_ALL =
|
||||
EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
|
||||
EHCI_INT_MASK_FRAMELIST_ROLLOVER | EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR |
|
||||
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF |
|
||||
EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC
|
||||
};
|
||||
|
||||
enum ehci_usbcmd_pos_ {
|
||||
EHCI_USBCMD_POS_RUN_STOP = 0,
|
||||
EHCI_USBCMD_POS_FRAMELIST_SZIE = 2,
|
||||
EHCI_USBCMD_POS_PERIOD_ENABLE = 4,
|
||||
EHCI_USBCMD_POS_ASYNC_ENABLE = 5,
|
||||
EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB = 15,
|
||||
EHCI_USBCMD_POS_INTERRUPT_THRESHOLD = 16
|
||||
};
|
||||
|
||||
enum ehci_portsc_change_mask_{
|
||||
EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE = BIT_(1),
|
||||
EHCI_PORTSC_MASK_PORT_ENABLE_CHAGNE = BIT_(3),
|
||||
EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE = BIT_(5),
|
||||
|
||||
EHCI_PORTSC_MASK_ALL =
|
||||
EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE |
|
||||
EHCI_PORTSC_MASK_PORT_ENABLE_CHAGNE |
|
||||
EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE
|
||||
};
|
||||
|
||||
typedef volatile struct {
|
||||
union {
|
||||
uint32_t usb_cmd ; ///< The Command Register indicates the command to be executed by the serial bus host controller. Writing to the register causes a command to be executed
|
||||
struct {
|
||||
uint32_t run_stop : 1 ; ///< Default 0b. 1=Run. 0=Stop. When set to a 1, the Host Controller proceeds with execution of the schedule. The Host Controller continues execution as long as this bit is set to a 1. When this bit is set to 0, the Host Controller completes the current and any actively pipelined transactions on the USB and then halts. The Host Controller must halt within 16 micro-frames after software clears the Run bit. The HC Halted bit in the status register indicates when the Host Controller has finished its pending pipelined transactions and has entered the stopped state. Software must not write a one to this field unless the host controller is in the Halted state (i.e. HCHaltedin the USBSTS register is a one). Doing so will yield undefined results.
|
||||
uint32_t reset : 1 ; ///< his control bit is used by software to reset the host controller. The effects of this on Root Hub registers are similar to a Chip Hardware Reset. When software writes a one to this bit, the Host Controller resets its internal pipelines, timers, counters, state machines, etc. to their initial value. Any transaction currently in progress on USB is immediately terminated. A USB reset is not driven on downstream ports.This bit is set to zero by the Host Controller when the reset process is complete. Software cannot terminate the reset process early by writing a zero to this register. Software should not set this bit to a one when the HCHaltedbit in the USBSTS register is a zero. Attempting to reset an actively running host controller will result in undefined behavior.
|
||||
uint32_t framelist_size : 2 ; ///< This field is R/W only if Programmable Frame List Flagin the HCCPARAMS registers is set to a one. This field specifies the size of the frame list.00b 1024 elements (4096 bytes) Default value 01b 512 elements (2048 bytes) 10b 256 elements (1024 bytes)
|
||||
uint32_t periodic_enable : 1 ; ///< This bit controls whether the host controller skips processing the Periodic Schedule. Values mean: 0b Do not process the Periodic Schedule 1b Use the PERIODICLISTBASE register to access the Periodic Schedule.
|
||||
uint32_t async_enable : 1 ; ///< This bit controls whether the host controller skips processing the Asynchronous Schedule. Values mean: 0b Do not process the Asynchronous Schedule 1b Use the ASYNCLISTADDR register to access the Asynchronous Schedule.
|
||||
uint32_t advacne_async : 1 ; ///< This bit is used as a doorbell by software to tell the host controller to issue an interrupt the next time it advances asynchronous schedule. Software must write a 1 to this bit to ringthe doorbell. When the host controller has evicted all appropriate cached schedule state, it sets the Interrupt on Async Advancestatus bit in the USBSTS register. If the Interrupt on Async Advance Enablebit in the USBINTR register is a one then the host controller will assert an interrupt at the next interrupt threshold. See Section 4.8.2 for operational details. The host controller sets this bit to a zero after it has set the Interrupt on Async Advance status bit in the USBSTS register to a one. Software should not write a one to this bit when the asynchronous schedule is disabled. Doing so will yield undefined results.
|
||||
uint32_t light_reset : 1 ; ///< This control bit is not required. If implemented, it allows the driver to reset the EHCI controller without affecting the state of the ports or the relationship to the companion host controllers. For example, the PORSTC registers should not be reset to their default values and the CF bit setting should not go to zero (retaining port ownership relationships). A host software read of this bit as zero indicates the Light Host Controller Reset has completed and it is safe for host software to re-initialize the host controller. A host software read of this bit as a one indicates the Light Host Controller Reset has not yet completed.
|
||||
uint32_t async_park : 2 ; ///< It contains a count of the number of successive transactions the host controller is allowed to execute from a high-speed queue head on the Asynchronous schedule before continuing traversal of the Asynchronous schedule. See Section 4.10.3.2 for full operational details. Valid values are 1h to 3h. Software must not write a zero to this bit when Park Mode Enableis a one as this will result in undefined behavior.
|
||||
uint32_t : 1 ; ///< reserved
|
||||
uint32_t async_park_enable : 1 ; ///< Software uses this bit to enable or disable Park mode. When this bit is one, Park mode is enabled. When this bit is a zero, Park mode is disabled.
|
||||
uint32_t : 3 ; ///< reserved
|
||||
uint32_t nxp_framelist_size_msb : 1 ; ///< NXP customized : Bit 2 of the Frame List Size bits \n 011b: 128 elements \n 100b: 64 elements \n 101b: 32 elements \n 110b: 16 elements \n 111b: 8 elements
|
||||
uint32_t int_threshold : 8 ; ///< Default 08h. This field is used by system software to select the maximum rate at which the host controller will issue interrupts. The only valid values are defined below. If software writes an invalid value to this register, the results are undefined. Value Maximum Interrupt Interval 00h Reserved 01h 1 micro-frame 02h 2 micro-frames 04h 4 micro-frames 08h 8 micro-frames (default, equates to 1 ms) 10h 16 micro-frames (2 ms) 20h 32 micro-frames (4 ms) 40h 64 micro-frames (8 ms) Refer to Section 4.15 for interrupts affected by this register. Any other value in this register yields undefined results. Software modifications to this bit while HCHalted bit is equal to zero results in undefined behavior.
|
||||
uint32_t : 0 ; // padding to the boundary of storage unit
|
||||
}usb_cmd_bit;
|
||||
};
|
||||
|
||||
union {
|
||||
uint32_t usb_sts ; ///< This register indicates pending interrupts and various states of the Host Controller. The status resulting from a transaction on the serial bus is not indicated in this register. Software sets a bit to 0 in this register by writing a 1 to it. See Section 4.15 for additional information concerning USB interrupt conditions.
|
||||
struct {
|
||||
uint32_t usb : 1 ; ///< R/WC The Host Controller sets this bit to 1 on the completion of a USB transaction, which results in the retirement of a Transfer Descriptor that had its IOC bit set. \n The Host Controller also sets this bit to 1 when a short packet is detected (actual number of bytes received was less than the expected number of bytes).
|
||||
uint32_t usb_error : 1 ; ///< R/WC The Host Controller sets this bit to 1 when completion of a USB transaction results in an error condition (e.g., error counter underflow). If the TD on which the error interrupt occurred also had its IOC bit set, both this bit and USBINT bit are set. See Section 4.15.1 for a list of the USB errors that will result in this bit being set to a one.
|
||||
uint32_t port_change_detect : 1 ; ///< R/WC The Host Controller sets this bit to a one when any port for which the Port Ownerbit is set to zero (see Section 2.3.9) has a change bit transition from a zero to a one or a Force Port Resumebit transition from a zero to a one as a result of a J-K transition detected on a suspended port.
|
||||
uint32_t framelist_rollover : 1 ; ///< R/WC The Host Controller sets this bit to a one when the Frame List Index(see Section 2.3.4) rolls over from its maximum value to zero. The exact value at which the rollover occurs depends on the frame list size. For example, if the frame list size (as programmed in the Frame List Sizefield of the USBCMD register) is 1024, the Frame Index Registerrolls over every time FRINDEX[13] toggles. Similarly, if the size is 512, the Host Controller sets this bit to a one every time FRINDEX[12] toggles.
|
||||
uint32_t pci_host_system_error : 1 ; ///< R/WC (not used by NXP) The Host Controller sets this bit to 1 when a serious error occurs during a host system access involving the Host Controller module. In a PCI system, conditions that set this bit to 1 include PCI Parity error, PCI Master Abort, and PCI Target Abort. When this error occurs, the Host Controller clears the Run/Stop bit in the Command register to prevent further execution of the scheduled TDs.
|
||||
uint32_t async_advance : 1 ; ///< R/WC 0=Default. System software can force the host controller to issue an interrupt the next time the host controller advances the asynchronous schedule by writing a one to the Interrupt on Async Advance Doorbell bit in the USBCMD register. This status bit indicates the assertion of that interrupt source.
|
||||
uint32_t : 1 ; ///< These bits are reserved and should be set to zero.
|
||||
uint32_t nxp_int_sof : 1 ; ///< R/WC NXP customized: this bit will be set every 125us and can be used by host controller driver as a time base.
|
||||
uint32_t : 4 ; ///< These bits are reserved and should be set to zero.
|
||||
uint32_t hc_halted : 1 ; ///< Read-Only 1=Default. This bit is a zero whenever the Run/Stop bit is a one. The Host Controller sets this bit to one after it has stopped executing as a result of the Run/Stop bit being set to 0, either by software or by the Host Controller hardware (e.g. internal error).
|
||||
uint32_t reclamation : 1 ; ///< Read-Only 0=Default. This is a read-only status bit, which is used to detect an empty asynchronous schedule. The operational model of empty schedule detection is described in Section 4.8.3. The valid transitions for this bit are described in Section 4.8.6.
|
||||
uint32_t period_schedule_status : 1 ; ///< Read-Only The bit reports the current real status of the Periodic Schedule. If this bit is a zero then the status of the Periodic Schedule is disabled. If this bit is a one then the status of the Periodic Schedule is enabled
|
||||
uint32_t async_schedule_status : 1 ; ///< Read-Only 0=Default. The bit reports the current real status of the Asynchronous Schedule. If this bit is a zero then the status of the Asynchronous Schedule is disabled. If this bit is a one then the status of the Asynchronous Schedule is enabled.
|
||||
uint32_t : 2 ; ///< reseved
|
||||
uint32_t nxp_int_async : 1 ; ///< R/WC NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set andthe TD was from the asynchronous schedule. This bit is also set by the Host when a short packet is detected andthe packet is on the asynchronous schedule.
|
||||
uint32_t nxp_int_period : 1 ; ///< R/WC NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set andthe TD was from the periodic schedule.
|
||||
uint32_t : 12 ; ///< reserved
|
||||
uint32_t : 0 ; // padding to the boundary of storage unit
|
||||
}usb_sts_bit;
|
||||
};
|
||||
|
||||
union{
|
||||
uint32_t usb_int_enable ; ///< This register enables and disables reporting of the corresponding interrupt to the software. When a bit is set and the corresponding interrupt is active, an interrupt is generated to the host. Interrupt sources that are disabled in this register still appear in the USBSTS to allow the software to poll for events.
|
||||
struct {
|
||||
uint32_t usb : 1 ; ///< When this bit is a one, and the USBINT bit in the USBSTS register is a one, the host controller will issue an interrupt at the next interrupt threshold. The interrupt is acknowledged by software clearing the USBINTbit.
|
||||
uint32_t usb_error : 1 ; ///< When this bit is a one, and the USBERRINT bit in the USBSTS register is a one, the host controller will issue an interrupt at the next interrupt threshold. The interrupt is acknowledged by software clearing the USBERRINTbit.
|
||||
uint32_t port_change_detect : 1 ; ///< When this bit is a one, and the Port Change Detect bit in the USBSTS register is a one, the host controller will issue an interrupt. The interrupt is acknowledged by software clearing the Port Change Detectbit.
|
||||
uint32_t framelist_rollover : 1 ; ///< When this bit is a one, and the Frame List Rolloverbit in the USBSTS register is a one, the host controller will issue an interrupt. The interrupt is acknowledged by software clearing the Frame List Rollover bit.
|
||||
uint32_t pci_host_system_error : 1 ; ///< (not used by NXP) When this bit is a one, and the Host System Error Statusbit in the USBSTS register is a one, the host controller will issue an interrupt. The interrupt is acknowledged by software clearing the Host System Error bit.
|
||||
uint32_t async_advance : 1 ; ///< When this bit is a one, and the Interrupt on Async Advancebit in the USBSTS register is a one, the host controller will issue an interrupt at the next interrupt threshold. The interrupt is acknowledged by software clearing the Interrupt on Async Advancebit.
|
||||
uint32_t : 1 ; ///< reserved
|
||||
uint32_t nxp_int_sof : 1 ; ///< NXP customized: if this bit is one and the SRI bit in the USBSTS register is one, the host controller will issue an interrupt. In host mode, the SRI bit will be set every 125 micro sec and can be used by the host controller as a time base. The interrupt is acknowledged by software clearing the SRI bit in the USBSTS register.
|
||||
uint32_t : 10 ; ///< reserved
|
||||
uint32_t nxp_int_async : 1 ; ///< NXP customized: When this bit is a one, and the USBHSTASYNCINT bit in the USBSTS register is a one, the host controller will issue an interrupt at the next interrupt threshold. The interrupt is acknowledged by software clearing the USBHSTASYNCINT bit.
|
||||
uint32_t nxp_int_period : 1 ; ///< NXP customized: When this bit is a one, and the USBHSTPERINT bit in the USBSTS register is a one, the host controller will issue an interrupt at the next interrupt threshold. The interrupt is acknowledged by software clearing the USBHSTPERINT bit.
|
||||
uint32_t : 12 ; ///< reserved
|
||||
uint32_t : 0 ; // padding to the boundary of storage unit
|
||||
}usb_int_enable_bit;
|
||||
};
|
||||
|
||||
uint32_t frame_index ; ///< This register is used by the host controller to index into the periodic frame list. The register updates every 125 microseconds (once each micro-frame). Bits [N:3] are used to select a particular entry in the Periodic Frame List during periodic schedule execution. The number of bits used for the index depends on the size of the frame list as set by system software in the Frame List Sizefield in the USBCMD register
|
||||
uint32_t ctrl_ds_seg ; ///< (not used by NXP) This 32-bit register corresponds to the most significant address bits [63:32] for all EHCI data structures. If the 64-bit Addressing Capabilityfield in HCCPARAMS is a zero, then this register is not used
|
||||
uint32_t periodic_list_base ; ///< This 32-bit register contains the beginning address of the Periodic Frame List in the system memory. System software loads this register prior to starting the schedule execution by the Host Controller (see 4.1). The memory structure referenced by this physical memory pointer is assumed to be 4-Kbyte aligned. The contents of this register are combined with the Frame Index Register (FRINDEX) to enable the Host Controller to step through the Periodic Frame List in sequence.
|
||||
uint32_t async_list_base ; ///< This 32-bit register contains the address of the next asynchronous queue head to be executed. Bits [4:0] of this register cannot be modified by system software and will always return a zero when read. The memory structure referenced by this physical memory pointer is assumed to be 32-byte (cache line) aligned
|
||||
uint32_t tt_control ; ///< nxp embedded transaction translator (reserved by EHCI specs)
|
||||
uint32_t reserved[8] ; ///< reserved by EHCI specs
|
||||
uint32_t config_flag ; ///< (not used by NXP) configured flag register
|
||||
|
||||
union {
|
||||
uint32_t portsc ; ///< port status and control
|
||||
struct {
|
||||
uint32_t current_connect_status : 1; ///< RO 1=Device is present on port. 0=No device is present. Default = 0. This value reflects the current state of the port, and may not correspond directly to the event that caused the Connect Status Change bit (Bit 1) to be set. This field is zero if Port Power is zero.
|
||||
uint32_t connect_status_change : 1; ///< R/WC 1=Change in Current Connect Status. 0=No change. Default = 0. Indicates a change has occurred in the port's Current Connect Status. The host controller sets this bit for all changes to the port device connect status, even if system software has not cleared an existing connect status change. For example, the insertion status changes twice before system software has cleared the changed condition, hub hardware will be "setting" an already-set bit (i.e., the bit will remain set). Software sets this bit to 0 by writing a 1 to it. This field is zero if Port Power is zero.
|
||||
uint32_t port_enable : 1; ///< 1=Enable. 0=Disable. Default = 0. Ports can only be enabled by the host controller as a part of the reset and enable. Software cannot enable a port by writing a one to this field. The host controller will only set this bit to a one when the reset sequence determines that the attached device is a high-speed device. Ports can be disabled by either a fault condition (disconnect event or other fault condition) or by host software. Note that the bit status does not change until the port state actually changes.
|
||||
uint32_t port_enable_change : 1; ///< R/WC 1=Port enabled/disabled status has changed. 0=No change. Default = 0. For the root hub, this bit gets set to a one only when a port is disabled due to the appropriate conditions existing at the EOF2 point (See Chapter 11 of the USB Specification for the definition of a Port Error). Software clears this bit by writing a 1 to it. This field is zero if Port Power is zero.
|
||||
uint32_t over_current_active : 1; ///< RO Default = 0. 1=This port currently has an over-current condition. 0=This port does not have an over-current condition. This bit will automatically transition from a one to a zero when the over current condition is removed.
|
||||
uint32_t over_current_change : 1; ///< R/WC Default = 0. 1=This bit gets set to a one when there is a change to Over-current Active. Software clears this bit by writing a one to this bit position.
|
||||
uint32_t force_port_resume : 1; ///< 1= Resume detected/driven on port. 0=No resume (K-state) detected/driven on port. Default = 0. This functionality defined for manipulating this bit depends on the value of the Suspendbit. For example, if the port is not suspended (Suspendand Enabledbits are a one) and software transitions this bit to a one, then the effects on the bus are undefined. Software sets this bit to a 1 to drive resume signaling. The Host Controller sets this bit to a 1 if a J-to-K transition is detected while the port is in the Suspend state. When this bit transitions to a one because a J-to-K transition is detected, the Port Change Detectbit in the USBSTS register is also set to a one. If software sets this bit to a one, the host controller must not set the Port Change Detectbit.
|
||||
uint32_t suspend : 1; ///< 1=Port in suspend state. 0=Port not in suspend state. Default = 0. Port Enabled Bit and Suspend bit of this register define the port states as follows: Bits [Port Enabled, Suspend] Port State 0X Disable 10 Enable 11 Suspend When in suspend state, downstream propagation of data is blocked on this port, except for port reset. The blocking occurs at the end of the current transaction, if a transaction was in progress when this bit was written to 1. In the suspend state, the port is sensitive to resume detection. Note that the bit status does not change until the port is suspended and that there may be a delay in suspending a port if there is a transaction currently in progress on the USB. A write of zero to this bit is ignored by the host controller. The host controller will unconditionally set this bit to a zero when: •Software sets the Force Port Resumebit to a zero (from a one). •Software sets the Port Resetbit to a one (from a zero).
|
||||
uint32_t port_reset : 1; ///< 1=Port is in Reset. 0=Port is not in Reset. Default = 0. When software writes a one to this bit (from a zero)
|
||||
uint32_t nxp_highspeed_status : 1; ///< NXP customized: 0=connected to the port is not in High-speed mode, 1=connected to the port is in High-speed mode
|
||||
uint32_t line_status : 2; ///< hese bits reflect the current logical levels of the D+ (bit 11) and D- (bit 10) signal lines. These bits are used for detection of low-speed USB devices prior to the port reset and enable sequence. This field is valid only when the port enable bit is zero and the current connect status bit is set to a one. The encoding of the bits are: 00b SE0, 10b J-state, 01b K-state, 11b undefined
|
||||
uint32_t port_power : 1; ///< 0= power off, 1= power on, Host/OTG controller requires port power control switches. This bit represents the current setting of the switch (0=off, 1=on). When power is not available on a port (i.e. PP equals a 0), the port is non-functional and will not report attaches, detaches, etc. When an over-current condition is detected on a powered port and PPC is a one, the PP bit in each affected port may be transitioned by the host controller driver from a one to a zero (removing power from the port).
|
||||
uint32_t port_owner : 1; ///< (not used by NXP)
|
||||
uint32_t port_indicator_control : 2; ///< Writing to this field effects the value of the pins USB0_IND1 and USB0_IND0. 00b: Port indication is off, 01b: Amber, 10b: green, 11b: undefined
|
||||
uint32_t port_test_control : 4; ///< When this field is zero, the port is NOT operating in a test mode. A non-zero value indicates that it is operating in test mode
|
||||
uint32_t wake_on_connect_enable : 1; ///< Default = 0b. Writing this bit to a one enables the port to be sensitive to device connects as wake-up events. See Section 4.3 for effects of this bit on resume event behavior. Refer to Section 4.3.1 for operational model.
|
||||
uint32_t wake_on_disconnect_enable : 1; ///< Default = 0b. Writing this bit to a one enables the port to be sensitive to device disconnects as wake-up events. See Section 4.3 for effects of this bit on resume event behavior. Refer to Section 4.3.1 for operational model.
|
||||
uint32_t wake_on_over_current_enable : 1; ///< Default = 0b. Writing this bit to a one enables the port to be sensitive to over-current conditions as wake-up events. See Section 4.3 for effects of this bit on resume event behavior. Refer to Section 4.3.1 for operational model.
|
||||
uint32_t nxp_phy_clock_disable : 1; ///< NXP customized: the PHY can be put into Low Power Suspend – Clock Disable when the downstream device has been put into suspend mode or when no downstream device is connected. Low power suspend is completely under the control of software. 0: enable PHY clock, 1: disable PHY clock
|
||||
uint32_t nxp_port_force_fullspeed : 1; ///< NXP customized: Writing this bit to a 1 will force the port to only connect at Full Speed. It disables the chirp sequence that allowsthe port to identify itself as High Speed. This is useful for testing FS configurations with a HS host, hub or device.
|
||||
uint32_t : 1;
|
||||
uint32_t nxp_port_speed : 2; ///< NXP customized: This register field indicates the speed atwhich the port is operating. For HS mode operation in the host controllerand HS/FS operation in the device controller the port routing steers data to the Protocol engine. For FS and LS mode operation in the host controller, the port routing steers data to the Protocol Engine w/ Embedded Transaction Translator. 0x0: Fullspeed, 0x1: Lowspeed, 0x2: Highspeed
|
||||
uint32_t : 0; // padding to the boundary of storage unit
|
||||
}portsc_bit;
|
||||
};
|
||||
}ehci_registers_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// EHCI Data Organization
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
//------------- Static Async/Period List Head, Each for one controller -------------//
|
||||
ehci_qhd_t async_head[CONTROLLER_HOST_NUMBER]; /// head qhd of async list, also is used as control endpoint for address 0
|
||||
|
||||
#if EHCI_PERIODIC_LIST
|
||||
// for NXP ECHI, only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist)
|
||||
// [0] : 1ms, [1] : 2ms, [2] : 4ms, [3] : 8 ms
|
||||
ehci_qhd_t period_head_arr[CONTROLLER_HOST_NUMBER][4];
|
||||
#endif
|
||||
|
||||
//------------- Data for Address 0 (use async head as its queue head) -------------//
|
||||
ehci_qtd_t addr0_qtd[3];
|
||||
|
||||
struct {
|
||||
struct {
|
||||
ehci_qhd_t qhd;
|
||||
ehci_qtd_t qtd[3];
|
||||
}control;
|
||||
|
||||
ehci_qhd_t qhd[HCD_MAX_ENDPOINT] ; ///< Queue Head Pool
|
||||
ehci_qtd_t qtd[HCD_MAX_XFER] ATTR_ALIGNED(32) ; ///< Queue Element Transfer Pool
|
||||
// ehci_itd_t itd[EHCI_MAX_ITD] ; ///< Iso Transfer Pool
|
||||
// ehci_sitd_t sitd[EHCI_MAX_SITD] ; ///< Split (FS) Isochronous Transfer Pool
|
||||
}device[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
}ehci_data_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_EHCI_H_ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file hcd.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 "hcd.h"
|
||||
|
||||
#if MODE_HOST_SUPPORTED
|
||||
|
||||
|
||||
#endif
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file hcd.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 group_usbh
|
||||
* \defgroup Group_HCD Host Controller Driver (HCD)
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_HCD_H_
|
||||
#define _TUSB_HCD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <common/tusb_common.h>
|
||||
|
||||
#if MODE_HOST_SUPPORTED
|
||||
// Max number of endpoints per device
|
||||
enum {
|
||||
HCD_MAX_ENDPOINT = CFG_TUSB_HOST_HUB + CFG_TUSB_HOST_HID_KEYBOARD + CFG_TUSB_HOST_HID_MOUSE + CFG_TUSB_HOST_HID_GENERIC +
|
||||
CFG_TUSB_HOST_MSC*2 + CFG_TUSB_HOST_CDC*3,
|
||||
|
||||
HCD_MAX_XFER = HCD_MAX_ENDPOINT*2,
|
||||
};
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
uint8_t dev_addr;
|
||||
uint8_t xfer_type;
|
||||
uint8_t index;
|
||||
uint8_t reserved;
|
||||
} pipe_handle_t;
|
||||
|
||||
static inline bool pipehandle_is_valid(pipe_handle_t pipe_hdl) ATTR_CONST ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT;
|
||||
static inline bool pipehandle_is_valid(pipe_handle_t pipe_hdl)
|
||||
{
|
||||
return pipe_hdl.dev_addr > 0;
|
||||
}
|
||||
|
||||
static inline bool pipehandle_is_equal(pipe_handle_t x, pipe_handle_t y) ATTR_CONST ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT;
|
||||
static inline bool pipehandle_is_equal(pipe_handle_t x, pipe_handle_t y)
|
||||
{
|
||||
return (x.dev_addr == y.dev_addr) && (x.xfer_type == y.xfer_type) && (x.index == y.index);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-HCD API
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_error_t hcd_init(void) ATTR_WARN_UNUSED_RESULT;
|
||||
void hal_hcd_isr(uint8_t hostid);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
// TODO control xfer should be used via usbh layer
|
||||
tusb_error_t hcd_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) ATTR_WARN_UNUSED_RESULT;
|
||||
tusb_error_t hcd_pipe_control_xfer(uint8_t dev_addr, tusb_control_request_t const * p_request, uint8_t data[]) ATTR_WARN_UNUSED_RESULT;
|
||||
tusb_error_t hcd_pipe_control_close(uint8_t dev_addr) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
pipe_handle_t hcd_pipe_open(uint8_t dev_addr, tusb_desc_endpoint_t const * endpoint_desc, uint8_t class_code) ATTR_WARN_UNUSED_RESULT;
|
||||
tusb_error_t hcd_pipe_queue_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes) ATTR_WARN_UNUSED_RESULT; // only queue, not transferring yet
|
||||
tusb_error_t hcd_pipe_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete) ATTR_WARN_UNUSED_RESULT;
|
||||
tusb_error_t hcd_pipe_close(pipe_handle_t pipe_hdl) /*ATTR_WARN_UNUSED_RESULT*/;
|
||||
|
||||
bool hcd_pipe_is_busy(pipe_handle_t pipe_hdl) ATTR_PURE;
|
||||
bool hcd_pipe_is_error(pipe_handle_t pipe_hdl) ATTR_PURE;
|
||||
bool hcd_pipe_is_stalled(pipe_handle_t pipe_hdl) ATTR_PURE; // stalled also counted as error
|
||||
|
||||
uint8_t hcd_pipe_get_endpoint_addr(pipe_handle_t pipe_hdl) ATTR_PURE;
|
||||
tusb_error_t hcd_pipe_clear_stall(pipe_handle_t pipe_hdl);
|
||||
|
||||
#if 0
|
||||
tusb_error_t hcd_pipe_cancel()ATTR_WARN_UNUSED_RESULT;
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PORT API
|
||||
//--------------------------------------------------------------------+
|
||||
/// return the current connect status of roothub port
|
||||
bool hcd_port_connect_status(uint8_t hostid) ATTR_PURE ATTR_WARN_UNUSED_RESULT; // TODO make inline if possible
|
||||
void hcd_port_reset(uint8_t hostid);
|
||||
tusb_speed_t hcd_port_speed_get(uint8_t hostid) ATTR_PURE ATTR_WARN_UNUSED_RESULT; // TODO make inline if possible
|
||||
void hcd_port_unplug(uint8_t hostid); // called by usbh to instruct hcd that it can execute unplug procedure
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HCD_H_ */
|
||||
|
||||
/// @}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file hub.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 && CFG_TUSB_HOST_HUB)
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "hub.h"
|
||||
#include "usbh_hub.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
pipe_handle_t pipe_status;
|
||||
uint8_t interface_number;
|
||||
uint8_t port_number;
|
||||
uint8_t status_change; // data from status change interrupt endpoint
|
||||
}usbh_hub_t;
|
||||
|
||||
CFG_TUSB_ATTR_USBRAM STATIC_VAR usbh_hub_t hub_data[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
ATTR_ALIGNED(4) CFG_TUSB_ATTR_USBRAM STATIC_VAR uint8_t hub_enum_buffer[sizeof(descriptor_hub_desc_t)];
|
||||
|
||||
//OSAL_SEM_DEF(hub_enum_semaphore);
|
||||
//static osal_semaphore_handle_t hub_enum_sem_hdl;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HUB
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_error_t hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature)
|
||||
{
|
||||
tusb_error_t error;
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
STASK_ASSERT(HUB_FEATURE_PORT_CONNECTION_CHANGE <= feature &&
|
||||
feature <= HUB_FEATURE_PORT_RESET_CHANGE);
|
||||
|
||||
//------------- Clear Port Feature request -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( hub_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_OTHER),
|
||||
HUB_REQUEST_CLEAR_FEATURE, feature, hub_port,
|
||||
0, NULL ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR( error );
|
||||
|
||||
//------------- Get Port Status to check if feature is cleared -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( hub_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_OTHER),
|
||||
HUB_REQUEST_GET_STATUS, 0, hub_port,
|
||||
4, hub_enum_buffer ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR( error );
|
||||
|
||||
//------------- Check if feature is cleared -------------//
|
||||
hub_port_status_response_t * p_port_status;
|
||||
p_port_status = (hub_port_status_response_t *) hub_enum_buffer;
|
||||
|
||||
STASK_ASSERT( !BIT_TEST_(p_port_status->status_change.value, feature-16) );
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
tusb_error_t hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port)
|
||||
{
|
||||
enum { RESET_DELAY = 200 }; // USB specs say only 50ms but many devices require much longer
|
||||
tusb_error_t error;
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
//------------- Set Port Reset -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( hub_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_OTHER),
|
||||
HUB_REQUEST_SET_FEATURE, HUB_FEATURE_PORT_RESET, hub_port,
|
||||
0, NULL ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR( error );
|
||||
|
||||
osal_task_delay(RESET_DELAY); // TODO Hub wait for Status Endpoint on Reset Change
|
||||
|
||||
//------------- Get Port Status to check if port is enabled, powered and reset_change -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( hub_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_OTHER),
|
||||
HUB_REQUEST_GET_STATUS, 0, hub_port,
|
||||
4, hub_enum_buffer ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR( error );
|
||||
|
||||
hub_port_status_response_t * p_port_status;
|
||||
p_port_status = (hub_port_status_response_t *) hub_enum_buffer;
|
||||
|
||||
STASK_ASSERT ( p_port_status->status_change.reset && p_port_status->status_current.connect_status &&
|
||||
p_port_status->status_current.port_power && p_port_status->status_current.port_enable);
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
// can only get the speed RIGHT AFTER hub_port_reset_subtask call
|
||||
tusb_speed_t hub_port_get_speed(void)
|
||||
{
|
||||
hub_port_status_response_t * p_port_status = (hub_port_status_response_t *) hub_enum_buffer;
|
||||
return (p_port_status->status_current.high_speed_device_attached) ? TUSB_SPEED_HIGH :
|
||||
(p_port_status->status_current.low_speed_device_attached ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CLASS-USBH API (don't require to verify parameters)
|
||||
//--------------------------------------------------------------------+
|
||||
void hub_init(void)
|
||||
{
|
||||
memclr_(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof(usbh_hub_t));
|
||||
// hub_enum_sem_hdl = osal_semaphore_create( OSAL_SEM_REF(hub_enum_semaphore) );
|
||||
}
|
||||
|
||||
tusb_error_t hub_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length)
|
||||
{
|
||||
tusb_error_t error;
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
// not support multiple TT yet
|
||||
if ( p_interface_desc->bInterfaceProtocol > 1 ) return TUSB_ERROR_HUB_FEATURE_NOT_SUPPORTED;
|
||||
|
||||
//------------- Open Interrupt Status Pipe -------------//
|
||||
tusb_desc_endpoint_t const *p_endpoint;
|
||||
p_endpoint = (tusb_desc_endpoint_t const *) descriptor_next( (uint8_t const*) p_interface_desc );
|
||||
|
||||
STASK_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType);
|
||||
STASK_ASSERT(TUSB_XFER_INTERRUPT == p_endpoint->bmAttributes.xfer);
|
||||
|
||||
hub_data[dev_addr-1].pipe_status = hcd_pipe_open(dev_addr, p_endpoint, TUSB_CLASS_HUB);
|
||||
STASK_ASSERT( pipehandle_is_valid(hub_data[dev_addr-1].pipe_status) );
|
||||
hub_data[dev_addr-1].interface_number = p_interface_desc->bInterfaceNumber;
|
||||
|
||||
(*p_length) = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
//------------- Get Hub Descriptor -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_DEVICE),
|
||||
HUB_REQUEST_GET_DESCRIPTOR, 0, 0,
|
||||
sizeof(descriptor_hub_desc_t), hub_enum_buffer ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
// only care about this field in hub descriptor
|
||||
hub_data[dev_addr-1].port_number = ((descriptor_hub_desc_t*) hub_enum_buffer)->bNbrPorts;
|
||||
|
||||
//------------- Set Port_Power on all ports -------------//
|
||||
static uint8_t i;
|
||||
for(i=1; i <= hub_data[dev_addr-1].port_number; i++)
|
||||
{
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_OTHER),
|
||||
HUB_REQUEST_SET_FEATURE, HUB_FEATURE_PORT_POWER, i,
|
||||
0, NULL ),
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
//------------- Queue the initial Status endpoint transfer -------------//
|
||||
STASK_ASSERT_ERR ( hcd_pipe_xfer(hub_data[dev_addr-1].pipe_status, &hub_data[dev_addr-1].status_change, 1, true) );
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
// is the response of interrupt endpoint polling
|
||||
void hub_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports
|
||||
|
||||
usbh_hub_t * p_hub = &hub_data[pipe_hdl.dev_addr-1];
|
||||
|
||||
if ( event == TUSB_EVENT_XFER_COMPLETE )
|
||||
{
|
||||
for (uint8_t port=1; port <= p_hub->port_number; port++)
|
||||
{ // TODO HUB ignore bit0 hub_status_change
|
||||
if ( BIT_TEST_(p_hub->status_change, port) )
|
||||
{
|
||||
usbh_hub_port_plugged_isr(pipe_hdl.dev_addr, port);
|
||||
break; // handle one port at a time, next port if any will be handled in the next cycle
|
||||
}
|
||||
}
|
||||
// NOTE: next status transfer is queued by usbh.c after handling this request
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO [HUB] check if hub is still plugged before polling status endpoint since failed usually mean hub unplugged
|
||||
// TU_ASSERT ( TUSB_ERROR_NONE == hcd_pipe_xfer(pipe_hdl, &p_hub->status_change, 1, true) );
|
||||
}
|
||||
}
|
||||
|
||||
void hub_close(uint8_t dev_addr)
|
||||
{
|
||||
(void) hcd_pipe_close(hub_data[dev_addr-1].pipe_status);
|
||||
memclr_(&hub_data[dev_addr-1], sizeof(usbh_hub_t));
|
||||
|
||||
// osal_semaphore_reset(hub_enum_sem_hdl);
|
||||
}
|
||||
|
||||
tusb_error_t hub_status_pipe_queue(uint8_t dev_addr)
|
||||
{
|
||||
return hcd_pipe_xfer(hub_data[dev_addr-1].pipe_status, &hub_data[dev_addr-1].status_change, 1, true);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file hub.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 group_class
|
||||
* \defgroup ClassDriver_Hub Hub (Host only)
|
||||
* \details Like most PC's OS, Hub support is completely hidden from Application. In fact, application cannot determine whether
|
||||
* a device is mounted directly via roothub or via a hub's port. All Hub-related procedures are performed and managed
|
||||
* by tinyusb stack. Unless you are trying to develop the stack itself, there are nothing else can be used by Application.
|
||||
* \note Due to my laziness, only 1-level of Hub is supported. In other way, the stack cannot mount a hub via another hub.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_HUB_H_
|
||||
#define _TUSB_HUB_H_
|
||||
|
||||
#include <common/tusb_common.h>
|
||||
#include "usbh.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//D1...D0: Logical Power Switching Mode
|
||||
//00: Ganged power switching (all ports’power at
|
||||
//once)
|
||||
//01: Individual port power switching
|
||||
//1X: Reserved. Used only on 1.0 compliant hubs
|
||||
//that implement no power switching
|
||||
//D2: Identifies a Compound Device
|
||||
//0: Hub is not part of a compound device.
|
||||
//1: Hub is part of a compound device.
|
||||
//D4...D3: Over-current Protection Mode
|
||||
//00: Global Over-current Protection. The hub
|
||||
//reports over-current as a summation of all
|
||||
//ports’current draw, without a breakdown of
|
||||
//individual port over-current status.
|
||||
//01: Individual Port Over-current Protection. The
|
||||
//hub reports over-current on a per-port basis.
|
||||
//Each port has an over-current status.
|
||||
//1X: No Over-current Protection. This option is
|
||||
//allowed only for bus-powered hubs that do not
|
||||
//implement over-current protection.
|
||||
//
|
||||
//D6...D5: TT Think TIme
|
||||
//00: TT requires at most 8 FS bit times of inter
|
||||
//transaction gap on a full-/low-speed
|
||||
//downstream bus.
|
||||
//01: TT requires at most 16 FS bit times.
|
||||
//10: TT requires at most 24 FS bit times.
|
||||
//11: TT requires at most 32 FS bit times.
|
||||
//D7: Port Indicators Supported
|
||||
//0: Port Indicators are not supported on its
|
||||
//downstream facing ports and the
|
||||
//PORT_INDICATOR request has no effect.
|
||||
//1: Port Indicators are supported on its
|
||||
//downstream facing ports and the
|
||||
//PORT_INDICATOR request controls the
|
||||
//indicators. See Section 11.5.3.
|
||||
//D15...D8: Reserved
|
||||
|
||||
typedef struct ATTR_PACKED{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
uint8_t bNbrPorts;
|
||||
uint16_t wHubCharacteristics;
|
||||
uint8_t bPwrOn2PwrGood;
|
||||
uint8_t bHubContrCurrent;
|
||||
uint8_t DeviceRemovable; // bitmap each bit for a port (from bit1)
|
||||
uint8_t PortPwrCtrlMask; // just for compatibility, should be 0xff
|
||||
} descriptor_hub_desc_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(descriptor_hub_desc_t) == 9, "size is not correct");
|
||||
|
||||
enum {
|
||||
HUB_REQUEST_GET_STATUS = 0 ,
|
||||
HUB_REQUEST_CLEAR_FEATURE = 1 ,
|
||||
|
||||
HUB_REQUEST_SET_FEATURE = 3 ,
|
||||
|
||||
HUB_REQUEST_GET_DESCRIPTOR = 6 ,
|
||||
HUB_REQUEST_SET_DESCRIPTOR = 7 ,
|
||||
HUB_REQUEST_CLEAR_TT_BUFFER = 8 ,
|
||||
HUB_REQUEST_RESET_TT = 9 ,
|
||||
HUB_REQUEST_GET_TT_STATE = 10 ,
|
||||
HUB_REQUEST_STOP_TT = 11
|
||||
};
|
||||
|
||||
enum {
|
||||
HUB_FEATURE_HUB_LOCAL_POWER_CHANGE = 0,
|
||||
HUB_FEATURE_HUB_OVER_CURRENT_CHANGE
|
||||
};
|
||||
|
||||
enum{
|
||||
HUB_FEATURE_PORT_CONNECTION = 0,
|
||||
HUB_FEATURE_PORT_ENABLE = 1,
|
||||
HUB_FEATURE_PORT_SUSPEND = 2,
|
||||
HUB_FEATURE_PORT_OVER_CURRENT = 3,
|
||||
HUB_FEATURE_PORT_RESET = 4,
|
||||
|
||||
HUB_FEATURE_PORT_POWER = 8,
|
||||
HUB_FEATURE_PORT_LOW_SPEED = 9,
|
||||
|
||||
HUB_FEATURE_PORT_CONNECTION_CHANGE = 16,
|
||||
HUB_FEATURE_PORT_ENABLE_CHANGE = 17,
|
||||
HUB_FEATURE_PORT_SUSPEND_CHANGE = 18,
|
||||
HUB_FEATURE_PORT_OVER_CURRENT_CHANGE = 19,
|
||||
HUB_FEATURE_PORT_RESET_CHANGE = 20,
|
||||
HUB_FEATURE_PORT_TEST = 21,
|
||||
HUB_FEATURE_PORT_INDICATOR = 22
|
||||
};
|
||||
|
||||
// data in response of HUB_REQUEST_GET_STATUS, wIndex = 0 (hub)
|
||||
typedef struct {
|
||||
union{
|
||||
struct ATTR_PACKED {
|
||||
uint16_t local_power_source : 1;
|
||||
uint16_t over_current : 1;
|
||||
uint16_t : 14;
|
||||
};
|
||||
|
||||
uint16_t value;
|
||||
} status, status_change;
|
||||
} hub_status_response_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(hub_status_response_t) == 4, "size is not correct");
|
||||
|
||||
// data in response of HUB_REQUEST_GET_STATUS, wIndex = Port num
|
||||
typedef struct {
|
||||
union {
|
||||
struct ATTR_PACKED {
|
||||
uint16_t connect_status : 1;
|
||||
uint16_t port_enable : 1;
|
||||
uint16_t suspend : 1;
|
||||
uint16_t over_current : 1;
|
||||
uint16_t reset : 1;
|
||||
|
||||
uint16_t : 3;
|
||||
uint16_t port_power : 1;
|
||||
uint16_t low_speed_device_attached : 1;
|
||||
uint16_t high_speed_device_attached : 1;
|
||||
uint16_t port_test_mode : 1;
|
||||
uint16_t port_indicator_control : 1;
|
||||
uint16_t : 0;
|
||||
};
|
||||
|
||||
uint16_t value;
|
||||
} status_current, status_change;
|
||||
} hub_port_status_response_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct");
|
||||
|
||||
tusb_error_t hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port);
|
||||
tusb_error_t hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature);
|
||||
tusb_speed_t hub_port_get_speed(void);
|
||||
tusb_error_t hub_status_pipe_queue(uint8_t dev_addr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef _TINY_USB_SOURCE_FILE_
|
||||
|
||||
void hub_init(void);
|
||||
tusb_error_t hub_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) ATTR_WARN_UNUSED_RESULT;
|
||||
void hub_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void hub_close(uint8_t dev_addr);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HUB_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,710 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file ohci.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/tusb_common.h>
|
||||
|
||||
#if MODE_HOST_SUPPORTED && (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X)
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "hal/hal.h"
|
||||
#include "osal/osal.h"
|
||||
#include "common/timeout_timer.h"
|
||||
|
||||
#include "../hcd.h"
|
||||
#include "../usbh_hcd.h"
|
||||
#include "ohci.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
#define OHCI_REG ((ohci_registers_t *) LPC_USB_BASE)
|
||||
|
||||
enum {
|
||||
OHCI_CONTROL_FUNCSTATE_RESET = 0,
|
||||
OHCI_CONTROL_FUNCSTATE_RESUME,
|
||||
OHCI_CONTROL_FUNCSTATE_OPERATIONAL,
|
||||
OHCI_CONTROL_FUNCSTATE_SUSPEND
|
||||
};
|
||||
|
||||
enum {
|
||||
OHCI_CONTROL_CONTROL_BULK_RATIO = 3, ///< This specifies the service ratio between Control and Bulk EDs. 0 = 1:1, 3 = 4:1
|
||||
OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK = BIT_(2),
|
||||
OHCI_CONTROL_LIST_ISOCHRONOUS_ENABLE_MASK = BIT_(3),
|
||||
OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK = BIT_(4),
|
||||
OHCI_CONTROL_LIST_BULK_ENABLE_MASK = BIT_(5),
|
||||
};
|
||||
|
||||
enum {
|
||||
OHCI_FMINTERVAL_FI = 0x2EDF, // 7.3.1 nominal (reset) value
|
||||
OHCI_FMINTERVAL_FSMPS = (6*(OHCI_FMINTERVAL_FI-210)) / 7, // 5.4 calculated based on maximum overhead + bit stuffing
|
||||
};
|
||||
|
||||
enum {
|
||||
OHCI_PERIODIC_START = 0x3E67
|
||||
};
|
||||
|
||||
#ifdef __CC_ARM
|
||||
#pragma diag_suppress 66 // Suppress Keil warnings #66-D: enumeration value is out of "int" range
|
||||
#endif
|
||||
|
||||
enum {
|
||||
OHCI_INT_SCHEDULING_OVERUN_MASK = BIT_(0),
|
||||
OHCI_INT_WRITEBACK_DONEHEAD_MASK = BIT_(1),
|
||||
OHCI_INT_SOF_MASK = BIT_(2),
|
||||
OHCI_INT_RESUME_DETECTED_MASK = BIT_(3),
|
||||
OHCI_INT_UNRECOVERABLE_ERROR_MASK = BIT_(4),
|
||||
OHCI_INT_FRAME_OVERFLOW_MASK = BIT_(5),
|
||||
OHCI_INT_RHPORT_STATUS_CHANGE_MASK = BIT_(6),
|
||||
|
||||
OHCI_INT_OWNERSHIP_CHANGE_MASK = BIT_(30),
|
||||
OHCI_INT_MASTER_ENABLE_MASK = BIT_(31),
|
||||
};
|
||||
|
||||
#ifdef __CC_ARM
|
||||
#pragma diag_default 66 // return Keil 66 to normal severity
|
||||
#endif
|
||||
|
||||
enum {
|
||||
OHCI_RHPORT_CURRENT_CONNECT_STATUS_MASK = BIT_(0),
|
||||
OHCI_RHPORT_PORT_ENABLE_STATUS_MASK = BIT_(1),
|
||||
OHCI_RHPORT_PORT_SUSPEND_STATUS_MASK = BIT_(2),
|
||||
OHCI_RHPORT_PORT_OVER_CURRENT_INDICATOR_MASK = BIT_(3),
|
||||
OHCI_RHPORT_PORT_RESET_STATUS_MASK = BIT_(4), ///< write '1' to reset port
|
||||
|
||||
OHCI_RHPORT_PORT_POWER_STATUS_MASK = BIT_(8),
|
||||
OHCI_RHPORT_LOW_SPEED_DEVICE_ATTACHED_MASK = BIT_(9),
|
||||
|
||||
OHCI_RHPORT_CONNECT_STATUS_CHANGE_MASK = BIT_(16),
|
||||
OHCI_RHPORT_PORT_ENABLE_CHANGE_MASK = BIT_(17),
|
||||
OHCI_RHPORT_PORT_SUSPEND_CHANGE_MASK = BIT_(18),
|
||||
OHCI_RHPORT_OVER_CURRENT_CHANGE_MASK = BIT_(19),
|
||||
OHCI_RHPORT_PORT_RESET_CHANGE_MASK = BIT_(20),
|
||||
|
||||
OHCI_RHPORT_ALL_CHANGE_MASK = OHCI_RHPORT_CONNECT_STATUS_CHANGE_MASK | OHCI_RHPORT_PORT_ENABLE_CHANGE_MASK |
|
||||
OHCI_RHPORT_PORT_SUSPEND_CHANGE_MASK | OHCI_RHPORT_OVER_CURRENT_CHANGE_MASK | OHCI_RHPORT_PORT_RESET_CHANGE_MASK
|
||||
};
|
||||
|
||||
enum {
|
||||
OHCI_CCODE_NO_ERROR = 0,
|
||||
OHCI_CCODE_CRC = 1,
|
||||
OHCI_CCODE_BIT_STUFFING = 2,
|
||||
OHCI_CCODE_DATA_TOGGLE_MISMATCH = 3,
|
||||
OHCI_CCODE_STALL = 4,
|
||||
OHCI_CCODE_DEVICE_NOT_RESPONDING = 5,
|
||||
OHCI_CCODE_PID_CHECK_FAILURE = 6,
|
||||
OHCI_CCODE_UNEXPECTED_PID = 7,
|
||||
OHCI_CCODE_DATA_OVERRUN = 8,
|
||||
OHCI_CCODE_DATA_UNDERRUN = 9,
|
||||
OHCI_CCODE_BUFFER_OVERRUN = 12,
|
||||
OHCI_CCODE_BUFFER_UNDERRUN = 13,
|
||||
OHCI_CCODE_NOT_ACCESSED = 14,
|
||||
};
|
||||
|
||||
enum {
|
||||
OHCI_INT_ON_COMPLETE_YES = 0,
|
||||
OHCI_INT_ON_COMPLETE_NO = BIN8(111)
|
||||
};
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_ATTR_USBRAM ATTR_ALIGNED(256) STATIC_VAR ohci_data_t ohci_data;
|
||||
|
||||
static ohci_ed_t * const p_ed_head[] =
|
||||
{
|
||||
[TUSB_XFER_CONTROL] = &ohci_data.control[0].ed,
|
||||
[TUSB_XFER_BULK ] = &ohci_data.bulk_head_ed,
|
||||
[TUSB_XFER_INTERRUPT] = &ohci_data.period_head_ed,
|
||||
[TUSB_XFER_ISOCHRONOUS] = NULL // TODO Isochronous
|
||||
};
|
||||
|
||||
static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed);
|
||||
static void ed_list_remove(ohci_ed_t * p_head, ohci_ed_t * p_ed);
|
||||
|
||||
static ohci_ed_t * ed_list_find_previous(ohci_ed_t const * p_head, ohci_ed_t const * p_ed);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-HCD API
|
||||
//--------------------------------------------------------------------+
|
||||
// Initialization according to 5.1.1.4
|
||||
tusb_error_t hcd_init(void)
|
||||
{
|
||||
//------------- Data Structure init -------------//
|
||||
memclr_(&ohci_data, sizeof(ohci_data_t));
|
||||
for(uint8_t i=0; i<32; i++)
|
||||
{ // assign all interrupt pointes to period head ed
|
||||
ohci_data.hcca.interrupt_table[i] = (uint32_t) &ohci_data.period_head_ed;
|
||||
}
|
||||
|
||||
ohci_data.control[0].ed.skip = 1;
|
||||
ohci_data.bulk_head_ed.skip = 1;
|
||||
ohci_data.period_head_ed.skip = 1;
|
||||
|
||||
// reset controller
|
||||
OHCI_REG->command_status_bit.controller_reset = 1;
|
||||
while( OHCI_REG->command_status_bit.controller_reset ) {} // should not take longer than 10 us
|
||||
|
||||
//------------- init ohci registers -------------//
|
||||
OHCI_REG->control_head_ed = (uint32_t) &ohci_data.control[0].ed;
|
||||
OHCI_REG->bulk_head_ed = (uint32_t) &ohci_data.bulk_head_ed;
|
||||
OHCI_REG->hcca = (uint32_t) &ohci_data.hcca;
|
||||
|
||||
OHCI_REG->interrupt_disable = OHCI_REG->interrupt_enable; // disable all interrupts
|
||||
OHCI_REG->interrupt_status = OHCI_REG->interrupt_status; // clear current set bits
|
||||
OHCI_REG->interrupt_enable = OHCI_INT_WRITEBACK_DONEHEAD_MASK | OHCI_INT_RESUME_DETECTED_MASK |
|
||||
OHCI_INT_UNRECOVERABLE_ERROR_MASK | /*OHCI_INT_FRAME_OVERFLOW_MASK |*/ OHCI_INT_RHPORT_STATUS_CHANGE_MASK |
|
||||
OHCI_INT_MASTER_ENABLE_MASK;
|
||||
|
||||
OHCI_REG->control |= OHCI_CONTROL_CONTROL_BULK_RATIO | OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK |
|
||||
OHCI_CONTROL_LIST_BULK_ENABLE_MASK | OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK; // TODO Isochronous
|
||||
|
||||
OHCI_REG->frame_interval = (OHCI_FMINTERVAL_FSMPS << 16) | OHCI_FMINTERVAL_FI;
|
||||
OHCI_REG->periodic_start = (OHCI_FMINTERVAL_FI * 9) / 10; // Periodic start is 90% of frame interval
|
||||
|
||||
OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power)
|
||||
OHCI_REG->rh_status_bit.local_power_status_change = 1; // set global power for ports
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PORT API
|
||||
//--------------------------------------------------------------------+
|
||||
void hcd_port_reset(uint8_t hostid)
|
||||
{
|
||||
OHCI_REG->rhport_status[0] = OHCI_RHPORT_PORT_RESET_STATUS_MASK;
|
||||
}
|
||||
|
||||
bool hcd_port_connect_status(uint8_t hostid)
|
||||
{
|
||||
return OHCI_REG->rhport_status_bit[0].current_connect_status;
|
||||
}
|
||||
|
||||
tusb_speed_t hcd_port_speed_get(uint8_t hostid)
|
||||
{
|
||||
return OHCI_REG->rhport_status_bit[0].low_speed_device_attached ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
|
||||
}
|
||||
|
||||
// TODO refractor abtract later
|
||||
void hcd_port_unplug(uint8_t hostid)
|
||||
{
|
||||
// TODO OHCI
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Controller API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROL PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
static inline tusb_xfer_type_t ed_get_xfer_type(ohci_ed_t const * const p_ed) ATTR_PURE ATTR_ALWAYS_INLINE;
|
||||
static inline tusb_xfer_type_t ed_get_xfer_type(ohci_ed_t const * const p_ed)
|
||||
{
|
||||
return (p_ed->endpoint_number == 0 ) ? TUSB_XFER_CONTROL :
|
||||
(p_ed->is_iso ) ? TUSB_XFER_ISOCHRONOUS :
|
||||
(p_ed->is_interrupt_xfer ) ? TUSB_XFER_INTERRUPT : TUSB_XFER_BULK;
|
||||
}
|
||||
|
||||
static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type, uint8_t interval)
|
||||
{
|
||||
// address 0 is used as async head, which always on the list --> cannot be cleared
|
||||
if (dev_addr != 0)
|
||||
{
|
||||
memclr_(p_ed, sizeof(ohci_ed_t));
|
||||
}
|
||||
|
||||
p_ed->device_address = dev_addr;
|
||||
p_ed->endpoint_number = endpoint_addr & 0x0F;
|
||||
p_ed->direction = (xfer_type == TUSB_XFER_CONTROL) ? OHCI_PID_SETUP : ( (endpoint_addr & TUSB_DIR_IN_MASK) ? OHCI_PID_IN : OHCI_PID_OUT );
|
||||
p_ed->speed = usbh_devices[dev_addr].speed;
|
||||
p_ed->is_iso = (xfer_type == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
|
||||
p_ed->max_package_size = max_packet_size;
|
||||
|
||||
p_ed->used = 1;
|
||||
p_ed->is_interrupt_xfer = (xfer_type == TUSB_XFER_INTERRUPT ? 1 : 0);
|
||||
}
|
||||
|
||||
static void gtd_init(ohci_gtd_t* p_td, void* data_ptr, uint16_t total_bytes)
|
||||
{
|
||||
memclr_(p_td, sizeof(ohci_gtd_t));
|
||||
|
||||
p_td->used = 1;
|
||||
p_td->expected_bytes = total_bytes;
|
||||
|
||||
p_td->buffer_rounding = 1; // less than queued length is not a error
|
||||
p_td->delay_interrupt = OHCI_INT_ON_COMPLETE_NO;
|
||||
p_td->condition_code = OHCI_CCODE_NOT_ACCESSED;
|
||||
|
||||
p_td->current_buffer_pointer = data_ptr;
|
||||
p_td->buffer_end = total_bytes ? (((uint8_t*) data_ptr) + total_bytes-1) : NULL;
|
||||
}
|
||||
|
||||
tusb_error_t hcd_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size)
|
||||
{
|
||||
ohci_ed_t* const p_ed = &ohci_data.control[dev_addr].ed;
|
||||
|
||||
ed_init(p_ed, dev_addr, max_packet_size, 0, TUSB_XFER_CONTROL, 0); // TODO binterval of control is ignored
|
||||
|
||||
if ( dev_addr != 0 )
|
||||
{ // insert to control head
|
||||
ed_list_insert( p_ed_head[TUSB_XFER_CONTROL], p_ed);
|
||||
}else
|
||||
{
|
||||
p_ed->skip = 0; // addr0 is used as static control head --> only need to clear skip bit
|
||||
}
|
||||
|
||||
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[])
|
||||
{
|
||||
ohci_ed_t* const p_ed = &ohci_data.control[dev_addr].ed;
|
||||
|
||||
ohci_gtd_t *p_setup = &ohci_data.control[dev_addr].gtd[0];
|
||||
ohci_gtd_t *p_data = p_setup + 1;
|
||||
ohci_gtd_t *p_status = p_setup + 2;
|
||||
|
||||
//------------- SETUP Phase -------------//
|
||||
gtd_init(p_setup, (void*) p_request, 8);
|
||||
p_setup->index = dev_addr;
|
||||
p_setup->pid = OHCI_PID_SETUP;
|
||||
p_setup->data_toggle = BIN8(10); // DATA0
|
||||
p_setup->next_td = (uint32_t) p_data;
|
||||
|
||||
//------------- DATA Phase -------------//
|
||||
if (p_request->wLength > 0)
|
||||
{
|
||||
gtd_init(p_data, data, p_request->wLength);
|
||||
p_data->index = dev_addr;
|
||||
p_data->pid = p_request->bmRequestType_bit.direction ? OHCI_PID_IN : OHCI_PID_OUT;
|
||||
p_data->data_toggle = BIN8(11); // DATA1
|
||||
}else
|
||||
{
|
||||
p_data = p_setup;
|
||||
}
|
||||
p_data->next_td = (uint32_t) p_status;
|
||||
|
||||
//------------- STATUS Phase -------------//
|
||||
gtd_init(p_status, NULL, 0); // zero-length data
|
||||
p_status->index = dev_addr;
|
||||
p_status->pid = p_request->bmRequestType_bit.direction ? OHCI_PID_OUT : OHCI_PID_IN; // reverse direction of data phase
|
||||
p_status->data_toggle = BIN8(11); // DATA1
|
||||
p_status->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
|
||||
|
||||
//------------- Attach TDs list to Control Endpoint -------------//
|
||||
p_ed->td_head.address = (uint32_t) p_setup;
|
||||
|
||||
OHCI_REG->command_status_bit.control_list_filled = 1;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t hcd_pipe_control_close(uint8_t dev_addr)
|
||||
{
|
||||
ohci_ed_t* const p_ed = &ohci_data.control[dev_addr].ed;
|
||||
|
||||
if ( dev_addr == 0 )
|
||||
{ // addr0 serves as static head --> only set skip bitx
|
||||
p_ed->skip = 1;
|
||||
}else
|
||||
{
|
||||
ed_list_remove( p_ed_head[ ed_get_xfer_type(p_ed)], p_ed );
|
||||
|
||||
// TODO refractor to be USBH
|
||||
usbh_devices[dev_addr].state = TUSB_DEVICE_STATE_UNPLUG;
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// BULK/INT/ISO PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
static inline uint8_t ed_get_index(ohci_ed_t const * const p_ed) ATTR_PURE ATTR_ALWAYS_INLINE;
|
||||
static inline uint8_t ed_get_index(ohci_ed_t const * const p_ed)
|
||||
{
|
||||
return p_ed - ohci_data.device[p_ed->device_address-1].ed;
|
||||
}
|
||||
|
||||
static inline ohci_ed_t * ed_from_pipe_handle(pipe_handle_t pipe_hdl) ATTR_PURE ATTR_ALWAYS_INLINE;
|
||||
static inline ohci_ed_t * ed_from_pipe_handle(pipe_handle_t pipe_hdl)
|
||||
{
|
||||
return &ohci_data.device[pipe_hdl.dev_addr-1].ed[pipe_hdl.index];
|
||||
}
|
||||
|
||||
static inline ohci_ed_t * ed_find_free(uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE;
|
||||
static inline ohci_ed_t * ed_find_free(uint8_t dev_addr)
|
||||
{
|
||||
for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; i++)
|
||||
{
|
||||
if ( !ohci_data.device[dev_addr-1].ed[i].used )
|
||||
{
|
||||
return &ohci_data.device[dev_addr-1].ed[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ohci_ed_t * ed_list_find_previous(ohci_ed_t const * p_head, ohci_ed_t const * p_ed)
|
||||
{
|
||||
uint32_t max_loop = HCD_MAX_ENDPOINT*CFG_TUSB_HOST_DEVICE_MAX;
|
||||
|
||||
ohci_ed_t const * p_prev = p_head;
|
||||
|
||||
TU_ASSERT(p_prev, NULL);
|
||||
|
||||
while ( align16(p_prev->next_ed) != 0 && /* not reach null */
|
||||
align16(p_prev->next_ed) != (uint32_t) p_ed && /* not found yet */
|
||||
max_loop > 0)
|
||||
{
|
||||
p_prev = (ohci_ed_t const *) align16(p_prev->next_ed);
|
||||
max_loop--;
|
||||
}
|
||||
|
||||
return ( align16(p_prev->next_ed) == (uint32_t) p_ed ) ? (ohci_ed_t*) p_prev : NULL;
|
||||
}
|
||||
|
||||
static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed)
|
||||
{
|
||||
p_ed->next_ed |= p_pre->next_ed; // to reserve 4 lsb bits
|
||||
p_pre->next_ed = (p_pre->next_ed & 0x0FUL) | ((uint32_t) p_ed);
|
||||
}
|
||||
|
||||
static void ed_list_remove(ohci_ed_t * p_head, ohci_ed_t * p_ed)
|
||||
{
|
||||
ohci_ed_t * const p_prev = ed_list_find_previous(p_head, p_ed);
|
||||
|
||||
p_prev->next_ed = (p_prev->next_ed & 0x0fUL) | align16(p_ed->next_ed);
|
||||
// point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED
|
||||
p_ed->next_ed = (uint32_t) p_head;
|
||||
p_ed->used = 0; // free ED
|
||||
}
|
||||
|
||||
pipe_handle_t hcd_pipe_open(uint8_t dev_addr, tusb_desc_endpoint_t const * p_endpoint_desc, uint8_t class_code)
|
||||
{
|
||||
pipe_handle_t const null_handle = { .dev_addr = 0, .xfer_type = 0, .index = 0 };
|
||||
|
||||
// TODO iso support
|
||||
TU_ASSERT(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS, null_handle );
|
||||
|
||||
//------------- Prepare Queue Head -------------//
|
||||
ohci_ed_t * const p_ed = ed_find_free(dev_addr);
|
||||
TU_ASSERT(p_ed, null_handle);
|
||||
|
||||
ed_init( p_ed, dev_addr, p_endpoint_desc->wMaxPacketSize.size, p_endpoint_desc->bEndpointAddress,
|
||||
p_endpoint_desc->bmAttributes.xfer, p_endpoint_desc->bInterval );
|
||||
p_ed->td_tail.class_code = class_code;
|
||||
|
||||
ed_list_insert( p_ed_head[p_endpoint_desc->bmAttributes.xfer], p_ed );
|
||||
|
||||
return (pipe_handle_t)
|
||||
{
|
||||
.dev_addr = dev_addr,
|
||||
.xfer_type = p_endpoint_desc->bmAttributes.xfer,
|
||||
.index = ed_get_index(p_ed)
|
||||
};
|
||||
}
|
||||
|
||||
static ohci_gtd_t * gtd_find_free(uint8_t dev_addr)
|
||||
{
|
||||
for(uint8_t i=0; i < HCD_MAX_XFER; i++)
|
||||
{
|
||||
if (!ohci_data.device[dev_addr-1].gtd[i].used)
|
||||
{
|
||||
return &ohci_data.device[dev_addr-1].gtd[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void td_insert_to_ed(ohci_ed_t* p_ed, ohci_gtd_t * p_gtd)
|
||||
{
|
||||
// tail is always NULL
|
||||
if ( align16(p_ed->td_head.address) == 0 )
|
||||
{ // TD queue is empty --> head = TD
|
||||
p_ed->td_head.address |= (uint32_t) p_gtd;
|
||||
}
|
||||
else
|
||||
{ // TODO currently only support queue up to 2 TD each endpoint at a time
|
||||
((ohci_gtd_t*) align16(p_ed->td_head.address))->next_td = (uint32_t) p_gtd;
|
||||
}
|
||||
}
|
||||
|
||||
static tusb_error_t pipe_queue_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete)
|
||||
{
|
||||
ohci_ed_t* const p_ed = ed_from_pipe_handle(pipe_hdl);
|
||||
|
||||
if ( !p_ed->is_iso )
|
||||
{
|
||||
ohci_gtd_t * const p_gtd = gtd_find_free(pipe_hdl.dev_addr);
|
||||
TU_ASSERT(p_gtd, TUSB_ERROR_EHCI_NOT_ENOUGH_QTD); // TODO refractor error code
|
||||
|
||||
gtd_init(p_gtd, buffer, total_bytes);
|
||||
p_gtd->index = pipe_hdl.index;
|
||||
if ( int_on_complete ) p_gtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
|
||||
|
||||
td_insert_to_ed(p_ed, p_gtd);
|
||||
}else
|
||||
{
|
||||
TU_ASSERT_ERR(TUSB_ERROR_NOT_SUPPORTED_YET);
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t hcd_pipe_queue_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes)
|
||||
{
|
||||
return pipe_queue_xfer(pipe_hdl, buffer, total_bytes, false);
|
||||
}
|
||||
|
||||
tusb_error_t hcd_pipe_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete)
|
||||
{
|
||||
TU_ASSERT_ERR( pipe_queue_xfer(pipe_hdl, buffer, total_bytes, true) );
|
||||
|
||||
tusb_xfer_type_t xfer_type = ed_get_xfer_type( ed_from_pipe_handle(pipe_hdl) );
|
||||
|
||||
if (TUSB_XFER_BULK == xfer_type) OHCI_REG->command_status_bit.bulk_list_filled = 1;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
/// pipe_close should only be called as a part of unmount/safe-remove process
|
||||
// endpoints are tied to an address, which only reclaim after a long delay when enumerating
|
||||
// thus there is no need to make sure ED is not in HC's cahed as it will not for sure
|
||||
tusb_error_t hcd_pipe_close(pipe_handle_t pipe_hdl)
|
||||
{
|
||||
ohci_ed_t * const p_ed = ed_from_pipe_handle(pipe_hdl);
|
||||
|
||||
ed_list_remove( p_ed_head[ ed_get_xfer_type(p_ed)], p_ed );
|
||||
|
||||
return TUSB_ERROR_FAILED;
|
||||
}
|
||||
|
||||
bool hcd_pipe_is_busy(pipe_handle_t pipe_hdl)
|
||||
{
|
||||
ohci_ed_t const * const p_ed = ed_from_pipe_handle(pipe_hdl);
|
||||
return align16(p_ed->td_head.address) != align16(p_ed->td_tail.address);
|
||||
}
|
||||
|
||||
bool hcd_pipe_is_error(pipe_handle_t pipe_hdl)
|
||||
{
|
||||
ohci_ed_t const * const p_ed = ed_from_pipe_handle(pipe_hdl);
|
||||
return p_ed->td_head.halted;
|
||||
}
|
||||
|
||||
bool hcd_pipe_is_stalled(pipe_handle_t pipe_hdl)
|
||||
{
|
||||
ohci_ed_t const * const p_ed = ed_from_pipe_handle(pipe_hdl);
|
||||
return p_ed->td_head.halted && p_ed->is_stalled;
|
||||
}
|
||||
|
||||
uint8_t hcd_pipe_get_endpoint_addr(pipe_handle_t pipe_hdl)
|
||||
{
|
||||
ohci_ed_t const * const p_ed = ed_from_pipe_handle(pipe_hdl);
|
||||
return p_ed->endpoint_number | (p_ed->direction == OHCI_PID_IN ? TUSB_DIR_IN_MASK : 0 );
|
||||
}
|
||||
|
||||
tusb_error_t hcd_pipe_clear_stall(pipe_handle_t pipe_hdl)
|
||||
{
|
||||
ohci_ed_t * const p_ed = ed_from_pipe_handle(pipe_hdl);
|
||||
|
||||
p_ed->is_stalled = 0;
|
||||
p_ed->td_tail.address &= 0x0Ful; // set tail pointer back to NULL
|
||||
|
||||
p_ed->td_head.toggle = 0; // reset data toggle
|
||||
p_ed->td_head.halted = 0;
|
||||
|
||||
if ( TUSB_XFER_BULK == ed_get_xfer_type(p_ed) ) OHCI_REG->command_status_bit.bulk_list_filled = 1;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Interrupt Handler
|
||||
//--------------------------------------------------------------------+
|
||||
static ohci_td_item_t* list_reverse(ohci_td_item_t* td_head)
|
||||
{
|
||||
ohci_td_item_t* td_reverse_head = NULL;
|
||||
|
||||
while(td_head != NULL)
|
||||
{
|
||||
uint32_t next = td_head->next_td;
|
||||
|
||||
// make current's item become reverse's first item
|
||||
td_head->next_td = (uint32_t) td_reverse_head;
|
||||
td_reverse_head = td_head;
|
||||
|
||||
td_head = (ohci_td_item_t*) next; // advance to next item
|
||||
}
|
||||
|
||||
return td_reverse_head;
|
||||
}
|
||||
|
||||
static inline bool gtd_is_control(ohci_gtd_t const * const p_qtd) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline bool gtd_is_control(ohci_gtd_t const * const p_qtd)
|
||||
{
|
||||
return ((uint32_t) p_qtd) < ((uint32_t) ohci_data.device); // check ohci_data_t for memory layout
|
||||
}
|
||||
|
||||
static inline ohci_ed_t* gtd_get_ed(ohci_gtd_t const * const p_qtd) ATTR_PURE ATTR_ALWAYS_INLINE;
|
||||
static inline ohci_ed_t* gtd_get_ed(ohci_gtd_t const * const p_qtd)
|
||||
{
|
||||
if ( gtd_is_control(p_qtd) )
|
||||
{
|
||||
return &ohci_data.control[p_qtd->index].ed;
|
||||
}else
|
||||
{
|
||||
uint8_t dev_addr_idx = (((uint32_t)p_qtd) - ((uint32_t)ohci_data.device)) / sizeof(ohci_data.device[0]);
|
||||
|
||||
return &ohci_data.device[dev_addr_idx].ed[p_qtd->index];
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_buffer) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_buffer)
|
||||
{ // 5.2.9 OHCI sample code
|
||||
return (align4k(buffer_end ^ current_buffer) ? 0x1000 : 0) +
|
||||
offset4k(buffer_end) - offset4k(current_buffer) + 1;
|
||||
}
|
||||
|
||||
static void done_queue_isr(uint8_t hostid)
|
||||
{
|
||||
uint8_t max_loop = (CFG_TUSB_HOST_DEVICE_MAX+1)*(HCD_MAX_XFER+OHCI_MAX_ITD);
|
||||
|
||||
// done head is written in reversed order of completion --> need to reverse the done queue first
|
||||
ohci_td_item_t* td_head = list_reverse ( (ohci_td_item_t*) align16(ohci_data.hcca.done_head) );
|
||||
|
||||
while( td_head != NULL && max_loop > 0)
|
||||
{
|
||||
// TODO check if td_head is iso td
|
||||
//------------- Non ISO transfer -------------//
|
||||
ohci_gtd_t * const p_qtd = (ohci_gtd_t *) td_head;
|
||||
tusb_event_t const event = (p_qtd->condition_code == OHCI_CCODE_NO_ERROR) ? TUSB_EVENT_XFER_COMPLETE :
|
||||
(p_qtd->condition_code == OHCI_CCODE_STALL) ? TUSB_EVENT_XFER_STALLED : TUSB_EVENT_XFER_ERROR;
|
||||
|
||||
p_qtd->used = 0; // free TD
|
||||
if ( (p_qtd->delay_interrupt == OHCI_INT_ON_COMPLETE_YES) || (event != TUSB_EVENT_XFER_COMPLETE) )
|
||||
{
|
||||
ohci_ed_t * const p_ed = gtd_get_ed(p_qtd);
|
||||
|
||||
uint32_t const xferred_bytes = p_qtd->expected_bytes - gtd_xfer_byte_left((uint32_t) p_qtd->buffer_end, (uint32_t) p_qtd->current_buffer_pointer);
|
||||
|
||||
// NOTE Assuming the current list is BULK and there is no other EDs in the list has queued TDs.
|
||||
// When there is a error resulting this ED is halted, and this EP still has other queued TD
|
||||
// --> the Bulk list only has this halted EP queueing TDs (remaining)
|
||||
// --> Bulk list will be considered as not empty by HC !!! while there is no attempt transaction on this list
|
||||
// --> HC will not process Control list (due to service ratio when Bulk list not empty)
|
||||
// To walk-around this, the halted ED will have TailP = HeadP (empty list condition), when clearing halt
|
||||
// the TailP must be set back to NULL for processing remaining TDs
|
||||
if ((event != TUSB_EVENT_XFER_COMPLETE))
|
||||
{
|
||||
p_ed->td_tail.address &= 0x0Ful;
|
||||
p_ed->td_tail.address |= align16(p_ed->td_head.address); // mark halted EP as empty queue
|
||||
if ( event == TUSB_EVENT_XFER_STALLED ) p_ed->is_stalled = 1;
|
||||
}
|
||||
|
||||
pipe_handle_t pipe_hdl =
|
||||
{
|
||||
.dev_addr = p_ed->device_address,
|
||||
.xfer_type = ed_get_xfer_type(p_ed),
|
||||
};
|
||||
|
||||
if ( pipe_hdl.xfer_type != TUSB_XFER_CONTROL) pipe_hdl.index = ed_get_index(p_ed);
|
||||
|
||||
usbh_xfer_isr(pipe_hdl, p_ed->td_tail.class_code, event, xferred_bytes);
|
||||
}
|
||||
|
||||
td_head = (ohci_td_item_t*) td_head->next_td;
|
||||
max_loop--;
|
||||
}
|
||||
}
|
||||
|
||||
void hal_hcd_isr(uint8_t hostid)
|
||||
{
|
||||
uint32_t const int_en = OHCI_REG->interrupt_enable;
|
||||
uint32_t const int_status = OHCI_REG->interrupt_status & int_en;
|
||||
|
||||
if (int_status == 0) return;
|
||||
|
||||
//------------- RootHub status -------------//
|
||||
if ( int_status & OHCI_INT_RHPORT_STATUS_CHANGE_MASK )
|
||||
{
|
||||
uint32_t const rhport_status = OHCI_REG->rhport_status[0] & OHCI_RHPORT_ALL_CHANGE_MASK;
|
||||
|
||||
// TODO dual port is not yet supported
|
||||
if ( rhport_status & OHCI_RHPORT_CONNECT_STATUS_CHANGE_MASK )
|
||||
{
|
||||
// TODO check if remote wake-up
|
||||
if ( OHCI_REG->rhport_status_bit[0].current_connect_status )
|
||||
{
|
||||
// TODO reset port immediately, without this controller will got 2-3 (debouncing connection status change)
|
||||
OHCI_REG->rhport_status[0] = OHCI_RHPORT_PORT_RESET_STATUS_MASK;
|
||||
usbh_hcd_rhport_plugged_isr(0);
|
||||
}else
|
||||
{
|
||||
usbh_hcd_rhport_unplugged_isr(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ( rhport_status & OHCI_RHPORT_PORT_SUSPEND_CHANGE_MASK)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
OHCI_REG->rhport_status[0] = rhport_status; // acknowledge all interrupt
|
||||
}
|
||||
|
||||
//------------- Transfer Complete -------------//
|
||||
if ( int_status & OHCI_INT_WRITEBACK_DONEHEAD_MASK)
|
||||
{
|
||||
done_queue_isr(hostid);
|
||||
}
|
||||
|
||||
OHCI_REG->interrupt_status = int_status; // Acknowledge handled interrupt
|
||||
}
|
||||
//--------------------------------------------------------------------+
|
||||
// HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file ohci.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 Group_HCD
|
||||
* @{
|
||||
* \defgroup OHCI
|
||||
* \brief OHCI driver. All documents sources mentioned here (eg section 3.5) is referring to OHCI Specs unless state otherwise
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_OHCI_H_
|
||||
#define _TUSB_OHCI_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI CONFIGURATION & CONSTANTS
|
||||
//--------------------------------------------------------------------+
|
||||
#define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enalbed
|
||||
#define OHCI_PERIODIC_LIST (defined HOST_HCD_XFER_INTERRUPT || defined HOST_HCD_XFER_ISOCHRONOUS)
|
||||
|
||||
// TODO merge OHCI with EHCI
|
||||
enum {
|
||||
OHCI_MAX_ITD = 4
|
||||
};
|
||||
|
||||
enum {
|
||||
OHCI_PID_SETUP = 0,
|
||||
OHCI_PID_OUT,
|
||||
OHCI_PID_IN,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Data Structure
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
uint32_t interrupt_table[32];
|
||||
volatile uint16_t frame_number;
|
||||
volatile uint16_t frame_pad;
|
||||
volatile uint32_t done_head;
|
||||
uint8_t reserved[116+4]; // TODO try to make use of this area if possible, extra 4 byte to make the whole struct size = 256
|
||||
}ohci_hcca_t; // ATTR_ALIGNED(256)
|
||||
|
||||
VERIFY_STATIC( sizeof(ohci_hcca_t) == 256, "size is not correct" );
|
||||
|
||||
typedef struct {
|
||||
uint32_t reserved[2];
|
||||
volatile uint32_t next_td;
|
||||
uint32_t reserved2;
|
||||
}ohci_td_item_t;
|
||||
|
||||
|
||||
typedef struct ATTR_ALIGNED(16) {
|
||||
//------------- Word 0 -------------//
|
||||
uint32_t used : 1;
|
||||
uint32_t index : 4; // endpoint index the td belongs to, or device address in case of control xfer
|
||||
uint32_t expected_bytes : 13; // TODO available for hcd
|
||||
|
||||
uint32_t buffer_rounding : 1;
|
||||
uint32_t pid : 2;
|
||||
uint32_t delay_interrupt : 3;
|
||||
volatile uint32_t data_toggle : 2;
|
||||
volatile uint32_t error_count : 2;
|
||||
volatile uint32_t condition_code : 4;
|
||||
/*---------- End Word 1 ----------*/
|
||||
|
||||
//------------- Word 1 -------------//
|
||||
volatile uint8_t* current_buffer_pointer;
|
||||
|
||||
//------------- Word 2 -------------//
|
||||
volatile uint32_t next_td;
|
||||
|
||||
//------------- Word 3 -------------//
|
||||
uint8_t* buffer_end;
|
||||
} ohci_gtd_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(ohci_gtd_t) == 16, "size is not correct" );
|
||||
|
||||
typedef struct ATTR_ALIGNED(16) {
|
||||
//------------- Word 0 -------------//
|
||||
uint32_t device_address : 7;
|
||||
uint32_t endpoint_number : 4;
|
||||
uint32_t direction : 2;
|
||||
uint32_t speed : 1;
|
||||
uint32_t skip : 1;
|
||||
uint32_t is_iso : 1;
|
||||
uint32_t max_package_size : 11;
|
||||
|
||||
uint32_t used : 1; // HCD
|
||||
uint32_t is_interrupt_xfer : 1;
|
||||
uint32_t is_stalled : 1;
|
||||
uint32_t : 2;
|
||||
|
||||
|
||||
//------------- Word 1 -------------//
|
||||
union {
|
||||
uint32_t address; // 4 lsb bits are free to use
|
||||
struct {
|
||||
uint32_t class_code : 4; // FIXME refractor to use interface number instead
|
||||
uint32_t : 28;
|
||||
};
|
||||
}td_tail;
|
||||
|
||||
//------------- Word 2 -------------//
|
||||
volatile union {
|
||||
uint32_t address;
|
||||
struct {
|
||||
uint32_t halted : 1;
|
||||
uint32_t toggle : 1;
|
||||
uint32_t : 30;
|
||||
};
|
||||
}td_head;
|
||||
|
||||
//------------- Word 3 -------------//
|
||||
uint32_t next_ed; // 4 lsb bits are free to use
|
||||
} ohci_ed_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(ohci_ed_t) == 16, "size is not correct" );
|
||||
|
||||
typedef struct ATTR_ALIGNED(32) {
|
||||
/*---------- Word 1 ----------*/
|
||||
uint32_t starting_frame : 16;
|
||||
uint32_t : 5; // can be used
|
||||
uint32_t delay_interrupt : 3;
|
||||
uint32_t frame_count : 3;
|
||||
uint32_t : 1; // can be used
|
||||
volatile uint32_t condition_code : 4;
|
||||
/*---------- End Word 1 ----------*/
|
||||
|
||||
/*---------- Word 2 ----------*/
|
||||
uint32_t buffer_page0; // 12 lsb bits can be used
|
||||
|
||||
/*---------- Word 3 ----------*/
|
||||
volatile uint32_t next_td;
|
||||
|
||||
/*---------- Word 4 ----------*/
|
||||
uint32_t buffer_end;
|
||||
|
||||
/*---------- Word 5-8 ----------*/
|
||||
volatile uint16_t offset_packetstatus[8];
|
||||
} ochi_itd_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(ochi_itd_t) == 32, "size is not correct" );
|
||||
|
||||
// structure with member alignment required from large to small
|
||||
typedef struct ATTR_ALIGNED(256) {
|
||||
ohci_hcca_t hcca;
|
||||
|
||||
ohci_ed_t bulk_head_ed; // static bulk head (dummy)
|
||||
ohci_ed_t period_head_ed; // static periodic list head (dummy)
|
||||
|
||||
// control endpoints has reserved resources
|
||||
struct {
|
||||
ohci_ed_t ed;
|
||||
ohci_gtd_t gtd[3]; // setup, data, status
|
||||
}control[CFG_TUSB_HOST_DEVICE_MAX+1];
|
||||
|
||||
struct {
|
||||
// ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
|
||||
ohci_ed_t ed[HCD_MAX_ENDPOINT];
|
||||
ohci_gtd_t gtd[HCD_MAX_XFER];
|
||||
}device[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
|
||||
} ohci_data_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Operational Register
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Data Organization
|
||||
//--------------------------------------------------------------------+
|
||||
typedef volatile struct
|
||||
{
|
||||
uint32_t revision;
|
||||
|
||||
union {
|
||||
uint32_t control;
|
||||
struct {
|
||||
uint32_t control_bulk_service_ratio : 2;
|
||||
uint32_t periodic_list_enable : 1;
|
||||
uint32_t isochronous_enable : 1;
|
||||
uint32_t control_list_enable : 1;
|
||||
uint32_t bulk_list_enable : 1;
|
||||
uint32_t hc_functional_state : 2;
|
||||
uint32_t interrupt_routing : 1;
|
||||
uint32_t remote_wakeup_connected : 1;
|
||||
uint32_t remote_wakeup_enale : 1;
|
||||
uint32_t : 0;
|
||||
}control_bit;
|
||||
};
|
||||
|
||||
union {
|
||||
uint32_t command_status;
|
||||
struct {
|
||||
uint32_t controller_reset : 1;
|
||||
uint32_t control_list_filled : 1;
|
||||
uint32_t bulk_list_filled : 1;
|
||||
uint32_t ownership_change_request : 1;
|
||||
uint32_t : 12;
|
||||
uint32_t scheduling_overrun_count : 2;
|
||||
}command_status_bit;
|
||||
};
|
||||
|
||||
uint32_t interrupt_status;
|
||||
uint32_t interrupt_enable;
|
||||
uint32_t interrupt_disable;
|
||||
|
||||
uint32_t hcca;
|
||||
uint32_t period_current_ed;
|
||||
uint32_t control_head_ed;
|
||||
uint32_t control_current_ed;
|
||||
uint32_t bulk_head_ed;
|
||||
uint32_t bulk_current_ed;
|
||||
uint32_t done_head;
|
||||
|
||||
uint32_t frame_interval;
|
||||
uint32_t frame_remaining;
|
||||
uint32_t frame_number;
|
||||
uint32_t periodic_start;
|
||||
uint32_t lowspeed_threshold;
|
||||
|
||||
uint32_t rh_descriptorA;
|
||||
uint32_t rh_descriptorB;
|
||||
|
||||
union {
|
||||
uint32_t rh_status;
|
||||
struct {
|
||||
uint32_t local_power_status : 1; // read Local Power Status; write: Clear Global Power
|
||||
uint32_t over_current_indicator : 1;
|
||||
uint32_t : 13;
|
||||
uint32_t device_remote_wakeup_enable : 1;
|
||||
uint32_t local_power_status_change : 1;
|
||||
uint32_t over_current_indicator_change : 1;
|
||||
uint32_t : 13;
|
||||
uint32_t clear_remote_wakeup_enable : 1;
|
||||
}rh_status_bit;
|
||||
};
|
||||
|
||||
union {
|
||||
uint32_t rhport_status[2]; // TODO NXP OHCI controller only has 2 ports
|
||||
struct {
|
||||
uint32_t current_connect_status : 1;
|
||||
uint32_t port_enable_status : 1;
|
||||
uint32_t port_suspend_status : 1;
|
||||
uint32_t port_over_current_indicator : 1;
|
||||
uint32_t port_reset_status : 1;
|
||||
uint32_t : 3;
|
||||
uint32_t port_power_status : 1;
|
||||
uint32_t low_speed_device_attached : 1;
|
||||
uint32_t : 6;
|
||||
uint32_t connect_status_change : 1;
|
||||
uint32_t port_enable_status_change : 1;
|
||||
uint32_t port_suspend_status_change : 1;
|
||||
uint32_t port_over_current_indicator_change : 1;
|
||||
uint32_t port_reset_status_change : 1;
|
||||
uint32_t : 0;
|
||||
}rhport_status_bit[2];
|
||||
};
|
||||
}ohci_registers_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(ohci_registers_t) == 0x5c, "size is not correct");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_OHCI_H_ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
+642
@@ -0,0 +1,642 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file usbd_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 "common/tusb_common.h"
|
||||
|
||||
#if MODE_HOST_SUPPORTED
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
#ifndef CFG_TUD_TASK_PRIO
|
||||
#define CFG_TUD_TASK_PRIO 0
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "tusb.h"
|
||||
#include "hub.h"
|
||||
#include "usbh_hcd.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
static host_class_driver_t const usbh_class_drivers[] =
|
||||
{
|
||||
#if HOST_CLASS_HID
|
||||
[TUSB_CLASS_HID] = {
|
||||
.init = hidh_init,
|
||||
.open_subtask = hidh_open_subtask,
|
||||
.isr = hidh_isr,
|
||||
.close = hidh_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_CDC
|
||||
[TUSB_CLASS_CDC] = {
|
||||
.init = cdch_init,
|
||||
.open_subtask = cdch_open_subtask,
|
||||
.isr = cdch_isr,
|
||||
.close = cdch_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_MSC
|
||||
[TUSB_CLASS_MSC] = {
|
||||
.init = msch_init,
|
||||
.open_subtask = msch_open_subtask,
|
||||
.isr = msch_isr,
|
||||
.close = msch_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_HUB
|
||||
[TUSB_CLASS_HUB] = {
|
||||
.init = hub_init,
|
||||
.open_subtask = hub_open_subtask,
|
||||
.isr = hub_isr,
|
||||
.close = hub_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_CUSTOM_CLASS
|
||||
[TUSB_CLASS_MAPPED_INDEX_END-1] = {
|
||||
.init = cush_init,
|
||||
.open_subtask = cush_open_subtask,
|
||||
.isr = cush_isr,
|
||||
.close = cush_close
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
enum { USBH_CLASS_DRIVER_COUNT = sizeof(usbh_class_drivers) / sizeof(host_class_driver_t) };
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_ATTR_USBRAM usbh_device_info_t usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1]; // including zero-address
|
||||
|
||||
//------------- Enumeration Task Data -------------/
|
||||
enum { ENUM_QUEUE_DEPTH = 16 };
|
||||
|
||||
STATIC_VAR osal_queue_t enum_queue_hdl;
|
||||
CFG_TUSB_ATTR_USBRAM ATTR_ALIGNED(4) STATIC_VAR uint8_t enum_data_buffer[CFG_TUSB_HOST_ENUM_BUFFER_SIZE];
|
||||
|
||||
//------------- Reporter Task Data -------------//
|
||||
|
||||
//------------- Helper Function Prototypes -------------//
|
||||
static inline uint8_t get_new_address(void) ATTR_ALWAYS_INLINE;
|
||||
static inline uint8_t get_configure_number_for_device(tusb_desc_device_t* dev_desc) ATTR_ALWAYS_INLINE;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PUBLIC API (Parameter Verification is required)
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_device_state_t tuh_device_get_state (uint8_t const dev_addr)
|
||||
{
|
||||
TU_ASSERT( dev_addr <= CFG_TUSB_HOST_DEVICE_MAX, TUSB_DEVICE_STATE_INVALID_PARAMETER);
|
||||
return (tusb_device_state_t) usbh_devices[dev_addr].state;
|
||||
}
|
||||
|
||||
uint32_t tuh_device_get_mounted_class_flag(uint8_t dev_addr)
|
||||
{
|
||||
return tuh_device_is_configured(dev_addr) ? usbh_devices[dev_addr].flag_supported_class : 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CLASS-USBD API (don't require to verify parameters)
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_error_t usbh_init(void)
|
||||
{
|
||||
memclr_(usbh_devices, sizeof(usbh_device_info_t)*(CFG_TUSB_HOST_DEVICE_MAX+1));
|
||||
|
||||
TU_ASSERT_ERR( hcd_init() );
|
||||
|
||||
//------------- Enumeration & Reporter Task init -------------//
|
||||
enum_queue_hdl = osal_queue_create( ENUM_QUEUE_DEPTH, sizeof(uint32_t) );
|
||||
TU_ASSERT(enum_queue_hdl, TUSB_ERROR_OSAL_QUEUE_FAILED);
|
||||
|
||||
osal_task_create(usbh_enumeration_task, "usbh", 200, NULL, CFG_TUD_TASK_PRIO);
|
||||
|
||||
//------------- Semaphore, Mutex for Control Pipe -------------//
|
||||
for(uint8_t i=0; i<CFG_TUSB_HOST_DEVICE_MAX+1; i++) // including address zero
|
||||
{
|
||||
usbh_device_info_t * const p_device = &usbh_devices[i];
|
||||
|
||||
p_device->control.sem_hdl = osal_semaphore_create(1, 0);
|
||||
TU_ASSERT(p_device->control.sem_hdl, TUSB_ERROR_OSAL_SEMAPHORE_FAILED);
|
||||
|
||||
p_device->control.mutex_hdl = osal_mutex_create();
|
||||
TU_ASSERT(p_device->control.mutex_hdl, TUSB_ERROR_OSAL_MUTEX_FAILED);
|
||||
}
|
||||
|
||||
//------------- class init -------------//
|
||||
for (uint8_t class_index = 1; class_index < USBH_CLASS_DRIVER_COUNT; class_index++)
|
||||
{
|
||||
if (usbh_class_drivers[class_index].init)
|
||||
{
|
||||
usbh_class_drivers[class_index].init();
|
||||
}
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//------------- USBH control transfer -------------//
|
||||
// function called within a task, requesting os blocking services, subtask input parameter must be static/global variables or constant
|
||||
tusb_error_t usbh_control_xfer_subtask(uint8_t dev_addr, uint8_t bmRequestType, uint8_t bRequest,
|
||||
uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t* data)
|
||||
{
|
||||
static tusb_error_t error; // FIXME [CMSIS-RTX] use svc for OS API, error value changed after mutex release at the end of function
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
osal_mutex_wait(usbh_devices[dev_addr].control.mutex_hdl, OSAL_TIMEOUT_NORMAL, &error);
|
||||
STASK_ASSERT_ERR_HDLR(error, osal_mutex_release(usbh_devices[dev_addr].control.mutex_hdl));
|
||||
|
||||
usbh_devices[dev_addr].control.request = (tusb_control_request_t) {
|
||||
{.bmRequestType = bmRequestType},
|
||||
.bRequest = bRequest,
|
||||
.wValue = wValue,
|
||||
.wIndex = wIndex,
|
||||
.wLength = wLength
|
||||
};
|
||||
|
||||
#ifndef _TEST_
|
||||
usbh_devices[dev_addr].control.pipe_status = 0;
|
||||
#else
|
||||
usbh_devices[dev_addr].control.pipe_status = TUSB_EVENT_XFER_COMPLETE; // in Test project, mark as complete immediately
|
||||
#endif
|
||||
|
||||
error = hcd_pipe_control_xfer(dev_addr, &usbh_devices[dev_addr].control.request, data);
|
||||
if ( TUSB_ERROR_NONE == error ) osal_semaphore_wait(usbh_devices[dev_addr].control.sem_hdl, OSAL_TIMEOUT_NORMAL, &error);
|
||||
osal_mutex_release(usbh_devices[dev_addr].control.mutex_hdl);
|
||||
|
||||
STASK_ASSERT_ERR(error);
|
||||
if (TUSB_EVENT_XFER_STALLED == usbh_devices[dev_addr].control.pipe_status) STASK_RETURN(TUSB_ERROR_USBH_XFER_STALLED);
|
||||
if (TUSB_EVENT_XFER_ERROR == usbh_devices[dev_addr].control.pipe_status) STASK_RETURN(TUSB_ERROR_USBH_XFER_FAILED);
|
||||
|
||||
// STASK_ASSERT_HDLR(TUSB_ERROR_NONE == error &&
|
||||
// TUSB_EVENT_XFER_COMPLETE == usbh_devices[dev_addr].control.pipe_status,
|
||||
// tuh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_DEVICE_NOT_RESPOND, NULL) );
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
tusb_error_t usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) ATTR_ALWAYS_INLINE;
|
||||
tusb_error_t usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size)
|
||||
{
|
||||
osal_semaphore_reset( usbh_devices[dev_addr].control.sem_hdl );
|
||||
osal_mutex_reset( usbh_devices[dev_addr].control.mutex_hdl );
|
||||
|
||||
TU_ASSERT_ERR( hcd_pipe_control_open(dev_addr, max_packet_size) );
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
static inline tusb_error_t usbh_pipe_control_close(uint8_t dev_addr) ATTR_ALWAYS_INLINE;
|
||||
static inline tusb_error_t usbh_pipe_control_close(uint8_t dev_addr)
|
||||
{
|
||||
TU_ASSERT_ERR( hcd_pipe_control_close(dev_addr) );
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
// TODO [USBH] unify pipe status get
|
||||
//tusb_interface_status_t usbh_pipe_status_get(pipe_handle_t pipe_hdl)
|
||||
//{
|
||||
// return TUSB_INTERFACE_STATUS_BUSY;
|
||||
//}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-HCD ISR/Callback API
|
||||
//--------------------------------------------------------------------+
|
||||
// interrupt caused by a TD (with IOC=1) in pipe of class class_code
|
||||
void usbh_xfer_isr(pipe_handle_t pipe_hdl, uint8_t class_code, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
uint8_t class_index = std_class_code_to_index(class_code);
|
||||
if (TUSB_XFER_CONTROL == pipe_hdl.xfer_type)
|
||||
{
|
||||
usbh_devices[ pipe_hdl.dev_addr ].control.pipe_status = event;
|
||||
// usbh_devices[ pipe_hdl.dev_addr ].control.xferred_bytes = xferred_bytes; not yet neccessary
|
||||
osal_semaphore_post( usbh_devices[ pipe_hdl.dev_addr ].control.sem_hdl );
|
||||
}else if (usbh_class_drivers[class_index].isr)
|
||||
{
|
||||
usbh_class_drivers[class_index].isr(pipe_hdl, event, xferred_bytes);
|
||||
}else
|
||||
{
|
||||
TU_ASSERT(false); // something wrong, no one claims the isr's source
|
||||
}
|
||||
}
|
||||
|
||||
void usbh_hub_port_plugged_isr(uint8_t hub_addr, uint8_t hub_port)
|
||||
{
|
||||
usbh_enumerate_t enum_entry =
|
||||
{
|
||||
.core_id = usbh_devices[hub_addr].core_id,
|
||||
.hub_addr = hub_addr,
|
||||
.hub_port = hub_port
|
||||
};
|
||||
|
||||
osal_queue_send(enum_queue_hdl, &enum_entry);
|
||||
}
|
||||
|
||||
void usbh_hcd_rhport_plugged_isr(uint8_t hostid)
|
||||
{
|
||||
usbh_enumerate_t enum_entry =
|
||||
{
|
||||
.core_id = hostid,
|
||||
.hub_addr = 0,
|
||||
.hub_port = 0
|
||||
};
|
||||
|
||||
osal_queue_send(enum_queue_hdl, &enum_entry);
|
||||
}
|
||||
|
||||
// a device unplugged on hostid, hub_addr, hub_port
|
||||
// return true if found and unmounted device, false if cannot find
|
||||
static void usbh_device_unplugged(uint8_t hostid, uint8_t hub_addr, uint8_t hub_port)
|
||||
{
|
||||
bool is_found = false;
|
||||
//------------- find the all devices (star-network) under port that is unplugged -------------//
|
||||
for (uint8_t dev_addr = 0; dev_addr <= CFG_TUSB_HOST_DEVICE_MAX; dev_addr ++)
|
||||
{
|
||||
if (usbh_devices[dev_addr].core_id == hostid &&
|
||||
(hub_addr == 0 || usbh_devices[dev_addr].hub_addr == hub_addr) && // hub_addr == 0 & hub_port == 0 means roothub
|
||||
(hub_port == 0 || usbh_devices[dev_addr].hub_port == hub_port) &&
|
||||
usbh_devices[dev_addr].state != TUSB_DEVICE_STATE_UNPLUG)
|
||||
{
|
||||
// TODO Hub multiple level
|
||||
for (uint8_t class_index = 1; class_index < USBH_CLASS_DRIVER_COUNT; class_index++)
|
||||
{
|
||||
if ((usbh_devices[dev_addr].flag_supported_class & BIT_(class_index)) &&
|
||||
usbh_class_drivers[class_index].close)
|
||||
{
|
||||
usbh_class_drivers[class_index].close(dev_addr);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO refractor
|
||||
// set to REMOVING to allow HCD to clean up its cached data for this device
|
||||
// HCD must set this device's state to TUSB_DEVICE_STATE_UNPLUG when done
|
||||
usbh_devices[dev_addr].state = TUSB_DEVICE_STATE_REMOVING;
|
||||
usbh_devices[dev_addr].flag_supported_class = 0;
|
||||
|
||||
usbh_pipe_control_close(dev_addr);
|
||||
|
||||
|
||||
is_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_found) hcd_port_unplug(usbh_devices[0].core_id); // TODO hack
|
||||
|
||||
}
|
||||
|
||||
void usbh_hcd_rhport_unplugged_isr(uint8_t hostid)
|
||||
{
|
||||
usbh_enumerate_t enum_entry =
|
||||
{
|
||||
.core_id = hostid,
|
||||
.hub_addr = 0,
|
||||
.hub_port = 0
|
||||
};
|
||||
|
||||
osal_queue_send(enum_queue_hdl, &enum_entry);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// ENUMERATION TASK
|
||||
//--------------------------------------------------------------------+
|
||||
static tusb_error_t enumeration_body_subtask(void);
|
||||
|
||||
// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper
|
||||
// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with
|
||||
// forever loop cannot have any return at all.
|
||||
void usbh_enumeration_task(void* param)
|
||||
{
|
||||
(void) param;
|
||||
|
||||
OSAL_TASK_BEGIN
|
||||
enumeration_body_subtask();
|
||||
OSAL_TASK_END
|
||||
}
|
||||
|
||||
tusb_error_t enumeration_body_subtask(void)
|
||||
{
|
||||
enum {
|
||||
POWER_STABLE_DELAY = 500,
|
||||
RESET_DELAY = 200 // USB specs say only 50ms but many devices require much longer
|
||||
};
|
||||
|
||||
tusb_error_t error;
|
||||
usbh_enumerate_t enum_entry;
|
||||
|
||||
// for OSAL_NONE local variable won't retain value after blocking service sem_wait/queue_recv
|
||||
static uint8_t new_addr;
|
||||
static uint8_t configure_selected = 1; // TODO move
|
||||
static uint8_t *p_desc = NULL; // TODO move
|
||||
|
||||
OSAL_SUBTASK_BEGIN
|
||||
|
||||
osal_queue_receive(enum_queue_hdl, &enum_entry, OSAL_TIMEOUT_WAIT_FOREVER, &error);
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
usbh_devices[0].core_id = enum_entry.core_id; // TODO refractor integrate to device_pool
|
||||
usbh_devices[0].hub_addr = enum_entry.hub_addr;
|
||||
usbh_devices[0].hub_port = enum_entry.hub_port;
|
||||
usbh_devices[0].state = TUSB_DEVICE_STATE_UNPLUG;
|
||||
|
||||
//------------- connected/disconnected directly with roothub -------------//
|
||||
if ( usbh_devices[0].hub_addr == 0)
|
||||
{
|
||||
if( hcd_port_connect_status(usbh_devices[0].core_id) )
|
||||
{ // connection event
|
||||
osal_task_delay(POWER_STABLE_DELAY); // wait until device is stable. Increase this if the first 8 bytes is failed to get
|
||||
|
||||
if ( !hcd_port_connect_status(usbh_devices[0].core_id) ) STASK_RETURN(TUSB_ERROR_NONE); // exit if device unplugged while delaying
|
||||
|
||||
hcd_port_reset( usbh_devices[0].core_id ); // port must be reset to have correct speed operation
|
||||
osal_task_delay(RESET_DELAY);
|
||||
|
||||
usbh_devices[0].speed = hcd_port_speed_get( usbh_devices[0].core_id );
|
||||
}
|
||||
else
|
||||
{ // disconnection event
|
||||
usbh_device_unplugged(usbh_devices[0].core_id, 0, 0);
|
||||
STASK_RETURN(TUSB_ERROR_NONE); // restart task
|
||||
}
|
||||
}
|
||||
#if CFG_TUSB_HOST_HUB
|
||||
//------------- connected/disconnected via hub -------------//
|
||||
else
|
||||
{
|
||||
//------------- Get Port Status -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_OTHER),
|
||||
HUB_REQUEST_GET_STATUS, 0, usbh_devices[0].hub_port,
|
||||
4, enum_data_buffer ),
|
||||
error
|
||||
);
|
||||
// STASK_ASSERT_ERR( error );
|
||||
STASK_ASSERT_ERR_HDLR(error, hub_status_pipe_queue( usbh_devices[0].hub_addr) ); // TODO hub refractor
|
||||
|
||||
// Acknowledge Port Connection Change
|
||||
STASK_INVOKE( hub_port_clear_feature_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port, HUB_FEATURE_PORT_CONNECTION_CHANGE), error );
|
||||
|
||||
hub_port_status_response_t * p_port_status;
|
||||
p_port_status = ((hub_port_status_response_t *) enum_data_buffer);
|
||||
|
||||
if ( ! p_port_status->status_change.connect_status ) STASK_RETURN(TUSB_ERROR_NONE); // only handle connection change
|
||||
|
||||
if ( ! p_port_status->status_current.connect_status )
|
||||
{ // Disconnection event
|
||||
usbh_device_unplugged(usbh_devices[0].core_id, usbh_devices[0].hub_addr, usbh_devices[0].hub_port);
|
||||
|
||||
(void) hub_status_pipe_queue( usbh_devices[0].hub_addr ); // done with hub, waiting for next data on status pipe
|
||||
STASK_RETURN(TUSB_ERROR_NONE); // restart task
|
||||
}
|
||||
else
|
||||
{ // Connection Event
|
||||
STASK_INVOKE ( hub_port_reset_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port), error );
|
||||
// STASK_ASSERT_ERR( error );
|
||||
STASK_ASSERT_ERR_HDLR(error, hub_status_pipe_queue( usbh_devices[0].hub_addr) ); // TODO hub refractor
|
||||
|
||||
usbh_devices[0].speed = hub_port_get_speed();
|
||||
|
||||
// Acknowledge Port Reset Change
|
||||
STASK_INVOKE( hub_port_clear_feature_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port, HUB_FEATURE_PORT_RESET_CHANGE), error );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
STASK_ASSERT_ERR( usbh_pipe_control_open(0, 8) );
|
||||
usbh_devices[0].state = TUSB_DEVICE_STATE_ADDRESSED;
|
||||
|
||||
//------------- Get first 8 bytes of device descriptor to get Control Endpoint Size -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( 0, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_STANDARD, TUSB_REQ_RCPT_DEVICE),
|
||||
TUSB_REQ_GET_DESCRIPTOR, (TUSB_DESC_DEVICE << 8), 0,
|
||||
8, enum_data_buffer ),
|
||||
error
|
||||
);
|
||||
|
||||
//------------- Reset device again before Set Address -------------//
|
||||
if (usbh_devices[0].hub_addr == 0)
|
||||
{ // connected directly to roothub
|
||||
STASK_ASSERT_ERR(error); // TODO some slow device is observed to fail the very fist controller xfer, can try more times
|
||||
hcd_port_reset( usbh_devices[0].core_id ); // reset port after 8 byte descriptor
|
||||
osal_task_delay(RESET_DELAY);
|
||||
}
|
||||
#if CFG_TUSB_HOST_HUB
|
||||
else
|
||||
{ // connected via a hub
|
||||
STASK_ASSERT_ERR_HDLR(error, hub_status_pipe_queue( usbh_devices[0].hub_addr) ); // TODO hub refractor
|
||||
STASK_INVOKE ( hub_port_reset_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port), error );
|
||||
|
||||
if ( TUSB_ERROR_NONE == error )
|
||||
{ // Acknowledge Port Reset Change if Reset Successful
|
||||
STASK_INVOKE( hub_port_clear_feature_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port, HUB_FEATURE_PORT_RESET_CHANGE), error );
|
||||
}
|
||||
|
||||
(void) hub_status_pipe_queue( usbh_devices[0].hub_addr ); // done with hub, waiting for next data on status pipe
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------- Set new address -------------//
|
||||
new_addr = get_new_address();
|
||||
STASK_ASSERT(new_addr <= CFG_TUSB_HOST_DEVICE_MAX); // TODO notify application we reach max devices
|
||||
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( 0, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_STANDARD, TUSB_REQ_RCPT_DEVICE),
|
||||
TUSB_REQ_SET_ADDRESS, new_addr, 0,
|
||||
0, NULL ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
//------------- update port info & close control pipe of addr0 -------------//
|
||||
usbh_devices[new_addr].core_id = usbh_devices[0].core_id;
|
||||
usbh_devices[new_addr].hub_addr = usbh_devices[0].hub_addr;
|
||||
usbh_devices[new_addr].hub_port = usbh_devices[0].hub_port;
|
||||
usbh_devices[new_addr].speed = usbh_devices[0].speed;
|
||||
usbh_devices[new_addr].state = TUSB_DEVICE_STATE_ADDRESSED;
|
||||
|
||||
usbh_pipe_control_close(0);
|
||||
usbh_devices[0].state = TUSB_DEVICE_STATE_UNPLUG;
|
||||
|
||||
// open control pipe for new address
|
||||
STASK_ASSERT_ERR ( usbh_pipe_control_open(new_addr, ((tusb_desc_device_t*) enum_data_buffer)->bMaxPacketSize0 ) );
|
||||
|
||||
//------------- Get full device descriptor -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_STANDARD, TUSB_REQ_RCPT_DEVICE),
|
||||
TUSB_REQ_GET_DESCRIPTOR, (TUSB_DESC_DEVICE << 8), 0,
|
||||
18, enum_data_buffer ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
// update device info TODO alignment issue
|
||||
usbh_devices[new_addr].vendor_id = ((tusb_desc_device_t*) enum_data_buffer)->idVendor;
|
||||
usbh_devices[new_addr].product_id = ((tusb_desc_device_t*) enum_data_buffer)->idProduct;
|
||||
usbh_devices[new_addr].configure_count = ((tusb_desc_device_t*) enum_data_buffer)->bNumConfigurations;
|
||||
|
||||
configure_selected = get_configure_number_for_device((tusb_desc_device_t*) enum_data_buffer);
|
||||
STASK_ASSERT(configure_selected <= usbh_devices[new_addr].configure_count); // TODO notify application when invalid configuration
|
||||
|
||||
//------------- Get 9 bytes of configuration descriptor -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_STANDARD, TUSB_REQ_RCPT_DEVICE),
|
||||
TUSB_REQ_GET_DESCRIPTOR, (TUSB_DESC_CONFIGURATION << 8) | (configure_selected - 1), 0,
|
||||
9, enum_data_buffer ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR(error);
|
||||
STASK_ASSERT_HDLR( CFG_TUSB_HOST_ENUM_BUFFER_SIZE >= ((tusb_desc_configuration_t*)enum_data_buffer)->wTotalLength,
|
||||
tuh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_CONFIG_DESC_TOO_LONG, NULL) );
|
||||
|
||||
//------------- Get full configuration descriptor -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_STANDARD, TUSB_REQ_RCPT_DEVICE),
|
||||
TUSB_REQ_GET_DESCRIPTOR, (TUSB_DESC_CONFIGURATION << 8) | (configure_selected - 1), 0,
|
||||
CFG_TUSB_HOST_ENUM_BUFFER_SIZE, enum_data_buffer ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
// update configuration info
|
||||
usbh_devices[new_addr].interface_count = ((tusb_desc_configuration_t*) enum_data_buffer)->bNumInterfaces;
|
||||
|
||||
//------------- Set Configure -------------//
|
||||
STASK_INVOKE(
|
||||
usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_STANDARD, TUSB_REQ_RCPT_DEVICE),
|
||||
TUSB_REQ_SET_CONFIGURATION, configure_selected, 0,
|
||||
0, NULL ),
|
||||
error
|
||||
);
|
||||
STASK_ASSERT_ERR(error);
|
||||
|
||||
usbh_devices[new_addr].state = TUSB_DEVICE_STATE_CONFIGURED;
|
||||
|
||||
//------------- TODO Get String Descriptors -------------//
|
||||
|
||||
//------------- parse configuration & install drivers -------------//
|
||||
p_desc = enum_data_buffer + sizeof(tusb_desc_configuration_t);
|
||||
|
||||
// parse each interfaces
|
||||
while( p_desc < enum_data_buffer + ((tusb_desc_configuration_t*)enum_data_buffer)->wTotalLength )
|
||||
{
|
||||
// skip until we see interface descriptor
|
||||
if ( TUSB_DESC_INTERFACE != p_desc[DESCRIPTOR_OFFSET_TYPE] )
|
||||
{
|
||||
p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // skip the descriptor, increase by the descriptor's length
|
||||
}else
|
||||
{
|
||||
static uint8_t class_index; // has to be static as it is used to call class's open_subtask
|
||||
|
||||
class_index = std_class_code_to_index( ((tusb_desc_interface_t*) p_desc)->bInterfaceClass );
|
||||
STASK_ASSERT( class_index != 0 ); // class_index == 0 means corrupted data, abort enumeration
|
||||
|
||||
if (usbh_class_drivers[class_index].open_subtask &&
|
||||
!(class_index == TUSB_CLASS_HUB && usbh_devices[new_addr].hub_addr != 0))
|
||||
{ // supported class, TODO Hub disable multiple level
|
||||
static uint16_t length;
|
||||
length = 0;
|
||||
|
||||
STASK_INVOKE ( // parameters in task/sub_task must be static storage (static or global)
|
||||
usbh_class_drivers[class_index].open_subtask( new_addr, (tusb_desc_interface_t*) p_desc, &length ),
|
||||
error
|
||||
);
|
||||
|
||||
if (error == TUSB_ERROR_NONE)
|
||||
{
|
||||
STASK_ASSERT( length >= sizeof(tusb_desc_interface_t) );
|
||||
usbh_devices[new_addr].flag_supported_class |= BIT_(class_index);
|
||||
p_desc += length;
|
||||
}else // Interface open failed, for example a subclass is not supported
|
||||
{
|
||||
p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // skip this interface, the rest will be skipped by the above loop
|
||||
}
|
||||
} else // unsupported class (not enable or yet implemented)
|
||||
{
|
||||
p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // skip this interface, the rest will be skipped by the above loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tuh_device_mount_succeed_cb(new_addr);
|
||||
|
||||
OSAL_SUBTASK_END
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// REPORTER TASK & ITS DATA
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
static inline uint8_t get_new_address(void)
|
||||
{
|
||||
uint8_t addr;
|
||||
for (addr=1; addr <= CFG_TUSB_HOST_DEVICE_MAX; addr++)
|
||||
{
|
||||
if (usbh_devices[addr].state == TUSB_DEVICE_STATE_UNPLUG)
|
||||
break;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
static inline uint8_t get_configure_number_for_device(tusb_desc_device_t* dev_desc)
|
||||
{
|
||||
uint8_t config_num = 1;
|
||||
|
||||
// invoke callback to ask user which configuration to select
|
||||
if (tuh_device_attached_cb)
|
||||
{
|
||||
config_num = min8_of(1, tuh_device_attached_cb(dev_desc) );
|
||||
}
|
||||
|
||||
return config_num;
|
||||
}
|
||||
|
||||
#endif
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file usbh.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 group_usbh USB Host Core (USBH)
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_USBH_H_
|
||||
#define _TUSB_USBH_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "osal/osal.h" // TODO refractor move to common.h ?
|
||||
#include "hcd.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef enum tusb_interface_status_{
|
||||
TUSB_INTERFACE_STATUS_READY = 0,
|
||||
TUSB_INTERFACE_STATUS_BUSY,
|
||||
TUSB_INTERFACE_STATUS_COMPLETE,
|
||||
TUSB_INTERFACE_STATUS_ERROR,
|
||||
TUSB_INTERFACE_STATUS_INVALID_PARA
|
||||
} tusb_interface_status_t;
|
||||
|
||||
typedef struct {
|
||||
void (* const init) (void);
|
||||
tusb_error_t (* const open_subtask)(uint8_t, tusb_desc_interface_t const *, uint16_t*);
|
||||
void (* const isr) (pipe_handle_t, tusb_event_t, uint32_t);
|
||||
void (* const close) (uint8_t);
|
||||
} host_class_driver_t;
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
//tusb_error_t tusbh_configuration_set (uint8_t dev_addr, uint8_t configure_number) ATTR_WARN_UNUSED_RESULT;
|
||||
tusb_device_state_t tuh_device_get_state (uint8_t dev_addr) ATTR_WARN_UNUSED_RESULT ATTR_PURE;
|
||||
static inline bool tuh_device_is_configured(uint8_t dev_addr) ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT ATTR_PURE;
|
||||
static inline bool tuh_device_is_configured(uint8_t dev_addr)
|
||||
{
|
||||
return tuh_device_get_state(dev_addr) == TUSB_DEVICE_STATE_CONFIGURED;
|
||||
}
|
||||
uint32_t tuh_device_get_mounted_class_flag(uint8_t dev_addr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION CALLBACK
|
||||
//--------------------------------------------------------------------+
|
||||
ATTR_WEAK uint8_t tuh_device_attached_cb (tusb_desc_device_t const *p_desc_device) ATTR_WARN_UNUSED_RESULT;
|
||||
ATTR_WEAK void tuh_device_mount_succeed_cb (uint8_t dev_addr);
|
||||
ATTR_WEAK void tuh_device_mount_failed_cb(tusb_error_t error, tusb_desc_device_t const *p_desc_device); // TODO refractor remove desc_device
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CLASS-USBH & INTERNAL API
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef _TINY_USB_SOURCE_FILE_
|
||||
|
||||
|
||||
void usbh_enumeration_task(void* param);
|
||||
tusb_error_t usbh_init(void);
|
||||
|
||||
tusb_error_t usbh_control_xfer_subtask(uint8_t dev_addr, uint8_t bmRequestType, uint8_t bRequest,
|
||||
uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t* data);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_USBH_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,114 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file usbh_hcd.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 Group_HCD
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_USBH_HCD_H_
|
||||
#define _TUSB_USBH_HCD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "osal/osal.h"
|
||||
|
||||
#ifdef _TEST_
|
||||
#include "hcd.h"
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-HCD common data structure
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct ATTR_ALIGNED(4){
|
||||
uint8_t core_id;
|
||||
uint8_t hub_addr;
|
||||
uint8_t hub_port;
|
||||
uint8_t reserve;
|
||||
} usbh_enumerate_t;
|
||||
|
||||
typedef struct {
|
||||
//------------- port -------------//
|
||||
uint8_t core_id;
|
||||
uint8_t hub_addr;
|
||||
uint8_t hub_port;
|
||||
uint8_t speed;
|
||||
|
||||
//------------- device descriptor -------------//
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
uint8_t configure_count; // bNumConfigurations alias
|
||||
|
||||
//------------- configuration descriptor -------------//
|
||||
uint8_t interface_count; // bNumInterfaces alias
|
||||
|
||||
//------------- device -------------//
|
||||
volatile uint8_t state; // device state, value from enum tusbh_device_state_t
|
||||
uint32_t flag_supported_class; // a bitmap of supported class
|
||||
|
||||
//------------- control pipe -------------//
|
||||
struct {
|
||||
volatile uint8_t pipe_status;
|
||||
// uint8_t xferred_bytes; TODO not yet necessary
|
||||
tusb_control_request_t request;
|
||||
|
||||
osal_semaphore_t sem_hdl; // used to synchronize with HCD when control xfer complete
|
||||
osal_mutex_t mutex_hdl; // used to exclusively occupy control pipe
|
||||
} control;
|
||||
} usbh_device_info_t;
|
||||
|
||||
extern usbh_device_info_t usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1]; // including zero-address
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// callback from HCD ISR
|
||||
//--------------------------------------------------------------------+
|
||||
void usbh_xfer_isr(pipe_handle_t pipe_hdl, uint8_t class_code, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void usbh_hcd_rhport_plugged_isr(uint8_t hostid);
|
||||
void usbh_hcd_rhport_unplugged_isr(uint8_t hostid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_USBH_HCD_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,64 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file usbh_hub.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 group_usbh
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_USBH_HUB_H_
|
||||
#define _TUSB_USBH_HUB_H_
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
void usbh_hub_port_plugged_isr(uint8_t hub_addr, uint8_t hub_port);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_USBH_HUB_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,27 @@
|
||||
# License
|
||||
|
||||
<pre>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. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.</pre>
|
||||
@@ -0,0 +1,54 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file osal.c
|
||||
@author hathach
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, 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"
|
||||
#include "osal.h"
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TICK API
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUSB_OS == OPT_OS_FREERTOS
|
||||
|
||||
uint32_t tusb_hal_millis(void)
|
||||
{
|
||||
return ( ( ((uint64_t) xTaskGetTickCount()) * 1000) / configTICK_RATE_HZ );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef _TUSB_OSAL_H_
|
||||
#define _TUSB_OSAL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \addtogroup group_osal
|
||||
* @{ */
|
||||
|
||||
#include "tusb_option.h"
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
enum
|
||||
{
|
||||
OSAL_TIMEOUT_NOTIMEOUT = 0, // return immediately
|
||||
OSAL_TIMEOUT_NORMAL = 10, // default timeout
|
||||
OSAL_TIMEOUT_WAIT_FOREVER = 0xFFFFFFFFUL
|
||||
};
|
||||
|
||||
#define OSAL_TIMEOUT_CONTROL_XFER OSAL_TIMEOUT_WAIT_FOREVER
|
||||
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
#include "osal_none.h"
|
||||
|
||||
#else
|
||||
#if CFG_TUSB_OS == OPT_OS_FREERTOS
|
||||
#include "osal_freeRTOS.h"
|
||||
#else
|
||||
#error CFG_TUSB_OS is not defined or OS is not supported yet
|
||||
#endif
|
||||
|
||||
#define OSAL_TASK_BEGIN while(1) {
|
||||
#define OSAL_TASK_END }
|
||||
|
||||
//------------- Sub Task -------------//
|
||||
#define OSAL_SUBTASK_BEGIN
|
||||
#define OSAL_SUBTASK_END return TUSB_ERROR_NONE;
|
||||
|
||||
#define STASK_RETURN(_error) return _error;
|
||||
#define STASK_INVOKE(_subtask, _status) (_status) = _subtask
|
||||
|
||||
//------------- Sub Task Assert -------------//
|
||||
#define STASK_ASSERT_ERR(_err) VERIFY_ERR(_err)
|
||||
#define STASK_ASSERT_ERR_HDLR(_err, _func) VERIFY_ERR_HDLR(_err, _func)
|
||||
|
||||
#define STASK_ASSERT(_cond) VERIFY(_cond, TUSB_ERROR_OSAL_TASK_FAILED)
|
||||
#define STASK_ASSERT_HDLR(_cond, _func) VERIFY_HDLR(_cond, _func)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* _TUSB_OSAL_H_ */
|
||||
@@ -0,0 +1,200 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file osal_freeRTOS.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 group_osal
|
||||
* @{
|
||||
* \defgroup Group_FreeRTOS FreeRTOS
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_OSAL_FREERTOS_H_
|
||||
#define _TUSB_OSAL_FREERTOS_H_
|
||||
|
||||
//------------- FreeRTOS Headers -------------//
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
#include "queue.h"
|
||||
#include "task.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Helper to determine if we are in ISR to use ISR API (only cover ARM Cortex)
|
||||
static inline bool in_isr(void)
|
||||
{
|
||||
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk);
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TASK API
|
||||
//--------------------------------------------------------------------+
|
||||
#define OSAL_TASK_DEF(_name, _str, _func, _prio, _stack_sz) \
|
||||
uint8_t _name##_##buf[_stack_sz*sizeof(StackType_t)]; \
|
||||
osal_task_def_t _name = { .func = _func, .prio = _prio, .stack_sz = _stack_sz, .buf = _name##_##buf, .strname = _str };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*func)(void *param);
|
||||
|
||||
uint16_t prio;
|
||||
uint16_t stack_sz;
|
||||
void* buf;
|
||||
const char* strname;
|
||||
|
||||
StaticTask_t stask;
|
||||
}osal_task_def_t;
|
||||
|
||||
typedef TaskHandle_t osal_task_t;
|
||||
|
||||
static inline osal_task_t osal_task_create(osal_task_def_t* taskdef)
|
||||
{
|
||||
return xTaskCreateStatic(taskdef->func, taskdef->strname, taskdef->stack_sz, NULL, taskdef->prio, taskdef->buf, &taskdef->stask);
|
||||
}
|
||||
|
||||
static inline void osal_task_delay(uint32_t msec)
|
||||
{
|
||||
vTaskDelay( pdMS_TO_TICKS(msec) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// QUEUE API
|
||||
//--------------------------------------------------------------------+
|
||||
#define OSAL_QUEUE_DEF(_name, _depth, _type) \
|
||||
uint8_t _name##_##buf[_depth*sizeof(_type)];\
|
||||
osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t depth;
|
||||
uint16_t item_sz;
|
||||
void* buf;
|
||||
|
||||
StaticQueue_t sq;
|
||||
}osal_queue_def_t;
|
||||
|
||||
typedef QueueHandle_t osal_queue_t;
|
||||
|
||||
static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
|
||||
{
|
||||
return xQueueCreateStatic(qdef->depth, qdef->item_sz, qdef->buf, &qdef->sq);
|
||||
}
|
||||
|
||||
static inline void osal_queue_receive (osal_queue_t const queue_hdl, void *p_data, uint32_t msec, tusb_error_t *p_error)
|
||||
{
|
||||
uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? portMAX_DELAY : pdMS_TO_TICKS(msec);
|
||||
(*p_error) = ( xQueueReceive(queue_hdl, p_data, ticks) ? TUSB_ERROR_NONE : TUSB_ERROR_OSAL_TIMEOUT);
|
||||
}
|
||||
|
||||
static inline bool osal_queue_send_isr(osal_queue_t const queue_hdl, void const * data)
|
||||
{
|
||||
return xQueueSendToBackFromISR(queue_hdl, data, NULL);
|
||||
}
|
||||
|
||||
static inline bool osal_queue_send(osal_queue_t const queue_hdl, void const * data)
|
||||
{
|
||||
return xQueueSendToBack(queue_hdl, data, OSAL_TIMEOUT_WAIT_FOREVER) == pdTRUE;
|
||||
}
|
||||
|
||||
static inline void osal_queue_flush(osal_queue_t const queue_hdl)
|
||||
{
|
||||
// TODO move to thread context
|
||||
// xQueueReset(queue_hdl);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef StaticSemaphore_t osal_semaphore_def_t;
|
||||
typedef SemaphoreHandle_t osal_semaphore_t;
|
||||
|
||||
static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
|
||||
{
|
||||
return xSemaphoreCreateBinaryStatic(semdef);
|
||||
}
|
||||
|
||||
static inline bool osal_semaphore_post_isr(osal_semaphore_t sem_hdl)
|
||||
{
|
||||
return xSemaphoreGiveFromISR(sem_hdl, NULL) == pdTRUE;
|
||||
}
|
||||
|
||||
static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl)
|
||||
{
|
||||
return xSemaphoreGive(sem_hdl) == pdTRUE;
|
||||
}
|
||||
|
||||
static inline void osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec, tusb_error_t *p_error)
|
||||
{
|
||||
uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? portMAX_DELAY : pdMS_TO_TICKS(msec);
|
||||
(*p_error) = (xSemaphoreTake(sem_hdl, ticks) ? TUSB_ERROR_NONE : TUSB_ERROR_OSAL_TIMEOUT);
|
||||
}
|
||||
|
||||
static inline void osal_semaphore_reset_isr(osal_semaphore_t const sem_hdl)
|
||||
{
|
||||
xSemaphoreTakeFromISR(sem_hdl, NULL);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MUTEX API (priority inheritance)
|
||||
//--------------------------------------------------------------------+
|
||||
typedef SemaphoreHandle_t osal_mutex_t;
|
||||
|
||||
#define osal_mutex_create(x) xSemaphoreCreateMutex()
|
||||
|
||||
static inline bool osal_mutex_release(osal_mutex_t mutex_hdl)
|
||||
{
|
||||
return xSemaphoreGive(mutex_hdl);
|
||||
}
|
||||
|
||||
static inline void osal_mutex_wait(osal_mutex_t mutex_hdl, uint32_t msec, tusb_error_t *p_error)
|
||||
{
|
||||
uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? portMAX_DELAY : pdMS_TO_TICKS(msec);
|
||||
(*p_error) = (xSemaphoreTake(mutex_hdl, ticks) ? TUSB_ERROR_NONE : TUSB_ERROR_OSAL_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_OSAL_FREERTOS_H_ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file osal_none.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 group_osal
|
||||
* \defgroup Group_OSNone None OS
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_OSAL_NONE_H_
|
||||
#define _TUSB_OSAL_NONE_H_
|
||||
|
||||
#include "common/tusb_fifo.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TASK API
|
||||
// NOTES: Each blocking OSAL_NONE services such as semaphore wait,
|
||||
// queue receive embedded return statement, therefore local variable
|
||||
// retain value before/after such services needed to declare as static
|
||||
// OSAL_TASK_LOOP
|
||||
// {
|
||||
// OSAL_TASK_BEGIN
|
||||
//
|
||||
// task body statements
|
||||
//
|
||||
// OSAL_TASK_LOOP_ENG
|
||||
// }
|
||||
//
|
||||
// NOTE: no switch statement is allowed in Task and subtask
|
||||
//--------------------------------------------------------------------+
|
||||
#define OSAL_TASK_DEF(_name, _str, _func, _prio, _stack_sz) osal_task_def_t _name;
|
||||
|
||||
typedef uint8_t osal_task_def_t;
|
||||
typedef void* osal_task_t;
|
||||
|
||||
static inline osal_task_t osal_task_create(osal_task_def_t* taskdef)
|
||||
{
|
||||
(void) taskdef;
|
||||
return (osal_task_t) 1; // return non zero
|
||||
}
|
||||
|
||||
#define TASK_RESTART \
|
||||
_state = 0
|
||||
|
||||
#define OSAL_TASK_BEGIN \
|
||||
static uint16_t _state = 0; \
|
||||
ATTR_UNUSED static uint32_t _timeout = 0; \
|
||||
(void) _timeout; \
|
||||
switch(_state) { \
|
||||
case 0: {
|
||||
|
||||
#define OSAL_TASK_END \
|
||||
default: TASK_RESTART; break; \
|
||||
}} \
|
||||
return;
|
||||
|
||||
#define osal_task_delay(msec) \
|
||||
do { \
|
||||
_timeout = tusb_hal_millis(); \
|
||||
_state = __LINE__; case __LINE__: \
|
||||
if ( _timeout + msec > tusb_hal_millis() ) \
|
||||
return TUSB_ERROR_OSAL_WAITING; \
|
||||
}while(0)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SUBTASK (a sub function that uses OS blocking services & called by a task
|
||||
//--------------------------------------------------------------------+
|
||||
#define OSAL_SUBTASK_BEGIN OSAL_TASK_BEGIN
|
||||
|
||||
#define OSAL_SUBTASK_END \
|
||||
default: TASK_RESTART; break; \
|
||||
}} \
|
||||
return TUSB_ERROR_NONE;
|
||||
|
||||
#define STASK_INVOKE(_subtask, _status) \
|
||||
do { \
|
||||
_state = __LINE__; case __LINE__: \
|
||||
{ \
|
||||
(_status) = _subtask; /* invoke sub task */ \
|
||||
if (TUSB_ERROR_OSAL_WAITING == (_status)) return TUSB_ERROR_OSAL_WAITING; \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
//------------- Sub Task Assert -------------//
|
||||
#define STASK_RETURN(error) do { TASK_RESTART; return error; } while(0)
|
||||
|
||||
#define STASK_ASSERT_ERR(_err) VERIFY_ERR_HDLR(_err, verify_breakpoint(); TASK_RESTART)
|
||||
#define STASK_ASSERT_ERR_HDLR(_err, _func) VERIFY_ERR_HDLR(_err, verify_breakpoint(); _func; TASK_RESTART )
|
||||
|
||||
#define STASK_ASSERT(_cond) VERIFY_HDLR(_cond, verify_breakpoint(); TASK_RESTART)
|
||||
#define STASK_ASSERT_HDLR(_cond, _func) VERIFY_HDLR(_cond, verify_breakpoint(); _func; TASK_RESTART)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// QUEUE API
|
||||
//--------------------------------------------------------------------+
|
||||
#define OSAL_QUEUE_DEF(_name, _depth, _type) FIFO_DEF(_name, _depth, _type, false)
|
||||
|
||||
typedef fifo_t osal_queue_def_t;
|
||||
typedef fifo_t* osal_queue_t;
|
||||
|
||||
static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
|
||||
{
|
||||
fifo_clear(qdef);
|
||||
return (osal_queue_t) qdef;
|
||||
}
|
||||
|
||||
static inline bool osal_queue_send_isr(osal_queue_t const queue_hdl, void const * data)
|
||||
{
|
||||
return fifo_write( (fifo_t*) queue_hdl, data);
|
||||
}
|
||||
|
||||
static inline void osal_queue_flush(osal_queue_t const queue_hdl)
|
||||
{
|
||||
queue_hdl->count = queue_hdl->rd_idx = queue_hdl->wr_idx = 0;
|
||||
}
|
||||
|
||||
#define osal_queue_receive(queue_hdl, p_data, msec, p_error) \
|
||||
do { \
|
||||
_timeout = tusb_hal_millis(); \
|
||||
_state = __LINE__; case __LINE__: \
|
||||
if( queue_hdl->count == 0 ) { \
|
||||
if ( (msec != OSAL_TIMEOUT_WAIT_FOREVER) && ( _timeout + msec <= tusb_hal_millis()) ) \
|
||||
*(p_error) = TUSB_ERROR_OSAL_TIMEOUT; \
|
||||
else \
|
||||
return TUSB_ERROR_OSAL_WAITING; \
|
||||
} else{ \
|
||||
/*tusb_hal_int_disable_all();*/ \
|
||||
fifo_read(queue_hdl, p_data); \
|
||||
/*tusb_hal_int_enable_all();*/ \
|
||||
*(p_error) = TUSB_ERROR_NONE; \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
volatile uint16_t count;
|
||||
uint16_t max_count;
|
||||
}osal_semaphore_def_t;
|
||||
|
||||
typedef osal_semaphore_def_t* osal_semaphore_t;
|
||||
|
||||
|
||||
static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
|
||||
{
|
||||
semdef->count = 0;
|
||||
semdef->max_count = 1;
|
||||
return semdef;
|
||||
}
|
||||
|
||||
#define osal_semaphore_post_isr osal_semaphore_post
|
||||
|
||||
static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl)
|
||||
{
|
||||
if (sem_hdl->count < sem_hdl->max_count ) sem_hdl->count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void osal_semaphore_reset_isr(osal_semaphore_t sem_hdl)
|
||||
{
|
||||
sem_hdl->count = 0;
|
||||
}
|
||||
|
||||
#define osal_semaphore_wait(sem_hdl, msec, p_error) \
|
||||
do { \
|
||||
_timeout = tusb_hal_millis(); \
|
||||
_state = __LINE__; case __LINE__: \
|
||||
if( sem_hdl->count == 0 ) { \
|
||||
if ( (msec != OSAL_TIMEOUT_WAIT_FOREVER) && (_timeout + msec <= tusb_hal_millis()) ) \
|
||||
*(p_error) = TUSB_ERROR_OSAL_TIMEOUT; \
|
||||
else \
|
||||
return TUSB_ERROR_OSAL_WAITING; \
|
||||
} else{ \
|
||||
/*tusb_hal_int_disable_all();*/ \
|
||||
sem_hdl->count--; \
|
||||
/*tusb_hal_int_enable_all();*/ \
|
||||
*(p_error) = TUSB_ERROR_NONE; \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MUTEX API (priority inheritance)
|
||||
//--------------------------------------------------------------------+
|
||||
#if 0
|
||||
typedef osal_semaphore_t osal_mutex_t;
|
||||
|
||||
static inline osal_mutex_t osal_mutex_create(void)
|
||||
{
|
||||
return osal_semaphore_create(1, 0);
|
||||
}
|
||||
|
||||
static inline bool osal_mutex_release(osal_mutex_t mutex_hdl)
|
||||
{
|
||||
return osal_semaphore_post(mutex_hdl);
|
||||
}
|
||||
|
||||
#define osal_mutex_wait osal_semaphore_wait
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_OSAL_NONE_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,538 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file dcd_nrf5x.c
|
||||
@author hathach
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, 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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if MODE_DEVICE_SUPPORTED && CFG_TUSB_MCU == OPT_MCU_NRF5X
|
||||
|
||||
// TODO remove
|
||||
#include "nrf.h"
|
||||
#include "nrf_power.h"
|
||||
#include "nrf_usbd.h"
|
||||
#include "nrf_clock.h"
|
||||
|
||||
#include "nrf_drv_usbd_errata.h"
|
||||
|
||||
#include "device/dcd.h"
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* MACRO TYPEDEF CONSTANT ENUM
|
||||
*------------------------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
// Max allowed by USB specs
|
||||
MAX_PACKET_SIZE = 64,
|
||||
|
||||
// Mask of all END event (IN & OUT) for all endpoints. ENDEPIN0-7, ENDEPOUT0-7, ENDISOIN, ENDISOOUT
|
||||
EDPT_END_ALL_MASK = 0x1FFBFCUL
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* VARIABLE DECLARATION
|
||||
*------------------------------------------------------------------*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t* buffer;
|
||||
uint16_t total_len;
|
||||
uint16_t actual_len;
|
||||
uint8_t mps; // max packet size
|
||||
|
||||
// FIXME nrf52840 does not NAK OUT packet properly
|
||||
bool data_received;
|
||||
|
||||
} nom_xfer_t;
|
||||
|
||||
/*static*/ struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t* buffer;
|
||||
uint16_t total_len;
|
||||
uint16_t actual_len;
|
||||
|
||||
uint8_t dir;
|
||||
}control;
|
||||
|
||||
// Non control: 7 endpoints IN & OUT (offset 1)
|
||||
nom_xfer_t xfer[7][2];
|
||||
|
||||
volatile bool dma_running;
|
||||
}_dcd;
|
||||
|
||||
void bus_reset(void)
|
||||
{
|
||||
for(int i=0; i<8; i++)
|
||||
{
|
||||
NRF_USBD->TASKS_STARTEPIN[i] = 0;
|
||||
NRF_USBD->TASKS_STARTEPOUT[i] = 0;
|
||||
}
|
||||
|
||||
NRF_USBD->TASKS_STARTISOIN = 0;
|
||||
NRF_USBD->TASKS_STARTISOOUT = 0;
|
||||
|
||||
varclr_(&_dcd);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Controller API
|
||||
*------------------------------------------------------------------*/
|
||||
bool dcd_init (uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_connect (uint8_t rhport)
|
||||
{
|
||||
|
||||
}
|
||||
void dcd_disconnect (uint8_t rhport)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
// Set Address is automatically update by hw controller
|
||||
}
|
||||
|
||||
void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) config_num;
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Control
|
||||
*------------------------------------------------------------------*/
|
||||
static void edpt_dma_start(uint8_t epnum, uint8_t dir)
|
||||
{
|
||||
// Only one dma could be active, TODO resolve when this is called in ISR and dma is running
|
||||
while ( _dcd.dma_running )
|
||||
{
|
||||
TU_ASSERT ( 0 == (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk), );
|
||||
}
|
||||
|
||||
_dcd.dma_running = true;
|
||||
|
||||
if ( dir == TUSB_DIR_OUT )
|
||||
{
|
||||
NRF_USBD->TASKS_STARTEPOUT[epnum] = 1;
|
||||
} else
|
||||
{
|
||||
NRF_USBD->TASKS_STARTEPIN[epnum] = 1;
|
||||
}
|
||||
|
||||
__ISB(); __DSB();
|
||||
}
|
||||
|
||||
static void edpt_dma_end(void)
|
||||
{
|
||||
_dcd.dma_running = false;
|
||||
}
|
||||
|
||||
static void xact_control_start(void)
|
||||
{
|
||||
// Each transaction is up to 64 bytes
|
||||
uint8_t const xact_len = min16_of(_dcd.control.total_len-_dcd.control.actual_len, MAX_PACKET_SIZE);
|
||||
|
||||
if ( _dcd.control.dir == TUSB_DIR_OUT )
|
||||
{
|
||||
// TODO control out
|
||||
NRF_USBD->EPOUT[0].PTR = (uint32_t) _dcd.control.buffer;
|
||||
NRF_USBD->EPOUT[0].MAXCNT = xact_len;
|
||||
|
||||
NRF_USBD->TASKS_EP0RCVOUT = 1;
|
||||
__ISB(); __DSB();
|
||||
}else
|
||||
{
|
||||
NRF_USBD->EPIN[0].PTR = (uint32_t) _dcd.control.buffer;
|
||||
NRF_USBD->EPIN[0].MAXCNT = xact_len;
|
||||
|
||||
edpt_dma_start(0, TUSB_DIR_IN);
|
||||
}
|
||||
|
||||
_dcd.control.buffer += xact_len;
|
||||
_dcd.control.actual_len += xact_len;
|
||||
}
|
||||
|
||||
bool dcd_control_xfer (uint8_t rhport, tusb_dir_t dir, uint8_t * buffer, uint16_t length)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
if ( length )
|
||||
{
|
||||
// Data Phase
|
||||
_dcd.control.total_len = length;
|
||||
_dcd.control.actual_len = 0;
|
||||
_dcd.control.buffer = buffer;
|
||||
_dcd.control.dir = (uint8_t) dir;
|
||||
|
||||
xact_control_start();
|
||||
}else
|
||||
{
|
||||
// Status Phase
|
||||
NRF_USBD->TASKS_EP0STATUS = 1;
|
||||
__ISB(); __DSB();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
static inline nom_xfer_t* get_td(uint8_t epnum, uint8_t dir)
|
||||
{
|
||||
return &_dcd.xfer[epnum-1][dir];
|
||||
}
|
||||
|
||||
/*------------- Bulk/Int OUT transfer -------------*/
|
||||
|
||||
/**
|
||||
* Prepare Bulk/Int out transaction, Endpoint start to accept/ACK Data
|
||||
* @param epnum
|
||||
*/
|
||||
static void xact_out_prepare(uint8_t epnum)
|
||||
{
|
||||
// Write any value to size will allow hw to ACK (accept data)
|
||||
NRF_USBD->SIZE.EPOUT[epnum] = 0;
|
||||
__ISB(); __DSB();
|
||||
}
|
||||
|
||||
static void xact_out_dma(uint8_t epnum)
|
||||
{
|
||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
||||
|
||||
uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum];
|
||||
|
||||
// Trigger DMA move data from Endpoint -> SRAM
|
||||
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
|
||||
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
|
||||
|
||||
edpt_dma_start(epnum, TUSB_DIR_OUT);
|
||||
|
||||
xfer->buffer += xact_len;
|
||||
xfer->actual_len += xact_len;
|
||||
}
|
||||
|
||||
|
||||
/*------------- Bulk/Int IN transfer -------------*/
|
||||
|
||||
/**
|
||||
* Prepare Bulk/Int in transaction, transfer data from Memory -> Endpoint
|
||||
* @param epnum
|
||||
*/
|
||||
static void xact_in_prepare(uint8_t epnum)
|
||||
{
|
||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN);
|
||||
|
||||
// Each transaction is up to Max Packet Size
|
||||
uint8_t const xact_len = min16_of(xfer->total_len - xfer->actual_len, xfer->mps);
|
||||
|
||||
NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
|
||||
NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
|
||||
|
||||
xfer->buffer += xact_len;
|
||||
|
||||
edpt_dma_start(epnum, TUSB_DIR_IN);
|
||||
}
|
||||
|
||||
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
uint8_t const epnum = edpt_number(desc_edpt->bEndpointAddress);
|
||||
uint8_t const dir = edpt_dir(desc_edpt->bEndpointAddress);
|
||||
|
||||
_dcd.xfer[epnum-1][dir].mps = desc_edpt->wMaxPacketSize.size;
|
||||
|
||||
if ( dir == TUSB_DIR_OUT )
|
||||
{
|
||||
NRF_USBD->INTENSET = BIT_(USBD_INTEN_ENDEPOUT0_Pos + epnum);
|
||||
NRF_USBD->EPOUTEN |= BIT_(epnum);
|
||||
}else
|
||||
{
|
||||
NRF_USBD->INTENSET = BIT_(USBD_INTEN_ENDEPIN0_Pos + epnum);
|
||||
NRF_USBD->EPINEN |= BIT_(epnum);
|
||||
}
|
||||
__ISB(); __DSB();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
uint8_t const epnum = edpt_number(ep_addr);
|
||||
uint8_t const dir = edpt_dir(ep_addr);
|
||||
|
||||
nom_xfer_t* xfer = get_td(epnum, dir);
|
||||
|
||||
xfer->buffer = buffer;
|
||||
xfer->total_len = total_bytes;
|
||||
xfer->actual_len = 0;
|
||||
|
||||
if ( dir == TUSB_DIR_OUT )
|
||||
{
|
||||
if ( xfer->data_received )
|
||||
{
|
||||
xfer->data_received = false;
|
||||
|
||||
// FIXME nrf52840 does not NAK OUT packet properly
|
||||
// Data already received preivously
|
||||
xact_out_dma(epnum);
|
||||
}else
|
||||
{
|
||||
xact_out_prepare(epnum);
|
||||
}
|
||||
}else
|
||||
{
|
||||
xact_in_prepare(epnum);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
if ( ep_addr == 0)
|
||||
{
|
||||
NRF_USBD->TASKS_EP0STALL = 1;
|
||||
}else
|
||||
{
|
||||
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | ep_addr;
|
||||
}
|
||||
|
||||
__ISB(); __DSB();
|
||||
}
|
||||
|
||||
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
if ( ep_addr )
|
||||
{
|
||||
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
|
||||
}
|
||||
}
|
||||
|
||||
bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
// USBD shouldn't check control endpoint state
|
||||
if ( 0 == ep_addr ) return false;
|
||||
|
||||
uint8_t const epnum = edpt_number(ep_addr);
|
||||
uint8_t const dir = edpt_dir(ep_addr);
|
||||
|
||||
nom_xfer_t* xfer = get_td(epnum, dir);
|
||||
|
||||
return xfer->actual_len < xfer->total_len;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
*------------------------------------------------------------------*/
|
||||
void USBD_IRQHandler(void)
|
||||
{
|
||||
uint32_t const inten = NRF_USBD->INTEN;
|
||||
uint32_t int_status = 0;
|
||||
|
||||
volatile uint32_t* regevt = &NRF_USBD->EVENTS_USBRESET;
|
||||
|
||||
for(int i=0; i<32; i++)
|
||||
{
|
||||
if ( BIT_TEST_(inten, i) && regevt[i] )
|
||||
{
|
||||
int_status |= BIT_(i);
|
||||
|
||||
// event clear
|
||||
regevt[i] = 0;
|
||||
__ISB(); __DSB();
|
||||
}
|
||||
}
|
||||
|
||||
/*------------- Interrupt Processing -------------*/
|
||||
if ( int_status & USBD_INTEN_USBRESET_Msk )
|
||||
{
|
||||
bus_reset();
|
||||
|
||||
dcd_bus_event(0, USBD_BUS_EVENT_RESET);
|
||||
}
|
||||
|
||||
if ( int_status & EDPT_END_ALL_MASK )
|
||||
{
|
||||
// DMA complete move data from SRAM -> Endpoint
|
||||
edpt_dma_end();
|
||||
}
|
||||
|
||||
/*------------- Control Transfer -------------*/
|
||||
if ( int_status & USBD_INTEN_EP0SETUP_Msk )
|
||||
{
|
||||
uint8_t setup[8] = {
|
||||
NRF_USBD->BMREQUESTTYPE, NRF_USBD->BREQUEST, NRF_USBD->WVALUEL, NRF_USBD->WVALUEH,
|
||||
NRF_USBD->WINDEXL, NRF_USBD->WINDEXH, NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH
|
||||
};
|
||||
|
||||
dcd_setup_received(0, setup);
|
||||
}
|
||||
|
||||
if ( int_status & USBD_INTEN_EP0DATADONE_Msk )
|
||||
{
|
||||
if ( _dcd.control.dir == TUSB_DIR_OUT )
|
||||
{
|
||||
// OUT data from Host -> Endpoint
|
||||
// Trigger DMA to move Endpoint -> SRAM
|
||||
edpt_dma_start(0, TUSB_DIR_OUT);
|
||||
}else
|
||||
{
|
||||
// IN: data transferred from Endpoint -> Host
|
||||
if ( _dcd.control.actual_len < _dcd.control.total_len )
|
||||
{
|
||||
xact_control_start();
|
||||
}else
|
||||
{
|
||||
// Control IN complete
|
||||
dcd_control_complete(0, _dcd.control.actual_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OUT data moved from Endpoint -> SRAM
|
||||
if ( int_status & USBD_INTEN_ENDEPOUT0_Msk)
|
||||
{
|
||||
if ( _dcd.control.actual_len < _dcd.control.total_len )
|
||||
{
|
||||
xact_control_start();
|
||||
}else
|
||||
{
|
||||
// Control OUT complete
|
||||
dcd_control_complete(0, _dcd.control.actual_len);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------- Bulk/Interrupt Transfer -------------*/
|
||||
if ( int_status & USBD_INTEN_EPDATA_Msk)
|
||||
{
|
||||
uint32_t data_status = NRF_USBD->EPDATASTATUS;
|
||||
|
||||
nrf_usbd_epdatastatus_clear(data_status);
|
||||
|
||||
// In: data from Endpoint -> Host
|
||||
for(uint8_t epnum=1; epnum<8; epnum++)
|
||||
{
|
||||
if ( BIT_TEST_(data_status, epnum ) )
|
||||
{
|
||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN);
|
||||
|
||||
xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT;
|
||||
|
||||
if ( xfer->actual_len < xfer->total_len )
|
||||
{
|
||||
// more to xfer
|
||||
xact_in_prepare(epnum);
|
||||
} else
|
||||
{
|
||||
// BULK/INT IN complete
|
||||
dcd_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OUT: data from Host -> Endpoint
|
||||
for(uint8_t epnum=1; epnum<8; epnum++)
|
||||
{
|
||||
if ( BIT_TEST_(data_status, 16+epnum ) )
|
||||
{
|
||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
||||
|
||||
if (xfer->actual_len < xfer->total_len)
|
||||
{
|
||||
xact_out_dma(epnum);
|
||||
}else
|
||||
{
|
||||
// FIXME nrf52840 does not NAK OUT packet properly
|
||||
// It will always ACK next package although we haven't write to SIZE yet
|
||||
|
||||
// Mark this endpoint with data received
|
||||
xfer->data_received = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OUT: data from DMA -> SRAM
|
||||
for(uint8_t epnum=1; epnum<8; epnum++)
|
||||
{
|
||||
if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum) )
|
||||
{
|
||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
||||
|
||||
uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
|
||||
|
||||
// Transfer complete if transaction len < Max Packet Size or total len is transferred
|
||||
if ( (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
|
||||
{
|
||||
// Prepare for more data from Host -> Endpoint
|
||||
xact_out_prepare(epnum);
|
||||
}else
|
||||
{
|
||||
xfer->total_len = xfer->actual_len;
|
||||
|
||||
// BULK/INT OUT complete
|
||||
dcd_xfer_complete(0, epnum, xfer->actual_len, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// SOF interrupt
|
||||
if ( int_status & USBD_INTEN_SOF_Msk )
|
||||
{
|
||||
dcd_bus_event(0, USBD_BUS_EVENT_SOF);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,334 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file hal_nrf5x.c
|
||||
@author hathach
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2018, 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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if MODE_DEVICE_SUPPORTED && CFG_TUSB_MCU == OPT_MCU_NRF5X
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "nrf.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_clock.h"
|
||||
#include "nrf_usbd.h"
|
||||
#include "nrf_drv_usbd_errata.h"
|
||||
|
||||
#include "app_util_platform.h"
|
||||
|
||||
#ifdef SOFTDEVICE_PRESENT
|
||||
#include "nrf_sdm.h"
|
||||
#include "nrf_soc.h"
|
||||
#else
|
||||
#include "nrf_drv_power.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_hal.h"
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* MACRO TYPEDEF CONSTANT ENUM
|
||||
*------------------------------------------------------------------*/
|
||||
#define USB_NVIC_PRIO 7
|
||||
|
||||
// TODO switch to use nrfx_power.h in sdk15
|
||||
enum
|
||||
{
|
||||
NRFX_POWER_USB_EVT_DETECTED = 0,
|
||||
NRFX_POWER_USB_EVT_REMOVED,
|
||||
NRFX_POWER_USB_EVT_READY
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* FUNCTION DECLARATION
|
||||
*------------------------------------------------------------------*/
|
||||
void tusb_hal_nrf_power_event(uint32_t event);
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* HFCLK helper
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
// check if SD is present and enabled
|
||||
static bool is_sd_enabled(void)
|
||||
{
|
||||
uint8_t sd_en = false;
|
||||
|
||||
#ifdef SOFTDEVICE_PRESENT
|
||||
(void) sd_softdevice_is_enabled(&sd_en);
|
||||
#endif
|
||||
|
||||
return sd_en;
|
||||
}
|
||||
|
||||
static bool hfclk_running(void)
|
||||
{
|
||||
#ifdef SOFTDEVICE_PRESENT
|
||||
if ( is_sd_enabled() )
|
||||
{
|
||||
uint32_t is_running;
|
||||
(void) sd_clock_hfclk_is_running(&is_running);
|
||||
return (is_running ? true : false);
|
||||
}
|
||||
#endif
|
||||
|
||||
return nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY);
|
||||
}
|
||||
|
||||
static void hfclk_enable(void)
|
||||
{
|
||||
// already running, nothing to do
|
||||
if ( hfclk_running() ) return;
|
||||
|
||||
#ifdef SOFTDEVICE_PRESENT
|
||||
if ( is_sd_enabled() )
|
||||
{
|
||||
(void)sd_clock_hfclk_request();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
|
||||
nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART);
|
||||
}
|
||||
|
||||
static void hfclk_disable(void)
|
||||
{
|
||||
#ifdef SOFTDEVICE_PRESENT
|
||||
if ( is_sd_enabled() )
|
||||
{
|
||||
(void)sd_clock_hfclk_release();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTOP);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* TUSB HAL
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
// tusb_hal_nrf_power_event must be called by SOC event handler
|
||||
bool tusb_hal_init(void)
|
||||
{
|
||||
#ifdef SOFTDEVICE_PRESENT
|
||||
if ( is_sd_enabled() )
|
||||
{
|
||||
sd_power_usbdetected_enable(true);
|
||||
sd_power_usbpwrrdy_enable(true);
|
||||
sd_power_usbremoved_enable(true);
|
||||
|
||||
// USB power may already be ready at this time -> no event generated
|
||||
// We need to execute the handler based on the status
|
||||
uint32_t usb_reg;
|
||||
sd_power_usbregstatus_get(&usb_reg);
|
||||
|
||||
if (usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk )
|
||||
{
|
||||
tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_DETECTED);
|
||||
}
|
||||
|
||||
if (usb_reg & POWER_USBREGSTATUS_OUTPUTRDY_Msk )
|
||||
{
|
||||
tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_READY);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void tusb_hal_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
NVIC_EnableIRQ(USBD_IRQn);
|
||||
}
|
||||
|
||||
void tusb_hal_int_disable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
NVIC_DisableIRQ(USBD_IRQn);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Controller Start up Sequence (USBD 51.4 specs)
|
||||
*------------------------------------------------------------------*/
|
||||
void tusb_hal_nrf_power_event (uint32_t event)
|
||||
{
|
||||
switch ( event )
|
||||
{
|
||||
case NRFX_POWER_USB_EVT_DETECTED:
|
||||
if ( !NRF_USBD->ENABLE )
|
||||
{
|
||||
/* Prepare for READY event receiving */
|
||||
nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK);
|
||||
|
||||
/* Enable the peripheral */
|
||||
// ERRATA 171, 187, 166
|
||||
|
||||
// Somehow Errata 187 check failed for pca10056 1.0.0 (2018.19)
|
||||
if ( nrf_drv_usbd_errata_187() )
|
||||
{
|
||||
CRITICAL_REGION_ENTER();
|
||||
if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
|
||||
{
|
||||
*((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
|
||||
*((volatile uint32_t *) (0x4006ED14)) = 0x00000003;
|
||||
*((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
|
||||
}
|
||||
else
|
||||
{
|
||||
*((volatile uint32_t *) (0x4006ED14)) = 0x00000003;
|
||||
}
|
||||
CRITICAL_REGION_EXIT();
|
||||
}
|
||||
|
||||
if ( nrf_drv_usbd_errata_171() )
|
||||
{
|
||||
CRITICAL_REGION_ENTER();
|
||||
if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
|
||||
{
|
||||
*((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
|
||||
*((volatile uint32_t *) (0x4006EC14)) = 0x000000C0;
|
||||
*((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
|
||||
}
|
||||
else
|
||||
{
|
||||
*((volatile uint32_t *) (0x4006EC14)) = 0x000000C0;
|
||||
}
|
||||
CRITICAL_REGION_EXIT();
|
||||
}
|
||||
|
||||
nrf_usbd_enable();
|
||||
|
||||
// Enable HFCLK
|
||||
hfclk_enable();
|
||||
}
|
||||
break;
|
||||
|
||||
case NRFX_POWER_USB_EVT_READY:
|
||||
/* Waiting for USBD peripheral enabled */
|
||||
while ( !(USBD_EVENTCAUSE_READY_Msk & NRF_USBD->EVENTCAUSE) ) { }
|
||||
|
||||
nrf_usbd_eventcause_clear(USBD_EVENTCAUSE_READY_Msk);
|
||||
nrf_usbd_event_clear(USBD_EVENTCAUSE_READY_Msk);
|
||||
|
||||
if ( nrf_drv_usbd_errata_171() )
|
||||
{
|
||||
CRITICAL_REGION_ENTER();
|
||||
if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
|
||||
{
|
||||
*((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
|
||||
*((volatile uint32_t *) (0x4006EC14)) = 0x00000000;
|
||||
*((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
|
||||
}
|
||||
else
|
||||
{
|
||||
*((volatile uint32_t *) (0x4006EC14)) = 0x00000000;
|
||||
}
|
||||
|
||||
CRITICAL_REGION_EXIT();
|
||||
}
|
||||
|
||||
// Somehow Errata 187 check failed for pca10056 1.0.0 (2018.19)
|
||||
if ( nrf_drv_usbd_errata_187() )
|
||||
{
|
||||
CRITICAL_REGION_ENTER();
|
||||
if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
|
||||
{
|
||||
*((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
|
||||
*((volatile uint32_t *) (0x4006ED14)) = 0x00000000;
|
||||
*((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
|
||||
}
|
||||
else
|
||||
{
|
||||
*((volatile uint32_t *) (0x4006ED14)) = 0x00000000;
|
||||
}
|
||||
CRITICAL_REGION_EXIT();
|
||||
}
|
||||
|
||||
if ( nrf_drv_usbd_errata_166() )
|
||||
{
|
||||
*((volatile uint32_t *) (NRF_USBD_BASE + 0x800)) = 0x7E3;
|
||||
*((volatile uint32_t *) (NRF_USBD_BASE + 0x804)) = 0x40;
|
||||
|
||||
__ISB();
|
||||
__DSB();
|
||||
}
|
||||
|
||||
nrf_usbd_isosplit_set(NRF_USBD_ISOSPLIT_Half);
|
||||
|
||||
// Enable interrupt. SOF is used as CDC auto flush
|
||||
NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_USBEVENT_Msk | USBD_INTEN_ACCESSFAULT_Msk |
|
||||
USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk |
|
||||
USBD_INTEN_EPDATA_Msk | ((CFG_TUD_CDC && CFG_TUD_CDC_FLUSH_ON_SOF) ? USBD_INTEN_SOF_Msk : 0);
|
||||
|
||||
// Enable interrupt, Priorities 0,1,4,5 (nRF52) are reserved for SoftDevice
|
||||
NVIC_SetPriority(USBD_IRQn, USB_NVIC_PRIO);
|
||||
NVIC_ClearPendingIRQ(USBD_IRQn);
|
||||
NVIC_EnableIRQ(USBD_IRQn);
|
||||
|
||||
// Wait for HFCLK
|
||||
while ( !hfclk_running() )
|
||||
{
|
||||
}
|
||||
|
||||
// Enable pull up
|
||||
nrf_usbd_pullup_enable();
|
||||
break;
|
||||
|
||||
case NRFX_POWER_USB_EVT_REMOVED:
|
||||
if ( NRF_USBD->ENABLE )
|
||||
{
|
||||
// Abort all transfers
|
||||
|
||||
// Disable pull up
|
||||
nrf_usbd_pullup_disable();
|
||||
|
||||
// Disable Interrupt
|
||||
NVIC_DisableIRQ(USBD_IRQn);
|
||||
|
||||
// disable all interrupt
|
||||
NRF_USBD->INTENCLR = NRF_USBD->INTEN;
|
||||
|
||||
nrf_usbd_disable();
|
||||
hfclk_disable();
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,570 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file dcd_lpc_11uxx_13uxx.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_DEVICE_SUPPORTED && (CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13UXX)
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
// NOTE: despite of being very the same to lpc13uxx controller, lpc11u's controller cannot queue transfer more than
|
||||
// endpoint's max packet size and need some soft DMA helper
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "hal/hal.h"
|
||||
#include "osal/osal.h"
|
||||
#include "common/timeout_timer.h"
|
||||
|
||||
#include "device/dcd.h"
|
||||
#include "usbd_dcd.h"
|
||||
#include "dcd_lpc_11uxx_13uxx.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
#define DCD_11U_13U_QHD_COUNT 10
|
||||
|
||||
enum {
|
||||
DCD_11U_13U_MAX_BYTE_PER_TD = (CFG_TUSB_MCU == OPT_MCU_LPC11UXX ? 64 : 1023)
|
||||
};
|
||||
|
||||
#ifdef __CC_ARM
|
||||
#pragma diag_suppress 66 // Suppress Keil warnings #66-D: enumeration value is out of "int" range
|
||||
#endif
|
||||
|
||||
enum {
|
||||
INT_MASK_SOF = BIT_(30),
|
||||
INT_MASK_DEVICE_STATUS = BIT_(31)
|
||||
};
|
||||
|
||||
#ifdef __CC_ARM
|
||||
#pragma diag_suppress 66 // Suppress Keil warnings #66-D: enumeration value is out of "int" range
|
||||
#endif
|
||||
|
||||
enum {
|
||||
CMDSTAT_DEVICE_ADDR_MASK = BIT_(7 )-1,
|
||||
CMDSTAT_DEVICE_ENABLE_MASK = BIT_(7 ),
|
||||
CMDSTAT_SETUP_RECEIVED_MASK = BIT_(8 ),
|
||||
CMDSTAT_DEVICE_CONNECT_MASK = BIT_(16), ///< reflect the softconnect only, does not reflect the actual attached state
|
||||
CMDSTAT_DEVICE_SUSPEND_MASK = BIT_(17),
|
||||
CMDSTAT_CONNECT_CHANGE_MASK = BIT_(24),
|
||||
CMDSTAT_SUSPEND_CHANGE_MASK = BIT_(25),
|
||||
CMDSTAT_RESET_CHANGE_MASK = BIT_(26),
|
||||
CMDSTAT_VBUS_DEBOUNCED_MASK = BIT_(28),
|
||||
};
|
||||
|
||||
// buffer input must be 64 byte alignment
|
||||
typedef struct ATTR_PACKED
|
||||
{
|
||||
volatile uint16_t buff_addr_offset ; ///< The address offset is updated by hardware after each successful reception/transmission of a packet. Hardware increments the original value with the integer value when the packet size is divided by 64.
|
||||
|
||||
volatile uint16_t nbytes : 10 ; ///< For OUT endpoints this is the number of bytes that can be received in this buffer. For IN endpoints this is the number of bytes that must be transmitted. HW decrements this value with the packet size every time when a packet is successfully transferred. Note: If a short packet is received on an OUT endpoint, the active bit will be cleared and the NBytes value indicates the remaining buffer space that is not used. Software calculates the received number of bytes by subtracting the remaining NBytes from the programmed value.
|
||||
uint16_t is_isochronous : 1 ;
|
||||
uint16_t feedback_toggle : 1 ; ///< For bulk endpoints and isochronous endpoints this bit is reserved and must be set to zero. For the control endpoint zero this bit is used as the toggle value. When the toggle reset bit is set, the data toggle is updated with the value programmed in this bit. When the endpoint is used as an interrupt endpoint, it can be set to the following values. 0: Interrupt endpoint in ‘toggle mode’ 1: Interrupt endpoint in ‘rate feedback mode’. This means that the data toggle is fixed to zero for all data packets. When the interrupt endpoint is in ‘rate feedback mode’, the TR bit must always be set to zero.
|
||||
uint16_t toggle_reset : 1 ; ///< When software sets this bit to one, the HW will set the toggle value equal to the value indicated in the “toggle value” (TV) bit. For the control endpoint zero, this is not needed to be used because the hardware resets the endpoint toggle to one for both directions when a setup token is received. For the other endpoints, the toggle can only be reset to zero when the endpoint is reset.
|
||||
uint16_t stall : 1 ; ///< 0: The selected endpoint is not stalled 1: The selected endpoint is stalled The Active bit has always higher priority than the Stall bit. This means that a Stall handshake is only sent when the active bit is zero and the stall bit is one. Software can only modify this bit when the active bit is zero.
|
||||
uint16_t disable : 1 ; ///< 0: The selected endpoint is enabled. 1: The selected endpoint is disabled. If a USB token is received for an endpoint that has the disabled bit set, hardware will ignore the token and not return any data or handshake. When a bus reset is received, software must set the disable bit of all endpoints to 1. Software can only modify this bit when the active bit is zero.
|
||||
volatile uint16_t active : 1 ; ///< The buffer is enabled. HW can use the buffer to store received OUT data or to transmit data on the IN endpoint. Software can only set this bit to ‘1’. As long as this bit is set to one, software is not allowed to update any of the values in this 32-bit word. In case software wants to deactivate the buffer, it must write a one to the corresponding “skip” bit in the USB Endpoint skip register. Hardware can only write this bit to zero. It will do this when it receives a short packet or when the NBytes field transitions to zero or when software has written a one to the “skip” bit.
|
||||
}dcd_11u_13u_qhd_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(dcd_11u_13u_qhd_t) == 4, "size is not correct" );
|
||||
|
||||
// NOTE data will be transferred as soon as dcd get request by dcd_pipe(_queue)_xfer using double buffering.
|
||||
// If there is another dcd_edpt_xfer request, the new request will be saved and executed when the first is done.
|
||||
// next_td stored the 2nd request information
|
||||
// current_td is used to keep track of number of remaining & xferred bytes of the current request.
|
||||
// queued_bytes_in_buff keep track of number of bytes queued to each buffer (in case of short packet)
|
||||
|
||||
typedef struct {
|
||||
dcd_11u_13u_qhd_t qhd[DCD_11U_13U_QHD_COUNT][2]; ///< must be 256 byte alignment, 2 for double buffer
|
||||
|
||||
// start at 80, the size should not exceed 48 (for setup_request align at 128)
|
||||
struct {
|
||||
uint16_t buff_addr_offset;
|
||||
uint16_t total_bytes;
|
||||
}next_td[DCD_11U_13U_QHD_COUNT];
|
||||
|
||||
uint32_t current_ioc; ///< interrupt on complete mask for current TD
|
||||
uint32_t next_ioc; ///< interrupt on complete mask for next TD
|
||||
|
||||
// must start from 128
|
||||
ATTR_ALIGNED(64) tusb_control_request_t setup_request;
|
||||
|
||||
struct {
|
||||
uint16_t remaining_bytes; ///< expected bytes of the queued transfer
|
||||
uint16_t xferred_total; ///< xferred bytes of the current transfer
|
||||
|
||||
uint16_t queued_bytes_in_buff[2]; ///< expected bytes that are queued for each buffer
|
||||
}current_td[DCD_11U_13U_QHD_COUNT];
|
||||
|
||||
uint8_t class_code[DCD_11U_13U_QHD_COUNT]; ///< class where the endpoints belongs to TODO no need for control endpoints
|
||||
|
||||
}dcd_11u_13u_data_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// CFG_TUSB_ATTR_USBRAM must have ATTR_ALIGNED(64) for lpc11u & lpc13u
|
||||
#ifdef __ICCARM__
|
||||
ATTR_ALIGNED(256) CFG_TUSB_ATTR_USBRAM // for IAR the first ATTR_ALIGNED takes effect
|
||||
#else
|
||||
CFG_TUSB_ATTR_USBRAM ATTR_ALIGNED(256) // GCC & Keil the last ATTR_ALIGNED takes effect
|
||||
#endif
|
||||
STATIC_VAR dcd_11u_13u_data_t dcd_data;
|
||||
|
||||
static inline uint16_t addr_offset(void const * p_buffer) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint16_t addr_offset(void const * p_buffer)
|
||||
{
|
||||
TU_ASSERT( (((uint32_t) p_buffer) & 0x3f) == 0, 0 );
|
||||
return (uint16_t) ( (((uint32_t) p_buffer) >> 6 ) & 0xFFFF) ;
|
||||
}
|
||||
|
||||
static void queue_xfer_to_buffer(uint8_t ep_id, uint8_t buff_idx, uint16_t buff_addr_offset, uint16_t total_bytes);
|
||||
static void pipe_queue_xfer(uint8_t ep_id, uint16_t buff_addr_offset, uint16_t total_bytes);
|
||||
static void queue_xfer_in_next_td(uint8_t ep_id);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROLLER API
|
||||
//--------------------------------------------------------------------+
|
||||
void dcd_connect(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
LPC_USB->DEVCMDSTAT |= CMDSTAT_DEVICE_CONNECT_MASK;
|
||||
}
|
||||
|
||||
void dcd_set_config(uint8_t rhport, uint8_t config_num)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
LPC_USB->DEVCMDSTAT &= ~CMDSTAT_DEVICE_ADDR_MASK;
|
||||
LPC_USB->DEVCMDSTAT |= dev_addr;
|
||||
}
|
||||
|
||||
bool dcd_init(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
LPC_USB->EPLISTSTART = (uint32_t) dcd_data.qhd;
|
||||
LPC_USB->DATABUFSTART = 0x20000000; // only SRAM1 & USB RAM can be used for transfer
|
||||
|
||||
LPC_USB->INTSTAT = LPC_USB->INTSTAT; // clear all pending interrupt
|
||||
LPC_USB->INTEN = INT_MASK_DEVICE_STATUS;
|
||||
LPC_USB->DEVCMDSTAT |= CMDSTAT_DEVICE_ENABLE_MASK | CMDSTAT_DEVICE_CONNECT_MASK |
|
||||
CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
|
||||
|
||||
NVIC_EnableIRQ(USB_IRQn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bus_reset(void)
|
||||
{
|
||||
memclr_(&dcd_data, sizeof(dcd_11u_13u_data_t));
|
||||
for(uint8_t ep_id = 2; ep_id < DCD_11U_13U_QHD_COUNT; ep_id++)
|
||||
{ // disable all non-control endpoints on bus reset
|
||||
dcd_data.qhd[ep_id][0].disable = dcd_data.qhd[ep_id][1].disable = 1;
|
||||
}
|
||||
|
||||
dcd_data.qhd[0][1].buff_addr_offset = addr_offset(&dcd_data.setup_request);
|
||||
|
||||
LPC_USB->EPINUSE = 0;
|
||||
LPC_USB->EPBUFCFG = 0; // all start with single buffer
|
||||
LPC_USB->EPSKIP = 0xFFFFFFFF;
|
||||
|
||||
LPC_USB->INTSTAT = LPC_USB->INTSTAT; // clear all pending interrupt
|
||||
LPC_USB->DEVCMDSTAT |= CMDSTAT_SETUP_RECEIVED_MASK; // clear setup received interrupt
|
||||
LPC_USB->INTEN = INT_MASK_DEVICE_STATUS | BIT_(0) | BIT_(1); // enable device status & control endpoints
|
||||
}
|
||||
|
||||
static void endpoint_non_control_isr(uint32_t int_status)
|
||||
{
|
||||
for(uint8_t ep_id = 2; ep_id < DCD_11U_13U_QHD_COUNT; ep_id++ )
|
||||
{
|
||||
if ( BIT_TEST_(int_status, ep_id) )
|
||||
{
|
||||
dcd_11u_13u_qhd_t * const arr_qhd = dcd_data.qhd[ep_id];
|
||||
|
||||
// when double buffering, the complete buffer is opposed to the current active buffer in EPINUSE
|
||||
uint8_t const buff_idx = LPC_USB->EPINUSE & BIT_(ep_id) ? 0 : 1;
|
||||
uint16_t const xferred_bytes = dcd_data.current_td[ep_id].queued_bytes_in_buff[buff_idx] - arr_qhd[buff_idx].nbytes;
|
||||
|
||||
dcd_data.current_td[ep_id].xferred_total += xferred_bytes;
|
||||
|
||||
// there are still data to transfer.
|
||||
if ( (arr_qhd[buff_idx].nbytes == 0) && (dcd_data.current_td[ep_id].remaining_bytes > 0) )
|
||||
{ // NOTE although buff_addr_offset has been increased when xfer is completed
|
||||
// but we still need to increase it one more as we are using double buffering.
|
||||
queue_xfer_to_buffer(ep_id, buff_idx, arr_qhd[buff_idx].buff_addr_offset+1, dcd_data.current_td[ep_id].remaining_bytes);
|
||||
}
|
||||
// short packet or (no more byte and both buffers are finished)
|
||||
else if ( (arr_qhd[buff_idx].nbytes > 0) || !arr_qhd[1-buff_idx].active )
|
||||
{ // current TD (request) is completed
|
||||
LPC_USB->EPSKIP = BIT_SET_(LPC_USB->EPSKIP, ep_id); // skip other endpoint in case of short-package
|
||||
|
||||
dcd_data.current_td[ep_id].remaining_bytes = 0;
|
||||
|
||||
if ( BIT_TEST_(dcd_data.current_ioc, ep_id) )
|
||||
{
|
||||
edpt_hdl_t edpt_hdl =
|
||||
{
|
||||
.rhport = 0,
|
||||
.index = ep_id,
|
||||
.class_code = dcd_data.class_code[ep_id]
|
||||
};
|
||||
|
||||
dcd_data.current_ioc = BIT_CLR_(dcd_data.current_ioc, edpt_hdl.index);
|
||||
|
||||
// TODO no way determine if the transfer is failed or not
|
||||
dcd_xfer_complete(edpt_hdl, dcd_data.current_td[ep_id].xferred_total, true);
|
||||
}
|
||||
|
||||
//------------- Next TD is available -------------//
|
||||
if ( dcd_data.next_td[ep_id].total_bytes != 0 )
|
||||
{
|
||||
queue_xfer_in_next_td(ep_id);
|
||||
}
|
||||
}else
|
||||
{
|
||||
// transfer complete, there is no more remaining bytes, but this buffer is not the last transaction (the other is)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void endpoint_control_isr(uint32_t int_status)
|
||||
{
|
||||
uint8_t const ep_id = ( int_status & BIT_(0) ) ? 0 : 1;
|
||||
|
||||
// there are still data to transfer.
|
||||
if ( (dcd_data.qhd[ep_id][0].nbytes == 0) && (dcd_data.current_td[ep_id].remaining_bytes > 0) )
|
||||
{
|
||||
queue_xfer_to_buffer(ep_id, 0, dcd_data.qhd[ep_id][0].buff_addr_offset, dcd_data.current_td[ep_id].remaining_bytes);
|
||||
}else
|
||||
{
|
||||
dcd_data.current_td[ep_id].remaining_bytes = 0;
|
||||
|
||||
if ( BIT_TEST_(dcd_data.current_ioc, ep_id) )
|
||||
{
|
||||
edpt_hdl_t edpt_hdl = { .rhport = 0 };
|
||||
|
||||
dcd_data.current_ioc = BIT_CLR_(dcd_data.current_ioc, ep_id);
|
||||
|
||||
// FIXME xferred_byte for control xfer is not needed now !!!
|
||||
dcd_xfer_complete(edpt_hdl, 0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hal_dcd_isr(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
uint32_t const int_enable = LPC_USB->INTEN;
|
||||
uint32_t const int_status = LPC_USB->INTSTAT & int_enable;
|
||||
LPC_USB->INTSTAT = int_status; // Acknowledge handled interrupt
|
||||
|
||||
if (int_status == 0) return;
|
||||
|
||||
uint32_t const dev_cmd_stat = LPC_USB->DEVCMDSTAT;
|
||||
|
||||
//------------- Device Status -------------//
|
||||
if ( int_status & INT_MASK_DEVICE_STATUS )
|
||||
{
|
||||
LPC_USB->DEVCMDSTAT |= CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
|
||||
if ( dev_cmd_stat & CMDSTAT_RESET_CHANGE_MASK) // bus reset
|
||||
{
|
||||
bus_reset();
|
||||
dcd_bus_event(0, USBD_BUS_EVENT_RESET);
|
||||
}
|
||||
|
||||
if (dev_cmd_stat & CMDSTAT_CONNECT_CHANGE_MASK)
|
||||
{ // device disconnect
|
||||
if (dev_cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
|
||||
{ // debouncing as this can be set when device is powering
|
||||
dcd_bus_event(0, USBD_BUS_EVENT_UNPLUGGED);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO support suspend & resume
|
||||
if (dev_cmd_stat & CMDSTAT_SUSPEND_CHANGE_MASK)
|
||||
{
|
||||
if (dev_cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK)
|
||||
{ // suspend signal, bus idle for more than 3ms
|
||||
// Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
|
||||
if (dev_cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
|
||||
{
|
||||
dcd_bus_event(0, USBD_BUS_EVENT_SUSPENDED);
|
||||
}
|
||||
}
|
||||
}
|
||||
// else
|
||||
// { // resume signal
|
||||
// dcd_bus_event(0, USBD_BUS_EVENT_RESUME);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
//------------- Setup Received -------------//
|
||||
if ( BIT_TEST_(int_status, 0) && (dev_cmd_stat & CMDSTAT_SETUP_RECEIVED_MASK) )
|
||||
{ // received control request from host
|
||||
// copy setup request & acknowledge so that the next setup can be received by hw
|
||||
dcd_setup_received(rhport, (uint8_t*)&dcd_data.setup_request);
|
||||
|
||||
// NXP control flowchart clear Active & Stall on both Control IN/OUT endpoints
|
||||
dcd_data.qhd[0][0].stall = dcd_data.qhd[1][0].stall = 0;
|
||||
|
||||
LPC_USB->DEVCMDSTAT |= CMDSTAT_SETUP_RECEIVED_MASK;
|
||||
dcd_data.qhd[0][1].buff_addr_offset = addr_offset(&dcd_data.setup_request);
|
||||
}
|
||||
//------------- Control Endpoint -------------//
|
||||
else if ( int_status & 0x03 )
|
||||
{
|
||||
endpoint_control_isr(int_status);
|
||||
}
|
||||
|
||||
//------------- Non-Control Endpoints -------------//
|
||||
if( int_status & ~(0x03UL) )
|
||||
{
|
||||
endpoint_non_control_isr(int_status);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROL PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
void dcd_control_stall(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
// TODO cannot able to STALL Control OUT endpoint !!!!! FIXME try some walk-around
|
||||
dcd_data.qhd[0][0].stall = dcd_data.qhd[1][0].stall = 1;
|
||||
}
|
||||
|
||||
bool dcd_control_xfer(uint8_t rhport, tusb_dir_t dir, uint8_t * p_buffer, uint16_t length, bool int_on_complete)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
// determine Endpoint where Data & Status phase occurred (IN or OUT)
|
||||
uint8_t const ep_data = (dir == TUSB_DIR_IN) ? 1 : 0;
|
||||
uint8_t const ep_status = 1 - ep_data;
|
||||
|
||||
dcd_data.current_ioc = int_on_complete ? BIT_SET_(dcd_data.current_ioc, ep_status) : BIT_CLR_(dcd_data.current_ioc, ep_status);
|
||||
|
||||
//------------- Data Phase -------------//
|
||||
if (length)
|
||||
{
|
||||
dcd_data.current_td[ep_data].remaining_bytes = length;
|
||||
dcd_data.current_td[ep_data].xferred_total = 0;
|
||||
|
||||
queue_xfer_to_buffer(ep_data, 0, addr_offset(p_buffer), length);
|
||||
}
|
||||
|
||||
//------------- Status Phase -------------//
|
||||
dcd_data.current_td[ep_status].remaining_bytes = 0;
|
||||
dcd_data.current_td[ep_status].xferred_total = 0;
|
||||
|
||||
queue_xfer_to_buffer(ep_status, 0, 0, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PIPE HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr)
|
||||
{
|
||||
return 2*(endpoint_addr & 0x0F) + ((endpoint_addr & TUSB_DIR_IN_MASK) ? 1 : 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline uint8_t edpt_phy2log(uint8_t physical_endpoint) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint8_t edpt_phy2log(uint8_t physical_endpoint)
|
||||
{
|
||||
return physical_endpoint/2;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// BULK/INTERRUPT/ISOCHRONOUS PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
void dcd_edpt_stall(edpt_hdl_t edpt_hdl)
|
||||
{
|
||||
dcd_data.qhd[edpt_hdl.index][0].stall = dcd_data.qhd[edpt_hdl.index][1].stall = 1;
|
||||
}
|
||||
|
||||
bool dcd_pipe_is_stalled(edpt_hdl_t edpt_hdl)
|
||||
{
|
||||
return dcd_data.qhd[edpt_hdl.index][0].stall || dcd_data.qhd[edpt_hdl.index][1].stall;
|
||||
}
|
||||
|
||||
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t edpt_addr)
|
||||
{
|
||||
uint8_t ep_id = edpt_addr2phy(edpt_addr);
|
||||
// uint8_t active_buffer = BIT_TEST_(LPC_USB->EPINUSE, ep_id) ? 1 : 0;
|
||||
|
||||
dcd_data.qhd[ep_id][0].stall = dcd_data.qhd[ep_id][1].stall = 0;
|
||||
|
||||
// since the next transfer always take place on buffer0 --> clear buffer0 toggle
|
||||
dcd_data.qhd[ep_id][0].toggle_reset = 1;
|
||||
dcd_data.qhd[ep_id][0].feedback_toggle = 0;
|
||||
|
||||
//------------- clear stall must carry on any previously queued transfer -------------//
|
||||
if ( dcd_data.next_td[ep_id].total_bytes != 0 )
|
||||
{
|
||||
queue_xfer_in_next_td(ep_id);
|
||||
}
|
||||
}
|
||||
|
||||
edpt_hdl_t dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc, uint8_t class_code)
|
||||
{
|
||||
(void) rhport;
|
||||
edpt_hdl_t const null_handle = { 0 };
|
||||
|
||||
if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) return null_handle; // TODO not support ISO yet
|
||||
|
||||
TU_ASSERT (p_endpoint_desc->wMaxPacketSize.size <= 64, null_handle); // TODO ISO can be 1023, but ISO not supported now
|
||||
|
||||
// TODO prevent to open if endpoint size is not 64
|
||||
|
||||
//------------- Prepare Queue Head -------------//
|
||||
uint8_t ep_id = edpt_addr2phy(p_endpoint_desc->bEndpointAddress);
|
||||
|
||||
TU_ASSERT( dcd_data.qhd[ep_id][0].disable && dcd_data.qhd[ep_id][1].disable, null_handle ); // endpoint must not previously opened, normally this means running out of endpoints
|
||||
|
||||
memclr_(dcd_data.qhd[ep_id], 2*sizeof(dcd_11u_13u_qhd_t));
|
||||
dcd_data.qhd[ep_id][0].is_isochronous = dcd_data.qhd[ep_id][1].is_isochronous = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
|
||||
dcd_data.class_code[ep_id] = class_code;
|
||||
|
||||
dcd_data.qhd[ep_id][0].disable = dcd_data.qhd[ep_id][1].disable = 0;
|
||||
|
||||
LPC_USB->EPBUFCFG |= BIT_(ep_id);
|
||||
LPC_USB->INTEN |= BIT_(ep_id);
|
||||
|
||||
return (edpt_hdl_t)
|
||||
{
|
||||
.rhport = 0,
|
||||
.index = ep_id,
|
||||
.class_code = class_code
|
||||
};
|
||||
}
|
||||
|
||||
bool dcd_edpt_busy(edpt_hdl_t edpt_hdl)
|
||||
{
|
||||
return dcd_data.qhd[edpt_hdl.index][0].active || dcd_data.qhd[edpt_hdl.index][1].active;
|
||||
}
|
||||
|
||||
static void queue_xfer_to_buffer(uint8_t ep_id, uint8_t buff_idx, uint16_t buff_addr_offset, uint16_t total_bytes)
|
||||
{
|
||||
uint16_t const queued_bytes = min16_of(total_bytes, DCD_11U_13U_MAX_BYTE_PER_TD);
|
||||
|
||||
dcd_data.current_td[ep_id].queued_bytes_in_buff[buff_idx] = queued_bytes;
|
||||
dcd_data.current_td[ep_id].remaining_bytes -= queued_bytes;
|
||||
|
||||
dcd_data.qhd[ep_id][buff_idx].buff_addr_offset = buff_addr_offset;
|
||||
dcd_data.qhd[ep_id][buff_idx].nbytes = queued_bytes;
|
||||
|
||||
dcd_data.qhd[ep_id][buff_idx].active = 1;
|
||||
}
|
||||
|
||||
static void pipe_queue_xfer(uint8_t ep_id, uint16_t buff_addr_offset, uint16_t total_bytes)
|
||||
{
|
||||
dcd_data.current_td[ep_id].remaining_bytes = total_bytes;
|
||||
dcd_data.current_td[ep_id].xferred_total = 0;
|
||||
dcd_data.current_td[ep_id].queued_bytes_in_buff[0] = 0;
|
||||
dcd_data.current_td[ep_id].queued_bytes_in_buff[1] = 0;
|
||||
|
||||
LPC_USB->EPINUSE = BIT_CLR_(LPC_USB->EPINUSE , ep_id); // force HW to use buffer0
|
||||
|
||||
// need to queue buffer1 first, as activate buffer0 can causes controller does transferring immediately
|
||||
// while buffer1 is not ready yet
|
||||
if ( total_bytes > DCD_11U_13U_MAX_BYTE_PER_TD)
|
||||
{
|
||||
queue_xfer_to_buffer(ep_id, 1, buff_addr_offset+1, total_bytes - DCD_11U_13U_MAX_BYTE_PER_TD);
|
||||
}
|
||||
|
||||
queue_xfer_to_buffer(ep_id, 0, buff_addr_offset, total_bytes);
|
||||
}
|
||||
|
||||
static void queue_xfer_in_next_td(uint8_t ep_id)
|
||||
{
|
||||
dcd_data.current_ioc |= ( dcd_data.next_ioc & BIT_(ep_id) ); // copy next IOC to current IOC
|
||||
|
||||
pipe_queue_xfer(ep_id, dcd_data.next_td[ep_id].buff_addr_offset, dcd_data.next_td[ep_id].total_bytes);
|
||||
|
||||
dcd_data.next_td[ep_id].total_bytes = 0; // clear this field as it is used to indicate whehther next TD available
|
||||
}
|
||||
|
||||
tusb_error_t dcd_edpt_queue_xfer(edpt_hdl_t edpt_hdl, uint8_t * buffer, uint16_t total_bytes)
|
||||
{
|
||||
TU_ASSERT( !dcd_edpt_busy(edpt_hdl), TUSB_ERROR_INTERFACE_IS_BUSY); // endpoint must not in transferring
|
||||
|
||||
dcd_data.current_ioc = BIT_CLR_(dcd_data.current_ioc, edpt_hdl.index);
|
||||
|
||||
pipe_queue_xfer(edpt_hdl.index, addr_offset(buffer), total_bytes);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t dcd_edpt_xfer(edpt_hdl_t edpt_hdl, uint8_t* buffer, uint16_t total_bytes, bool int_on_complete)
|
||||
{
|
||||
if( dcd_edpt_busy(edpt_hdl) || dcd_pipe_is_stalled(edpt_hdl) )
|
||||
{ // save this transfer data to next td if pipe is busy or already been stalled
|
||||
dcd_data.next_td[edpt_hdl.index].buff_addr_offset = addr_offset(buffer);
|
||||
dcd_data.next_td[edpt_hdl.index].total_bytes = total_bytes;
|
||||
|
||||
dcd_data.next_ioc = int_on_complete ? BIT_SET_(dcd_data.next_ioc, edpt_hdl.index) : BIT_CLR_(dcd_data.next_ioc, edpt_hdl.index);
|
||||
}else
|
||||
{
|
||||
dcd_data.current_ioc = int_on_complete ? BIT_SET_(dcd_data.current_ioc, edpt_hdl.index) : BIT_CLR_(dcd_data.current_ioc, edpt_hdl.index);
|
||||
|
||||
pipe_queue_xfer(edpt_hdl.index, addr_offset(buffer), total_bytes);
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file dcd_lpc13xx_12adc.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 group_dcd
|
||||
* \defgroup group_dcd_lpc11_13u LPC11uxx LPC13uxx
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_DCD_LPC13XX_12ADC_H_
|
||||
#define _TUSB_DCD_LPC13XX_12ADC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_DCD_LPC13XX_12ADC_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,532 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file dcd_lpc175x_6x.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_DEVICE_SUPPORTED && (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X)
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "device/dcd.h"
|
||||
#include "dcd_lpc175x_6x.h"
|
||||
#include "usbd_dcd.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
#define DCD_QHD_MAX 32
|
||||
#define DCD_QTD_MAX 32 // TODO scale with configure
|
||||
|
||||
typedef struct {
|
||||
volatile dcd_dma_descriptor_t* udca[DCD_QHD_MAX]; // must be 128 byte aligned
|
||||
dcd_dma_descriptor_t dd[DCD_QTD_MAX][2]; // each endpoints can have up to 2 DD queued at a time TODO 0-1 are not used, offset to reduce memory
|
||||
|
||||
uint8_t class_code[DCD_QHD_MAX];
|
||||
|
||||
struct {
|
||||
uint8_t* p_data;
|
||||
uint16_t remaining_bytes;
|
||||
uint8_t int_on_complete;
|
||||
}control_dma;
|
||||
|
||||
}dcd_data_t;
|
||||
|
||||
CFG_TUSB_ATTR_USBRAM ATTR_ALIGNED(128) STATIC_VAR dcd_data_t dcd_data;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
static void bus_reset(void);
|
||||
static tusb_error_t pipe_control_read(void * buffer, uint16_t length);
|
||||
static tusb_error_t pipe_control_write(void const * buffer, uint16_t length);
|
||||
static tusb_error_t pipe_control_xfer(uint8_t ep_id, uint8_t* p_buffer, uint16_t length);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PIPE HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr) ATTR_CONST ATTR_ALWAYS_INLINE;
|
||||
static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr)
|
||||
{
|
||||
return 2*(endpoint_addr & 0x0F) + ((endpoint_addr & TUSB_DIR_IN_MASK) ? 1 : 0);
|
||||
}
|
||||
|
||||
static inline void edpt_set_max_packet_size(uint8_t ep_id, uint16_t max_packet_size) ATTR_ALWAYS_INLINE;
|
||||
static inline void edpt_set_max_packet_size(uint8_t ep_id, uint16_t max_packet_size)
|
||||
{ // follows example in 11.10.4.2
|
||||
LPC_USB->USBReEp |= BIT_(ep_id);
|
||||
LPC_USB->USBEpInd = ep_id; // select index before setting packet size
|
||||
LPC_USB->USBMaxPSize = max_packet_size;
|
||||
|
||||
#ifndef _TEST_
|
||||
while ((LPC_USB->USBDevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {} // TODO can be omitted
|
||||
LPC_USB->USBDevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-DCD API
|
||||
//--------------------------------------------------------------------+
|
||||
static void bus_reset(void)
|
||||
{
|
||||
// step 7 : slave mode set up
|
||||
LPC_USB->USBEpIntClr = 0xFFFFFFFF; // clear all pending interrupt
|
||||
LPC_USB->USBDevIntClr = 0xFFFFFFFF; // clear all pending interrupt
|
||||
LPC_USB->USBEpIntEn = (uint32_t) BIN8(11); // control endpoint cannot use DMA, non-control all use DMA
|
||||
LPC_USB->USBEpIntPri = 0; // same priority for all endpoint
|
||||
|
||||
// step 8 : DMA set up
|
||||
LPC_USB->USBEpDMADis = 0xFFFFFFFF; // firstly disable all dma
|
||||
LPC_USB->USBDMARClr = 0xFFFFFFFF; // clear all pending interrupt
|
||||
LPC_USB->USBEoTIntClr = 0xFFFFFFFF;
|
||||
LPC_USB->USBNDDRIntClr = 0xFFFFFFFF;
|
||||
LPC_USB->USBSysErrIntClr = 0xFFFFFFFF;
|
||||
|
||||
memclr_(&dcd_data, sizeof(dcd_data_t));
|
||||
}
|
||||
|
||||
bool dcd_init(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
//------------- user manual 11.13 usb device controller initialization -------------// LPC_USB->USBEpInd = 0;
|
||||
// step 6 : set up control endpoint
|
||||
edpt_set_max_packet_size(0, CFG_TUD_ENDOINT0_SIZE);
|
||||
edpt_set_max_packet_size(1, CFG_TUD_ENDOINT0_SIZE);
|
||||
|
||||
bus_reset();
|
||||
|
||||
LPC_USB->USBDevIntEn = (DEV_INT_DEVICE_STATUS_MASK | DEV_INT_ENDPOINT_SLOW_MASK | DEV_INT_ERROR_MASK);
|
||||
LPC_USB->USBUDCAH = (uint32_t) dcd_data.udca;
|
||||
LPC_USB->USBDMAIntEn = (DMA_INT_END_OF_XFER_MASK | DMA_INT_ERROR_MASK );
|
||||
|
||||
sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 1); // connect
|
||||
|
||||
NVIC_EnableIRQ(USB_IRQn);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
static void endpoint_non_control_isr(uint32_t eot_int)
|
||||
{
|
||||
for(uint8_t ep_id = 2; ep_id < DCD_QHD_MAX; ep_id++ )
|
||||
{
|
||||
if ( BIT_TEST_(eot_int, ep_id) )
|
||||
{
|
||||
dcd_dma_descriptor_t* const p_first_dd = &dcd_data.dd[ep_id][0];
|
||||
dcd_dma_descriptor_t* const p_last_dd = dcd_data.dd[ep_id] + (p_first_dd->is_next_valid ? 1 : 0); // Maximum is 2 QTD are queued in an endpoint
|
||||
|
||||
// only handle when Controller already finished the last DD
|
||||
if ( dcd_data.udca[ep_id] == p_last_dd )
|
||||
{
|
||||
dcd_data.udca[ep_id] = p_first_dd; // UDCA currently points to the last DD, change to the fixed DD
|
||||
p_first_dd->buffer_length = 0; // buffer length is used to determined if first dd is queued in pipe xfer function
|
||||
|
||||
if ( p_last_dd->int_on_complete )
|
||||
{
|
||||
edpt_hdl_t edpt_hdl =
|
||||
{
|
||||
.rhport = 0,
|
||||
.index = ep_id,
|
||||
.class_code = dcd_data.class_code[ep_id]
|
||||
};
|
||||
bool succeeded = (p_last_dd->status == DD_STATUS_NORMAL || p_last_dd->status == DD_STATUS_DATA_UNDERUN) ? true : false;
|
||||
|
||||
dcd_xfer_complete(edpt_hdl, p_last_dd->present_count, succeeded); // report only xferred bytes in the IOC qtd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void endpoint_control_isr(void)
|
||||
{
|
||||
uint32_t const interrupt_enable = LPC_USB->USBEpIntEn;
|
||||
uint32_t const endpoint_int_status = LPC_USB->USBEpIntSt & interrupt_enable;
|
||||
// LPC_USB->USBEpIntClr = endpoint_int_status; // acknowledge interrupt TODO cannot immediately acknowledge setup packet
|
||||
|
||||
//------------- Setup Recieved-------------//
|
||||
if ( (endpoint_int_status & BIT_(0)) &&
|
||||
(sie_read(SIE_CMDCODE_ENDPOINT_SELECT+0, 1) & SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK) )
|
||||
{
|
||||
(void) sie_read(SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT+0, 1); // clear setup bit
|
||||
|
||||
tusb_control_request_t control_request;
|
||||
pipe_control_read(&control_request, 8); // TODO read before clear setup above
|
||||
dcd_setup_received(0, (uint8_t*) &control_request);
|
||||
}
|
||||
else if (endpoint_int_status & 0x03)
|
||||
{
|
||||
uint8_t const ep_id = ( endpoint_int_status & BIT_(0) ) ? 0 : 1;
|
||||
|
||||
if ( dcd_data.control_dma.remaining_bytes > 0 )
|
||||
{ // there are still data to transfer
|
||||
pipe_control_xfer(ep_id, dcd_data.control_dma.p_data, dcd_data.control_dma.remaining_bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
dcd_data.control_dma.remaining_bytes = 0;
|
||||
|
||||
if ( BIT_TEST_(dcd_data.control_dma.int_on_complete, ep_id) )
|
||||
{
|
||||
edpt_hdl_t edpt_hdl = { .rhport = 0, .class_code = 0 };
|
||||
dcd_data.control_dma.int_on_complete = 0;
|
||||
|
||||
// FIXME xferred_byte for control xfer is not needed now !!!
|
||||
dcd_xfer_complete(edpt_hdl, 0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LPC_USB->USBEpIntClr = endpoint_int_status; // acknowledge interrupt TODO cannot immediately acknowledge setup packet
|
||||
}
|
||||
|
||||
void hal_dcd_isr(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
uint32_t const device_int_enable = LPC_USB->USBDevIntEn;
|
||||
uint32_t const device_int_status = LPC_USB->USBDevIntSt & device_int_enable;
|
||||
LPC_USB->USBDevIntClr = device_int_status;// Acknowledge handled interrupt
|
||||
|
||||
//------------- usb bus event -------------//
|
||||
if (device_int_status & DEV_INT_DEVICE_STATUS_MASK)
|
||||
{
|
||||
uint8_t const dev_status_reg = sie_read(SIE_CMDCODE_DEVICE_STATUS, 1);
|
||||
if (dev_status_reg & SIE_DEV_STATUS_RESET_MASK)
|
||||
{
|
||||
bus_reset();
|
||||
dcd_bus_event(0, USBD_BUS_EVENT_RESET);
|
||||
}
|
||||
|
||||
if (dev_status_reg & SIE_DEV_STATUS_CONNECT_CHANGE_MASK)
|
||||
{ // device is disconnected, require using VBUS (P1_30)
|
||||
dcd_bus_event(0, USBD_BUS_EVENT_UNPLUGGED);
|
||||
}
|
||||
|
||||
if (dev_status_reg & SIE_DEV_STATUS_SUSPEND_CHANGE_MASK)
|
||||
{
|
||||
if (dev_status_reg & SIE_DEV_STATUS_SUSPEND_MASK)
|
||||
{
|
||||
dcd_bus_event(0, USBD_BUS_EVENT_SUSPENDED);
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// dcd_bus_event(0, USBD_BUS_EVENT_RESUME);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
//------------- Control Endpoint (Slave Mode) -------------//
|
||||
if (device_int_status & DEV_INT_ENDPOINT_SLOW_MASK)
|
||||
{
|
||||
endpoint_control_isr();
|
||||
}
|
||||
|
||||
//------------- Non-Control Endpoint (DMA Mode) -------------//
|
||||
uint32_t const dma_int_enable = LPC_USB->USBDMAIntEn;
|
||||
uint32_t const dma_int_status = LPC_USB->USBDMAIntSt & dma_int_enable;
|
||||
|
||||
if (dma_int_status & DMA_INT_END_OF_XFER_MASK)
|
||||
{
|
||||
uint32_t eot_int = LPC_USB->USBEoTIntSt;
|
||||
LPC_USB->USBEoTIntClr = eot_int; // acknowledge interrupt source
|
||||
|
||||
endpoint_non_control_isr(eot_int);
|
||||
}
|
||||
|
||||
if (device_int_status & DEV_INT_ERROR_MASK || dma_int_status & DMA_INT_ERROR_MASK)
|
||||
{
|
||||
uint32_t error_status = sie_read(SIE_CMDCODE_READ_ERROR_STATUS, 1);
|
||||
(void) error_status;
|
||||
// TU_ASSERT(false, (void) 0);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD API - CONTROLLER
|
||||
//--------------------------------------------------------------------+
|
||||
void dcd_connect(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 1);
|
||||
}
|
||||
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
sie_write(SIE_CMDCODE_SET_ADDRESS, 1, 0x80 | dev_addr); // 7th bit is : device_enable
|
||||
}
|
||||
|
||||
void dcd_set_config(uint8_t rhport, uint8_t config_num)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) config_num;
|
||||
sie_write(SIE_CMDCODE_CONFIGURE_DEVICE, 1, 1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PIPE CONTROL HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
static inline uint16_t length_byte2dword(uint16_t length_in_bytes) ATTR_ALWAYS_INLINE ATTR_CONST;
|
||||
static inline uint16_t length_byte2dword(uint16_t length_in_bytes)
|
||||
{
|
||||
return (length_in_bytes + 3) / 4; // length_in_dword
|
||||
}
|
||||
|
||||
static tusb_error_t pipe_control_xfer(uint8_t ep_id, uint8_t* p_buffer, uint16_t length)
|
||||
{
|
||||
uint16_t const packet_len = min16_of(length, CFG_TUD_ENDOINT0_SIZE);
|
||||
|
||||
if (ep_id)
|
||||
{
|
||||
TU_ASSERT_ERR ( pipe_control_write(p_buffer, packet_len) );
|
||||
}else
|
||||
{
|
||||
TU_ASSERT_ERR ( pipe_control_read(p_buffer, packet_len) );
|
||||
}
|
||||
|
||||
dcd_data.control_dma.remaining_bytes -= packet_len;
|
||||
dcd_data.control_dma.p_data += packet_len;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
static tusb_error_t pipe_control_write(void const * buffer, uint16_t length)
|
||||
{
|
||||
uint32_t const * p_write_data = (uint32_t const *) buffer;
|
||||
|
||||
LPC_USB->USBCtrl = USBCTRL_WRITE_ENABLE_MASK; // logical endpoint = 0
|
||||
LPC_USB->USBTxPLen = length;
|
||||
|
||||
for (uint16_t count = 0; count < length_byte2dword(length); count++)
|
||||
{
|
||||
LPC_USB->USBTxData = *p_write_data; // NOTE: cortex M3 have no problem with alignment
|
||||
p_write_data++;
|
||||
}
|
||||
|
||||
LPC_USB->USBCtrl = 0;
|
||||
|
||||
// select control IN & validate the endpoint
|
||||
sie_write(SIE_CMDCODE_ENDPOINT_SELECT+1, 0, 0);
|
||||
sie_write(SIE_CMDCODE_BUFFER_VALIDATE , 0, 0);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
static tusb_error_t pipe_control_read(void * buffer, uint16_t length)
|
||||
{
|
||||
LPC_USB->USBCtrl = USBCTRL_READ_ENABLE_MASK; // logical endpoint = 0
|
||||
while ((LPC_USB->USBRxPLen & USBRXPLEN_PACKET_READY_MASK) == 0) {} // TODO blocking, should have timeout
|
||||
|
||||
uint16_t actual_length = min16_of(length, (uint16_t) (LPC_USB->USBRxPLen & USBRXPLEN_PACKET_LENGTH_MASK) );
|
||||
uint32_t *p_read_data = (uint32_t*) buffer;
|
||||
for( uint16_t count=0; count < length_byte2dword(actual_length); count++)
|
||||
{
|
||||
*p_read_data = LPC_USB->USBRxData;
|
||||
p_read_data++; // increase by 4 ( sizeof(uint32_t) )
|
||||
}
|
||||
|
||||
LPC_USB->USBCtrl = 0;
|
||||
|
||||
// select control OUT & clear the endpoint
|
||||
sie_write(SIE_CMDCODE_ENDPOINT_SELECT+0, 0, 0);
|
||||
sie_write(SIE_CMDCODE_BUFFER_CLEAR , 0, 0);
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROL PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
void dcd_control_stall(uint8_t rhport)
|
||||
{
|
||||
sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+0, 1, SIE_SET_ENDPOINT_STALLED_MASK | SIE_SET_ENDPOINT_CONDITION_STALLED_MASK);
|
||||
}
|
||||
|
||||
bool dcd_control_xfer(uint8_t rhport, tusb_dir_t dir, uint8_t * p_buffer, uint16_t length, bool int_on_complete)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
VERIFY( !(length != 0 && p_buffer == NULL) );
|
||||
|
||||
// determine Endpoint where Data & Status phase occurred (IN or OUT)
|
||||
uint8_t const ep_data = (dir == TUSB_DIR_IN) ? 1 : 0;
|
||||
uint8_t const ep_status = 1 - ep_data;
|
||||
|
||||
dcd_data.control_dma.int_on_complete = int_on_complete ? BIT_(ep_status) : 0;
|
||||
|
||||
//------------- Data Phase -------------//
|
||||
if ( length )
|
||||
{
|
||||
dcd_data.control_dma.p_data = (uint8_t*) p_buffer;
|
||||
dcd_data.control_dma.remaining_bytes = length;
|
||||
|
||||
// lpc17xx already received the first DATA OUT packet by now
|
||||
VERIFY_ERR ( pipe_control_xfer(ep_data, p_buffer, length), false );
|
||||
}
|
||||
|
||||
//------------- Status Phase (opposite direct to Data) -------------//
|
||||
if (dir == TUSB_DIR_OUT)
|
||||
{ // only write for CONTROL OUT, CONTROL IN data will be retrieved in hal_dcd_isr // TODO ????
|
||||
VERIFY_ERR ( pipe_control_write(NULL, 0), false );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// BULK/INTERRUPT/ISO PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
edpt_hdl_t dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc, uint8_t class_code)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
edpt_hdl_t const null_handle = { 0 };
|
||||
|
||||
// TODO refractor to universal pipe open validation function
|
||||
if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) return null_handle; // TODO not support ISO yet
|
||||
TU_ASSERT (p_endpoint_desc->wMaxPacketSize.size <= 64, null_handle); // TODO ISO can be 1023, but ISO not supported now
|
||||
|
||||
uint8_t ep_id = edpt_addr2phy( p_endpoint_desc->bEndpointAddress );
|
||||
|
||||
//------------- Realize Endpoint with Max Packet Size -------------//
|
||||
edpt_set_max_packet_size(ep_id, p_endpoint_desc->wMaxPacketSize.size);
|
||||
dcd_data.class_code[ep_id] = class_code;
|
||||
|
||||
//------------- first DD prepare -------------//
|
||||
dcd_dma_descriptor_t* const p_dd = &dcd_data.dd[ep_id][0];
|
||||
memclr_(p_dd, sizeof(dcd_dma_descriptor_t));
|
||||
|
||||
p_dd->is_isochronous = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
|
||||
p_dd->max_packet_size = p_endpoint_desc->wMaxPacketSize.size;
|
||||
p_dd->is_retired = 1; // inactive at first
|
||||
|
||||
dcd_data.udca[ ep_id ] = p_dd; // hook to UDCA
|
||||
|
||||
sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0); // clear all endpoint status
|
||||
|
||||
return (edpt_hdl_t)
|
||||
{
|
||||
.rhport = 0,
|
||||
.index = ep_id,
|
||||
.class_code = class_code
|
||||
};
|
||||
}
|
||||
|
||||
bool dcd_edpt_busy(edpt_hdl_t edpt_hdl)
|
||||
{
|
||||
return (dcd_data.udca[edpt_hdl.index] != NULL && !dcd_data.udca[edpt_hdl.index]->is_retired);
|
||||
}
|
||||
|
||||
void dcd_edpt_stall(edpt_hdl_t edpt_hdl)
|
||||
{
|
||||
sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+edpt_hdl.index, 1, SIE_SET_ENDPOINT_STALLED_MASK);
|
||||
}
|
||||
|
||||
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t ep_id = ep_addr2phy(ep_addr);
|
||||
|
||||
sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0);
|
||||
}
|
||||
|
||||
void dd_xfer_init(dcd_dma_descriptor_t* p_dd, void* buffer, uint16_t total_bytes)
|
||||
{
|
||||
p_dd->next = 0;
|
||||
p_dd->is_next_valid = 0;
|
||||
p_dd->buffer_addr = (uint32_t) buffer;
|
||||
p_dd->buffer_length = total_bytes;
|
||||
p_dd->status = DD_STATUS_NOT_SERVICED;
|
||||
p_dd->iso_last_packet_valid = 0;
|
||||
p_dd->present_count = 0;
|
||||
}
|
||||
|
||||
tusb_error_t dcd_edpt_queue_xfer(edpt_hdl_t edpt_hdl, uint8_t * buffer, uint16_t total_bytes)
|
||||
{ // NOTE for sure the qhd has no dds
|
||||
dcd_dma_descriptor_t* const p_fixed_dd = &dcd_data.dd[edpt_hdl.index][0]; // always queue with the fixed DD
|
||||
|
||||
dd_xfer_init(p_fixed_dd, buffer, total_bytes);
|
||||
p_fixed_dd->is_retired = 1;
|
||||
p_fixed_dd->int_on_complete = 0;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t dcd_edpt_xfer(edpt_hdl_t edpt_hdl, uint8_t* buffer, uint16_t total_bytes, bool int_on_complete)
|
||||
{
|
||||
dcd_dma_descriptor_t* const p_first_dd = &dcd_data.dd[edpt_hdl.index][0];
|
||||
|
||||
//------------- fixed DD is already queued a xfer -------------//
|
||||
if ( p_first_dd->buffer_length )
|
||||
{
|
||||
// setup new dd
|
||||
dcd_dma_descriptor_t* const p_dd = &dcd_data.dd[ edpt_hdl.index ][1];
|
||||
memclr_(p_dd, sizeof(dcd_dma_descriptor_t));
|
||||
|
||||
dd_xfer_init(p_dd, buffer, total_bytes);
|
||||
|
||||
p_dd->max_packet_size = p_first_dd->max_packet_size;
|
||||
p_dd->is_isochronous = p_first_dd->is_isochronous;
|
||||
p_dd->int_on_complete = int_on_complete;
|
||||
|
||||
// hook to fixed dd
|
||||
p_first_dd->next = (uint32_t) p_dd;
|
||||
p_first_dd->is_next_valid = 1;
|
||||
}
|
||||
//------------- fixed DD is free -------------//
|
||||
else
|
||||
{
|
||||
dd_xfer_init(p_first_dd, buffer, total_bytes);
|
||||
p_first_dd->int_on_complete = int_on_complete;
|
||||
}
|
||||
|
||||
p_first_dd->is_retired = 0; // activate xfer
|
||||
dcd_data.udca[edpt_hdl.index] = p_first_dd;
|
||||
LPC_USB->USBEpDMAEn = BIT_(edpt_hdl.index);
|
||||
|
||||
if ( edpt_hdl.index % 2 )
|
||||
{ // endpoint IN need to actively raise DMA request
|
||||
LPC_USB->USBDMARSet = BIT_(edpt_hdl.index);
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,240 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file dcd_lpc175x_6x.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 group_dcd
|
||||
* \defgroup group_dcd_lpc175x_6x LPC175x_6x
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_DCD_LPC175X_6X_H_
|
||||
#define _TUSB_DCD_LPC175X_6X_H_
|
||||
|
||||
#include <common/tusb_common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct ATTR_ALIGNED(4)
|
||||
{
|
||||
//------------- Word 0 -------------//
|
||||
uint32_t next;
|
||||
|
||||
//------------- Word 1 -------------//
|
||||
uint16_t mode : 2; // either 00 normal or 01 ATLE(auto length extraction)
|
||||
uint16_t is_next_valid : 1;
|
||||
uint16_t int_on_complete : 1; ///< make use of reserved bit
|
||||
uint16_t is_isochronous : 1; // is an iso endpoint
|
||||
uint16_t max_packet_size : 11;
|
||||
volatile uint16_t buffer_length;
|
||||
|
||||
//------------- Word 2 -------------//
|
||||
volatile uint32_t buffer_addr;
|
||||
|
||||
//------------- Word 3 -------------//
|
||||
volatile uint16_t is_retired : 1; // initialized to zero
|
||||
volatile uint16_t status : 4;
|
||||
volatile uint16_t iso_last_packet_valid : 1;
|
||||
volatile uint16_t atle_is_lsb_extracted : 1; // used in ATLE mode
|
||||
volatile uint16_t atle_is_msb_extracted : 1; // used in ATLE mode
|
||||
volatile uint16_t atle_message_length_position : 6; // used in ATLE mode
|
||||
uint16_t : 2;
|
||||
volatile uint16_t present_count; // The number of bytes transferred by the DMA engine. The DMA engine updates this field after completing each packet transfer.
|
||||
|
||||
//------------- Word 4 -------------//
|
||||
// uint32_t iso_packet_size_addr; // iso only, can be omitted for non-iso
|
||||
}dcd_dma_descriptor_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(dcd_dma_descriptor_t) == 16, "size is not correct"); // TODO not support ISO for now
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Register Interface
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//------------- USB Interrupt USBIntSt -------------//
|
||||
//enum {
|
||||
// DCD_USB_REQ_LOW_PRIO_MASK = BIT_(0),
|
||||
// DCD_USB_REQ_HIGH_PRIO_MASK = BIT_(1),
|
||||
// DCD_USB_REQ_DMA_MASK = BIT_(2),
|
||||
// DCD_USB_REQ_NEED_CLOCK_MASK = BIT_(8),
|
||||
// DCD_USB_REQ_ENABLE_MASK = BIT_(31)
|
||||
//};
|
||||
|
||||
//------------- Device Interrupt USBDevInt -------------//
|
||||
enum {
|
||||
DEV_INT_FRAME_MASK = BIT_(0),
|
||||
DEV_INT_ENDPOINT_FAST_MASK = BIT_(1),
|
||||
DEV_INT_ENDPOINT_SLOW_MASK = BIT_(2),
|
||||
DEV_INT_DEVICE_STATUS_MASK = BIT_(3),
|
||||
DEV_INT_COMMAND_CODE_EMPTY_MASK = BIT_(4),
|
||||
DEV_INT_COMMAND_DATA_FULL_MASK = BIT_(5),
|
||||
DEV_INT_RX_ENDPOINT_PACKET_MASK = BIT_(6),
|
||||
DEV_INT_TX_ENDPOINT_PACKET_MASK = BIT_(7),
|
||||
DEV_INT_ENDPOINT_REALIZED_MASK = BIT_(8),
|
||||
DEV_INT_ERROR_MASK = BIT_(9)
|
||||
};
|
||||
|
||||
//------------- DMA Interrupt USBDMAInt-------------//
|
||||
enum {
|
||||
DMA_INT_END_OF_XFER_MASK = BIT_(0),
|
||||
DMA_INT_NEW_DD_REQUEST_MASK = BIT_(1),
|
||||
DMA_INT_ERROR_MASK = BIT_(2)
|
||||
};
|
||||
|
||||
//------------- USBCtrl -------------//
|
||||
enum {
|
||||
USBCTRL_READ_ENABLE_MASK = BIT_(0),
|
||||
USBCTRL_WRITE_ENABLE_MASK = BIT_(1),
|
||||
};
|
||||
|
||||
//------------- USBRxPLen -------------//
|
||||
enum {
|
||||
USBRXPLEN_PACKET_LENGTH_MASK = (BIT_(10)-1),
|
||||
USBRXPLEN_DATA_VALID_MASK = BIT_(10),
|
||||
USBRXPLEN_PACKET_READY_MASK = BIT_(11),
|
||||
};
|
||||
|
||||
//------------- SIE Command Code -------------//
|
||||
typedef enum
|
||||
{
|
||||
SIE_CMDPHASE_WRITE = 1,
|
||||
SIE_CMDPHASE_READ = 2,
|
||||
SIE_CMDPHASE_COMMAND = 5
|
||||
} sie_cmdphase_t;
|
||||
|
||||
enum {
|
||||
// device commands
|
||||
SIE_CMDCODE_SET_ADDRESS = 0xd0,
|
||||
SIE_CMDCODE_CONFIGURE_DEVICE = 0xd8,
|
||||
SIE_CMDCODE_SET_MODE = 0xf3,
|
||||
SIE_CMDCODE_READ_FRAME_NUMBER = 0xf5,
|
||||
SIE_CMDCODE_READ_TEST_REGISTER = 0xfd,
|
||||
SIE_CMDCODE_DEVICE_STATUS = 0xfe,
|
||||
SIE_CMDCODE_GET_ERROR = 0xff,
|
||||
SIE_CMDCODE_READ_ERROR_STATUS = 0xfb,
|
||||
|
||||
// endpoint commands
|
||||
SIE_CMDCODE_ENDPOINT_SELECT = 0x00, // + endpoint index
|
||||
SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT = 0x40, // + endpoint index, should use USBEpIntClr instead
|
||||
SIE_CMDCODE_ENDPOINT_SET_STATUS = 0x40, // + endpoint index
|
||||
SIE_CMDCODE_BUFFER_CLEAR = 0xf2,
|
||||
SIE_CMDCODE_BUFFER_VALIDATE = 0xfa
|
||||
};
|
||||
|
||||
//------------- SIE Device Status (get/set from SIE_CMDCODE_DEVICE_STATUS) -------------//
|
||||
enum {
|
||||
SIE_DEV_STATUS_CONNECT_STATUS_MASK = BIT_(0),
|
||||
SIE_DEV_STATUS_CONNECT_CHANGE_MASK = BIT_(1),
|
||||
SIE_DEV_STATUS_SUSPEND_MASK = BIT_(2),
|
||||
SIE_DEV_STATUS_SUSPEND_CHANGE_MASK = BIT_(3),
|
||||
SIE_DEV_STATUS_RESET_MASK = BIT_(4)
|
||||
};
|
||||
|
||||
//------------- SIE Select Endpoint Command -------------//
|
||||
enum {
|
||||
SIE_SELECT_ENDPOINT_FULL_EMPTY_MASK = BIT_(0), // 0: empty, 1 full. IN endpoint checks empty, OUT endpoint check full
|
||||
SIE_SELECT_ENDPOINT_STALL_MASK = BIT_(1),
|
||||
SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK = BIT_(2), // clear by SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT
|
||||
SIE_SELECT_ENDPOINT_PACKET_OVERWRITTEN_MASK = BIT_(3), // previous packet is overwritten by a SETUP packet
|
||||
SIE_SELECT_ENDPOINT_NAK_MASK = BIT_(4), // last packet response is NAK (auto clear by an ACK)
|
||||
SIE_SELECT_ENDPOINT_BUFFER1_FULL_MASK = BIT_(5),
|
||||
SIE_SELECT_ENDPOINT_BUFFER2_FULL_MASK = BIT_(6)
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SIE_SET_ENDPOINT_STALLED_MASK = BIT_(0),
|
||||
SIE_SET_ENDPOINT_DISABLED_MASK = BIT_(5),
|
||||
SIE_SET_ENDPOINT_RATE_FEEDBACK_MASK = BIT_(6),
|
||||
SIE_SET_ENDPOINT_CONDITION_STALLED_MASK = BIT_(7),
|
||||
}sie_endpoint_set_status_mask_t;
|
||||
|
||||
//------------- DMA Descriptor Status -------------//
|
||||
enum {
|
||||
DD_STATUS_NOT_SERVICED = 0,
|
||||
DD_STATUS_BEING_SERVICED,
|
||||
DD_STATUS_NORMAL,
|
||||
DD_STATUS_DATA_UNDERUN, // short packet
|
||||
DD_STATUS_DATA_OVERRUN,
|
||||
DD_STATUS_SYSTEM_ERROR
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SIE Command
|
||||
//--------------------------------------------------------------------+
|
||||
static inline void sie_cmd_code (sie_cmdphase_t phase, uint8_t code_data) ATTR_ALWAYS_INLINE;
|
||||
static inline void sie_cmd_code (sie_cmdphase_t phase, uint8_t code_data)
|
||||
{
|
||||
LPC_USB->USBDevIntClr = (DEV_INT_COMMAND_CODE_EMPTY_MASK | DEV_INT_COMMAND_DATA_FULL_MASK);
|
||||
LPC_USB->USBCmdCode = (phase << 8) | (code_data << 16);
|
||||
|
||||
uint32_t const wait_flag = (phase == SIE_CMDPHASE_READ) ? DEV_INT_COMMAND_DATA_FULL_MASK : DEV_INT_COMMAND_CODE_EMPTY_MASK;
|
||||
#ifndef _TEST_
|
||||
while ((LPC_USB->USBDevIntSt & wait_flag) == 0); // TODO blocking forever potential
|
||||
#endif
|
||||
LPC_USB->USBDevIntClr = wait_flag;
|
||||
}
|
||||
|
||||
static inline void sie_write (uint8_t cmd_code, uint8_t data_len, uint8_t data) ATTR_ALWAYS_INLINE;
|
||||
static inline void sie_write (uint8_t cmd_code, uint8_t data_len, uint8_t data)
|
||||
{
|
||||
sie_cmd_code(SIE_CMDPHASE_COMMAND, cmd_code);
|
||||
|
||||
if (data_len)
|
||||
{
|
||||
sie_cmd_code(SIE_CMDPHASE_WRITE, data);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t sie_read (uint8_t cmd_code, uint8_t data_len) ATTR_ALWAYS_INLINE;
|
||||
static inline uint32_t sie_read (uint8_t cmd_code, uint8_t data_len)
|
||||
{
|
||||
// TODO multiple read
|
||||
sie_cmd_code(SIE_CMDPHASE_COMMAND , cmd_code);
|
||||
sie_cmd_code(SIE_CMDPHASE_READ , cmd_code);
|
||||
return LPC_USB->USBCmdData;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_DCD_LPC175X_6X_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,120 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file hal_lpc175x_6x.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/tusb_common.h"
|
||||
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X
|
||||
#include "hal_usb.h"
|
||||
|
||||
|
||||
void tusb_hal_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport; // discard compiler's warning
|
||||
NVIC_EnableIRQ(USB_IRQn);
|
||||
}
|
||||
|
||||
void tusb_hal_int_disable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport; // discard compiler's warning
|
||||
NVIC_DisableIRQ(USB_IRQn);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// IMPLEMENTATION
|
||||
//--------------------------------------------------------------------+
|
||||
bool tusb_hal_init(void)
|
||||
{
|
||||
enum {
|
||||
USBCLK_DEVCIE = 0x12, // AHB + Device
|
||||
USBCLK_HOST = 0x19, // AHB + Host + OTG (!)
|
||||
|
||||
PCONP_PCUSB = BIT_(31)
|
||||
};
|
||||
|
||||
LPC_SC->PCONP |= PCONP_PCUSB; // enable USB Peripherals
|
||||
|
||||
//------------- user manual 11.13 usb device controller initialization -------------//
|
||||
PINSEL_ConfigPin( &(PINSEL_CFG_Type) { .Portnum = 0, .Pinnum = 29, .Funcnum = 1} ); // P0.29 as D+
|
||||
PINSEL_ConfigPin( &(PINSEL_CFG_Type) { .Portnum = 0, .Pinnum = 30, .Funcnum = 1} ); // P0.30 as D-
|
||||
|
||||
#if MODE_HOST_SUPPORTED
|
||||
PINSEL_ConfigPin( &(PINSEL_CFG_Type) { .Portnum = 1, .Pinnum = 22, .Funcnum = 2} ); // P1.22 as USB_PWRD
|
||||
PINSEL_ConfigPin( &(PINSEL_CFG_Type) { .Portnum = 1, .Pinnum = 19, .Funcnum = 2} ); // P1.19 as USB_PPWR
|
||||
|
||||
LPC_USB->USBClkCtrl = USBCLK_HOST;
|
||||
while ((LPC_USB->USBClkSt & USBCLK_HOST) != USBCLK_HOST);
|
||||
LPC_USB->OTGStCtrl = 0x3;
|
||||
#endif
|
||||
|
||||
#if MODE_DEVICE_SUPPORTED
|
||||
LPC_PINCON->PINSEL4 = bit_set_range(LPC_PINCON->PINSEL4, 18, 19, BIN8(01)); // P2_9 as USB Connect
|
||||
|
||||
// P1_30 as VBUS, ignore if it is already in VBUS mode
|
||||
if ( !(!BIT_TEST_(LPC_PINCON->PINSEL3, 28) && BIT_TEST_(LPC_PINCON->PINSEL3, 29)) )
|
||||
{
|
||||
// some board like lpcxpresso1769 does not connect VBUS signal to pin P1_30, this allow those board to overwrite
|
||||
// by always pulling P1_30 to high
|
||||
PINSEL_ConfigPin( &(PINSEL_CFG_Type) {
|
||||
.Portnum = 1, .Pinnum = 30,
|
||||
.Funcnum = 2, .Pinmode = PINSEL_PINMODE_PULLDOWN} );
|
||||
}
|
||||
|
||||
LPC_USB->USBClkCtrl = USBCLK_DEVCIE;
|
||||
while ((LPC_USB->USBClkSt & USBCLK_DEVCIE) != USBCLK_DEVCIE);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void USB_IRQHandler(void)
|
||||
{
|
||||
#if MODE_HOST_SUPPORTED
|
||||
hal_hcd_isr(0);
|
||||
#endif
|
||||
|
||||
#if MODE_DEVICE_SUPPORTED
|
||||
hal_dcd_isr(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void check_failed(uint8_t *file, uint32_t line)
|
||||
{
|
||||
(void) file;
|
||||
(void) line;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file hal_lpc175x_6x.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_HAL_MCU_H_
|
||||
#define _TUSB_HAL_MCU_H_
|
||||
|
||||
#include "LPC17xx.h"
|
||||
#include "lpc17xx_pinsel.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HAL_MCU_H_ */
|
||||
|
||||
@@ -0,0 +1,501 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file dcd_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 "tusb_option.h"
|
||||
|
||||
#if MODE_DEVICE_SUPPORTED && CFG_TUSB_MCU == OPT_MCU_LPC43XX
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "tusb_hal.h"
|
||||
#include "osal/osal.h"
|
||||
#include "common/timeout_timer.h"
|
||||
|
||||
#include "device/dcd.h"
|
||||
#include "dcd_lpc43xx.h"
|
||||
|
||||
#include "LPC43xx.h"
|
||||
#include "lpc43xx_cgu.h"
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
dcd_qhd_t qhd[DCD_QHD_MAX] ATTR_ALIGNED(64); ///< Must be at 2K alignment
|
||||
dcd_qtd_t qtd[DCD_QTD_MAX] ATTR_ALIGNED(32);
|
||||
}dcd_data_t;
|
||||
|
||||
extern ATTR_WEAK dcd_data_t dcd_data0;
|
||||
extern ATTR_WEAK dcd_data_t dcd_data1;
|
||||
|
||||
#if (CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE)
|
||||
CFG_TUSB_ATTR_USBRAM ATTR_ALIGNED(2048) STATIC_VAR dcd_data_t dcd_data0;
|
||||
#endif
|
||||
|
||||
#if (CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE)
|
||||
CFG_TUSB_ATTR_USBRAM ATTR_ALIGNED(2048) STATIC_VAR dcd_data_t dcd_data1;
|
||||
#endif
|
||||
|
||||
static LPC_USB0_Type * const LPC_USB[2] = { LPC_USB0, ((LPC_USB0_Type*) LPC_USB1_BASE) };
|
||||
static dcd_data_t* const dcd_data_ptr[2] = { &dcd_data0, &dcd_data1 };
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROLLER API
|
||||
//--------------------------------------------------------------------+
|
||||
void dcd_connect(uint8_t rhport)
|
||||
{
|
||||
LPC_USB[rhport]->USBCMD_D |= BIT_(0);
|
||||
}
|
||||
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
LPC_USB[rhport]->DEVICEADDR = (dev_addr << 25) | BIT_(24);
|
||||
}
|
||||
|
||||
void dcd_set_config(uint8_t rhport, uint8_t config_num)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// follows LPC43xx User Manual 23.10.3
|
||||
static void bus_reset(uint8_t rhport)
|
||||
{
|
||||
LPC_USB0_Type* const lpc_usb = LPC_USB[rhport];
|
||||
|
||||
// The reset value for all endpoint types is the control endpoint. If one endpoint
|
||||
//direction is enabled and the paired endpoint of opposite direction is disabled, then the
|
||||
//endpoint type of the unused direction must bechanged from the control type to any other
|
||||
//type (e.g. bulk). Leaving an unconfigured endpoint control will cause undefined behavior
|
||||
//for the data PID tracking on the active endpoint.
|
||||
lpc_usb->ENDPTCTRL1 = lpc_usb->ENDPTCTRL2 = lpc_usb->ENDPTCTRL3 =
|
||||
(TUSB_XFER_BULK << 2) | (TUSB_XFER_BULK << 18);
|
||||
|
||||
// USB1 only has 3 non-control endpoints
|
||||
if ( rhport == 0)
|
||||
{
|
||||
lpc_usb->ENDPTCTRL4 = lpc_usb->ENDPTCTRL5 = (TUSB_XFER_BULK << 2) | (TUSB_XFER_BULK << 18);
|
||||
}
|
||||
|
||||
//------------- Clear All Registers -------------//
|
||||
lpc_usb->ENDPTNAK = lpc_usb->ENDPTNAK;
|
||||
lpc_usb->ENDPTNAKEN = 0;
|
||||
lpc_usb->USBSTS_D = lpc_usb->USBSTS_D;
|
||||
lpc_usb->ENDPTSETUPSTAT = lpc_usb->ENDPTSETUPSTAT;
|
||||
lpc_usb->ENDPTCOMPLETE = lpc_usb->ENDPTCOMPLETE;
|
||||
|
||||
while (lpc_usb->ENDPTPRIME);
|
||||
lpc_usb->ENDPTFLUSH = 0xFFFFFFFF;
|
||||
while (lpc_usb->ENDPTFLUSH);
|
||||
|
||||
// read reset bit in portsc
|
||||
|
||||
//------------- Queue Head & Queue TD -------------//
|
||||
dcd_data_t* p_dcd = dcd_data_ptr[rhport];
|
||||
|
||||
memclr_(p_dcd, sizeof(dcd_data_t));
|
||||
|
||||
//------------- Set up Control Endpoints (0 OUT, 1 IN) -------------//
|
||||
p_dcd->qhd[0].zero_length_termination = p_dcd->qhd[1].zero_length_termination = 1;
|
||||
p_dcd->qhd[0].max_package_size = p_dcd->qhd[1].max_package_size = CFG_TUD_ENDOINT0_SIZE;
|
||||
p_dcd->qhd[0].qtd_overlay.next = p_dcd->qhd[1].qtd_overlay.next = QTD_NEXT_INVALID;
|
||||
|
||||
p_dcd->qhd[0].int_on_setup = 1; // OUT only
|
||||
|
||||
}
|
||||
|
||||
bool dcd_init(uint8_t rhport)
|
||||
{
|
||||
LPC_USB0_Type* const lpc_usb = LPC_USB[rhport];
|
||||
dcd_data_t* p_dcd = dcd_data_ptr[rhport];
|
||||
|
||||
memclr_(p_dcd, sizeof(dcd_data_t));
|
||||
|
||||
lpc_usb->ENDPOINTLISTADDR = (uint32_t) p_dcd->qhd; // Endpoint List Address has to be 2K alignment
|
||||
lpc_usb->USBSTS_D = lpc_usb->USBSTS_D;
|
||||
lpc_usb->USBINTR_D = INT_MASK_USB | INT_MASK_ERROR | INT_MASK_PORT_CHANGE | INT_MASK_RESET | INT_MASK_SUSPEND | INT_MASK_SOF;
|
||||
|
||||
lpc_usb->USBCMD_D &= ~0x00FF0000; // Interrupt Threshold Interval = 0
|
||||
lpc_usb->USBCMD_D |= BIT_(0); // connect
|
||||
|
||||
// enable interrupt
|
||||
NVIC_EnableIRQ(rhport ? USB1_IRQn : USB0_IRQn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PIPE HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
#if 0
|
||||
static inline uint8_t edpt_pos2phy(uint8_t pos)
|
||||
{ // 0-5 --> OUT, 16-21 IN
|
||||
return (pos < DCD_QHD_MAX/2) ? (2*pos) : (2*(pos-16)+1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint8_t edpt_phy2pos(uint8_t physical_endpoint)
|
||||
{
|
||||
return physical_endpoint/2 + ( (physical_endpoint%2) ? 16 : 0);
|
||||
}
|
||||
|
||||
static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr)
|
||||
{
|
||||
return 2*(endpoint_addr & 0x0F) + ((endpoint_addr & TUSB_DIR_IN_MASK) ? 1 : 0);
|
||||
}
|
||||
|
||||
static inline uint8_t edpt_phy2addr(uint8_t ep_idx)
|
||||
{
|
||||
return (ep_idx/2) | ( ep_idx & 0x01 ? TUSB_DIR_IN_MASK : 0 );
|
||||
}
|
||||
|
||||
static inline uint8_t edpt_phy2log(uint8_t physical_endpoint)
|
||||
{
|
||||
return physical_endpoint/2;
|
||||
}
|
||||
|
||||
static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes)
|
||||
{
|
||||
memclr_(p_qtd, sizeof(dcd_qtd_t));
|
||||
|
||||
p_qtd->used = 1;
|
||||
|
||||
p_qtd->next = QTD_NEXT_INVALID;
|
||||
p_qtd->active = 1;
|
||||
p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
|
||||
|
||||
if (data_ptr != NULL)
|
||||
{
|
||||
p_qtd->buffer[0] = (uint32_t) data_ptr;
|
||||
for(uint8_t i=1; i<5; i++)
|
||||
{
|
||||
p_qtd->buffer[i] |= align4k( p_qtd->buffer[i-1] ) + 4096;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// retval 0: invalid
|
||||
static inline uint8_t qtd_find_free(uint8_t rhport)
|
||||
{
|
||||
// QTD0 is reserved for control transfer
|
||||
for(uint8_t i=1; i<DCD_QTD_MAX; i++)
|
||||
{
|
||||
if ( dcd_data_ptr[rhport]->qtd[i].used == 0) return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROL PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// control transfer does not need to use qtd find function
|
||||
// follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism
|
||||
bool dcd_control_xfer(uint8_t rhport, tusb_dir_t dir, uint8_t * p_buffer, uint16_t length)
|
||||
{
|
||||
LPC_USB0_Type* const lpc_usb = LPC_USB[rhport];
|
||||
dcd_data_t* const p_dcd = dcd_data_ptr[rhport];
|
||||
|
||||
uint8_t const ep_phy = (dir == TUSB_DIR_IN) ? 1 : 0;
|
||||
|
||||
dcd_qhd_t* qhd = &p_dcd->qhd[ep_phy];
|
||||
|
||||
// wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
|
||||
while(lpc_usb->ENDPTSETUPSTAT & BIT_(0)) {}
|
||||
|
||||
VERIFY( !qhd->qtd_overlay.active );
|
||||
|
||||
dcd_qtd_t* qtd = &p_dcd->qtd[0];
|
||||
qtd_init(qtd, p_buffer, length);
|
||||
|
||||
// skip xfer complete for Status
|
||||
qtd->int_on_complete = (length > 0 ? 1 : 0);
|
||||
|
||||
qhd->qtd_overlay.next = (uint32_t) qtd;
|
||||
|
||||
lpc_usb->ENDPTPRIME = BIT_(edpt_phy2pos(ep_phy));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// BULK/INTERRUPT/ISOCHRONOUS PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
static inline volatile uint32_t * get_reg_control_addr(uint8_t rhport, uint8_t physical_endpoint)
|
||||
{
|
||||
return &(LPC_USB[rhport]->ENDPTCTRL0) + edpt_phy2log(physical_endpoint);
|
||||
}
|
||||
|
||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t ep_idx = edpt_addr2phy(ep_addr);
|
||||
volatile uint32_t * reg_control = get_reg_control_addr(rhport, ep_idx);
|
||||
|
||||
if ( ep_addr == 0)
|
||||
{
|
||||
// Stall both Control IN and OUT
|
||||
(*reg_control) |= ( (ENDPTCTRL_MASK_STALL << 16) || (ENDPTCTRL_MASK_STALL << 0) );
|
||||
}else
|
||||
{
|
||||
(*reg_control) |= ENDPTCTRL_MASK_STALL << (ep_idx & 0x01 ? 16 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
volatile uint32_t * reg_control = get_reg_control_addr(rhport, edpt_addr2phy(ep_addr));
|
||||
|
||||
// data toggle also need to be reset
|
||||
(*reg_control) |= ENDPTCTRL_MASK_TOGGLE_RESET << ((ep_addr & TUSB_DIR_IN_MASK) ? 16 : 0);
|
||||
(*reg_control) &= ~(ENDPTCTRL_MASK_STALL << ((ep_addr & TUSB_DIR_IN_MASK) ? 16 : 0));
|
||||
}
|
||||
|
||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
|
||||
{
|
||||
// TODO USB1 only has 4 non-control enpoint (USB0 has 5)
|
||||
// TODO not support ISO yet
|
||||
VERIFY ( p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
|
||||
|
||||
tusb_dir_t dir = (p_endpoint_desc->bEndpointAddress & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
|
||||
|
||||
//------------- Prepare Queue Head -------------//
|
||||
uint8_t ep_idx = edpt_addr2phy(p_endpoint_desc->bEndpointAddress);
|
||||
dcd_qhd_t * p_qhd = &dcd_data_ptr[rhport]->qhd[ep_idx];
|
||||
|
||||
memclr_(p_qhd, sizeof(dcd_qhd_t));
|
||||
|
||||
p_qhd->zero_length_termination = 1;
|
||||
p_qhd->max_package_size = p_endpoint_desc->wMaxPacketSize.size;
|
||||
p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
|
||||
|
||||
//------------- Endpoint Control Register -------------//
|
||||
volatile uint32_t * reg_control = get_reg_control_addr(rhport, ep_idx);
|
||||
|
||||
// endpoint must not be already enabled
|
||||
VERIFY( !( (*reg_control) & (ENDPTCTRL_MASK_ENABLE << (dir ? 16 : 0)) ) );
|
||||
|
||||
(*reg_control) |= ((p_endpoint_desc->bmAttributes.xfer << 2) | ENDPTCTRL_MASK_ENABLE | ENDPTCTRL_MASK_TOGGLE_RESET) << (dir ? 16 : 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t ep_idx = edpt_addr2phy(ep_addr);
|
||||
dcd_qhd_t const * p_qhd = &dcd_data_ptr[rhport]->qhd[ep_idx];
|
||||
|
||||
return p_qhd->list_qtd_idx[0] != 0; // qtd list is not empty
|
||||
// return !p_qhd->qtd_overlay.halted && p_qhd->qtd_overlay.active;
|
||||
}
|
||||
|
||||
// add only, controller virtually cannot know
|
||||
// TODO remove and merge to dcd_edpt_xfer
|
||||
static bool pipe_add_xfer(uint8_t rhport, uint8_t ed_idx, void * buffer, uint16_t total_bytes, bool int_on_complete)
|
||||
{
|
||||
uint8_t qtd_idx = qtd_find_free(rhport);
|
||||
TU_ASSERT(qtd_idx != 0);
|
||||
|
||||
dcd_data_t* p_dcd = dcd_data_ptr[rhport];
|
||||
dcd_qhd_t * p_qhd = &p_dcd->qhd[ed_idx];
|
||||
dcd_qtd_t * p_qtd = &p_dcd->qtd[qtd_idx];
|
||||
|
||||
//------------- Find free slot in qhd's array list -------------//
|
||||
uint8_t free_slot;
|
||||
for(free_slot=0; free_slot < DCD_QTD_PER_QHD_MAX; free_slot++)
|
||||
{
|
||||
if ( p_qhd->list_qtd_idx[free_slot] == 0 ) break; // found free slot
|
||||
}
|
||||
TU_ASSERT(free_slot < DCD_QTD_PER_QHD_MAX);
|
||||
|
||||
p_qhd->list_qtd_idx[free_slot] = qtd_idx; // add new qtd to qhd's array list
|
||||
|
||||
//------------- Prepare qtd -------------//
|
||||
qtd_init(p_qtd, buffer, total_bytes);
|
||||
p_qtd->int_on_complete = int_on_complete;
|
||||
|
||||
if ( free_slot > 0 ) p_dcd->qtd[ p_qhd->list_qtd_idx[free_slot-1] ].next = (uint32_t) p_qtd;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
||||
{
|
||||
uint8_t ep_idx = edpt_addr2phy(ep_addr);
|
||||
|
||||
VERIFY ( pipe_add_xfer(rhport, ep_idx, buffer, total_bytes, true) );
|
||||
|
||||
dcd_qhd_t* p_qhd = &dcd_data_ptr[rhport]->qhd[ ep_idx ];
|
||||
dcd_qtd_t* p_qtd = &dcd_data_ptr[rhport]->qtd[ p_qhd->list_qtd_idx[0] ];
|
||||
|
||||
p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // attach head QTD to QHD start transferring
|
||||
|
||||
LPC_USB[rhport]->ENDPTPRIME = BIT_( edpt_phy2pos(ep_idx) ) ;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------- Device Controller Driver's Interrupt Handler -------------//
|
||||
void xfer_complete_isr(uint8_t rhport, uint32_t reg_complete)
|
||||
{
|
||||
for(uint8_t ep_idx = 2; ep_idx < DCD_QHD_MAX; ep_idx++)
|
||||
{
|
||||
if ( BIT_TEST_(reg_complete, edpt_phy2pos(ep_idx)) )
|
||||
{ // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set
|
||||
dcd_qhd_t * p_qhd = &dcd_data_ptr[rhport]->qhd[ep_idx];
|
||||
|
||||
// retire all QTDs in array list, up to 1st still-active QTD
|
||||
while( p_qhd->list_qtd_idx[0] != 0 )
|
||||
{
|
||||
dcd_qtd_t * p_qtd = &dcd_data_ptr[rhport]->qtd[ p_qhd->list_qtd_idx[0] ];
|
||||
|
||||
if (p_qtd->active) break; // stop immediately if found still-active QTD and shift array list
|
||||
|
||||
//------------- Free QTD and shift array list -------------//
|
||||
p_qtd->used = 0; // free QTD
|
||||
memmove( (void*) p_qhd->list_qtd_idx, (void*) (p_qhd->list_qtd_idx+1), DCD_QTD_PER_QHD_MAX-1);
|
||||
p_qhd->list_qtd_idx[DCD_QTD_PER_QHD_MAX-1]=0;
|
||||
|
||||
if (p_qtd->int_on_complete)
|
||||
{
|
||||
bool succeeded = ( p_qtd->xact_err || p_qtd->halted || p_qtd->buffer_err ) ? false : true;
|
||||
|
||||
uint8_t ep_addr = edpt_phy2addr(ep_idx);
|
||||
dcd_xfer_complete(rhport, ep_addr, p_qtd->expected_bytes - p_qtd->total_bytes, succeeded); // only number of bytes in the IOC qtd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hal_dcd_isr(uint8_t rhport)
|
||||
{
|
||||
LPC_USB0_Type* const lpc_usb = LPC_USB[rhport];
|
||||
|
||||
uint32_t const int_enable = lpc_usb->USBINTR_D;
|
||||
uint32_t const int_status = lpc_usb->USBSTS_D & int_enable;
|
||||
lpc_usb->USBSTS_D = int_status; // Acknowledge handled interrupt
|
||||
|
||||
if (int_status == 0) return;// disabled interrupt sources
|
||||
|
||||
if (int_status & INT_MASK_RESET)
|
||||
{
|
||||
bus_reset(rhport);
|
||||
dcd_bus_event(rhport, USBD_BUS_EVENT_RESET);
|
||||
}
|
||||
|
||||
if (int_status & INT_MASK_SUSPEND)
|
||||
{
|
||||
if (lpc_usb->PORTSC1_D & PORTSC_SUSPEND_MASK)
|
||||
{ // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
|
||||
if ((lpc_usb->DEVICEADDR >> 25) & 0x0f)
|
||||
{
|
||||
dcd_bus_event(0, USBD_BUS_EVENT_SUSPENDED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO disconnection does not generate interrupt !!!!!!
|
||||
// if (int_status & INT_MASK_PORT_CHANGE)
|
||||
// {
|
||||
// if ( !(lpc_usb->PORTSC1_D & PORTSC_CURRENT_CONNECT_STATUS_MASK) )
|
||||
// {
|
||||
// dcd_bus_event(0, USBD_BUS_EVENT_UNPLUGGED);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (int_status & INT_MASK_USB)
|
||||
{
|
||||
uint32_t const edpt_complete = lpc_usb->ENDPTCOMPLETE;
|
||||
lpc_usb->ENDPTCOMPLETE = edpt_complete; // acknowledge
|
||||
|
||||
dcd_data_t* const p_dcd = dcd_data_ptr[rhport];
|
||||
|
||||
//------------- Set up Received -------------//
|
||||
if (lpc_usb->ENDPTSETUPSTAT)
|
||||
{
|
||||
// 23.10.10.2 Operational model for setup transfers
|
||||
lpc_usb->ENDPTSETUPSTAT = lpc_usb->ENDPTSETUPSTAT;// acknowledge
|
||||
|
||||
dcd_setup_received(rhport, (uint8_t*) &p_dcd->qhd[0].setup_request);
|
||||
}
|
||||
|
||||
//------------- Control Request Completed -------------//
|
||||
else if ( edpt_complete & ( BIT_(0) | BIT_(16)) )
|
||||
{
|
||||
// determine Control OUT or IN
|
||||
uint8_t ep_idx = BIT_TEST_(edpt_complete, 0) ? 0 : 1;
|
||||
|
||||
// TODO use the actual QTD instead of the qhd's overlay to get expected bytes for actual byte xferred
|
||||
dcd_qtd_t* const p_qtd = (dcd_qtd_t*) p_dcd->qhd[ep_idx].qtd_addr;
|
||||
|
||||
if ( p_qtd->int_on_complete )
|
||||
{
|
||||
bool succeeded = ( p_qtd->xact_err || p_qtd->halted || p_qtd->buffer_err ) ? false : true;
|
||||
(void) succeeded;
|
||||
|
||||
dcd_control_complete(rhport, p_qtd->expected_bytes - p_qtd->total_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
//------------- Transfer Complete -------------//
|
||||
if ( edpt_complete & ~(BIT_(0) | BIT_(16)) )
|
||||
{
|
||||
xfer_complete_isr(rhport, edpt_complete);
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & INT_MASK_SOF)
|
||||
{
|
||||
dcd_bus_event(rhport, USBD_BUS_EVENT_SOF);
|
||||
}
|
||||
|
||||
if (int_status & INT_MASK_NAK) {}
|
||||
if (int_status & INT_MASK_ERROR) TU_ASSERT(false, );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
#endif
|
||||
@@ -0,0 +1,165 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file dcd_lpc43xx.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 group_dcd
|
||||
* \defgroup group_dcd_lpc143xx LPC43xx
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_DCD_LPC43XX_H_
|
||||
#define _TUSB_DCD_LPC43XX_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
#define DCD_QHD_MAX 12
|
||||
#define DCD_QTD_MAX 12
|
||||
#define DCD_QTD_PER_QHD_MAX 2 // maximum number of qtd that are linked into one queue head at a time
|
||||
|
||||
#define QTD_NEXT_INVALID 0x01
|
||||
|
||||
/*---------- ENDPTCTRL ----------*/
|
||||
enum {
|
||||
ENDPTCTRL_MASK_STALL = BIT_(0),
|
||||
ENDPTCTRL_MASK_TOGGLE_INHIBIT = BIT_(5), ///< used for test only
|
||||
ENDPTCTRL_MASK_TOGGLE_RESET = BIT_(6),
|
||||
ENDPTCTRL_MASK_ENABLE = BIT_(7)
|
||||
};
|
||||
|
||||
/*---------- USBCMD ----------*/
|
||||
enum {
|
||||
USBCMD_MASK_RUN_STOP = BIT_(0),
|
||||
USBCMD_MASK_RESET = BIT_(1),
|
||||
USBCMD_MASK_SETUP_TRIPWIRE = BIT_(13),
|
||||
USBCMD_MASK_ADD_QTD_TRIPWIRE = BIT_(14) ///< This bit is used as a semaphore to ensure the to proper addition of a new dTD to an active (primed) endpoint’s linked list. This bit is set and cleared by software during the process of adding a new dTD
|
||||
};
|
||||
// Interrupt Threshold bit 23:16
|
||||
|
||||
/*---------- USBSTS, USBINTR ----------*/
|
||||
enum {
|
||||
INT_MASK_USB = BIT_(0),
|
||||
INT_MASK_ERROR = BIT_(1),
|
||||
INT_MASK_PORT_CHANGE = BIT_(2),
|
||||
INT_MASK_RESET = BIT_(6),
|
||||
INT_MASK_SOF = BIT_(7),
|
||||
INT_MASK_SUSPEND = BIT_(8),
|
||||
INT_MASK_NAK = BIT_(16)
|
||||
};
|
||||
|
||||
//------------- PORTSC -------------//
|
||||
enum {
|
||||
PORTSC_CURRENT_CONNECT_STATUS_MASK = BIT_(0),
|
||||
PORTSC_FORCE_PORT_RESUME_MASK = BIT_(6),
|
||||
PORTSC_SUSPEND_MASK = BIT_(7)
|
||||
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Word 0: Next QTD Pointer
|
||||
uint32_t next; ///< Next link pointer This field contains the physical memory address of the next dTD to be processed
|
||||
|
||||
// Word 1: qTQ Token
|
||||
uint32_t : 3 ;
|
||||
volatile uint32_t xact_err : 1 ;
|
||||
uint32_t : 1 ;
|
||||
volatile uint32_t buffer_err : 1 ;
|
||||
volatile uint32_t halted : 1 ;
|
||||
volatile uint32_t active : 1 ;
|
||||
uint32_t : 2 ;
|
||||
uint32_t iso_mult_override : 2 ; ///< This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO.
|
||||
uint32_t : 3 ;
|
||||
uint32_t int_on_complete : 1 ;
|
||||
volatile uint32_t total_bytes : 15 ;
|
||||
uint32_t : 0 ;
|
||||
|
||||
// Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
|
||||
uint32_t buffer[5]; ///< buffer1 has frame_n for TODO Isochronous
|
||||
|
||||
//------------- DCD Area -------------//
|
||||
uint16_t expected_bytes;
|
||||
uint8_t used;
|
||||
uint8_t reserved;
|
||||
} dcd_qtd_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(dcd_qtd_t) == 32, "size is not correct");
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Word 0: Capabilities and Characteristics
|
||||
uint32_t : 15 ; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed.
|
||||
uint32_t int_on_setup : 1 ; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received.
|
||||
uint32_t max_package_size : 11 ; ///< This directly corresponds to the maximum packet size of the associated endpoint (wMaxPacketSize)
|
||||
uint32_t : 2 ;
|
||||
uint32_t zero_length_termination : 1 ; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length.
|
||||
uint32_t iso_mult : 2 ; ///<
|
||||
uint32_t : 0 ;
|
||||
|
||||
// Word 1: Current qTD Pointer
|
||||
volatile uint32_t qtd_addr;
|
||||
|
||||
// Word 2-9: Transfer Overlay
|
||||
volatile dcd_qtd_t qtd_overlay;
|
||||
|
||||
// Word 10-11: Setup request (control OUT only)
|
||||
volatile tusb_control_request_t setup_request;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
/// Due to the fact QHD is 64 bytes aligned but occupies only 48 bytes
|
||||
/// thus there are 16 bytes padding free that we can make use of.
|
||||
//--------------------------------------------------------------------+
|
||||
volatile uint8_t list_qtd_idx[DCD_QTD_PER_QHD_MAX];
|
||||
|
||||
uint8_t reserved[16-DCD_QTD_PER_QHD_MAX];
|
||||
} dcd_qhd_t;
|
||||
|
||||
VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct");
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_DCD_LPC43XX_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,165 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@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 "tusb.h"
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_LPC43XX
|
||||
|
||||
#include "LPC43xx.h"
|
||||
#include "lpc43xx_cgu.h"
|
||||
|
||||
enum {
|
||||
LPC43XX_USBMODE_DEVICE = 2,
|
||||
LPC43XX_USBMODE_HOST = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
LPC43XX_USBMODE_VBUS_LOW = 0,
|
||||
LPC43XX_USBMODE_VBUS_HIGH = 1
|
||||
};
|
||||
|
||||
void tusb_hal_int_enable(uint8_t rhport)
|
||||
{
|
||||
NVIC_EnableIRQ(rhport ? USB1_IRQn : USB0_IRQn);
|
||||
}
|
||||
|
||||
void tusb_hal_int_disable(uint8_t rhport)
|
||||
{
|
||||
NVIC_DisableIRQ(rhport ? USB1_IRQn : USB0_IRQn);
|
||||
}
|
||||
|
||||
|
||||
static void hal_controller_reset(uint8_t rhport)
|
||||
{ // TODO timeout expired to prevent trap
|
||||
volatile uint32_t * p_reg_usbcmd;
|
||||
|
||||
p_reg_usbcmd = (rhport ? &LPC_USB1->USBCMD_D : &LPC_USB0->USBCMD_D);
|
||||
// NXP chip powered with non-host mode --> sts bit is not correctly reflected
|
||||
(*p_reg_usbcmd) |= BIT_(1);
|
||||
|
||||
// timeout_timer_t timeout;
|
||||
// timeout_set(&timeout, 2); // should not take longer the time to stop controller
|
||||
while( ((*p_reg_usbcmd) & BIT_(1)) /*&& !timeout_expired(&timeout)*/) {}
|
||||
//
|
||||
// return timeout_expired(&timeout) ? TUSB_ERROR_OSAL_TIMEOUT : TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
bool tusb_hal_init(void)
|
||||
{
|
||||
LPC_CREG->CREG0 &= ~(1<<5); /* Turn on the phy */
|
||||
|
||||
//------------- USB0 -------------//
|
||||
#if CFG_TUSB_RHPORT0_MODE
|
||||
CGU_EnableEntity(CGU_CLKSRC_PLL0, DISABLE); /* Disable PLL first */
|
||||
VERIFY( CGU_ERROR_SUCCESS == CGU_SetPLL0()); /* 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 */
|
||||
|
||||
// reset controller & set role
|
||||
hal_controller_reset(0);
|
||||
|
||||
#if CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST
|
||||
LPC_USB0->USBMODE_H = LPC43XX_USBMODE_HOST | (LPC43XX_USBMODE_VBUS_HIGH << 5);
|
||||
#else // TODO OTG
|
||||
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)*/;
|
||||
#if CFG_TUD_FULLSPEED // TODO for easy testing
|
||||
LPC_USB0->PORTSC1_D |= (1<<24); // force full speed
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//------------- USB1 -------------//
|
||||
#if CFG_TUSB_RHPORT1_MODE
|
||||
// Host require to config P2_5, 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_SCU->SFSUSB = (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST) ? 0x16 : 0x12; // enable USB1 with on-chip FS PHY
|
||||
|
||||
hal_controller_reset(1);
|
||||
|
||||
#if CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST
|
||||
LPC_USB1->USBMODE_H = LPC43XX_USBMODE_HOST | (LPC43XX_USBMODE_VBUS_HIGH << 5);
|
||||
#else // TODO OTG
|
||||
LPC_USB1->USBMODE_D = LPC43XX_USBMODE_DEVICE;
|
||||
#endif
|
||||
|
||||
LPC_USB1->PORTSC1_D |= (1<<24); // TODO abstract, force rhport to fullspeed
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void hal_dcd_isr(uint8_t rhport);
|
||||
|
||||
#if CFG_TUSB_RHPORT0_MODE
|
||||
void USB0_IRQHandler(void)
|
||||
{
|
||||
#if MODE_HOST_SUPPORTED
|
||||
hal_hcd_isr(0);
|
||||
#endif
|
||||
|
||||
#if MODE_DEVICE_SUPPORTED
|
||||
hal_dcd_isr(0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_RHPORT1_MODE
|
||||
void USB1_IRQHandler(void)
|
||||
{
|
||||
#if MODE_HOST_SUPPORTED
|
||||
hal_hcd_isr(1);
|
||||
#endif
|
||||
|
||||
#if MODE_DEVICE_SUPPORTED
|
||||
hal_dcd_isr(1);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void check_failed(uint8_t *file, uint32_t line)
|
||||
{
|
||||
(void) file;
|
||||
(void) line;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
To port tinyusb to support new MCU you need to implement all API in the
|
||||
- tusb_hal.h (mandatory for both device and host stack)
|
||||
- device/dcd.h for device stack
|
||||
- host/hcd.h for host stack
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file tusb.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.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
#include "tusb.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
tusb_error_t tusb_init(void)
|
||||
{
|
||||
VERIFY( tusb_hal_init(), TUSB_ERROR_FAILED ) ; // hardware init
|
||||
|
||||
#if MODE_HOST_SUPPORTED
|
||||
TU_ASSERT_ERR( usbh_init() ); // host stack init
|
||||
#endif
|
||||
|
||||
#if MODE_DEVICE_SUPPORTED
|
||||
TU_ASSERT_ERR ( usbd_init() ); // device stack init
|
||||
#endif
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
void tusb_task(void)
|
||||
{
|
||||
#if MODE_HOST_SUPPORTED
|
||||
usbh_enumeration_task(NULL);
|
||||
#endif
|
||||
|
||||
#if MODE_DEVICE_SUPPORTED
|
||||
usbd_task(NULL);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Debug
|
||||
*------------------------------------------------------------------*/
|
||||
#if CFG_TUSB_DEBUG
|
||||
|
||||
char const* const tusb_strerr[TUSB_ERROR_COUNT] =
|
||||
{
|
||||
ERROR_TABLE(ERROR_STRING)
|
||||
};
|
||||
|
||||
#endif
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file tusb.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_H_
|
||||
#define _TUSB_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "tusb_hal.h"
|
||||
#include "osal/osal.h"
|
||||
|
||||
//------------- HOST -------------//
|
||||
#if MODE_HOST_SUPPORTED
|
||||
#include "host/usbh.h"
|
||||
|
||||
#if HOST_CLASS_HID
|
||||
#include "class/hid/hid_host.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_MSC
|
||||
#include "class/msc/msc_host.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_CDC
|
||||
#include "class/cdc/cdc_host.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_HOST_CUSTOM_CLASS
|
||||
#include "class/custom_host.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//------------- DEVICE -------------//
|
||||
#if MODE_DEVICE_SUPPORTED
|
||||
#include "device/usbd.h"
|
||||
|
||||
#if DEVICE_CLASS_HID
|
||||
#include "class/hid/hid_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_CDC
|
||||
#include "class/cdc/cdc_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_MSC
|
||||
#include "class/msc/msc_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_CUSTOM_CLASS
|
||||
#include "class/custom/custom_device.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \ingroup group_application_api
|
||||
* @{ */
|
||||
|
||||
/** \brief Initialize the usb stack
|
||||
* \return Error Code of the \ref TUSB_ERROR enum
|
||||
* \note Function will initialize the stack according to configuration in the configure file (tusb_config.h)
|
||||
*/
|
||||
tusb_error_t tusb_init(void);
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
/** \brief Run all tinyusb's internal tasks (e.g host task, device task).
|
||||
* \note This function is only required when using no RTOS (\ref CFG_TUSB_OS == OPT_OS_NONE). All the stack functions
|
||||
* & callback are invoked within this function, so it should be called periodically within the mainloop
|
||||
*
|
||||
@code
|
||||
int main(void)
|
||||
{
|
||||
your_init_code();
|
||||
tusb_init();
|
||||
|
||||
// other config code
|
||||
|
||||
while(1) // the mainloop
|
||||
{
|
||||
your_application_code();
|
||||
|
||||
tusb_task(); // handle tinyusb event, task etc ...
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
*
|
||||
*/
|
||||
void tusb_task(void);
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_H_ */
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file hal.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_HAL_H_
|
||||
#define _TUSB_HAL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDES
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HAL API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \ingroup group_mcu
|
||||
* \defgroup group_hal Hardware Abtract Layer (HAL)
|
||||
* Hardware Abstraction Layer (HAL) is an abstraction layer, between the physical hardware and the tinyusb stack.
|
||||
* Its function is to hide differences in hardware from most of MCUs, so that most of the stack code does not need to be changed to
|
||||
* run on systems with a different MCU.
|
||||
* HAL are sets of routines that emulate some platform-specific details, giving programs direct access to the hardware resources.
|
||||
* @{ */
|
||||
|
||||
/** \brief Initialize USB controller hardware
|
||||
* \returns true if succeeded
|
||||
* \note This function is invoked by \ref tusb_init as part of the initialization.
|
||||
*/
|
||||
bool tusb_hal_init(void);
|
||||
|
||||
/** \brief Enable USB Interrupt on a specific USB Controller
|
||||
* \param[in] rhport is a zero-based index to identify USB controller's ID
|
||||
*/
|
||||
void tusb_hal_int_enable(uint8_t rhport);
|
||||
|
||||
/** \brief Disable USB Interrupt on a specific USB Controller
|
||||
* \param[in] rhport is a zero-based index to identify USB controller's ID
|
||||
*/
|
||||
void tusb_hal_int_disable(uint8_t rhport);
|
||||
|
||||
// Only required to implement if using No RTOS (osal_none)
|
||||
uint32_t tusb_hal_millis(void);
|
||||
|
||||
|
||||
// Enable all ports' interrupt
|
||||
static inline void tusb_hal_int_enable_all(void)
|
||||
{
|
||||
#ifdef CFG_TUSB_RHPORT0_MODE
|
||||
tusb_hal_int_enable(0);
|
||||
#endif
|
||||
|
||||
#ifdef CFG_TUSB_RHPORT0_MODE
|
||||
tusb_hal_int_enable(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Disable all ports' interrupt
|
||||
static inline void tusb_hal_int_disable_all(void)
|
||||
{
|
||||
#ifdef CFG_TUSB_RHPORT0_MODE
|
||||
tusb_hal_int_disable(0);
|
||||
#endif
|
||||
|
||||
#ifdef CFG_TUSB_RHPORT0_MODE
|
||||
tusb_hal_int_disable(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HAL_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,213 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@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_OPTION_H_
|
||||
#define _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)
|
||||
|
||||
/** \defgroup group_mcu Supported MCU
|
||||
* \ref CFG_TUSB_MCU must be defined to one of these
|
||||
* @{ */
|
||||
#define OPT_MCU_LPC11UXX 1 ///< NXP LPC11Uxx series
|
||||
#define OPT_MCU_LPC13XX 2 ///< NXP LPC13xx (not supported yet)
|
||||
#define OPT_MCU_LPC13UXX 3 ///< NXP LPC13xx 12 bit ADC series
|
||||
#define OPT_MCU_LPC175X_6X 4 ///< NXP LPC175x, LPC176x series
|
||||
#define OPT_MCU_LPC177X_8X 5 ///< NXP LPC177x, LPC178x series (not supported yet)
|
||||
#define OPT_MCU_LPC18XX 6 ///< NXP LPC18xx series (not supported yet)
|
||||
#define OPT_MCU_LPC43XX 7 ///< NXP LPC43xx series
|
||||
|
||||
#define OPT_MCU_NRF5X 100 ///< Nordic nRF5x series
|
||||
/** @} */
|
||||
|
||||
/** \defgroup group_supported_os Supported RTOS
|
||||
* \ref CFG_TUSB_OS must be defined to one of these
|
||||
* @{ */
|
||||
#define OPT_OS_NONE 1 ///< No RTOS is used
|
||||
#define OPT_OS_FREERTOS 2 ///< FreeRTOS is used
|
||||
/** @} */
|
||||
|
||||
|
||||
// Allow to use command line to change the config name/location
|
||||
#ifndef CFG_TUSB_CONFIG_FILE
|
||||
#define CFG_TUSB_CONFIG_FILE "tusb_config.h"
|
||||
#endif
|
||||
|
||||
#include CFG_TUSB_CONFIG_FILE
|
||||
|
||||
/** \addtogroup group_configuration
|
||||
* @{ */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROLLER
|
||||
//--------------------------------------------------------------------+
|
||||
/** \defgroup group_mode Controller Mode Selection
|
||||
* \brief CFG_TUSB_CONTROLLER_N_MODE must be defined with these
|
||||
* @{ */
|
||||
#define OPT_MODE_HOST 0x02 ///< Host Mode
|
||||
#define OPT_MODE_DEVICE 0x01 ///< Device Mode
|
||||
#define OPT_MODE_NONE 0x00 ///< Disabled
|
||||
/** @} */
|
||||
|
||||
#ifndef CFG_TUSB_RHPORT0_MODE
|
||||
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_RHPORT1_MODE
|
||||
#define CFG_TUSB_RHPORT1_MODE OPT_MODE_NONE
|
||||
#endif
|
||||
|
||||
#define CONTROLLER_HOST_NUMBER (\
|
||||
((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST) ? 1 : 0) + \
|
||||
((CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST) ? 1 : 0))
|
||||
|
||||
#define CONTROLLER_DEVICE_NUMBER (\
|
||||
((CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE) ? 1 : 0) + \
|
||||
((CFG_TUSB_RHPORT1_MODE & OPT_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 CFG_TUSB_CONTROLLER_N_MODE to OPT_MODE_HOST and/or OPT_MODE_DEVICE
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// COMMON OPTIONS
|
||||
//--------------------------------------------------------------------+
|
||||
/**
|
||||
determines the debug level for the stack
|
||||
- Level 3: TBD
|
||||
- Level 2: TBD
|
||||
- Level 1: Print out if Assert failed. STATIC_VAR is NULL --> accessible when debugging
|
||||
- Level 0: no debug information is generated
|
||||
*/
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#warning CFG_TUSB_DEBUG is not defined, default value is 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_ATTR_USBRAM
|
||||
#error CFG_TUSB_ATTR_USBRAM is not defined, please help me know how to place data in accessible RAM for usb controller
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef tu_malloc
|
||||
#include <stdlib.h>
|
||||
#define tu_malloc malloc
|
||||
#endif
|
||||
|
||||
#ifndef tu_free
|
||||
#define tu_free free
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// DEVICE OPTIONS
|
||||
//--------------------------------------------------------------------+
|
||||
#if MODE_DEVICE_SUPPORTED
|
||||
|
||||
#define DEVICE_CLASS_HID ( CFG_TUD_HID_KEYBOARD + CFG_TUD_HID_MOUSE + CFG_TUD_HID_GENERIC )
|
||||
|
||||
#ifndef CFG_TUD_ENDOINT0_SIZE
|
||||
#define CFG_TUD_ENDOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_ENUM_BUFFER_SIZE
|
||||
#define CFG_TUD_ENUM_BUFFER_SIZE 256
|
||||
#endif
|
||||
|
||||
#endif // MODE_DEVICE_SUPPORTED
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HOST OPTIONS
|
||||
//--------------------------------------------------------------------+
|
||||
#if MODE_HOST_SUPPORTED
|
||||
#ifndef CFG_TUSB_HOST_DEVICE_MAX
|
||||
#define CFG_TUSB_HOST_DEVICE_MAX 1
|
||||
#warning CFG_TUSB_HOST_DEVICE_MAX is not defined, default value is 1
|
||||
#endif
|
||||
|
||||
//------------- HUB CLASS -------------//
|
||||
#if CFG_TUSB_HOST_HUB && (CFG_TUSB_HOST_DEVICE_MAX == 1)
|
||||
#error there is no benefit enable hub with max device is 1. Please disable hub or increase CFG_TUSB_HOST_DEVICE_MAX
|
||||
#endif
|
||||
|
||||
//------------- HID CLASS -------------//
|
||||
#define HOST_CLASS_HID ( CFG_TUSB_HOST_HID_KEYBOARD + CFG_TUSB_HOST_HID_MOUSE + CFG_TUSB_HOST_HID_GENERIC )
|
||||
// #if HOST_CLASS_HID
|
||||
// #define HOST_HCD_XFER_INTERRUPT
|
||||
// #endif
|
||||
|
||||
#ifndef CFG_TUSB_HOST_ENUM_BUFFER_SIZE
|
||||
#define CFG_TUSB_HOST_ENUM_BUFFER_SIZE 256
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#endif // MODE_HOST_SUPPORTED
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Config Verification
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
#if (CFG_TUSB_OS != OPT_OS_NONE) && !defined (CFG_TUD_TASK_PRIO)
|
||||
#error CFG_TUD_TASK_PRIO need to be defined (hint: use the highest if possible)
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_ENDOINT0_SIZE > 64
|
||||
#error Control Endpoint Max Package Size cannot larger than 64
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_MSC_MAXLUN == 0 || CFG_TUD_MSC_MAXLUN > 16
|
||||
#error MSC Device: Incorrect setting of MAX LUN
|
||||
#endif
|
||||
|
||||
//#if CFG_TUD_MSC_BUFSIZE
|
||||
|
||||
|
||||
#endif /* _TUSB_OPTION_H_ */
|
||||
|
||||
/** @} */
|
||||
Reference in New Issue
Block a user