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.
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 USBHost::USBHost() : usbThread(osPriorityNormal, USB_THREAD_STACK) 00251 { 00252 headControlEndpoint = NULL; 00253 headBulkEndpoint = NULL; 00254 headInterruptEndpoint = NULL; 00255 tailControlEndpoint = NULL; 00256 tailBulkEndpoint = NULL; 00257 tailInterruptEndpoint = NULL; 00258 00259 lenReportDescr = 0; 00260 00261 controlEndpointAllocated = false; 00262 00263 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00264 deviceInUse[i] = false; 00265 devices[i].setAddress(i + 1); 00266 deviceReset[i] = false; 00267 deviceInited[i] = false; 00268 for (uint8_t j = 0; j < MAX_INTF; j++) 00269 deviceAttachedDriver[i][j] = false; 00270 } 00271 00272 #if MAX_HUB_NB 00273 for (uint8_t i = 0; i < MAX_HUB_NB; i++) { 00274 hubs[i].setHost(this); 00275 hub_in_use[i] = false; 00276 } 00277 #endif 00278 00279 usbThread.start(this, &USBHost::usb_process); 00280 } 00281 00282 USBHost::Lock::Lock(USBHost* pHost) : m_pHost(pHost) 00283 { 00284 m_pHost->usb_mutex.lock(); 00285 } 00286 00287 USBHost::Lock::~Lock() 00288 { 00289 m_pHost->usb_mutex.unlock(); 00290 } 00291 00292 void USBHost::transferCompleted(volatile uint32_t addr) 00293 { 00294 uint8_t state; 00295 00296 if(addr == 0) 00297 return; 00298 00299 volatile HCTD* tdList = NULL; 00300 00301 //First we must reverse the list order and dequeue each TD 00302 do { 00303 volatile HCTD* td = (volatile HCTD*)addr; 00304 addr = (uint32_t)td->nextTD; //Dequeue from physical list 00305 td->nextTD = (hcTd*)tdList; //Enqueue into reversed list 00306 tdList = td; 00307 } while(addr); 00308 00309 while(tdList != NULL) { 00310 volatile HCTD* td = tdList; 00311 tdList = (volatile HCTD*)td->nextTD; //Dequeue element now as it could be modified below 00312 if (td->ep != NULL) { 00313 USBEndpoint * ep = (USBEndpoint *)(td->ep); 00314 00315 if (((HCTD *)td)->control >> 28) { 00316 state = ((HCTD *)td)->control >> 28; 00317 } else { 00318 if (td->currBufPtr) 00319 ep->setLengthTransferred((uint32_t)td->currBufPtr - (uint32_t)ep->getBufStart()); 00320 state = 16 /*USB_TYPE_IDLE*/; 00321 } 00322 00323 ep->unqueueTransfer(td); 00324 00325 if (ep->getType() != CONTROL_ENDPOINT) { 00326 // callback on the processed td will be called from the usb_thread (not in ISR) 00327 message_t * usb_msg = mail_usb_event.alloc(); 00328 usb_msg->event_id = TD_PROCESSED_EVENT; 00329 usb_msg->td_addr = (void *)td; 00330 usb_msg->td_state = state; 00331 mail_usb_event.put(usb_msg); 00332 } 00333 ep->setState(state); 00334 ep->ep_queue.put((uint8_t*)1); 00335 } 00336 } 00337 } 00338 00339 USBHost * USBHost::getHostInst() 00340 { 00341 if (instHost == NULL) { 00342 instHost = new USBHost(); 00343 instHost->init(); 00344 } 00345 return instHost; 00346 } 00347 00348 00349 /* 00350 * Called when a device has been connected 00351 * Called in ISR!!!! (no printf) 00352 */ 00353 /* virtual */ void USBHost::deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent) 00354 { 00355 // be sure that the new device connected is not already connected... 00356 int idx = findDevice(hub, port, hub_parent); 00357 if (idx != -1) { 00358 if (deviceInited[idx]) 00359 return; 00360 } 00361 00362 message_t * usb_msg = mail_usb_event.alloc(); 00363 usb_msg->event_id = DEVICE_CONNECTED_EVENT; 00364 usb_msg->hub = hub; 00365 usb_msg->port = port; 00366 usb_msg->lowSpeed = lowSpeed; 00367 usb_msg->hub_parent = hub_parent; 00368 mail_usb_event.put(usb_msg); 00369 } 00370 00371 /* 00372 * Called when a device has been disconnected 00373 * Called in ISR!!!! (no printf) 00374 */ 00375 /* virtual */ void USBHost::deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr) 00376 { 00377 // be sure that the device disconnected is connected... 00378 int idx = findDevice(hub, port, hub_parent); 00379 if (idx != -1) { 00380 if (!deviceInUse[idx]) 00381 return; 00382 } else { 00383 return; 00384 } 00385 00386 message_t * usb_msg = mail_usb_event.alloc(); 00387 usb_msg->event_id = DEVICE_DISCONNECTED_EVENT; 00388 usb_msg->hub = hub; 00389 usb_msg->port = port; 00390 usb_msg->hub_parent = hub_parent; 00391 mail_usb_event.put(usb_msg); 00392 } 00393 00394 void USBHost::freeDevice(USBDeviceConnected * dev) 00395 { 00396 USBEndpoint * ep = NULL; 00397 HCED * ed = NULL; 00398 00399 #if MAX_HUB_NB 00400 if (dev->getClass() == HUB_CLASS) { 00401 if (dev->hub == NULL) { 00402 USB_ERR("HUB NULL!!!!!\r\n"); 00403 } else { 00404 dev->hub->hubDisconnected(); 00405 for (uint8_t i = 0; i < MAX_HUB_NB; i++) { 00406 if (dev->hub == &hubs[i]) { 00407 hub_in_use[i] = false; 00408 break; 00409 } 00410 } 00411 } 00412 } 00413 00414 // notify hub parent that this device has been disconnected 00415 if (dev->getHubParent()) 00416 dev->getHubParent()->deviceDisconnected(dev); 00417 00418 #endif 00419 00420 int idx = findDevice(dev); 00421 if (idx != -1) { 00422 deviceInUse[idx] = false; 00423 deviceReset[idx] = false; 00424 00425 for (uint8_t j = 0; j < MAX_INTF; j++) { 00426 deviceAttachedDriver[idx][j] = false; 00427 if (dev->getInterface(j) != NULL) { 00428 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)); 00429 for (int i = 0; i < dev->getInterface(j)->nb_endpoint; i++) { 00430 if ((ep = dev->getEndpoint(j, i)) != NULL) { 00431 ed = (HCED *)ep->getHCED(); 00432 ed->control |= (1 << 14); //sKip bit 00433 unqueueEndpoint(ep); 00434 00435 freeTD((volatile uint8_t*)ep->getTDList()[0]); 00436 freeTD((volatile uint8_t*)ep->getTDList()[1]); 00437 00438 freeED((uint8_t *)ep->getHCED()); 00439 } 00440 printList(BULK_ENDPOINT); 00441 printList(INTERRUPT_ENDPOINT); 00442 } 00443 USB_INFO("Device disconnected [%p - %s - hub: %d - port: %d]", dev, dev->getName(j), dev->getHub(), dev->getPort()); 00444 } 00445 } 00446 dev->disconnect(); 00447 } 00448 } 00449 00450 00451 void USBHost::unqueueEndpoint(USBEndpoint * ep) 00452 { 00453 USBEndpoint * prec = NULL; 00454 USBEndpoint * current = NULL; 00455 00456 for (int i = 0; i < 2; i++) { 00457 current = (i == 0) ? (USBEndpoint*)headBulkEndpoint : (USBEndpoint*)headInterruptEndpoint; 00458 prec = current; 00459 while (current != NULL) { 00460 if (current == ep) { 00461 if (current->nextEndpoint() != NULL) { 00462 prec->queueEndpoint(current->nextEndpoint()); 00463 if (current == headBulkEndpoint) { 00464 updateBulkHeadED((uint32_t)current->nextEndpoint()->getHCED()); 00465 headBulkEndpoint = current->nextEndpoint(); 00466 } else if (current == headInterruptEndpoint) { 00467 updateInterruptHeadED((uint32_t)current->nextEndpoint()->getHCED()); 00468 headInterruptEndpoint = current->nextEndpoint(); 00469 } 00470 } 00471 // here we are dequeuing the queue of ed 00472 // we need to update the tail pointer 00473 else { 00474 prec->queueEndpoint(NULL); 00475 if (current == headBulkEndpoint) { 00476 updateBulkHeadED(0); 00477 headBulkEndpoint = current->nextEndpoint(); 00478 } else if (current == headInterruptEndpoint) { 00479 updateInterruptHeadED(0); 00480 headInterruptEndpoint = current->nextEndpoint(); 00481 } 00482 00483 // modify tail 00484 switch (current->getType()) { 00485 case BULK_ENDPOINT: 00486 tailBulkEndpoint = prec; 00487 break; 00488 case INTERRUPT_ENDPOINT: 00489 tailInterruptEndpoint = prec; 00490 break; 00491 default: 00492 break; 00493 } 00494 } 00495 current->setState(USB_TYPE_FREE); 00496 return; 00497 } 00498 prec = current; 00499 current = current->nextEndpoint(); 00500 } 00501 } 00502 } 00503 00504 00505 USBDeviceConnected * USBHost::getDevice(uint8_t index) 00506 { 00507 if ((index >= MAX_DEVICE_CONNECTED) || (!deviceInUse[index])) { 00508 return NULL; 00509 } 00510 return (USBDeviceConnected*)&devices[index]; 00511 } 00512 00513 // create an USBEndpoint descriptor. the USBEndpoint is not linked 00514 USBEndpoint * USBHost::newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr) 00515 { 00516 int i = 0; 00517 HCED * ed = (HCED *)getED(); 00518 HCTD* td_list[2] = { (HCTD*)getTD(), (HCTD*)getTD() }; 00519 00520 memset((void *)td_list[0], 0x00, sizeof(HCTD)); 00521 memset((void *)td_list[1], 0x00, sizeof(HCTD)); 00522 00523 // search a free USBEndpoint 00524 for (i = 0; i < MAX_ENDPOINT; i++) { 00525 if (endpoints[i].getState() == USB_TYPE_FREE) { 00526 endpoints[i].init(ed, type, dir, size, addr, td_list); 00527 USB_DBG("USBEndpoint created (%p): type: %d, dir: %d, size: %d, addr: %d, state: %s", &endpoints[i], type, dir, size, addr, endpoints[i].getStateString()); 00528 return &endpoints[i]; 00529 } 00530 } 00531 USB_ERR("could not allocate more endpoints!!!!"); 00532 return NULL; 00533 } 00534 00535 00536 USB_TYPE USBHost::resetDevice(USBDeviceConnected * dev) 00537 { 00538 int index = findDevice(dev); 00539 if (index != -1) { 00540 USB_DBG("Resetting hub %d, port %d\n", dev->getHub(), dev->getPort()); 00541 Thread::wait(100); 00542 if (dev->getHub() == 0) { 00543 resetRootHub(); 00544 } 00545 #if MAX_HUB_NB 00546 else { 00547 dev->getHubParent()->portReset(dev->getPort()); 00548 } 00549 #endif 00550 Thread::wait(100); 00551 deviceReset[index] = true; 00552 return USB_TYPE_OK; 00553 } 00554 00555 return USB_TYPE_ERROR; 00556 } 00557 00558 // link the USBEndpoint to the linked list and attach an USBEndpoint to a device 00559 bool USBHost::addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep) 00560 { 00561 00562 if (ep == NULL) { 00563 return false; 00564 } 00565 00566 HCED * prevEd; 00567 00568 // set device address in the USBEndpoint descriptor 00569 if (dev == NULL) { 00570 ep->setDeviceAddress(0); 00571 } else { 00572 ep->setDeviceAddress(dev->getAddress()); 00573 } 00574 00575 if ((dev != NULL) && dev->getSpeed()) { 00576 ep->setSpeed(dev->getSpeed()); 00577 } 00578 00579 ep->setIntfNb(intf_nb); 00580 00581 // queue the new USBEndpoint on the ED list 00582 switch (ep->getType()) { 00583 00584 case CONTROL_ENDPOINT: 00585 prevEd = ( HCED*) controlHeadED(); 00586 if (!prevEd) { 00587 updateControlHeadED((uint32_t) ep->getHCED()); 00588 USB_DBG_TRANSFER("First control USBEndpoint: %08X", (uint32_t) ep->getHCED()); 00589 headControlEndpoint = ep; 00590 tailControlEndpoint = ep; 00591 return true; 00592 } 00593 tailControlEndpoint->queueEndpoint(ep); 00594 tailControlEndpoint = ep; 00595 return true; 00596 00597 case BULK_ENDPOINT: 00598 prevEd = ( HCED*) bulkHeadED(); 00599 if (!prevEd) { 00600 updateBulkHeadED((uint32_t) ep->getHCED()); 00601 USB_DBG_TRANSFER("First bulk USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED()); 00602 headBulkEndpoint = ep; 00603 tailBulkEndpoint = ep; 00604 break; 00605 } 00606 USB_DBG_TRANSFER("Queue BULK Ed %p after %p\r\n",ep->getHCED(), prevEd); 00607 tailBulkEndpoint->queueEndpoint(ep); 00608 tailBulkEndpoint = ep; 00609 break; 00610 00611 case INTERRUPT_ENDPOINT: 00612 prevEd = ( HCED*) interruptHeadED(); 00613 if (!prevEd) { 00614 updateInterruptHeadED((uint32_t) ep->getHCED()); 00615 USB_DBG_TRANSFER("First interrupt USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED()); 00616 headInterruptEndpoint = ep; 00617 tailInterruptEndpoint = ep; 00618 break; 00619 } 00620 USB_DBG_TRANSFER("Queue INTERRUPT Ed %p after %p\r\n",ep->getHCED(), prevEd); 00621 tailInterruptEndpoint->queueEndpoint(ep); 00622 tailInterruptEndpoint = ep; 00623 break; 00624 default: 00625 return false; 00626 } 00627 00628 ep->dev = dev; 00629 dev->addEndpoint(intf_nb, ep); 00630 00631 return true; 00632 } 00633 00634 00635 int USBHost::findDevice(USBDeviceConnected * dev) 00636 { 00637 for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00638 if (dev == &devices[i]) { 00639 return i; 00640 } 00641 } 00642 return -1; 00643 } 00644 00645 int USBHost::findDevice(uint8_t hub, uint8_t port, USBHostHub * hub_parent) 00646 { 00647 for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00648 if (devices[i].getHub() == hub && devices[i].getPort() == port) { 00649 if (hub_parent != NULL) { 00650 if (hub_parent == devices[i].getHubParent()) 00651 return i; 00652 } else { 00653 return i; 00654 } 00655 } 00656 } 00657 return -1; 00658 } 00659 00660 void USBHost::printList(ENDPOINT_TYPE type) 00661 { 00662 #if DEBUG_EP_STATE 00663 volatile HCED * hced; 00664 switch(type) { 00665 case CONTROL_ENDPOINT: 00666 hced = (HCED *)controlHeadED(); 00667 break; 00668 case BULK_ENDPOINT: 00669 hced = (HCED *)bulkHeadED(); 00670 break; 00671 case INTERRUPT_ENDPOINT: 00672 hced = (HCED *)interruptHeadED(); 00673 break; 00674 } 00675 volatile HCTD * hctd = NULL; 00676 const char * type_str = (type == BULK_ENDPOINT) ? "BULK" : 00677 ((type == INTERRUPT_ENDPOINT) ? "INTERRUPT" : 00678 ((type == CONTROL_ENDPOINT) ? "CONTROL" : "ISOCHRONOUS")); 00679 printf("State of %s:\r\n", type_str); 00680 while (hced != NULL) { 00681 uint8_t dir = ((hced->control & (3 << 11)) >> 11); 00682 printf("hced: %p [ADDR: %d, DIR: %s, EP_NB: 0x%X]\r\n", hced, 00683 hced->control & 0x7f, 00684 (dir == 1) ? "OUT" : ((dir == 0) ? "FROM_TD":"IN"), 00685 (hced->control & (0xf << 7)) >> 7); 00686 hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0xf)); 00687 while (hctd != hced->tailTD) { 00688 printf("\thctd: %p [DIR: %s]\r\n", hctd, ((hctd->control & (3 << 19)) >> 19) == 1 ? "OUT" : "IN"); 00689 hctd = hctd->nextTD; 00690 } 00691 printf("\thctd: %p\r\n", hctd); 00692 hced = hced->nextED; 00693 } 00694 printf("\r\n\r\n"); 00695 #endif 00696 } 00697 00698 00699 // add a transfer on the TD linked list 00700 USB_TYPE USBHost::addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len) 00701 { 00702 td_mutex.lock(); 00703 00704 // allocate a TD which will be freed in TDcompletion 00705 volatile HCTD * td = ed->getNextTD(); 00706 if (td == NULL) { 00707 return USB_TYPE_ERROR; 00708 } 00709 00710 uint32_t token = (ed->isSetup() ? TD_SETUP : ( (ed->getDir() == IN) ? TD_IN : TD_OUT )); 00711 00712 uint32_t td_toggle; 00713 00714 if (ed->getType() == CONTROL_ENDPOINT) { 00715 if (ed->isSetup()) { 00716 td_toggle = TD_TOGGLE_0; 00717 } else { 00718 td_toggle = TD_TOGGLE_1; 00719 } 00720 } else { 00721 td_toggle = 0; 00722 } 00723 00724 td->control = (TD_ROUNDING | token | TD_DELAY_INT(0) | td_toggle | TD_CC); 00725 td->currBufPtr = buf; 00726 td->bufEnd = (buf + (len - 1)); 00727 00728 ENDPOINT_TYPE type = ed->getType(); 00729 00730 disableList(type); 00731 ed->queueTransfer(); 00732 printList(type); 00733 enableList(type); 00734 00735 td_mutex.unlock(); 00736 00737 return USB_TYPE_PROCESSING; 00738 } 00739 00740 00741 00742 USB_TYPE USBHost::getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_dev_descr) 00743 { 00744 USB_TYPE t = controlRead( dev, 00745 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, 00746 GET_DESCRIPTOR, 00747 (DEVICE_DESCRIPTOR << 8) | (0), 00748 0, buf, MIN(DEVICE_DESCRIPTOR_LENGTH, max_len_buf)); 00749 if (len_dev_descr) 00750 *len_dev_descr = MIN(DEVICE_DESCRIPTOR_LENGTH, max_len_buf); 00751 00752 return t; 00753 } 00754 00755 USB_TYPE USBHost::getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_conf_descr) 00756 { 00757 USB_TYPE res; 00758 uint16_t total_conf_descr_length = 0; 00759 00760 // fourth step: get the beginning of the configuration descriptor to have the total length of the conf descr 00761 res = controlRead( dev, 00762 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, 00763 GET_DESCRIPTOR, 00764 (CONFIGURATION_DESCRIPTOR << 8) | (0), 00765 0, buf, CONFIGURATION_DESCRIPTOR_LENGTH); 00766 00767 if (res != USB_TYPE_OK) { 00768 USB_ERR("GET CONF 1 DESCR FAILED"); 00769 return res; 00770 } 00771 total_conf_descr_length = buf[2] | (buf[3] << 8); 00772 total_conf_descr_length = MIN(max_len_buf, total_conf_descr_length); 00773 00774 if (len_conf_descr) 00775 *len_conf_descr = total_conf_descr_length; 00776 00777 USB_DBG("TOTAL_LENGTH: %d \t NUM_INTERF: %d", total_conf_descr_length, buf[4]); 00778 00779 return controlRead( dev, 00780 USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, 00781 GET_DESCRIPTOR, 00782 (CONFIGURATION_DESCRIPTOR << 8) | (0), 00783 0, buf, total_conf_descr_length); 00784 } 00785 00786 00787 USB_TYPE USBHost::setAddress(USBDeviceConnected * dev, uint8_t address) { 00788 return controlWrite( dev, 00789 USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE, 00790 SET_ADDRESS, 00791 address, 00792 0, NULL, 0); 00793 00794 } 00795 00796 USB_TYPE USBHost::setConfiguration(USBDeviceConnected * dev, uint8_t conf) 00797 { 00798 return controlWrite( dev, 00799 USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE, 00800 SET_CONFIGURATION, 00801 conf, 00802 0, NULL, 0); 00803 } 00804 00805 uint8_t USBHost::numberDriverAttached(USBDeviceConnected * dev) { 00806 int index = findDevice(dev); 00807 uint8_t cnt = 0; 00808 if (index == -1) 00809 return 0; 00810 for (uint8_t i = 0; i < MAX_INTF; i++) { 00811 if (deviceAttachedDriver[index][i]) 00812 cnt++; 00813 } 00814 return cnt; 00815 } 00816 00817 // enumerate a device with the control USBEndpoint 00818 USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator) 00819 { 00820 uint16_t total_conf_descr_length = 0; 00821 USB_TYPE res; 00822 00823 do 00824 { 00825 Lock lock(this); 00826 00827 // don't enumerate a device which all interfaces are registered to a specific driver 00828 int index = findDevice(dev); 00829 00830 if (index == -1) { 00831 return USB_TYPE_ERROR; 00832 } 00833 00834 uint8_t nb_intf_attached = numberDriverAttached(dev); 00835 USB_DBG("dev: %p nb_intf: %d", dev, dev->getNbIntf()); 00836 USB_DBG("dev: %p nb_intf_attached: %d", dev, nb_intf_attached); 00837 if ((nb_intf_attached != 0) && (dev->getNbIntf() == nb_intf_attached)) { 00838 USB_DBG("Don't enumerate dev: %p because all intf are registered with a driver", dev); 00839 return USB_TYPE_OK; 00840 } 00841 00842 USB_DBG("Enumerate dev: %p", dev); 00843 00844 // third step: get the whole device descriptor to see vid, pid 00845 res = getDeviceDescriptor(dev, data, DEVICE_DESCRIPTOR_LENGTH); 00846 00847 if (res != USB_TYPE_OK) { 00848 USB_DBG("GET DEV DESCR FAILED"); 00849 return res; 00850 } 00851 00852 dev->setClass(data[4]); 00853 dev->setSubClass(data[5]); 00854 dev->setProtocol(data[6]); 00855 dev->setVid(data[8] | (data[9] << 8)); 00856 dev->setPid(data[10] | (data[11] << 8)); 00857 USB_DBG("CLASS: %02X \t VID: %04X \t PID: %04X", data[4], data[8] | (data[9] << 8), data[10] | (data[11] << 8)); 00858 00859 pEnumerator->setVidPid( data[8] | (data[9] << 8), data[10] | (data[11] << 8) ); 00860 00861 res = getConfigurationDescriptor(dev, data, sizeof(data), &total_conf_descr_length); 00862 if (res != USB_TYPE_OK) { 00863 return res; 00864 } 00865 00866 #if (DEBUG > 3) 00867 USB_DBG("CONFIGURATION DESCRIPTOR:\r\n"); 00868 for (int i = 0; i < total_conf_descr_length; i++) 00869 printf("%02X ", data[i]); 00870 printf("\r\n\r\n"); 00871 #endif 00872 00873 // Parse the configuration descriptor 00874 parseConfDescr(dev, data, total_conf_descr_length, pEnumerator); 00875 00876 // only set configuration if not enumerated before 00877 if (!dev->isEnumerated()) { 00878 00879 USB_DBG("Set configuration 1 on dev: %p", dev); 00880 // sixth step: set configuration (only 1 supported) 00881 res = setConfiguration(dev, 1); 00882 00883 if (res != USB_TYPE_OK) { 00884 USB_DBG("SET CONF FAILED"); 00885 return res; 00886 } 00887 } 00888 00889 dev->setEnumerated(); 00890 00891 // Now the device is enumerated! 00892 USB_DBG("dev %p is enumerated\r\n", dev); 00893 00894 } while(0); 00895 00896 // Some devices may require this delay 00897 Thread::wait(100); 00898 00899 return USB_TYPE_OK; 00900 } 00901 // this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor. 00902 void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) 00903 { 00904 uint32_t index = 0; 00905 uint32_t len_desc = 0; 00906 uint8_t id = 0; 00907 int nb_endpoints_used = 0; 00908 USBEndpoint * ep = NULL; 00909 uint8_t intf_nb = 0; 00910 bool parsing_intf = false; 00911 uint8_t current_intf = 0; 00912 00913 while (index < len) { 00914 len_desc = conf_descr[index]; 00915 id = conf_descr[index+1]; 00916 switch (id) { 00917 case CONFIGURATION_DESCRIPTOR: 00918 USB_DBG("dev: %p has %d intf", dev, conf_descr[4]); 00919 dev->setNbIntf(conf_descr[4]); 00920 break; 00921 case INTERFACE_DESCRIPTOR: 00922 if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) { 00923 if (intf_nb++ <= MAX_INTF) { 00924 current_intf = conf_descr[index + 2]; 00925 dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]); 00926 nb_endpoints_used = 0; 00927 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]); 00928 } else { 00929 USB_DBG("Drop intf..."); 00930 } 00931 parsing_intf = true; 00932 } else { 00933 parsing_intf = false; 00934 } 00935 break; 00936 case ENDPOINT_DESCRIPTOR: 00937 if (parsing_intf && (intf_nb <= MAX_INTF) ) { 00938 if (nb_endpoints_used < MAX_ENDPOINT_PER_INTERFACE) { 00939 if( pEnumerator->useEndpoint(current_intf, (ENDPOINT_TYPE)(conf_descr[index + 3] & 0x03), (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1)) ) { 00940 // if the USBEndpoint is isochronous -> skip it (TODO: fix this) 00941 if ((conf_descr[index + 3] & 0x03) != ISOCHRONOUS_ENDPOINT) { 00942 ep = newEndpoint((ENDPOINT_TYPE)(conf_descr[index+3] & 0x03), 00943 (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1), 00944 conf_descr[index + 4] | (conf_descr[index + 5] << 8), 00945 conf_descr[index + 2] & 0x0f); 00946 USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev); 00947 if (ep != NULL && dev != NULL) { 00948 addEndpoint(dev, current_intf, ep); 00949 } else { 00950 USB_DBG("EP NULL"); 00951 } 00952 nb_endpoints_used++; 00953 } else { 00954 USB_DBG("ISO USBEndpoint NOT SUPPORTED"); 00955 } 00956 } 00957 } 00958 } 00959 break; 00960 case HID_DESCRIPTOR: 00961 lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8); 00962 break; 00963 default: 00964 break; 00965 } 00966 index += len_desc; 00967 } 00968 } 00969 00970 00971 USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) 00972 { 00973 return generalTransfer(dev, ep, buf, len, blocking, BULK_ENDPOINT, true); 00974 } 00975 00976 USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) 00977 { 00978 return generalTransfer(dev, ep, buf, len, blocking, BULK_ENDPOINT, false); 00979 } 00980 00981 USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) 00982 { 00983 return generalTransfer(dev, ep, buf, len, blocking, INTERRUPT_ENDPOINT, true); 00984 } 00985 00986 USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) 00987 { 00988 return generalTransfer(dev, ep, buf, len, blocking, INTERRUPT_ENDPOINT, false); 00989 } 00990 00991 USB_TYPE USBHost::generalTransfer(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking, ENDPOINT_TYPE type, bool write) { 00992 00993 #if DEBUG_TRANSFER 00994 const char * type_str = (type == BULK_ENDPOINT) ? "BULK" : ((type == INTERRUPT_ENDPOINT) ? "INTERRUPT" : "ISOCHRONOUS"); 00995 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()); 00996 #endif 00997 00998 Lock lock(this); 00999 01000 USB_TYPE res; 01001 ENDPOINT_DIRECTION dir = (write) ? OUT : IN; 01002 01003 if (dev == NULL) { 01004 USB_ERR("dev NULL"); 01005 return USB_TYPE_ERROR; 01006 } 01007 01008 if (ep == NULL) { 01009 USB_ERR("ep NULL"); 01010 return USB_TYPE_ERROR; 01011 } 01012 01013 if (ep->getState() != USB_TYPE_IDLE) { 01014 USB_WARN("[ep: %p - dev: %p - %s] NOT IDLE: %s", ep, ep->dev, ep->dev->getName(ep->getIntfNb()), ep->getStateString()); 01015 return ep->getState(); 01016 } 01017 01018 if ((ep->getDir() != dir) || (ep->getType() != type)) { 01019 USB_ERR("[ep: %p - dev: %p] wrong dir or bad USBEndpoint type", ep, ep->dev); 01020 return USB_TYPE_ERROR; 01021 } 01022 01023 if (dev->getAddress() != ep->getDeviceAddress()) { 01024 USB_ERR("[ep: %p - dev: %p] USBEndpoint addr and device addr don't match", ep, ep->dev); 01025 return USB_TYPE_ERROR; 01026 } 01027 01028 #if DEBUG_TRANSFER 01029 if (write) { 01030 USB_DBG_TRANSFER("%s WRITE buffer", type_str); 01031 for (int i = 0; i < ep->getLengthTransferred(); i++) 01032 printf("%02X ", buf[i]); 01033 printf("\r\n\r\n"); 01034 } 01035 #endif 01036 addTransfer(ep, buf, len); 01037 01038 if (blocking) { 01039 01040 ep->ep_queue.get(); 01041 res = ep->getState(); 01042 01043 USB_DBG_TRANSFER("%s TRANSFER res: %s on ep: %p\r\n", type_str, ep->getStateString(), ep); 01044 01045 if (res != USB_TYPE_IDLE) { 01046 return res; 01047 } 01048 01049 return USB_TYPE_OK; 01050 } 01051 01052 return USB_TYPE_PROCESSING; 01053 01054 } 01055 01056 01057 USB_TYPE USBHost::controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { 01058 return controlTransfer(dev, requestType, request, value, index, buf, len, false); 01059 } 01060 01061 USB_TYPE USBHost::controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { 01062 return controlTransfer(dev, requestType, request, value, index, buf, len, true); 01063 } 01064 01065 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) 01066 { 01067 Lock lock(this); 01068 USB_DBG_TRANSFER("----- CONTROL %s [dev: %p - hub: %d - port: %d] ------", (write) ? "WRITE" : "READ", dev, dev->getHub(), dev->getPort()); 01069 01070 int length_transfer = len; 01071 USB_TYPE res; 01072 uint32_t token; 01073 01074 control->setSpeed(dev->getSpeed()); 01075 control->setSize(dev->getSizeControlEndpoint()); 01076 if (dev->isActiveAddress()) { 01077 control->setDeviceAddress(dev->getAddress()); 01078 } else { 01079 control->setDeviceAddress(0); 01080 } 01081 01082 USB_DBG_TRANSFER("Control transfer on device: %d\r\n", control->getDeviceAddress()); 01083 fillControlBuf(requestType, request, value, index, len); 01084 01085 #if DEBUG_TRANSFER 01086 USB_DBG_TRANSFER("SETUP PACKET: "); 01087 for (int i = 0; i < 8; i++) 01088 printf("%01X ", setupPacket[i]); 01089 printf("\r\n"); 01090 #endif 01091 01092 control->setNextToken(TD_SETUP); 01093 addTransfer(control, (uint8_t*)setupPacket, 8); 01094 01095 control->ep_queue.get(); 01096 res = control->getState(); 01097 01098 USB_DBG_TRANSFER("CONTROL setup stage %s", control->getStateString()); 01099 01100 if (res != USB_TYPE_IDLE) { 01101 return res; 01102 } 01103 01104 if (length_transfer) { 01105 token = (write) ? TD_OUT : TD_IN; 01106 control->setNextToken(token); 01107 addTransfer(control, (uint8_t *)buf, length_transfer); 01108 01109 control->ep_queue.get(); 01110 res = control->getState(); 01111 01112 #if DEBUG_TRANSFER 01113 USB_DBG_TRANSFER("CONTROL %s stage %s", (write) ? "WRITE" : "READ", control->getStateString()); 01114 if (write) { 01115 USB_DBG_TRANSFER("CONTROL WRITE buffer"); 01116 for (int i = 0; i < control->getLengthTransferred(); i++) 01117 printf("%02X ", buf[i]); 01118 printf("\r\n\r\n"); 01119 } else { 01120 USB_DBG_TRANSFER("CONTROL READ SUCCESS [%d bytes transferred]", control->getLengthTransferred()); 01121 for (int i = 0; i < control->getLengthTransferred(); i++) 01122 printf("%02X ", buf[i]); 01123 printf("\r\n\r\n"); 01124 } 01125 #endif 01126 01127 if (res != USB_TYPE_IDLE) { 01128 return res; 01129 } 01130 } 01131 01132 token = (write) ? TD_IN : TD_OUT; 01133 control->setNextToken(token); 01134 addTransfer(control, NULL, 0); 01135 01136 control->ep_queue.get(); 01137 res = control->getState(); 01138 01139 USB_DBG_TRANSFER("CONTROL ack stage %s", control->getStateString()); 01140 01141 if (res != USB_TYPE_IDLE) 01142 return res; 01143 01144 return USB_TYPE_OK; 01145 } 01146 01147 01148 void USBHost::fillControlBuf(uint8_t requestType, uint8_t request, uint16_t value, uint16_t index, int len) 01149 { 01150 setupPacket[0] = requestType; 01151 setupPacket[1] = request; 01152 setupPacket[2] = (uint8_t) value; 01153 setupPacket[3] = (uint8_t) (value >> 8); 01154 setupPacket[4] = (uint8_t) index; 01155 setupPacket[5] = (uint8_t) (index >> 8); 01156 setupPacket[6] = (uint8_t) len; 01157 setupPacket[7] = (uint8_t) (len >> 8); 01158 }
Generated on Tue Jul 12 2022 17:34:59 by
