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_ */
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
Reference in New Issue
Block a user