MAX3421E-based USB Host Shield Library

Dependents:   UsbHostMAX3421E_Hello

Committer:
hudakz
Date:
Mon Jul 13 07:03:06 2020 +0000
Revision:
1:2263e77400e9
Parent:
0:84353c479782
MAX3421E-based USB Host Shield Library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:84353c479782 1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
hudakz 0:84353c479782 2
hudakz 0:84353c479782 3 This software may be distributed and modified under the terms of the GNU
hudakz 0:84353c479782 4 General Public License version 2 (GPL2) as published by the Free Software
hudakz 0:84353c479782 5 Foundation and appearing in the file GPL2.TXT included in the packaging of
hudakz 0:84353c479782 6 this file. Please note that GPL2 Section 2[b] requires that all works based
hudakz 0:84353c479782 7 on this software must also be made publicly available under the terms of
hudakz 0:84353c479782 8 the GPL2 ("Copyleft").
hudakz 0:84353c479782 9
hudakz 0:84353c479782 10 Contact information
hudakz 0:84353c479782 11 -------------------
hudakz 0:84353c479782 12
hudakz 0:84353c479782 13 Circuits At Home, LTD
hudakz 0:84353c479782 14 Web : http://www.circuitsathome.com
hudakz 0:84353c479782 15 e-mail : support@circuitsathome.com
hudakz 0:84353c479782 16 */
hudakz 0:84353c479782 17 /* USB functions */
hudakz 0:84353c479782 18 #include "Usb.h"
hudakz 0:84353c479782 19
hudakz 0:84353c479782 20 static uint8_t usb_error = 0;
hudakz 0:84353c479782 21 static uint8_t usb_task_state;
hudakz 0:84353c479782 22
hudakz 0:84353c479782 23 /* constructor */
hudakz 1:2263e77400e9 24 Usb::Usb(PinName mosi, PinName miso, PinName sck, PinName ss, PinName intr) :
hudakz 0:84353c479782 25 MAX3421E(mosi, miso, sck, ss, intr),
hudakz 0:84353c479782 26 bmHubPre(0)
hudakz 0:84353c479782 27 {
hudakz 0:84353c479782 28 usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
hudakz 0:84353c479782 29 //init();
hudakz 0:84353c479782 30 }
hudakz 0:84353c479782 31
hudakz 0:84353c479782 32 /* Initialize data structures */
hudakz 1:2263e77400e9 33 int8_t Usb::init()
hudakz 0:84353c479782 34 {
hudakz 0:84353c479782 35 //devConfigIndex = 0;
hudakz 0:84353c479782 36 bmHubPre = 0;
hudakz 0:84353c479782 37 return MAX3421E::init();
hudakz 0:84353c479782 38 }
hudakz 0:84353c479782 39
hudakz 0:84353c479782 40 /**
hudakz 0:84353c479782 41 * @brief
hudakz 0:84353c479782 42 * @note
hudakz 0:84353c479782 43 * @param
hudakz 0:84353c479782 44 * @retval
hudakz 0:84353c479782 45 */
hudakz 1:2263e77400e9 46 uint8_t Usb::getUsbTaskState(void)
hudakz 0:84353c479782 47 {
hudakz 0:84353c479782 48 return(usb_task_state);
hudakz 0:84353c479782 49 }
hudakz 0:84353c479782 50
hudakz 0:84353c479782 51 /**
hudakz 0:84353c479782 52 * @brief
hudakz 0:84353c479782 53 * @note
hudakz 0:84353c479782 54 * @param
hudakz 0:84353c479782 55 * @retval
hudakz 0:84353c479782 56 */
hudakz 1:2263e77400e9 57 void Usb::setUsbTaskState(uint8_t state)
hudakz 0:84353c479782 58 {
hudakz 0:84353c479782 59 usb_task_state = state;
hudakz 0:84353c479782 60 }
hudakz 0:84353c479782 61
hudakz 0:84353c479782 62 /**
hudakz 0:84353c479782 63 * @brief
hudakz 0:84353c479782 64 * @note
hudakz 0:84353c479782 65 * @param
hudakz 0:84353c479782 66 * @retval
hudakz 0:84353c479782 67 */
hudakz 1:2263e77400e9 68 EpInfo* Usb::getEpInfoEntry(uint8_t addr, uint8_t ep)
hudakz 0:84353c479782 69 {
hudakz 0:84353c479782 70 UsbDevice* p = addrPool.GetUsbDevicePtr(addr);
hudakz 0:84353c479782 71
hudakz 0:84353c479782 72 if (!p || !p->epinfo)
hudakz 0:84353c479782 73 return NULL;
hudakz 0:84353c479782 74
hudakz 0:84353c479782 75 EpInfo* pep = p->epinfo;
hudakz 0:84353c479782 76
hudakz 0:84353c479782 77 for (uint8_t i = 0; i < p->epcount; i++) {
hudakz 0:84353c479782 78 if ((pep)->epAddr == ep)
hudakz 0:84353c479782 79 return pep;
hudakz 0:84353c479782 80
hudakz 0:84353c479782 81 pep++;
hudakz 0:84353c479782 82 }
hudakz 0:84353c479782 83
hudakz 0:84353c479782 84 return NULL;
hudakz 0:84353c479782 85 }
hudakz 0:84353c479782 86
hudakz 0:84353c479782 87 /* set device table entry */
hudakz 0:84353c479782 88
hudakz 0:84353c479782 89 /* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
hudakz 1:2263e77400e9 90 uint8_t Usb::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr)
hudakz 0:84353c479782 91 {
hudakz 0:84353c479782 92 if (!eprecord_ptr)
hudakz 0:84353c479782 93 return USB_ERROR_INVALID_ARGUMENT;
hudakz 0:84353c479782 94
hudakz 0:84353c479782 95 UsbDevice* p = addrPool.GetUsbDevicePtr(addr);
hudakz 0:84353c479782 96
hudakz 0:84353c479782 97 if (!p)
hudakz 0:84353c479782 98 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
hudakz 0:84353c479782 99
hudakz 0:84353c479782 100 p->address.devAddress = addr;
hudakz 0:84353c479782 101 p->epinfo = eprecord_ptr;
hudakz 0:84353c479782 102 p->epcount = epcount;
hudakz 0:84353c479782 103
hudakz 0:84353c479782 104 return 0;
hudakz 0:84353c479782 105 }
hudakz 0:84353c479782 106
hudakz 0:84353c479782 107 /**
hudakz 0:84353c479782 108 * @brief
hudakz 0:84353c479782 109 * @note
hudakz 0:84353c479782 110 * @param
hudakz 0:84353c479782 111 * @retval
hudakz 0:84353c479782 112 */
hudakz 1:2263e77400e9 113 uint8_t Usb::setAddress(uint8_t addr, uint8_t ep, EpInfo ** ppep, uint16_t* nak_limit)
hudakz 0:84353c479782 114 {
hudakz 0:84353c479782 115 UsbDevice* p = addrPool.GetUsbDevicePtr(addr);
hudakz 0:84353c479782 116
hudakz 0:84353c479782 117 if (!p)
hudakz 0:84353c479782 118 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
hudakz 0:84353c479782 119
hudakz 0:84353c479782 120 if (!p->epinfo)
hudakz 0:84353c479782 121 return USB_ERROR_EPINFO_IS_NULL;
hudakz 0:84353c479782 122
hudakz 0:84353c479782 123 *ppep = getEpInfoEntry(addr, ep);
hudakz 0:84353c479782 124
hudakz 0:84353c479782 125 if (!*ppep)
hudakz 0:84353c479782 126 return USB_ERROR_EP_NOT_FOUND_IN_TBL;
hudakz 0:84353c479782 127
hudakz 0:84353c479782 128 *nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
hudakz 0:84353c479782 129 (*nak_limit)--;
hudakz 0:84353c479782 130
hudakz 0:84353c479782 131 /*
hudakz 0:84353c479782 132 USBTRACE2("\r\nAddress: ", addr);
hudakz 0:84353c479782 133 USBTRACE2(" EP: ", ep);
hudakz 0:84353c479782 134 USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
hudakz 0:84353c479782 135 USBTRACE2(" NAK Limit: ", nak_limit);
hudakz 0:84353c479782 136 USBTRACE("\r\n");
hudakz 0:84353c479782 137 */
hudakz 0:84353c479782 138 regWr(rPERADDR, addr); //set peripheral address
hudakz 0:84353c479782 139 uint8_t mode = regRd(rMODE);
hudakz 0:84353c479782 140
hudakz 0:84353c479782 141 //Serial.print("\r\nMode: ");
hudakz 0:84353c479782 142
hudakz 0:84353c479782 143 //Serial.println( mode, HEX);
hudakz 0:84353c479782 144 //Serial.print("\r\nLS: ");
hudakz 0:84353c479782 145 //Serial.println(p->lowspeed, HEX);
hudakz 0:84353c479782 146 // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
hudakz 0:84353c479782 147 regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode &~(bmHUBPRE | bmLOWSPEED));
hudakz 0:84353c479782 148
hudakz 0:84353c479782 149 return 0;
hudakz 0:84353c479782 150 }
hudakz 0:84353c479782 151
hudakz 0:84353c479782 152 /* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
hudakz 0:84353c479782 153 /* depending on request. Actual requests are defined as inlines */
hudakz 0:84353c479782 154 /* return codes: */
hudakz 0:84353c479782 155 /* 00 = success */
hudakz 0:84353c479782 156
hudakz 0:84353c479782 157 /* 01-0f = non-zero HRSLT */
hudakz 1:2263e77400e9 158 uint8_t Usb::ctrlReq
hudakz 0:84353c479782 159 (
hudakz 0:84353c479782 160 uint8_t addr,
hudakz 0:84353c479782 161 uint8_t ep,
hudakz 0:84353c479782 162 uint8_t bmReqType,
hudakz 0:84353c479782 163 uint8_t bRequest,
hudakz 0:84353c479782 164 uint8_t wValLo,
hudakz 0:84353c479782 165 uint8_t wValHi,
hudakz 0:84353c479782 166 uint16_t wInd,
hudakz 0:84353c479782 167 uint16_t total,
hudakz 0:84353c479782 168 uint16_t nbytes,
hudakz 0:84353c479782 169 uint8_t* dataptr,
hudakz 0:84353c479782 170 USBReadParser* p
hudakz 0:84353c479782 171 )
hudakz 0:84353c479782 172 {
hudakz 0:84353c479782 173 bool direction = false; //request direction, IN or OUT
hudakz 0:84353c479782 174 uint8_t rcode;
hudakz 0:84353c479782 175 SETUP_PKT setup_pkt;
hudakz 0:84353c479782 176
hudakz 0:84353c479782 177 EpInfo* pep = NULL;
hudakz 0:84353c479782 178 uint16_t nak_limit = 0;
hudakz 0:84353c479782 179
hudakz 0:84353c479782 180 rcode = setAddress(addr, ep, &pep, &nak_limit);
hudakz 0:84353c479782 181
hudakz 0:84353c479782 182 if (rcode)
hudakz 0:84353c479782 183 return rcode;
hudakz 0:84353c479782 184
hudakz 0:84353c479782 185 direction = ((bmReqType & 0x80) > 0);
hudakz 0:84353c479782 186
hudakz 0:84353c479782 187 /* fill in setup packet */
hudakz 0:84353c479782 188 setup_pkt.ReqType_u.bmRequestType = bmReqType;
hudakz 0:84353c479782 189 setup_pkt.bRequest = bRequest;
hudakz 0:84353c479782 190 setup_pkt.wVal_u.wValueLo = wValLo;
hudakz 0:84353c479782 191 setup_pkt.wVal_u.wValueHi = wValHi;
hudakz 0:84353c479782 192 setup_pkt.wIndex = wInd;
hudakz 0:84353c479782 193 setup_pkt.wLength = total;
hudakz 0:84353c479782 194
hudakz 0:84353c479782 195 bytesWr(rSUDFIFO, 8, (uint8_t*) &setup_pkt); //transfer to setup packet FIFO
hudakz 0:84353c479782 196 rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet
hudakz 0:84353c479782 197 if (rcode) //return HRSLT if not zero
hudakz 0:84353c479782 198 return(rcode);
hudakz 0:84353c479782 199
hudakz 0:84353c479782 200 if (dataptr != NULL) {
hudakz 0:84353c479782 201
hudakz 0:84353c479782 202 //data stage, if present
hudakz 0:84353c479782 203 if (direction) {
hudakz 0:84353c479782 204
hudakz 0:84353c479782 205 //IN transfer
hudakz 0:84353c479782 206 uint16_t left = total;
hudakz 0:84353c479782 207
hudakz 0:84353c479782 208 pep->bmRcvToggle = 1; //bmRCVTOG1;
hudakz 0:84353c479782 209 while (left)
hudakz 0:84353c479782 210 {
hudakz 0:84353c479782 211 // Bytes read into buffer
hudakz 0:84353c479782 212 #if defined(ESP8266) || defined(ESP32)
hudakz 0:84353c479782 213 yield(); // needed in order to reset the watchdog timer on the ESP8266
hudakz 0:84353c479782 214 #endif
hudakz 0:84353c479782 215
hudakz 0:84353c479782 216 uint16_t read = nbytes;
hudakz 0:84353c479782 217 //uint16_t read = (left<nbytes) ? left : nbytes;
hudakz 0:84353c479782 218
hudakz 0:84353c479782 219 rcode = inTransfer(pep, nak_limit, &read, dataptr);
hudakz 0:84353c479782 220 if (rcode == hrTOGERR) {
hudakz 0:84353c479782 221
hudakz 0:84353c479782 222 // yes, we flip it wrong here so that next time it is actually correct!
hudakz 0:84353c479782 223 pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
hudakz 0:84353c479782 224 continue;
hudakz 0:84353c479782 225 }
hudakz 0:84353c479782 226
hudakz 0:84353c479782 227 if (rcode)
hudakz 0:84353c479782 228 return rcode;
hudakz 0:84353c479782 229
hudakz 0:84353c479782 230 // Invoke callback function if inTransfer completed successfully and callback function pointer is specified
hudakz 0:84353c479782 231 if (!rcode && p)
hudakz 0:84353c479782 232 ((USBReadParser*)p)->Parse(read, dataptr, total - left);
hudakz 0:84353c479782 233
hudakz 0:84353c479782 234 left -= read;
hudakz 0:84353c479782 235
hudakz 0:84353c479782 236 if (read < nbytes)
hudakz 0:84353c479782 237 break;
hudakz 0:84353c479782 238 }
hudakz 0:84353c479782 239 }
hudakz 0:84353c479782 240 else {
hudakz 0:84353c479782 241
hudakz 0:84353c479782 242 //OUT transfer
hudakz 0:84353c479782 243 pep->bmSndToggle = 1; //bmSNDTOG1;
hudakz 0:84353c479782 244 rcode = outTransfer(pep, nak_limit, nbytes, dataptr);
hudakz 0:84353c479782 245 }
hudakz 0:84353c479782 246
hudakz 0:84353c479782 247 if (rcode) //return error
hudakz 0:84353c479782 248 return(rcode);
hudakz 0:84353c479782 249 }
hudakz 0:84353c479782 250
hudakz 0:84353c479782 251 // Status stage
hudakz 0:84353c479782 252 return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction
hudakz 0:84353c479782 253 }
hudakz 0:84353c479782 254
hudakz 0:84353c479782 255 /* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
hudakz 0:84353c479782 256 /* Keep sending INs and writes data to memory area pointed by 'data' */
hudakz 0:84353c479782 257
hudakz 0:84353c479782 258 /* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
hudakz 0:84353c479782 259 fe USB xfer timeout */
hudakz 1:2263e77400e9 260 uint8_t Usb::inTransfer(uint8_t addr, uint8_t ep, uint16_t* nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/ )
hudakz 0:84353c479782 261 {
hudakz 0:84353c479782 262 EpInfo* pep = NULL;
hudakz 0:84353c479782 263 uint16_t nak_limit = 0;
hudakz 0:84353c479782 264
hudakz 0:84353c479782 265 uint8_t rcode = setAddress(addr, ep, &pep, &nak_limit);
hudakz 0:84353c479782 266
hudakz 0:84353c479782 267 if (rcode) {
hudakz 0:84353c479782 268 USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81);
hudakz 0:84353c479782 269 USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81);
hudakz 0:84353c479782 270 USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81);
hudakz 0:84353c479782 271 return rcode;
hudakz 0:84353c479782 272 }
hudakz 0:84353c479782 273
hudakz 0:84353c479782 274 return inTransfer(pep, nak_limit, nbytesptr, data, bInterval);
hudakz 0:84353c479782 275 }
hudakz 0:84353c479782 276
hudakz 0:84353c479782 277 /**
hudakz 0:84353c479782 278 * @brief
hudakz 0:84353c479782 279 * @note
hudakz 0:84353c479782 280 * @param
hudakz 0:84353c479782 281 * @retval
hudakz 0:84353c479782 282 */
hudakz 1:2263e77400e9 283 uint8_t Usb::inTransfer(EpInfo* pep, uint16_t nak_limit, uint16_t* nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/ )
hudakz 0:84353c479782 284 {
hudakz 0:84353c479782 285 uint8_t rcode = 0;
hudakz 0:84353c479782 286 uint8_t pktsize;
hudakz 0:84353c479782 287
hudakz 0:84353c479782 288 uint16_t nbytes = *nbytesptr;
hudakz 0:84353c479782 289
hudakz 0:84353c479782 290 //printf("Requesting %i bytes ", nbytes);
hudakz 0:84353c479782 291 uint8_t maxpktsize = pep->maxPktSize;
hudakz 0:84353c479782 292
hudakz 0:84353c479782 293 *nbytesptr = 0;
hudakz 0:84353c479782 294 regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
hudakz 0:84353c479782 295
hudakz 0:84353c479782 296 // use a 'break' to exit this loop
hudakz 0:84353c479782 297 while (1)
hudakz 0:84353c479782 298 {
hudakz 0:84353c479782 299 #if defined(ESP8266) || defined(ESP32)
hudakz 0:84353c479782 300 yield(); // needed in order to reset the watchdog timer on the ESP8266
hudakz 0:84353c479782 301 #endif
hudakz 0:84353c479782 302 rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
hudakz 0:84353c479782 303 if (rcode == hrTOGERR) {
hudakz 0:84353c479782 304
hudakz 0:84353c479782 305 // yes, we flip it wrong here so that next time it is actually correct!
hudakz 0:84353c479782 306 pep->bmRcvToggle = (regRd(rHRSL) & bmRCVTOGRD) ? 0 : 1;
hudakz 0:84353c479782 307 regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
hudakz 0:84353c479782 308 continue;
hudakz 0:84353c479782 309 }
hudakz 0:84353c479782 310
hudakz 0:84353c479782 311 if (rcode) {
hudakz 0:84353c479782 312
hudakz 0:84353c479782 313 //printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
hudakz 0:84353c479782 314 break; //should be 0, indicating ACK. Else return error code.
hudakz 0:84353c479782 315 }
hudakz 0:84353c479782 316
hudakz 0:84353c479782 317 /* check for RCVDAVIRQ and generate error if not present
hudakz 0:84353c479782 318 * the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred.
hudakz 0:84353c479782 319 * Need to add handling for that
hudakz 0:84353c479782 320 *
hudakz 0:84353c479782 321 * NOTE: I've seen this happen with SPI corruption -- xxxajk
hudakz 0:84353c479782 322 */
hudakz 0:84353c479782 323 if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
hudakz 0:84353c479782 324
hudakz 0:84353c479782 325 //printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
hudakz 0:84353c479782 326 rcode = 0xf0; //receive error
hudakz 0:84353c479782 327 break;
hudakz 0:84353c479782 328 }
hudakz 0:84353c479782 329
hudakz 0:84353c479782 330 pktsize = regRd(rRCVBC); //number of received bytes
hudakz 0:84353c479782 331
hudakz 0:84353c479782 332 //printf("Got %i bytes \r\n", pktsize);
hudakz 0:84353c479782 333 // This would be OK, but...
hudakz 0:84353c479782 334 //assert(pktsize <= nbytes);
hudakz 0:84353c479782 335 if (pktsize > nbytes) {
hudakz 0:84353c479782 336
hudakz 0:84353c479782 337 // This can happen. Use of assert on Arduino locks up the Arduino.
hudakz 0:84353c479782 338 // So I will trim the value, and hope for the best.
hudakz 0:84353c479782 339 //printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
hudakz 0:84353c479782 340 pktsize = nbytes;
hudakz 0:84353c479782 341 }
hudakz 0:84353c479782 342
hudakz 0:84353c479782 343 int16_t mem_left = (int16_t) nbytes -*((int16_t*)nbytesptr);
hudakz 0:84353c479782 344
hudakz 0:84353c479782 345 if (mem_left < 0)
hudakz 0:84353c479782 346 mem_left = 0;
hudakz 0:84353c479782 347
hudakz 0:84353c479782 348 data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data);
hudakz 0:84353c479782 349
hudakz 0:84353c479782 350 regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer
hudakz 0:84353c479782 351 *nbytesptr += pktsize; // add this packet's byte count to total transfer length
hudakz 0:84353c479782 352
hudakz 0:84353c479782 353 /* The transfer is complete under two conditions: */
hudakz 0:84353c479782 354 /* 1. The device sent a short packet (L.T. maxPacketSize) */
hudakz 0:84353c479782 355 /* 2. 'nbytes' have been transferred. */
hudakz 0:84353c479782 356 if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) {
hudakz 0:84353c479782 357
hudakz 0:84353c479782 358 // have we transferred 'nbytes' bytes?
hudakz 0:84353c479782 359 // Save toggle value
hudakz 0:84353c479782 360 pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
hudakz 0:84353c479782 361
hudakz 0:84353c479782 362 //printf("\r\n");
hudakz 0:84353c479782 363 rcode = 0;
hudakz 0:84353c479782 364 break;
hudakz 0:84353c479782 365 }
hudakz 0:84353c479782 366 else
hudakz 0:84353c479782 367 if (bInterval > 0)
hudakz 0:84353c479782 368 wait_ms(bInterval); // Delay according to polling interval
hudakz 0:84353c479782 369 } //while( 1 )
hudakz 0:84353c479782 370
hudakz 0:84353c479782 371 return(rcode);
hudakz 0:84353c479782 372 }
hudakz 0:84353c479782 373
hudakz 0:84353c479782 374 /* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
hudakz 0:84353c479782 375 /* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */
hudakz 0:84353c479782 376
hudakz 0:84353c479782 377 /* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
hudakz 1:2263e77400e9 378 uint8_t Usb::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data)
hudakz 0:84353c479782 379 {
hudakz 0:84353c479782 380 EpInfo* pep = NULL;
hudakz 0:84353c479782 381 uint16_t nak_limit = 0;
hudakz 0:84353c479782 382
hudakz 0:84353c479782 383 uint8_t rcode = setAddress(addr, ep, &pep, &nak_limit);
hudakz 0:84353c479782 384
hudakz 0:84353c479782 385 if (rcode)
hudakz 0:84353c479782 386 return rcode;
hudakz 0:84353c479782 387
hudakz 0:84353c479782 388 return outTransfer(pep, nak_limit, nbytes, data);
hudakz 0:84353c479782 389 }
hudakz 0:84353c479782 390
hudakz 0:84353c479782 391 /**
hudakz 0:84353c479782 392 * @brief
hudakz 0:84353c479782 393 * @note
hudakz 0:84353c479782 394 * @param
hudakz 0:84353c479782 395 * @retval
hudakz 0:84353c479782 396 */
hudakz 1:2263e77400e9 397 uint8_t Usb::outTransfer(EpInfo* pep, uint16_t nak_limit, uint16_t nbytes, uint8_t* data)
hudakz 0:84353c479782 398 {
hudakz 0:84353c479782 399 uint8_t rcode = hrSUCCESS, retry_count;
hudakz 0:84353c479782 400 uint8_t* data_p = data; //local copy of the data pointer
hudakz 0:84353c479782 401 uint16_t bytes_tosend, nak_count;
hudakz 0:84353c479782 402 uint16_t bytes_left = nbytes;
hudakz 0:84353c479782 403
hudakz 0:84353c479782 404 uint8_t maxpktsize = pep->maxPktSize;
hudakz 0:84353c479782 405
hudakz 0:84353c479782 406 if (maxpktsize < 1 || maxpktsize > 64)
hudakz 0:84353c479782 407 return USB_ERROR_INVALID_MAX_PKT_SIZE;
hudakz 0:84353c479782 408
hudakz 0:84353c479782 409 uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
hudakz 0:84353c479782 410
hudakz 0:84353c479782 411 regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
hudakz 0:84353c479782 412 while (bytes_left)
hudakz 0:84353c479782 413 {
hudakz 0:84353c479782 414 #if defined(ESP8266) || defined(ESP32)
hudakz 0:84353c479782 415 yield(); // needed in order to reset the watchdog timer on the ESP8266
hudakz 0:84353c479782 416 #endif
hudakz 0:84353c479782 417 retry_count = 0;
hudakz 0:84353c479782 418 nak_count = 0;
hudakz 0:84353c479782 419 bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
hudakz 0:84353c479782 420 bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
hudakz 0:84353c479782 421 regWr(rSNDBC, bytes_tosend); //set number of bytes
hudakz 0:84353c479782 422 regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
hudakz 0:84353c479782 423 while (!(regRd(rHIRQ) & bmHXFRDNIRQ))
hudakz 0:84353c479782 424 {
hudakz 0:84353c479782 425 #if defined(ESP8266) || defined(ESP32)
hudakz 0:84353c479782 426 yield(); // needed in order to reset the watchdog timer on the ESP8266
hudakz 0:84353c479782 427 #endif
hudakz 0:84353c479782 428 } //wait for the completion IRQ
hudakz 0:84353c479782 429
hudakz 0:84353c479782 430 regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
hudakz 0:84353c479782 431 rcode = (regRd(rHRSL) & 0x0f);
hudakz 0:84353c479782 432
hudakz 0:84353c479782 433 while (rcode && ((int32_t) ((uint32_t)millis() - timeout) < 0L))
hudakz 0:84353c479782 434 {
hudakz 0:84353c479782 435 #if defined(ESP8266) || defined(ESP32)
hudakz 0:84353c479782 436 yield(); // needed in order to reset the watchdog timer on the ESP8266
hudakz 0:84353c479782 437 #endif
hudakz 0:84353c479782 438 switch (rcode) {
hudakz 0:84353c479782 439 case hrNAK:
hudakz 0:84353c479782 440 nak_count++;
hudakz 0:84353c479782 441 if (nak_limit && (nak_count == nak_limit))
hudakz 0:84353c479782 442 goto breakout;
hudakz 0:84353c479782 443
hudakz 0:84353c479782 444 //return ( rcode);
hudakz 0:84353c479782 445 break;
hudakz 0:84353c479782 446
hudakz 0:84353c479782 447 case hrTIMEOUT:
hudakz 0:84353c479782 448 retry_count++;
hudakz 0:84353c479782 449 if (retry_count == USB_RETRY_LIMIT)
hudakz 0:84353c479782 450 goto breakout;
hudakz 0:84353c479782 451
hudakz 0:84353c479782 452 //return ( rcode);
hudakz 0:84353c479782 453 break;
hudakz 0:84353c479782 454
hudakz 0:84353c479782 455 case hrTOGERR:
hudakz 0:84353c479782 456 // yes, we flip it wrong here so that next time it is actually correct!
hudakz 0:84353c479782 457 pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
hudakz 0:84353c479782 458 regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
hudakz 0:84353c479782 459 break;
hudakz 0:84353c479782 460
hudakz 0:84353c479782 461 default:
hudakz 0:84353c479782 462 goto breakout;
hudakz 0:84353c479782 463 } //switch( rcode
hudakz 0:84353c479782 464
hudakz 0:84353c479782 465 /* process NAK according to Host out NAK bug */
hudakz 0:84353c479782 466 regWr(rSNDBC, 0);
hudakz 0:84353c479782 467 regWr(rSNDFIFO, *data_p);
hudakz 0:84353c479782 468 regWr(rSNDBC, bytes_tosend);
hudakz 0:84353c479782 469 regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
hudakz 0:84353c479782 470 while (!(regRd(rHIRQ) & bmHXFRDNIRQ))
hudakz 0:84353c479782 471 {
hudakz 0:84353c479782 472 #if defined(ESP8266) || defined(ESP32)
hudakz 0:84353c479782 473 yield(); // needed in order to reset the watchdog timer on the ESP8266
hudakz 0:84353c479782 474 #endif
hudakz 0:84353c479782 475 } //wait for the completion IRQ
hudakz 0:84353c479782 476
hudakz 0:84353c479782 477 regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
hudakz 0:84353c479782 478 rcode = (regRd(rHRSL) & 0x0f);
hudakz 0:84353c479782 479 } //while( rcode && ....
hudakz 0:84353c479782 480
hudakz 0:84353c479782 481 bytes_left -= bytes_tosend;
hudakz 0:84353c479782 482 data_p += bytes_tosend;
hudakz 0:84353c479782 483 } //while( bytes_left...
hudakz 0:84353c479782 484
hudakz 0:84353c479782 485 breakout:
hudakz 0:84353c479782 486 pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
hudakz 0:84353c479782 487 return(rcode); //should be 0 in all cases
hudakz 0:84353c479782 488 }
hudakz 0:84353c479782 489
hudakz 0:84353c479782 490 /* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
hudakz 0:84353c479782 491 /* If NAK, tries to re-send up to nak_limit times */
hudakz 0:84353c479782 492 /* If nak_limit == 0, do not count NAKs, exit after timeout */
hudakz 0:84353c479782 493 /* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
hudakz 0:84353c479782 494
hudakz 0:84353c479782 495 /* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */
hudakz 1:2263e77400e9 496 uint8_t Usb::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit)
hudakz 0:84353c479782 497 {
hudakz 0:84353c479782 498 uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
hudakz 0:84353c479782 499 uint8_t tmpdata;
hudakz 0:84353c479782 500 uint8_t rcode = hrSUCCESS;
hudakz 0:84353c479782 501 uint8_t retry_count = 0;
hudakz 0:84353c479782 502 uint16_t nak_count = 0;
hudakz 0:84353c479782 503
hudakz 0:84353c479782 504 while ((int32_t) ((uint32_t)millis() - timeout) < 0L)
hudakz 0:84353c479782 505 {
hudakz 0:84353c479782 506 #if defined(ESP8266) || defined(ESP32)
hudakz 0:84353c479782 507 yield(); // needed in order to reset the watchdog timer on the ESP8266
hudakz 0:84353c479782 508 #endif
hudakz 0:84353c479782 509 regWr(rHXFR, (token | ep)); //launch the transfer
hudakz 0:84353c479782 510 rcode = USB_ERROR_TRANSFER_TIMEOUT;
hudakz 0:84353c479782 511
hudakz 0:84353c479782 512 while ((int32_t) ((uint32_t)millis() - timeout) < 0L) //wait for transfer completion
hudakz 0:84353c479782 513 {
hudakz 0:84353c479782 514 #if defined(ESP8266) || defined(ESP32)
hudakz 0:84353c479782 515 yield(); // needed in order to reset the watchdog timer on the ESP8266
hudakz 0:84353c479782 516 #endif
hudakz 0:84353c479782 517 tmpdata = regRd(rHIRQ);
hudakz 0:84353c479782 518
hudakz 0:84353c479782 519 if (tmpdata & bmHXFRDNIRQ) {
hudakz 0:84353c479782 520 regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
hudakz 0:84353c479782 521 rcode = 0x00;
hudakz 0:84353c479782 522 break;
hudakz 0:84353c479782 523 } //if( tmpdata & bmHXFRDNIRQ
hudakz 0:84353c479782 524 } //while ( millis() < timeout
hudakz 0:84353c479782 525
hudakz 0:84353c479782 526 //if (rcode != 0x00) //exit if timeout
hudakz 0:84353c479782 527 // return ( rcode);
hudakz 0:84353c479782 528 rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result
hudakz 0:84353c479782 529 switch (rcode) {
hudakz 0:84353c479782 530 case hrNAK:
hudakz 0:84353c479782 531 nak_count++;
hudakz 0:84353c479782 532 if (nak_limit && (nak_count == nak_limit))
hudakz 0:84353c479782 533 return(rcode);
hudakz 0:84353c479782 534 break;
hudakz 0:84353c479782 535
hudakz 0:84353c479782 536 case hrTIMEOUT:
hudakz 0:84353c479782 537 retry_count++;
hudakz 0:84353c479782 538 if (retry_count == USB_RETRY_LIMIT)
hudakz 0:84353c479782 539 return(rcode);
hudakz 0:84353c479782 540 break;
hudakz 0:84353c479782 541
hudakz 0:84353c479782 542 default:
hudakz 0:84353c479782 543 return(rcode);
hudakz 0:84353c479782 544 } //switch( rcode
hudakz 0:84353c479782 545 } //while( timeout > millis()
hudakz 0:84353c479782 546
hudakz 0:84353c479782 547 return(rcode);
hudakz 0:84353c479782 548 }
hudakz 0:84353c479782 549
hudakz 0:84353c479782 550 /* USB main task. Performs enumeration/cleanup */
hudakz 1:2263e77400e9 551 void Usb::task(void) //USB state machine
hudakz 0:84353c479782 552 {
hudakz 0:84353c479782 553 uint8_t rcode;
hudakz 0:84353c479782 554 uint8_t tmpdata;
hudakz 0:84353c479782 555 static uint32_t delay = 0;
hudakz 0:84353c479782 556
hudakz 0:84353c479782 557 //USB_DEVICE_DESCRIPTOR buf;
hudakz 0:84353c479782 558 bool lowspeed = false;
hudakz 0:84353c479782 559
hudakz 0:84353c479782 560 MAX3421E::task();
hudakz 0:84353c479782 561
hudakz 0:84353c479782 562 tmpdata = getVbusState();
hudakz 0:84353c479782 563
hudakz 0:84353c479782 564 /* modify USB task state if Vbus changed */
hudakz 0:84353c479782 565 switch (tmpdata) {
hudakz 0:84353c479782 566 case SE1: //illegal state
hudakz 0:84353c479782 567 usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
hudakz 0:84353c479782 568 lowspeed = false;
hudakz 0:84353c479782 569 break;
hudakz 0:84353c479782 570
hudakz 0:84353c479782 571 case SE0: //disconnected
hudakz 0:84353c479782 572 if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
hudakz 0:84353c479782 573 usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
hudakz 0:84353c479782 574 lowspeed = false;
hudakz 0:84353c479782 575 break;
hudakz 0:84353c479782 576
hudakz 0:84353c479782 577 case LSHOST:
hudakz 0:84353c479782 578 lowspeed = true;
hudakz 0:84353c479782 579
hudakz 0:84353c479782 580 //intentional fallthrough
hudakz 0:84353c479782 581 case FSHOST: //attached
hudakz 0:84353c479782 582 if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
hudakz 0:84353c479782 583 delay = (uint32_t)millis() + USB_SETTLE_DELAY;
hudakz 0:84353c479782 584 usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
hudakz 0:84353c479782 585 }
hudakz 0:84353c479782 586 break;
hudakz 0:84353c479782 587 } // switch( tmpdata
hudakz 0:84353c479782 588
hudakz 0:84353c479782 589 for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
hudakz 0:84353c479782 590 if (devConfig[i])
hudakz 0:84353c479782 591 rcode = devConfig[i]->Poll();
hudakz 0:84353c479782 592
hudakz 0:84353c479782 593 switch (usb_task_state) {
hudakz 0:84353c479782 594 case USB_DETACHED_SUBSTATE_INITIALIZE:
hudakz 0:84353c479782 595 init();
hudakz 0:84353c479782 596
hudakz 0:84353c479782 597 for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
hudakz 0:84353c479782 598 if (devConfig[i])
hudakz 0:84353c479782 599 rcode = devConfig[i]->Release();
hudakz 0:84353c479782 600
hudakz 0:84353c479782 601 usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
hudakz 0:84353c479782 602 break;
hudakz 0:84353c479782 603
hudakz 0:84353c479782 604 case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
hudakz 0:84353c479782 605 break;
hudakz 0:84353c479782 606
hudakz 0:84353c479782 607 case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
hudakz 0:84353c479782 608 break;
hudakz 0:84353c479782 609
hudakz 0:84353c479782 610 case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
hudakz 0:84353c479782 611 if ((int32_t) ((uint32_t)millis() - delay) >= 0L)
hudakz 0:84353c479782 612 usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
hudakz 0:84353c479782 613 else
hudakz 0:84353c479782 614 break; // don't fall through
hudakz 0:84353c479782 615
hudakz 0:84353c479782 616 case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
hudakz 0:84353c479782 617 regWr(rHCTL, bmBUSRST); //issue bus reset
hudakz 0:84353c479782 618 usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
hudakz 0:84353c479782 619 break;
hudakz 0:84353c479782 620
hudakz 0:84353c479782 621 case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
hudakz 0:84353c479782 622 if ((regRd(rHCTL) & bmBUSRST) == 0) {
hudakz 0:84353c479782 623 tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
hudakz 0:84353c479782 624 regWr(rMODE, tmpdata);
hudakz 0:84353c479782 625 usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
hudakz 0:84353c479782 626
hudakz 0:84353c479782 627 //delay = (uint32_t)millis() + 20; //20ms wait after reset per USB spec
hudakz 0:84353c479782 628 }
hudakz 0:84353c479782 629 break;
hudakz 0:84353c479782 630
hudakz 0:84353c479782 631 case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
hudakz 0:84353c479782 632 if (regRd(rHIRQ) & bmFRAMEIRQ) {
hudakz 0:84353c479782 633
hudakz 0:84353c479782 634 //when first SOF received _and_ 20ms has passed we can continue
hudakz 0:84353c479782 635 /*
hudakz 0:84353c479782 636 if (delay < (uint32_t)millis()) //20ms passed
hudakz 0:84353c479782 637 usb_task_state = USB_STATE_CONFIGURING;
hudakz 0:84353c479782 638 */
hudakz 0:84353c479782 639 usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET;
hudakz 0:84353c479782 640 delay = (uint32_t)millis() + 20;
hudakz 0:84353c479782 641 }
hudakz 0:84353c479782 642 break;
hudakz 0:84353c479782 643
hudakz 0:84353c479782 644 case USB_ATTACHED_SUBSTATE_WAIT_RESET:
hudakz 0:84353c479782 645 if ((int32_t) ((uint32_t)millis() - delay) >= 0L)
hudakz 0:84353c479782 646 usb_task_state = USB_STATE_CONFIGURING;
hudakz 0:84353c479782 647 else
hudakz 0:84353c479782 648 break; // don't fall through
hudakz 0:84353c479782 649
hudakz 0:84353c479782 650 case USB_STATE_CONFIGURING:
hudakz 0:84353c479782 651 //Serial.print("\r\nConf.LS: ");
hudakz 0:84353c479782 652 //Serial.println(lowspeed, HEX);
hudakz 0:84353c479782 653 rcode = configuring(0, 0, lowspeed);
hudakz 0:84353c479782 654
hudakz 0:84353c479782 655 if (rcode) {
hudakz 0:84353c479782 656 if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
hudakz 0:84353c479782 657 usb_error = rcode;
hudakz 0:84353c479782 658 usb_task_state = USB_STATE_ERROR;
hudakz 0:84353c479782 659 }
hudakz 0:84353c479782 660 }
hudakz 0:84353c479782 661 else
hudakz 0:84353c479782 662 usb_task_state = USB_STATE_RUNNING;
hudakz 0:84353c479782 663 break;
hudakz 0:84353c479782 664
hudakz 0:84353c479782 665 case USB_STATE_RUNNING:
hudakz 0:84353c479782 666 break;
hudakz 0:84353c479782 667
hudakz 0:84353c479782 668 case USB_STATE_ERROR:
hudakz 0:84353c479782 669 //MAX3421E::Init();
hudakz 0:84353c479782 670 break;
hudakz 0:84353c479782 671 } // switch( usb_task_state )
hudakz 0:84353c479782 672 }
hudakz 0:84353c479782 673
hudakz 0:84353c479782 674 /**
hudakz 0:84353c479782 675 * @brief
hudakz 0:84353c479782 676 * @note
hudakz 0:84353c479782 677 * @param
hudakz 0:84353c479782 678 * @retval
hudakz 0:84353c479782 679 */
hudakz 1:2263e77400e9 680 uint8_t Usb::defaultAddressing(uint8_t parent, uint8_t port, bool lowspeed)
hudakz 0:84353c479782 681 {
hudakz 0:84353c479782 682 //uint8_t buf[12];
hudakz 0:84353c479782 683 uint8_t rcode;
hudakz 0:84353c479782 684 UsbDevice* p0 = NULL, *p = NULL;
hudakz 0:84353c479782 685
hudakz 0:84353c479782 686 // Get pointer to pseudo device with address 0 assigned
hudakz 0:84353c479782 687
hudakz 0:84353c479782 688 p0 = addrPool.GetUsbDevicePtr(0);
hudakz 0:84353c479782 689
hudakz 0:84353c479782 690 if (!p0)
hudakz 0:84353c479782 691 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
hudakz 0:84353c479782 692
hudakz 0:84353c479782 693 if (!p0->epinfo)
hudakz 0:84353c479782 694 return USB_ERROR_EPINFO_IS_NULL;
hudakz 0:84353c479782 695
hudakz 0:84353c479782 696 p0->lowspeed = (lowspeed) ? true : false;
hudakz 0:84353c479782 697
hudakz 0:84353c479782 698 // Allocate new address according to device class
hudakz 0:84353c479782 699 uint8_t bAddress = addrPool.AllocAddress(parent, false, port);
hudakz 0:84353c479782 700
hudakz 0:84353c479782 701 if (!bAddress)
hudakz 0:84353c479782 702 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
hudakz 0:84353c479782 703
hudakz 0:84353c479782 704 p = addrPool.GetUsbDevicePtr(bAddress);
hudakz 0:84353c479782 705
hudakz 0:84353c479782 706 if (!p)
hudakz 0:84353c479782 707 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
hudakz 0:84353c479782 708
hudakz 0:84353c479782 709 p->lowspeed = lowspeed;
hudakz 0:84353c479782 710
hudakz 0:84353c479782 711 // Assign new address to the device
hudakz 0:84353c479782 712 rcode = setAddr(0, 0, bAddress);
hudakz 0:84353c479782 713
hudakz 0:84353c479782 714 if (rcode) {
hudakz 0:84353c479782 715 addrPool.FreeAddress(bAddress);
hudakz 0:84353c479782 716 bAddress = 0;
hudakz 0:84353c479782 717 return rcode;
hudakz 0:84353c479782 718 }
hudakz 0:84353c479782 719
hudakz 0:84353c479782 720 return 0;
hudakz 0:84353c479782 721 }
hudakz 0:84353c479782 722
hudakz 0:84353c479782 723 /**
hudakz 0:84353c479782 724 * @brief
hudakz 0:84353c479782 725 * @note
hudakz 0:84353c479782 726 * @param
hudakz 0:84353c479782 727 * @retval
hudakz 0:84353c479782 728 */
hudakz 1:2263e77400e9 729 uint8_t Usb::attemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed)
hudakz 0:84353c479782 730 {
hudakz 0:84353c479782 731 //printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
hudakz 0:84353c479782 732 uint8_t retries = 0;
hudakz 0:84353c479782 733
hudakz 0:84353c479782 734 again:
hudakz 0:84353c479782 735 uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed);
hudakz 0:84353c479782 736 if (rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) {
hudakz 0:84353c479782 737 if (parent == 0) {
hudakz 0:84353c479782 738
hudakz 0:84353c479782 739 // Send a bus reset on the root interface.
hudakz 0:84353c479782 740 regWr(rHCTL, bmBUSRST); //issue bus reset
hudakz 0:84353c479782 741 wait_ms(102); // delay 102ms, compensate for clock inaccuracy.
hudakz 0:84353c479782 742 }
hudakz 0:84353c479782 743 else {
hudakz 0:84353c479782 744
hudakz 0:84353c479782 745 // reset parent port
hudakz 0:84353c479782 746 devConfig[parent]->ResetHubPort(port);
hudakz 0:84353c479782 747 }
hudakz 0:84353c479782 748 }
hudakz 0:84353c479782 749 else
hudakz 0:84353c479782 750 if (rcode == hrJERR && retries < 3) {
hudakz 0:84353c479782 751
hudakz 0:84353c479782 752 // Some devices returns this when plugged in - trying to initialize the device again usually works
hudakz 0:84353c479782 753 wait_ms(100);
hudakz 0:84353c479782 754 retries++;
hudakz 0:84353c479782 755 goto again;
hudakz 0:84353c479782 756 }
hudakz 0:84353c479782 757 else
hudakz 0:84353c479782 758 if (rcode)
hudakz 0:84353c479782 759 return rcode;
hudakz 0:84353c479782 760
hudakz 0:84353c479782 761 rcode = devConfig[driver]->Init(parent, port, lowspeed);
hudakz 0:84353c479782 762 if (rcode == hrJERR && retries < 3) {
hudakz 0:84353c479782 763
hudakz 0:84353c479782 764 // Some devices returns this when plugged in - trying to initialize the device again usually works
hudakz 0:84353c479782 765 wait_ms(100);
hudakz 0:84353c479782 766 retries++;
hudakz 0:84353c479782 767 goto again;
hudakz 0:84353c479782 768 }
hudakz 0:84353c479782 769
hudakz 0:84353c479782 770 if (rcode) {
hudakz 0:84353c479782 771
hudakz 0:84353c479782 772 // Issue a bus reset, because the device may be in a limbo state
hudakz 0:84353c479782 773 if (parent == 0) {
hudakz 0:84353c479782 774
hudakz 0:84353c479782 775 // Send a bus reset on the root interface.
hudakz 0:84353c479782 776 regWr(rHCTL, bmBUSRST); //issue bus reset
hudakz 0:84353c479782 777 wait_ms(102); // delay 102ms, compensate for clock inaccuracy.
hudakz 0:84353c479782 778 }
hudakz 0:84353c479782 779 else {
hudakz 0:84353c479782 780
hudakz 0:84353c479782 781 // reset parent port
hudakz 0:84353c479782 782 devConfig[parent]->ResetHubPort(port);
hudakz 0:84353c479782 783 }
hudakz 0:84353c479782 784 }
hudakz 0:84353c479782 785
hudakz 0:84353c479782 786 return rcode;
hudakz 0:84353c479782 787 }
hudakz 0:84353c479782 788
hudakz 0:84353c479782 789 /*
hudakz 0:84353c479782 790 * This is broken. We need to enumerate differently.
hudakz 0:84353c479782 791 * It causes major problems with several devices if detected in an unexpected order.
hudakz 0:84353c479782 792 *
hudakz 0:84353c479782 793 *
hudakz 0:84353c479782 794 * Oleg - I wouldn't do anything before the newly connected device is considered sane.
hudakz 0:84353c479782 795 * i.e.(delays are not indicated for brevity):
hudakz 0:84353c479782 796 * 1. reset
hudakz 0:84353c479782 797 * 2. GetDevDescr();
hudakz 0:84353c479782 798 * 3a. If ACK, continue with allocating address, addressing, etc.
hudakz 0:84353c479782 799 * 3b. Else reset again, count resets, stop at some number (5?).
hudakz 0:84353c479782 800 * 4. When max.number of resets is reached, toggle power/fail
hudakz 0:84353c479782 801 * 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()
hudakz 0:84353c479782 802 * it doesn't need to be reset again
hudakz 0:84353c479782 803 * New steps proposal:
hudakz 0:84353c479782 804 * 1: get address pool instance. exit on fail
hudakz 0:84353c479782 805 * 2: pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf). exit on fail.
hudakz 0:84353c479782 806 * 3: bus reset, 100ms delay
hudakz 0:84353c479782 807 * 4: set address
hudakz 0:84353c479782 808 * 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail
hudakz 0:84353c479782 809 * 6: while (configurations) {
hudakz 0:84353c479782 810 * for(each configuration) {
hudakz 0:84353c479782 811 * for (each driver) {
hudakz 0:84353c479782 812 * 6a: Ask device if it likes configuration. Returns 0 on OK.
hudakz 0:84353c479782 813 * If successful, the driver configured device.
hudakz 0:84353c479782 814 * The driver now owns the endpoints, and takes over managing them.
hudakz 0:84353c479782 815 * The following will need codes:
hudakz 0:84353c479782 816 * Everything went well, instance consumed, exit with success.
hudakz 0:84353c479782 817 * Instance already in use, ignore it, try next driver.
hudakz 0:84353c479782 818 * Not a supported device, ignore it, try next driver.
hudakz 0:84353c479782 819 * Not a supported configuration for this device, ignore it, try next driver.
hudakz 0:84353c479782 820 * Could not configure device, fatal, exit with fail.
hudakz 0:84353c479782 821 * }
hudakz 0:84353c479782 822 * }
hudakz 0:84353c479782 823 * }
hudakz 0:84353c479782 824 * 7: for(each driver) {
hudakz 0:84353c479782 825 * 7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID
hudakz 0:84353c479782 826 * 8: if we get here, no driver likes the device plugged in, so exit failure.
hudakz 0:84353c479782 827 *
hudakz 0:84353c479782 828 */
hudakz 1:2263e77400e9 829 uint8_t Usb::configuring(uint8_t parent, uint8_t port, bool lowspeed)
hudakz 0:84353c479782 830 {
hudakz 0:84353c479782 831 //uint8_t bAddress = 0;
hudakz 0:84353c479782 832
hudakz 0:84353c479782 833 //printf("Configuring: parent = %i, port = %i\r\n", parent, port);
hudakz 0:84353c479782 834 uint8_t devConfigIndex;
hudakz 0:84353c479782 835 uint8_t rcode = 0;
hudakz 0:84353c479782 836 uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
hudakz 0:84353c479782 837 USB_DEVICE_DESCRIPTOR* udd = reinterpret_cast < USB_DEVICE_DESCRIPTOR * > (buf);
hudakz 0:84353c479782 838 UsbDevice* p = NULL;
hudakz 0:84353c479782 839 EpInfo* oldep_ptr = NULL;
hudakz 0:84353c479782 840 EpInfo epInfo;
hudakz 0:84353c479782 841
hudakz 0:84353c479782 842 epInfo.epAddr = 0;
hudakz 0:84353c479782 843 epInfo.maxPktSize = 8;
hudakz 0:84353c479782 844 epInfo.bmSndToggle = 0;
hudakz 0:84353c479782 845 epInfo.bmRcvToggle = 0;
hudakz 0:84353c479782 846 epInfo.bmNakPower = USB_NAK_MAX_POWER;
hudakz 0:84353c479782 847
hudakz 0:84353c479782 848 //wait_ms(2000);
hudakz 0:84353c479782 849 AddressPool& addrPool = GetAddressPool();
hudakz 0:84353c479782 850 // Get pointer to pseudo device with address 0 assigned
hudakz 0:84353c479782 851
hudakz 0:84353c479782 852 p = addrPool.GetUsbDevicePtr(0);
hudakz 0:84353c479782 853 if (!p) {
hudakz 0:84353c479782 854
hudakz 0:84353c479782 855 //printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
hudakz 0:84353c479782 856 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
hudakz 0:84353c479782 857 }
hudakz 0:84353c479782 858
hudakz 0:84353c479782 859 // Save old pointer to EP_RECORD of address 0
hudakz 0:84353c479782 860 oldep_ptr = p->epinfo;
hudakz 0:84353c479782 861
hudakz 0:84353c479782 862 // Temporary assign new pointer to epInfo to p->epinfo in order to
hudakz 0:84353c479782 863 // avoid toggle inconsistence
hudakz 0:84353c479782 864 p->epinfo = &epInfo;
hudakz 0:84353c479782 865
hudakz 0:84353c479782 866 p->lowspeed = lowspeed;
hudakz 0:84353c479782 867
hudakz 0:84353c479782 868 // Get device descriptor
hudakz 0:84353c479782 869 rcode = getDevDescr(0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
hudakz 0:84353c479782 870
hudakz 0:84353c479782 871 // Restore p->epinfo
hudakz 0:84353c479782 872 p->epinfo = oldep_ptr;
hudakz 0:84353c479782 873
hudakz 0:84353c479782 874 if (rcode) {
hudakz 0:84353c479782 875
hudakz 0:84353c479782 876 //printf("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n");
hudakz 0:84353c479782 877 return rcode;
hudakz 0:84353c479782 878 }
hudakz 0:84353c479782 879
hudakz 0:84353c479782 880 // to-do?
hudakz 0:84353c479782 881 // Allocate new address according to device class
hudakz 0:84353c479782 882 //bAddress = addrPool.AllocAddress(parent, false, port);
hudakz 0:84353c479782 883 uint16_t vid = udd->idVendor;
hudakz 0:84353c479782 884 uint16_t pid = udd->idProduct;
hudakz 0:84353c479782 885 uint8_t klass = udd->bDeviceClass;
hudakz 0:84353c479782 886 uint8_t subklass = udd->bDeviceSubClass;
hudakz 0:84353c479782 887 // Attempt to configure if VID/PID or device class matches with a driver
hudakz 0:84353c479782 888
hudakz 0:84353c479782 889 // Qualify with subclass too.
hudakz 0:84353c479782 890 //
hudakz 0:84353c479782 891 // VID/PID & class tests default to false for drivers not yet ported
hudakz 0:84353c479782 892 // subclass defaults to true, so you don't have to define it if you don't have to.
hudakz 0:84353c479782 893 //
hudakz 0:84353c479782 894 for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
hudakz 0:84353c479782 895 if (!devConfig[devConfigIndex])
hudakz 0:84353c479782 896 continue; // no driver
hudakz 0:84353c479782 897 if (devConfig[devConfigIndex]->GetAddress())
hudakz 0:84353c479782 898 continue; // consumed
hudakz 0:84353c479782 899 if
hudakz 0:84353c479782 900 (
hudakz 0:84353c479782 901 devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) &&
hudakz 0:84353c479782 902 (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))
hudakz 0:84353c479782 903 ) {
hudakz 0:84353c479782 904 rcode = attemptConfig(devConfigIndex, parent, port, lowspeed);
hudakz 0:84353c479782 905 if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
hudakz 0:84353c479782 906 break;
hudakz 0:84353c479782 907 }
hudakz 0:84353c479782 908 }
hudakz 0:84353c479782 909
hudakz 0:84353c479782 910 if (devConfigIndex < USB_NUMDEVICES) {
hudakz 0:84353c479782 911 return rcode;
hudakz 0:84353c479782 912 }
hudakz 0:84353c479782 913
hudakz 0:84353c479782 914 // blindly attempt to configure
hudakz 0:84353c479782 915 for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
hudakz 0:84353c479782 916 if (!devConfig[devConfigIndex])
hudakz 0:84353c479782 917 continue;
hudakz 0:84353c479782 918 if (devConfig[devConfigIndex]->GetAddress())
hudakz 0:84353c479782 919 continue; // consumed
hudakz 0:84353c479782 920 if
hudakz 0:84353c479782 921 (
hudakz 0:84353c479782 922 devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) &&
hudakz 0:84353c479782 923 (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))
hudakz 0:84353c479782 924 ) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above
hudakz 0:84353c479782 925 rcode = attemptConfig(devConfigIndex, parent, port, lowspeed);
hudakz 0:84353c479782 926
hudakz 0:84353c479782 927 //printf("ERROR ENUMERATING %2.2x\r\n", rcode);
hudakz 0:84353c479782 928 if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) {
hudakz 0:84353c479782 929
hudakz 0:84353c479782 930 // in case of an error dev_index should be reset to 0
hudakz 0:84353c479782 931 // in order to start from the very beginning the
hudakz 0:84353c479782 932 // next time the program gets here
hudakz 0:84353c479782 933 //if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
hudakz 0:84353c479782 934 // devConfigIndex = 0;
hudakz 0:84353c479782 935 return rcode;
hudakz 0:84353c479782 936 }
hudakz 0:84353c479782 937 }
hudakz 0:84353c479782 938
hudakz 0:84353c479782 939 // if we get here that means that the device class is not supported by any of registered classes
hudakz 0:84353c479782 940 rcode = defaultAddressing(parent, port, lowspeed);
hudakz 0:84353c479782 941
hudakz 0:84353c479782 942 return rcode;
hudakz 0:84353c479782 943 }
hudakz 0:84353c479782 944
hudakz 0:84353c479782 945 /**
hudakz 0:84353c479782 946 * @brief
hudakz 0:84353c479782 947 * @note
hudakz 0:84353c479782 948 * @param
hudakz 0:84353c479782 949 * @retval
hudakz 0:84353c479782 950 */
hudakz 1:2263e77400e9 951 uint8_t Usb::releaseDevice(uint8_t addr)
hudakz 0:84353c479782 952 {
hudakz 0:84353c479782 953 if (!addr)
hudakz 0:84353c479782 954 return 0;
hudakz 0:84353c479782 955
hudakz 0:84353c479782 956 for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
hudakz 0:84353c479782 957 if (!devConfig[i])
hudakz 0:84353c479782 958 continue;
hudakz 0:84353c479782 959 if (devConfig[i]->GetAddress() == addr)
hudakz 0:84353c479782 960 return devConfig[i]->Release();
hudakz 0:84353c479782 961 }
hudakz 0:84353c479782 962
hudakz 0:84353c479782 963 return 0;
hudakz 0:84353c479782 964 }
hudakz 0:84353c479782 965
hudakz 0:84353c479782 966 #if 1 //!defined(USB_METHODS_INLINE)
hudakz 0:84353c479782 967
hudakz 0:84353c479782 968 //get device descriptor
hudakz 1:2263e77400e9 969 uint8_t Usb::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr)
hudakz 0:84353c479782 970 {
hudakz 0:84353c479782 971 return
hudakz 0:84353c479782 972 (
hudakz 0:84353c479782 973 ctrlReq
hudakz 0:84353c479782 974 (
hudakz 0:84353c479782 975 addr,
hudakz 0:84353c479782 976 ep,
hudakz 0:84353c479782 977 bmREQ_GET_DESCR,
hudakz 0:84353c479782 978 USB_REQUEST_GET_DESCRIPTOR,
hudakz 0:84353c479782 979 0x00,
hudakz 0:84353c479782 980 USB_DESCRIPTOR_DEVICE,
hudakz 0:84353c479782 981 0x0000,
hudakz 0:84353c479782 982 nbytes,
hudakz 0:84353c479782 983 nbytes,
hudakz 0:84353c479782 984 dataptr,
hudakz 0:84353c479782 985 NULL
hudakz 0:84353c479782 986 )
hudakz 0:84353c479782 987 );
hudakz 0:84353c479782 988 }
hudakz 0:84353c479782 989
hudakz 0:84353c479782 990 //get configuration descriptor
hudakz 1:2263e77400e9 991 uint8_t Usb::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr)
hudakz 0:84353c479782 992 {
hudakz 0:84353c479782 993 return
hudakz 0:84353c479782 994 (
hudakz 0:84353c479782 995 ctrlReq
hudakz 0:84353c479782 996 (
hudakz 0:84353c479782 997 addr,
hudakz 0:84353c479782 998 ep,
hudakz 0:84353c479782 999 bmREQ_GET_DESCR,
hudakz 0:84353c479782 1000 USB_REQUEST_GET_DESCRIPTOR,
hudakz 0:84353c479782 1001 conf,
hudakz 0:84353c479782 1002 USB_DESCRIPTOR_CONFIGURATION,
hudakz 0:84353c479782 1003 0x0000,
hudakz 0:84353c479782 1004 nbytes,
hudakz 0:84353c479782 1005 nbytes,
hudakz 0:84353c479782 1006 dataptr,
hudakz 0:84353c479782 1007 NULL
hudakz 0:84353c479782 1008 )
hudakz 0:84353c479782 1009 );
hudakz 0:84353c479782 1010 }
hudakz 0:84353c479782 1011
hudakz 0:84353c479782 1012 /* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this
hudakz 0:84353c479782 1013 total length. The length of the first request can be shorter ( 4 bytes ), however, there are devices which won't work unless this length is set to 9 */
hudakz 1:2263e77400e9 1014 uint8_t Usb::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser* p)
hudakz 0:84353c479782 1015 {
hudakz 0:84353c479782 1016 const uint8_t bufSize = 64;
hudakz 0:84353c479782 1017 uint8_t buf[bufSize];
hudakz 0:84353c479782 1018 USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast < USB_CONFIGURATION_DESCRIPTOR * > (buf);
hudakz 0:84353c479782 1019
hudakz 0:84353c479782 1020 uint8_t ret = getConfDescr(addr, ep, 9, conf, buf);
hudakz 0:84353c479782 1021
hudakz 0:84353c479782 1022 if (ret)
hudakz 0:84353c479782 1023 return ret;
hudakz 0:84353c479782 1024
hudakz 0:84353c479782 1025 uint16_t total = ucd->wTotalLength;
hudakz 0:84353c479782 1026
hudakz 0:84353c479782 1027 //USBTRACE2("\r\ntotal conf.size:", total);
hudakz 0:84353c479782 1028
hudakz 0:84353c479782 1029 return
hudakz 0:84353c479782 1030 (
hudakz 0:84353c479782 1031 ctrlReq
hudakz 0:84353c479782 1032 (
hudakz 0:84353c479782 1033 addr,
hudakz 0:84353c479782 1034 ep,
hudakz 0:84353c479782 1035 bmREQ_GET_DESCR,
hudakz 0:84353c479782 1036 USB_REQUEST_GET_DESCRIPTOR,
hudakz 0:84353c479782 1037 conf,
hudakz 0:84353c479782 1038 USB_DESCRIPTOR_CONFIGURATION,
hudakz 0:84353c479782 1039 0x0000,
hudakz 0:84353c479782 1040 total,
hudakz 0:84353c479782 1041 bufSize,
hudakz 0:84353c479782 1042 buf,
hudakz 0:84353c479782 1043 p
hudakz 0:84353c479782 1044 )
hudakz 0:84353c479782 1045 );
hudakz 0:84353c479782 1046 }
hudakz 0:84353c479782 1047
hudakz 0:84353c479782 1048 //get string descriptor
hudakz 1:2263e77400e9 1049 uint8_t Usb::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr)
hudakz 0:84353c479782 1050 {
hudakz 0:84353c479782 1051 return
hudakz 0:84353c479782 1052 (
hudakz 0:84353c479782 1053 ctrlReq
hudakz 0:84353c479782 1054 (
hudakz 0:84353c479782 1055 addr,
hudakz 0:84353c479782 1056 ep,
hudakz 0:84353c479782 1057 bmREQ_GET_DESCR,
hudakz 0:84353c479782 1058 USB_REQUEST_GET_DESCRIPTOR,
hudakz 0:84353c479782 1059 index,
hudakz 0:84353c479782 1060 USB_DESCRIPTOR_STRING,
hudakz 0:84353c479782 1061 langid,
hudakz 0:84353c479782 1062 ns,
hudakz 0:84353c479782 1063 ns,
hudakz 0:84353c479782 1064 dataptr,
hudakz 0:84353c479782 1065 NULL
hudakz 0:84353c479782 1066 )
hudakz 0:84353c479782 1067 );
hudakz 0:84353c479782 1068 }
hudakz 0:84353c479782 1069
hudakz 0:84353c479782 1070 //set address
hudakz 1:2263e77400e9 1071 uint8_t Usb::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
hudakz 0:84353c479782 1072 {
hudakz 0:84353c479782 1073 uint8_t rcode = ctrlReq
hudakz 0:84353c479782 1074 (
hudakz 0:84353c479782 1075 oldaddr,
hudakz 0:84353c479782 1076 ep,
hudakz 0:84353c479782 1077 bmREQ_SET,
hudakz 0:84353c479782 1078 USB_REQUEST_SET_ADDRESS,
hudakz 0:84353c479782 1079 newaddr,
hudakz 0:84353c479782 1080 0x00,
hudakz 0:84353c479782 1081 0x0000,
hudakz 0:84353c479782 1082 0x0000,
hudakz 0:84353c479782 1083 0x0000,
hudakz 0:84353c479782 1084 NULL,
hudakz 0:84353c479782 1085 NULL
hudakz 0:84353c479782 1086 );
hudakz 0:84353c479782 1087 //wait_ms(2); //per USB 2.0 sect.9.2.6.3
hudakz 0:84353c479782 1088
hudakz 0:84353c479782 1089 wait_ms(300); // Older spec says you should wait at least 200ms
hudakz 0:84353c479782 1090 return rcode;
hudakz 0:84353c479782 1091
hudakz 0:84353c479782 1092 //return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
hudakz 0:84353c479782 1093 }
hudakz 0:84353c479782 1094
hudakz 0:84353c479782 1095 //set configuration
hudakz 1:2263e77400e9 1096 uint8_t Usb::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
hudakz 0:84353c479782 1097 {
hudakz 0:84353c479782 1098 return
hudakz 0:84353c479782 1099 (
hudakz 0:84353c479782 1100 ctrlReq
hudakz 0:84353c479782 1101 (
hudakz 0:84353c479782 1102 addr,
hudakz 0:84353c479782 1103 ep,
hudakz 0:84353c479782 1104 bmREQ_SET,
hudakz 0:84353c479782 1105 USB_REQUEST_SET_CONFIGURATION,
hudakz 0:84353c479782 1106 conf_value,
hudakz 0:84353c479782 1107 0x00,
hudakz 0:84353c479782 1108 0x0000,
hudakz 0:84353c479782 1109 0x0000,
hudakz 0:84353c479782 1110 0x0000,
hudakz 0:84353c479782 1111 NULL,
hudakz 0:84353c479782 1112 NULL
hudakz 0:84353c479782 1113 )
hudakz 0:84353c479782 1114 );
hudakz 0:84353c479782 1115 }
hudakz 0:84353c479782 1116 #endif // defined(USB_METHODS_INLINE)