USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Usb.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 /* USB functions */
18 
19 #include "avrpins.h"
20 #include "max3421e.h"
21 #include "usbhost.h"
22 #include "Usb.h"
23 
24 #if defined(ARDUINO) && ARDUINO >=100
25 #include "Arduino.h"
26 #else
27 #include <WProgram.h>
28 #endif
29 
30 static uint8_t usb_error = 0;
31 static uint8_t usb_task_state;
32 
33 /* constructor */
34 USB::USB() : bmHubPre(0) {
35  usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
36  init();
37 }
38 
39 /* Initialize data structures */
40 void USB::init() {
41  devConfigIndex = 0;
42  bmHubPre = 0;
43 }
44 
45 uint8_t USB::getUsbTaskState(void) {
46  return ( usb_task_state);
47 }
48 
49 void USB::setUsbTaskState(uint8_t state) {
50  usb_task_state = state;
51 }
52 
53 EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) {
54  UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
55 
56  if (!p || !p->epinfo)
57  return NULL;
58 
59  EpInfo *pep = p->epinfo;
60 
61  for (uint8_t i = 0; i < p->epcount; i++) {
62  if ((pep)->epAddr == ep)
63  return pep;
64 
65  pep++;
66  }
67  return NULL;
68 }
69 
70 /* set device table entry */
71 
72 /* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
73 uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) {
74  if (!eprecord_ptr)
76 
77  UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
78 
79  if (!p)
81 
82  p->address = addr;
83  p->epinfo = eprecord_ptr;
84  p->epcount = epcount;
85 
86  return 0;
87 }
88 
89 uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit) {
90  UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
91 
92  if (!p)
94 
95  if (!p->epinfo)
97 
98  *ppep = getEpInfoEntry(addr, ep);
99 
100  if (!*ppep)
102 
103  nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
104  nak_limit--;
105  /*
106  USBTRACE2("\r\nAddress: ", addr);
107  USBTRACE2(" EP: ", ep);
108  USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
109  USBTRACE2(" NAK Limit: ", nak_limit);
110  USBTRACE("\r\n");
111  */
112  regWr(rPERADDR, addr); //set peripheral address
113 
114  uint8_t mode = regRd(rMODE);
115 
116  // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
117  regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
118 
119  return 0;
120 }
121 
122 /* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
123 /* depending on request. Actual requests are defined as inlines */
124 /* return codes: */
125 /* 00 = success */
126 
127 /* 01-0f = non-zero HRSLT */
128 uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
129  uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) {
130  bool direction = false; //request direction, IN or OUT
131  uint8_t rcode;
132  SETUP_PKT setup_pkt;
133 
134  EpInfo *pep = NULL;
135  uint16_t nak_limit;
136 
137  rcode = SetAddress(addr, ep, &pep, nak_limit);
138 
139  if (rcode)
140  return rcode;
141 
142  direction = ((bmReqType & 0x80) > 0);
143 
144  /* fill in setup packet */
145  setup_pkt.ReqType_u.bmRequestType = bmReqType;
146  setup_pkt.bRequest = bRequest;
147  setup_pkt.wVal_u.wValueLo = wValLo;
148  setup_pkt.wVal_u.wValueHi = wValHi;
149  setup_pkt.wIndex = wInd;
150  setup_pkt.wLength = total;
151 
152  bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO
153 
154  rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet
155 
156  if (rcode) //return HRSLT if not zero
157  return ( rcode);
158 
159  if (dataptr != NULL) //data stage, if present
160  {
161  if (direction) //IN transfer
162  {
163  uint16_t left = total;
164 
165  pep->bmRcvToggle = 1; //bmRCVTOG1;
166 
167  while (left) {
168  // Bytes read into buffer
169  uint16_t read = nbytes;
170  //uint16_t read = (left<nbytes) ? left : nbytes;
171 
172  rcode = InTransfer(pep, nak_limit, &read, dataptr);
173 
174  if (rcode)
175  return rcode;
176 
177  // Invoke callback function if inTransfer completed successfuly and callback function pointer is specified
178  if (!rcode && p)
179  ((USBReadParser*)p)->Parse(read, dataptr, total - left);
180 
181  left -= read;
182 
183  if (read < nbytes)
184  break;
185  }
186  } else //OUT transfer
187  {
188  pep->bmSndToggle = 1; //bmSNDTOG1;
189  rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
190  }
191  if (rcode) //return error
192  return ( rcode);
193  }
194  // Status stage
195  return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction
196 }
197 
198 /* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
199 /* Keep sending INs and writes data to memory area pointed by 'data' */
200 
201 /* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
202  fe USB xfer timeout */
203 uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data) {
204  EpInfo *pep = NULL;
205  uint16_t nak_limit = 0;
206 
207  uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit);
208 
209  if (rcode) {
210  //printf("SetAddress Failed");
211  return rcode;
212  }
213  return InTransfer(pep, nak_limit, nbytesptr, data);
214 }
215 
216 uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data) {
217  uint8_t rcode = 0;
218  uint8_t pktsize;
219 
220  uint16_t nbytes = *nbytesptr;
221  //printf("Requesting %i bytes ", nbytes);
222  uint8_t maxpktsize = pep->maxPktSize;
223 
224  *nbytesptr = 0;
225  regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
226 
227  while (1) // use a 'return' to exit this loop
228  {
229  rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
230 
231  if (rcode) {
232  //printf("Problem! %i\r\n", rcode);
233  break; //should be 0, indicating ACK. Else return error code.
234  }
235  /* check for RCVDAVIRQ and generate error if not present */
236  /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */
237  if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
238  //printf("Problem! NO RCVDAVIRQ!\r\n");
239  rcode = 0xf0; //receive error
240  break;
241  }
242  pktsize = regRd(rRCVBC); //number of received bytes
243  //printf("Got %i bytes ", pktsize);
244  assert(pktsize <= nbytes);
245 
246  int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
247 
248  if (mem_left < 0)
249  mem_left = 0;
250 
251  data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data);
252 
253  regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer
254  *nbytesptr += pktsize; // add this packet's byte count to total transfer length
255 
256  /* The transfer is complete under two conditions: */
257  /* 1. The device sent a short packet (L.T. maxPacketSize) */
258  /* 2. 'nbytes' have been transferred. */
259  if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes?
260  {
261  // Save toggle value
262  pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
263  //printf("\r\n");
264  rcode = 0;
265  break;
266  } // if
267  } //while( 1 )
268  return ( rcode);
269 }
270 
271 /* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
272 /* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */
273 
274 /* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
275 uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
276  EpInfo *pep = NULL;
277  uint16_t nak_limit;
278 
279  uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit);
280 
281  if (rcode)
282  return rcode;
283 
284  return OutTransfer(pep, nak_limit, nbytes, data);
285 }
286 
287 uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) {
288  uint8_t rcode = hrSUCCESS, retry_count;
289  uint8_t *data_p = data; //local copy of the data pointer
290  uint16_t bytes_tosend, nak_count;
291  uint16_t bytes_left = nbytes;
292 
293  uint8_t maxpktsize = pep->maxPktSize;
294 
295  if (maxpktsize < 1 || maxpktsize > 64)
297 
298  unsigned long timeout = millis() + USB_XFER_TIMEOUT;
299 
300  regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
301 
302  while (bytes_left) {
303  retry_count = 0;
304  nak_count = 0;
305  bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
306  bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
307  regWr(rSNDBC, bytes_tosend); //set number of bytes
308  regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
309  while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
310  regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
311  rcode = (regRd(rHRSL) & 0x0f);
312 
313  while (rcode && (timeout > millis())) {
314  switch (rcode) {
315  case hrNAK:
316  nak_count++;
317  if (nak_limit && (nak_count == nak_limit))
318  return ( rcode);
319  break;
320  case hrTIMEOUT:
321  retry_count++;
322  if (retry_count == USB_RETRY_LIMIT)
323  return ( rcode);
324  break;
325  default:
326  return ( rcode);
327  }//switch( rcode
328 
329  /* process NAK according to Host out NAK bug */
330  regWr(rSNDBC, 0);
331  regWr(rSNDFIFO, *data_p);
332  regWr(rSNDBC, bytes_tosend);
333  regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
334  while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
335  regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
336  rcode = (regRd(rHRSL) & 0x0f);
337  }//while( rcode && ....
338  bytes_left -= bytes_tosend;
339  data_p += bytes_tosend;
340  }//while( bytes_left...
341  pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
342  return ( rcode); //should be 0 in all cases
343 }
344 /* dispatch usb packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
345 /* If NAK, tries to re-send up to nak_limit times */
346 /* If nak_limit == 0, do not count NAKs, exit after timeout */
347 /* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
348 
349 /* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */
350 uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
351  unsigned long timeout = millis() + USB_XFER_TIMEOUT;
352  uint8_t tmpdata;
353  uint8_t rcode = hrSUCCESS;
354  uint8_t retry_count = 0;
355  uint16_t nak_count = 0;
356 
357  while (timeout > millis()) {
358  regWr(rHXFR, (token | ep)); //launch the transfer
360 
361  while (millis() < timeout) //wait for transfer completion
362  {
363  tmpdata = regRd(rHIRQ);
364 
365  if (tmpdata & bmHXFRDNIRQ) {
366  regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
367  rcode = 0x00;
368  break;
369  }//if( tmpdata & bmHXFRDNIRQ
370 
371  }//while ( millis() < timeout
372 
373  if (rcode != 0x00) //exit if timeout
374  return ( rcode);
375 
376  rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result
377 
378  switch (rcode) {
379  case hrNAK:
380  nak_count++;
381  if (nak_limit && (nak_count == nak_limit))
382  return ( rcode);
383  break;
384  case hrTIMEOUT:
385  retry_count++;
386  if (retry_count == USB_RETRY_LIMIT)
387  return ( rcode);
388  break;
389  default:
390  return ( rcode);
391  }//switch( rcode
392 
393  }//while( timeout > millis()
394  return ( rcode);
395 }
396 
397 /* USB main task. Performs enumeration/cleanup */
398 void USB::Task(void) //USB state machine
399 {
400  uint8_t rcode;
401  uint8_t tmpdata;
402  static unsigned long delay = 0;
403  //USB_DEVICE_DESCRIPTOR buf;
404  bool lowspeed = false;
405 
406  MAX3421E::Task();
407 
408  tmpdata = getVbusState();
409 
410  /* modify USB task state if Vbus changed */
411  switch (tmpdata) {
412  case SE1: //illegal state
413  usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
414  lowspeed = false;
415  break;
416  case SE0: //disconnected
417  if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
418  usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
419  lowspeed = false;
420  break;
421  case LSHOST:
422  lowspeed = true;
423  case FSHOST: //attached
424  if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
425  delay = millis() + USB_SETTLE_DELAY;
426  usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
427  }
428  break;
429  }// switch( tmpdata
430 
431  for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
432  if (devConfig[i])
433  rcode = devConfig[i]->Poll();
434 
435  switch (usb_task_state) {
437  init();
438 
439  for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
440  if (devConfig[i])
441  rcode = devConfig[i]->Release();
442 
443  usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
444  break;
445  case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
446  break;
447  case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
448  break;
449  case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
450  if (delay < millis())
451  usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
452  break;
454  regWr(rHCTL, bmBUSRST); //issue bus reset
456  break;
458  if ((regRd(rHCTL) & bmBUSRST) == 0) {
459  tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
460  regWr(rMODE, tmpdata);
461  usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
462  delay = millis() + 20; //20ms wait after reset per USB spec
463  }
464  break;
465  case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
466  if (regRd(rHIRQ) & bmFRAMEIRQ) //when first SOF received we can continue
467  {
468  if (delay < millis()) //20ms passed
469  usb_task_state = USB_STATE_CONFIGURING;
470  }
471  break;
473  rcode = Configuring(0, 0, lowspeed);
474 
475  if (rcode) {
477  usb_error = rcode;
478  usb_task_state = USB_STATE_ERROR;
479  }
480  } else
481  usb_task_state = USB_STATE_RUNNING;
482  break;
483  case USB_STATE_RUNNING:
484  break;
485  case USB_STATE_ERROR:
486  break;
487  } // switch( usb_task_state )
488 }
489 
490 uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
491  //uint8_t buf[12];
492  uint8_t rcode;
493  UsbDevice *p0 = NULL, *p = NULL;
494 
495  // Get pointer to pseudo device with address 0 assigned
496  p0 = addrPool.GetUsbDevicePtr(0);
497 
498  if (!p0)
500 
501  if (!p0->epinfo)
503 
504  p0->lowspeed = (lowspeed) ? true : false;
505 
506  // Allocate new address according to device class
507  uint8_t bAddress = addrPool.AllocAddress(parent, false, port);
508 
509  if (!bAddress)
511 
512  p = addrPool.GetUsbDevicePtr(bAddress);
513 
514  if (!p)
516 
517  p->lowspeed = lowspeed;
518 
519  // Assign new address to the device
520  rcode = setAddr(0, 0, bAddress);
521 
522  if (rcode) {
523  addrPool.FreeAddress(bAddress);
524  bAddress = 0;
525  return rcode;
526  }
527  return 0;
528 };
529 
530 uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
531  //static uint8_t dev_index = 0;
532  uint8_t rcode = 0;
533 
534  for (; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
535  if (!devConfig[devConfigIndex])
536  continue;
537 
538  rcode = devConfig[devConfigIndex]->Init(parent, port, lowspeed);
539 
540  if (!rcode) {
541  devConfigIndex = 0;
542  return 0;
543  }
545  // in case of an error dev_index should be reset to 0
546  // in order to start from the very beginning the
547  // next time the program gets here
549  devConfigIndex = 0;
550 
551  return rcode;
552  }
553  }
554  // if we get here that means that the device class is not supported by any of registered classes
555  devConfigIndex = 0;
556 
557  rcode = DefaultAddressing(parent, port, lowspeed);
558 
559  return rcode;
560 }
561 
562 uint8_t USB::ReleaseDevice(uint8_t addr) {
563  if (!addr)
564  return 0;
565 
566  for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
567  if (devConfig[i]->GetAddress() == addr)
568  return devConfig[i]->Release();
569 
570  return 0;
571 }
572 
573 #if 1
574 //get device descriptor
575 
576 uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
577  return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, NULL));
578 }
579 //get configuration descriptor
580 
581 uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
582  return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL));
583 }
584 
585 uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) {
586  const uint8_t bufSize = 64;
587  uint8_t buf[bufSize];
588 
589  uint8_t ret = getConfDescr(addr, ep, 8, conf, buf);
590 
591  if (ret)
592  return ret;
593 
594  uint16_t total = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength;
595 
596  //USBTRACE2("\r\ntotal conf.size:", total);
597 
598  return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p));
599 }
600 
601 //get string descriptor
602 
603 uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr) {
604  return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, NULL));
605 }
606 //set address
607 
608 uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
609  return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
610 }
611 //set configuration
612 
613 uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
614  return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
615 }
616 
617 #endif // defined(USB_METHODS_INLINE)
618