USB Host Shield 2.0
cdcacm.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
2 
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
8 the GPL2 ("Copyleft").
9 
10 Contact information
11 -------------------
12 
13 Circuits At Home, LTD
14 Web : http://www.circuitsathome.com
15 e-mail : support@circuitsathome.com
16  */
17 #include "cdcacm.h"
18 
19 const uint8_t ACM::epDataInIndex = 1;
20 const uint8_t ACM::epDataOutIndex = 2;
21 const uint8_t ACM::epInterruptInIndex = 3;
22 
23 ACM::ACM(USB *p, CDCAsyncOper *pasync) :
24 pUsb(p),
25 pAsync(pasync),
26 bAddress(0),
27 bControlIface(0),
28 bDataIface(0),
29 bNumEP(1),
30 qNextPollTime(0),
31 bPollEnable(false),
32 ready(false) {
33  _enhanced_status = enhanced_features(); // Set up features
34  for(uint8_t i = 0; i < ACM_MAX_ENDPOINTS; i++) {
35  epInfo[i].epAddr = 0;
36  epInfo[i].maxPktSize = (i) ? 0 : 8;
37  epInfo[i].bmSndToggle = 0;
38  epInfo[i].bmRcvToggle = 0;
40 
41  }
42  if(pUsb)
44 }
45 
46 uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) {
47 
48  const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
49 
50  uint8_t buf[constBufSize];
51  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
52 
53  uint8_t rcode;
54  UsbDevice *p = NULL;
55  EpInfo *oldep_ptr = NULL;
56  uint8_t num_of_conf; // number of configurations
57 
58  AddressPool &addrPool = pUsb->GetAddressPool();
59 
60  USBTRACE("ACM Init\r\n");
61 
62  if(bAddress)
64 
65  // Get pointer to pseudo device with address 0 assigned
66  p = addrPool.GetUsbDevicePtr(0);
67 
68  if(!p)
70 
71  if(!p->epinfo) {
72  USBTRACE("epinfo\r\n");
74  }
75 
76  // Save old pointer to EP_RECORD of address 0
77  oldep_ptr = p->epinfo;
78 
79  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
80  p->epinfo = epInfo;
81 
82  p->lowspeed = lowspeed;
83 
84  // Get device descriptor
85  rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
86 
87  // Restore p->epinfo
88  p->epinfo = oldep_ptr;
89 
90  if(rcode)
91  goto FailGetDevDescr;
92 
93  // Allocate new address according to device class
94  bAddress = addrPool.AllocAddress(parent, false, port);
95 
96  if(!bAddress)
98 
99  // Extract Max Packet Size from the device descriptor
101 
102  // Assign new address to the device
103  rcode = pUsb->setAddr(0, 0, bAddress);
104 
105  if(rcode) {
106  p->lowspeed = false;
107  addrPool.FreeAddress(bAddress);
108  bAddress = 0;
109  USBTRACE2("setAddr:", rcode);
110  return rcode;
111  }
112 
113  USBTRACE2("Addr:", bAddress);
114 
115  p->lowspeed = false;
116 
117  p = addrPool.GetUsbDevicePtr(bAddress);
118 
119  if(!p)
121 
122  p->lowspeed = lowspeed;
123 
124  num_of_conf = udd->bNumConfigurations;
125 
126  // Assign epInfo to epinfo pointer
127  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
128 
129  if(rcode)
130  goto FailSetDevTblEntry;
131 
132  USBTRACE2("NC:", num_of_conf);
133 
134  for(uint8_t i = 0; i < num_of_conf; i++) {
140  CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this);
141 
143  CP_MASK_COMPARE_CLASS> CdcDataParser(this);
144 
145  rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
146 
147  if(rcode)
148  goto FailGetConfDescr;
149 
150  rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
151 
152  if(rcode)
153  goto FailGetConfDescr;
154 
155  if(bNumEP > 1)
156  break;
157  } // for
158 
159  if(bNumEP < 4)
161 
162  // Assign epInfo to epinfo pointer
164 
165  USBTRACE2("Conf:", bConfNum);
166 
167  // Set Configuration Value
168  rcode = pUsb->setConf(bAddress, 0, bConfNum);
169 
170  if(rcode)
171  goto FailSetConfDescr;
172 
173  // Set up features status
175  half_duplex(false);
176  autoflowRTS(false);
177  autoflowDSR(false);
178  autoflowXON(false);
179  wide(false); // Always false, because this is only available in custom mode.
180  rcode = pAsync->OnInit(this);
181 
182  if(rcode)
183  goto FailOnInit;
184 
185  USBTRACE("ACM configured\r\n");
186 
187  ready = true;
188 
189  //bPollEnable = true;
190 
191  //USBTRACE("Poll enabled\r\n");
192  return 0;
193 
194 FailGetDevDescr:
195 #ifdef DEBUG_USB_HOST
197  goto Fail;
198 #endif
199 
200 FailSetDevTblEntry:
201 #ifdef DEBUG_USB_HOST
203  goto Fail;
204 #endif
205 
206 FailGetConfDescr:
207 #ifdef DEBUG_USB_HOST
209  goto Fail;
210 #endif
211 
212 FailSetConfDescr:
213 #ifdef DEBUG_USB_HOST
215  goto Fail;
216 #endif
217 
218 FailOnInit:
219 #ifdef DEBUG_USB_HOST
220  USBTRACE("OnInit:");
221 #endif
222 
223 #ifdef DEBUG_USB_HOST
224 Fail:
225  NotifyFail(rcode);
226 #endif
227  Release();
228  return rcode;
229 }
230 
231 void ACM::EndpointXtract(uint8_t conf, uint8_t iface __attribute__((unused)), uint8_t alt __attribute__((unused)), uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *pep) {
232  //ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
233  //ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
234  //ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
235 
236  bConfNum = conf;
237 
238  uint8_t index;
239 
240  if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80)
241  index = epInterruptInIndex;
243  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
244  else
245  return;
246 
247  // Fill in the endpoint info structure
248  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
249  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
250  epInfo[index].bmSndToggle = 0;
251  epInfo[index].bmRcvToggle = 0;
252 
253  bNumEP++;
254 
256 }
257 
258 uint8_t ACM::Release() {
259  ready = false;
261 
262  bControlIface = 0;
263  bDataIface = 0;
264  bNumEP = 1;
265 
266  bAddress = 0;
267  qNextPollTime = 0;
268  bPollEnable = false;
269  return 0;
270 }
271 
272 uint8_t ACM::Poll() {
273  //uint8_t rcode = 0;
274  //if(!bPollEnable)
275  // return 0;
276  //return rcode;
277  return 0;
278 }
279 
280 uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
281  uint8_t rv = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
282  if(rv && rv != hrNAK) {
283  Release();
284  }
285  return rv;
286 }
287 
288 uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) {
289  uint8_t rv = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
290  if(rv && rv != hrNAK) {
291  Release();
292  }
293  return rv;
294 }
295 
296 uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
297  uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
298  if(rv && rv != hrNAK) {
299  Release();
300  }
301  return rv;
302 }
303 
304 uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
305  uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
306  if(rv && rv != hrNAK) {
307  Release();
308  }
309  return rv;
310 }
311 
312 uint8_t ACM::ClearCommFeature(uint16_t fid) {
313  uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL));
314  if(rv && rv != hrNAK) {
315  Release();
316  }
317  return rv;
318 }
319 
320 uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) {
321  uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
322  if(rv && rv != hrNAK) {
323  Release();
324  }
325  return rv;
326 }
327 
328 uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) {
329  uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
330  if(rv && rv != hrNAK) {
331  Release();
332  }
333  return rv;
334 }
335 
336 uint8_t ACM::SetControlLineState(uint8_t state) {
337  uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL));
338  if(rv && rv != hrNAK) {
339  Release();
340  }
341  return rv;
342 }
343 
344 uint8_t ACM::SendBreak(uint16_t duration) {
345  uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL));
346  if(rv && rv != hrNAK) {
347  Release();
348  }
349  return rv;
350 }
351 
353  Notify(PSTR("Endpoint descriptor:"), 0x80);
354  Notify(PSTR("\r\nLength:\t\t"), 0x80);
355  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
356  Notify(PSTR("\r\nType:\t\t"), 0x80);
357  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
358  Notify(PSTR("\r\nAddress:\t"), 0x80);
359  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
360  Notify(PSTR("\r\nAttributes:\t"), 0x80);
361  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
362  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
363  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
364  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
365  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
366  Notify(PSTR("\r\n"), 0x80);
367 }
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:95
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:100
#define USB_CLASS_CDC_DATA
Definition: UsbCore.h:80
#define USB_CLASS_COM_AND_CDC_CTRL
Definition: UsbCore.h:73
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
Definition: UsbCore.h:92
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:98
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:97
#define USB_NAK_MAX_POWER
Definition: address.h:34
#define USB_NAK_NOWAIT
Definition: address.h:36
#define CDC_GET_LINE_CODING
Definition: cdcacm.h:63
#define CDC_SET_CONTROL_LINE_STATE
Definition: cdcacm.h:64
#define CDC_PROTOCOL_ITU_T_V_250
Definition: cdcacm.h:40
#define bmREQ_CDCOUT
Definition: cdcacm.h:22
#define CDC_CLEAR_COMM_FEATURE
Definition: cdcacm.h:55
#define CDC_SEND_BREAK
Definition: cdcacm.h:65
#define CDC_SET_COMM_FEATURE
Definition: cdcacm.h:53
#define ACM_MAX_ENDPOINTS
Definition: cdcacm.h:161
#define CDC_SUBCLASS_ACM
Definition: cdcacm.h:27
#define CDC_SET_LINE_CODING
Definition: cdcacm.h:62
#define CDC_GET_COMM_FEATURE
Definition: cdcacm.h:54
#define bmREQ_CDCIN
Definition: cdcacm.h:23
uint8_t bNumEP
Definition: cdcacm.h:171
static const uint8_t epDataOutIndex
Definition: cdcacm.h:181
uint8_t GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr)
Definition: cdcacm.cpp:304
uint8_t SendBreak(uint16_t duration)
Definition: cdcacm.cpp:344
virtual tty_features enhanced_features(void)
Definition: cdcacm.h:221
CDCAsyncOper * pAsync
Definition: cdcacm.h:166
uint8_t bControlIface
Definition: cdcacm.h:169
static const uint8_t epDataInIndex
Definition: cdcacm.h:180
virtual void autoflowRTS(bool s)
Definition: cdcacm.h:232
EpInfo epInfo[ACM_MAX_ENDPOINTS]
Definition: cdcacm.h:183
uint8_t SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr)
Definition: cdcacm.cpp:296
uint32_t qNextPollTime
Definition: cdcacm.h:172
uint8_t bDataIface
Definition: cdcacm.h:170
uint8_t ClearCommFeature(uint16_t fid)
Definition: cdcacm.cpp:312
uint8_t Release()
Definition: cdcacm.cpp:258
volatile bool bPollEnable
Definition: cdcacm.h:173
uint8_t Poll()
Definition: cdcacm.cpp:272
uint8_t SetLineCoding(const LINE_CODING *dataptr)
Definition: cdcacm.cpp:320
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr)
Definition: cdcacm.cpp:280
virtual void autoflowXON(bool s)
Definition: cdcacm.h:238
tty_features _enhanced_status
Definition: cdcacm.h:175
static const uint8_t epInterruptInIndex
Definition: cdcacm.h:182
uint8_t GetLineCoding(LINE_CODING *dataptr)
Definition: cdcacm.cpp:328
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR *ep_ptr)
Definition: cdcacm.cpp:352
ACM(USB *pusb, CDCAsyncOper *pasync)
Definition: cdcacm.cpp:23
virtual void wide(bool s)
Definition: cdcacm.h:244
uint8_t bAddress
Definition: cdcacm.h:167
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr)
Definition: cdcacm.cpp:288
virtual void autoflowDSR(bool s)
Definition: cdcacm.h:235
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: cdcacm.cpp:46
USB * pUsb
Definition: cdcacm.h:165
volatile bool ready
Definition: cdcacm.h:174
virtual void half_duplex(bool s)
Definition: cdcacm.h:241
uint8_t bConfNum
Definition: cdcacm.h:168
uint8_t SetControlLineState(uint8_t state)
Definition: cdcacm.cpp:336
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: cdcacm.cpp:231
virtual void FreeAddress(uint8_t addr)=0
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
virtual uint8_t OnInit(ACM *pacm)
Definition: cdcacm.h:131
Definition: UsbCore.h:212
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:801
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:845
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:836
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:232
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:806
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t *dataptr, USBReadParser *p)
Definition: Usb.cpp:126
AddressPool & GetAddressPool()
Definition: UsbCore.h:228
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval=0)
Definition: Usb.cpp:209
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:303
#define CP_MASK_COMPARE_PROTOCOL
#define CP_MASK_COMPARE_SUBCLASS
#define CP_MASK_COMPARE_CLASS
#define USBTRACE2(s, r)
Definition: macros.h:84
#define USBTRACE(s)
Definition: macros.h:82
#define hrNAK
Definition: max3421e.h:218
#define NotifyFailSetConfDescr(...)
Definition: message.h:60
#define NotifyFail(...)
Definition: message.h:62
#define Notify(...)
Definition: message.h:51
#define NotifyFailGetConfDescr(...)
Definition: message.h:59
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:58
#define NotifyFailGetDevDescr(...)
Definition: message.h:57
Definition: address.h:39
uint8_t bmNakPower
Definition: address.h:49
uint8_t bmRcvToggle
Definition: address.h:48
uint8_t epAddr
Definition: address.h:40
uint8_t maxPktSize
Definition: address.h:41
uint8_t bmSndToggle
Definition: address.h:47
uint8_t bMaxPacketSize0
Definition: usb_ch9.h:112
uint8_t bNumConfigurations
Definition: usb_ch9.h:119
uint8_t bEndpointAddress
Definition: usb_ch9.h:151
uint16_t wMaxPacketSize
Definition: usb_ch9.h:153
EpInfo * epinfo
Definition: address.h:83
bool lowspeed
Definition: address.h:86
#define USB_TRANSFER_TYPE_BULK
Definition: usb_ch9.h:92
#define bmUSB_TRANSFER_TYPE
Definition: usb_ch9.h:94
#define USB_TRANSFER_TYPE_INTERRUPT
Definition: usb_ch9.h:93
#define PSTR(str)