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