mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-17 05:32:55 +08:00
commit
7b20b80dc0
25
.gitattributes
vendored
Normal file
25
.gitattributes
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
*.c text
|
||||
*.cpp text
|
||||
*.h text
|
||||
*.icf text
|
||||
*.js text
|
||||
*.json text
|
||||
*.ld text
|
||||
*.md text
|
||||
*.mk text
|
||||
*.py text
|
||||
*.rst text
|
||||
*.s text
|
||||
*.txt text
|
||||
*.xml text
|
||||
*.yml text
|
||||
|
||||
Makefile text
|
||||
|
||||
# Windows-only Visual Studio things
|
||||
|
||||
*.sln text eol=crlf
|
||||
*.csproj text eol=crlf
|
@ -1,100 +1,100 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_class
|
||||
* \defgroup ClassDriver_Audio Audio
|
||||
* Currently only MIDI subclass is supported
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_AUDIO_H__
|
||||
#define _TUSB_AUDIO_H__
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Audio Interface Subclass Codes
|
||||
typedef enum
|
||||
{
|
||||
AUDIO_SUBCLASS_CONTROL = 0x01 , ///< Audio Control
|
||||
AUDIO_SUBCLASS_STREAMING , ///< Audio Streaming
|
||||
AUDIO_SUBCLASS_MIDI_STREAMING , ///< MIDI Streaming
|
||||
} audio_subclass_type_t;
|
||||
|
||||
/// Audio Protocol Codes
|
||||
typedef enum
|
||||
{
|
||||
AUDIO_PROTOCOL_V1 = 0x00, ///< Version 1.0
|
||||
AUDIO_PROTOCOL_V2 = 0x20, ///< Version 2.0
|
||||
AUDIO_PROTOCOL_V3 = 0x30, ///< Version 3.0
|
||||
} audio_protocol_type_t;
|
||||
|
||||
/// Audio Function Category Codes
|
||||
typedef enum
|
||||
{
|
||||
AUDIO_FUNC_DESKTOP_SPEAKER = 0x01,
|
||||
AUDIO_FUNC_HOME_THEATER = 0x02,
|
||||
AUDIO_FUNC_MICROPHONE = 0x03,
|
||||
AUDIO_FUNC_HEADSET = 0x04,
|
||||
AUDIO_FUNC_TELEPHONE = 0x05,
|
||||
AUDIO_FUNC_CONVERTER = 0x06,
|
||||
AUDIO_FUNC_SOUND_RECODER = 0x07,
|
||||
AUDIO_FUNC_IO_BOX = 0x08,
|
||||
AUDIO_FUNC_MUSICAL_INSTRUMENT = 0x09,
|
||||
AUDIO_FUNC_PRO_AUDIO = 0x0A,
|
||||
AUDIO_FUNC_AUDIO_VIDEO = 0x0B,
|
||||
AUDIO_FUNC_CONTROL_PANEL = 0x0C
|
||||
} audio_function_t;
|
||||
|
||||
/// Audio Class-Specific AC Interface Descriptor Subtypes
|
||||
typedef enum
|
||||
{
|
||||
AUDIO_CS_INTERFACE_HEADER = 0x01,
|
||||
AUDIO_CS_INTERFACE_INPUT_TERMINAL = 0x02,
|
||||
AUDIO_CS_INTERFACE_OUTPUT_TERMINAL = 0x03,
|
||||
AUDIO_CS_INTERFACE_MIXER_UNIT = 0x04,
|
||||
AUDIO_CS_INTERFACE_SELECTOR_UNIT = 0x05,
|
||||
AUDIO_CS_INTERFACE_FEATURE_UNIT = 0x06,
|
||||
AUDIO_CS_INTERFACE_EFFECT_UNIT = 0x07,
|
||||
AUDIO_CS_INTERFACE_PROCESSING_UNIT = 0x08,
|
||||
AUDIO_CS_INTERFACE_EXTENSION_UNIT = 0x09,
|
||||
AUDIO_CS_INTERFACE_CLOCK_SOURCE = 0x0A,
|
||||
AUDIO_CS_INTERFACE_CLOCK_SELECTOR = 0x0B,
|
||||
AUDIO_CS_INTERFACE_CLOCK_MULTIPLIER = 0x0C,
|
||||
AUDIO_CS_INTERFACE_SAMPLE_RATE_CONVERTER = 0x0D,
|
||||
} audio_cs_interface_subtype_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_class
|
||||
* \defgroup ClassDriver_Audio Audio
|
||||
* Currently only MIDI subclass is supported
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_AUDIO_H__
|
||||
#define _TUSB_AUDIO_H__
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Audio Interface Subclass Codes
|
||||
typedef enum
|
||||
{
|
||||
AUDIO_SUBCLASS_CONTROL = 0x01 , ///< Audio Control
|
||||
AUDIO_SUBCLASS_STREAMING , ///< Audio Streaming
|
||||
AUDIO_SUBCLASS_MIDI_STREAMING , ///< MIDI Streaming
|
||||
} audio_subclass_type_t;
|
||||
|
||||
/// Audio Protocol Codes
|
||||
typedef enum
|
||||
{
|
||||
AUDIO_PROTOCOL_V1 = 0x00, ///< Version 1.0
|
||||
AUDIO_PROTOCOL_V2 = 0x20, ///< Version 2.0
|
||||
AUDIO_PROTOCOL_V3 = 0x30, ///< Version 3.0
|
||||
} audio_protocol_type_t;
|
||||
|
||||
/// Audio Function Category Codes
|
||||
typedef enum
|
||||
{
|
||||
AUDIO_FUNC_DESKTOP_SPEAKER = 0x01,
|
||||
AUDIO_FUNC_HOME_THEATER = 0x02,
|
||||
AUDIO_FUNC_MICROPHONE = 0x03,
|
||||
AUDIO_FUNC_HEADSET = 0x04,
|
||||
AUDIO_FUNC_TELEPHONE = 0x05,
|
||||
AUDIO_FUNC_CONVERTER = 0x06,
|
||||
AUDIO_FUNC_SOUND_RECODER = 0x07,
|
||||
AUDIO_FUNC_IO_BOX = 0x08,
|
||||
AUDIO_FUNC_MUSICAL_INSTRUMENT = 0x09,
|
||||
AUDIO_FUNC_PRO_AUDIO = 0x0A,
|
||||
AUDIO_FUNC_AUDIO_VIDEO = 0x0B,
|
||||
AUDIO_FUNC_CONTROL_PANEL = 0x0C
|
||||
} audio_function_t;
|
||||
|
||||
/// Audio Class-Specific AC Interface Descriptor Subtypes
|
||||
typedef enum
|
||||
{
|
||||
AUDIO_CS_INTERFACE_HEADER = 0x01,
|
||||
AUDIO_CS_INTERFACE_INPUT_TERMINAL = 0x02,
|
||||
AUDIO_CS_INTERFACE_OUTPUT_TERMINAL = 0x03,
|
||||
AUDIO_CS_INTERFACE_MIXER_UNIT = 0x04,
|
||||
AUDIO_CS_INTERFACE_SELECTOR_UNIT = 0x05,
|
||||
AUDIO_CS_INTERFACE_FEATURE_UNIT = 0x06,
|
||||
AUDIO_CS_INTERFACE_EFFECT_UNIT = 0x07,
|
||||
AUDIO_CS_INTERFACE_PROCESSING_UNIT = 0x08,
|
||||
AUDIO_CS_INTERFACE_EXTENSION_UNIT = 0x09,
|
||||
AUDIO_CS_INTERFACE_CLOCK_SOURCE = 0x0A,
|
||||
AUDIO_CS_INTERFACE_CLOCK_SELECTOR = 0x0B,
|
||||
AUDIO_CS_INTERFACE_CLOCK_MULTIPLIER = 0x0C,
|
||||
AUDIO_CS_INTERFACE_SAMPLE_RATE_CONVERTER = 0x0D,
|
||||
} audio_cs_interface_subtype_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
@ -1,405 +1,405 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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
|
||||
* @{ */
|
||||
|
||||
// TODO remove
|
||||
/// 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_NONE = 0x00 , ///< No specific protocol
|
||||
CDC_COMM_PROTOCOL_ATCOMMAND , ///< 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;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Specific Functional Descriptor (Communication Interface)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// Header Functional Descriptor (Communication Interface)
|
||||
typedef struct TU_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_FUNC_DESC_
|
||||
uint16_t bcdCDC ; ///< CDC release number in Binary-Coded Decimal
|
||||
}cdc_desc_func_header_t;
|
||||
|
||||
/// Union Functional Descriptor (Communication Interface)
|
||||
typedef struct TU_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 TU_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 TU_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 TU_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 TU_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 TU_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;
|
||||
|
||||
TU_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 TU_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 TU_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 TU_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 TU_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 TU_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 TU_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct");
|
||||
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct");
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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
|
||||
* @{ */
|
||||
|
||||
// TODO remove
|
||||
/// 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_NONE = 0x00 , ///< No specific protocol
|
||||
CDC_COMM_PROTOCOL_ATCOMMAND , ///< 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;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Specific Functional Descriptor (Communication Interface)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// Header Functional Descriptor (Communication Interface)
|
||||
typedef struct TU_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_FUNC_DESC_
|
||||
uint16_t bcdCDC ; ///< CDC release number in Binary-Coded Decimal
|
||||
}cdc_desc_func_header_t;
|
||||
|
||||
/// Union Functional Descriptor (Communication Interface)
|
||||
typedef struct TU_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 TU_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 TU_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 TU_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 TU_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 TU_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;
|
||||
|
||||
TU_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 TU_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 TU_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 TU_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 TU_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 TU_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 TU_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct");
|
||||
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct");
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
@ -1,415 +1,415 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CDC)
|
||||
|
||||
#include "cdc_device.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_notif;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
// Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
|
||||
uint8_t line_state;
|
||||
|
||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||
char wanted_char;
|
||||
cdc_line_coding_t line_coding;
|
||||
|
||||
// FIFO
|
||||
tu_fifo_t rx_ff;
|
||||
tu_fifo_t tx_ff;
|
||||
|
||||
uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE];
|
||||
uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE];
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t rx_ff_mutex;
|
||||
osal_mutex_def_t tx_ff_mutex;
|
||||
#endif
|
||||
|
||||
// Endpoint Transfer buffer
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EPSIZE];
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EPSIZE];
|
||||
|
||||
}cdcd_interface_t;
|
||||
|
||||
#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
|
||||
|
||||
static void _prep_out_transaction (uint8_t itf)
|
||||
{
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
|
||||
// skip if previous transfer not complete
|
||||
if ( usbd_edpt_busy(TUD_OPT_RHPORT, p_cdc->ep_out) ) return;
|
||||
|
||||
// Prepare for incoming data but only allow what we can store in the ring buffer.
|
||||
uint16_t max_read = tu_fifo_remaining(&p_cdc->rx_ff);
|
||||
if ( max_read >= CFG_TUD_CDC_EPSIZE )
|
||||
{
|
||||
usbd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_out, p_cdc->epout_buf, CFG_TUD_CDC_EPSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_cdc_n_connected(uint8_t itf)
|
||||
{
|
||||
// DTR (bit 0) active is considered as connected
|
||||
return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0);
|
||||
}
|
||||
|
||||
uint8_t tud_cdc_n_get_line_state (uint8_t itf)
|
||||
{
|
||||
return _cdcd_itf[itf].line_state;
|
||||
}
|
||||
|
||||
void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding)
|
||||
{
|
||||
(*coding) = _cdcd_itf[itf].line_coding;
|
||||
}
|
||||
|
||||
void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted)
|
||||
{
|
||||
_cdcd_itf[itf].wanted_char = wanted;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// READ API
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t tud_cdc_n_available(uint8_t itf)
|
||||
{
|
||||
return tu_fifo_count(&_cdcd_itf[itf].rx_ff);
|
||||
}
|
||||
|
||||
uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint32_t num_read = tu_fifo_read_n(&_cdcd_itf[itf].rx_ff, buffer, bufsize);
|
||||
_prep_out_transaction(itf);
|
||||
return num_read;
|
||||
}
|
||||
|
||||
bool tud_cdc_n_peek(uint8_t itf, int pos, uint8_t* chr)
|
||||
{
|
||||
return tu_fifo_peek_at(&_cdcd_itf[itf].rx_ff, pos, chr);
|
||||
}
|
||||
|
||||
void tud_cdc_n_read_flush (uint8_t itf)
|
||||
{
|
||||
tu_fifo_clear(&_cdcd_itf[itf].rx_ff);
|
||||
_prep_out_transaction(itf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// WRITE API
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint16_t ret = tu_fifo_write_n(&_cdcd_itf[itf].tx_ff, buffer, bufsize);
|
||||
|
||||
#if 0 // TODO issue with circuitpython's REPL
|
||||
// flush if queue more than endpoint size
|
||||
if ( tu_fifo_count(&_cdcd_itf[itf].tx_ff) >= CFG_TUD_CDC_EPSIZE )
|
||||
{
|
||||
tud_cdc_n_write_flush(itf);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool tud_cdc_n_write_flush (uint8_t itf)
|
||||
{
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, p_cdc->ep_in) ); // skip if previous transfer not complete
|
||||
|
||||
uint16_t count = tu_fifo_read_n(&_cdcd_itf[itf].tx_ff, p_cdc->epin_buf, CFG_TUD_CDC_EPSIZE);
|
||||
if ( count )
|
||||
{
|
||||
TU_VERIFY( tud_cdc_n_connected(itf) ); // fifo is empty if not connected
|
||||
TU_ASSERT( usbd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_in, p_cdc->epin_buf, count) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t tud_cdc_n_write_available (uint8_t itf)
|
||||
{
|
||||
return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdcd_init(void)
|
||||
{
|
||||
tu_memclr(_cdcd_itf, sizeof(_cdcd_itf));
|
||||
|
||||
for(uint8_t i=0; i<CFG_TUD_CDC; i++)
|
||||
{
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
|
||||
|
||||
p_cdc->wanted_char = -1;
|
||||
|
||||
// default line coding is : stop bit = 1, parity = none, data bits = 8
|
||||
p_cdc->line_coding.bit_rate = 115200;
|
||||
p_cdc->line_coding.stop_bits = 0;
|
||||
p_cdc->line_coding.parity = 0;
|
||||
p_cdc->line_coding.data_bits = 8;
|
||||
|
||||
// config fifo
|
||||
tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, 1, false);
|
||||
tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, 1, false);
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
tu_fifo_config_mutex(&p_cdc->rx_ff, osal_mutex_create(&p_cdc->rx_ff_mutex));
|
||||
tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void cdcd_reset(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
for(uint8_t i=0; i<CFG_TUD_CDC; i++)
|
||||
{
|
||||
tu_memclr(&_cdcd_itf[i], ITF_MEM_RESET_SIZE);
|
||||
tu_fifo_clear(&_cdcd_itf[i].rx_ff);
|
||||
tu_fifo_clear(&_cdcd_itf[i].tx_ff);
|
||||
}
|
||||
}
|
||||
|
||||
bool cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length)
|
||||
{
|
||||
// Only support ACM subclass
|
||||
TU_ASSERT ( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass);
|
||||
|
||||
// Only support AT commands, no protocol and vendor specific commands.
|
||||
TU_ASSERT(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
|
||||
itf_desc->bInterfaceProtocol == 0xff);
|
||||
|
||||
// Find available interface
|
||||
cdcd_interface_t * p_cdc = NULL;
|
||||
uint8_t cdc_id;
|
||||
for(cdc_id=0; cdc_id<CFG_TUD_CDC; cdc_id++)
|
||||
{
|
||||
if ( _cdcd_itf[cdc_id].ep_in == 0 )
|
||||
{
|
||||
p_cdc = &_cdcd_itf[cdc_id];
|
||||
break;
|
||||
}
|
||||
}
|
||||
TU_ASSERT(p_cdc);
|
||||
|
||||
//------------- Control Interface -------------//
|
||||
p_cdc->itf_num = itf_desc->bInterfaceNumber;
|
||||
|
||||
uint8_t const * p_desc = tu_desc_next( itf_desc );
|
||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||
|
||||
// Communication Functional Descriptors
|
||||
while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) )
|
||||
{
|
||||
(*p_length) += tu_desc_len(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
|
||||
{
|
||||
// notification endpoint if any
|
||||
TU_ASSERT( dcd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc) );
|
||||
|
||||
p_cdc->ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
|
||||
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
//------------- Data Interface (if any) -------------//
|
||||
if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) &&
|
||||
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
|
||||
{
|
||||
// next to endpoint descriptor
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
|
||||
// Open endpoint pair
|
||||
TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in) );
|
||||
|
||||
(*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
|
||||
}
|
||||
|
||||
// Prepare for incoming data
|
||||
_prep_out_transaction(cdc_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Invoked when class request DATA stage is finished.
|
||||
// return false to stall control endpoint (e.g Host send non-sense DATA)
|
||||
bool cdcd_control_complete(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
//------------- Class Specific Request -------------//
|
||||
TU_VERIFY (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
||||
|
||||
uint8_t itf = 0;
|
||||
cdcd_interface_t* p_cdc = _cdcd_itf;
|
||||
|
||||
// Identify which interface to use
|
||||
for ( ; ; itf++, p_cdc++)
|
||||
{
|
||||
if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false;
|
||||
|
||||
if ( p_cdc->itf_num == request->wIndex ) break;
|
||||
}
|
||||
|
||||
// Invoke callback
|
||||
if ( CDC_REQUEST_SET_LINE_CODING == request->bRequest )
|
||||
{
|
||||
if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle class control request
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool cdcd_control_request(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
// Handle class request only
|
||||
TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
||||
|
||||
uint8_t itf = 0;
|
||||
cdcd_interface_t* p_cdc = _cdcd_itf;
|
||||
|
||||
// Identify which interface to use
|
||||
for ( ; ; itf++, p_cdc++)
|
||||
{
|
||||
if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false;
|
||||
|
||||
if ( p_cdc->itf_num == request->wIndex ) break;
|
||||
}
|
||||
|
||||
switch ( request->bRequest )
|
||||
{
|
||||
case CDC_REQUEST_SET_LINE_CODING:
|
||||
tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
|
||||
break;
|
||||
|
||||
case CDC_REQUEST_GET_LINE_CODING:
|
||||
tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
|
||||
break;
|
||||
|
||||
case CDC_REQUEST_SET_CONTROL_LINE_STATE:
|
||||
// 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)
|
||||
p_cdc->line_state = (uint8_t) request->wValue;
|
||||
|
||||
tud_control_status(rhport, request);
|
||||
|
||||
// Invoke callback
|
||||
if ( tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, tu_bit_test(request->wValue, 0), tu_bit_test(request->wValue, 1));
|
||||
break;
|
||||
|
||||
default: return false; // stall unsupported request
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) result;
|
||||
|
||||
uint8_t itf = 0;
|
||||
cdcd_interface_t* p_cdc = _cdcd_itf;
|
||||
|
||||
// Identify which interface to use
|
||||
for ( ; ; itf++, p_cdc++)
|
||||
{
|
||||
if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false;
|
||||
|
||||
if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) ) break;
|
||||
}
|
||||
|
||||
// Received new data
|
||||
if ( ep_addr == p_cdc->ep_out )
|
||||
{
|
||||
for(uint32_t i=0; i<xferred_bytes; i++)
|
||||
{
|
||||
tu_fifo_write(&p_cdc->rx_ff, &p_cdc->epout_buf[i]);
|
||||
|
||||
// Check for wanted char and invoke callback if needed
|
||||
if ( tud_cdc_rx_wanted_cb && ( ((signed char) p_cdc->wanted_char) != -1 ) && ( p_cdc->wanted_char == p_cdc->epout_buf[i] ) )
|
||||
{
|
||||
tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
|
||||
}
|
||||
}
|
||||
|
||||
// invoke receive callback (if there is still data)
|
||||
if (tud_cdc_rx_cb && tu_fifo_count(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf);
|
||||
|
||||
// prepare for OUT transaction
|
||||
_prep_out_transaction(itf);
|
||||
}
|
||||
|
||||
// Data sent to host, we could continue to fetch data tx fifo to send.
|
||||
// But it will cause incorrect baudrate set in line coding.
|
||||
// Though maybe the baudrate is not really important !!!
|
||||
// if ( ep_addr == p_cdc->ep_in )
|
||||
// {
|
||||
//
|
||||
// }
|
||||
|
||||
// nothing to do with notif endpoint for now
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CDC)
|
||||
|
||||
#include "cdc_device.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_notif;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
// Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
|
||||
uint8_t line_state;
|
||||
|
||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||
char wanted_char;
|
||||
cdc_line_coding_t line_coding;
|
||||
|
||||
// FIFO
|
||||
tu_fifo_t rx_ff;
|
||||
tu_fifo_t tx_ff;
|
||||
|
||||
uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE];
|
||||
uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE];
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t rx_ff_mutex;
|
||||
osal_mutex_def_t tx_ff_mutex;
|
||||
#endif
|
||||
|
||||
// Endpoint Transfer buffer
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EPSIZE];
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EPSIZE];
|
||||
|
||||
}cdcd_interface_t;
|
||||
|
||||
#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
|
||||
|
||||
static void _prep_out_transaction (uint8_t itf)
|
||||
{
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
|
||||
// skip if previous transfer not complete
|
||||
if ( usbd_edpt_busy(TUD_OPT_RHPORT, p_cdc->ep_out) ) return;
|
||||
|
||||
// Prepare for incoming data but only allow what we can store in the ring buffer.
|
||||
uint16_t max_read = tu_fifo_remaining(&p_cdc->rx_ff);
|
||||
if ( max_read >= CFG_TUD_CDC_EPSIZE )
|
||||
{
|
||||
usbd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_out, p_cdc->epout_buf, CFG_TUD_CDC_EPSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_cdc_n_connected(uint8_t itf)
|
||||
{
|
||||
// DTR (bit 0) active is considered as connected
|
||||
return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0);
|
||||
}
|
||||
|
||||
uint8_t tud_cdc_n_get_line_state (uint8_t itf)
|
||||
{
|
||||
return _cdcd_itf[itf].line_state;
|
||||
}
|
||||
|
||||
void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding)
|
||||
{
|
||||
(*coding) = _cdcd_itf[itf].line_coding;
|
||||
}
|
||||
|
||||
void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted)
|
||||
{
|
||||
_cdcd_itf[itf].wanted_char = wanted;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// READ API
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t tud_cdc_n_available(uint8_t itf)
|
||||
{
|
||||
return tu_fifo_count(&_cdcd_itf[itf].rx_ff);
|
||||
}
|
||||
|
||||
uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint32_t num_read = tu_fifo_read_n(&_cdcd_itf[itf].rx_ff, buffer, bufsize);
|
||||
_prep_out_transaction(itf);
|
||||
return num_read;
|
||||
}
|
||||
|
||||
bool tud_cdc_n_peek(uint8_t itf, int pos, uint8_t* chr)
|
||||
{
|
||||
return tu_fifo_peek_at(&_cdcd_itf[itf].rx_ff, pos, chr);
|
||||
}
|
||||
|
||||
void tud_cdc_n_read_flush (uint8_t itf)
|
||||
{
|
||||
tu_fifo_clear(&_cdcd_itf[itf].rx_ff);
|
||||
_prep_out_transaction(itf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// WRITE API
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint16_t ret = tu_fifo_write_n(&_cdcd_itf[itf].tx_ff, buffer, bufsize);
|
||||
|
||||
#if 0 // TODO issue with circuitpython's REPL
|
||||
// flush if queue more than endpoint size
|
||||
if ( tu_fifo_count(&_cdcd_itf[itf].tx_ff) >= CFG_TUD_CDC_EPSIZE )
|
||||
{
|
||||
tud_cdc_n_write_flush(itf);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool tud_cdc_n_write_flush (uint8_t itf)
|
||||
{
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, p_cdc->ep_in) ); // skip if previous transfer not complete
|
||||
|
||||
uint16_t count = tu_fifo_read_n(&_cdcd_itf[itf].tx_ff, p_cdc->epin_buf, CFG_TUD_CDC_EPSIZE);
|
||||
if ( count )
|
||||
{
|
||||
TU_VERIFY( tud_cdc_n_connected(itf) ); // fifo is empty if not connected
|
||||
TU_ASSERT( usbd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_in, p_cdc->epin_buf, count) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t tud_cdc_n_write_available (uint8_t itf)
|
||||
{
|
||||
return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdcd_init(void)
|
||||
{
|
||||
tu_memclr(_cdcd_itf, sizeof(_cdcd_itf));
|
||||
|
||||
for(uint8_t i=0; i<CFG_TUD_CDC; i++)
|
||||
{
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
|
||||
|
||||
p_cdc->wanted_char = -1;
|
||||
|
||||
// default line coding is : stop bit = 1, parity = none, data bits = 8
|
||||
p_cdc->line_coding.bit_rate = 115200;
|
||||
p_cdc->line_coding.stop_bits = 0;
|
||||
p_cdc->line_coding.parity = 0;
|
||||
p_cdc->line_coding.data_bits = 8;
|
||||
|
||||
// config fifo
|
||||
tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, 1, false);
|
||||
tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, 1, false);
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
tu_fifo_config_mutex(&p_cdc->rx_ff, osal_mutex_create(&p_cdc->rx_ff_mutex));
|
||||
tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void cdcd_reset(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
for(uint8_t i=0; i<CFG_TUD_CDC; i++)
|
||||
{
|
||||
tu_memclr(&_cdcd_itf[i], ITF_MEM_RESET_SIZE);
|
||||
tu_fifo_clear(&_cdcd_itf[i].rx_ff);
|
||||
tu_fifo_clear(&_cdcd_itf[i].tx_ff);
|
||||
}
|
||||
}
|
||||
|
||||
bool cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length)
|
||||
{
|
||||
// Only support ACM subclass
|
||||
TU_ASSERT ( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass);
|
||||
|
||||
// Only support AT commands, no protocol and vendor specific commands.
|
||||
TU_ASSERT(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
|
||||
itf_desc->bInterfaceProtocol == 0xff);
|
||||
|
||||
// Find available interface
|
||||
cdcd_interface_t * p_cdc = NULL;
|
||||
uint8_t cdc_id;
|
||||
for(cdc_id=0; cdc_id<CFG_TUD_CDC; cdc_id++)
|
||||
{
|
||||
if ( _cdcd_itf[cdc_id].ep_in == 0 )
|
||||
{
|
||||
p_cdc = &_cdcd_itf[cdc_id];
|
||||
break;
|
||||
}
|
||||
}
|
||||
TU_ASSERT(p_cdc);
|
||||
|
||||
//------------- Control Interface -------------//
|
||||
p_cdc->itf_num = itf_desc->bInterfaceNumber;
|
||||
|
||||
uint8_t const * p_desc = tu_desc_next( itf_desc );
|
||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||
|
||||
// Communication Functional Descriptors
|
||||
while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) )
|
||||
{
|
||||
(*p_length) += tu_desc_len(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
|
||||
{
|
||||
// notification endpoint if any
|
||||
TU_ASSERT( dcd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc) );
|
||||
|
||||
p_cdc->ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
|
||||
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
//------------- Data Interface (if any) -------------//
|
||||
if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) &&
|
||||
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
|
||||
{
|
||||
// next to endpoint descriptor
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
|
||||
// Open endpoint pair
|
||||
TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in) );
|
||||
|
||||
(*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
|
||||
}
|
||||
|
||||
// Prepare for incoming data
|
||||
_prep_out_transaction(cdc_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Invoked when class request DATA stage is finished.
|
||||
// return false to stall control endpoint (e.g Host send non-sense DATA)
|
||||
bool cdcd_control_complete(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
//------------- Class Specific Request -------------//
|
||||
TU_VERIFY (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
||||
|
||||
uint8_t itf = 0;
|
||||
cdcd_interface_t* p_cdc = _cdcd_itf;
|
||||
|
||||
// Identify which interface to use
|
||||
for ( ; ; itf++, p_cdc++)
|
||||
{
|
||||
if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false;
|
||||
|
||||
if ( p_cdc->itf_num == request->wIndex ) break;
|
||||
}
|
||||
|
||||
// Invoke callback
|
||||
if ( CDC_REQUEST_SET_LINE_CODING == request->bRequest )
|
||||
{
|
||||
if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle class control request
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool cdcd_control_request(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
// Handle class request only
|
||||
TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
||||
|
||||
uint8_t itf = 0;
|
||||
cdcd_interface_t* p_cdc = _cdcd_itf;
|
||||
|
||||
// Identify which interface to use
|
||||
for ( ; ; itf++, p_cdc++)
|
||||
{
|
||||
if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false;
|
||||
|
||||
if ( p_cdc->itf_num == request->wIndex ) break;
|
||||
}
|
||||
|
||||
switch ( request->bRequest )
|
||||
{
|
||||
case CDC_REQUEST_SET_LINE_CODING:
|
||||
tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
|
||||
break;
|
||||
|
||||
case CDC_REQUEST_GET_LINE_CODING:
|
||||
tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
|
||||
break;
|
||||
|
||||
case CDC_REQUEST_SET_CONTROL_LINE_STATE:
|
||||
// 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)
|
||||
p_cdc->line_state = (uint8_t) request->wValue;
|
||||
|
||||
tud_control_status(rhport, request);
|
||||
|
||||
// Invoke callback
|
||||
if ( tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, tu_bit_test(request->wValue, 0), tu_bit_test(request->wValue, 1));
|
||||
break;
|
||||
|
||||
default: return false; // stall unsupported request
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) result;
|
||||
|
||||
uint8_t itf = 0;
|
||||
cdcd_interface_t* p_cdc = _cdcd_itf;
|
||||
|
||||
// Identify which interface to use
|
||||
for ( ; ; itf++, p_cdc++)
|
||||
{
|
||||
if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false;
|
||||
|
||||
if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) ) break;
|
||||
}
|
||||
|
||||
// Received new data
|
||||
if ( ep_addr == p_cdc->ep_out )
|
||||
{
|
||||
for(uint32_t i=0; i<xferred_bytes; i++)
|
||||
{
|
||||
tu_fifo_write(&p_cdc->rx_ff, &p_cdc->epout_buf[i]);
|
||||
|
||||
// Check for wanted char and invoke callback if needed
|
||||
if ( tud_cdc_rx_wanted_cb && ( ((signed char) p_cdc->wanted_char) != -1 ) && ( p_cdc->wanted_char == p_cdc->epout_buf[i] ) )
|
||||
{
|
||||
tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
|
||||
}
|
||||
}
|
||||
|
||||
// invoke receive callback (if there is still data)
|
||||
if (tud_cdc_rx_cb && tu_fifo_count(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf);
|
||||
|
||||
// prepare for OUT transaction
|
||||
_prep_out_transaction(itf);
|
||||
}
|
||||
|
||||
// Data sent to host, we could continue to fetch data tx fifo to send.
|
||||
// But it will cause incorrect baudrate set in line coding.
|
||||
// Though maybe the baudrate is not really important !!!
|
||||
// if ( ep_addr == p_cdc->ep_in )
|
||||
// {
|
||||
//
|
||||
// }
|
||||
|
||||
// nothing to do with notif endpoint for now
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,213 +1,213 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Driver Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
#ifndef CFG_TUD_CDC_EPSIZE
|
||||
#define CFG_TUD_CDC_EPSIZE 64
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \addtogroup CDC_Serial Serial
|
||||
* @{
|
||||
* \defgroup CDC_Serial_Device Device
|
||||
* @{ */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API (Multiple Interfaces)
|
||||
// CFG_TUD_CDC > 1
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_cdc_n_connected (uint8_t itf);
|
||||
uint8_t tud_cdc_n_get_line_state (uint8_t itf);
|
||||
void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding);
|
||||
void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted);
|
||||
|
||||
uint32_t tud_cdc_n_available (uint8_t itf);
|
||||
uint32_t tud_cdc_n_read (uint8_t itf, void* buffer, uint32_t bufsize);
|
||||
void tud_cdc_n_read_flush (uint8_t itf);
|
||||
bool tud_cdc_n_peek (uint8_t itf, int pos, uint8_t* u8);
|
||||
static inline int32_t tud_cdc_n_read_char (uint8_t itf);
|
||||
|
||||
uint32_t tud_cdc_n_write (uint8_t itf, void const* buffer, uint32_t bufsize);
|
||||
bool tud_cdc_n_write_flush (uint8_t itf);
|
||||
uint32_t tud_cdc_n_write_available (uint8_t itf);
|
||||
static inline uint32_t tud_cdc_n_write_char (uint8_t itf, char ch);
|
||||
static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API (Interface0)
|
||||
//--------------------------------------------------------------------+
|
||||
static inline bool tud_cdc_connected (void);
|
||||
static inline uint8_t tud_cdc_get_line_state (void);
|
||||
static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding);
|
||||
static inline void tud_cdc_set_wanted_char (char wanted);
|
||||
|
||||
static inline uint32_t tud_cdc_available (void);
|
||||
static inline int32_t tud_cdc_read_char (void);
|
||||
static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize);
|
||||
static inline void tud_cdc_read_flush (void);
|
||||
static inline bool tud_cdc_peek (int pos, uint8_t* u8);
|
||||
|
||||
static inline uint32_t tud_cdc_write_char (char ch);
|
||||
static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize);
|
||||
static inline uint32_t tud_cdc_write_str (char const* str);
|
||||
static inline bool tud_cdc_write_flush (void);
|
||||
static inline uint32_t tud_cdc_write_available (void);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callback API (weak is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received new data
|
||||
TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf);
|
||||
|
||||
// Invoked when received `wanted_char`
|
||||
TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
|
||||
|
||||
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
|
||||
TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
|
||||
|
||||
// Invoked when line coding is change via SET_LINE_CODING
|
||||
TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Inline Functions
|
||||
//--------------------------------------------------------------------+
|
||||
static inline int32_t tud_cdc_n_read_char (uint8_t itf)
|
||||
{
|
||||
uint8_t ch;
|
||||
return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1;
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch)
|
||||
{
|
||||
return tud_cdc_n_write(itf, &ch, 1);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str)
|
||||
{
|
||||
return tud_cdc_n_write(itf, str, strlen(str));
|
||||
}
|
||||
|
||||
static inline bool tud_cdc_connected (void)
|
||||
{
|
||||
return tud_cdc_n_connected(0);
|
||||
}
|
||||
|
||||
static inline uint8_t tud_cdc_get_line_state (void)
|
||||
{
|
||||
return tud_cdc_n_get_line_state(0);
|
||||
}
|
||||
|
||||
static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding)
|
||||
{
|
||||
tud_cdc_n_get_line_coding(0, coding);
|
||||
}
|
||||
|
||||
static inline void tud_cdc_set_wanted_char (char wanted)
|
||||
{
|
||||
tud_cdc_n_set_wanted_char(0, wanted);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_available (void)
|
||||
{
|
||||
return tud_cdc_n_available(0);
|
||||
}
|
||||
|
||||
static inline int32_t tud_cdc_read_char (void)
|
||||
{
|
||||
return tud_cdc_n_read_char(0);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize)
|
||||
{
|
||||
return tud_cdc_n_read(0, buffer, bufsize);
|
||||
}
|
||||
|
||||
static inline void tud_cdc_read_flush (void)
|
||||
{
|
||||
tud_cdc_n_read_flush(0);
|
||||
}
|
||||
|
||||
static inline bool tud_cdc_peek (int pos, uint8_t* u8)
|
||||
{
|
||||
return tud_cdc_n_peek(0, pos, u8);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_write_char (char ch)
|
||||
{
|
||||
return tud_cdc_n_write_char(0, ch);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize)
|
||||
{
|
||||
return tud_cdc_n_write(0, buffer, bufsize);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_write_str (char const* str)
|
||||
{
|
||||
return tud_cdc_n_write_str(0, str);
|
||||
}
|
||||
|
||||
static inline bool tud_cdc_write_flush (void)
|
||||
{
|
||||
return tud_cdc_n_write_flush(0);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_write_available(void)
|
||||
{
|
||||
return tud_cdc_n_write_available(0);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL USBD-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdcd_init (void);
|
||||
void cdcd_reset (uint8_t rhport);
|
||||
bool cdcd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
|
||||
bool cdcd_control_request (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool cdcd_control_complete (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool cdcd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CDC_DEVICE_H_ */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Driver Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
#ifndef CFG_TUD_CDC_EPSIZE
|
||||
#define CFG_TUD_CDC_EPSIZE 64
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \addtogroup CDC_Serial Serial
|
||||
* @{
|
||||
* \defgroup CDC_Serial_Device Device
|
||||
* @{ */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API (Multiple Interfaces)
|
||||
// CFG_TUD_CDC > 1
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_cdc_n_connected (uint8_t itf);
|
||||
uint8_t tud_cdc_n_get_line_state (uint8_t itf);
|
||||
void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding);
|
||||
void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted);
|
||||
|
||||
uint32_t tud_cdc_n_available (uint8_t itf);
|
||||
uint32_t tud_cdc_n_read (uint8_t itf, void* buffer, uint32_t bufsize);
|
||||
void tud_cdc_n_read_flush (uint8_t itf);
|
||||
bool tud_cdc_n_peek (uint8_t itf, int pos, uint8_t* u8);
|
||||
static inline int32_t tud_cdc_n_read_char (uint8_t itf);
|
||||
|
||||
uint32_t tud_cdc_n_write (uint8_t itf, void const* buffer, uint32_t bufsize);
|
||||
bool tud_cdc_n_write_flush (uint8_t itf);
|
||||
uint32_t tud_cdc_n_write_available (uint8_t itf);
|
||||
static inline uint32_t tud_cdc_n_write_char (uint8_t itf, char ch);
|
||||
static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API (Interface0)
|
||||
//--------------------------------------------------------------------+
|
||||
static inline bool tud_cdc_connected (void);
|
||||
static inline uint8_t tud_cdc_get_line_state (void);
|
||||
static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding);
|
||||
static inline void tud_cdc_set_wanted_char (char wanted);
|
||||
|
||||
static inline uint32_t tud_cdc_available (void);
|
||||
static inline int32_t tud_cdc_read_char (void);
|
||||
static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize);
|
||||
static inline void tud_cdc_read_flush (void);
|
||||
static inline bool tud_cdc_peek (int pos, uint8_t* u8);
|
||||
|
||||
static inline uint32_t tud_cdc_write_char (char ch);
|
||||
static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize);
|
||||
static inline uint32_t tud_cdc_write_str (char const* str);
|
||||
static inline bool tud_cdc_write_flush (void);
|
||||
static inline uint32_t tud_cdc_write_available (void);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callback API (weak is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received new data
|
||||
TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf);
|
||||
|
||||
// Invoked when received `wanted_char`
|
||||
TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
|
||||
|
||||
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
|
||||
TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
|
||||
|
||||
// Invoked when line coding is change via SET_LINE_CODING
|
||||
TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Inline Functions
|
||||
//--------------------------------------------------------------------+
|
||||
static inline int32_t tud_cdc_n_read_char (uint8_t itf)
|
||||
{
|
||||
uint8_t ch;
|
||||
return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1;
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch)
|
||||
{
|
||||
return tud_cdc_n_write(itf, &ch, 1);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str)
|
||||
{
|
||||
return tud_cdc_n_write(itf, str, strlen(str));
|
||||
}
|
||||
|
||||
static inline bool tud_cdc_connected (void)
|
||||
{
|
||||
return tud_cdc_n_connected(0);
|
||||
}
|
||||
|
||||
static inline uint8_t tud_cdc_get_line_state (void)
|
||||
{
|
||||
return tud_cdc_n_get_line_state(0);
|
||||
}
|
||||
|
||||
static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding)
|
||||
{
|
||||
tud_cdc_n_get_line_coding(0, coding);
|
||||
}
|
||||
|
||||
static inline void tud_cdc_set_wanted_char (char wanted)
|
||||
{
|
||||
tud_cdc_n_set_wanted_char(0, wanted);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_available (void)
|
||||
{
|
||||
return tud_cdc_n_available(0);
|
||||
}
|
||||
|
||||
static inline int32_t tud_cdc_read_char (void)
|
||||
{
|
||||
return tud_cdc_n_read_char(0);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize)
|
||||
{
|
||||
return tud_cdc_n_read(0, buffer, bufsize);
|
||||
}
|
||||
|
||||
static inline void tud_cdc_read_flush (void)
|
||||
{
|
||||
tud_cdc_n_read_flush(0);
|
||||
}
|
||||
|
||||
static inline bool tud_cdc_peek (int pos, uint8_t* u8)
|
||||
{
|
||||
return tud_cdc_n_peek(0, pos, u8);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_write_char (char ch)
|
||||
{
|
||||
return tud_cdc_n_write_char(0, ch);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize)
|
||||
{
|
||||
return tud_cdc_n_write(0, buffer, bufsize);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_write_str (char const* str)
|
||||
{
|
||||
return tud_cdc_n_write_str(0, str);
|
||||
}
|
||||
|
||||
static inline bool tud_cdc_write_flush (void)
|
||||
{
|
||||
return tud_cdc_n_write_flush(0);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_cdc_write_available(void)
|
||||
{
|
||||
return tud_cdc_n_write_available(0);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL USBD-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdcd_init (void);
|
||||
void cdcd_reset (uint8_t rhport);
|
||||
bool cdcd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
|
||||
bool cdcd_control_request (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool cdcd_control_complete (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool cdcd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CDC_DEVICE_H_ */
|
||||
|
@ -1,225 +1,225 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_CDC)
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "cdc_host.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
uint8_t itf_num;
|
||||
uint8_t itf_protocol;
|
||||
|
||||
uint8_t ep_notif;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
cdc_acm_capability_t acm_capability;
|
||||
|
||||
} cdch_data_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
static cdch_data_t cdch_data[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
|
||||
bool tuh_cdc_mounted(uint8_t dev_addr)
|
||||
{
|
||||
cdch_data_t* cdc = &cdch_data[dev_addr-1];
|
||||
return cdc->ep_in && cdc->ep_out;
|
||||
}
|
||||
|
||||
bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid)
|
||||
{
|
||||
if ( !tuh_cdc_mounted(dev_addr) ) return false;
|
||||
|
||||
cdch_data_t const * p_cdc = &cdch_data[dev_addr-1];
|
||||
|
||||
switch (pipeid)
|
||||
{
|
||||
case CDC_PIPE_NOTIFICATION:
|
||||
return hcd_edpt_busy(dev_addr, p_cdc->ep_notif );
|
||||
|
||||
case CDC_PIPE_DATA_IN:
|
||||
return hcd_edpt_busy(dev_addr, p_cdc->ep_in );
|
||||
|
||||
case CDC_PIPE_DATA_OUT:
|
||||
return hcd_edpt_busy(dev_addr, p_cdc->ep_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 tuh_cdc_mounted(dev_addr) &&
|
||||
(CDC_COMM_PROTOCOL_ATCOMMAND <= cdch_data[dev_addr-1].itf_protocol) &&
|
||||
(cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA);
|
||||
}
|
||||
|
||||
bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify)
|
||||
{
|
||||
TU_VERIFY( tuh_cdc_mounted(dev_addr) );
|
||||
TU_VERIFY( p_data != NULL && length, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
uint8_t const ep_out = cdch_data[dev_addr-1].ep_out;
|
||||
if ( hcd_edpt_busy(dev_addr, ep_out) ) return false;
|
||||
|
||||
return hcd_pipe_xfer(dev_addr, ep_out, (void *) p_data, length, is_notify);
|
||||
}
|
||||
|
||||
bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify)
|
||||
{
|
||||
TU_VERIFY( tuh_cdc_mounted(dev_addr) );
|
||||
TU_VERIFY( p_buffer != NULL && length, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
uint8_t const ep_in = cdch_data[dev_addr-1].ep_in;
|
||||
if ( hcd_edpt_busy(dev_addr, ep_in) ) return false;
|
||||
|
||||
return hcd_pipe_xfer(dev_addr, ep_in, p_buffer, length, is_notify);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdch_init(void)
|
||||
{
|
||||
tu_memclr(cdch_data, sizeof(cdch_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
}
|
||||
|
||||
bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
|
||||
{
|
||||
// Only support ACM
|
||||
TU_VERIFY( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass);
|
||||
|
||||
// Only support AT commands, no protocol and vendor specific commands.
|
||||
TU_VERIFY(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
|
||||
0xff == itf_desc->bInterfaceProtocol);
|
||||
|
||||
uint8_t const * p_desc;
|
||||
cdch_data_t * p_cdc;
|
||||
|
||||
p_desc = tu_desc_next(itf_desc);
|
||||
p_cdc = &cdch_data[dev_addr-1];
|
||||
|
||||
p_cdc->itf_num = itf_desc->bInterfaceNumber;
|
||||
p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; // TODO 0xff is consider as rndis candidate, other is virtual Com
|
||||
|
||||
//------------- Communication Interface -------------//
|
||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||
|
||||
// Communication Functional Descriptors
|
||||
while( TUSB_DESC_CS_INTERFACE == p_desc[DESC_OFFSET_TYPE] )
|
||||
{
|
||||
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[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
|
||||
{
|
||||
// notification endpoint
|
||||
tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) p_desc;
|
||||
|
||||
TU_ASSERT( hcd_edpt_open(rhport, dev_addr, ep_desc) );
|
||||
p_cdc->ep_notif = ep_desc->bEndpointAddress;
|
||||
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
//------------- Data Interface (if any) -------------//
|
||||
if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) &&
|
||||
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
|
||||
{
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
|
||||
// data endpoints expected to be in pairs
|
||||
for(uint32_t i=0; i<2; i++)
|
||||
{
|
||||
tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *) p_desc;
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
|
||||
TU_ASSERT(TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
|
||||
|
||||
TU_ASSERT(hcd_edpt_open(rhport, dev_addr, ep_desc));
|
||||
|
||||
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
|
||||
{
|
||||
p_cdc->ep_in = ep_desc->bEndpointAddress;
|
||||
}else
|
||||
{
|
||||
p_cdc->ep_out = ep_desc->bEndpointAddress;
|
||||
}
|
||||
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next( p_desc );
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME move to seperate API : connect
|
||||
tusb_control_request_t request =
|
||||
{
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
|
||||
.wValue = 0x03, // dtr on, cst on
|
||||
.wIndex = p_cdc->itf_num,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
TU_ASSERT( usbh_control_xfer(dev_addr, &request, NULL) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cdch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) ep_addr;
|
||||
tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes );
|
||||
}
|
||||
|
||||
void cdch_close(uint8_t dev_addr)
|
||||
{
|
||||
cdch_data_t * p_cdc = &cdch_data[dev_addr-1];
|
||||
tu_memclr(p_cdc, sizeof(cdch_data_t));
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_CDC)
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "cdc_host.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
uint8_t itf_num;
|
||||
uint8_t itf_protocol;
|
||||
|
||||
uint8_t ep_notif;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
cdc_acm_capability_t acm_capability;
|
||||
|
||||
} cdch_data_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
static cdch_data_t cdch_data[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
|
||||
bool tuh_cdc_mounted(uint8_t dev_addr)
|
||||
{
|
||||
cdch_data_t* cdc = &cdch_data[dev_addr-1];
|
||||
return cdc->ep_in && cdc->ep_out;
|
||||
}
|
||||
|
||||
bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid)
|
||||
{
|
||||
if ( !tuh_cdc_mounted(dev_addr) ) return false;
|
||||
|
||||
cdch_data_t const * p_cdc = &cdch_data[dev_addr-1];
|
||||
|
||||
switch (pipeid)
|
||||
{
|
||||
case CDC_PIPE_NOTIFICATION:
|
||||
return hcd_edpt_busy(dev_addr, p_cdc->ep_notif );
|
||||
|
||||
case CDC_PIPE_DATA_IN:
|
||||
return hcd_edpt_busy(dev_addr, p_cdc->ep_in );
|
||||
|
||||
case CDC_PIPE_DATA_OUT:
|
||||
return hcd_edpt_busy(dev_addr, p_cdc->ep_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 tuh_cdc_mounted(dev_addr) &&
|
||||
(CDC_COMM_PROTOCOL_ATCOMMAND <= cdch_data[dev_addr-1].itf_protocol) &&
|
||||
(cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA);
|
||||
}
|
||||
|
||||
bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify)
|
||||
{
|
||||
TU_VERIFY( tuh_cdc_mounted(dev_addr) );
|
||||
TU_VERIFY( p_data != NULL && length, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
uint8_t const ep_out = cdch_data[dev_addr-1].ep_out;
|
||||
if ( hcd_edpt_busy(dev_addr, ep_out) ) return false;
|
||||
|
||||
return hcd_pipe_xfer(dev_addr, ep_out, (void *) p_data, length, is_notify);
|
||||
}
|
||||
|
||||
bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify)
|
||||
{
|
||||
TU_VERIFY( tuh_cdc_mounted(dev_addr) );
|
||||
TU_VERIFY( p_buffer != NULL && length, TUSB_ERROR_INVALID_PARA);
|
||||
|
||||
uint8_t const ep_in = cdch_data[dev_addr-1].ep_in;
|
||||
if ( hcd_edpt_busy(dev_addr, ep_in) ) return false;
|
||||
|
||||
return hcd_pipe_xfer(dev_addr, ep_in, p_buffer, length, is_notify);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-CLASS DRIVER API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdch_init(void)
|
||||
{
|
||||
tu_memclr(cdch_data, sizeof(cdch_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
}
|
||||
|
||||
bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
|
||||
{
|
||||
// Only support ACM
|
||||
TU_VERIFY( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass);
|
||||
|
||||
// Only support AT commands, no protocol and vendor specific commands.
|
||||
TU_VERIFY(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
|
||||
0xff == itf_desc->bInterfaceProtocol);
|
||||
|
||||
uint8_t const * p_desc;
|
||||
cdch_data_t * p_cdc;
|
||||
|
||||
p_desc = tu_desc_next(itf_desc);
|
||||
p_cdc = &cdch_data[dev_addr-1];
|
||||
|
||||
p_cdc->itf_num = itf_desc->bInterfaceNumber;
|
||||
p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; // TODO 0xff is consider as rndis candidate, other is virtual Com
|
||||
|
||||
//------------- Communication Interface -------------//
|
||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||
|
||||
// Communication Functional Descriptors
|
||||
while( TUSB_DESC_CS_INTERFACE == p_desc[DESC_OFFSET_TYPE] )
|
||||
{
|
||||
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[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
|
||||
{
|
||||
// notification endpoint
|
||||
tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) p_desc;
|
||||
|
||||
TU_ASSERT( hcd_edpt_open(rhport, dev_addr, ep_desc) );
|
||||
p_cdc->ep_notif = ep_desc->bEndpointAddress;
|
||||
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
//------------- Data Interface (if any) -------------//
|
||||
if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) &&
|
||||
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
|
||||
{
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
|
||||
// data endpoints expected to be in pairs
|
||||
for(uint32_t i=0; i<2; i++)
|
||||
{
|
||||
tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *) p_desc;
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
|
||||
TU_ASSERT(TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
|
||||
|
||||
TU_ASSERT(hcd_edpt_open(rhport, dev_addr, ep_desc));
|
||||
|
||||
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
|
||||
{
|
||||
p_cdc->ep_in = ep_desc->bEndpointAddress;
|
||||
}else
|
||||
{
|
||||
p_cdc->ep_out = ep_desc->bEndpointAddress;
|
||||
}
|
||||
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next( p_desc );
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME move to seperate API : connect
|
||||
tusb_control_request_t request =
|
||||
{
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
|
||||
.wValue = 0x03, // dtr on, cst on
|
||||
.wIndex = p_cdc->itf_num,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
TU_ASSERT( usbh_control_xfer(dev_addr, &request, NULL) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cdch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) ep_addr;
|
||||
tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes );
|
||||
}
|
||||
|
||||
void cdch_close(uint8_t dev_addr)
|
||||
{
|
||||
cdch_data_t * p_cdc = &cdch_data[dev_addr-1];
|
||||
tu_memclr(p_cdc, sizeof(cdch_data_t));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,123 +1,123 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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_MEM_SECTION.
|
||||
*/
|
||||
bool 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_MEM_SECTION)
|
||||
* \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_MEM_SECTION.
|
||||
*/
|
||||
bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CDC APPLICATION CALLBACKS
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/** \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 xfer_result_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
|
||||
* - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully.
|
||||
* - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error.
|
||||
* - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device.
|
||||
* \note
|
||||
*/
|
||||
void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes);
|
||||
|
||||
/// @} // group CDC_Serial_Host
|
||||
/// @}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdch_init(void);
|
||||
bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
|
||||
void cdch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void cdch_close(uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CDC_HOST_H_ */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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_MEM_SECTION.
|
||||
*/
|
||||
bool 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_MEM_SECTION)
|
||||
* \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_MEM_SECTION.
|
||||
*/
|
||||
bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CDC APPLICATION CALLBACKS
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/** \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 xfer_result_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
|
||||
* - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully.
|
||||
* - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error.
|
||||
* - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device.
|
||||
* \note
|
||||
*/
|
||||
void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes);
|
||||
|
||||
/// @} // group CDC_Serial_Host
|
||||
/// @}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdch_init(void);
|
||||
bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
|
||||
void cdch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void cdch_close(uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CDC_HOST_H_ */
|
||||
|
1746
src/class/hid/hid.h
1746
src/class/hid/hid.h
File diff suppressed because it is too large
Load Diff
@ -1,315 +1,315 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Driver Default Configure & Validation
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#ifndef CFG_TUD_HID_BUFSIZE
|
||||
#define CFG_TUD_HID_BUFSIZE 16
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Check if the interface is ready to use
|
||||
bool tud_hid_ready(void);
|
||||
|
||||
// Check if current mode is Boot (true) or Report (false)
|
||||
bool tud_hid_boot_mode(void);
|
||||
|
||||
// Send report to host
|
||||
bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len);
|
||||
|
||||
// KEYBOARD: convenient helper to send keyboard report if application
|
||||
// use template layout report as defined by hid_keyboard_report_t
|
||||
bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]);
|
||||
|
||||
// MOUSE: convenient helper to send mouse report if application
|
||||
// use template layout report as defined by hid_mouse_report_t
|
||||
bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Callbacks (Weak is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint8_t const * tud_hid_descriptor_report_cb(void);
|
||||
|
||||
// Invoked when received GET_REPORT control request
|
||||
// Application must fill buffer report's content and return its length.
|
||||
// Return zero will cause the stack to STALL request
|
||||
uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen);
|
||||
|
||||
// Invoked when received SET_REPORT control request or
|
||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||
void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize);
|
||||
|
||||
// Invoked when received SET_PROTOCOL request ( mode switch Boot <-> Report )
|
||||
TU_ATTR_WEAK void tud_hid_boot_mode_cb(uint8_t boot_mode);
|
||||
|
||||
// Invoked when received SET_IDLE request. return false will stall the request
|
||||
// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication
|
||||
// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms).
|
||||
TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t idle_rate);
|
||||
|
||||
/* --------------------------------------------------------------------+
|
||||
* HID Report Descriptor Template
|
||||
*
|
||||
* Convenient for declaring popular HID device (keyboard, mouse, consumer,
|
||||
* gamepad etc...). Templates take "HID_REPORT_ID(n)," as input, leave
|
||||
* empty if multiple reports is not used
|
||||
*
|
||||
* - Only 1 report: no parameter
|
||||
* uint8_t const report_desc[] = { TUD_HID_REPORT_DESC_KEYBOARD() };
|
||||
*
|
||||
* - Multiple Reports: "HID_REPORT_ID(ID)," must be passed to template
|
||||
* uint8_t const report_desc[] =
|
||||
* {
|
||||
* TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1), ) ,
|
||||
* TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(2), )
|
||||
* };
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
// Keyboard Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_KEYBOARD(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_KEYBOARD ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
/* 8 bits Modifier Keys (Shfit, Control, Alt) */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\
|
||||
HID_USAGE_MIN ( 224 ) ,\
|
||||
HID_USAGE_MAX ( 231 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
HID_REPORT_COUNT ( 8 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* 8 bit reserved */ \
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_CONSTANT ) ,\
|
||||
/* 6-byte Keycodes */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\
|
||||
HID_USAGE_MIN ( 0 ) ,\
|
||||
HID_USAGE_MAX ( 255 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 255 ) ,\
|
||||
HID_REPORT_COUNT ( 6 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
|
||||
/* 5-bit LED Indicator Kana | Compose | ScrollLock | CapsLock | NumLock */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_LED ) ,\
|
||||
HID_USAGE_MIN ( 1 ) ,\
|
||||
HID_USAGE_MAX ( 5 ) ,\
|
||||
HID_REPORT_COUNT ( 5 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* led padding */ \
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 3 ) ,\
|
||||
HID_OUTPUT ( HID_CONSTANT ) ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// Mouse Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_MOUSE(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||
HID_USAGE_MIN ( 1 ) ,\
|
||||
HID_USAGE_MAX ( 5 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
/* Left, Right, Middle, Backward, Forward buttons */ \
|
||||
HID_REPORT_COUNT( 5 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* 3 bit padding */ \
|
||||
HID_REPORT_COUNT( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 3 ) ,\
|
||||
HID_INPUT ( HID_CONSTANT ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
/* X, Y position [-127, 127] */ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
|
||||
HID_LOGICAL_MIN ( 0x81 ) ,\
|
||||
HID_LOGICAL_MAX ( 0x7f ) ,\
|
||||
HID_REPORT_COUNT( 2 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
|
||||
/* Verital wheel scroll [-127, 127] */ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\
|
||||
HID_LOGICAL_MIN ( 0x81 ) ,\
|
||||
HID_LOGICAL_MAX ( 0x7f ) ,\
|
||||
HID_REPORT_COUNT( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \
|
||||
/* Horizontal wheel scroll [-127, 127] */ \
|
||||
HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \
|
||||
HID_LOGICAL_MIN ( 0x81 ), \
|
||||
HID_LOGICAL_MAX ( 0x7f ), \
|
||||
HID_REPORT_COUNT( 1 ), \
|
||||
HID_REPORT_SIZE ( 8 ), \
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \
|
||||
HID_COLLECTION_END , \
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// Consumer Control Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_CONSUMER(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\
|
||||
HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
HID_LOGICAL_MIN ( 0x00 ) ,\
|
||||
HID_LOGICAL_MAX_N( 0x03FF, 2 ) ,\
|
||||
HID_USAGE_MIN ( 0x00 ) ,\
|
||||
HID_USAGE_MAX_N ( 0x03FF, 2 ) ,\
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 16 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
/* System Control Report Descriptor Template
|
||||
* 0x00 - do nothing
|
||||
* 0x01 - Power Off
|
||||
* 0x02 - Standby
|
||||
* 0x04 - Wake Host
|
||||
*/
|
||||
#define TUD_HID_REPORT_DESC_SYSTEM_CONTROL(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_CONTROL ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
/* 2 bit system power control */ \
|
||||
HID_LOGICAL_MIN ( 1 ) ,\
|
||||
HID_LOGICAL_MAX ( 3 ) ,\
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 2 ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_SLEEP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_WAKE_UP ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
|
||||
/* 6 bit padding */ \
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 6 ) ,\
|
||||
HID_INPUT ( HID_CONSTANT ) ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// Gamepad Report Descriptor Template
|
||||
// with 16 buttons and 2 joysticks with following layout
|
||||
// | Button Map (2 bytes) | X | Y | Z | Rz
|
||||
#define TUD_HID_REPORT_DESC_GAMEPAD(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
/* 16 bit Button Map */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||
HID_USAGE_MIN ( 1 ) ,\
|
||||
HID_USAGE_MAX ( 16 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
HID_REPORT_COUNT ( 16 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
|
||||
/* X, Y, Z, Rz (min -127, max 127 ) */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_LOGICAL_MIN ( 0x81 ) ,\
|
||||
HID_LOGICAL_MAX ( 0x7f ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\
|
||||
HID_REPORT_COUNT ( 4 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// HID Generic Input & Output
|
||||
// - 1st parameter is report size (mandatory)
|
||||
// - 2nd parameter is report id HID_REPORT_ID(n) (optional)
|
||||
#define TUD_HID_REPORT_DESC_GENERIC_INOUT(report_size, ...) \
|
||||
HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ),\
|
||||
HID_USAGE ( 0x01 ),\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
/* Input */ \
|
||||
HID_USAGE ( 0x02 ),\
|
||||
HID_LOGICAL_MIN ( 0x00 ),\
|
||||
HID_LOGICAL_MAX ( 0xff ),\
|
||||
HID_REPORT_SIZE ( 8 ),\
|
||||
HID_REPORT_COUNT( report_size ),\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
|
||||
/* Output */ \
|
||||
HID_USAGE ( 0x03 ),\
|
||||
HID_LOGICAL_MIN ( 0x00 ),\
|
||||
HID_LOGICAL_MAX ( 0xff ),\
|
||||
HID_REPORT_SIZE ( 8 ),\
|
||||
HID_REPORT_COUNT( report_size ),\
|
||||
HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void hidd_init (void);
|
||||
void hidd_reset (uint8_t rhport);
|
||||
bool hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
|
||||
bool hidd_control_request (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool hidd_control_complete (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HID_DEVICE_H_ */
|
||||
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Driver Default Configure & Validation
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#ifndef CFG_TUD_HID_BUFSIZE
|
||||
#define CFG_TUD_HID_BUFSIZE 16
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Check if the interface is ready to use
|
||||
bool tud_hid_ready(void);
|
||||
|
||||
// Check if current mode is Boot (true) or Report (false)
|
||||
bool tud_hid_boot_mode(void);
|
||||
|
||||
// Send report to host
|
||||
bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len);
|
||||
|
||||
// KEYBOARD: convenient helper to send keyboard report if application
|
||||
// use template layout report as defined by hid_keyboard_report_t
|
||||
bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]);
|
||||
|
||||
// MOUSE: convenient helper to send mouse report if application
|
||||
// use template layout report as defined by hid_mouse_report_t
|
||||
bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Callbacks (Weak is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint8_t const * tud_hid_descriptor_report_cb(void);
|
||||
|
||||
// Invoked when received GET_REPORT control request
|
||||
// Application must fill buffer report's content and return its length.
|
||||
// Return zero will cause the stack to STALL request
|
||||
uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen);
|
||||
|
||||
// Invoked when received SET_REPORT control request or
|
||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||
void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize);
|
||||
|
||||
// Invoked when received SET_PROTOCOL request ( mode switch Boot <-> Report )
|
||||
TU_ATTR_WEAK void tud_hid_boot_mode_cb(uint8_t boot_mode);
|
||||
|
||||
// Invoked when received SET_IDLE request. return false will stall the request
|
||||
// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication
|
||||
// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms).
|
||||
TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t idle_rate);
|
||||
|
||||
/* --------------------------------------------------------------------+
|
||||
* HID Report Descriptor Template
|
||||
*
|
||||
* Convenient for declaring popular HID device (keyboard, mouse, consumer,
|
||||
* gamepad etc...). Templates take "HID_REPORT_ID(n)," as input, leave
|
||||
* empty if multiple reports is not used
|
||||
*
|
||||
* - Only 1 report: no parameter
|
||||
* uint8_t const report_desc[] = { TUD_HID_REPORT_DESC_KEYBOARD() };
|
||||
*
|
||||
* - Multiple Reports: "HID_REPORT_ID(ID)," must be passed to template
|
||||
* uint8_t const report_desc[] =
|
||||
* {
|
||||
* TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1), ) ,
|
||||
* TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(2), )
|
||||
* };
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
// Keyboard Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_KEYBOARD(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_KEYBOARD ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
/* 8 bits Modifier Keys (Shfit, Control, Alt) */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\
|
||||
HID_USAGE_MIN ( 224 ) ,\
|
||||
HID_USAGE_MAX ( 231 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
HID_REPORT_COUNT ( 8 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* 8 bit reserved */ \
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_CONSTANT ) ,\
|
||||
/* 6-byte Keycodes */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\
|
||||
HID_USAGE_MIN ( 0 ) ,\
|
||||
HID_USAGE_MAX ( 255 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 255 ) ,\
|
||||
HID_REPORT_COUNT ( 6 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
|
||||
/* 5-bit LED Indicator Kana | Compose | ScrollLock | CapsLock | NumLock */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_LED ) ,\
|
||||
HID_USAGE_MIN ( 1 ) ,\
|
||||
HID_USAGE_MAX ( 5 ) ,\
|
||||
HID_REPORT_COUNT ( 5 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* led padding */ \
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 3 ) ,\
|
||||
HID_OUTPUT ( HID_CONSTANT ) ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// Mouse Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_MOUSE(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||
HID_USAGE_MIN ( 1 ) ,\
|
||||
HID_USAGE_MAX ( 5 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
/* Left, Right, Middle, Backward, Forward buttons */ \
|
||||
HID_REPORT_COUNT( 5 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* 3 bit padding */ \
|
||||
HID_REPORT_COUNT( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 3 ) ,\
|
||||
HID_INPUT ( HID_CONSTANT ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
/* X, Y position [-127, 127] */ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
|
||||
HID_LOGICAL_MIN ( 0x81 ) ,\
|
||||
HID_LOGICAL_MAX ( 0x7f ) ,\
|
||||
HID_REPORT_COUNT( 2 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
|
||||
/* Verital wheel scroll [-127, 127] */ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\
|
||||
HID_LOGICAL_MIN ( 0x81 ) ,\
|
||||
HID_LOGICAL_MAX ( 0x7f ) ,\
|
||||
HID_REPORT_COUNT( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \
|
||||
/* Horizontal wheel scroll [-127, 127] */ \
|
||||
HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \
|
||||
HID_LOGICAL_MIN ( 0x81 ), \
|
||||
HID_LOGICAL_MAX ( 0x7f ), \
|
||||
HID_REPORT_COUNT( 1 ), \
|
||||
HID_REPORT_SIZE ( 8 ), \
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \
|
||||
HID_COLLECTION_END , \
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// Consumer Control Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_CONSUMER(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\
|
||||
HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
HID_LOGICAL_MIN ( 0x00 ) ,\
|
||||
HID_LOGICAL_MAX_N( 0x03FF, 2 ) ,\
|
||||
HID_USAGE_MIN ( 0x00 ) ,\
|
||||
HID_USAGE_MAX_N ( 0x03FF, 2 ) ,\
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 16 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
/* System Control Report Descriptor Template
|
||||
* 0x00 - do nothing
|
||||
* 0x01 - Power Off
|
||||
* 0x02 - Standby
|
||||
* 0x04 - Wake Host
|
||||
*/
|
||||
#define TUD_HID_REPORT_DESC_SYSTEM_CONTROL(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_CONTROL ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
/* 2 bit system power control */ \
|
||||
HID_LOGICAL_MIN ( 1 ) ,\
|
||||
HID_LOGICAL_MAX ( 3 ) ,\
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 2 ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_SLEEP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_WAKE_UP ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
|
||||
/* 6 bit padding */ \
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 6 ) ,\
|
||||
HID_INPUT ( HID_CONSTANT ) ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// Gamepad Report Descriptor Template
|
||||
// with 16 buttons and 2 joysticks with following layout
|
||||
// | Button Map (2 bytes) | X | Y | Z | Rz
|
||||
#define TUD_HID_REPORT_DESC_GAMEPAD(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
/* 16 bit Button Map */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||
HID_USAGE_MIN ( 1 ) ,\
|
||||
HID_USAGE_MAX ( 16 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
HID_REPORT_COUNT ( 16 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
|
||||
/* X, Y, Z, Rz (min -127, max 127 ) */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_LOGICAL_MIN ( 0x81 ) ,\
|
||||
HID_LOGICAL_MAX ( 0x7f ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\
|
||||
HID_REPORT_COUNT ( 4 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// HID Generic Input & Output
|
||||
// - 1st parameter is report size (mandatory)
|
||||
// - 2nd parameter is report id HID_REPORT_ID(n) (optional)
|
||||
#define TUD_HID_REPORT_DESC_GENERIC_INOUT(report_size, ...) \
|
||||
HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ),\
|
||||
HID_USAGE ( 0x01 ),\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
/* Input */ \
|
||||
HID_USAGE ( 0x02 ),\
|
||||
HID_LOGICAL_MIN ( 0x00 ),\
|
||||
HID_LOGICAL_MAX ( 0xff ),\
|
||||
HID_REPORT_SIZE ( 8 ),\
|
||||
HID_REPORT_COUNT( report_size ),\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
|
||||
/* Output */ \
|
||||
HID_USAGE ( 0x03 ),\
|
||||
HID_LOGICAL_MIN ( 0x00 ),\
|
||||
HID_LOGICAL_MAX ( 0xff ),\
|
||||
HID_REPORT_SIZE ( 8 ),\
|
||||
HID_REPORT_COUNT( report_size ),\
|
||||
HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void hidd_init (void);
|
||||
void hidd_reset (uint8_t rhport);
|
||||
bool hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
|
||||
bool hidd_control_request (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool hidd_control_complete (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HID_DEVICE_H_ */
|
||||
|
||||
|
@ -1,289 +1,289 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (TUSB_OPT_HOST_ENABLED && HOST_CLASS_HID)
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "hid_host.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HID Interface common functions
|
||||
//--------------------------------------------------------------------+
|
||||
static inline bool 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_edpt_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));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void hidh_interface_close(hidh_interface_info_t *p_hid)
|
||||
{
|
||||
tu_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);
|
||||
TU_VERIFY (report, TUSB_ERROR_INVALID_PARA);
|
||||
TU_ASSERT (!hcd_edpt_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_TUH_HID_KEYBOARD
|
||||
|
||||
#if 0
|
||||
#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)
|
||||
};
|
||||
#endif
|
||||
|
||||
static 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_edpt_busy( keyboardh_data[dev_addr-1].pipe_hdl );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MOUSE
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUH_HID_MOUSE
|
||||
|
||||
static 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_edpt_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_TUH_HID_KEYBOARD
|
||||
tu_memclr(&keyboardh_data, sizeof(hidh_interface_info_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_HID_MOUSE
|
||||
tu_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_MEM_SECTION uint8_t report_descriptor[256];
|
||||
#endif
|
||||
|
||||
bool hidh_open_subtask(uint8_t dev_addr, 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[DESC_OFFSET_LEN];
|
||||
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[DESC_OFFSET_LEN];
|
||||
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);
|
||||
|
||||
//------------- SET IDLE (0) request -------------//
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = HID_REQ_CONTROL_SET_IDLE,
|
||||
.wValue = 0, // idle_rate = 0
|
||||
.wIndex = p_interface_desc->bInterfaceNumber,
|
||||
.wLength = 0
|
||||
};
|
||||
TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) );
|
||||
|
||||
#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_TUH_HID_KEYBOARD
|
||||
if ( HID_PROTOCOL_KEYBOARD == p_interface_desc->bInterfaceProtocol)
|
||||
{
|
||||
TU_ASSERT( 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_TUH_HID_MOUSE
|
||||
if ( HID_PROTOCOL_MOUSE == p_interface_desc->bInterfaceProtocol)
|
||||
{
|
||||
TU_ASSERT ( 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
|
||||
|
||||
{
|
||||
// Not supported protocol
|
||||
return false;
|
||||
}
|
||||
}else
|
||||
{
|
||||
// Not supported subclass
|
||||
return false;
|
||||
}
|
||||
|
||||
*p_length = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void hidh_isr(pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) xferred_bytes; // TODO may need to use this para later
|
||||
|
||||
#if CFG_TUH_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_TUH_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_TUH_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_TUH_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
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (TUSB_OPT_HOST_ENABLED && HOST_CLASS_HID)
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "hid_host.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HID Interface common functions
|
||||
//--------------------------------------------------------------------+
|
||||
static inline bool 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_edpt_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));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void hidh_interface_close(hidh_interface_info_t *p_hid)
|
||||
{
|
||||
tu_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);
|
||||
TU_VERIFY (report, TUSB_ERROR_INVALID_PARA);
|
||||
TU_ASSERT (!hcd_edpt_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_TUH_HID_KEYBOARD
|
||||
|
||||
#if 0
|
||||
#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)
|
||||
};
|
||||
#endif
|
||||
|
||||
static 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_edpt_busy( keyboardh_data[dev_addr-1].pipe_hdl );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MOUSE
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUH_HID_MOUSE
|
||||
|
||||
static 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_edpt_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_TUH_HID_KEYBOARD
|
||||
tu_memclr(&keyboardh_data, sizeof(hidh_interface_info_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_HID_MOUSE
|
||||
tu_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_MEM_SECTION uint8_t report_descriptor[256];
|
||||
#endif
|
||||
|
||||
bool hidh_open_subtask(uint8_t dev_addr, 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[DESC_OFFSET_LEN];
|
||||
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[DESC_OFFSET_LEN];
|
||||
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);
|
||||
|
||||
//------------- SET IDLE (0) request -------------//
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = HID_REQ_CONTROL_SET_IDLE,
|
||||
.wValue = 0, // idle_rate = 0
|
||||
.wIndex = p_interface_desc->bInterfaceNumber,
|
||||
.wLength = 0
|
||||
};
|
||||
TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) );
|
||||
|
||||
#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_TUH_HID_KEYBOARD
|
||||
if ( HID_PROTOCOL_KEYBOARD == p_interface_desc->bInterfaceProtocol)
|
||||
{
|
||||
TU_ASSERT( 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_TUH_HID_MOUSE
|
||||
if ( HID_PROTOCOL_MOUSE == p_interface_desc->bInterfaceProtocol)
|
||||
{
|
||||
TU_ASSERT ( 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
|
||||
|
||||
{
|
||||
// Not supported protocol
|
||||
return false;
|
||||
}
|
||||
}else
|
||||
{
|
||||
// Not supported subclass
|
||||
return false;
|
||||
}
|
||||
|
||||
*p_length = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void hidh_isr(pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) xferred_bytes; // TODO may need to use this para later
|
||||
|
||||
#if CFG_TUH_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_TUH_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_TUH_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_TUH_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
|
||||
|
@ -1,215 +1,215 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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);
|
||||
|
||||
//------------- 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 xfer_result_t
|
||||
* \note event can be one of following
|
||||
* - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully.
|
||||
* - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error.
|
||||
* - XFER_RESULT_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, xfer_result_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);
|
||||
|
||||
/** \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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);
|
||||
|
||||
//------------- 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 xfer_result_t
|
||||
* \note event can be one of following
|
||||
* - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully.
|
||||
* - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error.
|
||||
* - XFER_RESULT_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, xfer_result_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);
|
||||
tusb_error_t tuh_hid_generic_get_report(uint8_t dev_addr, void* p_report, bool int_on_complete);
|
||||
tusb_error_t tuh_hid_generic_set_report(uint8_t dev_addr, void* p_report, bool int_on_complete);
|
||||
tusb_interface_status_t tuh_hid_generic_get_status(uint8_t dev_addr);
|
||||
tusb_interface_status_t tuh_hid_generic_set_status(uint8_t dev_addr);
|
||||
|
||||
//------------- Application Callback -------------//
|
||||
void tuh_hid_generic_isr(uint8_t dev_addr, xfer_result_t event);
|
||||
|
||||
/** @} */ // Generic_Host
|
||||
/** @} */ // ClassDriver_HID_Generic
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
pipe_handle_t pipe_hdl;
|
||||
uint16_t report_size;
|
||||
uint8_t interface_number;
|
||||
}hidh_interface_info_t;
|
||||
|
||||
void hidh_init(void);
|
||||
bool hidh_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length);
|
||||
void hidh_isr(pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void hidh_close(uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HID_HOST_H_ */
|
||||
|
||||
/** @} */ // ClassDriver_HID
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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);
|
||||
|
||||
//------------- 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 xfer_result_t
|
||||
* \note event can be one of following
|
||||
* - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully.
|
||||
* - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error.
|
||||
* - XFER_RESULT_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, xfer_result_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);
|
||||
|
||||
/** \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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);
|
||||
|
||||
//------------- 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 xfer_result_t
|
||||
* \note event can be one of following
|
||||
* - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully.
|
||||
* - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error.
|
||||
* - XFER_RESULT_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, xfer_result_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);
|
||||
tusb_error_t tuh_hid_generic_get_report(uint8_t dev_addr, void* p_report, bool int_on_complete);
|
||||
tusb_error_t tuh_hid_generic_set_report(uint8_t dev_addr, void* p_report, bool int_on_complete);
|
||||
tusb_interface_status_t tuh_hid_generic_get_status(uint8_t dev_addr);
|
||||
tusb_interface_status_t tuh_hid_generic_set_status(uint8_t dev_addr);
|
||||
|
||||
//------------- Application Callback -------------//
|
||||
void tuh_hid_generic_isr(uint8_t dev_addr, xfer_result_t event);
|
||||
|
||||
/** @} */ // Generic_Host
|
||||
/** @} */ // ClassDriver_HID_Generic
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
pipe_handle_t pipe_hdl;
|
||||
uint16_t report_size;
|
||||
uint8_t interface_number;
|
||||
}hidh_interface_info_t;
|
||||
|
||||
void hidh_init(void);
|
||||
bool hidh_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length);
|
||||
void hidh_isr(pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void hidh_close(uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HID_HOST_H_ */
|
||||
|
||||
/** @} */ // ClassDriver_HID
|
||||
|
@ -1,167 +1,167 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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_MIDI_H__
|
||||
#define _TUSB_MIDI_H__
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Specific Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MIDI_CS_INTERFACE_HEADER = 0x01,
|
||||
MIDI_CS_INTERFACE_IN_JACK = 0x02,
|
||||
MIDI_CS_INTERFACE_OUT_JACK = 0x03,
|
||||
MIDI_CS_INTERFACE_ELEMENT = 0x04,
|
||||
} midi_cs_interface_subtype_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MIDI_CS_ENDPOINT_GENERAL = 0x01
|
||||
} midi_cs_endpoint_subtype_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MIDI_JACK_EMBEDDED = 0x01,
|
||||
MIDI_JACK_EXTERNAL = 0x02
|
||||
} midi_jack_type_t;
|
||||
|
||||
/// MIDI Interface Header Descriptor
|
||||
typedef struct TU_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
|
||||
uint16_t bcdMSC ; ///< MidiStreaming SubClass release number in Binary-Coded Decimal
|
||||
uint16_t wTotalLength ;
|
||||
} midi_desc_header_t;
|
||||
|
||||
/// MIDI In Jack Descriptor
|
||||
typedef struct TU_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
|
||||
uint8_t bJackType ; ///< Embedded or External
|
||||
uint8_t bJackID ; ///< Unique ID for MIDI IN Jack
|
||||
uint8_t iJack ; ///< string descriptor
|
||||
} midi_desc_in_jack_t;
|
||||
|
||||
|
||||
/// MIDI Out Jack Descriptor with single pin
|
||||
typedef struct TU_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
|
||||
uint8_t bJackType ; ///< Embedded or External
|
||||
uint8_t bJackID ; ///< Unique ID for MIDI IN Jack
|
||||
uint8_t bNrInputPins;
|
||||
|
||||
uint8_t baSourceID;
|
||||
uint8_t baSourcePin;
|
||||
|
||||
uint8_t iJack ; ///< string descriptor
|
||||
} midi_desc_out_jack_t ;
|
||||
|
||||
/// MIDI Out Jack Descriptor with multiple pins
|
||||
#define midi_desc_out_jack_n_t(input_num) \
|
||||
struct TU_ATTR_PACKED { \
|
||||
uint8_t bLength ; \
|
||||
uint8_t bDescriptorType ; \
|
||||
uint8_t bDescriptorSubType ; \
|
||||
uint8_t bJackType ; \
|
||||
uint8_t bJackID ; \
|
||||
uint8_t bNrInputPins ; \
|
||||
struct TU_ATTR_PACKED { \
|
||||
uint8_t baSourceID; \
|
||||
uint8_t baSourcePin; \
|
||||
} pins[input_num]; \
|
||||
uint8_t iJack ; \
|
||||
}
|
||||
|
||||
/// MIDI Element Descriptor
|
||||
typedef struct TU_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
|
||||
uint8_t bElementID;
|
||||
|
||||
uint8_t bNrInputPins;
|
||||
uint8_t baSourceID;
|
||||
uint8_t baSourcePin;
|
||||
|
||||
uint8_t bNrOutputPins;
|
||||
uint8_t bInTerminalLink;
|
||||
uint8_t bOutTerminalLink;
|
||||
uint8_t bElCapsSize;
|
||||
|
||||
uint16_t bmElementCaps;
|
||||
uint8_t iElement;
|
||||
} midi_desc_element_t;
|
||||
|
||||
/// MIDI Element Descriptor with multiple pins
|
||||
#define midi_desc_element_n_t(input_num) \
|
||||
struct TU_ATTR_PACKED { \
|
||||
uint8_t bLength; \
|
||||
uint8_t bDescriptorType; \
|
||||
uint8_t bDescriptorSubType; \
|
||||
uint8_t bElementID; \
|
||||
uint8_t bNrInputPins; \
|
||||
struct TU_ATTR_PACKED { \
|
||||
uint8_t baSourceID; \
|
||||
uint8_t baSourcePin; \
|
||||
} pins[input_num]; \
|
||||
uint8_t bNrOutputPins; \
|
||||
uint8_t bInTerminalLink; \
|
||||
uint8_t bOutTerminalLink; \
|
||||
uint8_t bElCapsSize; \
|
||||
uint16_t bmElementCaps; \
|
||||
uint8_t iElement; \
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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_MIDI_H__
|
||||
#define _TUSB_MIDI_H__
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Specific Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MIDI_CS_INTERFACE_HEADER = 0x01,
|
||||
MIDI_CS_INTERFACE_IN_JACK = 0x02,
|
||||
MIDI_CS_INTERFACE_OUT_JACK = 0x03,
|
||||
MIDI_CS_INTERFACE_ELEMENT = 0x04,
|
||||
} midi_cs_interface_subtype_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MIDI_CS_ENDPOINT_GENERAL = 0x01
|
||||
} midi_cs_endpoint_subtype_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MIDI_JACK_EMBEDDED = 0x01,
|
||||
MIDI_JACK_EXTERNAL = 0x02
|
||||
} midi_jack_type_t;
|
||||
|
||||
/// MIDI Interface Header Descriptor
|
||||
typedef struct TU_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
|
||||
uint16_t bcdMSC ; ///< MidiStreaming SubClass release number in Binary-Coded Decimal
|
||||
uint16_t wTotalLength ;
|
||||
} midi_desc_header_t;
|
||||
|
||||
/// MIDI In Jack Descriptor
|
||||
typedef struct TU_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
|
||||
uint8_t bJackType ; ///< Embedded or External
|
||||
uint8_t bJackID ; ///< Unique ID for MIDI IN Jack
|
||||
uint8_t iJack ; ///< string descriptor
|
||||
} midi_desc_in_jack_t;
|
||||
|
||||
|
||||
/// MIDI Out Jack Descriptor with single pin
|
||||
typedef struct TU_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
|
||||
uint8_t bJackType ; ///< Embedded or External
|
||||
uint8_t bJackID ; ///< Unique ID for MIDI IN Jack
|
||||
uint8_t bNrInputPins;
|
||||
|
||||
uint8_t baSourceID;
|
||||
uint8_t baSourcePin;
|
||||
|
||||
uint8_t iJack ; ///< string descriptor
|
||||
} midi_desc_out_jack_t ;
|
||||
|
||||
/// MIDI Out Jack Descriptor with multiple pins
|
||||
#define midi_desc_out_jack_n_t(input_num) \
|
||||
struct TU_ATTR_PACKED { \
|
||||
uint8_t bLength ; \
|
||||
uint8_t bDescriptorType ; \
|
||||
uint8_t bDescriptorSubType ; \
|
||||
uint8_t bJackType ; \
|
||||
uint8_t bJackID ; \
|
||||
uint8_t bNrInputPins ; \
|
||||
struct TU_ATTR_PACKED { \
|
||||
uint8_t baSourceID; \
|
||||
uint8_t baSourcePin; \
|
||||
} pins[input_num]; \
|
||||
uint8_t iJack ; \
|
||||
}
|
||||
|
||||
/// MIDI Element Descriptor
|
||||
typedef struct TU_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
|
||||
uint8_t bElementID;
|
||||
|
||||
uint8_t bNrInputPins;
|
||||
uint8_t baSourceID;
|
||||
uint8_t baSourcePin;
|
||||
|
||||
uint8_t bNrOutputPins;
|
||||
uint8_t bInTerminalLink;
|
||||
uint8_t bOutTerminalLink;
|
||||
uint8_t bElCapsSize;
|
||||
|
||||
uint16_t bmElementCaps;
|
||||
uint8_t iElement;
|
||||
} midi_desc_element_t;
|
||||
|
||||
/// MIDI Element Descriptor with multiple pins
|
||||
#define midi_desc_element_n_t(input_num) \
|
||||
struct TU_ATTR_PACKED { \
|
||||
uint8_t bLength; \
|
||||
uint8_t bDescriptorType; \
|
||||
uint8_t bDescriptorSubType; \
|
||||
uint8_t bElementID; \
|
||||
uint8_t bNrInputPins; \
|
||||
struct TU_ATTR_PACKED { \
|
||||
uint8_t baSourceID; \
|
||||
uint8_t baSourcePin; \
|
||||
} pins[input_num]; \
|
||||
uint8_t bNrOutputPins; \
|
||||
uint8_t bInTerminalLink; \
|
||||
uint8_t bOutTerminalLink; \
|
||||
uint8_t bElCapsSize; \
|
||||
uint16_t bmElementCaps; \
|
||||
uint8_t iElement; \
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
@ -1,361 +1,361 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_MIDI)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "midi_device.h"
|
||||
#include "class/audio/audio.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||
// FIFO
|
||||
tu_fifo_t rx_ff;
|
||||
tu_fifo_t tx_ff;
|
||||
uint8_t rx_ff_buf[CFG_TUD_MIDI_RX_BUFSIZE];
|
||||
uint8_t tx_ff_buf[CFG_TUD_MIDI_TX_BUFSIZE];
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t rx_ff_mutex;
|
||||
osal_mutex_def_t tx_ff_mutex;
|
||||
#endif
|
||||
|
||||
// We need to pack messages into words before queueing their transmission so buffer across write
|
||||
// calls.
|
||||
uint8_t message_buffer[4];
|
||||
uint8_t message_buffer_length;
|
||||
uint8_t message_target_length;
|
||||
|
||||
// Endpoint Transfer buffer
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EPSIZE];
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_MIDI_EPSIZE];
|
||||
|
||||
} midid_interface_t;
|
||||
|
||||
#define ITF_MEM_RESET_SIZE offsetof(midid_interface_t, rx_ff)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI];
|
||||
|
||||
bool tud_midi_n_mounted (uint8_t itf)
|
||||
{
|
||||
midid_interface_t* midi = &_midid_itf[itf];
|
||||
return midi->ep_in && midi->ep_out;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// READ API
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t tud_midi_n_available(uint8_t itf, uint8_t jack_id)
|
||||
{
|
||||
(void) jack_id;
|
||||
return tu_fifo_count(&_midid_itf[itf].rx_ff);
|
||||
}
|
||||
|
||||
uint32_t tud_midi_n_read(uint8_t itf, uint8_t jack_id, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
(void) jack_id;
|
||||
return tu_fifo_read_n(&_midid_itf[itf].rx_ff, buffer, bufsize);
|
||||
}
|
||||
|
||||
void tud_midi_n_read_flush (uint8_t itf, uint8_t jack_id)
|
||||
{
|
||||
(void) jack_id;
|
||||
tu_fifo_clear(&_midid_itf[itf].rx_ff);
|
||||
}
|
||||
|
||||
void midi_rx_done_cb(midid_interface_t* midi, uint8_t const* buffer, uint32_t bufsize) {
|
||||
if (bufsize % 4 != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(uint32_t i=0; i<bufsize; i += 4) {
|
||||
uint8_t header = buffer[i];
|
||||
// uint8_t cable_number = (header & 0xf0) >> 4;
|
||||
uint8_t code_index = header & 0x0f;
|
||||
// We always copy over the first byte.
|
||||
uint8_t count = 1;
|
||||
// Ignore subsequent bytes based on the code.
|
||||
if (code_index != 0x5 && code_index != 0xf) {
|
||||
count = 2;
|
||||
if (code_index != 0x2 && code_index != 0x6 && code_index != 0xc && code_index != 0xd) {
|
||||
count = 3;
|
||||
}
|
||||
}
|
||||
tu_fifo_write_n(&midi->rx_ff, &buffer[i + 1], count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// WRITE API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static bool maybe_transmit(midid_interface_t* midi, uint8_t itf_index)
|
||||
{
|
||||
(void) itf_index;
|
||||
|
||||
// skip if previous transfer not complete
|
||||
TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, midi->ep_in) );
|
||||
|
||||
uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epin_buf, CFG_TUD_MIDI_EPSIZE);
|
||||
if (count > 0)
|
||||
{
|
||||
TU_ASSERT( usbd_edpt_xfer(TUD_OPT_RHPORT, midi->ep_in, midi->epin_buf, count) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t tud_midi_n_write(uint8_t itf, uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize)
|
||||
{
|
||||
midid_interface_t* midi = &_midid_itf[itf];
|
||||
if (midi->itf_num == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t i = 0;
|
||||
while (i < bufsize) {
|
||||
uint8_t data = buffer[i];
|
||||
if (midi->message_buffer_length == 0) {
|
||||
uint8_t msg = data >> 4;
|
||||
midi->message_buffer[1] = data;
|
||||
midi->message_buffer_length = 2;
|
||||
// Check to see if we're still in a SysEx transmit.
|
||||
if (midi->message_buffer[0] == 0x4) {
|
||||
if (data == 0xf7) {
|
||||
midi->message_buffer[0] = 0x5;
|
||||
} else {
|
||||
midi->message_buffer_length = 4;
|
||||
}
|
||||
} else if ((msg >= 0x8 && msg <= 0xB) || msg == 0xE) {
|
||||
midi->message_buffer[0] = jack_id << 4 | msg;
|
||||
midi->message_target_length = 4;
|
||||
} else if (msg == 0xC || msg == 0xD) {
|
||||
midi->message_buffer[0] = jack_id << 4 | msg;
|
||||
midi->message_target_length = 3;
|
||||
} else if (msg == 0xf) {
|
||||
if (data == 0xf0) {
|
||||
midi->message_buffer[0] = 0x4;
|
||||
midi->message_target_length = 4;
|
||||
} else if (data == 0xf1 || data == 0xf3) {
|
||||
midi->message_buffer[0] = 0x2;
|
||||
midi->message_target_length = 3;
|
||||
} else if (data == 0xf2) {
|
||||
midi->message_buffer[0] = 0x3;
|
||||
midi->message_target_length = 4;
|
||||
} else {
|
||||
midi->message_buffer[0] = 0x5;
|
||||
midi->message_target_length = 2;
|
||||
}
|
||||
} else {
|
||||
// Pack individual bytes if we don't support packing them into words.
|
||||
midi->message_buffer[0] = jack_id << 4 | 0xf;
|
||||
midi->message_buffer[2] = 0;
|
||||
midi->message_buffer[3] = 0;
|
||||
midi->message_buffer_length = 2;
|
||||
midi->message_target_length = 2;
|
||||
}
|
||||
} else {
|
||||
midi->message_buffer[midi->message_buffer_length] = data;
|
||||
midi->message_buffer_length += 1;
|
||||
// See if this byte ends a SysEx.
|
||||
if (midi->message_buffer[0] == 0x4 && data == 0xf7) {
|
||||
midi->message_buffer[0] = 0x4 + (midi->message_buffer_length - 1);
|
||||
midi->message_target_length = midi->message_buffer_length;
|
||||
}
|
||||
}
|
||||
|
||||
if (midi->message_buffer_length == midi->message_target_length) {
|
||||
uint16_t written = tu_fifo_write_n(&midi->tx_ff, midi->message_buffer, 4);
|
||||
if (written < 4) {
|
||||
TU_ASSERT( written == 0 );
|
||||
break;
|
||||
}
|
||||
midi->message_buffer_length = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
maybe_transmit(midi, itf);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void midid_init(void)
|
||||
{
|
||||
tu_memclr(_midid_itf, sizeof(_midid_itf));
|
||||
|
||||
for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
|
||||
{
|
||||
midid_interface_t* midi = &_midid_itf[i];
|
||||
|
||||
// config fifo
|
||||
tu_fifo_config(&midi->rx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, true);
|
||||
tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, true);
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
tu_fifo_config_mutex(&midi->rx_ff, osal_mutex_create(&midi->rx_ff_mutex));
|
||||
tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void midid_reset(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
|
||||
{
|
||||
midid_interface_t* midi = &_midid_itf[i];
|
||||
tu_memclr(midi, ITF_MEM_RESET_SIZE);
|
||||
tu_fifo_clear(&midi->rx_ff);
|
||||
tu_fifo_clear(&midi->tx_ff);
|
||||
}
|
||||
}
|
||||
|
||||
bool midid_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length)
|
||||
{
|
||||
// For now handle the audio control interface as well.
|
||||
if ( AUDIO_SUBCLASS_CONTROL == p_interface_desc->bInterfaceSubClass) {
|
||||
uint8_t const * p_desc = tu_desc_next ( (uint8_t const *) p_interface_desc );
|
||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||
|
||||
// Skip over the class specific descriptor.
|
||||
(*p_length) += tu_desc_len(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == p_interface_desc->bInterfaceSubClass &&
|
||||
AUDIO_PROTOCOL_V1 == p_interface_desc->bInterfaceProtocol );
|
||||
|
||||
// Find available interface
|
||||
midid_interface_t * p_midi = NULL;
|
||||
for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
|
||||
{
|
||||
if ( _midid_itf[i].ep_in == 0 && _midid_itf[i].ep_out == 0 )
|
||||
{
|
||||
p_midi = &_midid_itf[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p_midi->itf_num = p_interface_desc->bInterfaceNumber;
|
||||
|
||||
uint8_t const * p_desc = tu_desc_next( (uint8_t const *) p_interface_desc );
|
||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||
|
||||
uint8_t found_endpoints = 0;
|
||||
while (found_endpoints < p_interface_desc->bNumEndpoints)
|
||||
{
|
||||
if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
|
||||
{
|
||||
TU_ASSERT( dcd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), false);
|
||||
uint8_t ep_addr = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
|
||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
|
||||
p_midi->ep_in = ep_addr;
|
||||
} else {
|
||||
p_midi->ep_out = ep_addr;
|
||||
}
|
||||
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
found_endpoints += 1;
|
||||
}
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
// Prepare for incoming data
|
||||
TU_ASSERT( usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EPSIZE), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool midid_control_complete(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) p_request;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool midid_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) p_request;
|
||||
|
||||
// driver doesn't support any request yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) result;
|
||||
|
||||
uint8_t itf = 0;
|
||||
midid_interface_t* p_midi = _midid_itf;
|
||||
|
||||
for ( ; ; itf++, p_midi++)
|
||||
{
|
||||
if (itf >= TU_ARRAY_SIZE(_midid_itf)) return false;
|
||||
|
||||
if ( ep_addr == p_midi->ep_out ) break;
|
||||
}
|
||||
|
||||
// receive new data
|
||||
if ( ep_addr == p_midi->ep_out )
|
||||
{
|
||||
midi_rx_done_cb(p_midi, p_midi->epout_buf, xferred_bytes);
|
||||
|
||||
// prepare for next
|
||||
TU_ASSERT( usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EPSIZE), false );
|
||||
} else if ( ep_addr == p_midi->ep_in ) {
|
||||
maybe_transmit(p_midi, itf);
|
||||
}
|
||||
|
||||
// nothing to do with in and notif endpoint
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_MIDI)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "midi_device.h"
|
||||
#include "class/audio/audio.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||
// FIFO
|
||||
tu_fifo_t rx_ff;
|
||||
tu_fifo_t tx_ff;
|
||||
uint8_t rx_ff_buf[CFG_TUD_MIDI_RX_BUFSIZE];
|
||||
uint8_t tx_ff_buf[CFG_TUD_MIDI_TX_BUFSIZE];
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t rx_ff_mutex;
|
||||
osal_mutex_def_t tx_ff_mutex;
|
||||
#endif
|
||||
|
||||
// We need to pack messages into words before queueing their transmission so buffer across write
|
||||
// calls.
|
||||
uint8_t message_buffer[4];
|
||||
uint8_t message_buffer_length;
|
||||
uint8_t message_target_length;
|
||||
|
||||
// Endpoint Transfer buffer
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EPSIZE];
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_MIDI_EPSIZE];
|
||||
|
||||
} midid_interface_t;
|
||||
|
||||
#define ITF_MEM_RESET_SIZE offsetof(midid_interface_t, rx_ff)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI];
|
||||
|
||||
bool tud_midi_n_mounted (uint8_t itf)
|
||||
{
|
||||
midid_interface_t* midi = &_midid_itf[itf];
|
||||
return midi->ep_in && midi->ep_out;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// READ API
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t tud_midi_n_available(uint8_t itf, uint8_t jack_id)
|
||||
{
|
||||
(void) jack_id;
|
||||
return tu_fifo_count(&_midid_itf[itf].rx_ff);
|
||||
}
|
||||
|
||||
uint32_t tud_midi_n_read(uint8_t itf, uint8_t jack_id, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
(void) jack_id;
|
||||
return tu_fifo_read_n(&_midid_itf[itf].rx_ff, buffer, bufsize);
|
||||
}
|
||||
|
||||
void tud_midi_n_read_flush (uint8_t itf, uint8_t jack_id)
|
||||
{
|
||||
(void) jack_id;
|
||||
tu_fifo_clear(&_midid_itf[itf].rx_ff);
|
||||
}
|
||||
|
||||
void midi_rx_done_cb(midid_interface_t* midi, uint8_t const* buffer, uint32_t bufsize) {
|
||||
if (bufsize % 4 != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(uint32_t i=0; i<bufsize; i += 4) {
|
||||
uint8_t header = buffer[i];
|
||||
// uint8_t cable_number = (header & 0xf0) >> 4;
|
||||
uint8_t code_index = header & 0x0f;
|
||||
// We always copy over the first byte.
|
||||
uint8_t count = 1;
|
||||
// Ignore subsequent bytes based on the code.
|
||||
if (code_index != 0x5 && code_index != 0xf) {
|
||||
count = 2;
|
||||
if (code_index != 0x2 && code_index != 0x6 && code_index != 0xc && code_index != 0xd) {
|
||||
count = 3;
|
||||
}
|
||||
}
|
||||
tu_fifo_write_n(&midi->rx_ff, &buffer[i + 1], count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// WRITE API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static bool maybe_transmit(midid_interface_t* midi, uint8_t itf_index)
|
||||
{
|
||||
(void) itf_index;
|
||||
|
||||
// skip if previous transfer not complete
|
||||
TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, midi->ep_in) );
|
||||
|
||||
uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epin_buf, CFG_TUD_MIDI_EPSIZE);
|
||||
if (count > 0)
|
||||
{
|
||||
TU_ASSERT( usbd_edpt_xfer(TUD_OPT_RHPORT, midi->ep_in, midi->epin_buf, count) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t tud_midi_n_write(uint8_t itf, uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize)
|
||||
{
|
||||
midid_interface_t* midi = &_midid_itf[itf];
|
||||
if (midi->itf_num == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t i = 0;
|
||||
while (i < bufsize) {
|
||||
uint8_t data = buffer[i];
|
||||
if (midi->message_buffer_length == 0) {
|
||||
uint8_t msg = data >> 4;
|
||||
midi->message_buffer[1] = data;
|
||||
midi->message_buffer_length = 2;
|
||||
// Check to see if we're still in a SysEx transmit.
|
||||
if (midi->message_buffer[0] == 0x4) {
|
||||
if (data == 0xf7) {
|
||||
midi->message_buffer[0] = 0x5;
|
||||
} else {
|
||||
midi->message_buffer_length = 4;
|
||||
}
|
||||
} else if ((msg >= 0x8 && msg <= 0xB) || msg == 0xE) {
|
||||
midi->message_buffer[0] = jack_id << 4 | msg;
|
||||
midi->message_target_length = 4;
|
||||
} else if (msg == 0xC || msg == 0xD) {
|
||||
midi->message_buffer[0] = jack_id << 4 | msg;
|
||||
midi->message_target_length = 3;
|
||||
} else if (msg == 0xf) {
|
||||
if (data == 0xf0) {
|
||||
midi->message_buffer[0] = 0x4;
|
||||
midi->message_target_length = 4;
|
||||
} else if (data == 0xf1 || data == 0xf3) {
|
||||
midi->message_buffer[0] = 0x2;
|
||||
midi->message_target_length = 3;
|
||||
} else if (data == 0xf2) {
|
||||
midi->message_buffer[0] = 0x3;
|
||||
midi->message_target_length = 4;
|
||||
} else {
|
||||
midi->message_buffer[0] = 0x5;
|
||||
midi->message_target_length = 2;
|
||||
}
|
||||
} else {
|
||||
// Pack individual bytes if we don't support packing them into words.
|
||||
midi->message_buffer[0] = jack_id << 4 | 0xf;
|
||||
midi->message_buffer[2] = 0;
|
||||
midi->message_buffer[3] = 0;
|
||||
midi->message_buffer_length = 2;
|
||||
midi->message_target_length = 2;
|
||||
}
|
||||
} else {
|
||||
midi->message_buffer[midi->message_buffer_length] = data;
|
||||
midi->message_buffer_length += 1;
|
||||
// See if this byte ends a SysEx.
|
||||
if (midi->message_buffer[0] == 0x4 && data == 0xf7) {
|
||||
midi->message_buffer[0] = 0x4 + (midi->message_buffer_length - 1);
|
||||
midi->message_target_length = midi->message_buffer_length;
|
||||
}
|
||||
}
|
||||
|
||||
if (midi->message_buffer_length == midi->message_target_length) {
|
||||
uint16_t written = tu_fifo_write_n(&midi->tx_ff, midi->message_buffer, 4);
|
||||
if (written < 4) {
|
||||
TU_ASSERT( written == 0 );
|
||||
break;
|
||||
}
|
||||
midi->message_buffer_length = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
maybe_transmit(midi, itf);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void midid_init(void)
|
||||
{
|
||||
tu_memclr(_midid_itf, sizeof(_midid_itf));
|
||||
|
||||
for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
|
||||
{
|
||||
midid_interface_t* midi = &_midid_itf[i];
|
||||
|
||||
// config fifo
|
||||
tu_fifo_config(&midi->rx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, true);
|
||||
tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, true);
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
tu_fifo_config_mutex(&midi->rx_ff, osal_mutex_create(&midi->rx_ff_mutex));
|
||||
tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void midid_reset(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
|
||||
{
|
||||
midid_interface_t* midi = &_midid_itf[i];
|
||||
tu_memclr(midi, ITF_MEM_RESET_SIZE);
|
||||
tu_fifo_clear(&midi->rx_ff);
|
||||
tu_fifo_clear(&midi->tx_ff);
|
||||
}
|
||||
}
|
||||
|
||||
bool midid_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length)
|
||||
{
|
||||
// For now handle the audio control interface as well.
|
||||
if ( AUDIO_SUBCLASS_CONTROL == p_interface_desc->bInterfaceSubClass) {
|
||||
uint8_t const * p_desc = tu_desc_next ( (uint8_t const *) p_interface_desc );
|
||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||
|
||||
// Skip over the class specific descriptor.
|
||||
(*p_length) += tu_desc_len(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == p_interface_desc->bInterfaceSubClass &&
|
||||
AUDIO_PROTOCOL_V1 == p_interface_desc->bInterfaceProtocol );
|
||||
|
||||
// Find available interface
|
||||
midid_interface_t * p_midi = NULL;
|
||||
for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
|
||||
{
|
||||
if ( _midid_itf[i].ep_in == 0 && _midid_itf[i].ep_out == 0 )
|
||||
{
|
||||
p_midi = &_midid_itf[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p_midi->itf_num = p_interface_desc->bInterfaceNumber;
|
||||
|
||||
uint8_t const * p_desc = tu_desc_next( (uint8_t const *) p_interface_desc );
|
||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||
|
||||
uint8_t found_endpoints = 0;
|
||||
while (found_endpoints < p_interface_desc->bNumEndpoints)
|
||||
{
|
||||
if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
|
||||
{
|
||||
TU_ASSERT( dcd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), false);
|
||||
uint8_t ep_addr = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
|
||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
|
||||
p_midi->ep_in = ep_addr;
|
||||
} else {
|
||||
p_midi->ep_out = ep_addr;
|
||||
}
|
||||
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
found_endpoints += 1;
|
||||
}
|
||||
(*p_length) += p_desc[DESC_OFFSET_LEN];
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
// Prepare for incoming data
|
||||
TU_ASSERT( usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EPSIZE), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool midid_control_complete(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) p_request;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool midid_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) p_request;
|
||||
|
||||
// driver doesn't support any request yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) result;
|
||||
|
||||
uint8_t itf = 0;
|
||||
midid_interface_t* p_midi = _midid_itf;
|
||||
|
||||
for ( ; ; itf++, p_midi++)
|
||||
{
|
||||
if (itf >= TU_ARRAY_SIZE(_midid_itf)) return false;
|
||||
|
||||
if ( ep_addr == p_midi->ep_out ) break;
|
||||
}
|
||||
|
||||
// receive new data
|
||||
if ( ep_addr == p_midi->ep_out )
|
||||
{
|
||||
midi_rx_done_cb(p_midi, p_midi->epout_buf, xferred_bytes);
|
||||
|
||||
// prepare for next
|
||||
TU_ASSERT( usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EPSIZE), false );
|
||||
} else if ( ep_addr == p_midi->ep_in ) {
|
||||
maybe_transmit(p_midi, itf);
|
||||
}
|
||||
|
||||
// nothing to do with in and notif endpoint
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,138 +1,138 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_MIDI_DEVICE_H_
|
||||
#define _TUSB_MIDI_DEVICE_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "device/usbd.h"
|
||||
|
||||
#include "class/audio/audio.h"
|
||||
#include "midi.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Driver Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
#ifndef CFG_TUD_MIDI_EPSIZE
|
||||
#define CFG_TUD_MIDI_EPSIZE 64
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \addtogroup MIDI_Serial Serial
|
||||
* @{
|
||||
* \defgroup MIDI_Serial_Device Device
|
||||
* @{ */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API (Multiple Interfaces)
|
||||
// CFG_TUD_MIDI > 1
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_midi_n_mounted (uint8_t itf);
|
||||
uint32_t tud_midi_n_available (uint8_t itf, uint8_t jack_id);
|
||||
uint32_t tud_midi_n_read (uint8_t itf, uint8_t jack_id, void* buffer, uint32_t bufsize);
|
||||
void tud_midi_n_read_flush (uint8_t itf, uint8_t jack_id);
|
||||
uint32_t tud_midi_n_write (uint8_t itf, uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize);
|
||||
|
||||
static inline
|
||||
uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API (Interface0)
|
||||
//--------------------------------------------------------------------+
|
||||
static inline bool tud_midi_mounted (void);
|
||||
static inline uint32_t tud_midi_available (void);
|
||||
static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize);
|
||||
static inline void tud_midi_read_flush (void);
|
||||
static inline uint32_t tud_midi_write (uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize);
|
||||
static inline uint32_t tudi_midi_write24 (uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callback API (weak is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Inline Functions
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static inline uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3)
|
||||
{
|
||||
uint8_t msg[3] = { b1, b2, b3 };
|
||||
return tud_midi_n_write(itf, jack_id, msg, 3);
|
||||
}
|
||||
|
||||
static inline bool tud_midi_mounted (void)
|
||||
{
|
||||
return tud_midi_n_mounted(0);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_midi_available (void)
|
||||
{
|
||||
return tud_midi_n_available(0, 0);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize)
|
||||
{
|
||||
return tud_midi_n_read(0, 0, buffer, bufsize);
|
||||
}
|
||||
|
||||
static inline void tud_midi_read_flush (void)
|
||||
{
|
||||
tud_midi_n_read_flush(0, 0);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_midi_write (uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize)
|
||||
{
|
||||
return tud_midi_n_write(0, jack_id, buffer, bufsize);
|
||||
}
|
||||
|
||||
static inline uint32_t tudi_midi_write24 (uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3)
|
||||
{
|
||||
uint8_t msg[3] = { b1, b2, b3 };
|
||||
return tud_midi_write(jack_id, msg, 3);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void midid_init (void);
|
||||
void midid_reset (uint8_t rhport);
|
||||
bool midid_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
|
||||
bool midid_control_request (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool midid_control_complete (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool midid_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MIDI_DEVICE_H_ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_MIDI_DEVICE_H_
|
||||
#define _TUSB_MIDI_DEVICE_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "device/usbd.h"
|
||||
|
||||
#include "class/audio/audio.h"
|
||||
#include "midi.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Driver Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
#ifndef CFG_TUD_MIDI_EPSIZE
|
||||
#define CFG_TUD_MIDI_EPSIZE 64
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \addtogroup MIDI_Serial Serial
|
||||
* @{
|
||||
* \defgroup MIDI_Serial_Device Device
|
||||
* @{ */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API (Multiple Interfaces)
|
||||
// CFG_TUD_MIDI > 1
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_midi_n_mounted (uint8_t itf);
|
||||
uint32_t tud_midi_n_available (uint8_t itf, uint8_t jack_id);
|
||||
uint32_t tud_midi_n_read (uint8_t itf, uint8_t jack_id, void* buffer, uint32_t bufsize);
|
||||
void tud_midi_n_read_flush (uint8_t itf, uint8_t jack_id);
|
||||
uint32_t tud_midi_n_write (uint8_t itf, uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize);
|
||||
|
||||
static inline
|
||||
uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API (Interface0)
|
||||
//--------------------------------------------------------------------+
|
||||
static inline bool tud_midi_mounted (void);
|
||||
static inline uint32_t tud_midi_available (void);
|
||||
static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize);
|
||||
static inline void tud_midi_read_flush (void);
|
||||
static inline uint32_t tud_midi_write (uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize);
|
||||
static inline uint32_t tudi_midi_write24 (uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callback API (weak is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Inline Functions
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static inline uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3)
|
||||
{
|
||||
uint8_t msg[3] = { b1, b2, b3 };
|
||||
return tud_midi_n_write(itf, jack_id, msg, 3);
|
||||
}
|
||||
|
||||
static inline bool tud_midi_mounted (void)
|
||||
{
|
||||
return tud_midi_n_mounted(0);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_midi_available (void)
|
||||
{
|
||||
return tud_midi_n_available(0, 0);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize)
|
||||
{
|
||||
return tud_midi_n_read(0, 0, buffer, bufsize);
|
||||
}
|
||||
|
||||
static inline void tud_midi_read_flush (void)
|
||||
{
|
||||
tud_midi_n_read_flush(0, 0);
|
||||
}
|
||||
|
||||
static inline uint32_t tud_midi_write (uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize)
|
||||
{
|
||||
return tud_midi_n_write(0, jack_id, buffer, bufsize);
|
||||
}
|
||||
|
||||
static inline uint32_t tudi_midi_write24 (uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3)
|
||||
{
|
||||
uint8_t msg[3] = { b1, b2, b3 };
|
||||
return tud_midi_write(jack_id, msg, 3);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void midid_init (void);
|
||||
void midid_reset (uint8_t rhport);
|
||||
bool midid_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
|
||||
bool midid_control_request (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool midid_control_complete (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool midid_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MIDI_DEVICE_H_ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
@ -1,392 +1,392 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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_REQ_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_REQ_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 TU_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 total_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(msc_cbw_t) == 31, "size is not correct");
|
||||
|
||||
/// Command Status Wrapper
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_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_START_STOP_UNIT = 0x1B,
|
||||
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_SENSE_NONE = 0x00, ///< no specific Sense Key. This would be the case for a successful command
|
||||
SCSI_SENSE_RECOVERED_ERROR = 0x01, ///< ndicates the last command completed successfully with some recovery action performed by the disc drive.
|
||||
SCSI_SENSE_NOT_READY = 0x02, ///< Indicates the logical unit addressed cannot be accessed.
|
||||
SCSI_SENSE_MEDIUM_ERROR = 0x03, ///< Indicates the command terminated with a non-recovered error condition.
|
||||
SCSI_SENSE_HARDWARE_ERROR = 0x04, ///< Indicates the disc drive detected a nonrecoverable hardware failure while performing the command or during a self test.
|
||||
SCSI_SENSE_ILLEGAL_REQUEST = 0x05, ///< Indicates an illegal parameter in the command descriptor block or in the additional parameters
|
||||
SCSI_SENSE_UNIT_ATTENTION = 0x06, ///< Indicates the disc drive may have been reset.
|
||||
SCSI_SENSE_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_SENSE_FIRMWARE_ERROR = 0x08, ///< Vendor specific sense key.
|
||||
SCSI_SENSE_ABORTED_COMMAND = 0x0b, ///< Indicates the disc drive aborted the command.
|
||||
SCSI_SENSE_EQUAL = 0x0c, ///< Indicates a SEARCH DATA command has satisfied an equal comparison.
|
||||
SCSI_SENSE_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_SENSE_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 TU_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_test_unit_ready_t) == 6, "size is not correct");
|
||||
|
||||
/// SCSI Inquiry Command
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_inquiry_t) == 6, "size is not correct");
|
||||
|
||||
/// SCSI Inquiry Response Data
|
||||
typedef struct TU_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.
|
||||
uint8_t product_id[16]; ///< 16 bytes of ASCII data defined by the vendor.
|
||||
uint8_t product_rev[4]; ///< 4 bytes of ASCII data defined by the vendor.
|
||||
} scsi_inquiry_resp_t;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_inquiry_resp_t) == 36, "size is not correct");
|
||||
|
||||
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t response_code : 7; ///< 70h - current errors, Fixed Format 71h - deferred errors, Fixed Format
|
||||
uint8_t valid : 1;
|
||||
|
||||
uint8_t reserved;
|
||||
|
||||
uint8_t sense_key : 4;
|
||||
uint8_t : 1;
|
||||
uint8_t ili : 1; ///< Incorrect length indicator
|
||||
uint8_t end_of_medium : 1;
|
||||
uint8_t filemark : 1;
|
||||
|
||||
uint32_t information;
|
||||
uint8_t add_sense_len;
|
||||
uint32_t command_specific_info;
|
||||
uint8_t add_sense_code;
|
||||
uint8_t add_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_resp_t;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_sense_fixed_resp_t) == 18, "size is not correct");
|
||||
|
||||
typedef struct TU_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_sense6_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_t) == 6, "size is not correct");
|
||||
|
||||
// This is only a Mode parameter header(6).
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t data_len;
|
||||
uint8_t medium_type;
|
||||
|
||||
uint8_t reserved : 7;
|
||||
bool write_protected : 1;
|
||||
|
||||
uint8_t block_descriptor_len;
|
||||
} scsi_mode_sense6_resp_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_resp_t) == 4, "size is not correct");
|
||||
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(scsi_prevent_allow_medium_removal_t) == 6, "size is not correct");
|
||||
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code;
|
||||
|
||||
uint8_t immded : 1;
|
||||
uint8_t : 7;
|
||||
|
||||
uint8_t TU_RESERVED;
|
||||
|
||||
uint8_t power_condition_mod : 4;
|
||||
uint8_t : 4;
|
||||
|
||||
uint8_t start : 1;
|
||||
uint8_t load_eject : 1;
|
||||
uint8_t no_flush : 1;
|
||||
uint8_t : 1;
|
||||
uint8_t power_condition : 4;
|
||||
|
||||
uint8_t control;
|
||||
} scsi_start_stop_unit_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(scsi_start_stop_unit_t) == 6, "size is not correct");
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SCSI MMC
|
||||
//--------------------------------------------------------------------+
|
||||
/// SCSI Read Format Capacity: Write Capacity
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code;
|
||||
uint8_t reserved[6];
|
||||
uint16_t alloc_length;
|
||||
uint8_t control;
|
||||
} scsi_read_format_capacity_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_t) == 10, "size is not correct");
|
||||
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_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 TU_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;
|
||||
|
||||
TU_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_resp_t;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_resp_t) == 8, "size is not correct");
|
||||
|
||||
/// SCSI Read 10 Command
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_read10_t) == 10, "size is not correct");
|
||||
TU_VERIFY_STATIC(sizeof(scsi_write10_t) == 10, "size is not correct");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MSC_H_ */
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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_REQ_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_REQ_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 TU_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 total_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(msc_cbw_t) == 31, "size is not correct");
|
||||
|
||||
/// Command Status Wrapper
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_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_START_STOP_UNIT = 0x1B,
|
||||
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_SENSE_NONE = 0x00, ///< no specific Sense Key. This would be the case for a successful command
|
||||
SCSI_SENSE_RECOVERED_ERROR = 0x01, ///< ndicates the last command completed successfully with some recovery action performed by the disc drive.
|
||||
SCSI_SENSE_NOT_READY = 0x02, ///< Indicates the logical unit addressed cannot be accessed.
|
||||
SCSI_SENSE_MEDIUM_ERROR = 0x03, ///< Indicates the command terminated with a non-recovered error condition.
|
||||
SCSI_SENSE_HARDWARE_ERROR = 0x04, ///< Indicates the disc drive detected a nonrecoverable hardware failure while performing the command or during a self test.
|
||||
SCSI_SENSE_ILLEGAL_REQUEST = 0x05, ///< Indicates an illegal parameter in the command descriptor block or in the additional parameters
|
||||
SCSI_SENSE_UNIT_ATTENTION = 0x06, ///< Indicates the disc drive may have been reset.
|
||||
SCSI_SENSE_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_SENSE_FIRMWARE_ERROR = 0x08, ///< Vendor specific sense key.
|
||||
SCSI_SENSE_ABORTED_COMMAND = 0x0b, ///< Indicates the disc drive aborted the command.
|
||||
SCSI_SENSE_EQUAL = 0x0c, ///< Indicates a SEARCH DATA command has satisfied an equal comparison.
|
||||
SCSI_SENSE_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_SENSE_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 TU_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_test_unit_ready_t) == 6, "size is not correct");
|
||||
|
||||
/// SCSI Inquiry Command
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_inquiry_t) == 6, "size is not correct");
|
||||
|
||||
/// SCSI Inquiry Response Data
|
||||
typedef struct TU_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.
|
||||
uint8_t product_id[16]; ///< 16 bytes of ASCII data defined by the vendor.
|
||||
uint8_t product_rev[4]; ///< 4 bytes of ASCII data defined by the vendor.
|
||||
} scsi_inquiry_resp_t;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_inquiry_resp_t) == 36, "size is not correct");
|
||||
|
||||
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t response_code : 7; ///< 70h - current errors, Fixed Format 71h - deferred errors, Fixed Format
|
||||
uint8_t valid : 1;
|
||||
|
||||
uint8_t reserved;
|
||||
|
||||
uint8_t sense_key : 4;
|
||||
uint8_t : 1;
|
||||
uint8_t ili : 1; ///< Incorrect length indicator
|
||||
uint8_t end_of_medium : 1;
|
||||
uint8_t filemark : 1;
|
||||
|
||||
uint32_t information;
|
||||
uint8_t add_sense_len;
|
||||
uint32_t command_specific_info;
|
||||
uint8_t add_sense_code;
|
||||
uint8_t add_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_resp_t;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_sense_fixed_resp_t) == 18, "size is not correct");
|
||||
|
||||
typedef struct TU_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_sense6_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_t) == 6, "size is not correct");
|
||||
|
||||
// This is only a Mode parameter header(6).
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t data_len;
|
||||
uint8_t medium_type;
|
||||
|
||||
uint8_t reserved : 7;
|
||||
bool write_protected : 1;
|
||||
|
||||
uint8_t block_descriptor_len;
|
||||
} scsi_mode_sense6_resp_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_resp_t) == 4, "size is not correct");
|
||||
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(scsi_prevent_allow_medium_removal_t) == 6, "size is not correct");
|
||||
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code;
|
||||
|
||||
uint8_t immded : 1;
|
||||
uint8_t : 7;
|
||||
|
||||
uint8_t TU_RESERVED;
|
||||
|
||||
uint8_t power_condition_mod : 4;
|
||||
uint8_t : 4;
|
||||
|
||||
uint8_t start : 1;
|
||||
uint8_t load_eject : 1;
|
||||
uint8_t no_flush : 1;
|
||||
uint8_t : 1;
|
||||
uint8_t power_condition : 4;
|
||||
|
||||
uint8_t control;
|
||||
} scsi_start_stop_unit_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(scsi_start_stop_unit_t) == 6, "size is not correct");
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SCSI MMC
|
||||
//--------------------------------------------------------------------+
|
||||
/// SCSI Read Format Capacity: Write Capacity
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t cmd_code;
|
||||
uint8_t reserved[6];
|
||||
uint16_t alloc_length;
|
||||
uint8_t control;
|
||||
} scsi_read_format_capacity_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_t) == 10, "size is not correct");
|
||||
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_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 TU_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;
|
||||
|
||||
TU_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_resp_t;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_resp_t) == 8, "size is not correct");
|
||||
|
||||
/// SCSI Read 10 Command
|
||||
typedef struct TU_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;
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(scsi_read10_t) == 10, "size is not correct");
|
||||
TU_VERIFY_STATIC(sizeof(scsi_write10_t) == 10, "size is not correct");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MSC_H_ */
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,165 +1,165 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Driver Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct");
|
||||
|
||||
#ifndef CFG_TUD_MSC_BUFSIZE
|
||||
#error CFG_TUD_MSC_BUFSIZE must be defined, value of a block size should work well, the more the better
|
||||
#endif
|
||||
|
||||
/** \addtogroup ClassDriver_MSC
|
||||
* @{
|
||||
* \defgroup MSC_Device Device
|
||||
* @{ */
|
||||
|
||||
bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callbacks (WEAK is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/**
|
||||
* Invoked when received \ref SCSI_CMD_READ_10 command
|
||||
* \param[in] lun Logical unit number
|
||||
* \param[in] lba Logical Block Address to be read
|
||||
* \param[in] offset Byte offset from LBA
|
||||
* \param[out] buffer Buffer which application need to update with the response data.
|
||||
* \param[in] bufsize Requested bytes
|
||||
*
|
||||
* \return Number of byte read, if it is less than requested bytes by \a \b bufsize. Tinyusb will transfer
|
||||
* this amount first and invoked this again for remaining data.
|
||||
*
|
||||
* \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 parameters again some time later.
|
||||
*
|
||||
* \retval negative Indicate error e.g reading disk I/O. tinyusb will \b STALL the corresponding
|
||||
* endpoint and return failed status in command status wrapper phase.
|
||||
*/
|
||||
int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
|
||||
|
||||
/**
|
||||
* Invoked when received \ref SCSI_CMD_WRITE_10 command
|
||||
* \param[in] lun Logical unit number
|
||||
* \param[in] lba Logical Block Address to be write
|
||||
* \param[in] offset Byte offset from LBA
|
||||
* \param[out] buffer Buffer which holds written data.
|
||||
* \param[in] bufsize Requested bytes
|
||||
*
|
||||
* \return Number of byte written, if it is less than requested bytes by \a \b bufsize. Tinyusb will proceed with
|
||||
* other work and invoked this again with adjusted parameters.
|
||||
*
|
||||
* \retval zero Indicate application is not ready yet e.g disk I/O is not complete.
|
||||
* Tinyusb will invoke this callback with the same parameters 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.
|
||||
*/
|
||||
int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
|
||||
|
||||
// Invoked when received SCSI_CMD_INQUIRY
|
||||
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]);
|
||||
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool tud_msc_test_unit_ready_cb(uint8_t lun);
|
||||
|
||||
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
|
||||
// Application update block count and block size
|
||||
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size);
|
||||
|
||||
/**
|
||||
* Invoked when received an SCSI command not in built-in list below.
|
||||
* - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE
|
||||
* - READ10 and WRITE10 has their own callbacks
|
||||
*
|
||||
* \param[in] lun Logical unit number
|
||||
* \param[in] scsi_cmd SCSI command contents which application must examine to response accordingly
|
||||
* \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.
|
||||
*
|
||||
* \return Actual bytes processed, can be zero for no-data command.
|
||||
* \retval negative Indicate error e.g unsupported command, tinyusb will \b STALL the corresponding
|
||||
* endpoint and return failed status in command status wrapper phase.
|
||||
*/
|
||||
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize);
|
||||
|
||||
/*------------- Optional callbacks -------------*/
|
||||
|
||||
// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation
|
||||
TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void);
|
||||
|
||||
// Invoked when received Start Stop Unit command
|
||||
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
|
||||
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
|
||||
TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject);
|
||||
|
||||
// Invoked when Read10 command is complete
|
||||
TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);
|
||||
|
||||
// Invoke when Write10 command is complete, can be used to flush flash caching
|
||||
TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun);
|
||||
|
||||
// Invoked when command in tud_msc_scsi_cb is complete
|
||||
TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]);
|
||||
|
||||
// Hook to make a mass storage device read-only. TODO remove
|
||||
TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun);
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void mscd_init (void);
|
||||
void mscd_reset (uint8_t rhport);
|
||||
bool mscd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
|
||||
bool mscd_control_request (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool mscd_control_complete (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool mscd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MSC_DEVICE_H_ */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Driver Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct");
|
||||
|
||||
#ifndef CFG_TUD_MSC_BUFSIZE
|
||||
#error CFG_TUD_MSC_BUFSIZE must be defined, value of a block size should work well, the more the better
|
||||
#endif
|
||||
|
||||
/** \addtogroup ClassDriver_MSC
|
||||
* @{
|
||||
* \defgroup MSC_Device Device
|
||||
* @{ */
|
||||
|
||||
bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callbacks (WEAK is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/**
|
||||
* Invoked when received \ref SCSI_CMD_READ_10 command
|
||||
* \param[in] lun Logical unit number
|
||||
* \param[in] lba Logical Block Address to be read
|
||||
* \param[in] offset Byte offset from LBA
|
||||
* \param[out] buffer Buffer which application need to update with the response data.
|
||||
* \param[in] bufsize Requested bytes
|
||||
*
|
||||
* \return Number of byte read, if it is less than requested bytes by \a \b bufsize. Tinyusb will transfer
|
||||
* this amount first and invoked this again for remaining data.
|
||||
*
|
||||
* \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 parameters again some time later.
|
||||
*
|
||||
* \retval negative Indicate error e.g reading disk I/O. tinyusb will \b STALL the corresponding
|
||||
* endpoint and return failed status in command status wrapper phase.
|
||||
*/
|
||||
int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
|
||||
|
||||
/**
|
||||
* Invoked when received \ref SCSI_CMD_WRITE_10 command
|
||||
* \param[in] lun Logical unit number
|
||||
* \param[in] lba Logical Block Address to be write
|
||||
* \param[in] offset Byte offset from LBA
|
||||
* \param[out] buffer Buffer which holds written data.
|
||||
* \param[in] bufsize Requested bytes
|
||||
*
|
||||
* \return Number of byte written, if it is less than requested bytes by \a \b bufsize. Tinyusb will proceed with
|
||||
* other work and invoked this again with adjusted parameters.
|
||||
*
|
||||
* \retval zero Indicate application is not ready yet e.g disk I/O is not complete.
|
||||
* Tinyusb will invoke this callback with the same parameters 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.
|
||||
*/
|
||||
int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
|
||||
|
||||
// Invoked when received SCSI_CMD_INQUIRY
|
||||
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]);
|
||||
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool tud_msc_test_unit_ready_cb(uint8_t lun);
|
||||
|
||||
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
|
||||
// Application update block count and block size
|
||||
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size);
|
||||
|
||||
/**
|
||||
* Invoked when received an SCSI command not in built-in list below.
|
||||
* - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE
|
||||
* - READ10 and WRITE10 has their own callbacks
|
||||
*
|
||||
* \param[in] lun Logical unit number
|
||||
* \param[in] scsi_cmd SCSI command contents which application must examine to response accordingly
|
||||
* \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.
|
||||
*
|
||||
* \return Actual bytes processed, can be zero for no-data command.
|
||||
* \retval negative Indicate error e.g unsupported command, tinyusb will \b STALL the corresponding
|
||||
* endpoint and return failed status in command status wrapper phase.
|
||||
*/
|
||||
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize);
|
||||
|
||||
/*------------- Optional callbacks -------------*/
|
||||
|
||||
// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation
|
||||
TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void);
|
||||
|
||||
// Invoked when received Start Stop Unit command
|
||||
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
|
||||
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
|
||||
TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject);
|
||||
|
||||
// Invoked when Read10 command is complete
|
||||
TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);
|
||||
|
||||
// Invoke when Write10 command is complete, can be used to flush flash caching
|
||||
TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun);
|
||||
|
||||
// Invoked when command in tud_msc_scsi_cb is complete
|
||||
TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]);
|
||||
|
||||
// Hook to make a mass storage device read-only. TODO remove
|
||||
TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun);
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void mscd_init (void);
|
||||
void mscd_reset (uint8_t rhport);
|
||||
bool mscd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
|
||||
bool mscd_control_request (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool mscd_control_complete (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool mscd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MSC_DEVICE_H_ */
|
||||
|
@ -1,413 +1,413 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED & CFG_TUH_MSC
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "msc_host.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION static msch_interface_t msch_data[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
|
||||
//------------- Initalization Data -------------//
|
||||
static osal_semaphore_def_t msch_sem_def;
|
||||
static osal_semaphore_t msch_sem_hdl;
|
||||
|
||||
// buffer used to read scsi information when mounted, largest response data currently is inquiry
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msch_buffer[sizeof(scsi_inquiry_resp_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_edpt_busy(dev_addr, msch_data[dev_addr-1].ep_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(uint8_t dev_addr, 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( hcd_pipe_xfer(dev_addr, p_msch->ep_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t), false), TUSB_ERROR_FAILED );
|
||||
TU_ASSERT( hcd_pipe_queue_xfer(dev_addr, p_msch->ep_in , p_buffer, p_msch->cbw.total_bytes), TUSB_ERROR_FAILED );
|
||||
}else
|
||||
{
|
||||
TU_ASSERT( hcd_pipe_queue_xfer(dev_addr, p_msch->ep_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t)), TUSB_ERROR_FAILED );
|
||||
TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_out , p_buffer, p_msch->cbw.total_bytes, false), TUSB_ERROR_FAILED );
|
||||
}
|
||||
}
|
||||
|
||||
TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_in , (uint8_t*) &p_msch->csw, sizeof(msc_csw_t), true), TUSB_ERROR_FAILED);
|
||||
|
||||
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.total_bytes = sizeof(scsi_inquiry_resp_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_resp_t)
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_inquiry, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(dev_addr, 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.total_bytes = sizeof(scsi_read_capacity10_resp_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(dev_addr, 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.total_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(dev_addr, 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.total_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( hcd_pipe_xfer(dev_addr, p_msch->ep_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t), false), TUSB_ERROR_FAILED );
|
||||
TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_in , (uint8_t*) p_csw, sizeof(msc_csw_t), true), TUSB_ERROR_FAILED );
|
||||
|
||||
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.total_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 = tu_htonl(lba),
|
||||
.block_count = tu_htons(block_count)
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_read10, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(dev_addr, 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.total_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 = tu_htonl(lba),
|
||||
.block_count = tu_htons(block_count)
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_write10, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(dev_addr, p_msch, (void*) p_buffer));
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CLASS-USBH API (don't require to verify parameters)
|
||||
//--------------------------------------------------------------------+
|
||||
void msch_init(void)
|
||||
{
|
||||
tu_memclr(msch_data, sizeof(msch_interface_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
msch_sem_hdl = osal_semaphore_create(&msch_sem_def);
|
||||
}
|
||||
|
||||
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
|
||||
{
|
||||
TU_VERIFY (MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass &&
|
||||
MSC_PROTOCOL_BOT == itf_desc->bInterfaceProtocol);
|
||||
|
||||
msch_interface_t* p_msc = &msch_data[dev_addr-1];
|
||||
|
||||
//------------- Open Data Pipe -------------//
|
||||
tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
|
||||
|
||||
for(uint32_t i=0; i<2; i++)
|
||||
{
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
|
||||
TU_ASSERT(TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
|
||||
|
||||
TU_ASSERT(hcd_edpt_open(rhport, dev_addr, ep_desc));
|
||||
|
||||
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
|
||||
{
|
||||
p_msc->ep_in = ep_desc->bEndpointAddress;
|
||||
}else
|
||||
{
|
||||
p_msc->ep_out = ep_desc->bEndpointAddress;
|
||||
}
|
||||
|
||||
ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc);
|
||||
}
|
||||
|
||||
p_msc->itf_numr = itf_desc->bInterfaceNumber;
|
||||
(*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
//------------- Get Max Lun -------------//
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN },
|
||||
.bRequest = MSC_REQ_GET_MAX_LUN,
|
||||
.wValue = 0,
|
||||
.wIndex = p_msc->itf_numr,
|
||||
.wLength = 1
|
||||
};
|
||||
// TODO STALL means zero
|
||||
TU_ASSERT( usbh_control_xfer( dev_addr, &request, msch_buffer ) );
|
||||
p_msc->max_lun = msch_buffer[0];
|
||||
|
||||
#if 0
|
||||
//------------- Reset -------------//
|
||||
request = (tusb_control_request_t) {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = MSC_REQ_RESET,
|
||||
.wValue = 0,
|
||||
.wIndex = p_msc->itf_numr,
|
||||
.wLength = 0
|
||||
};
|
||||
TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) );
|
||||
#endif
|
||||
|
||||
enum { SCSI_XFER_TIMEOUT = 2000 };
|
||||
//------------- SCSI Inquiry -------------//
|
||||
tusbh_msc_inquiry(dev_addr, 0, msch_buffer);
|
||||
TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT) );
|
||||
|
||||
memcpy(p_msc->vendor_id , ((scsi_inquiry_resp_t*) msch_buffer)->vendor_id , 8);
|
||||
memcpy(p_msc->product_id, ((scsi_inquiry_resp_t*) msch_buffer)->product_id, 16);
|
||||
|
||||
//------------- SCSI Read Capacity 10 -------------//
|
||||
tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer);
|
||||
TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT));
|
||||
|
||||
// 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_edpt_stalled(dev_addr, p_msc->ep_in) )
|
||||
{
|
||||
// clear stall TODO abstract clear stall function
|
||||
request = (tusb_control_request_t) {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_ENDPOINT, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = TUSB_REQ_CLEAR_FEATURE,
|
||||
.wValue = 0,
|
||||
.wIndex = p_msc->ep_in,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
TU_ASSERT(usbh_control_xfer( dev_addr, &request, NULL ));
|
||||
|
||||
hcd_edpt_clear_stall(dev_addr, p_msc->ep_in);
|
||||
TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT) ); // wait for SCSI status
|
||||
|
||||
//------------- SCSI Request Sense -------------//
|
||||
(void) tuh_msc_request_sense(dev_addr, 0, msch_buffer);
|
||||
TU_ASSERT(osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT));
|
||||
|
||||
//------------- Re-read SCSI Read Capactity -------------//
|
||||
tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer);
|
||||
TU_ASSERT(osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT));
|
||||
}
|
||||
|
||||
p_msc->last_lba = tu_ntohl( ((scsi_read_capacity10_resp_t*)msch_buffer)->last_lba );
|
||||
p_msc->block_size = (uint16_t) tu_ntohl( ((scsi_read_capacity10_resp_t*)msch_buffer)->block_size );
|
||||
|
||||
p_msc->is_initialized = true;
|
||||
|
||||
tuh_msc_mounted_cb(dev_addr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void msch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
msch_interface_t* p_msc = &msch_data[dev_addr-1];
|
||||
if ( ep_addr == p_msc->ep_in )
|
||||
{
|
||||
if (p_msc->is_initialized)
|
||||
{
|
||||
tuh_msc_isr(dev_addr, event, xferred_bytes);
|
||||
}else
|
||||
{ // still initializing under open subtask
|
||||
osal_semaphore_post(msch_sem_hdl, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void msch_close(uint8_t dev_addr)
|
||||
{
|
||||
tu_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
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED & CFG_TUH_MSC
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "msc_host.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION static msch_interface_t msch_data[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
|
||||
//------------- Initalization Data -------------//
|
||||
static osal_semaphore_def_t msch_sem_def;
|
||||
static osal_semaphore_t msch_sem_hdl;
|
||||
|
||||
// buffer used to read scsi information when mounted, largest response data currently is inquiry
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msch_buffer[sizeof(scsi_inquiry_resp_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_edpt_busy(dev_addr, msch_data[dev_addr-1].ep_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(uint8_t dev_addr, 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( hcd_pipe_xfer(dev_addr, p_msch->ep_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t), false), TUSB_ERROR_FAILED );
|
||||
TU_ASSERT( hcd_pipe_queue_xfer(dev_addr, p_msch->ep_in , p_buffer, p_msch->cbw.total_bytes), TUSB_ERROR_FAILED );
|
||||
}else
|
||||
{
|
||||
TU_ASSERT( hcd_pipe_queue_xfer(dev_addr, p_msch->ep_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t)), TUSB_ERROR_FAILED );
|
||||
TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_out , p_buffer, p_msch->cbw.total_bytes, false), TUSB_ERROR_FAILED );
|
||||
}
|
||||
}
|
||||
|
||||
TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_in , (uint8_t*) &p_msch->csw, sizeof(msc_csw_t), true), TUSB_ERROR_FAILED);
|
||||
|
||||
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.total_bytes = sizeof(scsi_inquiry_resp_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_resp_t)
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_inquiry, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(dev_addr, 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.total_bytes = sizeof(scsi_read_capacity10_resp_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(dev_addr, 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.total_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(dev_addr, 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.total_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( hcd_pipe_xfer(dev_addr, p_msch->ep_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t), false), TUSB_ERROR_FAILED );
|
||||
TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_in , (uint8_t*) p_csw, sizeof(msc_csw_t), true), TUSB_ERROR_FAILED );
|
||||
|
||||
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.total_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 = tu_htonl(lba),
|
||||
.block_count = tu_htons(block_count)
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_read10, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(dev_addr, 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.total_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 = tu_htonl(lba),
|
||||
.block_count = tu_htons(block_count)
|
||||
};
|
||||
|
||||
memcpy(p_msch->cbw.command, &cmd_write10, p_msch->cbw.cmd_len);
|
||||
|
||||
TU_ASSERT_ERR ( msch_command_xfer(dev_addr, p_msch, (void*) p_buffer));
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CLASS-USBH API (don't require to verify parameters)
|
||||
//--------------------------------------------------------------------+
|
||||
void msch_init(void)
|
||||
{
|
||||
tu_memclr(msch_data, sizeof(msch_interface_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
msch_sem_hdl = osal_semaphore_create(&msch_sem_def);
|
||||
}
|
||||
|
||||
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
|
||||
{
|
||||
TU_VERIFY (MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass &&
|
||||
MSC_PROTOCOL_BOT == itf_desc->bInterfaceProtocol);
|
||||
|
||||
msch_interface_t* p_msc = &msch_data[dev_addr-1];
|
||||
|
||||
//------------- Open Data Pipe -------------//
|
||||
tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
|
||||
|
||||
for(uint32_t i=0; i<2; i++)
|
||||
{
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
|
||||
TU_ASSERT(TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
|
||||
|
||||
TU_ASSERT(hcd_edpt_open(rhport, dev_addr, ep_desc));
|
||||
|
||||
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
|
||||
{
|
||||
p_msc->ep_in = ep_desc->bEndpointAddress;
|
||||
}else
|
||||
{
|
||||
p_msc->ep_out = ep_desc->bEndpointAddress;
|
||||
}
|
||||
|
||||
ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc);
|
||||
}
|
||||
|
||||
p_msc->itf_numr = itf_desc->bInterfaceNumber;
|
||||
(*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
//------------- Get Max Lun -------------//
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN },
|
||||
.bRequest = MSC_REQ_GET_MAX_LUN,
|
||||
.wValue = 0,
|
||||
.wIndex = p_msc->itf_numr,
|
||||
.wLength = 1
|
||||
};
|
||||
// TODO STALL means zero
|
||||
TU_ASSERT( usbh_control_xfer( dev_addr, &request, msch_buffer ) );
|
||||
p_msc->max_lun = msch_buffer[0];
|
||||
|
||||
#if 0
|
||||
//------------- Reset -------------//
|
||||
request = (tusb_control_request_t) {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = MSC_REQ_RESET,
|
||||
.wValue = 0,
|
||||
.wIndex = p_msc->itf_numr,
|
||||
.wLength = 0
|
||||
};
|
||||
TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) );
|
||||
#endif
|
||||
|
||||
enum { SCSI_XFER_TIMEOUT = 2000 };
|
||||
//------------- SCSI Inquiry -------------//
|
||||
tusbh_msc_inquiry(dev_addr, 0, msch_buffer);
|
||||
TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT) );
|
||||
|
||||
memcpy(p_msc->vendor_id , ((scsi_inquiry_resp_t*) msch_buffer)->vendor_id , 8);
|
||||
memcpy(p_msc->product_id, ((scsi_inquiry_resp_t*) msch_buffer)->product_id, 16);
|
||||
|
||||
//------------- SCSI Read Capacity 10 -------------//
|
||||
tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer);
|
||||
TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT));
|
||||
|
||||
// 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_edpt_stalled(dev_addr, p_msc->ep_in) )
|
||||
{
|
||||
// clear stall TODO abstract clear stall function
|
||||
request = (tusb_control_request_t) {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_ENDPOINT, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = TUSB_REQ_CLEAR_FEATURE,
|
||||
.wValue = 0,
|
||||
.wIndex = p_msc->ep_in,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
TU_ASSERT(usbh_control_xfer( dev_addr, &request, NULL ));
|
||||
|
||||
hcd_edpt_clear_stall(dev_addr, p_msc->ep_in);
|
||||
TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT) ); // wait for SCSI status
|
||||
|
||||
//------------- SCSI Request Sense -------------//
|
||||
(void) tuh_msc_request_sense(dev_addr, 0, msch_buffer);
|
||||
TU_ASSERT(osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT));
|
||||
|
||||
//------------- Re-read SCSI Read Capactity -------------//
|
||||
tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer);
|
||||
TU_ASSERT(osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT));
|
||||
}
|
||||
|
||||
p_msc->last_lba = tu_ntohl( ((scsi_read_capacity10_resp_t*)msch_buffer)->last_lba );
|
||||
p_msc->block_size = (uint16_t) tu_ntohl( ((scsi_read_capacity10_resp_t*)msch_buffer)->block_size );
|
||||
|
||||
p_msc->is_initialized = true;
|
||||
|
||||
tuh_msc_mounted_cb(dev_addr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void msch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
msch_interface_t* p_msc = &msch_data[dev_addr-1];
|
||||
if ( ep_addr == p_msc->ep_in )
|
||||
{
|
||||
if (p_msc->is_initialized)
|
||||
{
|
||||
tuh_msc_isr(dev_addr, event, xferred_bytes);
|
||||
}else
|
||||
{ // still initializing under open subtask
|
||||
osal_semaphore_post(msch_sem_hdl, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void msch_close(uint8_t dev_addr)
|
||||
{
|
||||
tu_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
|
||||
|
@ -1,206 +1,206 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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); // 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);
|
||||
|
||||
//------------- 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 xfer_result_t
|
||||
* \param[in] xferred_bytes Number of bytes transferred via USB bus
|
||||
* \note event can be one of following
|
||||
* - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully.
|
||||
* - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error.
|
||||
* - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device.
|
||||
* \note
|
||||
*/
|
||||
void tuh_msc_isr(uint8_t dev_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
uint8_t itf_numr;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
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);
|
||||
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
|
||||
void msch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void msch_close(uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MSC_HOST_H_ */
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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);
|
||||
|
||||
/** \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_MEM_SECTION)
|
||||
* \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); // 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);
|
||||
|
||||
//------------- 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 xfer_result_t
|
||||
* \param[in] xferred_bytes Number of bytes transferred via USB bus
|
||||
* \note event can be one of following
|
||||
* - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully.
|
||||
* - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error.
|
||||
* - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device.
|
||||
* \note
|
||||
*/
|
||||
void tuh_msc_isr(uint8_t dev_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
uint8_t itf_numr;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
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);
|
||||
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
|
||||
void msch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void msch_close(uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MSC_HOST_H_ */
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
|
@ -1,275 +1,275 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common
|
||||
* \defgroup Group_CommonH common.h
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_COMMON_H_
|
||||
#define _TUSB_COMMON_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Macros Helper
|
||||
//--------------------------------------------------------------------+
|
||||
#define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
|
||||
#define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) )
|
||||
#define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) )
|
||||
|
||||
#define TU_U16_HIGH(u16) ((uint8_t) (((u16) >> 8) & 0x00ff))
|
||||
#define TU_U16_LOW(u16) ((uint8_t) ((u16) & 0x00ff))
|
||||
#define U16_TO_U8S_BE(u16) TU_U16_HIGH(u16), TU_U16_LOW(u16)
|
||||
#define U16_TO_U8S_LE(u16) TU_U16_LOW(u16), TU_U16_HIGH(u16)
|
||||
|
||||
#define U32_B1_U8(u32) ((uint8_t) (((u32) >> 24) & 0x000000ff)) // MSB
|
||||
#define U32_B2_U8(u32) ((uint8_t) (((u32) >> 16) & 0x000000ff))
|
||||
#define U32_B3_U8(u32) ((uint8_t) (((u32) >> 8) & 0x000000ff))
|
||||
#define U32_B4_U8(u32) ((uint8_t) ((u32) & 0x000000ff)) // LSB
|
||||
|
||||
#define U32_TO_U8S_BE(u32) U32_B1_U8(u32), U32_B2_U8(u32), U32_B3_U8(u32), U32_B4_U8(u32)
|
||||
#define U32_TO_U8S_LE(u32) U32_B4_U8(u32), U32_B3_U8(u32), U32_B2_U8(u32), U32_B1_U8(u32)
|
||||
|
||||
#define TU_BIT(n) (1U << (n))
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Includes
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Standard Headers
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Tinyusb Common Headers
|
||||
#include "tusb_option.h"
|
||||
#include "tusb_compiler.h"
|
||||
#include "tusb_verify.h"
|
||||
#include "tusb_error.h" // TODO remove
|
||||
#include "tusb_timeout.h"
|
||||
#include "tusb_types.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Inline Functions
|
||||
//--------------------------------------------------------------------+
|
||||
#define tu_memclr(buffer, size) memset((buffer), 0, (size))
|
||||
#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var)))
|
||||
|
||||
static inline uint32_t tu_u32(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4)
|
||||
{
|
||||
return ( ((uint32_t) b1) << 24) + ( ((uint32_t) b2) << 16) + ( ((uint32_t) b3) << 8) + b4;
|
||||
}
|
||||
|
||||
static inline uint16_t tu_u16(uint8_t high, uint8_t low)
|
||||
{
|
||||
return (uint16_t)((((uint16_t) high) << 8) + low);
|
||||
}
|
||||
|
||||
static inline uint8_t tu_u16_high(uint16_t u16) { return (uint8_t) (((uint16_t) (u16 >> 8)) & 0x00ff); }
|
||||
static inline uint8_t tu_u16_low (uint16_t u16) { return (uint8_t) (u16 & 0x00ff); }
|
||||
|
||||
// Min
|
||||
static inline uint8_t tu_min8 (uint8_t x, uint8_t y ) { return (x < y) ? x : y; }
|
||||
static inline uint16_t tu_min16 (uint16_t x, uint16_t y) { return (x < y) ? x : y; }
|
||||
static inline uint32_t tu_min32 (uint32_t x, uint32_t y) { return (x < y) ? x : y; }
|
||||
|
||||
// Max
|
||||
static inline uint8_t tu_max8 (uint8_t x, uint8_t y ) { return (x > y) ? x : y; }
|
||||
static inline uint16_t tu_max16 (uint16_t x, uint16_t y) { return (x > y) ? x : y; }
|
||||
static inline uint32_t tu_max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; }
|
||||
|
||||
// Align
|
||||
static inline uint32_t tu_align_n(uint32_t value, uint32_t alignment)
|
||||
{
|
||||
return value & ((uint32_t) ~(alignment-1));
|
||||
}
|
||||
|
||||
static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); }
|
||||
static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); }
|
||||
static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); }
|
||||
static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
|
||||
|
||||
//------------- Mathematics -------------//
|
||||
static inline uint32_t tu_abs(int32_t value) { return (uint32_t)((value < 0) ? (-value) : value); }
|
||||
|
||||
/// inclusive range checking
|
||||
static inline bool tu_within(uint32_t lower, uint32_t value, uint32_t upper)
|
||||
{
|
||||
return (lower <= value) && (value <= upper);
|
||||
}
|
||||
|
||||
// log2 of a value is its MSB's position
|
||||
// TODO use clz TODO remove
|
||||
static inline uint8_t tu_log2(uint32_t value)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
while (value >>= 1)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Bit
|
||||
static inline uint32_t tu_bit_set (uint32_t value, uint8_t pos) { return value | TU_BIT(pos); }
|
||||
static inline uint32_t tu_bit_clear(uint32_t value, uint8_t pos) { return value & (~TU_BIT(pos)); }
|
||||
static inline bool tu_bit_test (uint32_t value, uint8_t pos) { return (value & TU_BIT(pos)) ? true : false; }
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Count number of arguments of __VA_ARGS__
|
||||
* - reference https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s
|
||||
* - _GET_NTH_ARG() takes args >= N (64) but only expand to Nth one (64th)
|
||||
* - _RSEQ_N() is reverse sequential to N to add padding to have
|
||||
* Nth position is the same as the number of arguments
|
||||
* - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma)
|
||||
*------------------------------------------------------------------*/
|
||||
#ifndef TU_ARGS_NUM
|
||||
|
||||
#define TU_ARGS_NUM(...) NARG_(_0, ##__VA_ARGS__,_RSEQ_N())
|
||||
|
||||
#define NARG_(...) _GET_NTH_ARG(__VA_ARGS__)
|
||||
#define _GET_NTH_ARG( \
|
||||
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
|
||||
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
|
||||
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
|
||||
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
|
||||
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
|
||||
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
|
||||
_61,_62,_63,N,...) N
|
||||
#define _RSEQ_N() \
|
||||
62,61,60, \
|
||||
59,58,57,56,55,54,53,52,51,50, \
|
||||
49,48,47,46,45,44,43,42,41,40, \
|
||||
39,38,37,36,35,34,33,32,31,30, \
|
||||
29,28,27,26,25,24,23,22,21,20, \
|
||||
19,18,17,16,15,14,13,12,11,10, \
|
||||
9,8,7,6,5,4,3,2,1,0
|
||||
#endif
|
||||
|
||||
// To be removed
|
||||
//------------- Binary constant -------------//
|
||||
#if defined(__GNUC__) && !defined(__CC_ARM)
|
||||
|
||||
#define TU_BIN8(x) ((uint8_t) (0b##x))
|
||||
#define TU_BIN16(b1, b2) ((uint16_t) (0b##b1##b2))
|
||||
#define TU_BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4))
|
||||
|
||||
#else
|
||||
|
||||
// internal macro of B8, B16, B32
|
||||
#define _B8__(x) (((x&0x0000000FUL)?1:0) \
|
||||
+((x&0x000000F0UL)?2:0) \
|
||||
+((x&0x00000F00UL)?4:0) \
|
||||
+((x&0x0000F000UL)?8:0) \
|
||||
+((x&0x000F0000UL)?16:0) \
|
||||
+((x&0x00F00000UL)?32:0) \
|
||||
+((x&0x0F000000UL)?64:0) \
|
||||
+((x&0xF0000000UL)?128:0))
|
||||
|
||||
#define TU_BIN8(d) ((uint8_t) _B8__(0x##d##UL))
|
||||
#define TU_BIN16(dmsb,dlsb) (((uint16_t)TU_BIN8(dmsb)<<8) + TU_BIN8(dlsb))
|
||||
#define TU_BIN32(dmsb,db2,db3,dlsb) \
|
||||
(((uint32_t)TU_BIN8(dmsb)<<24) \
|
||||
+ ((uint32_t)TU_BIN8(db2)<<16) \
|
||||
+ ((uint32_t)TU_BIN8(db3)<<8) \
|
||||
+ TU_BIN8(dlsb))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Debug Function
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// CFG_TUSB_DEBUG for debugging
|
||||
// 0 : no debug
|
||||
// 1 : print when there is error
|
||||
// 2 : print out log
|
||||
#if CFG_TUSB_DEBUG
|
||||
|
||||
void tu_print_mem(void const *buf, uint16_t count, uint8_t indent);
|
||||
|
||||
#ifndef tu_printf
|
||||
#define tu_printf printf
|
||||
#endif
|
||||
|
||||
// Log with debug level 1
|
||||
#define TU_LOG1 tu_printf
|
||||
#define TU_LOG1_MEM tu_print_mem
|
||||
#define TU_LOG1_LOCATION() tu_printf("%s: %d:\n", __PRETTY_FUNCTION__, __LINE__)
|
||||
|
||||
// Log with debug level 2
|
||||
#if CFG_TUSB_DEBUG > 1
|
||||
#define TU_LOG2 TU_LOG1
|
||||
#define TU_LOG2_MEM TU_LOG1_MEM
|
||||
#define TU_LOG2_LOCATION() TU_LOG1_LOCATION()
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t key;
|
||||
char const * data;
|
||||
}lookup_entry_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t count;
|
||||
lookup_entry_t const* items;
|
||||
} lookup_table_t;
|
||||
|
||||
static inline char const* lookup_find(lookup_table_t const* p_table, uint32_t key)
|
||||
{
|
||||
for(uint16_t i=0; i<p_table->count; i++)
|
||||
{
|
||||
if (p_table->items[i].key == key) return p_table->items[i].data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // CFG_TUSB_DEBUG
|
||||
|
||||
#ifndef TU_LOG1
|
||||
#define TU_LOG1(...)
|
||||
#define TU_LOG1_MEM(...)
|
||||
#endif
|
||||
|
||||
#ifndef TU_LOG2
|
||||
#define TU_LOG2(...)
|
||||
#define TU_LOG2_MEM(...)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_COMMON_H_ */
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common
|
||||
* \defgroup Group_CommonH common.h
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_COMMON_H_
|
||||
#define _TUSB_COMMON_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Macros Helper
|
||||
//--------------------------------------------------------------------+
|
||||
#define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
|
||||
#define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) )
|
||||
#define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) )
|
||||
|
||||
#define TU_U16_HIGH(u16) ((uint8_t) (((u16) >> 8) & 0x00ff))
|
||||
#define TU_U16_LOW(u16) ((uint8_t) ((u16) & 0x00ff))
|
||||
#define U16_TO_U8S_BE(u16) TU_U16_HIGH(u16), TU_U16_LOW(u16)
|
||||
#define U16_TO_U8S_LE(u16) TU_U16_LOW(u16), TU_U16_HIGH(u16)
|
||||
|
||||
#define U32_B1_U8(u32) ((uint8_t) (((u32) >> 24) & 0x000000ff)) // MSB
|
||||
#define U32_B2_U8(u32) ((uint8_t) (((u32) >> 16) & 0x000000ff))
|
||||
#define U32_B3_U8(u32) ((uint8_t) (((u32) >> 8) & 0x000000ff))
|
||||
#define U32_B4_U8(u32) ((uint8_t) ((u32) & 0x000000ff)) // LSB
|
||||
|
||||
#define U32_TO_U8S_BE(u32) U32_B1_U8(u32), U32_B2_U8(u32), U32_B3_U8(u32), U32_B4_U8(u32)
|
||||
#define U32_TO_U8S_LE(u32) U32_B4_U8(u32), U32_B3_U8(u32), U32_B2_U8(u32), U32_B1_U8(u32)
|
||||
|
||||
#define TU_BIT(n) (1U << (n))
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Includes
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Standard Headers
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Tinyusb Common Headers
|
||||
#include "tusb_option.h"
|
||||
#include "tusb_compiler.h"
|
||||
#include "tusb_verify.h"
|
||||
#include "tusb_error.h" // TODO remove
|
||||
#include "tusb_timeout.h"
|
||||
#include "tusb_types.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Inline Functions
|
||||
//--------------------------------------------------------------------+
|
||||
#define tu_memclr(buffer, size) memset((buffer), 0, (size))
|
||||
#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var)))
|
||||
|
||||
static inline uint32_t tu_u32(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4)
|
||||
{
|
||||
return ( ((uint32_t) b1) << 24) + ( ((uint32_t) b2) << 16) + ( ((uint32_t) b3) << 8) + b4;
|
||||
}
|
||||
|
||||
static inline uint16_t tu_u16(uint8_t high, uint8_t low)
|
||||
{
|
||||
return (uint16_t)((((uint16_t) high) << 8) + low);
|
||||
}
|
||||
|
||||
static inline uint8_t tu_u16_high(uint16_t u16) { return (uint8_t) (((uint16_t) (u16 >> 8)) & 0x00ff); }
|
||||
static inline uint8_t tu_u16_low (uint16_t u16) { return (uint8_t) (u16 & 0x00ff); }
|
||||
|
||||
// Min
|
||||
static inline uint8_t tu_min8 (uint8_t x, uint8_t y ) { return (x < y) ? x : y; }
|
||||
static inline uint16_t tu_min16 (uint16_t x, uint16_t y) { return (x < y) ? x : y; }
|
||||
static inline uint32_t tu_min32 (uint32_t x, uint32_t y) { return (x < y) ? x : y; }
|
||||
|
||||
// Max
|
||||
static inline uint8_t tu_max8 (uint8_t x, uint8_t y ) { return (x > y) ? x : y; }
|
||||
static inline uint16_t tu_max16 (uint16_t x, uint16_t y) { return (x > y) ? x : y; }
|
||||
static inline uint32_t tu_max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; }
|
||||
|
||||
// Align
|
||||
static inline uint32_t tu_align_n(uint32_t value, uint32_t alignment)
|
||||
{
|
||||
return value & ((uint32_t) ~(alignment-1));
|
||||
}
|
||||
|
||||
static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); }
|
||||
static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); }
|
||||
static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); }
|
||||
static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
|
||||
|
||||
//------------- Mathematics -------------//
|
||||
static inline uint32_t tu_abs(int32_t value) { return (uint32_t)((value < 0) ? (-value) : value); }
|
||||
|
||||
/// inclusive range checking
|
||||
static inline bool tu_within(uint32_t lower, uint32_t value, uint32_t upper)
|
||||
{
|
||||
return (lower <= value) && (value <= upper);
|
||||
}
|
||||
|
||||
// log2 of a value is its MSB's position
|
||||
// TODO use clz TODO remove
|
||||
static inline uint8_t tu_log2(uint32_t value)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
while (value >>= 1)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Bit
|
||||
static inline uint32_t tu_bit_set (uint32_t value, uint8_t pos) { return value | TU_BIT(pos); }
|
||||
static inline uint32_t tu_bit_clear(uint32_t value, uint8_t pos) { return value & (~TU_BIT(pos)); }
|
||||
static inline bool tu_bit_test (uint32_t value, uint8_t pos) { return (value & TU_BIT(pos)) ? true : false; }
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Count number of arguments of __VA_ARGS__
|
||||
* - reference https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s
|
||||
* - _GET_NTH_ARG() takes args >= N (64) but only expand to Nth one (64th)
|
||||
* - _RSEQ_N() is reverse sequential to N to add padding to have
|
||||
* Nth position is the same as the number of arguments
|
||||
* - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma)
|
||||
*------------------------------------------------------------------*/
|
||||
#ifndef TU_ARGS_NUM
|
||||
|
||||
#define TU_ARGS_NUM(...) NARG_(_0, ##__VA_ARGS__,_RSEQ_N())
|
||||
|
||||
#define NARG_(...) _GET_NTH_ARG(__VA_ARGS__)
|
||||
#define _GET_NTH_ARG( \
|
||||
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
|
||||
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
|
||||
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
|
||||
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
|
||||
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
|
||||
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
|
||||
_61,_62,_63,N,...) N
|
||||
#define _RSEQ_N() \
|
||||
62,61,60, \
|
||||
59,58,57,56,55,54,53,52,51,50, \
|
||||
49,48,47,46,45,44,43,42,41,40, \
|
||||
39,38,37,36,35,34,33,32,31,30, \
|
||||
29,28,27,26,25,24,23,22,21,20, \
|
||||
19,18,17,16,15,14,13,12,11,10, \
|
||||
9,8,7,6,5,4,3,2,1,0
|
||||
#endif
|
||||
|
||||
// To be removed
|
||||
//------------- Binary constant -------------//
|
||||
#if defined(__GNUC__) && !defined(__CC_ARM)
|
||||
|
||||
#define TU_BIN8(x) ((uint8_t) (0b##x))
|
||||
#define TU_BIN16(b1, b2) ((uint16_t) (0b##b1##b2))
|
||||
#define TU_BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4))
|
||||
|
||||
#else
|
||||
|
||||
// internal macro of B8, B16, B32
|
||||
#define _B8__(x) (((x&0x0000000FUL)?1:0) \
|
||||
+((x&0x000000F0UL)?2:0) \
|
||||
+((x&0x00000F00UL)?4:0) \
|
||||
+((x&0x0000F000UL)?8:0) \
|
||||
+((x&0x000F0000UL)?16:0) \
|
||||
+((x&0x00F00000UL)?32:0) \
|
||||
+((x&0x0F000000UL)?64:0) \
|
||||
+((x&0xF0000000UL)?128:0))
|
||||
|
||||
#define TU_BIN8(d) ((uint8_t) _B8__(0x##d##UL))
|
||||
#define TU_BIN16(dmsb,dlsb) (((uint16_t)TU_BIN8(dmsb)<<8) + TU_BIN8(dlsb))
|
||||
#define TU_BIN32(dmsb,db2,db3,dlsb) \
|
||||
(((uint32_t)TU_BIN8(dmsb)<<24) \
|
||||
+ ((uint32_t)TU_BIN8(db2)<<16) \
|
||||
+ ((uint32_t)TU_BIN8(db3)<<8) \
|
||||
+ TU_BIN8(dlsb))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Debug Function
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// CFG_TUSB_DEBUG for debugging
|
||||
// 0 : no debug
|
||||
// 1 : print when there is error
|
||||
// 2 : print out log
|
||||
#if CFG_TUSB_DEBUG
|
||||
|
||||
void tu_print_mem(void const *buf, uint16_t count, uint8_t indent);
|
||||
|
||||
#ifndef tu_printf
|
||||
#define tu_printf printf
|
||||
#endif
|
||||
|
||||
// Log with debug level 1
|
||||
#define TU_LOG1 tu_printf
|
||||
#define TU_LOG1_MEM tu_print_mem
|
||||
#define TU_LOG1_LOCATION() tu_printf("%s: %d:\n", __PRETTY_FUNCTION__, __LINE__)
|
||||
|
||||
// Log with debug level 2
|
||||
#if CFG_TUSB_DEBUG > 1
|
||||
#define TU_LOG2 TU_LOG1
|
||||
#define TU_LOG2_MEM TU_LOG1_MEM
|
||||
#define TU_LOG2_LOCATION() TU_LOG1_LOCATION()
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t key;
|
||||
char const * data;
|
||||
}lookup_entry_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t count;
|
||||
lookup_entry_t const* items;
|
||||
} lookup_table_t;
|
||||
|
||||
static inline char const* lookup_find(lookup_table_t const* p_table, uint32_t key)
|
||||
{
|
||||
for(uint16_t i=0; i<p_table->count; i++)
|
||||
{
|
||||
if (p_table->items[i].key == key) return p_table->items[i].data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // CFG_TUSB_DEBUG
|
||||
|
||||
#ifndef TU_LOG1
|
||||
#define TU_LOG1(...)
|
||||
#define TU_LOG1_MEM(...)
|
||||
#endif
|
||||
|
||||
#ifndef TU_LOG2
|
||||
#define TU_LOG2(...)
|
||||
#define TU_LOG2_MEM(...)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_COMMON_H_ */
|
||||
|
||||
/** @} */
|
||||
|
@ -1,140 +1,140 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common
|
||||
* \defgroup Group_Compiler Compiler
|
||||
* \brief Group_Compiler brief
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_COMPILER_H_
|
||||
#define _TUSB_COMPILER_H_
|
||||
|
||||
#define TU_STRING(x) #x ///< stringify without expand
|
||||
#define TU_XSTRING(x) TU_STRING(x) ///< expand then stringify
|
||||
#define TU_STRCAT(a, b) a##b ///< concat without expand
|
||||
#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat
|
||||
|
||||
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
|
||||
#define _TU_COUNTER_ __COUNTER__
|
||||
#else
|
||||
#define _TU_COUNTER_ __LINE__
|
||||
#endif
|
||||
|
||||
// Compile-time Assert
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define TU_VERIFY_STATIC _Static_assert
|
||||
#else
|
||||
#define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) }
|
||||
#endif
|
||||
|
||||
// for declaration of reserved field, make use of _TU_COUNTER_
|
||||
#define TU_RESERVED TU_XSTRCAT(reserved, _TU_COUNTER_)
|
||||
|
||||
#define TU_LITTLE_ENDIAN (0x12u)
|
||||
#define TU_BIG_ENDIAN (0x21u)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Compiler porting with Attribute and Endian
|
||||
//--------------------------------------------------------------------+
|
||||
#if defined(__GNUC__)
|
||||
#define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
|
||||
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
|
||||
#define TU_ATTR_PACKED __attribute__ ((packed))
|
||||
#define TU_ATTR_PREPACKED
|
||||
#define TU_ATTR_WEAK __attribute__ ((weak))
|
||||
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
|
||||
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
|
||||
#define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used
|
||||
|
||||
// Endian conversion use well-known host to network (big endian) naming
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define TU_BYTE_ORDER TU_LITTLE_ENDIAN
|
||||
#else
|
||||
#define TU_BYTE_ORDER TU_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#define TU_BSWAP16(u16) (__builtin_bswap16(u16))
|
||||
#define TU_BSWAP32(u32) (__builtin_bswap32(u32))
|
||||
|
||||
#elif defined(__TI_COMPILER_VERSION__)
|
||||
#define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
|
||||
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
|
||||
#define TU_ATTR_PACKED __attribute__ ((packed))
|
||||
#define TU_ATTR_PREPACKED
|
||||
#define TU_ATTR_WEAK __attribute__ ((weak))
|
||||
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
|
||||
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
|
||||
#define TU_ATTR_USED __attribute__ ((used))
|
||||
|
||||
// __BYTE_ORDER is defined in the TI ARM compiler, but not MSP430 (which is little endian)
|
||||
#if ((__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)) || defined(__MSP430__)
|
||||
#define TU_BYTE_ORDER TU_LITTLE_ENDIAN
|
||||
#else
|
||||
#define TU_BYTE_ORDER TU_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#define TU_BSWAP16(u16) (__builtin_bswap16(u16))
|
||||
#define TU_BSWAP32(u32) (__builtin_bswap32(u32))
|
||||
|
||||
#else
|
||||
#error "Compiler attribute porting is required"
|
||||
#endif
|
||||
|
||||
#if (TU_BYTE_ORDER == TU_LITTLE_ENDIAN)
|
||||
|
||||
#define tu_htons(u16) (TU_BSWAP16(u16))
|
||||
#define tu_ntohs(u16) (TU_BSWAP16(u16))
|
||||
|
||||
#define tu_htonl(u32) (TU_BSWAP32(u32))
|
||||
#define tu_ntohl(u32) (TU_BSWAP32(u32))
|
||||
|
||||
#define tu_htole16(u16) (u16)
|
||||
#define tu_le16toh(u16) (u16)
|
||||
|
||||
#define tu_htole32(u32) (u32)
|
||||
#define tu_le32toh(u32) (u32)
|
||||
|
||||
#elif (TU_BYTE_ORDER == TU_BIG_ENDIAN)
|
||||
|
||||
#define tu_htons(u16) (u16)
|
||||
#define tu_ntohs(u16) (u16)
|
||||
|
||||
#define tu_htonl(u32) (u32)
|
||||
#define tu_ntohl(u32) (u32)
|
||||
|
||||
#define tu_htole16(u16) (tu_bswap16(u16))
|
||||
#define tu_le16toh(u16) (tu_bswap16(u16))
|
||||
|
||||
#define tu_htole32(u32) (tu_bswap32(u32))
|
||||
#define tu_le32toh(u32) (tu_bswap32(u32))
|
||||
|
||||
#else
|
||||
#error Byte order is undefined
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_COMPILER_H_ */
|
||||
|
||||
/// @}
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common
|
||||
* \defgroup Group_Compiler Compiler
|
||||
* \brief Group_Compiler brief
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_COMPILER_H_
|
||||
#define _TUSB_COMPILER_H_
|
||||
|
||||
#define TU_STRING(x) #x ///< stringify without expand
|
||||
#define TU_XSTRING(x) TU_STRING(x) ///< expand then stringify
|
||||
#define TU_STRCAT(a, b) a##b ///< concat without expand
|
||||
#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat
|
||||
|
||||
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
|
||||
#define _TU_COUNTER_ __COUNTER__
|
||||
#else
|
||||
#define _TU_COUNTER_ __LINE__
|
||||
#endif
|
||||
|
||||
// Compile-time Assert
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define TU_VERIFY_STATIC _Static_assert
|
||||
#else
|
||||
#define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) }
|
||||
#endif
|
||||
|
||||
// for declaration of reserved field, make use of _TU_COUNTER_
|
||||
#define TU_RESERVED TU_XSTRCAT(reserved, _TU_COUNTER_)
|
||||
|
||||
#define TU_LITTLE_ENDIAN (0x12u)
|
||||
#define TU_BIG_ENDIAN (0x21u)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Compiler porting with Attribute and Endian
|
||||
//--------------------------------------------------------------------+
|
||||
#if defined(__GNUC__)
|
||||
#define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
|
||||
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
|
||||
#define TU_ATTR_PACKED __attribute__ ((packed))
|
||||
#define TU_ATTR_PREPACKED
|
||||
#define TU_ATTR_WEAK __attribute__ ((weak))
|
||||
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
|
||||
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
|
||||
#define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used
|
||||
|
||||
// Endian conversion use well-known host to network (big endian) naming
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define TU_BYTE_ORDER TU_LITTLE_ENDIAN
|
||||
#else
|
||||
#define TU_BYTE_ORDER TU_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#define TU_BSWAP16(u16) (__builtin_bswap16(u16))
|
||||
#define TU_BSWAP32(u32) (__builtin_bswap32(u32))
|
||||
|
||||
#elif defined(__TI_COMPILER_VERSION__)
|
||||
#define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
|
||||
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
|
||||
#define TU_ATTR_PACKED __attribute__ ((packed))
|
||||
#define TU_ATTR_PREPACKED
|
||||
#define TU_ATTR_WEAK __attribute__ ((weak))
|
||||
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
|
||||
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
|
||||
#define TU_ATTR_USED __attribute__ ((used))
|
||||
|
||||
// __BYTE_ORDER is defined in the TI ARM compiler, but not MSP430 (which is little endian)
|
||||
#if ((__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)) || defined(__MSP430__)
|
||||
#define TU_BYTE_ORDER TU_LITTLE_ENDIAN
|
||||
#else
|
||||
#define TU_BYTE_ORDER TU_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#define TU_BSWAP16(u16) (__builtin_bswap16(u16))
|
||||
#define TU_BSWAP32(u32) (__builtin_bswap32(u32))
|
||||
|
||||
#else
|
||||
#error "Compiler attribute porting is required"
|
||||
#endif
|
||||
|
||||
#if (TU_BYTE_ORDER == TU_LITTLE_ENDIAN)
|
||||
|
||||
#define tu_htons(u16) (TU_BSWAP16(u16))
|
||||
#define tu_ntohs(u16) (TU_BSWAP16(u16))
|
||||
|
||||
#define tu_htonl(u32) (TU_BSWAP32(u32))
|
||||
#define tu_ntohl(u32) (TU_BSWAP32(u32))
|
||||
|
||||
#define tu_htole16(u16) (u16)
|
||||
#define tu_le16toh(u16) (u16)
|
||||
|
||||
#define tu_htole32(u32) (u32)
|
||||
#define tu_le32toh(u32) (u32)
|
||||
|
||||
#elif (TU_BYTE_ORDER == TU_BIG_ENDIAN)
|
||||
|
||||
#define tu_htons(u16) (u16)
|
||||
#define tu_ntohs(u16) (u16)
|
||||
|
||||
#define tu_htonl(u32) (u32)
|
||||
#define tu_ntohl(u32) (u32)
|
||||
|
||||
#define tu_htole16(u16) (tu_bswap16(u16))
|
||||
#define tu_le16toh(u16) (tu_bswap16(u16))
|
||||
|
||||
#define tu_htole32(u32) (tu_bswap32(u32))
|
||||
#define tu_le32toh(u32) (tu_bswap32(u32))
|
||||
|
||||
#else
|
||||
#error Byte order is undefined
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_COMPILER_H_ */
|
||||
|
||||
/// @}
|
||||
|
@ -1,74 +1,74 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common
|
||||
* \defgroup Group_Error Error Codes
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_ERRORS_H_
|
||||
#define _TUSB_ERRORS_H_
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ERROR_ENUM(x) x,
|
||||
#define ERROR_STRING(x) #x,
|
||||
|
||||
#define ERROR_TABLE(ENTRY) \
|
||||
ENTRY(TUSB_ERROR_NONE )\
|
||||
ENTRY(TUSB_ERROR_INVALID_PARA )\
|
||||
ENTRY(TUSB_ERROR_DEVICE_NOT_READY )\
|
||||
ENTRY(TUSB_ERROR_INTERFACE_IS_BUSY )\
|
||||
ENTRY(TUSB_ERROR_HCD_OPEN_PIPE_FAILED )\
|
||||
ENTRY(TUSB_ERROR_OSAL_TIMEOUT )\
|
||||
ENTRY(TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED )\
|
||||
ENTRY(TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED )\
|
||||
ENTRY(TUSB_ERROR_NOT_SUPPORTED )\
|
||||
ENTRY(TUSB_ERROR_NOT_ENOUGH_MEMORY )\
|
||||
ENTRY(TUSB_ERROR_FAILED )\
|
||||
|
||||
/// \brief Error Code returned
|
||||
typedef enum
|
||||
{
|
||||
ERROR_TABLE(ERROR_ENUM)
|
||||
TUSB_ERROR_COUNT
|
||||
}tusb_error_t;
|
||||
|
||||
#if CFG_TUSB_DEBUG
|
||||
/// Enum to String for debugging purposes. Only available if \ref CFG_TUSB_DEBUG > 0
|
||||
extern char const* const tusb_strerr[TUSB_ERROR_COUNT];
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_ERRORS_H_ */
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common
|
||||
* \defgroup Group_Error Error Codes
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_ERRORS_H_
|
||||
#define _TUSB_ERRORS_H_
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ERROR_ENUM(x) x,
|
||||
#define ERROR_STRING(x) #x,
|
||||
|
||||
#define ERROR_TABLE(ENTRY) \
|
||||
ENTRY(TUSB_ERROR_NONE )\
|
||||
ENTRY(TUSB_ERROR_INVALID_PARA )\
|
||||
ENTRY(TUSB_ERROR_DEVICE_NOT_READY )\
|
||||
ENTRY(TUSB_ERROR_INTERFACE_IS_BUSY )\
|
||||
ENTRY(TUSB_ERROR_HCD_OPEN_PIPE_FAILED )\
|
||||
ENTRY(TUSB_ERROR_OSAL_TIMEOUT )\
|
||||
ENTRY(TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED )\
|
||||
ENTRY(TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED )\
|
||||
ENTRY(TUSB_ERROR_NOT_SUPPORTED )\
|
||||
ENTRY(TUSB_ERROR_NOT_ENOUGH_MEMORY )\
|
||||
ENTRY(TUSB_ERROR_FAILED )\
|
||||
|
||||
/// \brief Error Code returned
|
||||
typedef enum
|
||||
{
|
||||
ERROR_TABLE(ERROR_ENUM)
|
||||
TUSB_ERROR_COUNT
|
||||
}tusb_error_t;
|
||||
|
||||
#if CFG_TUSB_DEBUG
|
||||
/// Enum to String for debugging purposes. Only available if \ref CFG_TUSB_DEBUG > 0
|
||||
extern char const* const tusb_strerr[TUSB_ERROR_COUNT];
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_ERRORS_H_ */
|
||||
|
||||
/** @} */
|
||||
|
@ -1,288 +1,288 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "osal/osal.h"
|
||||
#include "tusb_fifo.h"
|
||||
|
||||
// implement mutex lock and unlock
|
||||
#if CFG_FIFO_MUTEX
|
||||
|
||||
static void tu_fifo_lock(tu_fifo_t *f)
|
||||
{
|
||||
if (f->mutex)
|
||||
{
|
||||
osal_mutex_lock(f->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
static void tu_fifo_unlock(tu_fifo_t *f)
|
||||
{
|
||||
if (f->mutex)
|
||||
{
|
||||
osal_mutex_unlock(f->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define tu_fifo_lock(_ff)
|
||||
#define tu_fifo_unlock(_ff)
|
||||
|
||||
#endif
|
||||
|
||||
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable)
|
||||
{
|
||||
tu_fifo_lock(f);
|
||||
|
||||
f->buffer = (uint8_t*) buffer;
|
||||
f->depth = depth;
|
||||
f->item_size = item_size;
|
||||
f->overwritable = overwritable;
|
||||
|
||||
f->rd_idx = f->wr_idx = f->count = 0;
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// retrieve data from fifo
|
||||
static void _tu_ff_pull(tu_fifo_t* f, void * buffer)
|
||||
{
|
||||
memcpy(buffer,
|
||||
f->buffer + (f->rd_idx * f->item_size),
|
||||
f->item_size);
|
||||
|
||||
f->rd_idx = (f->rd_idx + 1) % f->depth;
|
||||
f->count--;
|
||||
}
|
||||
|
||||
// send data to fifo
|
||||
static void _tu_ff_push(tu_fifo_t* f, void const * data)
|
||||
{
|
||||
memcpy( f->buffer + (f->wr_idx * f->item_size),
|
||||
data,
|
||||
f->item_size);
|
||||
|
||||
f->wr_idx = (f->wr_idx + 1) % f->depth;
|
||||
|
||||
if (tu_fifo_full(f))
|
||||
{
|
||||
f->rd_idx = f->wr_idx; // keep the full state (rd == wr && len = size)
|
||||
}
|
||||
else
|
||||
{
|
||||
f->count++;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Read one byte out of the RX buffer.
|
||||
|
||||
This function will return the byte located at the array index of the
|
||||
read pointer, and then increment the read pointer index. If the read
|
||||
pointer exceeds the maximum buffer size, it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] buffer
|
||||
Pointer to the place holder for data read from the buffer
|
||||
|
||||
@returns TRUE if the queue is not empty
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool tu_fifo_read(tu_fifo_t* f, void * buffer)
|
||||
{
|
||||
if( tu_fifo_empty(f) ) return false;
|
||||
|
||||
tu_fifo_lock(f);
|
||||
|
||||
_tu_ff_pull(f, buffer);
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief This function will read n elements into the array index specified by
|
||||
the write pointer and increment the write index. If the write index
|
||||
exceeds the max buffer size, then it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] buffer
|
||||
The pointer to data location
|
||||
@param[in] count
|
||||
Number of element that buffer can afford
|
||||
|
||||
@returns number of items read from the FIFO
|
||||
*/
|
||||
/******************************************************************************/
|
||||
uint16_t tu_fifo_read_n (tu_fifo_t* f, void * buffer, uint16_t count)
|
||||
{
|
||||
if( tu_fifo_empty(f) ) return 0;
|
||||
|
||||
tu_fifo_lock(f);
|
||||
|
||||
/* Limit up to fifo's count */
|
||||
if ( count > f->count ) count = f->count;
|
||||
|
||||
uint8_t* buf8 = (uint8_t*) buffer;
|
||||
uint16_t len = 0;
|
||||
|
||||
while (len < count)
|
||||
{
|
||||
_tu_ff_pull(f, buf8);
|
||||
|
||||
len++;
|
||||
buf8 += f->item_size;
|
||||
}
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Reads one item without removing it from the FIFO
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] pos
|
||||
Position to read from in the FIFO buffer
|
||||
@param[in] p_buffer
|
||||
Pointer to the place holder for data read from the buffer
|
||||
|
||||
@returns TRUE if the queue is not empty
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t pos, void * p_buffer)
|
||||
{
|
||||
if ( pos >= f->count ) return false;
|
||||
|
||||
// rd_idx is pos=0
|
||||
uint16_t index = (f->rd_idx + pos) % f->depth;
|
||||
memcpy(p_buffer,
|
||||
f->buffer + (index * f->item_size),
|
||||
f->item_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Write one element into the RX buffer.
|
||||
|
||||
This function will write one element into the array index specified by
|
||||
the write pointer and increment the write index. If the write index
|
||||
exceeds the max buffer size, then it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] data
|
||||
The byte to add to the FIFO
|
||||
|
||||
@returns TRUE if the data was written to the FIFO (overwrittable
|
||||
FIFO will always return TRUE)
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool tu_fifo_write (tu_fifo_t* f, const void * data)
|
||||
{
|
||||
if ( tu_fifo_full(f) && !f->overwritable ) return false;
|
||||
|
||||
tu_fifo_lock(f);
|
||||
|
||||
_tu_ff_push(f, data);
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief This function will write n elements into the array index specified by
|
||||
the write pointer and increment the write index. If the write index
|
||||
exceeds the max buffer size, then it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] data
|
||||
The pointer to data to add to the FIFO
|
||||
@param[in] count
|
||||
Number of element
|
||||
@return Number of written elements
|
||||
*/
|
||||
/******************************************************************************/
|
||||
uint16_t tu_fifo_write_n (tu_fifo_t* f, const void * data, uint16_t count)
|
||||
{
|
||||
if ( count == 0 ) return 0;
|
||||
|
||||
tu_fifo_lock(f);
|
||||
|
||||
// Not overwritable limit up to full
|
||||
if (!f->overwritable) count = tu_min16(count, tu_fifo_remaining(f));
|
||||
|
||||
uint8_t const* buf8 = (uint8_t const*) data;
|
||||
uint16_t len = 0;
|
||||
|
||||
while (len < count)
|
||||
{
|
||||
_tu_ff_push(f, buf8);
|
||||
|
||||
len++;
|
||||
buf8 += f->item_size;
|
||||
}
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Clear the fifo read and write pointers and set length to zero
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool tu_fifo_clear(tu_fifo_t *f)
|
||||
{
|
||||
tu_fifo_lock(f);
|
||||
|
||||
f->rd_idx = f->wr_idx = f->count = 0;
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "osal/osal.h"
|
||||
#include "tusb_fifo.h"
|
||||
|
||||
// implement mutex lock and unlock
|
||||
#if CFG_FIFO_MUTEX
|
||||
|
||||
static void tu_fifo_lock(tu_fifo_t *f)
|
||||
{
|
||||
if (f->mutex)
|
||||
{
|
||||
osal_mutex_lock(f->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
static void tu_fifo_unlock(tu_fifo_t *f)
|
||||
{
|
||||
if (f->mutex)
|
||||
{
|
||||
osal_mutex_unlock(f->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define tu_fifo_lock(_ff)
|
||||
#define tu_fifo_unlock(_ff)
|
||||
|
||||
#endif
|
||||
|
||||
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable)
|
||||
{
|
||||
tu_fifo_lock(f);
|
||||
|
||||
f->buffer = (uint8_t*) buffer;
|
||||
f->depth = depth;
|
||||
f->item_size = item_size;
|
||||
f->overwritable = overwritable;
|
||||
|
||||
f->rd_idx = f->wr_idx = f->count = 0;
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// retrieve data from fifo
|
||||
static void _tu_ff_pull(tu_fifo_t* f, void * buffer)
|
||||
{
|
||||
memcpy(buffer,
|
||||
f->buffer + (f->rd_idx * f->item_size),
|
||||
f->item_size);
|
||||
|
||||
f->rd_idx = (f->rd_idx + 1) % f->depth;
|
||||
f->count--;
|
||||
}
|
||||
|
||||
// send data to fifo
|
||||
static void _tu_ff_push(tu_fifo_t* f, void const * data)
|
||||
{
|
||||
memcpy( f->buffer + (f->wr_idx * f->item_size),
|
||||
data,
|
||||
f->item_size);
|
||||
|
||||
f->wr_idx = (f->wr_idx + 1) % f->depth;
|
||||
|
||||
if (tu_fifo_full(f))
|
||||
{
|
||||
f->rd_idx = f->wr_idx; // keep the full state (rd == wr && len = size)
|
||||
}
|
||||
else
|
||||
{
|
||||
f->count++;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Read one byte out of the RX buffer.
|
||||
|
||||
This function will return the byte located at the array index of the
|
||||
read pointer, and then increment the read pointer index. If the read
|
||||
pointer exceeds the maximum buffer size, it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] buffer
|
||||
Pointer to the place holder for data read from the buffer
|
||||
|
||||
@returns TRUE if the queue is not empty
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool tu_fifo_read(tu_fifo_t* f, void * buffer)
|
||||
{
|
||||
if( tu_fifo_empty(f) ) return false;
|
||||
|
||||
tu_fifo_lock(f);
|
||||
|
||||
_tu_ff_pull(f, buffer);
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief This function will read n elements into the array index specified by
|
||||
the write pointer and increment the write index. If the write index
|
||||
exceeds the max buffer size, then it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] buffer
|
||||
The pointer to data location
|
||||
@param[in] count
|
||||
Number of element that buffer can afford
|
||||
|
||||
@returns number of items read from the FIFO
|
||||
*/
|
||||
/******************************************************************************/
|
||||
uint16_t tu_fifo_read_n (tu_fifo_t* f, void * buffer, uint16_t count)
|
||||
{
|
||||
if( tu_fifo_empty(f) ) return 0;
|
||||
|
||||
tu_fifo_lock(f);
|
||||
|
||||
/* Limit up to fifo's count */
|
||||
if ( count > f->count ) count = f->count;
|
||||
|
||||
uint8_t* buf8 = (uint8_t*) buffer;
|
||||
uint16_t len = 0;
|
||||
|
||||
while (len < count)
|
||||
{
|
||||
_tu_ff_pull(f, buf8);
|
||||
|
||||
len++;
|
||||
buf8 += f->item_size;
|
||||
}
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Reads one item without removing it from the FIFO
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] pos
|
||||
Position to read from in the FIFO buffer
|
||||
@param[in] p_buffer
|
||||
Pointer to the place holder for data read from the buffer
|
||||
|
||||
@returns TRUE if the queue is not empty
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t pos, void * p_buffer)
|
||||
{
|
||||
if ( pos >= f->count ) return false;
|
||||
|
||||
// rd_idx is pos=0
|
||||
uint16_t index = (f->rd_idx + pos) % f->depth;
|
||||
memcpy(p_buffer,
|
||||
f->buffer + (index * f->item_size),
|
||||
f->item_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Write one element into the RX buffer.
|
||||
|
||||
This function will write one element into the array index specified by
|
||||
the write pointer and increment the write index. If the write index
|
||||
exceeds the max buffer size, then it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] data
|
||||
The byte to add to the FIFO
|
||||
|
||||
@returns TRUE if the data was written to the FIFO (overwrittable
|
||||
FIFO will always return TRUE)
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool tu_fifo_write (tu_fifo_t* f, const void * data)
|
||||
{
|
||||
if ( tu_fifo_full(f) && !f->overwritable ) return false;
|
||||
|
||||
tu_fifo_lock(f);
|
||||
|
||||
_tu_ff_push(f, data);
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief This function will write n elements into the array index specified by
|
||||
the write pointer and increment the write index. If the write index
|
||||
exceeds the max buffer size, then it will roll over to zero.
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] data
|
||||
The pointer to data to add to the FIFO
|
||||
@param[in] count
|
||||
Number of element
|
||||
@return Number of written elements
|
||||
*/
|
||||
/******************************************************************************/
|
||||
uint16_t tu_fifo_write_n (tu_fifo_t* f, const void * data, uint16_t count)
|
||||
{
|
||||
if ( count == 0 ) return 0;
|
||||
|
||||
tu_fifo_lock(f);
|
||||
|
||||
// Not overwritable limit up to full
|
||||
if (!f->overwritable) count = tu_min16(count, tu_fifo_remaining(f));
|
||||
|
||||
uint8_t const* buf8 = (uint8_t const*) data;
|
||||
uint16_t len = 0;
|
||||
|
||||
while (len < count)
|
||||
{
|
||||
_tu_ff_push(f, buf8);
|
||||
|
||||
len++;
|
||||
buf8 += f->item_size;
|
||||
}
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Clear the fifo read and write pointers and set length to zero
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
*/
|
||||
/******************************************************************************/
|
||||
bool tu_fifo_clear(tu_fifo_t *f)
|
||||
{
|
||||
tu_fifo_lock(f);
|
||||
|
||||
f->rd_idx = f->wr_idx = f->count = 0;
|
||||
|
||||
tu_fifo_unlock(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,131 +1,131 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common
|
||||
* \defgroup group_fifo fifo
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_FIFO_H_
|
||||
#define _TUSB_FIFO_H_
|
||||
|
||||
// mutex is only needed for RTOS
|
||||
// for OS None, we don't get preempted
|
||||
#define CFG_FIFO_MUTEX (CFG_TUSB_OS != OPT_OS_NONE)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
#define tu_fifo_mutex_t osal_mutex_t
|
||||
#endif
|
||||
|
||||
|
||||
/** \struct tu_fifo_t
|
||||
* \brief Simple Circular FIFO
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t* buffer ; ///< buffer pointer
|
||||
uint16_t depth ; ///< max items
|
||||
uint16_t item_size ; ///< size of each item
|
||||
bool overwritable ;
|
||||
|
||||
volatile uint16_t count ; ///< number of items in queue
|
||||
volatile uint16_t wr_idx ; ///< write pointer
|
||||
volatile uint16_t rd_idx ; ///< read pointer
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
tu_fifo_mutex_t mutex;
|
||||
#endif
|
||||
|
||||
} tu_fifo_t;
|
||||
|
||||
#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
|
||||
uint8_t _name##_buf[_depth*sizeof(_type)]; \
|
||||
tu_fifo_t _name = { \
|
||||
.buffer = _name##_buf, \
|
||||
.depth = _depth, \
|
||||
.item_size = sizeof(_type), \
|
||||
.overwritable = _overwritable, \
|
||||
}
|
||||
|
||||
bool tu_fifo_clear(tu_fifo_t *f);
|
||||
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
static inline void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t mutex_hdl)
|
||||
{
|
||||
f->mutex = mutex_hdl;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool tu_fifo_write (tu_fifo_t* f, void const * p_data);
|
||||
uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t count);
|
||||
|
||||
bool tu_fifo_read (tu_fifo_t* f, void * p_buffer);
|
||||
uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t count);
|
||||
|
||||
bool tu_fifo_peek_at (tu_fifo_t* f, uint16_t pos, void * p_buffer);
|
||||
|
||||
static inline bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer)
|
||||
{
|
||||
return tu_fifo_peek_at(f, 0, p_buffer);
|
||||
}
|
||||
|
||||
static inline bool tu_fifo_empty(tu_fifo_t* f)
|
||||
{
|
||||
return (f->count == 0);
|
||||
}
|
||||
|
||||
static inline bool tu_fifo_full(tu_fifo_t* f)
|
||||
{
|
||||
return (f->count == f->depth);
|
||||
}
|
||||
|
||||
static inline uint16_t tu_fifo_count(tu_fifo_t* f)
|
||||
{
|
||||
return f->count;
|
||||
}
|
||||
|
||||
static inline uint16_t tu_fifo_remaining(tu_fifo_t* f)
|
||||
{
|
||||
return f->depth - f->count;
|
||||
}
|
||||
|
||||
static inline uint16_t tu_fifo_depth(tu_fifo_t* f)
|
||||
{
|
||||
return f->depth;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_FIFO_H_ */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common
|
||||
* \defgroup group_fifo fifo
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_FIFO_H_
|
||||
#define _TUSB_FIFO_H_
|
||||
|
||||
// mutex is only needed for RTOS
|
||||
// for OS None, we don't get preempted
|
||||
#define CFG_FIFO_MUTEX (CFG_TUSB_OS != OPT_OS_NONE)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
#define tu_fifo_mutex_t osal_mutex_t
|
||||
#endif
|
||||
|
||||
|
||||
/** \struct tu_fifo_t
|
||||
* \brief Simple Circular FIFO
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t* buffer ; ///< buffer pointer
|
||||
uint16_t depth ; ///< max items
|
||||
uint16_t item_size ; ///< size of each item
|
||||
bool overwritable ;
|
||||
|
||||
volatile uint16_t count ; ///< number of items in queue
|
||||
volatile uint16_t wr_idx ; ///< write pointer
|
||||
volatile uint16_t rd_idx ; ///< read pointer
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
tu_fifo_mutex_t mutex;
|
||||
#endif
|
||||
|
||||
} tu_fifo_t;
|
||||
|
||||
#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
|
||||
uint8_t _name##_buf[_depth*sizeof(_type)]; \
|
||||
tu_fifo_t _name = { \
|
||||
.buffer = _name##_buf, \
|
||||
.depth = _depth, \
|
||||
.item_size = sizeof(_type), \
|
||||
.overwritable = _overwritable, \
|
||||
}
|
||||
|
||||
bool tu_fifo_clear(tu_fifo_t *f);
|
||||
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
static inline void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t mutex_hdl)
|
||||
{
|
||||
f->mutex = mutex_hdl;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool tu_fifo_write (tu_fifo_t* f, void const * p_data);
|
||||
uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t count);
|
||||
|
||||
bool tu_fifo_read (tu_fifo_t* f, void * p_buffer);
|
||||
uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t count);
|
||||
|
||||
bool tu_fifo_peek_at (tu_fifo_t* f, uint16_t pos, void * p_buffer);
|
||||
|
||||
static inline bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer)
|
||||
{
|
||||
return tu_fifo_peek_at(f, 0, p_buffer);
|
||||
}
|
||||
|
||||
static inline bool tu_fifo_empty(tu_fifo_t* f)
|
||||
{
|
||||
return (f->count == 0);
|
||||
}
|
||||
|
||||
static inline bool tu_fifo_full(tu_fifo_t* f)
|
||||
{
|
||||
return (f->count == f->depth);
|
||||
}
|
||||
|
||||
static inline uint16_t tu_fifo_count(tu_fifo_t* f)
|
||||
{
|
||||
return f->count;
|
||||
}
|
||||
|
||||
static inline uint16_t tu_fifo_remaining(tu_fifo_t* f)
|
||||
{
|
||||
return f->depth - f->count;
|
||||
}
|
||||
|
||||
static inline uint16_t tu_fifo_depth(tu_fifo_t* f)
|
||||
{
|
||||
return f->depth;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_FIFO_H_ */
|
||||
|
@ -1,80 +1,80 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common Common Files
|
||||
* \defgroup Group_TimeoutTimer timeout timer
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_TIMEOUT_H_
|
||||
#define _TUSB_TIMEOUT_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t start;
|
||||
uint32_t interval;
|
||||
}tu_timeout_t;
|
||||
|
||||
#if 0
|
||||
|
||||
extern uint32_t tusb_hal_millis(void);
|
||||
|
||||
static inline void tu_timeout_set(tu_timeout_t* tt, uint32_t msec)
|
||||
{
|
||||
tt->interval = msec;
|
||||
tt->start = tusb_hal_millis();
|
||||
}
|
||||
|
||||
static inline bool tu_timeout_expired(tu_timeout_t* tt)
|
||||
{
|
||||
return ( tusb_hal_millis() - tt->start ) >= tt->interval;
|
||||
}
|
||||
|
||||
// For used with periodic event to prevent drift
|
||||
static inline void tu_timeout_reset(tu_timeout_t* tt)
|
||||
{
|
||||
tt->start += tt->interval;
|
||||
}
|
||||
|
||||
static inline void tu_timeout_restart(tu_timeout_t* tt)
|
||||
{
|
||||
tt->start = tusb_hal_millis();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_TIMEOUT_H_ */
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common Common Files
|
||||
* \defgroup Group_TimeoutTimer timeout timer
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_TIMEOUT_H_
|
||||
#define _TUSB_TIMEOUT_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t start;
|
||||
uint32_t interval;
|
||||
}tu_timeout_t;
|
||||
|
||||
#if 0
|
||||
|
||||
extern uint32_t tusb_hal_millis(void);
|
||||
|
||||
static inline void tu_timeout_set(tu_timeout_t* tt, uint32_t msec)
|
||||
{
|
||||
tt->interval = msec;
|
||||
tt->start = tusb_hal_millis();
|
||||
}
|
||||
|
||||
static inline bool tu_timeout_expired(tu_timeout_t* tt)
|
||||
{
|
||||
return ( tusb_hal_millis() - tt->start ) >= tt->interval;
|
||||
}
|
||||
|
||||
// For used with periodic event to prevent drift
|
||||
static inline void tu_timeout_reset(tu_timeout_t* tt)
|
||||
{
|
||||
tt->start += tt->interval;
|
||||
}
|
||||
|
||||
static inline void tu_timeout_restart(tu_timeout_t* tt)
|
||||
{
|
||||
tt->start = tusb_hal_millis();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_TIMEOUT_H_ */
|
||||
|
||||
/** @} */
|
||||
|
@ -1,481 +1,481 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_usb_definitions
|
||||
* \defgroup USBDef_Type USB Types
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_TYPES_H_
|
||||
#define _TUSB_TYPES_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "tusb_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* CONSTANTS
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
/// defined base on EHCI specs value for Endpoint Speed
|
||||
typedef enum
|
||||
{
|
||||
TUSB_SPEED_FULL = 0,
|
||||
TUSB_SPEED_LOW ,
|
||||
TUSB_SPEED_HIGH
|
||||
}tusb_speed_t;
|
||||
|
||||
/// defined base on USB Specs Endpoint's bmAttributes
|
||||
typedef enum
|
||||
{
|
||||
TUSB_XFER_CONTROL = 0 ,
|
||||
TUSB_XFER_ISOCHRONOUS ,
|
||||
TUSB_XFER_BULK ,
|
||||
TUSB_XFER_INTERRUPT
|
||||
}tusb_xfer_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_DIR_OUT = 0,
|
||||
TUSB_DIR_IN = 1,
|
||||
|
||||
TUSB_DIR_IN_MASK = 0x80
|
||||
}tusb_dir_t;
|
||||
|
||||
/// USB Descriptor Types
|
||||
typedef enum
|
||||
{
|
||||
TUSB_DESC_DEVICE = 0x01,
|
||||
TUSB_DESC_CONFIGURATION = 0x02,
|
||||
TUSB_DESC_STRING = 0x03,
|
||||
TUSB_DESC_INTERFACE = 0x04,
|
||||
TUSB_DESC_ENDPOINT = 0x05,
|
||||
TUSB_DESC_DEVICE_QUALIFIER = 0x06,
|
||||
TUSB_DESC_OTHER_SPEED_CONFIG = 0x07,
|
||||
TUSB_DESC_INTERFACE_POWER = 0x08,
|
||||
TUSB_DESC_OTG = 0x09,
|
||||
TUSB_DESC_DEBUG = 0x0A,
|
||||
TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B,
|
||||
|
||||
TUSB_DESC_BOS = 0x0F,
|
||||
TUSB_DESC_DEVICE_CAPABILITY = 0x10,
|
||||
|
||||
TUSB_DESC_FUNCTIONAL = 0x21,
|
||||
|
||||
// Class Specific Descriptor
|
||||
TUSB_DESC_CS_DEVICE = 0x21,
|
||||
TUSB_DESC_CS_CONFIGURATION = 0x22,
|
||||
TUSB_DESC_CS_STRING = 0x23,
|
||||
TUSB_DESC_CS_INTERFACE = 0x24,
|
||||
TUSB_DESC_CS_ENDPOINT = 0x25,
|
||||
|
||||
TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION = 0x30,
|
||||
TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31
|
||||
}tusb_desc_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_GET_STATUS = 0 ,
|
||||
TUSB_REQ_CLEAR_FEATURE = 1 ,
|
||||
TUSB_REQ_RESERVED = 2 ,
|
||||
TUSB_REQ_SET_FEATURE = 3 ,
|
||||
TUSB_REQ_RESERVED2 = 4 ,
|
||||
TUSB_REQ_SET_ADDRESS = 5 ,
|
||||
TUSB_REQ_GET_DESCRIPTOR = 6 ,
|
||||
TUSB_REQ_SET_DESCRIPTOR = 7 ,
|
||||
TUSB_REQ_GET_CONFIGURATION = 8 ,
|
||||
TUSB_REQ_SET_CONFIGURATION = 9 ,
|
||||
TUSB_REQ_GET_INTERFACE = 10 ,
|
||||
TUSB_REQ_SET_INTERFACE = 11 ,
|
||||
TUSB_REQ_SYNCH_FRAME = 12
|
||||
}tusb_request_code_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_FEATURE_EDPT_HALT = 0,
|
||||
TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1,
|
||||
TUSB_REQ_FEATURE_TEST_MODE = 2
|
||||
}tusb_request_feature_selector_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_TYPE_STANDARD = 0,
|
||||
TUSB_REQ_TYPE_CLASS,
|
||||
TUSB_REQ_TYPE_VENDOR,
|
||||
TUSB_REQ_TYPE_INVALID
|
||||
} tusb_request_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_RCPT_DEVICE =0,
|
||||
TUSB_REQ_RCPT_INTERFACE,
|
||||
TUSB_REQ_RCPT_ENDPOINT,
|
||||
TUSB_REQ_RCPT_OTHER
|
||||
} tusb_request_recipient_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_CLASS_UNSPECIFIED = 0 ,
|
||||
TUSB_CLASS_AUDIO = 1 ,
|
||||
TUSB_CLASS_CDC = 2 ,
|
||||
TUSB_CLASS_HID = 3 ,
|
||||
TUSB_CLASS_RESERVED_4 = 4 ,
|
||||
TUSB_CLASS_PHYSICAL = 5 ,
|
||||
TUSB_CLASS_IMAGE = 6 ,
|
||||
TUSB_CLASS_PRINTER = 7 ,
|
||||
TUSB_CLASS_MSC = 8 ,
|
||||
TUSB_CLASS_HUB = 9 ,
|
||||
TUSB_CLASS_CDC_DATA = 10 ,
|
||||
TUSB_CLASS_SMART_CARD = 11 ,
|
||||
TUSB_CLASS_RESERVED_12 = 12 ,
|
||||
TUSB_CLASS_CONTENT_SECURITY = 13 ,
|
||||
TUSB_CLASS_VIDEO = 14 ,
|
||||
TUSB_CLASS_PERSONAL_HEALTHCARE = 15 ,
|
||||
TUSB_CLASS_AUDIO_VIDEO = 16 ,
|
||||
|
||||
TUSB_CLASS_DIAGNOSTIC = 0xDC ,
|
||||
TUSB_CLASS_WIRELESS_CONTROLLER = 0xE0 ,
|
||||
TUSB_CLASS_MISC = 0xEF ,
|
||||
TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE ,
|
||||
TUSB_CLASS_VENDOR_SPECIFIC = 0xFF
|
||||
}tusb_class_code_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MISC_SUBCLASS_COMMON = 2
|
||||
}misc_subclass_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MISC_PROTOCOL_IAD = 1
|
||||
}misc_protocol_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DEVICE_CAPABILITY_WIRELESS_USB = 0x01,
|
||||
DEVICE_CAPABILITY_USB20_EXTENSION = 0x02,
|
||||
DEVICE_CAPABILITY_SUPERSPEED_USB = 0x03,
|
||||
DEVICE_CAPABILITY_CONTAINER_id = 0x04,
|
||||
DEVICE_CAPABILITY_PLATFORM = 0x05,
|
||||
DEVICE_CAPABILITY_POWER_DELIVERY = 0x06,
|
||||
DEVICE_CAPABILITY_BATTERY_INFO = 0x07,
|
||||
DEVICE_CAPABILITY_PD_CONSUMER_PORT = 0x08,
|
||||
DEVICE_CAPABILITY_PD_PROVIDER_PORT = 0x09,
|
||||
DEVICE_CAPABILITY_SUPERSPEED_PLUS = 0x0A,
|
||||
DEVICE_CAPABILITY_PRECESION_TIME_MEASUREMENT = 0x0B,
|
||||
DEVICE_CAPABILITY_WIRELESS_USB_EXT = 0x0C,
|
||||
DEVICE_CAPABILITY_BILLBOARD = 0x0D,
|
||||
DEVICE_CAPABILITY_AUTHENTICATION = 0x0E,
|
||||
DEVICE_CAPABILITY_BILLBOARD_EX = 0x0F,
|
||||
DEVICE_CAPABILITY_CONFIGURATION_SUMMARY = 0x10
|
||||
}device_capability_type_t;
|
||||
|
||||
enum {
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5),
|
||||
TUSB_DESC_CONFIG_ATT_SELF_POWERED = TU_BIT(6),
|
||||
};
|
||||
|
||||
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
|
||||
|
||||
/// Device State TODO remove
|
||||
typedef enum
|
||||
{
|
||||
TUSB_DEVICE_STATE_UNPLUG = 0 ,
|
||||
TUSB_DEVICE_STATE_CONFIGURED ,
|
||||
TUSB_DEVICE_STATE_SUSPENDED ,
|
||||
}tusb_device_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XFER_RESULT_SUCCESS,
|
||||
XFER_RESULT_FAILED,
|
||||
XFER_RESULT_STALLED,
|
||||
}xfer_result_t;
|
||||
|
||||
enum // TODO remove
|
||||
{
|
||||
DESC_OFFSET_LEN = 0,
|
||||
DESC_OFFSET_TYPE = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
INTERFACE_INVALID_NUMBER = 0xff
|
||||
};
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00,
|
||||
MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01,
|
||||
MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02,
|
||||
MS_OS_20_FEATURE_COMPATBLE_ID = 0x03,
|
||||
MS_OS_20_FEATURE_REG_PROPERTY = 0x04,
|
||||
MS_OS_20_FEATURE_MIN_RESUME_TIME = 0x05,
|
||||
MS_OS_20_FEATURE_MODEL_ID = 0x06,
|
||||
MS_OS_20_FEATURE_CCGP_DEVICE = 0x07,
|
||||
MS_OS_20_FEATURE_VENDOR_REVISION = 0x08
|
||||
} microsoft_os_20_type_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USB Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// USB Device Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes.
|
||||
uint8_t bDescriptorType ; ///< DEVICE Descriptor Type.
|
||||
uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant.
|
||||
|
||||
uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific.
|
||||
uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
|
||||
uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis.
|
||||
uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64.
|
||||
|
||||
uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF).
|
||||
uint16_t idProduct ; ///< Product ID (assigned by the manufacturer).
|
||||
uint16_t bcdDevice ; ///< Device release number in binary-coded decimal.
|
||||
uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer.
|
||||
uint8_t iProduct ; ///< Index of string descriptor describing product.
|
||||
uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number.
|
||||
|
||||
uint8_t bNumConfigurations ; ///< Number of possible configurations.
|
||||
} tusb_desc_device_t;
|
||||
|
||||
// USB Binary Device Object Store (BOS) Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type
|
||||
uint16_t wTotalLength ; ///< Total length of data returned for this descriptor
|
||||
uint8_t bNumDeviceCaps ; ///< Number of device capability descriptors in the BOS
|
||||
} tusb_desc_bos_t;
|
||||
|
||||
/// USB Configuration Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type
|
||||
uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration.
|
||||
|
||||
uint8_t bNumInterfaces ; ///< Number of interfaces supported by this configuration
|
||||
uint8_t bConfigurationValue ; ///< Value to use as an argument to the SetConfiguration() request to select this configuration.
|
||||
uint8_t iConfiguration ; ///< Index of string descriptor describing this configuration
|
||||
uint8_t bmAttributes ; ///< Configuration characteristics \n D7: Reserved (set to one)\n D6: Self-powered \n D5: Remote Wakeup \n D4...0: Reserved (reset to zero) \n D7 is reserved and must be set to one for historical reasons. \n A device configuration that uses power from the bus and a local source reports a non-zero value in bMaxPower to indicate the amount of bus power required and sets D6. The actual power source at runtime may be determined using the GetStatus(DEVICE) request (see USB 2.0 spec Section 9.4.5). \n If a device configuration supports remote wakeup, D5 is set to one.
|
||||
uint8_t bMaxPower ; ///< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (i.e., 50 = 100 mA).
|
||||
} tusb_desc_configuration_t;
|
||||
|
||||
/// USB Interface Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type
|
||||
|
||||
uint8_t bInterfaceNumber ; ///< Number of this interface. Zero-based value identifying the index in the array of concurrent interfaces supported by this configuration.
|
||||
uint8_t bAlternateSetting ; ///< Value used to select this alternate setting for the interface identified in the prior field
|
||||
uint8_t bNumEndpoints ; ///< Number of endpoints used by this interface (excluding endpoint zero). If this value is zero, this interface only uses the Default Control Pipe.
|
||||
uint8_t bInterfaceClass ; ///< Class code (assigned by the USB-IF). \li A value of zero is reserved for future standardization. \li If this field is set to FFH, the interface class is vendor-specific. \li All other values are reserved for assignment by the USB-IF.
|
||||
uint8_t bInterfaceSubClass ; ///< Subclass code (assigned by the USB-IF). \n These codes are qualified by the value of the bInterfaceClass field. \li If the bInterfaceClass field is reset to zero, this field must also be reset to zero. \li If the bInterfaceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
|
||||
uint8_t bInterfaceProtocol ; ///< Protocol code (assigned by the USB). \n These codes are qualified by the value of the bInterfaceClass and the bInterfaceSubClass fields. If an interface supports class-specific requests, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use a class-specific protocol on this interface. \li If this field is set to FFH, the device uses a vendor-specific protocol for this interface.
|
||||
uint8_t iInterface ; ///< Index of string descriptor describing this interface
|
||||
} tusb_desc_interface_t;
|
||||
|
||||
/// USB Endpoint Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< ENDPOINT Descriptor Type
|
||||
|
||||
uint8_t bEndpointAddress ; ///< The address of the endpoint on the USB device described by this descriptor. The address is encoded as follows: \n Bit 3...0: The endpoint number \n Bit 6...4: Reserved, reset to zero \n Bit 7: Direction, ignored for control endpoints 0 = OUT endpoint 1 = IN endpoint.
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint8_t xfer : 2;
|
||||
uint8_t sync : 2;
|
||||
uint8_t usage : 2;
|
||||
uint8_t : 2;
|
||||
} bmAttributes ; ///< This field describes the endpoint's attributes when it is configured using the bConfigurationValue. \n Bits 1..0: Transfer Type \n- 00 = Control \n- 01 = Isochronous \n- 10 = Bulk \n- 11 = Interrupt \n If not an isochronous endpoint, bits 5..2 are reserved and must be set to zero. If isochronous, they are defined as follows: \n Bits 3..2: Synchronization Type \n- 00 = No Synchronization \n- 01 = Asynchronous \n- 10 = Adaptive \n- 11 = Synchronous \n Bits 5..4: Usage Type \n- 00 = Data endpoint \n- 01 = Feedback endpoint \n- 10 = Implicit feedback Data endpoint \n- 11 = Reserved \n Refer to Chapter 5 of USB 2.0 specification for more information. \n All other bits are reserved and must be reset to zero. Reserved bits must be ignored by the host.
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t size : 11; ///< Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. \n For isochronous endpoints, this value is used to reserve the bus time in the schedule, required for the per-(micro)frame data payloads. The pipe may, on an ongoing basis, actually use less bandwidth than that reserved. The device reports, if necessary, the actual bandwidth used via its normal, non-USB defined mechanisms. \n For all endpoints, bits 10..0 specify the maximum packet size (in bytes). \n For high-speed isochronous and interrupt endpoints: \n Bits 12..11 specify the number of additional transaction opportunities per microframe: \n- 00 = None (1 transaction per microframe) \n- 01 = 1 additional (2 per microframe) \n- 10 = 2 additional (3 per microframe) \n- 11 = Reserved \n Bits 15..13 are reserved and must be set to zero.
|
||||
uint16_t hs_period_mult : 2;
|
||||
uint16_t : 0;
|
||||
}wMaxPacketSize;
|
||||
|
||||
uint8_t bInterval ; ///< Interval for polling endpoint for data transfers. Expressed in frames or microframes depending on the device operating speed (i.e., either 1 millisecond or 125 us units). \n- For full-/high-speed isochronous endpoints, this value must be in the range from 1 to 16. The bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$). \n- For full-/low-speed interrupt endpoints, the value of this field may be from 1 to 255. \n- For high-speed interrupt endpoints, the bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$) . This value must be from 1 to 16. \n- For high-speed bulk/control OUT endpoints, the bInterval must specify the maximum NAK rate of the endpoint. A value of 0 indicates the endpoint never NAKs. Other values indicate at most 1 NAK each bInterval number of microframes. This value must be in the range from 0 to 255. \n Refer to Chapter 5 of USB 2.0 specification for more information.
|
||||
} tusb_desc_endpoint_t;
|
||||
|
||||
/// USB Other Speed Configuration Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
uint16_t wTotalLength ; ///< Total length of data returned
|
||||
|
||||
uint8_t bNumInterfaces ; ///< Number of interfaces supported by this speed configuration
|
||||
uint8_t bConfigurationValue ; ///< Value to use to select configuration
|
||||
uint8_t IConfiguration ; ///< Index of string descriptor
|
||||
uint8_t bmAttributes ; ///< Same as Configuration descriptor
|
||||
uint8_t bMaxPower ; ///< Same as Configuration descriptor
|
||||
} tusb_desc_other_speed_t;
|
||||
|
||||
/// USB Device Qualifier Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Device Qualifier Type
|
||||
uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00)
|
||||
|
||||
uint8_t bDeviceClass ; ///< Class Code
|
||||
uint8_t bDeviceSubClass ; ///< SubClass Code
|
||||
uint8_t bDeviceProtocol ; ///< Protocol Code
|
||||
uint8_t bMaxPacketSize0 ; ///< Maximum packet size for other speed
|
||||
uint8_t bNumConfigurations ; ///< Number of Other-speed Configurations
|
||||
uint8_t bReserved ; ///< Reserved for future use, must be zero
|
||||
} tusb_desc_device_qualifier_t;
|
||||
|
||||
/// USB Interface Association Descriptor (IAD ECN)
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
|
||||
uint8_t bFirstInterface ; ///< Index of the first associated interface.
|
||||
uint8_t bInterfaceCount ; ///< Total number of associated interfaces.
|
||||
|
||||
uint8_t bFunctionClass ; ///< Interface class ID.
|
||||
uint8_t bFunctionSubClass ; ///< Interface subclass ID.
|
||||
uint8_t bFunctionProtocol ; ///< Interface protocol ID.
|
||||
|
||||
uint8_t iFunction ; ///< Index of the string descriptor describing the interface association.
|
||||
} tusb_desc_interface_assoc_t;
|
||||
|
||||
// USB String Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< Descriptor Type
|
||||
uint16_t unicode_string[];
|
||||
} tusb_desc_string_t;
|
||||
|
||||
// USB Binary Device Object Store (BOS)
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType ;
|
||||
uint8_t bDevCapabilityType;
|
||||
uint8_t bReserved;
|
||||
uint8_t PlatformCapabilityUUID[16];
|
||||
uint8_t CapabilityData[];
|
||||
} tusb_desc_bos_platform_t;
|
||||
|
||||
// USB WebuSB URL Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bScheme;
|
||||
char url[];
|
||||
} tusb_desc_webusb_url_t;
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Types
|
||||
*------------------------------------------------------------------*/
|
||||
typedef struct TU_ATTR_PACKED{
|
||||
union {
|
||||
struct TU_ATTR_PACKED {
|
||||
uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
|
||||
uint8_t type : 2; ///< Request type tusb_request_type_t.
|
||||
uint8_t direction : 1; ///< Direction type. tusb_dir_t
|
||||
} bmRequestType_bit;
|
||||
|
||||
uint8_t bmRequestType;
|
||||
};
|
||||
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} tusb_control_request_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "mostly compiler option issue");
|
||||
|
||||
// TODO move to somewhere suitable
|
||||
static inline uint8_t bm_request_type(uint8_t direction, uint8_t type, uint8_t recipient)
|
||||
{
|
||||
return ((uint8_t) (direction << 7)) | ((uint8_t) (type << 5)) | (recipient);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Get direction from Endpoint address
|
||||
static inline tusb_dir_t tu_edpt_dir(uint8_t addr)
|
||||
{
|
||||
return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
|
||||
}
|
||||
|
||||
// Get Endpoint number from address
|
||||
static inline uint8_t tu_edpt_number(uint8_t addr)
|
||||
{
|
||||
return (uint8_t)(addr & (~TUSB_DIR_IN_MASK));
|
||||
}
|
||||
|
||||
static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)
|
||||
{
|
||||
return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Descriptor helper
|
||||
//--------------------------------------------------------------------+
|
||||
static inline uint8_t const * tu_desc_next(void const* desc)
|
||||
{
|
||||
uint8_t const* desc8 = (uint8_t const*) desc;
|
||||
return desc8 + desc8[DESC_OFFSET_LEN];
|
||||
}
|
||||
|
||||
static inline uint8_t tu_desc_type(void const* desc)
|
||||
{
|
||||
return ((uint8_t const*) desc)[DESC_OFFSET_TYPE];
|
||||
}
|
||||
|
||||
static inline uint8_t tu_desc_len(void const* desc)
|
||||
{
|
||||
return ((uint8_t const*) desc)[DESC_OFFSET_LEN];
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_TYPES_H_ */
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_usb_definitions
|
||||
* \defgroup USBDef_Type USB Types
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_TYPES_H_
|
||||
#define _TUSB_TYPES_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "tusb_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* CONSTANTS
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
/// defined base on EHCI specs value for Endpoint Speed
|
||||
typedef enum
|
||||
{
|
||||
TUSB_SPEED_FULL = 0,
|
||||
TUSB_SPEED_LOW ,
|
||||
TUSB_SPEED_HIGH
|
||||
}tusb_speed_t;
|
||||
|
||||
/// defined base on USB Specs Endpoint's bmAttributes
|
||||
typedef enum
|
||||
{
|
||||
TUSB_XFER_CONTROL = 0 ,
|
||||
TUSB_XFER_ISOCHRONOUS ,
|
||||
TUSB_XFER_BULK ,
|
||||
TUSB_XFER_INTERRUPT
|
||||
}tusb_xfer_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_DIR_OUT = 0,
|
||||
TUSB_DIR_IN = 1,
|
||||
|
||||
TUSB_DIR_IN_MASK = 0x80
|
||||
}tusb_dir_t;
|
||||
|
||||
/// USB Descriptor Types
|
||||
typedef enum
|
||||
{
|
||||
TUSB_DESC_DEVICE = 0x01,
|
||||
TUSB_DESC_CONFIGURATION = 0x02,
|
||||
TUSB_DESC_STRING = 0x03,
|
||||
TUSB_DESC_INTERFACE = 0x04,
|
||||
TUSB_DESC_ENDPOINT = 0x05,
|
||||
TUSB_DESC_DEVICE_QUALIFIER = 0x06,
|
||||
TUSB_DESC_OTHER_SPEED_CONFIG = 0x07,
|
||||
TUSB_DESC_INTERFACE_POWER = 0x08,
|
||||
TUSB_DESC_OTG = 0x09,
|
||||
TUSB_DESC_DEBUG = 0x0A,
|
||||
TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B,
|
||||
|
||||
TUSB_DESC_BOS = 0x0F,
|
||||
TUSB_DESC_DEVICE_CAPABILITY = 0x10,
|
||||
|
||||
TUSB_DESC_FUNCTIONAL = 0x21,
|
||||
|
||||
// Class Specific Descriptor
|
||||
TUSB_DESC_CS_DEVICE = 0x21,
|
||||
TUSB_DESC_CS_CONFIGURATION = 0x22,
|
||||
TUSB_DESC_CS_STRING = 0x23,
|
||||
TUSB_DESC_CS_INTERFACE = 0x24,
|
||||
TUSB_DESC_CS_ENDPOINT = 0x25,
|
||||
|
||||
TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION = 0x30,
|
||||
TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31
|
||||
}tusb_desc_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_GET_STATUS = 0 ,
|
||||
TUSB_REQ_CLEAR_FEATURE = 1 ,
|
||||
TUSB_REQ_RESERVED = 2 ,
|
||||
TUSB_REQ_SET_FEATURE = 3 ,
|
||||
TUSB_REQ_RESERVED2 = 4 ,
|
||||
TUSB_REQ_SET_ADDRESS = 5 ,
|
||||
TUSB_REQ_GET_DESCRIPTOR = 6 ,
|
||||
TUSB_REQ_SET_DESCRIPTOR = 7 ,
|
||||
TUSB_REQ_GET_CONFIGURATION = 8 ,
|
||||
TUSB_REQ_SET_CONFIGURATION = 9 ,
|
||||
TUSB_REQ_GET_INTERFACE = 10 ,
|
||||
TUSB_REQ_SET_INTERFACE = 11 ,
|
||||
TUSB_REQ_SYNCH_FRAME = 12
|
||||
}tusb_request_code_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_FEATURE_EDPT_HALT = 0,
|
||||
TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1,
|
||||
TUSB_REQ_FEATURE_TEST_MODE = 2
|
||||
}tusb_request_feature_selector_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_TYPE_STANDARD = 0,
|
||||
TUSB_REQ_TYPE_CLASS,
|
||||
TUSB_REQ_TYPE_VENDOR,
|
||||
TUSB_REQ_TYPE_INVALID
|
||||
} tusb_request_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_RCPT_DEVICE =0,
|
||||
TUSB_REQ_RCPT_INTERFACE,
|
||||
TUSB_REQ_RCPT_ENDPOINT,
|
||||
TUSB_REQ_RCPT_OTHER
|
||||
} tusb_request_recipient_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_CLASS_UNSPECIFIED = 0 ,
|
||||
TUSB_CLASS_AUDIO = 1 ,
|
||||
TUSB_CLASS_CDC = 2 ,
|
||||
TUSB_CLASS_HID = 3 ,
|
||||
TUSB_CLASS_RESERVED_4 = 4 ,
|
||||
TUSB_CLASS_PHYSICAL = 5 ,
|
||||
TUSB_CLASS_IMAGE = 6 ,
|
||||
TUSB_CLASS_PRINTER = 7 ,
|
||||
TUSB_CLASS_MSC = 8 ,
|
||||
TUSB_CLASS_HUB = 9 ,
|
||||
TUSB_CLASS_CDC_DATA = 10 ,
|
||||
TUSB_CLASS_SMART_CARD = 11 ,
|
||||
TUSB_CLASS_RESERVED_12 = 12 ,
|
||||
TUSB_CLASS_CONTENT_SECURITY = 13 ,
|
||||
TUSB_CLASS_VIDEO = 14 ,
|
||||
TUSB_CLASS_PERSONAL_HEALTHCARE = 15 ,
|
||||
TUSB_CLASS_AUDIO_VIDEO = 16 ,
|
||||
|
||||
TUSB_CLASS_DIAGNOSTIC = 0xDC ,
|
||||
TUSB_CLASS_WIRELESS_CONTROLLER = 0xE0 ,
|
||||
TUSB_CLASS_MISC = 0xEF ,
|
||||
TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE ,
|
||||
TUSB_CLASS_VENDOR_SPECIFIC = 0xFF
|
||||
}tusb_class_code_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MISC_SUBCLASS_COMMON = 2
|
||||
}misc_subclass_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MISC_PROTOCOL_IAD = 1
|
||||
}misc_protocol_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DEVICE_CAPABILITY_WIRELESS_USB = 0x01,
|
||||
DEVICE_CAPABILITY_USB20_EXTENSION = 0x02,
|
||||
DEVICE_CAPABILITY_SUPERSPEED_USB = 0x03,
|
||||
DEVICE_CAPABILITY_CONTAINER_id = 0x04,
|
||||
DEVICE_CAPABILITY_PLATFORM = 0x05,
|
||||
DEVICE_CAPABILITY_POWER_DELIVERY = 0x06,
|
||||
DEVICE_CAPABILITY_BATTERY_INFO = 0x07,
|
||||
DEVICE_CAPABILITY_PD_CONSUMER_PORT = 0x08,
|
||||
DEVICE_CAPABILITY_PD_PROVIDER_PORT = 0x09,
|
||||
DEVICE_CAPABILITY_SUPERSPEED_PLUS = 0x0A,
|
||||
DEVICE_CAPABILITY_PRECESION_TIME_MEASUREMENT = 0x0B,
|
||||
DEVICE_CAPABILITY_WIRELESS_USB_EXT = 0x0C,
|
||||
DEVICE_CAPABILITY_BILLBOARD = 0x0D,
|
||||
DEVICE_CAPABILITY_AUTHENTICATION = 0x0E,
|
||||
DEVICE_CAPABILITY_BILLBOARD_EX = 0x0F,
|
||||
DEVICE_CAPABILITY_CONFIGURATION_SUMMARY = 0x10
|
||||
}device_capability_type_t;
|
||||
|
||||
enum {
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5),
|
||||
TUSB_DESC_CONFIG_ATT_SELF_POWERED = TU_BIT(6),
|
||||
};
|
||||
|
||||
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
|
||||
|
||||
/// Device State TODO remove
|
||||
typedef enum
|
||||
{
|
||||
TUSB_DEVICE_STATE_UNPLUG = 0 ,
|
||||
TUSB_DEVICE_STATE_CONFIGURED ,
|
||||
TUSB_DEVICE_STATE_SUSPENDED ,
|
||||
}tusb_device_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XFER_RESULT_SUCCESS,
|
||||
XFER_RESULT_FAILED,
|
||||
XFER_RESULT_STALLED,
|
||||
}xfer_result_t;
|
||||
|
||||
enum // TODO remove
|
||||
{
|
||||
DESC_OFFSET_LEN = 0,
|
||||
DESC_OFFSET_TYPE = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
INTERFACE_INVALID_NUMBER = 0xff
|
||||
};
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00,
|
||||
MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01,
|
||||
MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02,
|
||||
MS_OS_20_FEATURE_COMPATBLE_ID = 0x03,
|
||||
MS_OS_20_FEATURE_REG_PROPERTY = 0x04,
|
||||
MS_OS_20_FEATURE_MIN_RESUME_TIME = 0x05,
|
||||
MS_OS_20_FEATURE_MODEL_ID = 0x06,
|
||||
MS_OS_20_FEATURE_CCGP_DEVICE = 0x07,
|
||||
MS_OS_20_FEATURE_VENDOR_REVISION = 0x08
|
||||
} microsoft_os_20_type_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USB Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// USB Device Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes.
|
||||
uint8_t bDescriptorType ; ///< DEVICE Descriptor Type.
|
||||
uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant.
|
||||
|
||||
uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific.
|
||||
uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
|
||||
uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis.
|
||||
uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64.
|
||||
|
||||
uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF).
|
||||
uint16_t idProduct ; ///< Product ID (assigned by the manufacturer).
|
||||
uint16_t bcdDevice ; ///< Device release number in binary-coded decimal.
|
||||
uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer.
|
||||
uint8_t iProduct ; ///< Index of string descriptor describing product.
|
||||
uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number.
|
||||
|
||||
uint8_t bNumConfigurations ; ///< Number of possible configurations.
|
||||
} tusb_desc_device_t;
|
||||
|
||||
// USB Binary Device Object Store (BOS) Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type
|
||||
uint16_t wTotalLength ; ///< Total length of data returned for this descriptor
|
||||
uint8_t bNumDeviceCaps ; ///< Number of device capability descriptors in the BOS
|
||||
} tusb_desc_bos_t;
|
||||
|
||||
/// USB Configuration Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type
|
||||
uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration.
|
||||
|
||||
uint8_t bNumInterfaces ; ///< Number of interfaces supported by this configuration
|
||||
uint8_t bConfigurationValue ; ///< Value to use as an argument to the SetConfiguration() request to select this configuration.
|
||||
uint8_t iConfiguration ; ///< Index of string descriptor describing this configuration
|
||||
uint8_t bmAttributes ; ///< Configuration characteristics \n D7: Reserved (set to one)\n D6: Self-powered \n D5: Remote Wakeup \n D4...0: Reserved (reset to zero) \n D7 is reserved and must be set to one for historical reasons. \n A device configuration that uses power from the bus and a local source reports a non-zero value in bMaxPower to indicate the amount of bus power required and sets D6. The actual power source at runtime may be determined using the GetStatus(DEVICE) request (see USB 2.0 spec Section 9.4.5). \n If a device configuration supports remote wakeup, D5 is set to one.
|
||||
uint8_t bMaxPower ; ///< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (i.e., 50 = 100 mA).
|
||||
} tusb_desc_configuration_t;
|
||||
|
||||
/// USB Interface Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type
|
||||
|
||||
uint8_t bInterfaceNumber ; ///< Number of this interface. Zero-based value identifying the index in the array of concurrent interfaces supported by this configuration.
|
||||
uint8_t bAlternateSetting ; ///< Value used to select this alternate setting for the interface identified in the prior field
|
||||
uint8_t bNumEndpoints ; ///< Number of endpoints used by this interface (excluding endpoint zero). If this value is zero, this interface only uses the Default Control Pipe.
|
||||
uint8_t bInterfaceClass ; ///< Class code (assigned by the USB-IF). \li A value of zero is reserved for future standardization. \li If this field is set to FFH, the interface class is vendor-specific. \li All other values are reserved for assignment by the USB-IF.
|
||||
uint8_t bInterfaceSubClass ; ///< Subclass code (assigned by the USB-IF). \n These codes are qualified by the value of the bInterfaceClass field. \li If the bInterfaceClass field is reset to zero, this field must also be reset to zero. \li If the bInterfaceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
|
||||
uint8_t bInterfaceProtocol ; ///< Protocol code (assigned by the USB). \n These codes are qualified by the value of the bInterfaceClass and the bInterfaceSubClass fields. If an interface supports class-specific requests, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use a class-specific protocol on this interface. \li If this field is set to FFH, the device uses a vendor-specific protocol for this interface.
|
||||
uint8_t iInterface ; ///< Index of string descriptor describing this interface
|
||||
} tusb_desc_interface_t;
|
||||
|
||||
/// USB Endpoint Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< ENDPOINT Descriptor Type
|
||||
|
||||
uint8_t bEndpointAddress ; ///< The address of the endpoint on the USB device described by this descriptor. The address is encoded as follows: \n Bit 3...0: The endpoint number \n Bit 6...4: Reserved, reset to zero \n Bit 7: Direction, ignored for control endpoints 0 = OUT endpoint 1 = IN endpoint.
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint8_t xfer : 2;
|
||||
uint8_t sync : 2;
|
||||
uint8_t usage : 2;
|
||||
uint8_t : 2;
|
||||
} bmAttributes ; ///< This field describes the endpoint's attributes when it is configured using the bConfigurationValue. \n Bits 1..0: Transfer Type \n- 00 = Control \n- 01 = Isochronous \n- 10 = Bulk \n- 11 = Interrupt \n If not an isochronous endpoint, bits 5..2 are reserved and must be set to zero. If isochronous, they are defined as follows: \n Bits 3..2: Synchronization Type \n- 00 = No Synchronization \n- 01 = Asynchronous \n- 10 = Adaptive \n- 11 = Synchronous \n Bits 5..4: Usage Type \n- 00 = Data endpoint \n- 01 = Feedback endpoint \n- 10 = Implicit feedback Data endpoint \n- 11 = Reserved \n Refer to Chapter 5 of USB 2.0 specification for more information. \n All other bits are reserved and must be reset to zero. Reserved bits must be ignored by the host.
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t size : 11; ///< Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. \n For isochronous endpoints, this value is used to reserve the bus time in the schedule, required for the per-(micro)frame data payloads. The pipe may, on an ongoing basis, actually use less bandwidth than that reserved. The device reports, if necessary, the actual bandwidth used via its normal, non-USB defined mechanisms. \n For all endpoints, bits 10..0 specify the maximum packet size (in bytes). \n For high-speed isochronous and interrupt endpoints: \n Bits 12..11 specify the number of additional transaction opportunities per microframe: \n- 00 = None (1 transaction per microframe) \n- 01 = 1 additional (2 per microframe) \n- 10 = 2 additional (3 per microframe) \n- 11 = Reserved \n Bits 15..13 are reserved and must be set to zero.
|
||||
uint16_t hs_period_mult : 2;
|
||||
uint16_t : 0;
|
||||
}wMaxPacketSize;
|
||||
|
||||
uint8_t bInterval ; ///< Interval for polling endpoint for data transfers. Expressed in frames or microframes depending on the device operating speed (i.e., either 1 millisecond or 125 us units). \n- For full-/high-speed isochronous endpoints, this value must be in the range from 1 to 16. The bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$). \n- For full-/low-speed interrupt endpoints, the value of this field may be from 1 to 255. \n- For high-speed interrupt endpoints, the bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$) . This value must be from 1 to 16. \n- For high-speed bulk/control OUT endpoints, the bInterval must specify the maximum NAK rate of the endpoint. A value of 0 indicates the endpoint never NAKs. Other values indicate at most 1 NAK each bInterval number of microframes. This value must be in the range from 0 to 255. \n Refer to Chapter 5 of USB 2.0 specification for more information.
|
||||
} tusb_desc_endpoint_t;
|
||||
|
||||
/// USB Other Speed Configuration Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
uint16_t wTotalLength ; ///< Total length of data returned
|
||||
|
||||
uint8_t bNumInterfaces ; ///< Number of interfaces supported by this speed configuration
|
||||
uint8_t bConfigurationValue ; ///< Value to use to select configuration
|
||||
uint8_t IConfiguration ; ///< Index of string descriptor
|
||||
uint8_t bmAttributes ; ///< Same as Configuration descriptor
|
||||
uint8_t bMaxPower ; ///< Same as Configuration descriptor
|
||||
} tusb_desc_other_speed_t;
|
||||
|
||||
/// USB Device Qualifier Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Device Qualifier Type
|
||||
uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00)
|
||||
|
||||
uint8_t bDeviceClass ; ///< Class Code
|
||||
uint8_t bDeviceSubClass ; ///< SubClass Code
|
||||
uint8_t bDeviceProtocol ; ///< Protocol Code
|
||||
uint8_t bMaxPacketSize0 ; ///< Maximum packet size for other speed
|
||||
uint8_t bNumConfigurations ; ///< Number of Other-speed Configurations
|
||||
uint8_t bReserved ; ///< Reserved for future use, must be zero
|
||||
} tusb_desc_device_qualifier_t;
|
||||
|
||||
/// USB Interface Association Descriptor (IAD ECN)
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
|
||||
uint8_t bFirstInterface ; ///< Index of the first associated interface.
|
||||
uint8_t bInterfaceCount ; ///< Total number of associated interfaces.
|
||||
|
||||
uint8_t bFunctionClass ; ///< Interface class ID.
|
||||
uint8_t bFunctionSubClass ; ///< Interface subclass ID.
|
||||
uint8_t bFunctionProtocol ; ///< Interface protocol ID.
|
||||
|
||||
uint8_t iFunction ; ///< Index of the string descriptor describing the interface association.
|
||||
} tusb_desc_interface_assoc_t;
|
||||
|
||||
// USB String Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< Descriptor Type
|
||||
uint16_t unicode_string[];
|
||||
} tusb_desc_string_t;
|
||||
|
||||
// USB Binary Device Object Store (BOS)
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType ;
|
||||
uint8_t bDevCapabilityType;
|
||||
uint8_t bReserved;
|
||||
uint8_t PlatformCapabilityUUID[16];
|
||||
uint8_t CapabilityData[];
|
||||
} tusb_desc_bos_platform_t;
|
||||
|
||||
// USB WebuSB URL Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bScheme;
|
||||
char url[];
|
||||
} tusb_desc_webusb_url_t;
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Types
|
||||
*------------------------------------------------------------------*/
|
||||
typedef struct TU_ATTR_PACKED{
|
||||
union {
|
||||
struct TU_ATTR_PACKED {
|
||||
uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
|
||||
uint8_t type : 2; ///< Request type tusb_request_type_t.
|
||||
uint8_t direction : 1; ///< Direction type. tusb_dir_t
|
||||
} bmRequestType_bit;
|
||||
|
||||
uint8_t bmRequestType;
|
||||
};
|
||||
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} tusb_control_request_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "mostly compiler option issue");
|
||||
|
||||
// TODO move to somewhere suitable
|
||||
static inline uint8_t bm_request_type(uint8_t direction, uint8_t type, uint8_t recipient)
|
||||
{
|
||||
return ((uint8_t) (direction << 7)) | ((uint8_t) (type << 5)) | (recipient);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Get direction from Endpoint address
|
||||
static inline tusb_dir_t tu_edpt_dir(uint8_t addr)
|
||||
{
|
||||
return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
|
||||
}
|
||||
|
||||
// Get Endpoint number from address
|
||||
static inline uint8_t tu_edpt_number(uint8_t addr)
|
||||
{
|
||||
return (uint8_t)(addr & (~TUSB_DIR_IN_MASK));
|
||||
}
|
||||
|
||||
static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)
|
||||
{
|
||||
return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Descriptor helper
|
||||
//--------------------------------------------------------------------+
|
||||
static inline uint8_t const * tu_desc_next(void const* desc)
|
||||
{
|
||||
uint8_t const* desc8 = (uint8_t const*) desc;
|
||||
return desc8 + desc8[DESC_OFFSET_LEN];
|
||||
}
|
||||
|
||||
static inline uint8_t tu_desc_type(void const* desc)
|
||||
{
|
||||
return ((uint8_t const*) desc)[DESC_OFFSET_TYPE];
|
||||
}
|
||||
|
||||
static inline uint8_t tu_desc_len(void const* desc)
|
||||
{
|
||||
return ((uint8_t const*) desc)[DESC_OFFSET_LEN];
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_TYPES_H_ */
|
||||
|
||||
/** @} */
|
||||
|
302
src/device/dcd.h
302
src/device/dcd.h
@ -1,151 +1,151 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_usbd
|
||||
* \defgroup group_dcd Device Controller Driver (DCD)
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_DCD_H_
|
||||
#define _TUSB_DCD_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DCD_EVENT_INVALID = 0,
|
||||
DCD_EVENT_BUS_RESET,
|
||||
DCD_EVENT_UNPLUGGED,
|
||||
DCD_EVENT_SOF,
|
||||
DCD_EVENT_SUSPEND, // TODO LPM Sleep L1 support
|
||||
DCD_EVENT_RESUME,
|
||||
|
||||
DCD_EVENT_SETUP_RECEIVED,
|
||||
DCD_EVENT_XFER_COMPLETE,
|
||||
|
||||
// Not an DCD event, just a convenient way to defer ISR function
|
||||
USBD_EVENT_FUNC_CALL,
|
||||
|
||||
DCD_EVENT_COUNT
|
||||
} dcd_eventid_t;
|
||||
|
||||
typedef struct TU_ATTR_ALIGNED(4)
|
||||
{
|
||||
uint8_t rhport;
|
||||
uint8_t event_id;
|
||||
|
||||
union {
|
||||
// USBD_EVT_SETUP_RECEIVED
|
||||
tusb_control_request_t setup_received;
|
||||
|
||||
// USBD_EVT_XFER_COMPLETE
|
||||
struct {
|
||||
uint8_t ep_addr;
|
||||
uint8_t result;
|
||||
uint32_t len;
|
||||
}xfer_complete;
|
||||
|
||||
// USBD_EVENT_FUNC_CALL
|
||||
struct {
|
||||
void (*func) (void*);
|
||||
void* param;
|
||||
}func_call;
|
||||
};
|
||||
} dcd_event_t;
|
||||
|
||||
//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct");
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Device API
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
// Initialize controller to device mode
|
||||
void dcd_init (uint8_t rhport);
|
||||
|
||||
// Interrupt Handler
|
||||
void dcd_isr (uint8_t rhport);
|
||||
|
||||
// Enable device interrupt
|
||||
void dcd_int_enable (uint8_t rhport);
|
||||
|
||||
// Disable device interrupt
|
||||
void dcd_int_disable(uint8_t rhport);
|
||||
|
||||
// Receive Set Address request, mcu port must also include status IN response
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr);
|
||||
|
||||
// Receive Set Configure request
|
||||
void dcd_set_config (uint8_t rhport, uint8_t config_num);
|
||||
|
||||
// Wake up host
|
||||
void dcd_remote_wakeup(uint8_t rhport);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when a control transfer's status stage is complete.
|
||||
// May help DCD to prepare for next control transfer, this API is optional.
|
||||
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK;
|
||||
|
||||
// Configure endpoint's registers according to descriptor
|
||||
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
|
||||
|
||||
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
|
||||
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
|
||||
|
||||
// Stall endpoint
|
||||
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr);
|
||||
|
||||
// clear stall, data toggle is also reset to DATA0
|
||||
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Event API (Implemented by device stack)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Called by DCD to notify device stack
|
||||
extern void dcd_event_handler(dcd_event_t const * event, bool in_isr);
|
||||
|
||||
// helper to send bus signal event
|
||||
extern void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr);
|
||||
|
||||
// helper to send setup received
|
||||
extern void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr);
|
||||
|
||||
// helper to send transfer complete event
|
||||
extern void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_DCD_H_ */
|
||||
|
||||
/// @}
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_usbd
|
||||
* \defgroup group_dcd Device Controller Driver (DCD)
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_DCD_H_
|
||||
#define _TUSB_DCD_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DCD_EVENT_INVALID = 0,
|
||||
DCD_EVENT_BUS_RESET,
|
||||
DCD_EVENT_UNPLUGGED,
|
||||
DCD_EVENT_SOF,
|
||||
DCD_EVENT_SUSPEND, // TODO LPM Sleep L1 support
|
||||
DCD_EVENT_RESUME,
|
||||
|
||||
DCD_EVENT_SETUP_RECEIVED,
|
||||
DCD_EVENT_XFER_COMPLETE,
|
||||
|
||||
// Not an DCD event, just a convenient way to defer ISR function
|
||||
USBD_EVENT_FUNC_CALL,
|
||||
|
||||
DCD_EVENT_COUNT
|
||||
} dcd_eventid_t;
|
||||
|
||||
typedef struct TU_ATTR_ALIGNED(4)
|
||||
{
|
||||
uint8_t rhport;
|
||||
uint8_t event_id;
|
||||
|
||||
union {
|
||||
// USBD_EVT_SETUP_RECEIVED
|
||||
tusb_control_request_t setup_received;
|
||||
|
||||
// USBD_EVT_XFER_COMPLETE
|
||||
struct {
|
||||
uint8_t ep_addr;
|
||||
uint8_t result;
|
||||
uint32_t len;
|
||||
}xfer_complete;
|
||||
|
||||
// USBD_EVENT_FUNC_CALL
|
||||
struct {
|
||||
void (*func) (void*);
|
||||
void* param;
|
||||
}func_call;
|
||||
};
|
||||
} dcd_event_t;
|
||||
|
||||
//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct");
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Device API
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
// Initialize controller to device mode
|
||||
void dcd_init (uint8_t rhport);
|
||||
|
||||
// Interrupt Handler
|
||||
void dcd_isr (uint8_t rhport);
|
||||
|
||||
// Enable device interrupt
|
||||
void dcd_int_enable (uint8_t rhport);
|
||||
|
||||
// Disable device interrupt
|
||||
void dcd_int_disable(uint8_t rhport);
|
||||
|
||||
// Receive Set Address request, mcu port must also include status IN response
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr);
|
||||
|
||||
// Receive Set Configure request
|
||||
void dcd_set_config (uint8_t rhport, uint8_t config_num);
|
||||
|
||||
// Wake up host
|
||||
void dcd_remote_wakeup(uint8_t rhport);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when a control transfer's status stage is complete.
|
||||
// May help DCD to prepare for next control transfer, this API is optional.
|
||||
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK;
|
||||
|
||||
// Configure endpoint's registers according to descriptor
|
||||
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
|
||||
|
||||
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
|
||||
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
|
||||
|
||||
// Stall endpoint
|
||||
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr);
|
||||
|
||||
// clear stall, data toggle is also reset to DATA0
|
||||
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Event API (Implemented by device stack)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Called by DCD to notify device stack
|
||||
extern void dcd_event_handler(dcd_event_t const * event, bool in_isr);
|
||||
|
||||
// helper to send bus signal event
|
||||
extern void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr);
|
||||
|
||||
// helper to send setup received
|
||||
extern void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr);
|
||||
|
||||
// helper to send transfer complete event
|
||||
extern void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_DCD_H_ */
|
||||
|
||||
/// @}
|
||||
|
2002
src/device/usbd.c
2002
src/device/usbd.c
File diff suppressed because it is too large
Load Diff
@ -1,335 +1,335 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_usbd
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_USBD_H_
|
||||
#define _TUSB_USBD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "dcd.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Init device stack
|
||||
bool tud_init (void);
|
||||
|
||||
// Task function should be called in main/rtos loop
|
||||
void tud_task (void);
|
||||
|
||||
// Interrupt handler, name alias to DCD
|
||||
#define tud_isr dcd_isr
|
||||
|
||||
// Check if device is connected and configured
|
||||
bool tud_mounted(void);
|
||||
|
||||
// Check if device is suspended
|
||||
bool tud_suspended(void);
|
||||
|
||||
// Check if device is ready to transfer
|
||||
static inline bool tud_ready(void)
|
||||
{
|
||||
return tud_mounted() && !tud_suspended();
|
||||
}
|
||||
|
||||
// Remote wake up host, only if suspended and enabled by host
|
||||
bool tud_remote_wakeup(void);
|
||||
|
||||
// Carry out Data and Status stage of control transfer
|
||||
// - If len = 0, it is equivalent to sending status only
|
||||
// - If len > wLength : it will be truncated
|
||||
bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len);
|
||||
|
||||
// Send STATUS (zero length) packet
|
||||
bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callbacks (WEAK is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received GET DEVICE DESCRIPTOR request
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const * tud_descriptor_device_cb(void);
|
||||
|
||||
// Invoked when received GET BOS DESCRIPTOR request
|
||||
// Application return pointer to descriptor
|
||||
TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void);
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint8_t const * tud_descriptor_configuration_cb(uint8_t index);
|
||||
|
||||
// Invoked when received GET STRING DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint16_t const* tud_descriptor_string_cb(uint8_t index);
|
||||
|
||||
// Invoked when device is mounted (configured)
|
||||
TU_ATTR_WEAK void tud_mount_cb(void);
|
||||
|
||||
// Invoked when device is unmounted
|
||||
TU_ATTR_WEAK void tud_umount_cb(void);
|
||||
|
||||
// Invoked when usb bus is suspended
|
||||
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
|
||||
TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en);
|
||||
|
||||
// Invoked when usb bus is resumed
|
||||
TU_ATTR_WEAK void tud_resume_cb(void);
|
||||
|
||||
// Invoked when received control request with VENDOR TYPE
|
||||
TU_ATTR_WEAK bool tud_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request);
|
||||
TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binary Device Object Store (BOS) Descriptor Templates
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#define TUD_BOS_DESC_LEN 5
|
||||
|
||||
// total length, number of device caps
|
||||
#define TUD_BOS_DESCRIPTOR(_total_len, _caps_num) \
|
||||
5, TUSB_DESC_BOS, U16_TO_U8S_LE(_total_len), _caps_num
|
||||
|
||||
// Device Capability Platform 128-bit UUID + Data
|
||||
#define TUD_BOS_PLATFORM_DESCRIPTOR(...) \
|
||||
4+TU_ARGS_NUM(__VA_ARGS__), TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_PLATFORM, 0x00, __VA_ARGS__
|
||||
|
||||
//------------- WebUSB BOS Platform -------------//
|
||||
|
||||
// Descriptor Length
|
||||
#define TUD_BOS_WEBUSB_DESC_LEN 24
|
||||
|
||||
// Vendor Code, iLandingPage
|
||||
#define TUD_BOS_WEBUSB_DESCRIPTOR(_vendor_code, _ipage) \
|
||||
TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_WEBUSB_UUID, U16_TO_U8S_LE(0x0100), _vendor_code, _ipage)
|
||||
|
||||
#define TUD_BOS_WEBUSB_UUID \
|
||||
0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, \
|
||||
0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65
|
||||
|
||||
//------------- Microsoft OS 2.0 Platform -------------//
|
||||
#define TUD_BOS_MICROSOFT_OS_DESC_LEN 28
|
||||
|
||||
// Total Length of descriptor set, vendor code
|
||||
#define TUD_BOS_MS_OS_20_DESCRIPTOR(_desc_set_len, _vendor_code) \
|
||||
TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_MS_OS_20_UUID, U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(_desc_set_len), _vendor_code, 0)
|
||||
|
||||
#define TUD_BOS_MS_OS_20_UUID \
|
||||
0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, \
|
||||
0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration & Interface Descriptor Templates
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//------------- Configuration -------------//
|
||||
#define TUD_CONFIG_DESC_LEN (9)
|
||||
|
||||
// Interface count, string index, total length, attribute, power in mA
|
||||
#define TUD_CONFIG_DESCRIPTOR(_itfcount, _stridx, _total_len, _attribute, _power_ma) \
|
||||
9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, 1, _stridx, TU_BIT(7) | _attribute, (_power_ma)/2
|
||||
|
||||
//------------- CDC -------------//
|
||||
|
||||
// Length of template descriptor: 66 bytes
|
||||
#define TUD_CDC_DESC_LEN (8+9+5+5+4+5+7+9+7+7)
|
||||
|
||||
// CDC Descriptor Template
|
||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||
#define TUD_CDC_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \
|
||||
/* Interface Associate */\
|
||||
8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_ATCOMMAND, 0,\
|
||||
/* CDC Control Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_ATCOMMAND, _stridx,\
|
||||
/* CDC Header */\
|
||||
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
|
||||
/* CDC Call */\
|
||||
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
|
||||
/* CDC ACM: support line request */\
|
||||
4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\
|
||||
/* CDC Union */\
|
||||
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
|
||||
/* Endpoint Notification */\
|
||||
7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\
|
||||
/* CDC Data Interface */\
|
||||
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
|
||||
/* Endpoint Out */\
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
|
||||
|
||||
//------------- MSC -------------//
|
||||
|
||||
// Length of template descriptor: 23 bytes
|
||||
#define TUD_MSC_DESC_LEN (9 + 7 + 7)
|
||||
|
||||
// Interface number, string index, EP Out & EP In address, EP size
|
||||
#define TUD_MSC_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
|
||||
/* Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_MSC, MSC_SUBCLASS_SCSI, MSC_PROTOCOL_BOT, _stridx,\
|
||||
/* Endpoint Out */\
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
|
||||
|
||||
//------------- HID -------------//
|
||||
|
||||
// Length of template descriptor: 25 bytes
|
||||
#define TUD_HID_DESC_LEN (9 + 9 + 7)
|
||||
|
||||
// HID Input only descriptor
|
||||
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
|
||||
#define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \
|
||||
/* Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
|
||||
/* HID descriptor */\
|
||||
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
|
||||
|
||||
// Length of template descriptor: 32 bytes
|
||||
#define TUD_HID_INOUT_DESC_LEN (9 + 9 + 7 + 7)
|
||||
|
||||
// HID Input & Output descriptor
|
||||
// Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval
|
||||
#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epout, _epin, _epsize, _ep_interval) \
|
||||
/* Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
|
||||
/* HID descriptor */\
|
||||
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
|
||||
/* Endpoint Out */\
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval, \
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
|
||||
|
||||
//------------- MIDI -------------//
|
||||
|
||||
// Length of template descriptor (96 bytes)
|
||||
#define TUD_MIDI_DESC_LEN (9 + 9 + 9 + 7 + 6 + 6 + 9 + 9 + 7 + 5 + 7 + 5)
|
||||
|
||||
// MIDI simple descriptor
|
||||
// - 1 Embedded Jack In connected to 1 External Jack Out
|
||||
// - 1 Embedded Jack out connected to 1 External Jack In
|
||||
#define TUD_MIDI_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
|
||||
/* Audio Control (AC) Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_PROTOCOL_V1, _stridx,\
|
||||
/* AC Header */\
|
||||
9, TUSB_DESC_CS_INTERFACE, AUDIO_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0009), 1, (uint8_t)((_itfnum)+1),\
|
||||
/* MIDI Streaming (MS) Interface */\
|
||||
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_PROTOCOL_V1, 0,\
|
||||
/* MS Header */\
|
||||
7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0025),\
|
||||
/* MS In Jack (Embedded) */\
|
||||
6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, 1, 0,\
|
||||
/* MS In Jack (External) */\
|
||||
6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, 2, 0,\
|
||||
/* MS Out Jack (Embedded), connected to In Jack External */\
|
||||
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, 3, 1, 2, 1, 0,\
|
||||
/* MS Out Jack (External), connected to In Jack Embedded */\
|
||||
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, 4, 1, 1, 1, 0,\
|
||||
/* Endpoint Out */\
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
|
||||
/* MS Endpoint (connected to embedded jack in) */\
|
||||
5, TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, 1, 1,\
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
|
||||
/* MS Endpoint (connected to embedded jack out) */\
|
||||
5, TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, 1, 3
|
||||
|
||||
//------------- TUD_USBTMC/USB488 -------------//
|
||||
#define TUD_USBTMC_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
|
||||
#define TUD_USBTMC_APP_SUBCLASS 0x03u
|
||||
|
||||
#define TUD_USBTMC_PROTOCOL_STD 0x00u
|
||||
#define TUD_USBTMC_PROTOCOL_USB488 0x01u
|
||||
|
||||
// Interface number, number of endpoints, EP string index, USB_TMC_PROTOCOL*, bulk-out endpoint ID,
|
||||
// bulk-in endpoint ID
|
||||
#define TUD_USBTMC_IF_DESCRIPTOR(_itfnum, _bNumEndpoints, _stridx, _itfProtocol) \
|
||||
/* Interface */ \
|
||||
0x09, TUSB_DESC_INTERFACE, _itfnum, 0x00, _bNumEndpoints, TUD_USBTMC_APP_CLASS, TUD_USBTMC_APP_SUBCLASS, _itfProtocol, _stridx
|
||||
|
||||
#define TUD_USBTMC_IF_DESCRIPTOR_LEN 9u
|
||||
|
||||
#define TUD_USBTMC_BULK_DESCRIPTORS(_epout, _epin, _bulk_epsize) \
|
||||
/* Endpoint Out */ \
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u, \
|
||||
/* Endpoint In */ \
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u
|
||||
|
||||
#define TUD_USBTMC_BULK_DESCRIPTORS_LEN (7u+7u)
|
||||
|
||||
/* optional interrupt endpoint */ \
|
||||
// _int_pollingInterval : for LS/FS, expressed in frames (1ms each). 16 may be a good number?
|
||||
#define TUD_USBTMC_INT_DESCRIPTOR(_ep_interrupt, _ep_interrupt_size, _int_pollingInterval ) \
|
||||
7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16
|
||||
|
||||
#define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u)
|
||||
|
||||
|
||||
//------------- Vendor -------------//
|
||||
#define TUD_VENDOR_DESC_LEN (9+7+7)
|
||||
|
||||
// Interface number, string index, EP Out & IN address, EP size
|
||||
#define TUD_VENDOR_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
|
||||
/* Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, _stridx,\
|
||||
/* Endpoint Out */\
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
|
||||
|
||||
//------------- DFU Runtime -------------//
|
||||
#define TUD_DFU_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
|
||||
#define TUD_DFU_APP_SUBCLASS 0x01u
|
||||
|
||||
// Length of template descriptr: 18 bytes
|
||||
#define TUD_DFU_RT_DESC_LEN (9 + 9)
|
||||
|
||||
// DFU runtime descriptor
|
||||
// Interface number, string index, attributes, detach timeout, transfer size
|
||||
#define TUD_DFU_RT_DESCRIPTOR(_itfnum, _stridx, _attr, _timeout, _xfer_size) \
|
||||
/* Interface */ \
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_RT, _stridx, \
|
||||
/* Function */ \
|
||||
9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_USBD_H_ */
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_usbd
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_USBD_H_
|
||||
#define _TUSB_USBD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "dcd.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Init device stack
|
||||
bool tud_init (void);
|
||||
|
||||
// Task function should be called in main/rtos loop
|
||||
void tud_task (void);
|
||||
|
||||
// Interrupt handler, name alias to DCD
|
||||
#define tud_isr dcd_isr
|
||||
|
||||
// Check if device is connected and configured
|
||||
bool tud_mounted(void);
|
||||
|
||||
// Check if device is suspended
|
||||
bool tud_suspended(void);
|
||||
|
||||
// Check if device is ready to transfer
|
||||
static inline bool tud_ready(void)
|
||||
{
|
||||
return tud_mounted() && !tud_suspended();
|
||||
}
|
||||
|
||||
// Remote wake up host, only if suspended and enabled by host
|
||||
bool tud_remote_wakeup(void);
|
||||
|
||||
// Carry out Data and Status stage of control transfer
|
||||
// - If len = 0, it is equivalent to sending status only
|
||||
// - If len > wLength : it will be truncated
|
||||
bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len);
|
||||
|
||||
// Send STATUS (zero length) packet
|
||||
bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callbacks (WEAK is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received GET DEVICE DESCRIPTOR request
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const * tud_descriptor_device_cb(void);
|
||||
|
||||
// Invoked when received GET BOS DESCRIPTOR request
|
||||
// Application return pointer to descriptor
|
||||
TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void);
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint8_t const * tud_descriptor_configuration_cb(uint8_t index);
|
||||
|
||||
// Invoked when received GET STRING DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint16_t const* tud_descriptor_string_cb(uint8_t index);
|
||||
|
||||
// Invoked when device is mounted (configured)
|
||||
TU_ATTR_WEAK void tud_mount_cb(void);
|
||||
|
||||
// Invoked when device is unmounted
|
||||
TU_ATTR_WEAK void tud_umount_cb(void);
|
||||
|
||||
// Invoked when usb bus is suspended
|
||||
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
|
||||
TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en);
|
||||
|
||||
// Invoked when usb bus is resumed
|
||||
TU_ATTR_WEAK void tud_resume_cb(void);
|
||||
|
||||
// Invoked when received control request with VENDOR TYPE
|
||||
TU_ATTR_WEAK bool tud_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request);
|
||||
TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binary Device Object Store (BOS) Descriptor Templates
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#define TUD_BOS_DESC_LEN 5
|
||||
|
||||
// total length, number of device caps
|
||||
#define TUD_BOS_DESCRIPTOR(_total_len, _caps_num) \
|
||||
5, TUSB_DESC_BOS, U16_TO_U8S_LE(_total_len), _caps_num
|
||||
|
||||
// Device Capability Platform 128-bit UUID + Data
|
||||
#define TUD_BOS_PLATFORM_DESCRIPTOR(...) \
|
||||
4+TU_ARGS_NUM(__VA_ARGS__), TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_PLATFORM, 0x00, __VA_ARGS__
|
||||
|
||||
//------------- WebUSB BOS Platform -------------//
|
||||
|
||||
// Descriptor Length
|
||||
#define TUD_BOS_WEBUSB_DESC_LEN 24
|
||||
|
||||
// Vendor Code, iLandingPage
|
||||
#define TUD_BOS_WEBUSB_DESCRIPTOR(_vendor_code, _ipage) \
|
||||
TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_WEBUSB_UUID, U16_TO_U8S_LE(0x0100), _vendor_code, _ipage)
|
||||
|
||||
#define TUD_BOS_WEBUSB_UUID \
|
||||
0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, \
|
||||
0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65
|
||||
|
||||
//------------- Microsoft OS 2.0 Platform -------------//
|
||||
#define TUD_BOS_MICROSOFT_OS_DESC_LEN 28
|
||||
|
||||
// Total Length of descriptor set, vendor code
|
||||
#define TUD_BOS_MS_OS_20_DESCRIPTOR(_desc_set_len, _vendor_code) \
|
||||
TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_MS_OS_20_UUID, U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(_desc_set_len), _vendor_code, 0)
|
||||
|
||||
#define TUD_BOS_MS_OS_20_UUID \
|
||||
0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, \
|
||||
0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration & Interface Descriptor Templates
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//------------- Configuration -------------//
|
||||
#define TUD_CONFIG_DESC_LEN (9)
|
||||
|
||||
// Interface count, string index, total length, attribute, power in mA
|
||||
#define TUD_CONFIG_DESCRIPTOR(_itfcount, _stridx, _total_len, _attribute, _power_ma) \
|
||||
9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, 1, _stridx, TU_BIT(7) | _attribute, (_power_ma)/2
|
||||
|
||||
//------------- CDC -------------//
|
||||
|
||||
// Length of template descriptor: 66 bytes
|
||||
#define TUD_CDC_DESC_LEN (8+9+5+5+4+5+7+9+7+7)
|
||||
|
||||
// CDC Descriptor Template
|
||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||
#define TUD_CDC_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \
|
||||
/* Interface Associate */\
|
||||
8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_ATCOMMAND, 0,\
|
||||
/* CDC Control Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_ATCOMMAND, _stridx,\
|
||||
/* CDC Header */\
|
||||
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
|
||||
/* CDC Call */\
|
||||
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
|
||||
/* CDC ACM: support line request */\
|
||||
4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\
|
||||
/* CDC Union */\
|
||||
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
|
||||
/* Endpoint Notification */\
|
||||
7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\
|
||||
/* CDC Data Interface */\
|
||||
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
|
||||
/* Endpoint Out */\
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
|
||||
|
||||
//------------- MSC -------------//
|
||||
|
||||
// Length of template descriptor: 23 bytes
|
||||
#define TUD_MSC_DESC_LEN (9 + 7 + 7)
|
||||
|
||||
// Interface number, string index, EP Out & EP In address, EP size
|
||||
#define TUD_MSC_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
|
||||
/* Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_MSC, MSC_SUBCLASS_SCSI, MSC_PROTOCOL_BOT, _stridx,\
|
||||
/* Endpoint Out */\
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
|
||||
|
||||
//------------- HID -------------//
|
||||
|
||||
// Length of template descriptor: 25 bytes
|
||||
#define TUD_HID_DESC_LEN (9 + 9 + 7)
|
||||
|
||||
// HID Input only descriptor
|
||||
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
|
||||
#define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \
|
||||
/* Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
|
||||
/* HID descriptor */\
|
||||
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
|
||||
|
||||
// Length of template descriptor: 32 bytes
|
||||
#define TUD_HID_INOUT_DESC_LEN (9 + 9 + 7 + 7)
|
||||
|
||||
// HID Input & Output descriptor
|
||||
// Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval
|
||||
#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epout, _epin, _epsize, _ep_interval) \
|
||||
/* Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
|
||||
/* HID descriptor */\
|
||||
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
|
||||
/* Endpoint Out */\
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval, \
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
|
||||
|
||||
//------------- MIDI -------------//
|
||||
|
||||
// Length of template descriptor (96 bytes)
|
||||
#define TUD_MIDI_DESC_LEN (9 + 9 + 9 + 7 + 6 + 6 + 9 + 9 + 7 + 5 + 7 + 5)
|
||||
|
||||
// MIDI simple descriptor
|
||||
// - 1 Embedded Jack In connected to 1 External Jack Out
|
||||
// - 1 Embedded Jack out connected to 1 External Jack In
|
||||
#define TUD_MIDI_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
|
||||
/* Audio Control (AC) Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_PROTOCOL_V1, _stridx,\
|
||||
/* AC Header */\
|
||||
9, TUSB_DESC_CS_INTERFACE, AUDIO_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0009), 1, (uint8_t)((_itfnum)+1),\
|
||||
/* MIDI Streaming (MS) Interface */\
|
||||
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_PROTOCOL_V1, 0,\
|
||||
/* MS Header */\
|
||||
7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0025),\
|
||||
/* MS In Jack (Embedded) */\
|
||||
6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, 1, 0,\
|
||||
/* MS In Jack (External) */\
|
||||
6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, 2, 0,\
|
||||
/* MS Out Jack (Embedded), connected to In Jack External */\
|
||||
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, 3, 1, 2, 1, 0,\
|
||||
/* MS Out Jack (External), connected to In Jack Embedded */\
|
||||
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, 4, 1, 1, 1, 0,\
|
||||
/* Endpoint Out */\
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
|
||||
/* MS Endpoint (connected to embedded jack in) */\
|
||||
5, TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, 1, 1,\
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
|
||||
/* MS Endpoint (connected to embedded jack out) */\
|
||||
5, TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, 1, 3
|
||||
|
||||
//------------- TUD_USBTMC/USB488 -------------//
|
||||
#define TUD_USBTMC_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
|
||||
#define TUD_USBTMC_APP_SUBCLASS 0x03u
|
||||
|
||||
#define TUD_USBTMC_PROTOCOL_STD 0x00u
|
||||
#define TUD_USBTMC_PROTOCOL_USB488 0x01u
|
||||
|
||||
// Interface number, number of endpoints, EP string index, USB_TMC_PROTOCOL*, bulk-out endpoint ID,
|
||||
// bulk-in endpoint ID
|
||||
#define TUD_USBTMC_IF_DESCRIPTOR(_itfnum, _bNumEndpoints, _stridx, _itfProtocol) \
|
||||
/* Interface */ \
|
||||
0x09, TUSB_DESC_INTERFACE, _itfnum, 0x00, _bNumEndpoints, TUD_USBTMC_APP_CLASS, TUD_USBTMC_APP_SUBCLASS, _itfProtocol, _stridx
|
||||
|
||||
#define TUD_USBTMC_IF_DESCRIPTOR_LEN 9u
|
||||
|
||||
#define TUD_USBTMC_BULK_DESCRIPTORS(_epout, _epin, _bulk_epsize) \
|
||||
/* Endpoint Out */ \
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u, \
|
||||
/* Endpoint In */ \
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u
|
||||
|
||||
#define TUD_USBTMC_BULK_DESCRIPTORS_LEN (7u+7u)
|
||||
|
||||
/* optional interrupt endpoint */ \
|
||||
// _int_pollingInterval : for LS/FS, expressed in frames (1ms each). 16 may be a good number?
|
||||
#define TUD_USBTMC_INT_DESCRIPTOR(_ep_interrupt, _ep_interrupt_size, _int_pollingInterval ) \
|
||||
7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16
|
||||
|
||||
#define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u)
|
||||
|
||||
|
||||
//------------- Vendor -------------//
|
||||
#define TUD_VENDOR_DESC_LEN (9+7+7)
|
||||
|
||||
// Interface number, string index, EP Out & IN address, EP size
|
||||
#define TUD_VENDOR_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
|
||||
/* Interface */\
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, _stridx,\
|
||||
/* Endpoint Out */\
|
||||
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
|
||||
/* Endpoint In */\
|
||||
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
|
||||
|
||||
//------------- DFU Runtime -------------//
|
||||
#define TUD_DFU_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
|
||||
#define TUD_DFU_APP_SUBCLASS 0x01u
|
||||
|
||||
// Length of template descriptr: 18 bytes
|
||||
#define TUD_DFU_RT_DESC_LEN (9 + 9)
|
||||
|
||||
// DFU runtime descriptor
|
||||
// Interface number, string index, attributes, detach timeout, transfer size
|
||||
#define TUD_DFU_RT_DESCRIPTOR(_itfnum, _stridx, _attr, _timeout, _xfer_size) \
|
||||
/* Interface */ \
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_RT, _stridx, \
|
||||
/* Function */ \
|
||||
9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_USBD_H_ */
|
||||
|
||||
/** @} */
|
||||
|
1712
src/host/ehci/ehci.c
1712
src/host/ehci/ehci.c
File diff suppressed because it is too large
Load Diff
294
src/host/hcd.h
294
src/host/hcd.h
@ -1,147 +1,147 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_usbh
|
||||
* \defgroup Group_HCD Host Controller Driver (HCD)
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_HCD_H_
|
||||
#define _TUSB_HCD_H_
|
||||
|
||||
#include <common/tusb_common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef enum
|
||||
{
|
||||
HCD_EVENT_DEVICE_ATTACH,
|
||||
HCD_EVENT_DEVICE_REMOVE,
|
||||
HCD_EVENT_XFER_COMPLETE,
|
||||
} hcd_eventid_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t rhport;
|
||||
uint8_t event_id;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t hub_addr;
|
||||
uint8_t hub_port;
|
||||
} attach, remove;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t ep_addr;
|
||||
uint8_t result;
|
||||
uint32_t len;
|
||||
} xfer_complete;
|
||||
};
|
||||
|
||||
} hcd_event_t;
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
// Max number of endpoints per device
|
||||
enum {
|
||||
HCD_MAX_ENDPOINT = CFG_TUSB_HOST_DEVICE_MAX*(CFG_TUH_HUB + CFG_TUH_HID_KEYBOARD + CFG_TUH_HID_MOUSE + CFG_TUSB_HOST_HID_GENERIC +
|
||||
CFG_TUH_MSC*2 + CFG_TUH_CDC*3),
|
||||
|
||||
HCD_MAX_XFER = HCD_MAX_ENDPOINT*2,
|
||||
};
|
||||
|
||||
//#define HCD_MAX_ENDPOINT 16
|
||||
//#define HCD_MAX_XFER 16
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HCD API
|
||||
//--------------------------------------------------------------------+
|
||||
bool hcd_init(void);
|
||||
void hcd_isr(uint8_t hostid);
|
||||
void hcd_int_enable (uint8_t rhport);
|
||||
void hcd_int_disable(uint8_t rhport);
|
||||
|
||||
// PORT API
|
||||
/// return the current connect status of roothub port
|
||||
bool hcd_port_connect_status(uint8_t hostid);
|
||||
void hcd_port_reset(uint8_t hostid);
|
||||
tusb_speed_t hcd_port_speed_get(uint8_t hostid);
|
||||
|
||||
// HCD closes all opened endpoints belong to this device
|
||||
void hcd_device_close(uint8_t rhport, uint8_t dev_addr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Event function
|
||||
//--------------------------------------------------------------------+
|
||||
void hcd_event_handler(hcd_event_t const* event, bool in_isr);
|
||||
|
||||
// Helper to send device attach event
|
||||
void hcd_event_device_attach(uint8_t rhport);
|
||||
|
||||
// Helper to send device removal event
|
||||
void hcd_event_device_remove(uint8_t rhport);
|
||||
|
||||
// Helper to send USB transfer event
|
||||
void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoints API
|
||||
//--------------------------------------------------------------------+
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]);
|
||||
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
|
||||
|
||||
bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr);
|
||||
bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr);
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr);
|
||||
|
||||
// TODO merge with pipe_xfer
|
||||
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
// TODO control xfer should be used via usbh layer
|
||||
bool hcd_pipe_queue_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes); // only queue, not transferring yet
|
||||
bool hcd_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete);
|
||||
|
||||
#if 0
|
||||
tusb_error_t hcd_pipe_cancel();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HCD_H_ */
|
||||
|
||||
/// @}
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_usbh
|
||||
* \defgroup Group_HCD Host Controller Driver (HCD)
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_HCD_H_
|
||||
#define _TUSB_HCD_H_
|
||||
|
||||
#include <common/tusb_common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef enum
|
||||
{
|
||||
HCD_EVENT_DEVICE_ATTACH,
|
||||
HCD_EVENT_DEVICE_REMOVE,
|
||||
HCD_EVENT_XFER_COMPLETE,
|
||||
} hcd_eventid_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t rhport;
|
||||
uint8_t event_id;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t hub_addr;
|
||||
uint8_t hub_port;
|
||||
} attach, remove;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t ep_addr;
|
||||
uint8_t result;
|
||||
uint32_t len;
|
||||
} xfer_complete;
|
||||
};
|
||||
|
||||
} hcd_event_t;
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
// Max number of endpoints per device
|
||||
enum {
|
||||
HCD_MAX_ENDPOINT = CFG_TUSB_HOST_DEVICE_MAX*(CFG_TUH_HUB + CFG_TUH_HID_KEYBOARD + CFG_TUH_HID_MOUSE + CFG_TUSB_HOST_HID_GENERIC +
|
||||
CFG_TUH_MSC*2 + CFG_TUH_CDC*3),
|
||||
|
||||
HCD_MAX_XFER = HCD_MAX_ENDPOINT*2,
|
||||
};
|
||||
|
||||
//#define HCD_MAX_ENDPOINT 16
|
||||
//#define HCD_MAX_XFER 16
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HCD API
|
||||
//--------------------------------------------------------------------+
|
||||
bool hcd_init(void);
|
||||
void hcd_isr(uint8_t hostid);
|
||||
void hcd_int_enable (uint8_t rhport);
|
||||
void hcd_int_disable(uint8_t rhport);
|
||||
|
||||
// PORT API
|
||||
/// return the current connect status of roothub port
|
||||
bool hcd_port_connect_status(uint8_t hostid);
|
||||
void hcd_port_reset(uint8_t hostid);
|
||||
tusb_speed_t hcd_port_speed_get(uint8_t hostid);
|
||||
|
||||
// HCD closes all opened endpoints belong to this device
|
||||
void hcd_device_close(uint8_t rhport, uint8_t dev_addr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Event function
|
||||
//--------------------------------------------------------------------+
|
||||
void hcd_event_handler(hcd_event_t const* event, bool in_isr);
|
||||
|
||||
// Helper to send device attach event
|
||||
void hcd_event_device_attach(uint8_t rhport);
|
||||
|
||||
// Helper to send device removal event
|
||||
void hcd_event_device_remove(uint8_t rhport);
|
||||
|
||||
// Helper to send USB transfer event
|
||||
void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoints API
|
||||
//--------------------------------------------------------------------+
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]);
|
||||
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
|
||||
|
||||
bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr);
|
||||
bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr);
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr);
|
||||
|
||||
// TODO merge with pipe_xfer
|
||||
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PIPE API
|
||||
//--------------------------------------------------------------------+
|
||||
// TODO control xfer should be used via usbh layer
|
||||
bool hcd_pipe_queue_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes); // only queue, not transferring yet
|
||||
bool hcd_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete);
|
||||
|
||||
#if 0
|
||||
tusb_error_t hcd_pipe_cancel();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HCD_H_ */
|
||||
|
||||
/// @}
|
||||
|
500
src/host/hub.c
500
src/host/hub.c
@ -1,250 +1,250 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HUB)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "hub.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_status;
|
||||
uint8_t port_number;
|
||||
uint8_t status_change; // data from status change interrupt endpoint
|
||||
}usbh_hub_t;
|
||||
|
||||
CFG_TUSB_MEM_SECTION static usbh_hub_t hub_data[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
TU_ATTR_ALIGNED(4) CFG_TUSB_MEM_SECTION static uint8_t hub_enum_buffer[sizeof(descriptor_hub_desc_t)];
|
||||
|
||||
//OSAL_SEM_DEF(hub_enum_semaphore);
|
||||
//static osal_semaphore_handle_t hub_enum_sem_hdl;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HUB
|
||||
//--------------------------------------------------------------------+
|
||||
bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature)
|
||||
{
|
||||
TU_ASSERT(HUB_FEATURE_PORT_CONNECTION_CHANGE <= feature && feature <= HUB_FEATURE_PORT_RESET_CHANGE);
|
||||
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = HUB_REQUEST_CLEAR_FEATURE,
|
||||
.wValue = feature,
|
||||
.wIndex = hub_port,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
//------------- Clear Port Feature request -------------//
|
||||
TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) );
|
||||
|
||||
//------------- Get Port Status to check if feature is cleared -------------//
|
||||
request = (tusb_control_request_t ) {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN },
|
||||
.bRequest = HUB_REQUEST_GET_STATUS,
|
||||
.wValue = 0,
|
||||
.wIndex = hub_port,
|
||||
.wLength = 4
|
||||
};
|
||||
|
||||
TU_ASSERT( usbh_control_xfer( hub_addr, &request, hub_enum_buffer ) );
|
||||
|
||||
//------------- Check if feature is cleared -------------//
|
||||
hub_port_status_response_t * p_port_status;
|
||||
p_port_status = (hub_port_status_response_t *) hub_enum_buffer;
|
||||
|
||||
TU_ASSERT( !tu_bit_test(p_port_status->status_change.value, feature-16) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port)
|
||||
{
|
||||
enum { RESET_DELAY = 200 }; // USB specs say only 50ms but many devices require much longer
|
||||
|
||||
//------------- Set Port Reset -------------//
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = HUB_REQUEST_SET_FEATURE,
|
||||
.wValue = HUB_FEATURE_PORT_RESET,
|
||||
.wIndex = hub_port,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) );
|
||||
|
||||
osal_task_delay(RESET_DELAY); // TODO Hub wait for Status Endpoint on Reset Change
|
||||
|
||||
//------------- Get Port Status to check if port is enabled, powered and reset_change -------------//
|
||||
request = (tusb_control_request_t ) {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN },
|
||||
.bRequest = HUB_REQUEST_GET_STATUS,
|
||||
.wValue = 0,
|
||||
.wIndex = hub_port,
|
||||
.wLength = 4
|
||||
};
|
||||
|
||||
TU_ASSERT( usbh_control_xfer( hub_addr, &request, hub_enum_buffer ) );
|
||||
|
||||
hub_port_status_response_t * p_port_status;
|
||||
p_port_status = (hub_port_status_response_t *) hub_enum_buffer;
|
||||
|
||||
TU_ASSERT ( p_port_status->status_change.reset && p_port_status->status_current.connect_status &&
|
||||
p_port_status->status_current.port_power && p_port_status->status_current.port_enable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// can only get the speed RIGHT AFTER hub_port_reset_subtask call
|
||||
tusb_speed_t hub_port_get_speed(void)
|
||||
{
|
||||
hub_port_status_response_t * p_port_status = (hub_port_status_response_t *) hub_enum_buffer;
|
||||
return (p_port_status->status_current.high_speed_device_attached) ? TUSB_SPEED_HIGH :
|
||||
(p_port_status->status_current.low_speed_device_attached ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CLASS-USBH API (don't require to verify parameters)
|
||||
//--------------------------------------------------------------------+
|
||||
void hub_init(void)
|
||||
{
|
||||
tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof(usbh_hub_t));
|
||||
// hub_enum_sem_hdl = osal_semaphore_create( OSAL_SEM_REF(hub_enum_semaphore) );
|
||||
}
|
||||
|
||||
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
|
||||
{
|
||||
// not support multiple TT yet
|
||||
if ( itf_desc->bInterfaceProtocol > 1 ) return false;
|
||||
|
||||
//------------- Open Interrupt Status Pipe -------------//
|
||||
tusb_desc_endpoint_t const *ep_desc;
|
||||
ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
|
||||
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
|
||||
TU_ASSERT(TUSB_XFER_INTERRUPT == ep_desc->bmAttributes.xfer);
|
||||
|
||||
TU_ASSERT(hcd_edpt_open(rhport, dev_addr, ep_desc));
|
||||
|
||||
hub_data[dev_addr-1].itf_num = itf_desc->bInterfaceNumber;
|
||||
hub_data[dev_addr-1].ep_status = ep_desc->bEndpointAddress;
|
||||
|
||||
(*p_length) = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
//------------- Get Hub Descriptor -------------//
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN },
|
||||
.bRequest = HUB_REQUEST_GET_DESCRIPTOR,
|
||||
.wValue = 0,
|
||||
.wIndex = 0,
|
||||
.wLength = sizeof(descriptor_hub_desc_t)
|
||||
};
|
||||
|
||||
TU_ASSERT( usbh_control_xfer( dev_addr, &request, hub_enum_buffer ) );
|
||||
|
||||
// only care about this field in hub descriptor
|
||||
hub_data[dev_addr-1].port_number = ((descriptor_hub_desc_t*) hub_enum_buffer)->bNbrPorts;
|
||||
|
||||
//------------- Set Port_Power on all ports -------------//
|
||||
// TODO may only power port with attached
|
||||
request = (tusb_control_request_t ) {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = HUB_REQUEST_SET_FEATURE,
|
||||
.wValue = HUB_FEATURE_PORT_POWER,
|
||||
.wIndex = 0,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
for(uint8_t i=1; i <= hub_data[dev_addr-1].port_number; i++)
|
||||
{
|
||||
request.wIndex = i;
|
||||
TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) );
|
||||
}
|
||||
|
||||
//------------- Queue the initial Status endpoint transfer -------------//
|
||||
TU_ASSERT( hcd_pipe_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1, true) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// is the response of interrupt endpoint polling
|
||||
#include "usbh_hcd.h" // FIXME remove
|
||||
void hub_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports
|
||||
(void) ep_addr;
|
||||
|
||||
usbh_hub_t * p_hub = &hub_data[dev_addr-1];
|
||||
|
||||
if ( event == XFER_RESULT_SUCCESS )
|
||||
{
|
||||
for (uint8_t port=1; port <= p_hub->port_number; port++)
|
||||
{
|
||||
// TODO HUB ignore bit0 hub_status_change
|
||||
if ( tu_bit_test(p_hub->status_change, port) )
|
||||
{
|
||||
hcd_event_t event =
|
||||
{
|
||||
.rhport = _usbh_devices[dev_addr].rhport,
|
||||
.event_id = HCD_EVENT_DEVICE_ATTACH
|
||||
};
|
||||
|
||||
event.attach.hub_addr = dev_addr;
|
||||
event.attach.hub_port = port;
|
||||
|
||||
hcd_event_handler(&event, true);
|
||||
break; // handle one port at a time, next port if any will be handled in the next cycle
|
||||
}
|
||||
}
|
||||
// NOTE: next status transfer is queued by usbh.c after handling this request
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO [HUB] check if hub is still plugged before polling status endpoint since failed usually mean hub unplugged
|
||||
// TU_ASSERT ( hub_status_pipe_queue(dev_addr) );
|
||||
}
|
||||
}
|
||||
|
||||
void hub_close(uint8_t dev_addr)
|
||||
{
|
||||
tu_memclr(&hub_data[dev_addr-1], sizeof(usbh_hub_t));
|
||||
// osal_semaphore_reset(hub_enum_sem_hdl);
|
||||
}
|
||||
|
||||
bool hub_status_pipe_queue(uint8_t dev_addr)
|
||||
{
|
||||
return hcd_pipe_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1, true);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HUB)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "hub.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_status;
|
||||
uint8_t port_number;
|
||||
uint8_t status_change; // data from status change interrupt endpoint
|
||||
}usbh_hub_t;
|
||||
|
||||
CFG_TUSB_MEM_SECTION static usbh_hub_t hub_data[CFG_TUSB_HOST_DEVICE_MAX];
|
||||
TU_ATTR_ALIGNED(4) CFG_TUSB_MEM_SECTION static uint8_t hub_enum_buffer[sizeof(descriptor_hub_desc_t)];
|
||||
|
||||
//OSAL_SEM_DEF(hub_enum_semaphore);
|
||||
//static osal_semaphore_handle_t hub_enum_sem_hdl;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HUB
|
||||
//--------------------------------------------------------------------+
|
||||
bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature)
|
||||
{
|
||||
TU_ASSERT(HUB_FEATURE_PORT_CONNECTION_CHANGE <= feature && feature <= HUB_FEATURE_PORT_RESET_CHANGE);
|
||||
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = HUB_REQUEST_CLEAR_FEATURE,
|
||||
.wValue = feature,
|
||||
.wIndex = hub_port,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
//------------- Clear Port Feature request -------------//
|
||||
TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) );
|
||||
|
||||
//------------- Get Port Status to check if feature is cleared -------------//
|
||||
request = (tusb_control_request_t ) {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN },
|
||||
.bRequest = HUB_REQUEST_GET_STATUS,
|
||||
.wValue = 0,
|
||||
.wIndex = hub_port,
|
||||
.wLength = 4
|
||||
};
|
||||
|
||||
TU_ASSERT( usbh_control_xfer( hub_addr, &request, hub_enum_buffer ) );
|
||||
|
||||
//------------- Check if feature is cleared -------------//
|
||||
hub_port_status_response_t * p_port_status;
|
||||
p_port_status = (hub_port_status_response_t *) hub_enum_buffer;
|
||||
|
||||
TU_ASSERT( !tu_bit_test(p_port_status->status_change.value, feature-16) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port)
|
||||
{
|
||||
enum { RESET_DELAY = 200 }; // USB specs say only 50ms but many devices require much longer
|
||||
|
||||
//------------- Set Port Reset -------------//
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = HUB_REQUEST_SET_FEATURE,
|
||||
.wValue = HUB_FEATURE_PORT_RESET,
|
||||
.wIndex = hub_port,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) );
|
||||
|
||||
osal_task_delay(RESET_DELAY); // TODO Hub wait for Status Endpoint on Reset Change
|
||||
|
||||
//------------- Get Port Status to check if port is enabled, powered and reset_change -------------//
|
||||
request = (tusb_control_request_t ) {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN },
|
||||
.bRequest = HUB_REQUEST_GET_STATUS,
|
||||
.wValue = 0,
|
||||
.wIndex = hub_port,
|
||||
.wLength = 4
|
||||
};
|
||||
|
||||
TU_ASSERT( usbh_control_xfer( hub_addr, &request, hub_enum_buffer ) );
|
||||
|
||||
hub_port_status_response_t * p_port_status;
|
||||
p_port_status = (hub_port_status_response_t *) hub_enum_buffer;
|
||||
|
||||
TU_ASSERT ( p_port_status->status_change.reset && p_port_status->status_current.connect_status &&
|
||||
p_port_status->status_current.port_power && p_port_status->status_current.port_enable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// can only get the speed RIGHT AFTER hub_port_reset_subtask call
|
||||
tusb_speed_t hub_port_get_speed(void)
|
||||
{
|
||||
hub_port_status_response_t * p_port_status = (hub_port_status_response_t *) hub_enum_buffer;
|
||||
return (p_port_status->status_current.high_speed_device_attached) ? TUSB_SPEED_HIGH :
|
||||
(p_port_status->status_current.low_speed_device_attached ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CLASS-USBH API (don't require to verify parameters)
|
||||
//--------------------------------------------------------------------+
|
||||
void hub_init(void)
|
||||
{
|
||||
tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof(usbh_hub_t));
|
||||
// hub_enum_sem_hdl = osal_semaphore_create( OSAL_SEM_REF(hub_enum_semaphore) );
|
||||
}
|
||||
|
||||
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
|
||||
{
|
||||
// not support multiple TT yet
|
||||
if ( itf_desc->bInterfaceProtocol > 1 ) return false;
|
||||
|
||||
//------------- Open Interrupt Status Pipe -------------//
|
||||
tusb_desc_endpoint_t const *ep_desc;
|
||||
ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
|
||||
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
|
||||
TU_ASSERT(TUSB_XFER_INTERRUPT == ep_desc->bmAttributes.xfer);
|
||||
|
||||
TU_ASSERT(hcd_edpt_open(rhport, dev_addr, ep_desc));
|
||||
|
||||
hub_data[dev_addr-1].itf_num = itf_desc->bInterfaceNumber;
|
||||
hub_data[dev_addr-1].ep_status = ep_desc->bEndpointAddress;
|
||||
|
||||
(*p_length) = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
//------------- Get Hub Descriptor -------------//
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN },
|
||||
.bRequest = HUB_REQUEST_GET_DESCRIPTOR,
|
||||
.wValue = 0,
|
||||
.wIndex = 0,
|
||||
.wLength = sizeof(descriptor_hub_desc_t)
|
||||
};
|
||||
|
||||
TU_ASSERT( usbh_control_xfer( dev_addr, &request, hub_enum_buffer ) );
|
||||
|
||||
// only care about this field in hub descriptor
|
||||
hub_data[dev_addr-1].port_number = ((descriptor_hub_desc_t*) hub_enum_buffer)->bNbrPorts;
|
||||
|
||||
//------------- Set Port_Power on all ports -------------//
|
||||
// TODO may only power port with attached
|
||||
request = (tusb_control_request_t ) {
|
||||
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
|
||||
.bRequest = HUB_REQUEST_SET_FEATURE,
|
||||
.wValue = HUB_FEATURE_PORT_POWER,
|
||||
.wIndex = 0,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
for(uint8_t i=1; i <= hub_data[dev_addr-1].port_number; i++)
|
||||
{
|
||||
request.wIndex = i;
|
||||
TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) );
|
||||
}
|
||||
|
||||
//------------- Queue the initial Status endpoint transfer -------------//
|
||||
TU_ASSERT( hcd_pipe_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1, true) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// is the response of interrupt endpoint polling
|
||||
#include "usbh_hcd.h" // FIXME remove
|
||||
void hub_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports
|
||||
(void) ep_addr;
|
||||
|
||||
usbh_hub_t * p_hub = &hub_data[dev_addr-1];
|
||||
|
||||
if ( event == XFER_RESULT_SUCCESS )
|
||||
{
|
||||
for (uint8_t port=1; port <= p_hub->port_number; port++)
|
||||
{
|
||||
// TODO HUB ignore bit0 hub_status_change
|
||||
if ( tu_bit_test(p_hub->status_change, port) )
|
||||
{
|
||||
hcd_event_t event =
|
||||
{
|
||||
.rhport = _usbh_devices[dev_addr].rhport,
|
||||
.event_id = HCD_EVENT_DEVICE_ATTACH
|
||||
};
|
||||
|
||||
event.attach.hub_addr = dev_addr;
|
||||
event.attach.hub_port = port;
|
||||
|
||||
hcd_event_handler(&event, true);
|
||||
break; // handle one port at a time, next port if any will be handled in the next cycle
|
||||
}
|
||||
}
|
||||
// NOTE: next status transfer is queued by usbh.c after handling this request
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO [HUB] check if hub is still plugged before polling status endpoint since failed usually mean hub unplugged
|
||||
// TU_ASSERT ( hub_status_pipe_queue(dev_addr) );
|
||||
}
|
||||
}
|
||||
|
||||
void hub_close(uint8_t dev_addr)
|
||||
{
|
||||
tu_memclr(&hub_data[dev_addr-1], sizeof(usbh_hub_t));
|
||||
// osal_semaphore_reset(hub_enum_sem_hdl);
|
||||
}
|
||||
|
||||
bool hub_status_pipe_queue(uint8_t dev_addr)
|
||||
{
|
||||
return hcd_pipe_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1, true);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
388
src/host/hub.h
388
src/host/hub.h
@ -1,194 +1,194 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_class
|
||||
* \defgroup ClassDriver_Hub Hub (Host only)
|
||||
* \details Like most PC's OS, Hub support is completely hidden from Application. In fact, application cannot determine whether
|
||||
* a device is mounted directly via roothub or via a hub's port. All Hub-related procedures are performed and managed
|
||||
* by tinyusb stack. Unless you are trying to develop the stack itself, there are nothing else can be used by Application.
|
||||
* \note Due to my laziness, only 1-level of Hub is supported. In other way, the stack cannot mount a hub via another hub.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_HUB_H_
|
||||
#define _TUSB_HUB_H_
|
||||
|
||||
#include <common/tusb_common.h>
|
||||
#include "usbh.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//D1...D0: Logical Power Switching Mode
|
||||
//00: Ganged power switching (all ports’power at
|
||||
//once)
|
||||
//01: Individual port power switching
|
||||
//1X: Reserved. Used only on 1.0 compliant hubs
|
||||
//that implement no power switching
|
||||
//D2: Identifies a Compound Device
|
||||
//0: Hub is not part of a compound device.
|
||||
//1: Hub is part of a compound device.
|
||||
//D4...D3: Over-current Protection Mode
|
||||
//00: Global Over-current Protection. The hub
|
||||
//reports over-current as a summation of all
|
||||
//ports’current draw, without a breakdown of
|
||||
//individual port over-current status.
|
||||
//01: Individual Port Over-current Protection. The
|
||||
//hub reports over-current on a per-port basis.
|
||||
//Each port has an over-current status.
|
||||
//1X: No Over-current Protection. This option is
|
||||
//allowed only for bus-powered hubs that do not
|
||||
//implement over-current protection.
|
||||
//
|
||||
//D6...D5: TT Think TIme
|
||||
//00: TT requires at most 8 FS bit times of inter
|
||||
//transaction gap on a full-/low-speed
|
||||
//downstream bus.
|
||||
//01: TT requires at most 16 FS bit times.
|
||||
//10: TT requires at most 24 FS bit times.
|
||||
//11: TT requires at most 32 FS bit times.
|
||||
//D7: Port Indicators Supported
|
||||
//0: Port Indicators are not supported on its
|
||||
//downstream facing ports and the
|
||||
//PORT_INDICATOR request has no effect.
|
||||
//1: Port Indicators are supported on its
|
||||
//downstream facing ports and the
|
||||
//PORT_INDICATOR request controls the
|
||||
//indicators. See Section 11.5.3.
|
||||
//D15...D8: Reserved
|
||||
|
||||
typedef struct TU_ATTR_PACKED{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
uint8_t bNbrPorts;
|
||||
uint16_t wHubCharacteristics;
|
||||
uint8_t bPwrOn2PwrGood;
|
||||
uint8_t bHubContrCurrent;
|
||||
uint8_t DeviceRemovable; // bitmap each bit for a port (from bit1)
|
||||
uint8_t PortPwrCtrlMask; // just for compatibility, should be 0xff
|
||||
} descriptor_hub_desc_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(descriptor_hub_desc_t) == 9, "size is not correct");
|
||||
|
||||
enum {
|
||||
HUB_REQUEST_GET_STATUS = 0 ,
|
||||
HUB_REQUEST_CLEAR_FEATURE = 1 ,
|
||||
|
||||
HUB_REQUEST_SET_FEATURE = 3 ,
|
||||
|
||||
HUB_REQUEST_GET_DESCRIPTOR = 6 ,
|
||||
HUB_REQUEST_SET_DESCRIPTOR = 7 ,
|
||||
HUB_REQUEST_CLEAR_TT_BUFFER = 8 ,
|
||||
HUB_REQUEST_RESET_TT = 9 ,
|
||||
HUB_REQUEST_GET_TT_STATE = 10 ,
|
||||
HUB_REQUEST_STOP_TT = 11
|
||||
};
|
||||
|
||||
enum {
|
||||
HUB_FEATURE_HUB_LOCAL_POWER_CHANGE = 0,
|
||||
HUB_FEATURE_HUB_OVER_CURRENT_CHANGE
|
||||
};
|
||||
|
||||
enum{
|
||||
HUB_FEATURE_PORT_CONNECTION = 0,
|
||||
HUB_FEATURE_PORT_ENABLE = 1,
|
||||
HUB_FEATURE_PORT_SUSPEND = 2,
|
||||
HUB_FEATURE_PORT_OVER_CURRENT = 3,
|
||||
HUB_FEATURE_PORT_RESET = 4,
|
||||
|
||||
HUB_FEATURE_PORT_POWER = 8,
|
||||
HUB_FEATURE_PORT_LOW_SPEED = 9,
|
||||
|
||||
HUB_FEATURE_PORT_CONNECTION_CHANGE = 16,
|
||||
HUB_FEATURE_PORT_ENABLE_CHANGE = 17,
|
||||
HUB_FEATURE_PORT_SUSPEND_CHANGE = 18,
|
||||
HUB_FEATURE_PORT_OVER_CURRENT_CHANGE = 19,
|
||||
HUB_FEATURE_PORT_RESET_CHANGE = 20,
|
||||
HUB_FEATURE_PORT_TEST = 21,
|
||||
HUB_FEATURE_PORT_INDICATOR = 22
|
||||
};
|
||||
|
||||
// data in response of HUB_REQUEST_GET_STATUS, wIndex = 0 (hub)
|
||||
typedef struct {
|
||||
union{
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t local_power_source : 1;
|
||||
uint16_t over_current : 1;
|
||||
uint16_t : 14;
|
||||
};
|
||||
|
||||
uint16_t value;
|
||||
} status, status_change;
|
||||
} hub_status_response_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(hub_status_response_t) == 4, "size is not correct");
|
||||
|
||||
// data in response of HUB_REQUEST_GET_STATUS, wIndex = Port num
|
||||
typedef struct {
|
||||
union {
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t connect_status : 1;
|
||||
uint16_t port_enable : 1;
|
||||
uint16_t suspend : 1;
|
||||
uint16_t over_current : 1;
|
||||
uint16_t reset : 1;
|
||||
|
||||
uint16_t : 3;
|
||||
uint16_t port_power : 1;
|
||||
uint16_t low_speed_device_attached : 1;
|
||||
uint16_t high_speed_device_attached : 1;
|
||||
uint16_t port_test_mode : 1;
|
||||
uint16_t port_indicator_control : 1;
|
||||
uint16_t : 0;
|
||||
};
|
||||
|
||||
uint16_t value;
|
||||
} status_current, status_change;
|
||||
} hub_port_status_response_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct");
|
||||
|
||||
bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port);
|
||||
bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature);
|
||||
tusb_speed_t hub_port_get_speed(void);
|
||||
bool hub_status_pipe_queue(uint8_t dev_addr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void hub_init(void);
|
||||
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
|
||||
void hub_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void hub_close(uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HUB_H_ */
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_class
|
||||
* \defgroup ClassDriver_Hub Hub (Host only)
|
||||
* \details Like most PC's OS, Hub support is completely hidden from Application. In fact, application cannot determine whether
|
||||
* a device is mounted directly via roothub or via a hub's port. All Hub-related procedures are performed and managed
|
||||
* by tinyusb stack. Unless you are trying to develop the stack itself, there are nothing else can be used by Application.
|
||||
* \note Due to my laziness, only 1-level of Hub is supported. In other way, the stack cannot mount a hub via another hub.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_HUB_H_
|
||||
#define _TUSB_HUB_H_
|
||||
|
||||
#include <common/tusb_common.h>
|
||||
#include "usbh.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//D1...D0: Logical Power Switching Mode
|
||||
//00: Ganged power switching (all ports’power at
|
||||
//once)
|
||||
//01: Individual port power switching
|
||||
//1X: Reserved. Used only on 1.0 compliant hubs
|
||||
//that implement no power switching
|
||||
//D2: Identifies a Compound Device
|
||||
//0: Hub is not part of a compound device.
|
||||
//1: Hub is part of a compound device.
|
||||
//D4...D3: Over-current Protection Mode
|
||||
//00: Global Over-current Protection. The hub
|
||||
//reports over-current as a summation of all
|
||||
//ports’current draw, without a breakdown of
|
||||
//individual port over-current status.
|
||||
//01: Individual Port Over-current Protection. The
|
||||
//hub reports over-current on a per-port basis.
|
||||
//Each port has an over-current status.
|
||||
//1X: No Over-current Protection. This option is
|
||||
//allowed only for bus-powered hubs that do not
|
||||
//implement over-current protection.
|
||||
//
|
||||
//D6...D5: TT Think TIme
|
||||
//00: TT requires at most 8 FS bit times of inter
|
||||
//transaction gap on a full-/low-speed
|
||||
//downstream bus.
|
||||
//01: TT requires at most 16 FS bit times.
|
||||
//10: TT requires at most 24 FS bit times.
|
||||
//11: TT requires at most 32 FS bit times.
|
||||
//D7: Port Indicators Supported
|
||||
//0: Port Indicators are not supported on its
|
||||
//downstream facing ports and the
|
||||
//PORT_INDICATOR request has no effect.
|
||||
//1: Port Indicators are supported on its
|
||||
//downstream facing ports and the
|
||||
//PORT_INDICATOR request controls the
|
||||
//indicators. See Section 11.5.3.
|
||||
//D15...D8: Reserved
|
||||
|
||||
typedef struct TU_ATTR_PACKED{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
uint8_t bNbrPorts;
|
||||
uint16_t wHubCharacteristics;
|
||||
uint8_t bPwrOn2PwrGood;
|
||||
uint8_t bHubContrCurrent;
|
||||
uint8_t DeviceRemovable; // bitmap each bit for a port (from bit1)
|
||||
uint8_t PortPwrCtrlMask; // just for compatibility, should be 0xff
|
||||
} descriptor_hub_desc_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(descriptor_hub_desc_t) == 9, "size is not correct");
|
||||
|
||||
enum {
|
||||
HUB_REQUEST_GET_STATUS = 0 ,
|
||||
HUB_REQUEST_CLEAR_FEATURE = 1 ,
|
||||
|
||||
HUB_REQUEST_SET_FEATURE = 3 ,
|
||||
|
||||
HUB_REQUEST_GET_DESCRIPTOR = 6 ,
|
||||
HUB_REQUEST_SET_DESCRIPTOR = 7 ,
|
||||
HUB_REQUEST_CLEAR_TT_BUFFER = 8 ,
|
||||
HUB_REQUEST_RESET_TT = 9 ,
|
||||
HUB_REQUEST_GET_TT_STATE = 10 ,
|
||||
HUB_REQUEST_STOP_TT = 11
|
||||
};
|
||||
|
||||
enum {
|
||||
HUB_FEATURE_HUB_LOCAL_POWER_CHANGE = 0,
|
||||
HUB_FEATURE_HUB_OVER_CURRENT_CHANGE
|
||||
};
|
||||
|
||||
enum{
|
||||
HUB_FEATURE_PORT_CONNECTION = 0,
|
||||
HUB_FEATURE_PORT_ENABLE = 1,
|
||||
HUB_FEATURE_PORT_SUSPEND = 2,
|
||||
HUB_FEATURE_PORT_OVER_CURRENT = 3,
|
||||
HUB_FEATURE_PORT_RESET = 4,
|
||||
|
||||
HUB_FEATURE_PORT_POWER = 8,
|
||||
HUB_FEATURE_PORT_LOW_SPEED = 9,
|
||||
|
||||
HUB_FEATURE_PORT_CONNECTION_CHANGE = 16,
|
||||
HUB_FEATURE_PORT_ENABLE_CHANGE = 17,
|
||||
HUB_FEATURE_PORT_SUSPEND_CHANGE = 18,
|
||||
HUB_FEATURE_PORT_OVER_CURRENT_CHANGE = 19,
|
||||
HUB_FEATURE_PORT_RESET_CHANGE = 20,
|
||||
HUB_FEATURE_PORT_TEST = 21,
|
||||
HUB_FEATURE_PORT_INDICATOR = 22
|
||||
};
|
||||
|
||||
// data in response of HUB_REQUEST_GET_STATUS, wIndex = 0 (hub)
|
||||
typedef struct {
|
||||
union{
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t local_power_source : 1;
|
||||
uint16_t over_current : 1;
|
||||
uint16_t : 14;
|
||||
};
|
||||
|
||||
uint16_t value;
|
||||
} status, status_change;
|
||||
} hub_status_response_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(hub_status_response_t) == 4, "size is not correct");
|
||||
|
||||
// data in response of HUB_REQUEST_GET_STATUS, wIndex = Port num
|
||||
typedef struct {
|
||||
union {
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t connect_status : 1;
|
||||
uint16_t port_enable : 1;
|
||||
uint16_t suspend : 1;
|
||||
uint16_t over_current : 1;
|
||||
uint16_t reset : 1;
|
||||
|
||||
uint16_t : 3;
|
||||
uint16_t port_power : 1;
|
||||
uint16_t low_speed_device_attached : 1;
|
||||
uint16_t high_speed_device_attached : 1;
|
||||
uint16_t port_test_mode : 1;
|
||||
uint16_t port_indicator_control : 1;
|
||||
uint16_t : 0;
|
||||
};
|
||||
|
||||
uint16_t value;
|
||||
} status_current, status_change;
|
||||
} hub_port_status_response_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct");
|
||||
|
||||
bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port);
|
||||
bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature);
|
||||
tusb_speed_t hub_port_get_speed(void);
|
||||
bool hub_status_pipe_queue(uint8_t dev_addr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void hub_init(void);
|
||||
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
|
||||
void hub_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void hub_close(uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HUB_H_ */
|
||||
|
||||
/** @} */
|
||||
|
1302
src/host/ohci/ohci.c
1302
src/host/ohci/ohci.c
File diff suppressed because it is too large
Load Diff
@ -1,291 +1,291 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_HCD
|
||||
* @{
|
||||
* \defgroup OHCI
|
||||
* \brief OHCI driver. All documents sources mentioned here (eg section 3.5) is referring to OHCI Specs unless state otherwise
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_OHCI_H_
|
||||
#define _TUSB_OHCI_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI CONFIGURATION & CONSTANTS
|
||||
//--------------------------------------------------------------------+
|
||||
#define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enalbed
|
||||
#define OHCI_PERIODIC_LIST (defined HOST_HCD_XFER_INTERRUPT || defined HOST_HCD_XFER_ISOCHRONOUS)
|
||||
|
||||
// TODO merge OHCI with EHCI
|
||||
enum {
|
||||
OHCI_MAX_ITD = 4
|
||||
};
|
||||
|
||||
enum {
|
||||
OHCI_PID_SETUP = 0,
|
||||
OHCI_PID_OUT,
|
||||
OHCI_PID_IN,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Data Structure
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
uint32_t interrupt_table[32];
|
||||
volatile uint16_t frame_number;
|
||||
volatile uint16_t frame_pad;
|
||||
volatile uint32_t done_head;
|
||||
uint8_t reserved[116+4]; // TODO try to make use of this area if possible, extra 4 byte to make the whole struct size = 256
|
||||
}ohci_hcca_t; // TU_ATTR_ALIGNED(256)
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(ohci_hcca_t) == 256, "size is not correct" );
|
||||
|
||||
typedef struct {
|
||||
uint32_t reserved[2];
|
||||
volatile uint32_t next;
|
||||
uint32_t reserved2;
|
||||
}ohci_td_item_t;
|
||||
|
||||
|
||||
typedef struct TU_ATTR_ALIGNED(16)
|
||||
{
|
||||
// Word 0
|
||||
uint32_t used : 1;
|
||||
uint32_t index : 4; // endpoint index the td belongs to, or device address in case of control xfer
|
||||
uint32_t expected_bytes : 13; // TODO available for hcd
|
||||
|
||||
uint32_t buffer_rounding : 1;
|
||||
uint32_t pid : 2;
|
||||
uint32_t delay_interrupt : 3;
|
||||
volatile uint32_t data_toggle : 2;
|
||||
volatile uint32_t error_count : 2;
|
||||
volatile uint32_t condition_code : 4;
|
||||
|
||||
// Word 1
|
||||
volatile uint8_t* current_buffer_pointer;
|
||||
|
||||
// Word 2 : next TD
|
||||
volatile uint32_t next;
|
||||
|
||||
// Word 3
|
||||
uint8_t* buffer_end;
|
||||
} ohci_gtd_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(ohci_gtd_t) == 16, "size is not correct" );
|
||||
|
||||
typedef struct TU_ATTR_ALIGNED(16)
|
||||
{
|
||||
// Word 0
|
||||
uint32_t dev_addr : 7;
|
||||
uint32_t ep_number : 4;
|
||||
uint32_t pid : 2; // 00b from TD, 01b Out, 10b In
|
||||
uint32_t speed : 1;
|
||||
uint32_t skip : 1;
|
||||
uint32_t is_iso : 1;
|
||||
uint32_t max_packet_size : 11;
|
||||
// HCD: make use of 5 reserved bits
|
||||
uint32_t used : 1;
|
||||
uint32_t is_interrupt_xfer : 1;
|
||||
uint32_t is_stalled : 1;
|
||||
uint32_t : 2;
|
||||
|
||||
// Word 1
|
||||
uint32_t td_tail;
|
||||
|
||||
// Word 2
|
||||
volatile union {
|
||||
uint32_t address;
|
||||
struct {
|
||||
uint32_t halted : 1;
|
||||
uint32_t toggle : 1;
|
||||
uint32_t : 30;
|
||||
};
|
||||
}td_head;
|
||||
|
||||
// Word 3: next ED
|
||||
uint32_t next;
|
||||
} ohci_ed_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(ohci_ed_t) == 16, "size is not correct" );
|
||||
|
||||
typedef struct TU_ATTR_ALIGNED(32)
|
||||
{
|
||||
/*---------- Word 1 ----------*/
|
||||
uint32_t starting_frame : 16;
|
||||
uint32_t : 5; // can be used
|
||||
uint32_t delay_interrupt : 3;
|
||||
uint32_t frame_count : 3;
|
||||
uint32_t : 1; // can be used
|
||||
volatile uint32_t condition_code : 4;
|
||||
|
||||
/*---------- Word 2 ----------*/
|
||||
uint32_t buffer_page0; // 12 lsb bits can be used
|
||||
|
||||
/*---------- Word 3 ----------*/
|
||||
volatile uint32_t next;
|
||||
|
||||
/*---------- Word 4 ----------*/
|
||||
uint32_t buffer_end;
|
||||
|
||||
/*---------- Word 5-8 ----------*/
|
||||
volatile uint16_t offset_packetstatus[8];
|
||||
} ochi_itd_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(ochi_itd_t) == 32, "size is not correct" );
|
||||
|
||||
// structure with member alignment required from large to small
|
||||
typedef struct TU_ATTR_ALIGNED(256)
|
||||
{
|
||||
ohci_hcca_t hcca;
|
||||
|
||||
ohci_ed_t bulk_head_ed; // static bulk head (dummy)
|
||||
ohci_ed_t period_head_ed; // static periodic list head (dummy)
|
||||
|
||||
// control endpoints has reserved resources
|
||||
struct {
|
||||
ohci_ed_t ed;
|
||||
ohci_gtd_t gtd;
|
||||
}control[CFG_TUSB_HOST_DEVICE_MAX+1];
|
||||
|
||||
// ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
|
||||
ohci_ed_t ed_pool[HCD_MAX_ENDPOINT];
|
||||
ohci_gtd_t gtd_pool[HCD_MAX_XFER];
|
||||
|
||||
} ohci_data_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Operational Register
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Data Organization
|
||||
//--------------------------------------------------------------------+
|
||||
typedef volatile struct
|
||||
{
|
||||
uint32_t revision;
|
||||
|
||||
union {
|
||||
uint32_t control;
|
||||
struct {
|
||||
uint32_t control_bulk_service_ratio : 2;
|
||||
uint32_t periodic_list_enable : 1;
|
||||
uint32_t isochronous_enable : 1;
|
||||
uint32_t control_list_enable : 1;
|
||||
uint32_t bulk_list_enable : 1;
|
||||
uint32_t hc_functional_state : 2;
|
||||
uint32_t interrupt_routing : 1;
|
||||
uint32_t remote_wakeup_connected : 1;
|
||||
uint32_t remote_wakeup_enale : 1;
|
||||
uint32_t : 0;
|
||||
}control_bit;
|
||||
};
|
||||
|
||||
union {
|
||||
uint32_t command_status;
|
||||
struct {
|
||||
uint32_t controller_reset : 1;
|
||||
uint32_t control_list_filled : 1;
|
||||
uint32_t bulk_list_filled : 1;
|
||||
uint32_t ownership_change_request : 1;
|
||||
uint32_t : 12;
|
||||
uint32_t scheduling_overrun_count : 2;
|
||||
}command_status_bit;
|
||||
};
|
||||
|
||||
uint32_t interrupt_status;
|
||||
uint32_t interrupt_enable;
|
||||
uint32_t interrupt_disable;
|
||||
|
||||
uint32_t hcca;
|
||||
uint32_t period_current_ed;
|
||||
uint32_t control_head_ed;
|
||||
uint32_t control_current_ed;
|
||||
uint32_t bulk_head_ed;
|
||||
uint32_t bulk_current_ed;
|
||||
uint32_t done_head;
|
||||
|
||||
uint32_t frame_interval;
|
||||
uint32_t frame_remaining;
|
||||
uint32_t frame_number;
|
||||
uint32_t periodic_start;
|
||||
uint32_t lowspeed_threshold;
|
||||
|
||||
uint32_t rh_descriptorA;
|
||||
uint32_t rh_descriptorB;
|
||||
|
||||
union {
|
||||
uint32_t rh_status;
|
||||
struct {
|
||||
uint32_t local_power_status : 1; // read Local Power Status; write: Clear Global Power
|
||||
uint32_t over_current_indicator : 1;
|
||||
uint32_t : 13;
|
||||
uint32_t device_remote_wakeup_enable : 1;
|
||||
uint32_t local_power_status_change : 1;
|
||||
uint32_t over_current_indicator_change : 1;
|
||||
uint32_t : 13;
|
||||
uint32_t clear_remote_wakeup_enable : 1;
|
||||
}rh_status_bit;
|
||||
};
|
||||
|
||||
union {
|
||||
uint32_t rhport_status[2]; // TODO NXP OHCI controller only has 2 ports
|
||||
struct {
|
||||
uint32_t current_connect_status : 1;
|
||||
uint32_t port_enable_status : 1;
|
||||
uint32_t port_suspend_status : 1;
|
||||
uint32_t port_over_current_indicator : 1;
|
||||
uint32_t port_reset_status : 1;
|
||||
uint32_t : 3;
|
||||
uint32_t port_power_status : 1;
|
||||
uint32_t low_speed_device_attached : 1;
|
||||
uint32_t : 6;
|
||||
uint32_t connect_status_change : 1;
|
||||
uint32_t port_enable_status_change : 1;
|
||||
uint32_t port_suspend_status_change : 1;
|
||||
uint32_t port_over_current_indicator_change : 1;
|
||||
uint32_t port_reset_status_change : 1;
|
||||
uint32_t : 0;
|
||||
}rhport_status_bit[2];
|
||||
};
|
||||
}ohci_registers_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(ohci_registers_t) == 0x5c, "size is not correct");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_OHCI_H_ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_HCD
|
||||
* @{
|
||||
* \defgroup OHCI
|
||||
* \brief OHCI driver. All documents sources mentioned here (eg section 3.5) is referring to OHCI Specs unless state otherwise
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_OHCI_H_
|
||||
#define _TUSB_OHCI_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI CONFIGURATION & CONSTANTS
|
||||
//--------------------------------------------------------------------+
|
||||
#define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enalbed
|
||||
#define OHCI_PERIODIC_LIST (defined HOST_HCD_XFER_INTERRUPT || defined HOST_HCD_XFER_ISOCHRONOUS)
|
||||
|
||||
// TODO merge OHCI with EHCI
|
||||
enum {
|
||||
OHCI_MAX_ITD = 4
|
||||
};
|
||||
|
||||
enum {
|
||||
OHCI_PID_SETUP = 0,
|
||||
OHCI_PID_OUT,
|
||||
OHCI_PID_IN,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Data Structure
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
uint32_t interrupt_table[32];
|
||||
volatile uint16_t frame_number;
|
||||
volatile uint16_t frame_pad;
|
||||
volatile uint32_t done_head;
|
||||
uint8_t reserved[116+4]; // TODO try to make use of this area if possible, extra 4 byte to make the whole struct size = 256
|
||||
}ohci_hcca_t; // TU_ATTR_ALIGNED(256)
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(ohci_hcca_t) == 256, "size is not correct" );
|
||||
|
||||
typedef struct {
|
||||
uint32_t reserved[2];
|
||||
volatile uint32_t next;
|
||||
uint32_t reserved2;
|
||||
}ohci_td_item_t;
|
||||
|
||||
|
||||
typedef struct TU_ATTR_ALIGNED(16)
|
||||
{
|
||||
// Word 0
|
||||
uint32_t used : 1;
|
||||
uint32_t index : 4; // endpoint index the td belongs to, or device address in case of control xfer
|
||||
uint32_t expected_bytes : 13; // TODO available for hcd
|
||||
|
||||
uint32_t buffer_rounding : 1;
|
||||
uint32_t pid : 2;
|
||||
uint32_t delay_interrupt : 3;
|
||||
volatile uint32_t data_toggle : 2;
|
||||
volatile uint32_t error_count : 2;
|
||||
volatile uint32_t condition_code : 4;
|
||||
|
||||
// Word 1
|
||||
volatile uint8_t* current_buffer_pointer;
|
||||
|
||||
// Word 2 : next TD
|
||||
volatile uint32_t next;
|
||||
|
||||
// Word 3
|
||||
uint8_t* buffer_end;
|
||||
} ohci_gtd_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(ohci_gtd_t) == 16, "size is not correct" );
|
||||
|
||||
typedef struct TU_ATTR_ALIGNED(16)
|
||||
{
|
||||
// Word 0
|
||||
uint32_t dev_addr : 7;
|
||||
uint32_t ep_number : 4;
|
||||
uint32_t pid : 2; // 00b from TD, 01b Out, 10b In
|
||||
uint32_t speed : 1;
|
||||
uint32_t skip : 1;
|
||||
uint32_t is_iso : 1;
|
||||
uint32_t max_packet_size : 11;
|
||||
// HCD: make use of 5 reserved bits
|
||||
uint32_t used : 1;
|
||||
uint32_t is_interrupt_xfer : 1;
|
||||
uint32_t is_stalled : 1;
|
||||
uint32_t : 2;
|
||||
|
||||
// Word 1
|
||||
uint32_t td_tail;
|
||||
|
||||
// Word 2
|
||||
volatile union {
|
||||
uint32_t address;
|
||||
struct {
|
||||
uint32_t halted : 1;
|
||||
uint32_t toggle : 1;
|
||||
uint32_t : 30;
|
||||
};
|
||||
}td_head;
|
||||
|
||||
// Word 3: next ED
|
||||
uint32_t next;
|
||||
} ohci_ed_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(ohci_ed_t) == 16, "size is not correct" );
|
||||
|
||||
typedef struct TU_ATTR_ALIGNED(32)
|
||||
{
|
||||
/*---------- Word 1 ----------*/
|
||||
uint32_t starting_frame : 16;
|
||||
uint32_t : 5; // can be used
|
||||
uint32_t delay_interrupt : 3;
|
||||
uint32_t frame_count : 3;
|
||||
uint32_t : 1; // can be used
|
||||
volatile uint32_t condition_code : 4;
|
||||
|
||||
/*---------- Word 2 ----------*/
|
||||
uint32_t buffer_page0; // 12 lsb bits can be used
|
||||
|
||||
/*---------- Word 3 ----------*/
|
||||
volatile uint32_t next;
|
||||
|
||||
/*---------- Word 4 ----------*/
|
||||
uint32_t buffer_end;
|
||||
|
||||
/*---------- Word 5-8 ----------*/
|
||||
volatile uint16_t offset_packetstatus[8];
|
||||
} ochi_itd_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(ochi_itd_t) == 32, "size is not correct" );
|
||||
|
||||
// structure with member alignment required from large to small
|
||||
typedef struct TU_ATTR_ALIGNED(256)
|
||||
{
|
||||
ohci_hcca_t hcca;
|
||||
|
||||
ohci_ed_t bulk_head_ed; // static bulk head (dummy)
|
||||
ohci_ed_t period_head_ed; // static periodic list head (dummy)
|
||||
|
||||
// control endpoints has reserved resources
|
||||
struct {
|
||||
ohci_ed_t ed;
|
||||
ohci_gtd_t gtd;
|
||||
}control[CFG_TUSB_HOST_DEVICE_MAX+1];
|
||||
|
||||
// ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
|
||||
ohci_ed_t ed_pool[HCD_MAX_ENDPOINT];
|
||||
ohci_gtd_t gtd_pool[HCD_MAX_XFER];
|
||||
|
||||
} ohci_data_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Operational Register
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Data Organization
|
||||
//--------------------------------------------------------------------+
|
||||
typedef volatile struct
|
||||
{
|
||||
uint32_t revision;
|
||||
|
||||
union {
|
||||
uint32_t control;
|
||||
struct {
|
||||
uint32_t control_bulk_service_ratio : 2;
|
||||
uint32_t periodic_list_enable : 1;
|
||||
uint32_t isochronous_enable : 1;
|
||||
uint32_t control_list_enable : 1;
|
||||
uint32_t bulk_list_enable : 1;
|
||||
uint32_t hc_functional_state : 2;
|
||||
uint32_t interrupt_routing : 1;
|
||||
uint32_t remote_wakeup_connected : 1;
|
||||
uint32_t remote_wakeup_enale : 1;
|
||||
uint32_t : 0;
|
||||
}control_bit;
|
||||
};
|
||||
|
||||
union {
|
||||
uint32_t command_status;
|
||||
struct {
|
||||
uint32_t controller_reset : 1;
|
||||
uint32_t control_list_filled : 1;
|
||||
uint32_t bulk_list_filled : 1;
|
||||
uint32_t ownership_change_request : 1;
|
||||
uint32_t : 12;
|
||||
uint32_t scheduling_overrun_count : 2;
|
||||
}command_status_bit;
|
||||
};
|
||||
|
||||
uint32_t interrupt_status;
|
||||
uint32_t interrupt_enable;
|
||||
uint32_t interrupt_disable;
|
||||
|
||||
uint32_t hcca;
|
||||
uint32_t period_current_ed;
|
||||
uint32_t control_head_ed;
|
||||
uint32_t control_current_ed;
|
||||
uint32_t bulk_head_ed;
|
||||
uint32_t bulk_current_ed;
|
||||
uint32_t done_head;
|
||||
|
||||
uint32_t frame_interval;
|
||||
uint32_t frame_remaining;
|
||||
uint32_t frame_number;
|
||||
uint32_t periodic_start;
|
||||
uint32_t lowspeed_threshold;
|
||||
|
||||
uint32_t rh_descriptorA;
|
||||
uint32_t rh_descriptorB;
|
||||
|
||||
union {
|
||||
uint32_t rh_status;
|
||||
struct {
|
||||
uint32_t local_power_status : 1; // read Local Power Status; write: Clear Global Power
|
||||
uint32_t over_current_indicator : 1;
|
||||
uint32_t : 13;
|
||||
uint32_t device_remote_wakeup_enable : 1;
|
||||
uint32_t local_power_status_change : 1;
|
||||
uint32_t over_current_indicator_change : 1;
|
||||
uint32_t : 13;
|
||||
uint32_t clear_remote_wakeup_enable : 1;
|
||||
}rh_status_bit;
|
||||
};
|
||||
|
||||
union {
|
||||
uint32_t rhport_status[2]; // TODO NXP OHCI controller only has 2 ports
|
||||
struct {
|
||||
uint32_t current_connect_status : 1;
|
||||
uint32_t port_enable_status : 1;
|
||||
uint32_t port_suspend_status : 1;
|
||||
uint32_t port_over_current_indicator : 1;
|
||||
uint32_t port_reset_status : 1;
|
||||
uint32_t : 3;
|
||||
uint32_t port_power_status : 1;
|
||||
uint32_t low_speed_device_attached : 1;
|
||||
uint32_t : 6;
|
||||
uint32_t connect_status_change : 1;
|
||||
uint32_t port_enable_status_change : 1;
|
||||
uint32_t port_suspend_status_change : 1;
|
||||
uint32_t port_over_current_indicator_change : 1;
|
||||
uint32_t port_reset_status_change : 1;
|
||||
uint32_t : 0;
|
||||
}rhport_status_bit[2];
|
||||
};
|
||||
}ohci_registers_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(ohci_registers_t) == 0x5c, "size is not correct");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_OHCI_H_ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
1352
src/host/usbh.c
1352
src/host/usbh.c
File diff suppressed because it is too large
Load Diff
196
src/osal/osal.h
196
src/osal/osal.h
@ -1,98 +1,98 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_OSAL_H_
|
||||
#define _TUSB_OSAL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \addtogroup group_osal
|
||||
* @{ */
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
enum
|
||||
{
|
||||
OSAL_TIMEOUT_NOTIMEOUT = 0, // return immediately
|
||||
OSAL_TIMEOUT_NORMAL = 10, // default timeout
|
||||
OSAL_TIMEOUT_WAIT_FOREVER = 0xFFFFFFFFUL
|
||||
};
|
||||
|
||||
#define OSAL_TIMEOUT_CONTROL_XFER OSAL_TIMEOUT_WAIT_FOREVER
|
||||
|
||||
typedef void (*osal_task_func_t)( void * );
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
#include "osal_none.h"
|
||||
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
|
||||
#include "osal_freertos.h"
|
||||
#elif CFG_TUSB_OS == OPT_OS_MYNEWT
|
||||
#include "osal_mynewt.h"
|
||||
#else
|
||||
#error OS is not supported yet
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OSAL Porting API
|
||||
//--------------------------------------------------------------------+
|
||||
static inline void osal_task_delay(uint32_t msec);
|
||||
|
||||
//------------- Semaphore -------------//
|
||||
static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
|
||||
static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
|
||||
static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec);
|
||||
|
||||
static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed
|
||||
|
||||
//------------- Mutex -------------//
|
||||
static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
|
||||
static inline bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
|
||||
static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl);
|
||||
|
||||
//------------- Queue -------------//
|
||||
static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
|
||||
static inline bool osal_queue_receive(osal_queue_t const qhdl, void* data);
|
||||
static inline bool osal_queue_send(osal_queue_t const qhdl, void const * data, bool in_isr);
|
||||
|
||||
#if 0 // TODO remove subtask related macros later
|
||||
// Sub Task
|
||||
#define OSAL_SUBTASK_BEGIN
|
||||
#define OSAL_SUBTASK_END return TUSB_ERROR_NONE;
|
||||
|
||||
#define STASK_RETURN(_error) return _error;
|
||||
#define STASK_INVOKE(_subtask, _status) (_status) = _subtask
|
||||
#define STASK_ASSERT(_cond) TU_VERIFY(_cond, TUSB_ERROR_OSAL_TASK_FAILED)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* _TUSB_OSAL_H_ */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_OSAL_H_
|
||||
#define _TUSB_OSAL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \addtogroup group_osal
|
||||
* @{ */
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
enum
|
||||
{
|
||||
OSAL_TIMEOUT_NOTIMEOUT = 0, // return immediately
|
||||
OSAL_TIMEOUT_NORMAL = 10, // default timeout
|
||||
OSAL_TIMEOUT_WAIT_FOREVER = 0xFFFFFFFFUL
|
||||
};
|
||||
|
||||
#define OSAL_TIMEOUT_CONTROL_XFER OSAL_TIMEOUT_WAIT_FOREVER
|
||||
|
||||
typedef void (*osal_task_func_t)( void * );
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
#include "osal_none.h"
|
||||
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
|
||||
#include "osal_freertos.h"
|
||||
#elif CFG_TUSB_OS == OPT_OS_MYNEWT
|
||||
#include "osal_mynewt.h"
|
||||
#else
|
||||
#error OS is not supported yet
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OSAL Porting API
|
||||
//--------------------------------------------------------------------+
|
||||
static inline void osal_task_delay(uint32_t msec);
|
||||
|
||||
//------------- Semaphore -------------//
|
||||
static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
|
||||
static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
|
||||
static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec);
|
||||
|
||||
static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed
|
||||
|
||||
//------------- Mutex -------------//
|
||||
static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
|
||||
static inline bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
|
||||
static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl);
|
||||
|
||||
//------------- Queue -------------//
|
||||
static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
|
||||
static inline bool osal_queue_receive(osal_queue_t const qhdl, void* data);
|
||||
static inline bool osal_queue_send(osal_queue_t const qhdl, void const * data, bool in_isr);
|
||||
|
||||
#if 0 // TODO remove subtask related macros later
|
||||
// Sub Task
|
||||
#define OSAL_SUBTASK_BEGIN
|
||||
#define OSAL_SUBTASK_END return TUSB_ERROR_NONE;
|
||||
|
||||
#define STASK_RETURN(_error) return _error;
|
||||
#define STASK_INVOKE(_subtask, _status) (_status) = _subtask
|
||||
#define STASK_ASSERT(_cond) TU_VERIFY(_cond, TUSB_ERROR_OSAL_TASK_FAILED)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* _TUSB_OSAL_H_ */
|
||||
|
@ -1,210 +1,210 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_OSAL_NONE_H_
|
||||
#define _TUSB_OSAL_NONE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TASK API
|
||||
//--------------------------------------------------------------------+
|
||||
static inline void osal_task_delay(uint32_t msec)
|
||||
{
|
||||
(void) msec;
|
||||
// TODO only used by Host stack, will implement using SOF
|
||||
|
||||
// uint32_t start = tusb_hal_millis();
|
||||
// while ( ( tusb_hal_millis() - start ) < msec ) {}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binary Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
volatile uint16_t count;
|
||||
}osal_semaphore_def_t;
|
||||
|
||||
typedef osal_semaphore_def_t* osal_semaphore_t;
|
||||
|
||||
static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
|
||||
{
|
||||
semdef->count = 0;
|
||||
return semdef;
|
||||
}
|
||||
|
||||
static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
|
||||
{
|
||||
(void) in_isr;
|
||||
sem_hdl->count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO blocking for now
|
||||
static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
|
||||
{
|
||||
(void) msec;
|
||||
|
||||
while (sem_hdl->count == 0) { }
|
||||
sem_hdl->count--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
|
||||
{
|
||||
sem_hdl->count = 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MUTEX API
|
||||
// Within tinyusb, mutex is never used in ISR context
|
||||
//--------------------------------------------------------------------+
|
||||
typedef osal_semaphore_def_t osal_mutex_def_t;
|
||||
typedef osal_semaphore_t osal_mutex_t;
|
||||
|
||||
static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
|
||||
{
|
||||
mdef->count = 1;
|
||||
return mdef;
|
||||
}
|
||||
|
||||
static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
|
||||
{
|
||||
return osal_semaphore_wait(mutex_hdl, msec);
|
||||
}
|
||||
|
||||
static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
|
||||
{
|
||||
return osal_semaphore_post(mutex_hdl, false);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// QUEUE API
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_fifo.h"
|
||||
|
||||
// extern to avoid including dcd.h and hcd.h
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
extern void dcd_int_disable(uint8_t rhport);
|
||||
extern void dcd_int_enable(uint8_t rhport);
|
||||
#endif
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
extern void hcd_int_disable(uint8_t rhport);
|
||||
extern void hcd_int_enable(uint8_t rhport);
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t role; // device or host
|
||||
tu_fifo_t ff;
|
||||
}osal_queue_def_t;
|
||||
|
||||
typedef osal_queue_def_t* osal_queue_t;
|
||||
|
||||
// role device/host is used by OS NONE for mutex (disable usb isr) only
|
||||
#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
|
||||
uint8_t _name##_buf[_depth*sizeof(_type)]; \
|
||||
osal_queue_def_t _name = { \
|
||||
.role = _role, \
|
||||
.ff = { \
|
||||
.buffer = _name##_buf, \
|
||||
.depth = _depth, \
|
||||
.item_size = sizeof(_type), \
|
||||
.overwritable = false, \
|
||||
}\
|
||||
}
|
||||
|
||||
// lock queue by disable usb isr
|
||||
static inline void _osal_q_lock(osal_queue_t qhdl)
|
||||
{
|
||||
(void) qhdl;
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
if (qhdl->role == OPT_MODE_DEVICE) dcd_int_disable(TUD_OPT_RHPORT);
|
||||
#endif
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
if (qhdl->role == OPT_MODE_HOST) hcd_int_disable(TUH_OPT_RHPORT);
|
||||
#endif
|
||||
}
|
||||
|
||||
// unlock queue
|
||||
static inline void _osal_q_unlock(osal_queue_t qhdl)
|
||||
{
|
||||
(void) qhdl;
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
if (qhdl->role == OPT_MODE_DEVICE) dcd_int_enable(TUD_OPT_RHPORT);
|
||||
#endif
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
if (qhdl->role == OPT_MODE_HOST) hcd_int_enable(TUH_OPT_RHPORT);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
|
||||
{
|
||||
tu_fifo_clear(&qdef->ff);
|
||||
return (osal_queue_t) qdef;
|
||||
}
|
||||
|
||||
// non blocking
|
||||
static inline bool osal_queue_receive(osal_queue_t const qhdl, void* data)
|
||||
{
|
||||
_osal_q_lock(qhdl);
|
||||
bool success = tu_fifo_read(&qhdl->ff, data);
|
||||
_osal_q_unlock(qhdl);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline bool osal_queue_send(osal_queue_t const qhdl, void const * data, bool in_isr)
|
||||
{
|
||||
if (!in_isr) {
|
||||
_osal_q_lock(qhdl);
|
||||
}
|
||||
|
||||
bool success = tu_fifo_write(&qhdl->ff, data);
|
||||
|
||||
if (!in_isr) {
|
||||
_osal_q_unlock(qhdl);
|
||||
}
|
||||
|
||||
TU_ASSERT(success);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_OSAL_NONE_H_ */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_OSAL_NONE_H_
|
||||
#define _TUSB_OSAL_NONE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TASK API
|
||||
//--------------------------------------------------------------------+
|
||||
static inline void osal_task_delay(uint32_t msec)
|
||||
{
|
||||
(void) msec;
|
||||
// TODO only used by Host stack, will implement using SOF
|
||||
|
||||
// uint32_t start = tusb_hal_millis();
|
||||
// while ( ( tusb_hal_millis() - start ) < msec ) {}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binary Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
volatile uint16_t count;
|
||||
}osal_semaphore_def_t;
|
||||
|
||||
typedef osal_semaphore_def_t* osal_semaphore_t;
|
||||
|
||||
static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
|
||||
{
|
||||
semdef->count = 0;
|
||||
return semdef;
|
||||
}
|
||||
|
||||
static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
|
||||
{
|
||||
(void) in_isr;
|
||||
sem_hdl->count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO blocking for now
|
||||
static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
|
||||
{
|
||||
(void) msec;
|
||||
|
||||
while (sem_hdl->count == 0) { }
|
||||
sem_hdl->count--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
|
||||
{
|
||||
sem_hdl->count = 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MUTEX API
|
||||
// Within tinyusb, mutex is never used in ISR context
|
||||
//--------------------------------------------------------------------+
|
||||
typedef osal_semaphore_def_t osal_mutex_def_t;
|
||||
typedef osal_semaphore_t osal_mutex_t;
|
||||
|
||||
static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
|
||||
{
|
||||
mdef->count = 1;
|
||||
return mdef;
|
||||
}
|
||||
|
||||
static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
|
||||
{
|
||||
return osal_semaphore_wait(mutex_hdl, msec);
|
||||
}
|
||||
|
||||
static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
|
||||
{
|
||||
return osal_semaphore_post(mutex_hdl, false);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// QUEUE API
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_fifo.h"
|
||||
|
||||
// extern to avoid including dcd.h and hcd.h
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
extern void dcd_int_disable(uint8_t rhport);
|
||||
extern void dcd_int_enable(uint8_t rhport);
|
||||
#endif
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
extern void hcd_int_disable(uint8_t rhport);
|
||||
extern void hcd_int_enable(uint8_t rhport);
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t role; // device or host
|
||||
tu_fifo_t ff;
|
||||
}osal_queue_def_t;
|
||||
|
||||
typedef osal_queue_def_t* osal_queue_t;
|
||||
|
||||
// role device/host is used by OS NONE for mutex (disable usb isr) only
|
||||
#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
|
||||
uint8_t _name##_buf[_depth*sizeof(_type)]; \
|
||||
osal_queue_def_t _name = { \
|
||||
.role = _role, \
|
||||
.ff = { \
|
||||
.buffer = _name##_buf, \
|
||||
.depth = _depth, \
|
||||
.item_size = sizeof(_type), \
|
||||
.overwritable = false, \
|
||||
}\
|
||||
}
|
||||
|
||||
// lock queue by disable usb isr
|
||||
static inline void _osal_q_lock(osal_queue_t qhdl)
|
||||
{
|
||||
(void) qhdl;
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
if (qhdl->role == OPT_MODE_DEVICE) dcd_int_disable(TUD_OPT_RHPORT);
|
||||
#endif
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
if (qhdl->role == OPT_MODE_HOST) hcd_int_disable(TUH_OPT_RHPORT);
|
||||
#endif
|
||||
}
|
||||
|
||||
// unlock queue
|
||||
static inline void _osal_q_unlock(osal_queue_t qhdl)
|
||||
{
|
||||
(void) qhdl;
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
if (qhdl->role == OPT_MODE_DEVICE) dcd_int_enable(TUD_OPT_RHPORT);
|
||||
#endif
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
if (qhdl->role == OPT_MODE_HOST) hcd_int_enable(TUH_OPT_RHPORT);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
|
||||
{
|
||||
tu_fifo_clear(&qdef->ff);
|
||||
return (osal_queue_t) qdef;
|
||||
}
|
||||
|
||||
// non blocking
|
||||
static inline bool osal_queue_receive(osal_queue_t const qhdl, void* data)
|
||||
{
|
||||
_osal_q_lock(qhdl);
|
||||
bool success = tu_fifo_read(&qhdl->ff, data);
|
||||
_osal_q_unlock(qhdl);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline bool osal_queue_send(osal_queue_t const qhdl, void const * data, bool in_isr)
|
||||
{
|
||||
if (!in_isr) {
|
||||
_osal_q_lock(qhdl);
|
||||
}
|
||||
|
||||
bool success = tu_fifo_write(&qhdl->ff, data);
|
||||
|
||||
if (!in_isr) {
|
||||
_osal_q_unlock(qhdl);
|
||||
}
|
||||
|
||||
TU_ASSERT(success);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_OSAL_NONE_H_ */
|
||||
|
@ -1,444 +1,444 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Peter Lawrence
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/*
|
||||
Theory of operation:
|
||||
|
||||
The NUC121/NUC125/NUC126 USBD peripheral has eight "EP"s, but each is simplex,
|
||||
so two collectively (peripheral nomenclature of "EP0" and "EP1") are needed to
|
||||
implement USB EP0. PERIPH_EP0 and PERIPH_EP1 are used by this driver for
|
||||
EP0_IN and EP0_OUT respectively. This leaves up to six for user usage.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED && ( (CFG_TUSB_MCU == OPT_MCU_NUC121) || (CFG_TUSB_MCU == OPT_MCU_NUC126) )
|
||||
|
||||
#include "device/dcd.h"
|
||||
#include "NuMicro.h"
|
||||
|
||||
/* allocation of USBD RAM for Setup, EP0_IN, and and EP_OUT */
|
||||
#define PERIPH_SETUP_BUF_BASE 0
|
||||
#define PERIPH_SETUP_BUF_LEN 8
|
||||
#define PERIPH_EP0_BUF_BASE (PERIPH_SETUP_BUF_BASE + PERIPH_SETUP_BUF_LEN)
|
||||
#define PERIPH_EP0_BUF_LEN CFG_TUD_ENDPOINT0_SIZE
|
||||
#define PERIPH_EP1_BUF_BASE (PERIPH_EP0_BUF_BASE + PERIPH_EP0_BUF_LEN)
|
||||
#define PERIPH_EP1_BUF_LEN CFG_TUD_ENDPOINT0_SIZE
|
||||
#define PERIPH_EP2_BUF_BASE (PERIPH_EP1_BUF_BASE + PERIPH_EP1_BUF_LEN)
|
||||
|
||||
/* rather important info unfortunately not provided by device include files: how much there is */
|
||||
#define USBD_BUF_SIZE ((CFG_TUSB_MCU == OPT_MCU_NUC121) ? 768 : 512)
|
||||
|
||||
enum ep_enum
|
||||
{
|
||||
PERIPH_EP0 = 0,
|
||||
PERIPH_EP1 = 1,
|
||||
PERIPH_EP2 = 2,
|
||||
PERIPH_EP3 = 3,
|
||||
PERIPH_EP4 = 4,
|
||||
PERIPH_EP5 = 5,
|
||||
PERIPH_EP6 = 6,
|
||||
PERIPH_EP7 = 7,
|
||||
PERIPH_MAX_EP,
|
||||
};
|
||||
|
||||
/* set by dcd_set_address() */
|
||||
static volatile uint8_t assigned_address;
|
||||
|
||||
/* reset by dcd_init(), this is used by dcd_edpt_open() to assign USBD peripheral buffer addresses */
|
||||
static uint32_t bufseg_addr;
|
||||
|
||||
/* used by dcd_edpt_xfer() and the ISR to reset the data sync (DATA0/DATA1) in an EP0_IN transfer */
|
||||
static bool active_ep0_xfer;
|
||||
|
||||
/* RAM table needed to track ongoing transfers performed by dcd_edpt_xfer(), dcd_in_xfer(), and the ISR */
|
||||
static struct xfer_ctl_t
|
||||
{
|
||||
uint8_t *data_ptr; /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */
|
||||
union {
|
||||
uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */
|
||||
uint16_t out_bytes_so_far; /* but for OUT endpoints, we track how many bytes we've transferred so far */
|
||||
};
|
||||
uint16_t max_packet_size; /* needed since device driver only finds out this at runtime */
|
||||
uint16_t total_bytes; /* quantity needed to pass as argument to dcd_event_xfer_complete() (for IN endpoints) */
|
||||
} xfer_table[PERIPH_MAX_EP];
|
||||
|
||||
/*
|
||||
local helper functions
|
||||
*/
|
||||
|
||||
static void usb_attach(void)
|
||||
{
|
||||
USBD->SE0 &= ~USBD_SE0_SE0_Msk;
|
||||
}
|
||||
|
||||
static void usb_detach(void)
|
||||
{
|
||||
USBD->SE0 |= USBD_SE0_SE0_Msk;
|
||||
}
|
||||
|
||||
static void usb_control_send_zlp(void)
|
||||
{
|
||||
USBD->EP[PERIPH_EP0].CFG |= USBD_CFG_DSQSYNC_Msk;
|
||||
USBD->EP[PERIPH_EP0].MXPLD = 0;
|
||||
}
|
||||
|
||||
/* reconstruct ep_addr from particular USB Configuration Register */
|
||||
static uint8_t decode_ep_addr(USBD_EP_T *ep)
|
||||
{
|
||||
uint8_t ep_addr = ep->CFG & USBD_CFG_EPNUM_Msk;
|
||||
if ( USBD_CFG_EPMODE_IN == (ep->CFG & USBD_CFG_STATE_Msk) )
|
||||
ep_addr |= TUSB_DIR_IN_MASK;
|
||||
return ep_addr;
|
||||
}
|
||||
|
||||
/* map 8-bit ep_addr into peripheral endpoint index (PERIPH_EP0...) */
|
||||
static USBD_EP_T *ep_entry(uint8_t ep_addr, bool add)
|
||||
{
|
||||
USBD_EP_T *ep;
|
||||
enum ep_enum ep_index;
|
||||
|
||||
for (ep_index = PERIPH_EP0, ep = USBD->EP; ep_index < PERIPH_MAX_EP; ep_index++, ep++)
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
/* take first peripheral endpoint that is unused */
|
||||
if (0 == (ep->CFG & USBD_CFG_STATE_Msk)) return ep;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* find a peripheral endpoint that matches ep_addr */
|
||||
uint8_t candidate_ep_addr = decode_ep_addr(ep);
|
||||
if (candidate_ep_addr == ep_addr) return ep;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* perform an IN endpoint transfer; this is called by dcd_edpt_xfer() and the ISR */
|
||||
static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
|
||||
{
|
||||
uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size);
|
||||
|
||||
memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now);
|
||||
ep->MXPLD = bytes_now;
|
||||
}
|
||||
|
||||
/* centralized location for USBD interrupt enable bit mask */
|
||||
static const uint32_t enabled_irqs = USBD_INTSTS_VBDETIF_Msk | USBD_INTSTS_BUSIF_Msk | USBD_INTSTS_SETUP_Msk | USBD_INTSTS_USBIF_Msk | USBD_INTSTS_SOFIF_Msk;
|
||||
|
||||
/*
|
||||
NUC121/NUC125/NUC126 TinyUSB API driver implementation
|
||||
*/
|
||||
|
||||
void dcd_init(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
#ifdef SUPPORT_LPM
|
||||
USBD->ATTR = 0x7D0 | USBD_LPMACK;
|
||||
#else
|
||||
USBD->ATTR = 0x7D0;
|
||||
#endif
|
||||
|
||||
usb_detach();
|
||||
|
||||
USBD->STBUFSEG = PERIPH_SETUP_BUF_BASE;
|
||||
|
||||
for (enum ep_enum ep_index = PERIPH_EP0; ep_index < PERIPH_MAX_EP; ep_index++)
|
||||
{
|
||||
USBD->EP[ep_index].CFGP &= ~USBD_CFG_STATE_Msk;
|
||||
}
|
||||
|
||||
/* allocate the default EP0 endpoints */
|
||||
|
||||
USBD->EP[PERIPH_EP0].CFG = USBD_CFG_CSTALL_Msk | USBD_CFG_EPMODE_IN;
|
||||
USBD->EP[PERIPH_EP0].BUFSEG = PERIPH_EP0_BUF_BASE;
|
||||
xfer_table[PERIPH_EP0].max_packet_size = PERIPH_EP0_BUF_LEN;
|
||||
|
||||
USBD->EP[PERIPH_EP1].CFG = USBD_CFG_CSTALL_Msk | USBD_CFG_EPMODE_OUT;
|
||||
USBD->EP[PERIPH_EP1].BUFSEG = PERIPH_EP1_BUF_BASE;
|
||||
xfer_table[PERIPH_EP1].max_packet_size = PERIPH_EP1_BUF_LEN;
|
||||
|
||||
/* USB RAM beyond what we've allocated above is available to the user */
|
||||
bufseg_addr = PERIPH_EP2_BUF_BASE;
|
||||
|
||||
usb_attach();
|
||||
|
||||
USBD->INTSTS = enabled_irqs;
|
||||
USBD->INTEN = enabled_irqs;
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
NVIC_EnableIRQ(USBD_IRQn);
|
||||
}
|
||||
|
||||
void dcd_int_disable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
NVIC_DisableIRQ(USBD_IRQn);
|
||||
}
|
||||
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
usb_control_send_zlp(); /* SET_ADDRESS is the one exception where TinyUSB doesn't use dcd_edpt_xfer() to generate a ZLP */
|
||||
assigned_address = dev_addr;
|
||||
}
|
||||
|
||||
void dcd_set_config(uint8_t rhport, uint8_t config_num)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) config_num;
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
USBD->ATTR = USBD_ATTR_RWAKEUP_Msk;
|
||||
}
|
||||
|
||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
USBD_EP_T *ep = ep_entry(p_endpoint_desc->bEndpointAddress, true);
|
||||
TU_ASSERT(ep);
|
||||
|
||||
/* mine the data for the information we need */
|
||||
int const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
|
||||
int const size = p_endpoint_desc->wMaxPacketSize.size;
|
||||
tusb_xfer_type_t const type = p_endpoint_desc->bmAttributes.xfer;
|
||||
struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
|
||||
|
||||
/* allocate buffer from USB RAM */
|
||||
ep->BUFSEG = bufseg_addr;
|
||||
bufseg_addr += size;
|
||||
TU_ASSERT(bufseg_addr <= USBD_BUF_SIZE);
|
||||
|
||||
/* construct USB Configuration Register value and then write it */
|
||||
uint32_t cfg = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
|
||||
cfg |= (TUSB_DIR_IN == dir) ? USBD_CFG_EPMODE_IN : USBD_CFG_EPMODE_OUT;
|
||||
if (TUSB_XFER_ISOCHRONOUS == type)
|
||||
cfg |= USBD_CFG_TYPE_ISO;
|
||||
ep->CFG = cfg;
|
||||
|
||||
/* make a note of the endpoint size */
|
||||
xfer->max_packet_size = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
/* mine the data for the information we need */
|
||||
tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
USBD_EP_T *ep = ep_entry(ep_addr, false);
|
||||
struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
|
||||
|
||||
/* store away the information we'll needing now and later */
|
||||
xfer->data_ptr = buffer;
|
||||
xfer->in_remaining_bytes = total_bytes;
|
||||
xfer->total_bytes = total_bytes;
|
||||
|
||||
/* for the first of one or more EP0_IN packets in a message, the first must be DATA1 */
|
||||
if ( (0x80 == ep_addr) && !active_ep0_xfer ) ep->CFG |= USBD_CFG_DSQSYNC_Msk;
|
||||
|
||||
if (TUSB_DIR_IN == dir)
|
||||
{
|
||||
dcd_in_xfer(xfer, ep);
|
||||
}
|
||||
else
|
||||
{
|
||||
xfer->out_bytes_so_far = 0;
|
||||
ep->MXPLD = xfer->max_packet_size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
USBD_EP_T *ep = ep_entry(ep_addr, false);
|
||||
ep->CFGP |= USBD_CFGP_SSTALL_Msk;
|
||||
}
|
||||
|
||||
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
USBD_EP_T *ep = ep_entry(ep_addr, false);
|
||||
ep->CFG |= USBD_CFG_CSTALL_Msk;
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(void)
|
||||
{
|
||||
uint32_t status = USBD->INTSTS;
|
||||
#ifdef SUPPORT_LPM
|
||||
uint32_t state = USBD->ATTR & 0x300f;
|
||||
#else
|
||||
uint32_t state = USBD->ATTR & 0xf;
|
||||
#endif
|
||||
|
||||
if(status & USBD_INTSTS_VBDETIF_Msk)
|
||||
{
|
||||
if(USBD->VBUSDET & USBD_VBUSDET_VBUSDET_Msk)
|
||||
{
|
||||
/* USB connect */
|
||||
USBD->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* USB disconnect */
|
||||
USBD->ATTR &= ~USBD_ATTR_USBEN_Msk;
|
||||
}
|
||||
}
|
||||
|
||||
if(status & USBD_INTSTS_BUSIF_Msk)
|
||||
{
|
||||
if(state & USBD_ATTR_USBRST_Msk)
|
||||
{
|
||||
/* USB bus reset */
|
||||
USBD->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
|
||||
|
||||
/* Reset all endpoints to DATA0 */
|
||||
for(enum ep_enum ep_index = PERIPH_EP0; ep_index < PERIPH_MAX_EP; ep_index++)
|
||||
USBD->EP[ep_index].CFG &= ~USBD_CFG_DSQSYNC_Msk;
|
||||
|
||||
/* Reset USB device address */
|
||||
USBD->FADDR = 0;
|
||||
|
||||
/* reset EP0_IN flag */
|
||||
active_ep0_xfer = false;
|
||||
|
||||
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
|
||||
}
|
||||
|
||||
if(state & USBD_ATTR_SUSPEND_Msk)
|
||||
{
|
||||
/* Enable USB but disable PHY */
|
||||
USBD->ATTR &= ~USBD_ATTR_PHYEN_Msk;
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
|
||||
}
|
||||
|
||||
if(state & USBD_ATTR_RESUME_Msk)
|
||||
{
|
||||
/* Enable USB and enable PHY */
|
||||
USBD->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
|
||||
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
|
||||
}
|
||||
}
|
||||
|
||||
if(status & USBD_INTSTS_SETUP_Msk)
|
||||
{
|
||||
/* clear the data ready flag of control endpoints */
|
||||
USBD->EP[PERIPH_EP0].CFGP |= USBD_CFGP_CLRRDY_Msk;
|
||||
USBD->EP[PERIPH_EP1].CFGP |= USBD_CFGP_CLRRDY_Msk;
|
||||
|
||||
/* get SETUP packet from USB buffer */
|
||||
dcd_event_setup_received(0, (uint8_t *)USBD_BUF_BASE, true);
|
||||
}
|
||||
|
||||
if(status & USBD_INTSTS_USBIF_Msk)
|
||||
{
|
||||
if (status & USBD_INTSTS_EPEVT0_Msk) /* PERIPH_EP0 (EP0_IN) event: this is treated separately from the rest */
|
||||
{
|
||||
/* given ACK from host has happened, we can now set the address (if not already done) */
|
||||
if((USBD->FADDR != assigned_address) && (USBD->FADDR == 0)) USBD->FADDR = assigned_address;
|
||||
|
||||
uint16_t const available_bytes = USBD->EP[PERIPH_EP0].MXPLD;
|
||||
|
||||
active_ep0_xfer = (available_bytes == xfer_table[PERIPH_EP0].max_packet_size);
|
||||
|
||||
dcd_event_xfer_complete(0, 0x80, available_bytes, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
|
||||
/* service PERIPH_EP1 through PERIPH_EP7 */
|
||||
enum ep_enum ep_index;
|
||||
uint32_t mask;
|
||||
struct xfer_ctl_t *xfer;
|
||||
USBD_EP_T *ep;
|
||||
for (ep_index = PERIPH_EP1, mask = USBD_INTSTS_EPEVT1_Msk, xfer = &xfer_table[PERIPH_EP1], ep = &USBD->EP[PERIPH_EP1]; ep_index <= PERIPH_EP7; ep_index++, mask <<= 1, xfer++, ep++)
|
||||
{
|
||||
if(status & mask)
|
||||
{
|
||||
USBD->INTSTS = mask;
|
||||
|
||||
uint16_t const available_bytes = ep->MXPLD;
|
||||
uint8_t const ep_addr = decode_ep_addr(ep);
|
||||
bool const out_ep = !(ep_addr & TUSB_DIR_IN_MASK);
|
||||
|
||||
if (out_ep)
|
||||
{
|
||||
/* copy the data from the PC to the previously provided buffer */
|
||||
memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes);
|
||||
xfer->out_bytes_so_far += available_bytes;
|
||||
xfer->data_ptr += available_bytes;
|
||||
|
||||
/* when the transfer is finished, alert TinyUSB; otherwise, accept more data */
|
||||
if ( (xfer->total_bytes == xfer->out_bytes_so_far) || (available_bytes < xfer->max_packet_size) )
|
||||
dcd_event_xfer_complete(0, ep_addr, xfer->out_bytes_so_far, XFER_RESULT_SUCCESS, true);
|
||||
else
|
||||
ep->MXPLD = xfer->max_packet_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* update the bookkeeping to reflect the data that has now been sent to the PC */
|
||||
xfer->in_remaining_bytes -= available_bytes;
|
||||
xfer->data_ptr += available_bytes;
|
||||
|
||||
/* if more data to send, send it; otherwise, alert TinyUSB that we've finished */
|
||||
if (xfer->in_remaining_bytes)
|
||||
dcd_in_xfer(xfer, ep);
|
||||
else
|
||||
dcd_event_xfer_complete(0, ep_addr, xfer->total_bytes, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(status & USBD_INTSTS_SOFIF_Msk)
|
||||
{
|
||||
/* Start-Of-Frame event */
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
|
||||
}
|
||||
|
||||
/* acknowledge all interrupts */
|
||||
USBD->INTSTS = status & enabled_irqs;
|
||||
}
|
||||
|
||||
void dcd_isr(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
USBD_IRQHandler();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Peter Lawrence
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/*
|
||||
Theory of operation:
|
||||
|
||||
The NUC121/NUC125/NUC126 USBD peripheral has eight "EP"s, but each is simplex,
|
||||
so two collectively (peripheral nomenclature of "EP0" and "EP1") are needed to
|
||||
implement USB EP0. PERIPH_EP0 and PERIPH_EP1 are used by this driver for
|
||||
EP0_IN and EP0_OUT respectively. This leaves up to six for user usage.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED && ( (CFG_TUSB_MCU == OPT_MCU_NUC121) || (CFG_TUSB_MCU == OPT_MCU_NUC126) )
|
||||
|
||||
#include "device/dcd.h"
|
||||
#include "NuMicro.h"
|
||||
|
||||
/* allocation of USBD RAM for Setup, EP0_IN, and and EP_OUT */
|
||||
#define PERIPH_SETUP_BUF_BASE 0
|
||||
#define PERIPH_SETUP_BUF_LEN 8
|
||||
#define PERIPH_EP0_BUF_BASE (PERIPH_SETUP_BUF_BASE + PERIPH_SETUP_BUF_LEN)
|
||||
#define PERIPH_EP0_BUF_LEN CFG_TUD_ENDPOINT0_SIZE
|
||||
#define PERIPH_EP1_BUF_BASE (PERIPH_EP0_BUF_BASE + PERIPH_EP0_BUF_LEN)
|
||||
#define PERIPH_EP1_BUF_LEN CFG_TUD_ENDPOINT0_SIZE
|
||||
#define PERIPH_EP2_BUF_BASE (PERIPH_EP1_BUF_BASE + PERIPH_EP1_BUF_LEN)
|
||||
|
||||
/* rather important info unfortunately not provided by device include files: how much there is */
|
||||
#define USBD_BUF_SIZE ((CFG_TUSB_MCU == OPT_MCU_NUC121) ? 768 : 512)
|
||||
|
||||
enum ep_enum
|
||||
{
|
||||
PERIPH_EP0 = 0,
|
||||
PERIPH_EP1 = 1,
|
||||
PERIPH_EP2 = 2,
|
||||
PERIPH_EP3 = 3,
|
||||
PERIPH_EP4 = 4,
|
||||
PERIPH_EP5 = 5,
|
||||
PERIPH_EP6 = 6,
|
||||
PERIPH_EP7 = 7,
|
||||
PERIPH_MAX_EP,
|
||||
};
|
||||
|
||||
/* set by dcd_set_address() */
|
||||
static volatile uint8_t assigned_address;
|
||||
|
||||
/* reset by dcd_init(), this is used by dcd_edpt_open() to assign USBD peripheral buffer addresses */
|
||||
static uint32_t bufseg_addr;
|
||||
|
||||
/* used by dcd_edpt_xfer() and the ISR to reset the data sync (DATA0/DATA1) in an EP0_IN transfer */
|
||||
static bool active_ep0_xfer;
|
||||
|
||||
/* RAM table needed to track ongoing transfers performed by dcd_edpt_xfer(), dcd_in_xfer(), and the ISR */
|
||||
static struct xfer_ctl_t
|
||||
{
|
||||
uint8_t *data_ptr; /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */
|
||||
union {
|
||||
uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */
|
||||
uint16_t out_bytes_so_far; /* but for OUT endpoints, we track how many bytes we've transferred so far */
|
||||
};
|
||||
uint16_t max_packet_size; /* needed since device driver only finds out this at runtime */
|
||||
uint16_t total_bytes; /* quantity needed to pass as argument to dcd_event_xfer_complete() (for IN endpoints) */
|
||||
} xfer_table[PERIPH_MAX_EP];
|
||||
|
||||
/*
|
||||
local helper functions
|
||||
*/
|
||||
|
||||
static void usb_attach(void)
|
||||
{
|
||||
USBD->SE0 &= ~USBD_SE0_SE0_Msk;
|
||||
}
|
||||
|
||||
static void usb_detach(void)
|
||||
{
|
||||
USBD->SE0 |= USBD_SE0_SE0_Msk;
|
||||
}
|
||||
|
||||
static void usb_control_send_zlp(void)
|
||||
{
|
||||
USBD->EP[PERIPH_EP0].CFG |= USBD_CFG_DSQSYNC_Msk;
|
||||
USBD->EP[PERIPH_EP0].MXPLD = 0;
|
||||
}
|
||||
|
||||
/* reconstruct ep_addr from particular USB Configuration Register */
|
||||
static uint8_t decode_ep_addr(USBD_EP_T *ep)
|
||||
{
|
||||
uint8_t ep_addr = ep->CFG & USBD_CFG_EPNUM_Msk;
|
||||
if ( USBD_CFG_EPMODE_IN == (ep->CFG & USBD_CFG_STATE_Msk) )
|
||||
ep_addr |= TUSB_DIR_IN_MASK;
|
||||
return ep_addr;
|
||||
}
|
||||
|
||||
/* map 8-bit ep_addr into peripheral endpoint index (PERIPH_EP0...) */
|
||||
static USBD_EP_T *ep_entry(uint8_t ep_addr, bool add)
|
||||
{
|
||||
USBD_EP_T *ep;
|
||||
enum ep_enum ep_index;
|
||||
|
||||
for (ep_index = PERIPH_EP0, ep = USBD->EP; ep_index < PERIPH_MAX_EP; ep_index++, ep++)
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
/* take first peripheral endpoint that is unused */
|
||||
if (0 == (ep->CFG & USBD_CFG_STATE_Msk)) return ep;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* find a peripheral endpoint that matches ep_addr */
|
||||
uint8_t candidate_ep_addr = decode_ep_addr(ep);
|
||||
if (candidate_ep_addr == ep_addr) return ep;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* perform an IN endpoint transfer; this is called by dcd_edpt_xfer() and the ISR */
|
||||
static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
|
||||
{
|
||||
uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size);
|
||||
|
||||
memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now);
|
||||
ep->MXPLD = bytes_now;
|
||||
}
|
||||
|
||||
/* centralized location for USBD interrupt enable bit mask */
|
||||
static const uint32_t enabled_irqs = USBD_INTSTS_VBDETIF_Msk | USBD_INTSTS_BUSIF_Msk | USBD_INTSTS_SETUP_Msk | USBD_INTSTS_USBIF_Msk | USBD_INTSTS_SOFIF_Msk;
|
||||
|
||||
/*
|
||||
NUC121/NUC125/NUC126 TinyUSB API driver implementation
|
||||
*/
|
||||
|
||||
void dcd_init(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
#ifdef SUPPORT_LPM
|
||||
USBD->ATTR = 0x7D0 | USBD_LPMACK;
|
||||
#else
|
||||
USBD->ATTR = 0x7D0;
|
||||
#endif
|
||||
|
||||
usb_detach();
|
||||
|
||||
USBD->STBUFSEG = PERIPH_SETUP_BUF_BASE;
|
||||
|
||||
for (enum ep_enum ep_index = PERIPH_EP0; ep_index < PERIPH_MAX_EP; ep_index++)
|
||||
{
|
||||
USBD->EP[ep_index].CFGP &= ~USBD_CFG_STATE_Msk;
|
||||
}
|
||||
|
||||
/* allocate the default EP0 endpoints */
|
||||
|
||||
USBD->EP[PERIPH_EP0].CFG = USBD_CFG_CSTALL_Msk | USBD_CFG_EPMODE_IN;
|
||||
USBD->EP[PERIPH_EP0].BUFSEG = PERIPH_EP0_BUF_BASE;
|
||||
xfer_table[PERIPH_EP0].max_packet_size = PERIPH_EP0_BUF_LEN;
|
||||
|
||||
USBD->EP[PERIPH_EP1].CFG = USBD_CFG_CSTALL_Msk | USBD_CFG_EPMODE_OUT;
|
||||
USBD->EP[PERIPH_EP1].BUFSEG = PERIPH_EP1_BUF_BASE;
|
||||
xfer_table[PERIPH_EP1].max_packet_size = PERIPH_EP1_BUF_LEN;
|
||||
|
||||
/* USB RAM beyond what we've allocated above is available to the user */
|
||||
bufseg_addr = PERIPH_EP2_BUF_BASE;
|
||||
|
||||
usb_attach();
|
||||
|
||||
USBD->INTSTS = enabled_irqs;
|
||||
USBD->INTEN = enabled_irqs;
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
NVIC_EnableIRQ(USBD_IRQn);
|
||||
}
|
||||
|
||||
void dcd_int_disable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
NVIC_DisableIRQ(USBD_IRQn);
|
||||
}
|
||||
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
usb_control_send_zlp(); /* SET_ADDRESS is the one exception where TinyUSB doesn't use dcd_edpt_xfer() to generate a ZLP */
|
||||
assigned_address = dev_addr;
|
||||
}
|
||||
|
||||
void dcd_set_config(uint8_t rhport, uint8_t config_num)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) config_num;
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
USBD->ATTR = USBD_ATTR_RWAKEUP_Msk;
|
||||
}
|
||||
|
||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
USBD_EP_T *ep = ep_entry(p_endpoint_desc->bEndpointAddress, true);
|
||||
TU_ASSERT(ep);
|
||||
|
||||
/* mine the data for the information we need */
|
||||
int const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
|
||||
int const size = p_endpoint_desc->wMaxPacketSize.size;
|
||||
tusb_xfer_type_t const type = p_endpoint_desc->bmAttributes.xfer;
|
||||
struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
|
||||
|
||||
/* allocate buffer from USB RAM */
|
||||
ep->BUFSEG = bufseg_addr;
|
||||
bufseg_addr += size;
|
||||
TU_ASSERT(bufseg_addr <= USBD_BUF_SIZE);
|
||||
|
||||
/* construct USB Configuration Register value and then write it */
|
||||
uint32_t cfg = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
|
||||
cfg |= (TUSB_DIR_IN == dir) ? USBD_CFG_EPMODE_IN : USBD_CFG_EPMODE_OUT;
|
||||
if (TUSB_XFER_ISOCHRONOUS == type)
|
||||
cfg |= USBD_CFG_TYPE_ISO;
|
||||
ep->CFG = cfg;
|
||||
|
||||
/* make a note of the endpoint size */
|
||||
xfer->max_packet_size = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
/* mine the data for the information we need */
|
||||
tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
USBD_EP_T *ep = ep_entry(ep_addr, false);
|
||||
struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
|
||||
|
||||
/* store away the information we'll needing now and later */
|
||||
xfer->data_ptr = buffer;
|
||||
xfer->in_remaining_bytes = total_bytes;
|
||||
xfer->total_bytes = total_bytes;
|
||||
|
||||
/* for the first of one or more EP0_IN packets in a message, the first must be DATA1 */
|
||||
if ( (0x80 == ep_addr) && !active_ep0_xfer ) ep->CFG |= USBD_CFG_DSQSYNC_Msk;
|
||||
|
||||
if (TUSB_DIR_IN == dir)
|
||||
{
|
||||
dcd_in_xfer(xfer, ep);
|
||||
}
|
||||
else
|
||||
{
|
||||
xfer->out_bytes_so_far = 0;
|
||||
ep->MXPLD = xfer->max_packet_size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
USBD_EP_T *ep = ep_entry(ep_addr, false);
|
||||
ep->CFGP |= USBD_CFGP_SSTALL_Msk;
|
||||
}
|
||||
|
||||
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
USBD_EP_T *ep = ep_entry(ep_addr, false);
|
||||
ep->CFG |= USBD_CFG_CSTALL_Msk;
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(void)
|
||||
{
|
||||
uint32_t status = USBD->INTSTS;
|
||||
#ifdef SUPPORT_LPM
|
||||
uint32_t state = USBD->ATTR & 0x300f;
|
||||
#else
|
||||
uint32_t state = USBD->ATTR & 0xf;
|
||||
#endif
|
||||
|
||||
if(status & USBD_INTSTS_VBDETIF_Msk)
|
||||
{
|
||||
if(USBD->VBUSDET & USBD_VBUSDET_VBUSDET_Msk)
|
||||
{
|
||||
/* USB connect */
|
||||
USBD->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* USB disconnect */
|
||||
USBD->ATTR &= ~USBD_ATTR_USBEN_Msk;
|
||||
}
|
||||
}
|
||||
|
||||
if(status & USBD_INTSTS_BUSIF_Msk)
|
||||
{
|
||||
if(state & USBD_ATTR_USBRST_Msk)
|
||||
{
|
||||
/* USB bus reset */
|
||||
USBD->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
|
||||
|
||||
/* Reset all endpoints to DATA0 */
|
||||
for(enum ep_enum ep_index = PERIPH_EP0; ep_index < PERIPH_MAX_EP; ep_index++)
|
||||
USBD->EP[ep_index].CFG &= ~USBD_CFG_DSQSYNC_Msk;
|
||||
|
||||
/* Reset USB device address */
|
||||
USBD->FADDR = 0;
|
||||
|
||||
/* reset EP0_IN flag */
|
||||
active_ep0_xfer = false;
|
||||
|
||||
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
|
||||
}
|
||||
|
||||
if(state & USBD_ATTR_SUSPEND_Msk)
|
||||
{
|
||||
/* Enable USB but disable PHY */
|
||||
USBD->ATTR &= ~USBD_ATTR_PHYEN_Msk;
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
|
||||
}
|
||||
|
||||
if(state & USBD_ATTR_RESUME_Msk)
|
||||
{
|
||||
/* Enable USB and enable PHY */
|
||||
USBD->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
|
||||
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
|
||||
}
|
||||
}
|
||||
|
||||
if(status & USBD_INTSTS_SETUP_Msk)
|
||||
{
|
||||
/* clear the data ready flag of control endpoints */
|
||||
USBD->EP[PERIPH_EP0].CFGP |= USBD_CFGP_CLRRDY_Msk;
|
||||
USBD->EP[PERIPH_EP1].CFGP |= USBD_CFGP_CLRRDY_Msk;
|
||||
|
||||
/* get SETUP packet from USB buffer */
|
||||
dcd_event_setup_received(0, (uint8_t *)USBD_BUF_BASE, true);
|
||||
}
|
||||
|
||||
if(status & USBD_INTSTS_USBIF_Msk)
|
||||
{
|
||||
if (status & USBD_INTSTS_EPEVT0_Msk) /* PERIPH_EP0 (EP0_IN) event: this is treated separately from the rest */
|
||||
{
|
||||
/* given ACK from host has happened, we can now set the address (if not already done) */
|
||||
if((USBD->FADDR != assigned_address) && (USBD->FADDR == 0)) USBD->FADDR = assigned_address;
|
||||
|
||||
uint16_t const available_bytes = USBD->EP[PERIPH_EP0].MXPLD;
|
||||
|
||||
active_ep0_xfer = (available_bytes == xfer_table[PERIPH_EP0].max_packet_size);
|
||||
|
||||
dcd_event_xfer_complete(0, 0x80, available_bytes, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
|
||||
/* service PERIPH_EP1 through PERIPH_EP7 */
|
||||
enum ep_enum ep_index;
|
||||
uint32_t mask;
|
||||
struct xfer_ctl_t *xfer;
|
||||
USBD_EP_T *ep;
|
||||
for (ep_index = PERIPH_EP1, mask = USBD_INTSTS_EPEVT1_Msk, xfer = &xfer_table[PERIPH_EP1], ep = &USBD->EP[PERIPH_EP1]; ep_index <= PERIPH_EP7; ep_index++, mask <<= 1, xfer++, ep++)
|
||||
{
|
||||
if(status & mask)
|
||||
{
|
||||
USBD->INTSTS = mask;
|
||||
|
||||
uint16_t const available_bytes = ep->MXPLD;
|
||||
uint8_t const ep_addr = decode_ep_addr(ep);
|
||||
bool const out_ep = !(ep_addr & TUSB_DIR_IN_MASK);
|
||||
|
||||
if (out_ep)
|
||||
{
|
||||
/* copy the data from the PC to the previously provided buffer */
|
||||
memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes);
|
||||
xfer->out_bytes_so_far += available_bytes;
|
||||
xfer->data_ptr += available_bytes;
|
||||
|
||||
/* when the transfer is finished, alert TinyUSB; otherwise, accept more data */
|
||||
if ( (xfer->total_bytes == xfer->out_bytes_so_far) || (available_bytes < xfer->max_packet_size) )
|
||||
dcd_event_xfer_complete(0, ep_addr, xfer->out_bytes_so_far, XFER_RESULT_SUCCESS, true);
|
||||
else
|
||||
ep->MXPLD = xfer->max_packet_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* update the bookkeeping to reflect the data that has now been sent to the PC */
|
||||
xfer->in_remaining_bytes -= available_bytes;
|
||||
xfer->data_ptr += available_bytes;
|
||||
|
||||
/* if more data to send, send it; otherwise, alert TinyUSB that we've finished */
|
||||
if (xfer->in_remaining_bytes)
|
||||
dcd_in_xfer(xfer, ep);
|
||||
else
|
||||
dcd_event_xfer_complete(0, ep_addr, xfer->total_bytes, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(status & USBD_INTSTS_SOFIF_Msk)
|
||||
{
|
||||
/* Start-Of-Frame event */
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
|
||||
}
|
||||
|
||||
/* acknowledge all interrupts */
|
||||
USBD->INTSTS = status & enabled_irqs;
|
||||
}
|
||||
|
||||
void dcd_isr(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
USBD_IRQHandler();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
296
src/tusb.c
296
src/tusb.c
@ -1,148 +1,148 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED || TUSB_OPT_DEVICE_ENABLED
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
static bool _initialized = false;
|
||||
|
||||
// TODO clean up
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
#include "device/usbd_pvt.h"
|
||||
#endif
|
||||
|
||||
bool tusb_init(void)
|
||||
{
|
||||
// skip if already initialized
|
||||
if (_initialized) return true;
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
TU_ASSERT( usbh_init() ); // init host stack
|
||||
#endif
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
TU_ASSERT ( tud_init() ); // init device stack
|
||||
#endif
|
||||
|
||||
_initialized = true;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
bool tusb_inited(void)
|
||||
{
|
||||
return _initialized;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Debug
|
||||
*------------------------------------------------------------------*/
|
||||
#if CFG_TUSB_DEBUG
|
||||
#include <ctype.h>
|
||||
|
||||
char const* const tusb_strerr[TUSB_ERROR_COUNT] = { ERROR_TABLE(ERROR_STRING) };
|
||||
|
||||
static void dump_str_line(uint8_t const* buf, uint16_t count)
|
||||
{
|
||||
// each line is 16 bytes
|
||||
for(int i=0; i<count; i++)
|
||||
{
|
||||
const char ch = buf[i];
|
||||
tu_printf("%c", isprint(ch) ? ch : '.');
|
||||
}
|
||||
}
|
||||
|
||||
// size : item size in bytes
|
||||
// count : number of item
|
||||
// print offet or not (handfy for dumping large memory)
|
||||
void tu_print_mem(void const *buf, uint16_t count, uint8_t indent)
|
||||
{
|
||||
uint8_t const size = 1; // fixed 1 byte for now
|
||||
|
||||
if ( !buf || !count )
|
||||
{
|
||||
tu_printf("NULL\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t const *buf8 = (uint8_t const *) buf;
|
||||
|
||||
char format[] = "%00lX";
|
||||
format[2] += 2*size;
|
||||
|
||||
const uint8_t item_per_line = 16 / size;
|
||||
|
||||
for(uint32_t i=0; i<count; i++)
|
||||
{
|
||||
uint32_t value=0;
|
||||
|
||||
if ( i%item_per_line == 0 )
|
||||
{
|
||||
// Print Ascii
|
||||
if ( i != 0 )
|
||||
{
|
||||
tu_printf(" | ");
|
||||
dump_str_line(buf8-16, 16);
|
||||
tu_printf("\r\n");
|
||||
}
|
||||
|
||||
for(uint8_t s=0; s < indent; s++) tu_printf(" ");
|
||||
|
||||
// print offset or absolute address
|
||||
tu_printf("%03lX: ", 16*i/item_per_line);
|
||||
}
|
||||
|
||||
memcpy(&value, buf8, size);
|
||||
buf8 += size;
|
||||
|
||||
tu_printf(" ");
|
||||
tu_printf(format, value);
|
||||
}
|
||||
|
||||
// fill up last row to 16 for printing ascii
|
||||
const uint16_t remain = count%16;
|
||||
uint8_t nback = (remain ? remain : 16);
|
||||
|
||||
if ( remain )
|
||||
{
|
||||
for(int i=0; i< 16-remain; i++)
|
||||
{
|
||||
tu_printf(" ");
|
||||
for(int j=0; j<2*size; j++) tu_printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
tu_printf(" | ");
|
||||
dump_str_line(buf8-nback, nback);
|
||||
tu_printf("\r\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // host or device enabled
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED || TUSB_OPT_DEVICE_ENABLED
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
static bool _initialized = false;
|
||||
|
||||
// TODO clean up
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
#include "device/usbd_pvt.h"
|
||||
#endif
|
||||
|
||||
bool tusb_init(void)
|
||||
{
|
||||
// skip if already initialized
|
||||
if (_initialized) return true;
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
TU_ASSERT( usbh_init() ); // init host stack
|
||||
#endif
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
TU_ASSERT ( tud_init() ); // init device stack
|
||||
#endif
|
||||
|
||||
_initialized = true;
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
bool tusb_inited(void)
|
||||
{
|
||||
return _initialized;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Debug
|
||||
*------------------------------------------------------------------*/
|
||||
#if CFG_TUSB_DEBUG
|
||||
#include <ctype.h>
|
||||
|
||||
char const* const tusb_strerr[TUSB_ERROR_COUNT] = { ERROR_TABLE(ERROR_STRING) };
|
||||
|
||||
static void dump_str_line(uint8_t const* buf, uint16_t count)
|
||||
{
|
||||
// each line is 16 bytes
|
||||
for(int i=0; i<count; i++)
|
||||
{
|
||||
const char ch = buf[i];
|
||||
tu_printf("%c", isprint(ch) ? ch : '.');
|
||||
}
|
||||
}
|
||||
|
||||
// size : item size in bytes
|
||||
// count : number of item
|
||||
// print offet or not (handfy for dumping large memory)
|
||||
void tu_print_mem(void const *buf, uint16_t count, uint8_t indent)
|
||||
{
|
||||
uint8_t const size = 1; // fixed 1 byte for now
|
||||
|
||||
if ( !buf || !count )
|
||||
{
|
||||
tu_printf("NULL\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t const *buf8 = (uint8_t const *) buf;
|
||||
|
||||
char format[] = "%00lX";
|
||||
format[2] += 2*size;
|
||||
|
||||
const uint8_t item_per_line = 16 / size;
|
||||
|
||||
for(uint32_t i=0; i<count; i++)
|
||||
{
|
||||
uint32_t value=0;
|
||||
|
||||
if ( i%item_per_line == 0 )
|
||||
{
|
||||
// Print Ascii
|
||||
if ( i != 0 )
|
||||
{
|
||||
tu_printf(" | ");
|
||||
dump_str_line(buf8-16, 16);
|
||||
tu_printf("\r\n");
|
||||
}
|
||||
|
||||
for(uint8_t s=0; s < indent; s++) tu_printf(" ");
|
||||
|
||||
// print offset or absolute address
|
||||
tu_printf("%03lX: ", 16*i/item_per_line);
|
||||
}
|
||||
|
||||
memcpy(&value, buf8, size);
|
||||
buf8 += size;
|
||||
|
||||
tu_printf(" ");
|
||||
tu_printf(format, value);
|
||||
}
|
||||
|
||||
// fill up last row to 16 for printing ascii
|
||||
const uint16_t remain = count%16;
|
||||
uint8_t nback = (remain ? remain : 16);
|
||||
|
||||
if ( remain )
|
||||
{
|
||||
for(int i=0; i< 16-remain; i++)
|
||||
{
|
||||
tu_printf(" ");
|
||||
for(int j=0; j<2*size; j++) tu_printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
tu_printf(" | ");
|
||||
dump_str_line(buf8-nback, nback);
|
||||
tu_printf("\r\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // host or device enabled
|
||||
|
236
src/tusb.h
236
src/tusb.h
@ -1,118 +1,118 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_H_
|
||||
#define _TUSB_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "osal/osal.h"
|
||||
#include "common/tusb_fifo.h"
|
||||
|
||||
//------------- HOST -------------//
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
#include "host/usbh.h"
|
||||
|
||||
#if HOST_CLASS_HID
|
||||
#include "class/hid/hid_host.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_MSC
|
||||
#include "class/msc/msc_host.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_CDC
|
||||
#include "class/cdc/cdc_host.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_VENDOR
|
||||
#include "class/vendor/vendor_host.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//------------- DEVICE -------------//
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
#include "device/usbd.h"
|
||||
|
||||
#if CFG_TUD_HID
|
||||
#include "class/hid/hid_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_CDC
|
||||
#include "class/cdc/cdc_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_MSC
|
||||
#include "class/msc/msc_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_MIDI
|
||||
#include "class/midi/midi_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_VENDOR
|
||||
#include "class/vendor/vendor_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_USBTMC
|
||||
#include "class/usbtmc/usbtmc_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_DFU_RT
|
||||
#include "class/dfu/dfu_rt_device.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \ingroup group_application_api
|
||||
* @{ */
|
||||
|
||||
// Initialize device/host stack
|
||||
bool tusb_init(void);
|
||||
|
||||
// Check if stack is initialized
|
||||
bool tusb_inited(void);
|
||||
|
||||
// TODO
|
||||
// bool tusb_teardown(void);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_H_ */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_H_
|
||||
#define _TUSB_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "osal/osal.h"
|
||||
#include "common/tusb_fifo.h"
|
||||
|
||||
//------------- HOST -------------//
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
#include "host/usbh.h"
|
||||
|
||||
#if HOST_CLASS_HID
|
||||
#include "class/hid/hid_host.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_MSC
|
||||
#include "class/msc/msc_host.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_CDC
|
||||
#include "class/cdc/cdc_host.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_VENDOR
|
||||
#include "class/vendor/vendor_host.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//------------- DEVICE -------------//
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
#include "device/usbd.h"
|
||||
|
||||
#if CFG_TUD_HID
|
||||
#include "class/hid/hid_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_CDC
|
||||
#include "class/cdc/cdc_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_MSC
|
||||
#include "class/msc/msc_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_MIDI
|
||||
#include "class/midi/midi_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_VENDOR
|
||||
#include "class/vendor/vendor_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_USBTMC
|
||||
#include "class/usbtmc/usbtmc_device.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_DFU_RT
|
||||
#include "class/dfu/dfu_rt_device.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \ingroup group_application_api
|
||||
* @{ */
|
||||
|
||||
// Initialize device/host stack
|
||||
bool tusb_init(void);
|
||||
|
||||
// Check if stack is initialized
|
||||
bool tusb_inited(void);
|
||||
|
||||
// TODO
|
||||
// bool tusb_teardown(void);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_H_ */
|
||||
|
@ -1,240 +1,240 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_OPTION_H_
|
||||
#define _TUSB_OPTION_H_
|
||||
|
||||
#define TUSB_VERSION_MAJOR 0
|
||||
#define TUSB_VERSION_MINOR 5
|
||||
#define TUSB_VERSION_REVISION 0
|
||||
#define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)
|
||||
|
||||
/** \defgroup group_mcu Supported MCU
|
||||
* \ref CFG_TUSB_MCU must be defined to one of these
|
||||
* @{ */
|
||||
|
||||
#define OPT_MCU_NONE 0
|
||||
|
||||
// LPC
|
||||
#define OPT_MCU_LPC11UXX 1 ///< NXP LPC11Uxx
|
||||
#define OPT_MCU_LPC13XX 2 ///< NXP LPC13xx
|
||||
#define OPT_MCU_LPC15XX 3 ///< NXP LPC15xx
|
||||
#define OPT_MCU_LPC175X_6X 4 ///< NXP LPC175x, LPC176x
|
||||
#define OPT_MCU_LPC177X_8X 5 ///< NXP LPC177x, LPC178x
|
||||
#define OPT_MCU_LPC18XX 6 ///< NXP LPC18xx
|
||||
#define OPT_MCU_LPC40XX 7 ///< NXP LPC40xx
|
||||
#define OPT_MCU_LPC43XX 8 ///< NXP LPC43xx
|
||||
#define OPT_MCU_LPC51UXX 9 ///< NXP LPC51U6x
|
||||
#define OPT_MCU_LPC54XXX 10 ///< NXP LPC54xxx
|
||||
#define OPT_MCU_LPC55XX 11 ///< NXP LPC55xx
|
||||
|
||||
// NRF
|
||||
#define OPT_MCU_NRF5X 100 ///< Nordic nRF5x series
|
||||
|
||||
// SAM
|
||||
#define OPT_MCU_SAMD21 200 ///< MicroChip SAMD21
|
||||
#define OPT_MCU_SAMD51 201 ///< MicroChip SAMD51
|
||||
#define OPT_MCU_SAMG 202 ///< MicroChip SAMDG series
|
||||
|
||||
// STM32
|
||||
#define OPT_MCU_STM32F0 300 ///< ST STM32F0
|
||||
#define OPT_MCU_STM32F1 301 ///< ST STM32F1
|
||||
#define OPT_MCU_STM32F2 302 ///< ST STM32F2
|
||||
#define OPT_MCU_STM32F3 303 ///< ST STM32F3
|
||||
#define OPT_MCU_STM32F4 304 ///< ST STM32F4
|
||||
#define OPT_MCU_STM32F7 305 ///< ST STM32F7
|
||||
#define OPT_MCU_STM32H7 306 ///< ST STM32H7
|
||||
#define OPT_MCU_STM32L0 307 ///< ST STM32L0
|
||||
#define OPT_MCU_STM32L1 308 ///< ST STM32L1
|
||||
#define OPT_MCU_STM32L4 309 ///< ST STM32L4
|
||||
|
||||
#define OPT_MCU_CXD56 400 ///< SONY CXD56
|
||||
|
||||
#define OPT_MCU_VALENTYUSB_EPTRI 600 ///< Fomu eptri config
|
||||
|
||||
#define OPT_MCU_MIMXRT10XX 700 ///< NXP iMX RT10xx
|
||||
|
||||
#define OPT_MCU_NUC121 800
|
||||
#define OPT_MCU_NUC126 801
|
||||
|
||||
/** @} */
|
||||
|
||||
/** \defgroup group_supported_os Supported RTOS
|
||||
* \ref CFG_TUSB_OS must be defined to one of these
|
||||
* @{ */
|
||||
#define OPT_OS_NONE 1 ///< No RTOS
|
||||
#define OPT_OS_FREERTOS 2 ///< FreeRTOS
|
||||
#define OPT_OS_MYNEWT 3 ///< Mynewt OS
|
||||
/** @} */
|
||||
|
||||
|
||||
// Allow to use command line to change the config name/location
|
||||
#ifndef CFG_TUSB_CONFIG_FILE
|
||||
#define CFG_TUSB_CONFIG_FILE "tusb_config.h"
|
||||
#endif
|
||||
|
||||
#include CFG_TUSB_CONFIG_FILE
|
||||
|
||||
/** \addtogroup group_configuration
|
||||
* @{ */
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// CONTROLLER
|
||||
// Only 1 roothub port can be configured to be device and/or host.
|
||||
// tinyusb does not support dual devices or dual host configuration
|
||||
//--------------------------------------------------------------------
|
||||
/** \defgroup group_mode Controller Mode Selection
|
||||
* \brief CFG_TUSB_CONTROLLER_N_MODE must be defined with these
|
||||
* @{ */
|
||||
#define OPT_MODE_NONE 0x00 ///< Disabled
|
||||
#define OPT_MODE_DEVICE 0x01 ///< Device Mode
|
||||
#define OPT_MODE_HOST 0x02 ///< Host Mode
|
||||
#define OPT_MODE_HIGH_SPEED 0x10 ///< High speed
|
||||
/** @} */
|
||||
|
||||
#ifndef CFG_TUSB_RHPORT0_MODE
|
||||
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_RHPORT1_MODE
|
||||
#define CFG_TUSB_RHPORT1_MODE OPT_MODE_NONE
|
||||
#endif
|
||||
|
||||
#if ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST) && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST)) || \
|
||||
((CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE) && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE))
|
||||
#error "tinyusb does not support same modes on more than 1 roothub port"
|
||||
#endif
|
||||
|
||||
// Which roothub port is configured as host
|
||||
#define TUH_OPT_RHPORT ( (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST) ? 0 : ((CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST) ? 1 : -1) )
|
||||
#define TUSB_OPT_HOST_ENABLED ( TUH_OPT_RHPORT >= 0 )
|
||||
|
||||
// Which roothub port is configured as device
|
||||
#define TUD_OPT_RHPORT ( (CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE) ? 0 : ((CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE) ? 1 : -1) )
|
||||
|
||||
#if TUD_OPT_RHPORT == 0
|
||||
#define TUD_OPT_HIGH_SPEED ( CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED )
|
||||
#else
|
||||
#define TUD_OPT_HIGH_SPEED ( CFG_TUSB_RHPORT1_MODE & OPT_MODE_HIGH_SPEED )
|
||||
#endif
|
||||
|
||||
#define TUSB_OPT_DEVICE_ENABLED ( TUD_OPT_RHPORT >= 0 )
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// COMMON OPTIONS
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Debug enable to print out error message
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#endif
|
||||
|
||||
// place data in accessible RAM for usb controller
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE OPTIONS
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_CDC
|
||||
#define CFG_TUD_CDC 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_MSC
|
||||
#define CFG_TUD_MSC 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_HID
|
||||
#define CFG_TUD_HID 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_MIDI
|
||||
#define CFG_TUD_MIDI 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_VENDOR
|
||||
#define CFG_TUD_VENDOR 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_USBTMC
|
||||
#define CFG_TUD_USBTMC 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_DFU_RT
|
||||
#define CFG_TUD_DFU_RT 0
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// HOST OPTIONS
|
||||
//--------------------------------------------------------------------
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
#ifndef CFG_TUSB_HOST_DEVICE_MAX
|
||||
#define CFG_TUSB_HOST_DEVICE_MAX 1
|
||||
#warning CFG_TUSB_HOST_DEVICE_MAX is not defined, default value is 1
|
||||
#endif
|
||||
|
||||
//------------- HUB CLASS -------------//
|
||||
#if CFG_TUH_HUB && (CFG_TUSB_HOST_DEVICE_MAX == 1)
|
||||
#error there is no benefit enable hub with max device is 1. Please disable hub or increase CFG_TUSB_HOST_DEVICE_MAX
|
||||
#endif
|
||||
|
||||
//------------- HID CLASS -------------//
|
||||
#define HOST_CLASS_HID ( CFG_TUH_HID_KEYBOARD + CFG_TUH_HID_MOUSE + CFG_TUSB_HOST_HID_GENERIC )
|
||||
|
||||
#ifndef CFG_TUSB_HOST_ENUM_BUFFER_SIZE
|
||||
#define CFG_TUSB_HOST_ENUM_BUFFER_SIZE 256
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#endif // TUSB_OPT_HOST_ENABLED
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Configuration Validation
|
||||
//------------------------------------------------------------------
|
||||
#if CFG_TUD_ENDPOINT0_SIZE > 64
|
||||
#error Control Endpoint Max Packet Size cannot be larger than 64
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_OPTION_H_ */
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_OPTION_H_
|
||||
#define _TUSB_OPTION_H_
|
||||
|
||||
#define TUSB_VERSION_MAJOR 0
|
||||
#define TUSB_VERSION_MINOR 5
|
||||
#define TUSB_VERSION_REVISION 0
|
||||
#define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)
|
||||
|
||||
/** \defgroup group_mcu Supported MCU
|
||||
* \ref CFG_TUSB_MCU must be defined to one of these
|
||||
* @{ */
|
||||
|
||||
#define OPT_MCU_NONE 0
|
||||
|
||||
// LPC
|
||||
#define OPT_MCU_LPC11UXX 1 ///< NXP LPC11Uxx
|
||||
#define OPT_MCU_LPC13XX 2 ///< NXP LPC13xx
|
||||
#define OPT_MCU_LPC15XX 3 ///< NXP LPC15xx
|
||||
#define OPT_MCU_LPC175X_6X 4 ///< NXP LPC175x, LPC176x
|
||||
#define OPT_MCU_LPC177X_8X 5 ///< NXP LPC177x, LPC178x
|
||||
#define OPT_MCU_LPC18XX 6 ///< NXP LPC18xx
|
||||
#define OPT_MCU_LPC40XX 7 ///< NXP LPC40xx
|
||||
#define OPT_MCU_LPC43XX 8 ///< NXP LPC43xx
|
||||
#define OPT_MCU_LPC51UXX 9 ///< NXP LPC51U6x
|
||||
#define OPT_MCU_LPC54XXX 10 ///< NXP LPC54xxx
|
||||
#define OPT_MCU_LPC55XX 11 ///< NXP LPC55xx
|
||||
|
||||
// NRF
|
||||
#define OPT_MCU_NRF5X 100 ///< Nordic nRF5x series
|
||||
|
||||
// SAM
|
||||
#define OPT_MCU_SAMD21 200 ///< MicroChip SAMD21
|
||||
#define OPT_MCU_SAMD51 201 ///< MicroChip SAMD51
|
||||
#define OPT_MCU_SAMG 202 ///< MicroChip SAMDG series
|
||||
|
||||
// STM32
|
||||
#define OPT_MCU_STM32F0 300 ///< ST STM32F0
|
||||
#define OPT_MCU_STM32F1 301 ///< ST STM32F1
|
||||
#define OPT_MCU_STM32F2 302 ///< ST STM32F2
|
||||
#define OPT_MCU_STM32F3 303 ///< ST STM32F3
|
||||
#define OPT_MCU_STM32F4 304 ///< ST STM32F4
|
||||
#define OPT_MCU_STM32F7 305 ///< ST STM32F7
|
||||
#define OPT_MCU_STM32H7 306 ///< ST STM32H7
|
||||
#define OPT_MCU_STM32L0 307 ///< ST STM32L0
|
||||
#define OPT_MCU_STM32L1 308 ///< ST STM32L1
|
||||
#define OPT_MCU_STM32L4 309 ///< ST STM32L4
|
||||
|
||||
#define OPT_MCU_CXD56 400 ///< SONY CXD56
|
||||
|
||||
#define OPT_MCU_VALENTYUSB_EPTRI 600 ///< Fomu eptri config
|
||||
|
||||
#define OPT_MCU_MIMXRT10XX 700 ///< NXP iMX RT10xx
|
||||
|
||||
#define OPT_MCU_NUC121 800
|
||||
#define OPT_MCU_NUC126 801
|
||||
|
||||
/** @} */
|
||||
|
||||
/** \defgroup group_supported_os Supported RTOS
|
||||
* \ref CFG_TUSB_OS must be defined to one of these
|
||||
* @{ */
|
||||
#define OPT_OS_NONE 1 ///< No RTOS
|
||||
#define OPT_OS_FREERTOS 2 ///< FreeRTOS
|
||||
#define OPT_OS_MYNEWT 3 ///< Mynewt OS
|
||||
/** @} */
|
||||
|
||||
|
||||
// Allow to use command line to change the config name/location
|
||||
#ifndef CFG_TUSB_CONFIG_FILE
|
||||
#define CFG_TUSB_CONFIG_FILE "tusb_config.h"
|
||||
#endif
|
||||
|
||||
#include CFG_TUSB_CONFIG_FILE
|
||||
|
||||
/** \addtogroup group_configuration
|
||||
* @{ */
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// CONTROLLER
|
||||
// Only 1 roothub port can be configured to be device and/or host.
|
||||
// tinyusb does not support dual devices or dual host configuration
|
||||
//--------------------------------------------------------------------
|
||||
/** \defgroup group_mode Controller Mode Selection
|
||||
* \brief CFG_TUSB_CONTROLLER_N_MODE must be defined with these
|
||||
* @{ */
|
||||
#define OPT_MODE_NONE 0x00 ///< Disabled
|
||||
#define OPT_MODE_DEVICE 0x01 ///< Device Mode
|
||||
#define OPT_MODE_HOST 0x02 ///< Host Mode
|
||||
#define OPT_MODE_HIGH_SPEED 0x10 ///< High speed
|
||||
/** @} */
|
||||
|
||||
#ifndef CFG_TUSB_RHPORT0_MODE
|
||||
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_RHPORT1_MODE
|
||||
#define CFG_TUSB_RHPORT1_MODE OPT_MODE_NONE
|
||||
#endif
|
||||
|
||||
#if ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST) && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST)) || \
|
||||
((CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE) && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE))
|
||||
#error "tinyusb does not support same modes on more than 1 roothub port"
|
||||
#endif
|
||||
|
||||
// Which roothub port is configured as host
|
||||
#define TUH_OPT_RHPORT ( (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST) ? 0 : ((CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST) ? 1 : -1) )
|
||||
#define TUSB_OPT_HOST_ENABLED ( TUH_OPT_RHPORT >= 0 )
|
||||
|
||||
// Which roothub port is configured as device
|
||||
#define TUD_OPT_RHPORT ( (CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE) ? 0 : ((CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE) ? 1 : -1) )
|
||||
|
||||
#if TUD_OPT_RHPORT == 0
|
||||
#define TUD_OPT_HIGH_SPEED ( CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED )
|
||||
#else
|
||||
#define TUD_OPT_HIGH_SPEED ( CFG_TUSB_RHPORT1_MODE & OPT_MODE_HIGH_SPEED )
|
||||
#endif
|
||||
|
||||
#define TUSB_OPT_DEVICE_ENABLED ( TUD_OPT_RHPORT >= 0 )
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// COMMON OPTIONS
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Debug enable to print out error message
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#endif
|
||||
|
||||
// place data in accessible RAM for usb controller
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE OPTIONS
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_CDC
|
||||
#define CFG_TUD_CDC 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_MSC
|
||||
#define CFG_TUD_MSC 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_HID
|
||||
#define CFG_TUD_HID 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_MIDI
|
||||
#define CFG_TUD_MIDI 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_VENDOR
|
||||
#define CFG_TUD_VENDOR 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_USBTMC
|
||||
#define CFG_TUD_USBTMC 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_DFU_RT
|
||||
#define CFG_TUD_DFU_RT 0
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// HOST OPTIONS
|
||||
//--------------------------------------------------------------------
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
#ifndef CFG_TUSB_HOST_DEVICE_MAX
|
||||
#define CFG_TUSB_HOST_DEVICE_MAX 1
|
||||
#warning CFG_TUSB_HOST_DEVICE_MAX is not defined, default value is 1
|
||||
#endif
|
||||
|
||||
//------------- HUB CLASS -------------//
|
||||
#if CFG_TUH_HUB && (CFG_TUSB_HOST_DEVICE_MAX == 1)
|
||||
#error there is no benefit enable hub with max device is 1. Please disable hub or increase CFG_TUSB_HOST_DEVICE_MAX
|
||||
#endif
|
||||
|
||||
//------------- HID CLASS -------------//
|
||||
#define HOST_CLASS_HID ( CFG_TUH_HID_KEYBOARD + CFG_TUH_HID_MOUSE + CFG_TUSB_HOST_HID_GENERIC )
|
||||
|
||||
#ifndef CFG_TUSB_HOST_ENUM_BUFFER_SIZE
|
||||
#define CFG_TUSB_HOST_ENUM_BUFFER_SIZE 256
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#endif // TUSB_OPT_HOST_ENABLED
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Configuration Validation
|
||||
//------------------------------------------------------------------
|
||||
#if CFG_TUD_ENDPOINT0_SIZE > 64
|
||||
#error Control Endpoint Max Packet Size cannot be larger than 64
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_OPTION_H_ */
|
||||
|
||||
/** @} */
|
||||
|
Loading…
x
Reference in New Issue
Block a user