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 = 0;
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  if (rcode == hrTOGERR) {
174  // yes, we flip it wrong here so that next time it is actually correct!
175  pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
176  continue;
177  }
178 
179  if (rcode)
180  return rcode;
181 
182  // Invoke callback function if inTransfer completed successfully and callback function pointer is specified
183  if (!rcode && p)
184  ((USBReadParser*)p)->Parse(read, dataptr, total - left);
185 
186  left -= read;
187 
188  if (read < nbytes)
189  break;
190  }
191  } else //OUT transfer
192  {
193  pep->bmSndToggle = 1; //bmSNDTOG1;
194  rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
195  }
196  if (rcode) //return error
197  return ( rcode);
198  }
199  // Status stage
200  return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction
201 }
202 
203 /* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
204 /* Keep sending INs and writes data to memory area pointed by 'data' */
205 
206 /* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
207  fe USB xfer timeout */
208 uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data) {
209  EpInfo *pep = NULL;
210  uint16_t nak_limit = 0;
211 
212  uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit);
213 
214  if (rcode) {
215  //printf("SetAddress Failed");
216  return rcode;
217  }
218  return InTransfer(pep, nak_limit, nbytesptr, data);
219 }
220 
221 uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data) {
222  uint8_t rcode = 0;
223  uint8_t pktsize;
224 
225  uint16_t nbytes = *nbytesptr;
226  //printf("Requesting %i bytes ", nbytes);
227  uint8_t maxpktsize = pep->maxPktSize;
228 
229  *nbytesptr = 0;
230  regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
231 
232  while (1) // use a 'return' to exit this loop
233  {
234  rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
235  if (rcode == hrTOGERR) {
236  // yes, we flip it wrong here so that next time it is actually correct!
237  pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
238  regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
239  continue;
240  }
241  if (rcode) {
242  //printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
243  break; //should be 0, indicating ACK. Else return error code.
244  }
245  /* check for RCVDAVIRQ and generate error if not present */
246  /* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */
247  if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
248  //printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
249  rcode = 0xf0; //receive error
250  break;
251  }
252  pktsize = regRd(rRCVBC); //number of received bytes
253  //printf("Got %i bytes \r\n", pktsize);
254  // This would be OK, but...
255  //assert(pktsize <= nbytes);
256  if (pktsize > nbytes) {
257  // This can happen. Use of assert on Arduino locks up the Arduino.
258  // So I will trim the value, and hope for the best.
259  //printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
260  pktsize = nbytes;
261  }
262 
263  int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
264 
265  if (mem_left < 0)
266  mem_left = 0;
267 
268  data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data);
269 
270  regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer
271  *nbytesptr += pktsize; // add this packet's byte count to total transfer length
272 
273  /* The transfer is complete under two conditions: */
274  /* 1. The device sent a short packet (L.T. maxPacketSize) */
275  /* 2. 'nbytes' have been transferred. */
276  if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes?
277  {
278  // Save toggle value
279  pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
280  //printf("\r\n");
281  rcode = 0;
282  break;
283  } // if
284  } //while( 1 )
285  return ( rcode);
286 }
287 
288 /* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
289 /* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */
290 
291 /* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
292 uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
293  EpInfo *pep = NULL;
294  uint16_t nak_limit = 0;
295 
296  uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit);
297 
298  if (rcode)
299  return rcode;
300 
301  return OutTransfer(pep, nak_limit, nbytes, data);
302 }
303 
304 uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) {
305  uint8_t rcode = hrSUCCESS, retry_count;
306  uint8_t *data_p = data; //local copy of the data pointer
307  uint16_t bytes_tosend, nak_count;
308  uint16_t bytes_left = nbytes;
309 
310  uint8_t maxpktsize = pep->maxPktSize;
311 
312  if (maxpktsize < 1 || maxpktsize > 64)
314 
315  unsigned long timeout = millis() + USB_XFER_TIMEOUT;
316 
317  regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
318 
319  while (bytes_left) {
320  retry_count = 0;
321  nak_count = 0;
322  bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
323  bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
324  regWr(rSNDBC, bytes_tosend); //set number of bytes
325  regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
326  while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
327  regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
328  rcode = (regRd(rHRSL) & 0x0f);
329 
330  while (rcode && (timeout > millis())) {
331  switch (rcode) {
332  case hrNAK:
333  nak_count++;
334  if (nak_limit && (nak_count == nak_limit))
335  goto breakout;
336  //return ( rcode);
337  break;
338  case hrTIMEOUT:
339  retry_count++;
340  if (retry_count == USB_RETRY_LIMIT)
341  goto breakout;
342  //return ( rcode);
343  break;
344  case hrTOGERR:
345  // yes, we flip it wrong here so that next time it is actually correct!
346  pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
347  regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
348  break;
349  default:
350  goto breakout;
351  }//switch( rcode
352 
353  /* process NAK according to Host out NAK bug */
354  regWr(rSNDBC, 0);
355  regWr(rSNDFIFO, *data_p);
356  regWr(rSNDBC, bytes_tosend);
357  regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
358  while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
359  regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
360  rcode = (regRd(rHRSL) & 0x0f);
361  }//while( rcode && ....
362  bytes_left -= bytes_tosend;
363  data_p += bytes_tosend;
364  }//while( bytes_left...
365 breakout:
366 
367  pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
368  return ( rcode); //should be 0 in all cases
369 }
370 /* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
371 /* If NAK, tries to re-send up to nak_limit times */
372 /* If nak_limit == 0, do not count NAKs, exit after timeout */
373 /* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
374 
375 /* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */
376 uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
377  unsigned long timeout = millis() + USB_XFER_TIMEOUT;
378  uint8_t tmpdata;
379  uint8_t rcode = hrSUCCESS;
380  uint8_t retry_count = 0;
381  uint16_t nak_count = 0;
382 
383  while (timeout > millis()) {
384  regWr(rHXFR, (token | ep)); //launch the transfer
386 
387  while (timeout > millis()) //wait for transfer completion
388  {
389  tmpdata = regRd(rHIRQ);
390 
391  if (tmpdata & bmHXFRDNIRQ) {
392  regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
393  rcode = 0x00;
394  break;
395  }//if( tmpdata & bmHXFRDNIRQ
396 
397  }//while ( millis() < timeout
398 
399  //if (rcode != 0x00) //exit if timeout
400  // return ( rcode);
401 
402  rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result
403 
404  switch (rcode) {
405  case hrNAK:
406  nak_count++;
407  if (nak_limit && (nak_count == nak_limit))
408  return (rcode);
409  break;
410  case hrTIMEOUT:
411  retry_count++;
412  if (retry_count == USB_RETRY_LIMIT)
413  return (rcode);
414  break;
415  default:
416  return (rcode);
417  }//switch( rcode
418 
419  }//while( timeout > millis()
420  return ( rcode);
421 }
422 
423 /* USB main task. Performs enumeration/cleanup */
424 void USB::Task(void) //USB state machine
425 {
426  uint8_t rcode;
427  uint8_t tmpdata;
428  static unsigned long delay = 0;
429  //USB_DEVICE_DESCRIPTOR buf;
430  bool lowspeed = false;
431 
432  MAX3421E::Task();
433 
434  tmpdata = getVbusState();
435 
436  /* modify USB task state if Vbus changed */
437  switch (tmpdata) {
438  case SE1: //illegal state
439  usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
440  lowspeed = false;
441  break;
442  case SE0: //disconnected
443  if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
444  usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
445  lowspeed = false;
446  break;
447  case LSHOST:
448  if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
449  lowspeed = true;
450  }
451  case FSHOST: //attached
452  if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
453  delay = millis() + USB_SETTLE_DELAY;
454  usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
455  }
456  break;
457  }// switch( tmpdata
458 
459  for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
460  if (devConfig[i])
461  rcode = devConfig[i]->Poll();
462 
463  switch (usb_task_state) {
465  init();
466 
467  for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
468  if (devConfig[i])
469  rcode = devConfig[i]->Release();
470 
471  usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
472  break;
473  case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
474  break;
475  case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
476  break;
477  case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
478  if (delay < millis())
479  usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
480  break;
482  regWr(rHCTL, bmBUSRST); //issue bus reset
484  break;
486  if ((regRd(rHCTL) & bmBUSRST) == 0) {
487  tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
488  regWr(rMODE, tmpdata);
489  usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
490  //delay = millis() + 20; //20ms wait after reset per USB spec
491  }
492  break;
493  case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
494  if (regRd(rHIRQ) & bmFRAMEIRQ) {
495  //when first SOF received _and_ 20ms has passed we can continue
496  /*
497  if (delay < millis()) //20ms passed
498  usb_task_state = USB_STATE_CONFIGURING;
499  */
500  usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET;
501  delay = millis() + 20;
502  }
503  break;
505  if (delay < millis()) usb_task_state = USB_STATE_CONFIGURING;
506  break;
508  rcode = Configuring(0, 0, lowspeed);
509 
510  if (rcode) {
512  usb_error = rcode;
513  usb_task_state = USB_STATE_ERROR;
514  }
515  } else
516  usb_task_state = USB_STATE_RUNNING;
517  break;
518  case USB_STATE_RUNNING:
519  break;
520  case USB_STATE_ERROR:
521  //MAX3421E::Init();
522  break;
523  } // switch( usb_task_state )
524 }
525 
526 uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
527  //uint8_t buf[12];
528  uint8_t rcode;
529  UsbDevice *p0 = NULL, *p = NULL;
530 
531  // Get pointer to pseudo device with address 0 assigned
532  p0 = addrPool.GetUsbDevicePtr(0);
533 
534  if (!p0)
536 
537  if (!p0->epinfo)
539 
540  p0->lowspeed = (lowspeed) ? true : false;
541 
542  // Allocate new address according to device class
543  uint8_t bAddress = addrPool.AllocAddress(parent, false, port);
544 
545  if (!bAddress)
547 
548  p = addrPool.GetUsbDevicePtr(bAddress);
549 
550  if (!p)
552 
553  p->lowspeed = lowspeed;
554 
555  // Assign new address to the device
556  rcode = setAddr(0, 0, bAddress);
557 
558  if (rcode) {
559  addrPool.FreeAddress(bAddress);
560  bAddress = 0;
561  return rcode;
562  }
563  return 0;
564 };
565 
566 /*
567  * This is broken. We need to enumerate differently.
568  * It causes major problems with several devices if detected in an unexpected order.
569  *
570  *
571  * Oleg - I wouldn't do anything before the newly connected device is considered sane.
572  * i.e.(delays are not indicated for brevity):
573  * 1. reset
574  * 2. GetDevDescr();
575  * 3a. If ACK, continue with allocating address, addressing, etc.
576  * 3b. Else reset again, count resets, stop at some number (5?).
577  * 4. When max.number of resets is reached, toggle power/fail
578  * If desired, this could be modified by performing two resets with GetDevDescr() in the middle - however, from my experience, if a device answers to GDD()
579  * it doesn't need to be reset again
580  * New steps proposal:
581  * 1: get address pool instance. exit on fail
582  * 2: pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf). exit on fail.
583  * 3: bus reset, 100ms delay
584  * 4: set address
585  * 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail
586  * 6: while (configurations) {
587  * for(each configuration) {
588  * for (each driver) {
589  * 6a: Ask device if it likes configuration. Returns 0 on OK.
590  * If successful, the driver configured device.
591  * The driver now owns the endpoints, and takes over managing them.
592  * The following will need codes:
593  * Everything went well, instance consumed, exit with success.
594  * Instance already in use, ignore it, try next driver.
595  * Not a supported device, ignore it, try next driver.
596  * Not a supported configuration for this device, ignore it, try next driver.
597  * Could not configure device, fatal, exit with fail.
598  * }
599  * }
600  * }
601  * 7: for(each driver) {
602  * 7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID
603  * 8: if we get here, no driver likes the device plugged in, so exit failure.
604  *
605  */
606 uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
607  uint8_t rcode = 0;
608 
609  for (; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
610  if (!devConfig[devConfigIndex])
611  continue;
612 
613  rcode = devConfig[devConfigIndex]->ConfigureDevice(parent, port, lowspeed);
615  if (parent == 0) {
616  // Send a bus reset on the root interface.
617  regWr(rHCTL, bmBUSRST); //issue bus reset
618  delay(102); // delay 102ms, compensate for clock inaccuracy.
619  } /* else {
620  * @Oleg
621  * TO-DO:
622  * How do we do an individual bus reset on a child interface?
623  * Is that even possible with the current code?
624  */
625  }
626  rcode = devConfig[devConfigIndex]->Init(parent, port, lowspeed);
627  if (!rcode) {
628  devConfigIndex = 0;
629  return 0;
630  }
631  //printf("ERROR ENUMERATING %2.2x\r\n", rcode);
633  // in case of an error dev_index should be reset to 0
634  // in order to start from the very beginning the
635  // next time the program gets here
637  devConfigIndex = 0;
638  return rcode;
639  }
640  }
641  // if we get here that means that the device class is not supported by any of registered classes
642  devConfigIndex = 0;
643 
644  rcode = DefaultAddressing(parent, port, lowspeed);
645 
646  return rcode;
647 }
648 
649 uint8_t USB::ReleaseDevice(uint8_t addr) {
650  if (!addr)
651  return 0;
652 
653  for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
654  if (devConfig[i]->GetAddress() == addr)
655  return devConfig[i]->Release();
656 
657  return 0;
658 }
659 
660 #if 1
661 //get device descriptor
662 
663 uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
664  return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, NULL));
665 }
666 //get configuration descriptor
667 
668 uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
669  return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL));
670 }
671 
672 uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) {
673  const uint8_t bufSize = 64;
674  uint8_t buf[bufSize];
675 
676  uint8_t ret = getConfDescr(addr, ep, 8, conf, buf);
677 
678  if (ret)
679  return ret;
680 
681  uint16_t total = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength;
682 
683  //USBTRACE2("\r\ntotal conf.size:", total);
684 
685  return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p));
686 }
687 
688 //get string descriptor
689 
690 uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr) {
691  return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, NULL));
692 }
693 //set address
694 
695 uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
696  return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
697 }
698 //set configuration
699 
700 uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
701  return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
702 }
703 
704 #endif // defined(USB_METHODS_INLINE)
705