tinyusb  0.4
Click here to lend your support to tinyusb donation and make a donation at pledgie.com
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
cdc_host.c
Go to the documentation of this file.
1 /**************************************************************************/
37 /**************************************************************************/
38 
39 #include "tusb_option.h"
40 
41 #if (MODE_HOST_SUPPORTED && TUSB_CFG_HOST_CDC)
42 
43 #define _TINY_USB_SOURCE_FILE_
44 
45 //--------------------------------------------------------------------+
46 // INCLUDE
47 //--------------------------------------------------------------------+
48 #include "common/common.h"
49 #include "cdc_host.h"
50 
51 //--------------------------------------------------------------------+
52 // MACRO CONSTANT TYPEDEF
53 //--------------------------------------------------------------------+
54 
55 //--------------------------------------------------------------------+
56 // INTERNAL OBJECT & FUNCTION DECLARATION
57 //--------------------------------------------------------------------+
58 /*STATIC_*/ cdch_data_t cdch_data[TUSB_CFG_HOST_DEVICE_MAX]; // TODO to be static
59 
60 static inline cdc_pipeid_t get_app_pipeid(pipe_handle_t pipe_hdl) ATTR_PURE ATTR_ALWAYS_INLINE;
61 static inline cdc_pipeid_t get_app_pipeid(pipe_handle_t pipe_hdl)
62 {
63  cdch_data_t const * p_cdc = &cdch_data[pipe_hdl.dev_addr-1];
64 
65  return pipehandle_is_equal( pipe_hdl, p_cdc->pipe_notification ) ? CDC_PIPE_NOTIFICATION :
66  pipehandle_is_equal( pipe_hdl, p_cdc->pipe_in ) ? CDC_PIPE_DATA_IN :
67  pipehandle_is_equal( pipe_hdl, p_cdc->pipe_out ) ? CDC_PIPE_DATA_OUT : CDC_PIPE_ERROR;
68 }
69 
70 
71 STATIC_ INLINE_ bool tusbh_cdc_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT;
72 STATIC_ INLINE_ bool tusbh_cdc_is_mounted(uint8_t dev_addr)
73 {
74 // FIXME cannot use mounted class flag as at the point _open_sublass is called, the flag is not set yet
75 #ifdef _TEST_
76  return (tusbh_device_get_mounted_class_flag(dev_addr) & BIT_(TUSB_CLASS_CDC)) != 0;
77 #else
78  return pipehandle_is_valid(cdch_data[dev_addr-1].pipe_in) &&
79  pipehandle_is_valid(cdch_data[dev_addr-1].pipe_out);
80 #endif
81 }
82 
83 bool tusbh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid)
84 {
85  if ( !tusbh_cdc_is_mounted(dev_addr) ) return false;
86 
87  cdch_data_t const * p_cdc = &cdch_data[dev_addr-1];
88 
89  switch (pipeid)
90  {
92  return hcd_pipe_is_busy( p_cdc->pipe_notification );
93 
94  case CDC_PIPE_DATA_IN:
95  return hcd_pipe_is_busy( p_cdc->pipe_in );
96 
97  case CDC_PIPE_DATA_OUT:
98  return hcd_pipe_is_busy( p_cdc->pipe_out );
99 
100  default:
101  return false;
102  }
103 }
104 
105 
106 //--------------------------------------------------------------------+
107 // APPLICATION API (parameter validation needed)
108 //--------------------------------------------------------------------+
109 bool tusbh_cdc_serial_is_mounted(uint8_t dev_addr)
110 {
111  // TODO consider all AT Command as serial candidate
112  return tusbh_cdc_is_mounted(dev_addr) &&
113  (CDC_COMM_PROTOCOL_ATCOMMAND <= cdch_data[dev_addr-1].interface_protocol) &&
114  (cdch_data[dev_addr-1].interface_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA);
115 }
116 
117 tusb_error_t tusbh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify)
118 {
119  ASSERT( tusbh_cdc_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED);
120  ASSERT( p_data != NULL && length, TUSB_ERROR_INVALID_PARA);
121 
122  pipe_handle_t pipe_out = cdch_data[dev_addr-1].pipe_out;
123  if ( hcd_pipe_is_busy(pipe_out) ) return TUSB_ERROR_INTERFACE_IS_BUSY;
124 
125  return hcd_pipe_xfer( pipe_out, (void *) p_data, length, is_notify);
126 }
127 
128 tusb_error_t tusbh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify)
129 {
130  ASSERT( tusbh_cdc_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED);
131  ASSERT( p_buffer != NULL && length, TUSB_ERROR_INVALID_PARA);
132 
133  pipe_handle_t pipe_in = cdch_data[dev_addr-1].pipe_in;
134  if ( hcd_pipe_is_busy(pipe_in) ) return TUSB_ERROR_INTERFACE_IS_BUSY;
135 
136  return hcd_pipe_xfer( pipe_in, p_buffer, length, is_notify);
137 }
138 
139 //--------------------------------------------------------------------+
140 // USBH-CLASS DRIVER API
141 //--------------------------------------------------------------------+
142 void cdch_init(void)
143 {
144  memclr_(cdch_data, sizeof(cdch_data_t)*TUSB_CFG_HOST_DEVICE_MAX);
145 }
146 
147 tusb_error_t cdch_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t const *p_interface_desc, uint16_t *p_length)
148 {
149  OSAL_SUBTASK_BEGIN
150  // TODO change following assert to subtask_assert
151 
152  if ( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL != p_interface_desc->bInterfaceSubClass) return TUSB_ERROR_CDC_UNSUPPORTED_SUBCLASS;
153 
155  0xff == p_interface_desc->bInterfaceProtocol) )
156  {
157  return TUSB_ERROR_CDC_UNSUPPORTED_PROTOCOL;
158  }
159 
160  uint8_t const * p_desc;
161  cdch_data_t * p_cdc;
162 
163  p_desc = descriptor_next ( (uint8_t const *) p_interface_desc );
164  p_cdc = &cdch_data[dev_addr-1]; // non-static variable cannot be used after OS service call
165 
166  p_cdc->interface_number = p_interface_desc->bInterfaceNumber;
167  p_cdc->interface_protocol = p_interface_desc->bInterfaceProtocol; // TODO 0xff is consider as rndis candidate, other is virtual Com
168 
169  //------------- Communication Interface -------------//
170  (*p_length) = sizeof(tusb_descriptor_interface_t);
171 
172  while( TUSB_DESC_TYPE_INTERFACE_CLASS_SPECIFIC == p_desc[DESCRIPTOR_OFFSET_TYPE] )
173  { // Communication Functional Descriptors
174  if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) )
175  { // save ACM bmCapabilities
176  p_cdc->acm_capability = ((cdc_desc_func_abstract_control_management_t const *) p_desc)->bmCapabilities;
177  }
178 
179  (*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
180  p_desc = descriptor_next(p_desc);
181  }
182 
183  if ( TUSB_DESC_TYPE_ENDPOINT == p_desc[DESCRIPTOR_OFFSET_TYPE])
184  { // notification endpoint if any
185  p_cdc->pipe_notification = hcd_pipe_open(dev_addr, (tusb_descriptor_endpoint_t const *) p_desc, TUSB_CLASS_CDC);
186 
187  (*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
188  p_desc = descriptor_next(p_desc);
189 
190  ASSERT(pipehandle_is_valid(p_cdc->pipe_notification), TUSB_ERROR_HCD_OPEN_PIPE_FAILED);
191  }
192 
193  //------------- Data Interface (if any) -------------//
194  if ( (TUSB_DESC_TYPE_INTERFACE == p_desc[DESCRIPTOR_OFFSET_TYPE]) &&
195  (TUSB_CLASS_CDC_DATA == ((tusb_descriptor_interface_t const *) p_desc)->bInterfaceClass) )
196  {
197  (*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
198  p_desc = descriptor_next(p_desc);
199 
200  // data endpoints expected to be in pairs
201  for(uint32_t i=0; i<2; i++)
202  {
203  tusb_descriptor_endpoint_t const *p_endpoint = (tusb_descriptor_endpoint_t const *) p_desc;
204  ASSERT_INT(TUSB_DESC_TYPE_ENDPOINT, p_endpoint->bDescriptorType, TUSB_ERROR_USBH_DESCRIPTOR_CORRUPTED);
205  ASSERT_INT(TUSB_XFER_BULK, p_endpoint->bmAttributes.xfer, TUSB_ERROR_USBH_DESCRIPTOR_CORRUPTED);
206 
207  pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_DEV_TO_HOST_MASK ) ?
208  &p_cdc->pipe_in : &p_cdc->pipe_out;
209 
210  (*p_pipe_hdl) = hcd_pipe_open(dev_addr, p_endpoint, TUSB_CLASS_CDC);
211  ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED );
212 
213  (*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH];
214  p_desc = descriptor_next( p_desc );
215  }
216  }
217 
218  {
219  // FIXME mounted class flag is not set yet
220  tusbh_cdc_mounted_cb(dev_addr);
221  }
222 
223  OSAL_SUBTASK_END
224 }
225 
226 void cdch_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
227 {
228  tusbh_cdc_xfer_isr( pipe_hdl.dev_addr, event, get_app_pipeid(pipe_hdl), xferred_bytes );
229 }
230 
231 void cdch_close(uint8_t dev_addr)
232 {
233  cdch_data_t * p_cdc = &cdch_data[dev_addr-1];
234 
235  (void) hcd_pipe_close(p_cdc->pipe_notification);
236  (void) hcd_pipe_close(p_cdc->pipe_in);
237  (void) hcd_pipe_close(p_cdc->pipe_out);
238 
239  memclr_(p_cdc, sizeof(cdch_data_t));
240 
241  tusbh_cdc_unmounted_cb(dev_addr);
242 
243 }
244 
245 #endif
#define BIT_(n)
n-th Bit
Definition: binary.h:54
USB Standard Interface Descriptor (section 9.6.1 table 9-12)
Abstract Control Model [USBPSTN1.2].
Definition: cdc.h:71
#define ATTR_WARN_UNUSED_RESULT
The warn_unused_result attribute causes a warning to be emitted if a caller of the function with this...
Definition: compiler_gcc.h:118
uint8_t bInterfaceProtocol
Protocol code (assigned by the USB). These codes are qualified by the value of the bInterfaceClass ...
AT Commands: V.250 etc.
Definition: cdc.h:86
#define TUSB_CFG_HOST_DEVICE_MAX
Maximum number of device host stack can manage If hub class is not enabled, set this equal to numbe...
Notification pipe.
Definition: cdc.h:59
#define ATTR_PURE
Many functions have no effects except the return value and their return value depends only on the par...
Definition: compiler_gcc.h:96
bool tusbh_cdc_serial_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT
Check if device support CDC Serial interface or not.
tusb_error_t tusbh_cdc_receive(uint8_t dev_addr, void *p_buffer, uint32_t length, bool is_notify)
Perform USB IN transfer to get data from device.
Data in pipe.
Definition: cdc.h:60
struct tusb_descriptor_endpoint_t::@8 bmAttributes
This field describes the endpoint's attributes when it is configured using the bConfigurationValue. Bits 1..0: Transfer Type - 00 = Control - 01 = Isochronous - 10 = Bulk - 11 = Interrupt If not an isochronous endpoint, bits 5..2 are reserved and must be set to zero. If isochronous, they are defined as follows: Bits 3..2: Synchronization Type - 00 = No Synchronization - 01 = Asynchronous - 10 = Adaptive - 11 = Synchronous Bits 5..4: Usage Type - 00 = Data endpoint - 01 = Feedback endpoint - 10 = Implicit feedback Data endpoint - 11 = Reserved Refer to Chapter 5 of USB 2.0 specification for more information. All other bits are reserved and must be reset to zero. Reserved bits must be ignored by the host.
AT Commands defined by TIA for CDMA.
Definition: cdc.h:91
static bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST
inclusive range checking
Definition: common.h:236
uint8_t bDescriptorType
ENDPOINT Descriptor Type.
uint8_t bInterfaceSubClass
Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bInterfaceCla...
Abstract Control Management Functional Descriptor.
Definition: cdc.h:100
USB Standard Endpoint Descriptor (section 9.6.1 table 9-13)
Invalid Pipe ID.
Definition: cdc.h:62
cdc_pipeid_t
CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In)
Definition: cdc.h:58
uint8_t bInterfaceNumber
Number of this interface. Zero-based value identifying the index in the array of concurrent interface...
tusb_error_t tusbh_cdc_send(uint8_t dev_addr, void const *p_data, uint32_t length, bool is_notify)
Perform USB OUT transfer to device.
void tusbh_cdc_xfer_isr(uint8_t dev_addr, tusb_event_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes)
Callback function that is invoked when an transferring event occurred.
Abstract Control Management Functional Descriptor.
Definition: cdc.h:296
tusb_error_t
Error Code returned.
Definition: tusb_errors.h:100
void tusbh_cdc_mounted_cb(uint8_t dev_addr)
Callback function that will be invoked when a device with CDC Abstract Control Model interface is mou...
void tusbh_cdc_unmounted_cb(uint8_t dev_addr)
Callback function that will be invoked when a device with CDC Abstract Control Model interface is unm...
#define ATTR_ALWAYS_INLINE
Generally, functions are not inlined unless optimization is specified. For functions declared inline...
Definition: compiler_gcc.h:89
Data out pipe.
Definition: cdc.h:61
uint8_t bEndpointAddress
The address of the endpoint on the USB device described by this descriptor. The address is encoded as...
bool tusbh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) ATTR_PURE ATTR_WARN_UNUSED_RESULT
Check if the interface is currently busy or not.