Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of gr-peach-opencv-project-sd-card by
USBHost.cpp
00001 /* mbed USBHost Library 00002 * Copyright (c) 2006-2013 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 00018 #include "USBHost.h" 00019 #include "USBHostHub.h" 00020 00021 USBHost * USBHost::instHost = NULL; 00022 00023 #define DEVICE_CONNECTED_EVENT (1 << 0) 00024 #define DEVICE_DISCONNECTED_EVENT (1 << 1) 00025 #define TD_PROCESSED_EVENT (1 << 2) 00026 00027 #define MAX_TRY_ENUMERATE_HUB 3 00028 00029 #define MIN(a, b) ((a > b) ? b : a) 00030 00031 /** 00032 * How interrupts are processed: 00033 * - new device connected: 00034 * - a message is queued in queue_usb_event with the id DEVICE_CONNECTED_EVENT 00035 * - when the usb_thread receives the event, it: 00036 * - resets the device 00037 * - reads the device descriptor 00038 * - sets the address of the device 00039 * - if it is a hub, enumerates it 00040 * - device disconnected: 00041 * - a message is queued in queue_usb_event with the id DEVICE_DISCONNECTED_EVENT 00042 * - when the usb_thread receives the event, it: 00043 * - free the device and all its children (hub) 00044 * - td processed 00045 * - a message is queued in queue_usb_event with the id TD_PROCESSED_EVENT 00046 * - when the usb_thread receives the event, it: 00047 * - call the callback attached to the endpoint where the td is attached 00048 */ 00049 void USBHost::usb_process() { 00050 00051 bool controlListState; 00052 bool bulkListState; 00053 bool interruptListState; 00054 USBEndpoint * ep; 00055 uint8_t i, j, res, timeout_set_addr = 10; 00056 uint8_t buf[8]; 00057 bool too_many_hub; 00058 int idx; 00059 00060 #if DEBUG_TRANSFER 00061 uint8_t * buf_transfer; 00062 #endif 00063 00064 #if MAX_HUB_NB 00065 uint8_t k; 00066 #endif 00067 00068 while(1) { 00069 osEvent evt = mail_usb_event.get(); 00070 00071 if (evt.status == osEventMail) { 00072 00073 message_t * usb_msg = (message_t*)evt.value.p; 00074 00075 switch (usb_msg->event_id) { 00076 00077 // a new device has been connected 00078 case DEVICE_CONNECTED_EVENT: 00079 too_many_hub = false; 00080 buf[4] = 0; 00081 00082 do 00083 { 00084 Lock lock(this); 00085 00086 for (i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00087 if (!deviceInUse[i]) { 00088 USB_DBG_EVENT("new device connected: %p\r\n", &devices[i]); 00089 devices[i].init(usb_msg->hub, usb_msg->port, usb_msg->lowSpeed); 00090 deviceReset[i] = false; 00091 deviceInited[i] = true; 00092 break; 00093 } 00094 } 00095 00096 if (i == MAX_DEVICE_CONNECTED) { 00097 USB_ERR("Too many device connected!!\r\n"); 00098 continue; 00099 } 00100 00101 if (!controlEndpointAllocated) { 00102 control = newEndpoint(CONTROL_ENDPOINT, OUT, 0x08, 0x00); 00103 addEndpoint(NULL, 0, (USBEndpoint*)control); 00104 controlEndpointAllocated = true; 00105 } 00106 00107 #if MAX_HUB_NB 00108 if (usb_msg->hub_parent) 00109 devices[i].setHubParent((USBHostHub *)(usb_msg->hub_parent)); 00110 #endif 00111 00112 for (j = 0; j < timeout_set_addr; j++) { 00113 00114 resetDevice(&devices[i]); 00115 00116 // set size of control endpoint 00117 devices[i].setSizeControlEndpoint(8); 00118 00119 devices[i].activeAddress(false); 00120 00121 // get first 8 bit of device descriptor 00122 // and check if we deal with a hub 00123 USB_DBG("usb_thread read device descriptor on dev: %p\r\n", &devices[i]); 00124 res = getDeviceDescriptor(&devices[i], buf, 8); 00125 00126 if (res != USB_TYPE_OK) { 00127 USB_ERR("usb_thread could not read dev descr"); 00128 continue; 00129 } 00130 00131 // set size of control endpoint 00132 devices[i].setSizeControlEndpoint(buf[7]); 00133 00134 // second step: set an address to the device 00135 res = setAddress(&devices[i], devices[i].getAddress()); 00136 00137 if (res != USB_TYPE_OK) { 00138 USB_ERR("SET ADDR FAILED"); 00139 continue; 00140 } 00141 devices[i].activeAddress(true); 00142 USB_DBG("Address of %p: %d", &devices[i], devices[i].getAddress()); 00143 00144 // try to read again the device descriptor to check if the device 00145 // answers to its new address 00146 res = getDeviceDescriptor(&devices[i], buf, 8); 00147 00148 if (res == USB_TYPE_OK) { 00149 break; 00150 } 00151 00152 Thread::wait(100); 00153 } 00154 00155 USB_INFO("New device connected: %p [hub: %d - port: %d]", &devices[i], usb_msg->hub, usb_msg->port); 00156 00157 #if MAX_HUB_NB 00158 if (buf[4] == HUB_CLASS) { 00159 for (k = 0; k < MAX_HUB_NB; k++) { 00160 if (hub_in_use[k] == false) { 00161 for (uint8_t j = 0; j < MAX_TRY_ENUMERATE_HUB; j++) { 00162 if (hubs[k].connect(&devices[i])) { 00163 devices[i].hub = &hubs[k]; 00164 hub_in_use[k] = true; 00165 break; 00166 } 00167 } 00168 if (hub_in_use[k] == true) 00169 break; 00170 } 00171 } 00172 00173 if (k == MAX_HUB_NB) { 00174 USB_ERR("Too many hubs connected!!\r\n"); 00175 too_many_hub = true; 00176 } 00177 } 00178 00179 if (usb_msg->hub_parent) 00180 ((USBHostHub *)(usb_msg->hub_parent))->deviceConnected(&devices[i]); 00181 #endif 00182 00183 if ((i < MAX_DEVICE_CONNECTED) && !too_many_hub) { 00184 deviceInUse[i] = true; 00185 } 00186 00187 } while(0); 00188 00189 break; 00190 00191 // a device has been disconnected 00192 case DEVICE_DISCONNECTED_EVENT: 00193 00194 do 00195 { 00196 Lock lock(this); 00197 00198 controlListState = disableList(CONTROL_ENDPOINT); 00199 bulkListState = disableList(BULK_ENDPOINT); 00200 interruptListState = disableList(INTERRUPT_ENDPOINT); 00201 00202 idx = findDevice(usb_msg->hub, usb_msg->port, (USBHostHub *)(usb_msg->hub_parent)); 00203 if (idx != -1) { 00204 freeDevice((USBDeviceConnected*)&devices[idx]); 00205 } 00206 00207 if (controlListState) enableList(CONTROL_ENDPOINT); 00208 if (bulkListState) enableList(BULK_ENDPOINT); 00209 if (interruptListState) enableList(INTERRUPT_ENDPOINT); 00210 00211 } while(0); 00212 00213 break; 00214 00215 // a td has been processed 00216 // call callback on the ed associated to the td 00217 // we are not in ISR -> users can use printf in their callback method 00218 case TD_PROCESSED_EVENT: 00219 ep = (USBEndpoint *) ((HCTD *)usb_msg->td_addr)->ep; 00220 if (usb_msg->td_state == USB_TYPE_IDLE) { 00221 USB_DBG_EVENT("call callback on td %p [ep: %p state: %s - dev: %p - %s]", usb_msg->td_addr, ep, ep->getStateString(), ep->dev, ep->dev->getName(ep->getIntfNb())); 00222 00223 #if DEBUG_TRANSFER 00224 if (ep->getDir() == IN) { 00225 buf_transfer = ep->getBufStart(); 00226 printf("READ SUCCESS [%d bytes transferred - td: 0x%08X] on ep: [%p - addr: %02X]: ", ep->getLengthTransferred(), usb_msg->td_addr, ep, ep->getAddress()); 00227 for (int i = 0; i < ep->getLengthTransferred(); i++) 00228 printf("%02X ", buf_transfer[i]); 00229 printf("\r\n\r\n"); 00230 } 00231 #endif 00232 ep->call(); 00233 } else { 00234 idx = findDevice(ep->dev); 00235 if (idx != -1) { 00236 if (deviceInUse[idx]) { 00237 USB_WARN("td %p processed but not in idle state: %s [ep: %p - dev: %p - %s]", usb_msg->td_addr, ep->getStateString(), ep, ep->dev, ep->dev->getName(ep->getIntfNb())); 00238 ep->setState(USB_TYPE_IDLE); 00239 } 00240 } 00241 } 00242 break; 00243 } 00244 00245 mail_usb_event.free(usb_msg); 00246 } 00247 } 00248 } 00249 00250 /* static */void USBHost::usb_process_static(void const * arg) { 00251 ((USBHost *)arg)->usb_process(); 00252 } 00253 00254 USBHost::USBHost() : usbThread(USBHost::usb_process_static, (void *)this, osPriorityNormal, USB_THREAD_STACK) 00255 { 00256 headControlEndpoint = NULL; 00257 headBulkEndpoint = NULL; 00258 headInterruptEndpoint = NULL; 00259 tailControlEndpoint = NULL; 00260 tailBulkEndpoint = NULL; 00261 tailInterruptEndpoint = NULL; 00262 00263 lenReportDescr = 0; 00264 00265 controlEndpointAllocated = false; 00266 00267 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00268 deviceInUse[i] = false; 00269 devices[i].setAddress(i + 1); 00270 deviceReset[i] = false; 00271 deviceInited[i] = false; 00272 for (uint8_t j = 0; j < MAX_INTF; j++) 00273 deviceAttachedDriver[i][j] = false; 00274 } 00275 00276 #if MAX_HUB_NB 00277 for (uint8_t i = 0; i < MAX_HUB_NB; i++) { 00278 hubs[i].setHost(this); 00279 hub_in_use[i] = false; 00280 } 00281 #endif 00282 } 00283 00284 USBHost::Lock::Lock(USBHost* pHost) : m_pHost(pHost) 00285 { 00286 m_pHost->usb_mutex.lock(); 00287 } 00288 00289 USBHost::Lock::~Lock() 00290 { 00291 m_pHost->usb_mutex.unlock(); 00292 } 00293 00294 void USBHost::transferCompleted(volatile uint32_t addr) 00295 { 00296 uint8_t state; 00297 00298 if(addr == 0) 00299 return; 00300 00301 volatile HCTD* tdList = NULL; 00302 00303 //First we must reverse the list order and dequeue each TD 00304 do { 00305 volatile HCTD* td = (volatile HCTD*)addr; 00306 addr = (uint32_t)td->nextTD; //Dequeue from physical list 00307 td->nextTD = (hcTd*)tdList; //Enqueue into reversed list 00308 tdList = td; 00309 } while(addr); 00310 00311 while(tdList != NULL) { 00312 volatile HCTD* td = tdList; 00313 tdList = (volatile HCTD*)td->nextTD; //Dequeue element now as it could be modified below 00314 if (td->ep != NULL) { 00315 USBEndpoint * ep = (USBEndpoint *)(td->ep); 00316 00317 if (((HCTD *)td)->control >> 28) { 00318 state = ((HCTD *)td)->control >> 28; 00319 } else { 00320 if (td->currBufPtr) 00321 ep->setLengthTransferred((uint32_t)td->currBufPtr - (uint32_t)ep->getBufStart()); 00322 state = 16 /*USB_TYPE_IDLE*/; 00323 } 00324 00325 ep->unqueueTransfer(td); 00326 00327 if (ep->getType() != CONTROL_ENDPOINT) { 00328 // callback on the processed td will be called from the usb_thread (not in ISR) 00329 message_t * usb_msg = mail_usb_event.alloc(); 00330 usb_msg->event_id = TD_PROCESSED_EVENT; 00331 usb_msg->td_addr = (void *)td; 00332 usb_msg->td_state = state; 00333 mail_usb_event.put(usb_msg); 00334 } 00335 ep->setState(state); 00336 ep->ep_queue.put((uint8_t*)1); 00337 } 00338 } 00339 } 00340 00341 USBHost * USBHost::getHostInst() 00342 { 00343 if (instHost == NULL) { 00344 instHost = new USBHost(); 00345 instHost->init(); 00346 } 00347 return instHost; 00348 } 00349 00350 00351 /* 00352 * Called when a device has been connected 00353 * Called in ISR!!!! (no printf) 00354 */ 00355 /* virtual */ void USBHost::deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent) 00356 { 00357 // be sure that the new device connected is not already connected... 00358 int idx = findDevice(hub, port, hub_parent); 00359 if (idx != -1) { 00360 if (deviceInited[idx]) 00361 return; 00362 } 00363 00364 message_t * usb_msg = mail_usb_event.alloc(); 00365 usb_msg->event_id = DEVICE_CONNECTED_EVENT; 00366 usb_msg->hub = hub; 00367 usb_msg->port = port; 00368 usb_msg->lowSpeed = lowSpeed; 00369 usb_msg->hub_parent = hub_parent; 00370 mail_usb_event.put(usb_msg); 00371 } 00372 00373 /* 00374 * Called when a device has been disconnected 00375 * Called in ISR!!!! (no printf) 00376 */ 00377 /* virtual */ void USBHost::deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr) 00378 { 00379 // be sure that the device disconnected is connected... 00380 int idx = findDevice(hub, port, hub_parent); 00381 if (idx != -1) { 00382 if (!deviceInUse[idx]) 00383 return; 00384 } else { 00385 return; 00386 } 00387 00388 message_t * usb_msg = mail_usb_event.alloc(); 00389 usb_msg->event_id = DEVICE_DISCONNECTED_EVENT; 00390 usb_msg->hub = hub; 00391 usb_msg->port = port; 00392 usb_msg->hub_parent = hub_parent; 00393 mail_usb_event.put(usb_msg); 00394 } 00395 00396 void USBHost::freeDevice(USBDeviceConnected * dev) 00397 { 00398 USBEndpoint * ep = NULL; 00399 HCED * ed = NULL; 00400 00401 #if MAX_HUB_NB 00402 if (dev->getClass() == HUB_CLASS) { 00403 if (dev->hub == NULL) { 00404 USB_ERR("HUB NULL!!!!!\r\n"); 00405 } else { 00406 dev->hub->hubDisconnected(); 00407 for (uint8_t i = 0; i < MAX_HUB_NB; i++) { 00408 if (dev->hub == &hubs[i]) { 00409 hub_in_use[i] = false; 00410 break; 00411 } 00412 } 00413 } 00414 } 00415 00416 // notify hub parent that this device has been disconnected 00417 if (dev->getHubParent()) 00418 dev->getHubParent()->deviceDisconnected(dev); 00419 00420 #endif 00421 00422 int idx = findDevice(dev); 00423 if (idx != -1) { 00424 deviceInUse[idx] = false; 00425 deviceReset[idx] = false; 00426 00427 for (uint8_t j = 0; j < MAX_INTF; j++) { 00428 deviceAttachedDriver[idx][j] = false; 00429 if (dev->getInterface(j) != NULL) { 00430 USB_DBG("FREE INTF %d on dev: %p, %p, nb_endpot: %d, %s", j, (void *)dev->getInterface(j), dev, dev->getInterface(j)->nb_endpoint, dev->getName(j)); 00431 for (int i = 0; i < dev->getInterface(j)->nb_endpoint; i++) { 00432 if ((ep = dev->getEndpoint(j, i)) != NULL) { 00433 ed = (HCED *)ep->getHCED(); 00434 ed->control |= (1 << 14); //sKip bit 00435 unqueueEndpoint(ep); 00436 00437 freeTD((volatile uint8_t*)ep->getTDList()[0]); 00438 freeTD((volatile uint8_t*)ep->getTDList()[1]); 00439 00440 freeED((uint8_t *)ep->getHCED()); 00441 } 00442 printList(BULK_ENDPOINT); 00443 printList(INTERRUPT_ENDPOINT); 00444 } 00445 USB_INFO("Device disconnected [%p - %s - hub: %d - port: %d]", dev, dev->getName(j), dev->getHub(), dev->getPort()); 00446 } 00447 } 00448 dev->disconnect(); 00449 } 00450 } 00451 00452 00453 void USBHost::unqueueEndpoint(USBEndpoint * ep) 00454 { 00455 USBEndpoint * prec = NULL; 00456 USBEndpoint * current = NULL; 00457 00458 for (int i = 0; i < 2; i++) { 00459 current = (i == 0) ? (USBEndpoint*)headBulkEndpoint : (USBEndpoint*)headInterruptEndpoint; 00460 prec = current; 00461 while (current != NULL) { 00462 if (current == ep) { 00463 if (current->nextEndpoint() != NULL) { 00464 prec->queueEndpoint(current->nextEndpoint()); 00465 if (current == headBulkEndpoint) { 00466 updateBulkHeadED((uint32_t)current->nextEndpoint()->getHCED()); 00467 headBulkEndpoint = current->nextEndpoint(); 00468 } else if (current == headInterruptEndpoint) { 00469 updateInterruptHeadED((uint32_t)current->nextEndpoint()->getHCED()); 00470 headInterruptEndpoint = current->nextEndpoint(); 00471 } 00472 } 00473 // here we are dequeuing the queue of ed 00474 // we need to update the tail pointer 00475 else { 00476 prec->queueEndpoint(NULL); 00477 if (current == headBulkEndpoint) { 00478 updateBulkHeadED(0); 00479 headBulkEndpoint = current->nextEndpoint(); 00480 } else if (current == headInterruptEndpoint) { 00481 updateInterruptHeadED(0); 00482 headInterruptEndpoint = current->nextEndpoint(); 00483 } 00484 00485 // modify tail 00486 switch (current->getType()) { 00487 case BULK_ENDPOINT: 00488 tailBulkEndpoint = prec; 00489 break; 00490 case INTERRUPT_ENDPOINT: 00491 tailInterruptEndpoint = prec; 00492 break; 00493 default: 00494 break; 00495 } 00496 } 00497 current->setState(USB_TYPE_FREE); 00498 return; 00499 } 00500 prec = current; 00501 current = current->nextEndpoint(); 00502 } 00503 } 00504 } 00505 00506 00507 USBDeviceConnected * USBHost::getDevice(uint8_t index) 00508 { 00509 if ((index >= MAX_DEVICE_CONNECTED) || (!deviceInUse[index])) { 00510 return NULL; 00511 } 00512 return (USBDeviceConnected*)&devices[index]; 00513 } 00514 00515 // create an USBEndpoint descriptor. the USBEndpoint is not linked 00516 USBEndpoint * USBHost::newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr) 00517 { 00518 int i = 0; 00519 HCED * ed = (HCED *)getED(); 00520 HCTD* td_list[2] = { (HCTD*)getTD(), (HCTD*)getTD() }; 00521 00522 memset((void *)td_list[0], 0x00, sizeof(HCTD)); 00523 memset((void *)td_list[1], 0x00, sizeof(HCTD)); 00524 00525 // search a free USBEndpoint 00526 for (i = 0; i < MAX_ENDPOINT; i++) { 00527 if (endpoints[i].getState() == USB_TYPE_FREE) { 00528 endpoints[i].init(ed, type, dir, size, addr, td_list); 00529 USB_DBG("USBEndpoint created (%p): type: %d, dir: %d, size: %d, addr: %d, state: %s", &endpoints[i], type, dir, size, addr, endpoints[i].getStateString()); 00530 return &endpoints[i]; 00531 } 00532 } 00533 USB_ERR("could not allocate more endpoints!!!!"); 00534 return NULL; 00535 } 00536 00537 00538 USB_TYPE USBHost::resetDevice(USBDeviceConnected * dev) 00539 { 00540 int index = findDevice(dev); 00541 if (index != -1) { 00542 USB_DBG("Resetting hub %d, port %d\n", dev->getHub(), dev->getPort()); 00543 Thread::wait(100); 00544 if (dev->getHub() == 0) { 00545 resetRootHub(); 00546 } 00547 #if MAX_HUB_NB 00548 else { 00549 dev->getHubParent()->portReset(dev->getPort()); 00550 } 00551 #endif 00552 Thread::wait(100); 00553 deviceReset[index] = true; 00554 return USB_TYPE_OK; 00555 } 00556 00557 return USB_TYPE_ERROR; 00558 } 00559 00560 // link the USBEndpoint to the linked list and attach an USBEndpoint to a device 00561 bool USBHost::addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep) 00562 { 00563 00564 if (ep == NULL) { 00565 return false; 00566 } 00567 00568 HCED * prevEd; 00569 00570 // set device address in the USBEndpoint descriptor 00571 if (dev == NULL) { 00572 ep->setDeviceAddress(0); 00573 } else { 00574 ep->setDeviceAddress(dev->getAddress()); 00575 } 00576 00577 if ((dev != NULL) && dev->getSpeed()) { 00578 ep->setSpeed(dev->getSpeed()); 00579 } 00580 00581 ep->setIntfNb(intf_nb); 00582 00583 // queue the new USBEndpoint on the ED list 00584 switch (ep->getType()) { 00585 00586 case CONTROL_ENDPOINT: 00587 prevEd = ( HCED*) controlHeadED(); 00588 if (!prevEd) { 00589 updateControlHeadED((uint32_t) ep->getHCED()); 00590 USB_DBG_TRANSFER("First control USBEndpoint: %08X", (uint32_t) ep->getHCED()); 00591 headControlEndpoint = ep; 00592 tailControlEndpoint = ep; 00593 return true; 00594 } 00595 tailControlEndpoint->queueEndpoint(ep); 00596 tailControlEndpoint = ep; 00597 return true; 00598 00599 case BULK_ENDPOINT: 00600 prevEd = ( HCED*) bulkHeadED(); 00601 if (!prevEd) { 00602 updateBulkHeadED((uint32_t) ep->getHCED()); 00603 USB_DBG_TRANSFER("First bulk USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED()); 00604 headBulkEndpoint = ep; 00605 tailBulkEndpoint = ep; 00606 break; 00607 } 00608 USB_DBG_TRANSFER("Queue BULK Ed %p after %p\r\n",ep->getHCED(), prevEd); 00609 tailBulkEndpoint->queueEndpoint(ep); 00610 tailBulkEndpoint = ep; 00611 break; 00612 00613 case INTERRUPT_ENDPOINT: 00614 prevEd = ( HCED*) interruptHeadED(); 00615 if (!prevEd) { 00616 updateInterruptHeadED((uint32_t) ep->getHCED()); 00617 USB_DBG_TRANSFER("First interrupt USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED()); 00618 headInterruptEndpoint = ep; 00619 tailInterruptEndpoint = ep; 00620 break; 00621 } 00622 USB_DBG_TRANSFER("Queue INTERRUPT Ed %p after %p\r\n",ep->getHCED(), prevEd); 00623 tailInterruptEndpoint->queueEndpoint(ep); 00624 tailInterruptEndpoint = ep; 00625 break; 00626 default: 00627 return false; 00628 } 00629 00630 ep->dev = dev; 00631 dev->addEndpoint(intf_nb, ep); 00632 00633 return true; 00634 } 00635 00636 00637 int USBHost::findDevice(USBDeviceConnected * dev) 00638 { 00639 for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00640 if (dev == &devices[i]) { 00641 return i; 00642 } 00643 } 00644 return -1; 00645 } 00646 00647 int USBHost::findDevice(uint8_t hub, uint8_t port, USBHostHub * hub_parent) 00648 { 00649 for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00650 if (devices[i].getHub() == hub && devices[i].getPort() == port) { 00651 if (hub_parent != NULL) { 00652 if (hub_parent == devices[i].getHubParent()) 00653 return i; 00654 } else { 00655 return i; 00656 } 00657 } 00658 } 00659 return -1; 00660 } 00661 00662 void USBHost::printList(ENDPOINT_TYPE type) 00663 { 00664 #if DEBUG_EP_STATE 00665 volatile HCED * hced; 00666 switch(type) { 00667 case CONTROL_ENDPOINT: 00668 hced = (HCED *)controlHeadED(); 00669 break; 00670 case BULK_ENDPOINT: 00671 hced = (HCED *)bulkHeadED(); 00672 break; 00673 case INTERRUPT_ENDPOINT: 00674 hced = (HCED *)interruptHeadED(); 00675 break; 00676 } 00677 volatile HCTD * hctd = NULL; 00678 const char * type_str = (type == BULK_ENDPOINT) ? "BULK" : 00679 ((type == INTERRUPT_ENDPOINT) ? "INTERRUPT" : 00680 ((type == CONTROL_ENDPOINT) ? "CONTROL" : "ISOCHRONOUS")); 00681 printf("State of %s:\r\n", type_str); 00682 while (hced != NULL) { 00683 uint8_t dir = ((hced->control & (3 << 11)) >> 11); 00684 printf("hced: %p [ADDR: %d, DIR: %s, EP_NB: 0x%X]\r\n", hced, 00685 hced->control & 0x7f, 00686 (dir == 1) ? "OUT" : ((dir == 0) ? "FROM_TD":"IN"), 00687 (hced->control & (0xf << 7)) >> 7); 00688 hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0xf)); 00689 while (hctd != hced->tailTD) { 00690 printf("\thctd: %p [DIR: %s]\r\n", hctd, ((hctd->control & (3 << 19)) >> 19) == 1 ? "OUT" : "IN"); 00691 hctd = hctd->nextTD; 00692 } 00693 printf("\thctd: %p\r\n", hctd); 00694 hced = hced->nextED; 00695 } 00696 printf("\r\n\r\n"); 00697 #endif 00698 } 00699 00700 00701 // add a transfer on the TD linked list 00702 USB_TYPE USBHost::addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len) 00703 { 00704 td_mutex.lock(); 00705 00706 // allocate a TD which will be freed in TDcompletion 00707 volatile HCTD * td = ed->getNextTD(); 00708 if (td == NULL) { 00709 return USB_TYPE_ERROR; 00710 } 00711 00712 uint32_t token = (ed->isSetup() ? TD_SETUP : ( (ed->getDir() == IN) ? TD_IN : TD_OUT )); 00713 00714 uint32_t td_toggle; 00715 00716 if (ed->getType() == CONTROL_ENDPOINT) { 00717 if (ed->isSetup()) { 00718 td_toggle = TD_TOGGLE_0; 00719 } else { 00720 td_toggle = TD_TOGGLE_1; 00721 } 00722 } else { 00723 td_toggle = 0; 00724 } 00725 00726 td->control = (TD_ROUNDING | token | TD_DELAY_INT(0) | td_toggle | TD_CC); 00727 td->currBufPtr = buf; 00728 td->bufEnd = (buf + (len - 1)); 00729 00730 ENDPOINT_TYPE type = ed->getType(); 00731 00732 disableList(type); 00733 ed->queueTransfer(); 00734 printList(type); 00735 enableList(type); 00736 00737 td_mutex.unlock(); 00738 00739 return USB_TYPE_PROCESSING; 00740 } 00741 00742 00743 00744 USB_TYPE USBHost::getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_dev_descr) 00745 { 00746 USB_TYPE t = controlRead( dev, 00747 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, 00748 GET_DESCRIPTOR, 00749 (DEVICE_DESCRIPTOR << 8) | (0), 00750 0, buf, MIN(DEVICE_DESCRIPTOR_LENGTH, max_len_buf)); 00751 if (len_dev_descr) 00752 *len_dev_descr = MIN(DEVICE_DESCRIPTOR_LENGTH, max_len_buf); 00753 00754 return t; 00755 } 00756 00757 USB_TYPE USBHost::getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_conf_descr) 00758 { 00759 USB_TYPE res; 00760 uint16_t total_conf_descr_length = 0; 00761 00762 // fourth step: get the beginning of the configuration descriptor to have the total length of the conf descr 00763 res = controlRead( dev, 00764 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, 00765 GET_DESCRIPTOR, 00766 (CONFIGURATION_DESCRIPTOR << 8) | (0), 00767 0, buf, CONFIGURATION_DESCRIPTOR_LENGTH); 00768 00769 if (res != USB_TYPE_OK) { 00770 USB_ERR("GET CONF 1 DESCR FAILED"); 00771 return res; 00772 } 00773 total_conf_descr_length = buf[2] | (buf[3] << 8); 00774 total_conf_descr_length = MIN(max_len_buf, total_conf_descr_length); 00775 00776 if (len_conf_descr) 00777 *len_conf_descr = total_conf_descr_length; 00778 00779 USB_DBG("TOTAL_LENGTH: %d \t NUM_INTERF: %d", total_conf_descr_length, buf[4]); 00780 00781 return controlRead( dev, 00782 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, 00783 GET_DESCRIPTOR, 00784 (CONFIGURATION_DESCRIPTOR << 8) | (0), 00785 0, buf, total_conf_descr_length); 00786 } 00787 00788 00789 USB_TYPE USBHost::setAddress(USBDeviceConnected * dev, uint8_t address) { 00790 return controlWrite( dev, 00791 USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE, 00792 SET_ADDRESS, 00793 address, 00794 0, NULL, 0); 00795 00796 } 00797 00798 USB_TYPE USBHost::setConfiguration(USBDeviceConnected * dev, uint8_t conf) 00799 { 00800 return controlWrite( dev, 00801 USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE, 00802 SET_CONFIGURATION, 00803 conf, 00804 0, NULL, 0); 00805 } 00806 00807 uint8_t USBHost::numberDriverAttached(USBDeviceConnected * dev) { 00808 int index = findDevice(dev); 00809 uint8_t cnt = 0; 00810 if (index == -1) 00811 return 0; 00812 for (uint8_t i = 0; i < MAX_INTF; i++) { 00813 if (deviceAttachedDriver[index][i]) 00814 cnt++; 00815 } 00816 return cnt; 00817 } 00818 00819 // enumerate a device with the control USBEndpoint 00820 USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator) 00821 { 00822 uint16_t total_conf_descr_length = 0; 00823 USB_TYPE res; 00824 00825 do 00826 { 00827 Lock lock(this); 00828 00829 // don't enumerate a device which all interfaces are registered to a specific driver 00830 int index = findDevice(dev); 00831 00832 if (index == -1) { 00833 return USB_TYPE_ERROR; 00834 } 00835 00836 uint8_t nb_intf_attached = numberDriverAttached(dev); 00837 USB_DBG("dev: %p nb_intf: %d", dev, dev->getNbIntf()); 00838 USB_DBG("dev: %p nb_intf_attached: %d", dev, nb_intf_attached); 00839 if ((nb_intf_attached != 0) && (dev->getNbIntf() == nb_intf_attached)) { 00840 USB_DBG("Don't enumerate dev: %p because all intf are registered with a driver", dev); 00841 return USB_TYPE_OK; 00842 } 00843 00844 USB_DBG("Enumerate dev: %p", dev); 00845 00846 // third step: get the whole device descriptor to see vid, pid 00847 res = getDeviceDescriptor(dev, data, DEVICE_DESCRIPTOR_LENGTH); 00848 00849 if (res != USB_TYPE_OK) { 00850 USB_DBG("GET DEV DESCR FAILED"); 00851 return res; 00852 } 00853 00854 dev->setClass(data[4]); 00855 dev->setSubClass(data[5]); 00856 dev->setProtocol(data[6]); 00857 dev->setVid(data[8] | (data[9] << 8)); 00858 dev->setPid(data[10] | (data[11] << 8)); 00859 USB_DBG("CLASS: %02X \t VID: %04X \t PID: %04X", data[4], data[8] | (data[9] << 8), data[10] | (data[11] << 8)); 00860 00861 pEnumerator->setVidPid( data[8] | (data[9] << 8), data[10] | (data[11] << 8) ); 00862 00863 res = getConfigurationDescriptor(dev, data, sizeof(data), &total_conf_descr_length); 00864 if (res != USB_TYPE_OK) { 00865 return res; 00866 } 00867 00868 #if (DEBUG > 3) 00869 USB_DBG("CONFIGURATION DESCRIPTOR:\r\n"); 00870 for (int i = 0; i < total_conf_descr_length; i++) 00871 printf("%02X ", data[i]); 00872 printf("\r\n\r\n"); 00873 #endif 00874 00875 // Parse the configuration descriptor 00876 parseConfDescr(dev, data, total_conf_descr_length, pEnumerator); 00877 00878 // only set configuration if not enumerated before 00879 if (!dev->isEnumerated()) { 00880 00881 USB_DBG("Set configuration 1 on dev: %p", dev); 00882 // sixth step: set configuration (only 1 supported) 00883 res = setConfiguration(dev, 1); 00884 00885 if (res != USB_TYPE_OK) { 00886 USB_DBG("SET CONF FAILED"); 00887 return res; 00888 } 00889 } 00890 00891 dev->setEnumerated(); 00892 00893 // Now the device is enumerated! 00894 USB_DBG("dev %p is enumerated\r\n", dev); 00895 00896 } while(0); 00897 00898 // Some devices may require this delay 00899 Thread::wait(100); 00900 00901 return USB_TYPE_OK; 00902 } 00903 // this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor. 00904 void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) 00905 { 00906 uint32_t index = 0; 00907 uint32_t len_desc = 0; 00908 uint8_t id = 0; 00909 int nb_endpoints_used = 0; 00910 USBEndpoint * ep = NULL; 00911 uint8_t intf_nb = 0; 00912 bool parsing_intf = false; 00913 uint8_t current_intf = 0; 00914 00915 while (index < len) { 00916 len_desc = conf_descr[index]; 00917 id = conf_descr[index+1]; 00918 switch (id) { 00919 case CONFIGURATION_DESCRIPTOR: 00920 USB_DBG("dev: %p has %d intf", dev, conf_descr[4]); 00921 dev->setNbIntf(conf_descr[4]); 00922 break; 00923 case INTERFACE_DESCRIPTOR: 00924 if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) { 00925 if (intf_nb++ <= MAX_INTF) { 00926 current_intf = conf_descr[index + 2]; 00927 dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]); 00928 nb_endpoints_used = 0; 00929 USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]); 00930 } else { 00931 USB_DBG("Drop intf..."); 00932 } 00933 parsing_intf = true; 00934 } else { 00935 parsing_intf = false; 00936 } 00937 break; 00938 case ENDPOINT_DESCRIPTOR: 00939 if (parsing_intf && (intf_nb <= MAX_INTF) ) { 00940 if (nb_endpoints_used < MAX_ENDPOINT_PER_INTERFACE) { 00941 if( pEnumerator->useEndpoint(current_intf, (ENDPOINT_TYPE)(conf_descr[index + 3] & 0x03), (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1)) ) { 00942 // if the USBEndpoint is isochronous -> skip it (TODO: fix this) 00943 if ((conf_descr[index + 3] & 0x03) != ISOCHRONOUS_ENDPOINT) { 00944 ep = newEndpoint((ENDPOINT_TYPE)(conf_descr[index+3] & 0x03), 00945 (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1), 00946 conf_descr[index + 4] | (conf_descr[index + 5] << 8), 00947 conf_descr[index + 2] & 0x0f); 00948 USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev); 00949 if (ep != NULL && dev != NULL) { 00950 addEndpoint(dev, current_intf, ep); 00951 } else { 00952 USB_DBG("EP NULL"); 00953 } 00954 nb_endpoints_used++; 00955 } else { 00956 USB_DBG("ISO USBEndpoint NOT SUPPORTED"); 00957 } 00958 } 00959 } 00960 } 00961 break; 00962 case HID_DESCRIPTOR: 00963 lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8); 00964 break; 00965 default: 00966 break; 00967 } 00968 index += len_desc; 00969 } 00970 } 00971 00972 00973 USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) 00974 { 00975 return generalTransfer(dev, ep, buf, len, blocking, BULK_ENDPOINT, true); 00976 } 00977 00978 USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) 00979 { 00980 return generalTransfer(dev, ep, buf, len, blocking, BULK_ENDPOINT, false); 00981 } 00982 00983 USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) 00984 { 00985 return generalTransfer(dev, ep, buf, len, blocking, INTERRUPT_ENDPOINT, true); 00986 } 00987 00988 USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) 00989 { 00990 return generalTransfer(dev, ep, buf, len, blocking, INTERRUPT_ENDPOINT, false); 00991 } 00992 00993 USB_TYPE USBHost::generalTransfer(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking, ENDPOINT_TYPE type, bool write) { 00994 00995 #if DEBUG_TRANSFER 00996 const char * type_str = (type == BULK_ENDPOINT) ? "BULK" : ((type == INTERRUPT_ENDPOINT) ? "INTERRUPT" : "ISOCHRONOUS"); 00997 USB_DBG_TRANSFER("----- %s %s [dev: %p - %s - hub: %d - port: %d - addr: %d - ep: %02X]------", type_str, (write) ? "WRITE" : "READ", dev, dev->getName(ep->getIntfNb()), dev->getHub(), dev->getPort(), dev->getAddress(), ep->getAddress()); 00998 #endif 00999 01000 Lock lock(this); 01001 01002 USB_TYPE res; 01003 ENDPOINT_DIRECTION dir = (write) ? OUT : IN; 01004 01005 if (dev == NULL) { 01006 USB_ERR("dev NULL"); 01007 return USB_TYPE_ERROR; 01008 } 01009 01010 if (ep == NULL) { 01011 USB_ERR("ep NULL"); 01012 return USB_TYPE_ERROR; 01013 } 01014 01015 if (ep->getState() != USB_TYPE_IDLE) { 01016 USB_WARN("[ep: %p - dev: %p - %s] NOT IDLE: %s", ep, ep->dev, ep->dev->getName(ep->getIntfNb()), ep->getStateString()); 01017 return ep->getState(); 01018 } 01019 01020 if ((ep->getDir() != dir) || (ep->getType() != type)) { 01021 USB_ERR("[ep: %p - dev: %p] wrong dir or bad USBEndpoint type", ep, ep->dev); 01022 return USB_TYPE_ERROR; 01023 } 01024 01025 if (dev->getAddress() != ep->getDeviceAddress()) { 01026 USB_ERR("[ep: %p - dev: %p] USBEndpoint addr and device addr don't match", ep, ep->dev); 01027 return USB_TYPE_ERROR; 01028 } 01029 01030 #if DEBUG_TRANSFER 01031 if (write) { 01032 USB_DBG_TRANSFER("%s WRITE buffer", type_str); 01033 for (int i = 0; i < ep->getLengthTransferred(); i++) 01034 printf("%02X ", buf[i]); 01035 printf("\r\n\r\n"); 01036 } 01037 #endif 01038 addTransfer(ep, buf, len); 01039 01040 if (blocking) { 01041 01042 ep->ep_queue.get(); 01043 res = ep->getState(); 01044 01045 USB_DBG_TRANSFER("%s TRANSFER res: %s on ep: %p\r\n", type_str, ep->getStateString(), ep); 01046 01047 if (res != USB_TYPE_IDLE) { 01048 return res; 01049 } 01050 01051 return USB_TYPE_OK; 01052 } 01053 01054 return USB_TYPE_PROCESSING; 01055 01056 } 01057 01058 01059 USB_TYPE USBHost::controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { 01060 return controlTransfer(dev, requestType, request, value, index, buf, len, false); 01061 } 01062 01063 USB_TYPE USBHost::controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { 01064 return controlTransfer(dev, requestType, request, value, index, buf, len, true); 01065 } 01066 01067 USB_TYPE USBHost::controlTransfer(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len, bool write) 01068 { 01069 Lock lock(this); 01070 USB_DBG_TRANSFER("----- CONTROL %s [dev: %p - hub: %d - port: %d] ------", (write) ? "WRITE" : "READ", dev, dev->getHub(), dev->getPort()); 01071 01072 int length_transfer = len; 01073 USB_TYPE res; 01074 uint32_t token; 01075 01076 control->setSpeed(dev->getSpeed()); 01077 control->setSize(dev->getSizeControlEndpoint()); 01078 if (dev->isActiveAddress()) { 01079 control->setDeviceAddress(dev->getAddress()); 01080 } else { 01081 control->setDeviceAddress(0); 01082 } 01083 01084 USB_DBG_TRANSFER("Control transfer on device: %d\r\n", control->getDeviceAddress()); 01085 fillControlBuf(requestType, request, value, index, len); 01086 01087 #if DEBUG_TRANSFER 01088 USB_DBG_TRANSFER("SETUP PACKET: "); 01089 for (int i = 0; i < 8; i++) 01090 printf("%01X ", setupPacket[i]); 01091 printf("\r\n"); 01092 #endif 01093 01094 control->setNextToken(TD_SETUP); 01095 addTransfer(control, (uint8_t*)setupPacket, 8); 01096 01097 control->ep_queue.get(); 01098 res = control->getState(); 01099 01100 USB_DBG_TRANSFER("CONTROL setup stage %s", control->getStateString()); 01101 01102 if (res != USB_TYPE_IDLE) { 01103 return res; 01104 } 01105 01106 if (length_transfer) { 01107 token = (write) ? TD_OUT : TD_IN; 01108 control->setNextToken(token); 01109 addTransfer(control, (uint8_t *)buf, length_transfer); 01110 01111 control->ep_queue.get(); 01112 res = control->getState(); 01113 01114 #if DEBUG_TRANSFER 01115 USB_DBG_TRANSFER("CONTROL %s stage %s", (write) ? "WRITE" : "READ", control->getStateString()); 01116 if (write) { 01117 USB_DBG_TRANSFER("CONTROL WRITE buffer"); 01118 for (int i = 0; i < control->getLengthTransferred(); i++) 01119 printf("%02X ", buf[i]); 01120 printf("\r\n\r\n"); 01121 } else { 01122 USB_DBG_TRANSFER("CONTROL READ SUCCESS [%d bytes transferred]", control->getLengthTransferred()); 01123 for (int i = 0; i < control->getLengthTransferred(); i++) 01124 printf("%02X ", buf[i]); 01125 printf("\r\n\r\n"); 01126 } 01127 #endif 01128 01129 if (res != USB_TYPE_IDLE) { 01130 return res; 01131 } 01132 } 01133 01134 token = (write) ? TD_IN : TD_OUT; 01135 control->setNextToken(token); 01136 addTransfer(control, NULL, 0); 01137 01138 control->ep_queue.get(); 01139 res = control->getState(); 01140 01141 USB_DBG_TRANSFER("CONTROL ack stage %s", control->getStateString()); 01142 01143 if (res != USB_TYPE_IDLE) 01144 return res; 01145 01146 return USB_TYPE_OK; 01147 } 01148 01149 01150 void USBHost::fillControlBuf(uint8_t requestType, uint8_t request, uint16_t value, uint16_t index, int len) 01151 { 01152 setupPacket[0] = requestType; 01153 setupPacket[1] = request; 01154 setupPacket[2] = (uint8_t) value; 01155 setupPacket[3] = (uint8_t) (value >> 8); 01156 setupPacket[4] = (uint8_t) index; 01157 setupPacket[5] = (uint8_t) (index >> 8); 01158 setupPacket[6] = (uint8_t) len; 01159 setupPacket[7] = (uint8_t) (len >> 8); 01160 }
Generated on Tue Jul 12 2022 14:47:47 by
1.7.2
