1 /* 2 * Copyright 2003-2008, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 * Niels S. Reedijk 8 */ 9 10 11 #include <module.h> 12 #include <unistd.h> 13 #include <util/kernel_cpp.h> 14 #include "usb_private.h" 15 #include "PhysicalMemoryAllocator.h" 16 17 #include <fs/devfs.h> 18 19 20 Stack::Stack() 21 : fExploreThread(-1), 22 fFirstExploreDone(false), 23 fStopThreads(false), 24 fAllocator(NULL), 25 fObjectIndex(1), 26 fObjectMaxCount(1024), 27 fObjectArray(NULL), 28 fDriverList(NULL) 29 { 30 TRACE("stack init\n"); 31 32 mutex_init(&fStackLock, "usb stack lock"); 33 mutex_init(&fExploreLock, "usb explore lock"); 34 35 size_t objectArraySize = fObjectMaxCount * sizeof(Object *); 36 fObjectArray = (Object **)malloc(objectArraySize); 37 if (fObjectArray == NULL) { 38 TRACE_ERROR("failed to allocate object array\n"); 39 return; 40 } 41 42 memset(fObjectArray, 0, objectArraySize); 43 44 fAllocator = new(std::nothrow) PhysicalMemoryAllocator("USB Stack Allocator", 45 8, B_PAGE_SIZE * 32, 64); 46 if (!fAllocator || fAllocator->InitCheck() < B_OK) { 47 TRACE_ERROR("failed to allocate the allocator\n"); 48 delete fAllocator; 49 fAllocator = NULL; 50 return; 51 } 52 53 // Check for host controller modules. 54 // 55 // While using a fixed list of names is inflexible, it allows us to control 56 // the order in which we try modules. There are controllers/BIOSes that 57 // require UHCI/OHCI to be initialized before EHCI or otherwise they 58 // refuse to publish any high-speed devices. 59 // 60 // On other systems, the ordering is probably ensured because the EHCI 61 // controller is required to have a higher PCI function number than the 62 // companion host controllers (per the EHCI specs) and it would therefore 63 // be enumerated as the last item. As this does not apply to us, we have to 64 // ensure ordering using another method. 65 // 66 // Furthermore, on some systems, there can be ports shared between 67 // EHCI and XHCI, defaulting to EHCI. The XHCI module will switch these 68 // ports before the EHCI module discovers them. 69 const char *moduleNames[] = { 70 "busses/usb/xhci", 71 "busses/usb/uhci", 72 "busses/usb/ohci", 73 "busses/usb/ehci", 74 NULL 75 }; 76 77 TRACE("looking for host controller modules\n"); 78 for (uint32 i = 0; moduleNames[i]; i++) { 79 TRACE("looking for module %s\n", moduleNames[i]); 80 81 usb_host_controller_info *module = NULL; 82 if (get_module(moduleNames[i], (module_info **)&module) != B_OK) 83 continue; 84 85 TRACE("adding module %s\n", moduleNames[i]); 86 if (module->add_to(this) < B_OK) { 87 put_module(moduleNames[i]); 88 continue; 89 } 90 91 TRACE("module %s successfully loaded\n", moduleNames[i]); 92 } 93 94 if (fBusManagers.Count() == 0) { 95 TRACE_ERROR("no bus managers available\n"); 96 return; 97 } 98 99 fExploreThread = spawn_kernel_thread(ExploreThread, "usb explore", 100 B_LOW_PRIORITY, this); 101 resume_thread(fExploreThread); 102 103 // wait for the first explore to complete. this ensures that a driver that 104 // is opening the module does not get rescanned while or before installing 105 // its hooks. 106 while (!fFirstExploreDone) 107 snooze(10000); 108 } 109 110 111 Stack::~Stack() 112 { 113 int32 result; 114 fStopThreads = true; 115 wait_for_thread(fExploreThread, &result); 116 117 mutex_lock(&fStackLock); 118 mutex_destroy(&fStackLock); 119 mutex_lock(&fExploreLock); 120 mutex_destroy(&fExploreLock); 121 122 // Release the bus modules 123 for (Vector<BusManager *>::Iterator i = fBusManagers.Begin(); 124 i != fBusManagers.End(); i++) { 125 delete (*i); 126 } 127 128 delete fAllocator; 129 free(fObjectArray); 130 } 131 132 133 status_t 134 Stack::InitCheck() 135 { 136 if (fBusManagers.Count() == 0) 137 return ENODEV; 138 return B_OK; 139 } 140 141 142 bool 143 Stack::Lock() 144 { 145 return (mutex_lock(&fStackLock) == B_OK); 146 } 147 148 149 void 150 Stack::Unlock() 151 { 152 mutex_unlock(&fStackLock); 153 } 154 155 156 usb_id 157 Stack::GetUSBID(Object *object) 158 { 159 if (!Lock()) 160 return fObjectMaxCount; 161 162 uint32 id = fObjectIndex; 163 uint32 tries = fObjectMaxCount; 164 while (tries-- > 0) { 165 if (fObjectArray[id] == NULL) { 166 fObjectIndex = (id + 1) % fObjectMaxCount; 167 fObjectArray[id] = object; 168 Unlock(); 169 return (usb_id)id; 170 } 171 172 id = (id + 1) % fObjectMaxCount; 173 } 174 175 TRACE_ERROR("the stack has run out of usb_ids\n"); 176 Unlock(); 177 return 0; 178 } 179 180 181 void 182 Stack::PutUSBID(Object *object) 183 { 184 if (!Lock()) 185 return; 186 187 usb_id id = object->USBID(); 188 if (id >= fObjectMaxCount) { 189 TRACE_ERROR("tried to put an invalid usb_id\n"); 190 Unlock(); 191 return; 192 } 193 if (fObjectArray[id] != object) { 194 TRACE_ERROR("tried to put an object with incorrect usb_id\n"); 195 Unlock(); 196 return; 197 } 198 199 fObjectArray[id] = NULL; 200 201 #if KDEBUG 202 // Validate that no children of this object are still in the stack. 203 for (usb_id i = 0; i < fObjectMaxCount; i++) { 204 if (fObjectArray[i] == NULL) 205 continue; 206 207 ASSERT_PRINT(fObjectArray[i]->Parent() != object, 208 "%s", fObjectArray[i]->TypeName()); 209 } 210 #endif 211 212 Unlock(); 213 } 214 215 216 Object * 217 Stack::GetObject(usb_id id) 218 { 219 if (!Lock()) 220 return NULL; 221 222 if (id >= fObjectMaxCount) { 223 TRACE_ERROR("tried to get object with invalid usb_id\n"); 224 Unlock(); 225 return NULL; 226 } 227 228 Object *result = fObjectArray[id]; 229 230 if (result != NULL) 231 result->SetBusy(true); 232 233 Unlock(); 234 return result; 235 } 236 237 238 Object * 239 Stack::GetObjectNoLock(usb_id id) const 240 { 241 ASSERT(debug_debugger_running()); 242 if (id >= fObjectMaxCount) 243 return NULL; 244 return fObjectArray[id]; 245 } 246 247 248 int32 249 Stack::ExploreThread(void *data) 250 { 251 Stack *stack = (Stack *)data; 252 253 while (!stack->fStopThreads) { 254 if (mutex_lock(&stack->fExploreLock) != B_OK) 255 break; 256 257 rescan_item *rescanList = NULL; 258 change_item *changeItem = NULL; 259 for (int32 i = 0; i < stack->fBusManagers.Count(); i++) { 260 Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub(); 261 if (rootHub) 262 rootHub->Explore(&changeItem); 263 } 264 265 while (changeItem) { 266 stack->NotifyDeviceChange(changeItem->device, &rescanList, changeItem->added); 267 if (!changeItem->added) { 268 // everyone possibly holding a reference is now notified so we 269 // can delete the device 270 changeItem->device->GetBusManager()->FreeDevice(changeItem->device); 271 } 272 273 change_item *next = changeItem->link; 274 delete changeItem; 275 changeItem = next; 276 } 277 278 stack->fFirstExploreDone = true; 279 mutex_unlock(&stack->fExploreLock); 280 stack->RescanDrivers(rescanList); 281 snooze(USB_DELAY_HUB_EXPLORE); 282 } 283 284 return B_OK; 285 } 286 287 288 void 289 Stack::AddBusManager(BusManager *busManager) 290 { 291 fBusManagers.PushBack(busManager); 292 } 293 294 295 int32 296 Stack::IndexOfBusManager(BusManager *busManager) 297 { 298 return fBusManagers.IndexOf(busManager); 299 } 300 301 302 BusManager * 303 Stack::BusManagerAt(int32 index) const 304 { 305 return fBusManagers.ElementAt(index); 306 } 307 308 309 status_t 310 Stack::AllocateChunk(void **logicalAddress, phys_addr_t *physicalAddress, 311 size_t size) 312 { 313 return fAllocator->Allocate(size, logicalAddress, physicalAddress); 314 } 315 316 317 status_t 318 Stack::FreeChunk(void *logicalAddress, phys_addr_t physicalAddress, 319 size_t size) 320 { 321 return fAllocator->Deallocate(size, logicalAddress, physicalAddress); 322 } 323 324 325 area_id 326 Stack::AllocateArea(void **logicalAddress, phys_addr_t *physicalAddress, size_t size, 327 const char *name) 328 { 329 TRACE("allocating %ld bytes for %s\n", size, name); 330 331 void *logAddress; 332 size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 333 area_id area = create_area(name, &logAddress, B_ANY_KERNEL_ADDRESS, size, 334 B_32_BIT_CONTIGUOUS, 0); 335 // TODO: Use B_CONTIGUOUS when the TODOs regarding 64 bit physical 336 // addresses are fixed (if possible). 337 338 if (area < B_OK) { 339 TRACE_ERROR("couldn't allocate area %s\n", name); 340 return B_ERROR; 341 } 342 343 physical_entry physicalEntry; 344 status_t result = get_memory_map(logAddress, size, &physicalEntry, 1); 345 if (result < B_OK) { 346 delete_area(area); 347 TRACE_ERROR("couldn't map area %s\n", name); 348 return B_ERROR; 349 } 350 351 memset(logAddress, 0, size); 352 if (logicalAddress) 353 *logicalAddress = logAddress; 354 355 if (physicalAddress) 356 *physicalAddress = (phys_addr_t)physicalEntry.address; 357 358 TRACE("area = %" B_PRId32 ", size = %" B_PRIuSIZE ", log = %p, phy = %#" 359 B_PRIxPHYSADDR "\n", area, size, logAddress, physicalEntry.address); 360 return area; 361 } 362 363 364 void 365 Stack::NotifyDeviceChange(Device *device, rescan_item **rescanList, bool added) 366 { 367 TRACE("device %s\n", added ? "added" : "removed"); 368 369 usb_driver_info *element = fDriverList; 370 while (element) { 371 status_t result = device->ReportDevice(element->support_descriptors, 372 element->support_descriptor_count, &element->notify_hooks, 373 &element->cookies, added, false); 374 375 if (result >= B_OK) { 376 const char *driverName = element->driver_name; 377 if (element->republish_driver_name) 378 driverName = element->republish_driver_name; 379 380 bool already = false; 381 rescan_item *rescanItem = *rescanList; 382 while (rescanItem) { 383 if (strcmp(rescanItem->name, driverName) == 0) { 384 // this driver is going to be rescanned already 385 already = true; 386 break; 387 } 388 rescanItem = rescanItem->link; 389 } 390 391 if (!already) { 392 rescanItem = new(std::nothrow) rescan_item; 393 if (!rescanItem) 394 return; 395 396 rescanItem->name = driverName; 397 rescanItem->link = *rescanList; 398 *rescanList = rescanItem; 399 } 400 } 401 402 element = element->link; 403 } 404 } 405 406 407 void 408 Stack::RescanDrivers(rescan_item *rescanItem) 409 { 410 while (rescanItem) { 411 // the device is supported by this driver. it either got notified 412 // already by the hooks or it is not loaded at this time. in any 413 // case we will rescan the driver so it either is loaded and can 414 // scan for supported devices or its publish_devices hook will be 415 // called to expose changed devices. 416 417 // use the private devfs API to republish a device 418 devfs_rescan_driver(rescanItem->name); 419 420 rescan_item *next = rescanItem->link; 421 delete rescanItem; 422 rescanItem = next; 423 } 424 } 425 426 427 status_t 428 Stack::RegisterDriver(const char *driverName, 429 const usb_support_descriptor *descriptors, 430 size_t descriptorCount, const char *republishDriverName) 431 { 432 TRACE("register driver \"%s\"\n", driverName); 433 if (!driverName) 434 return B_BAD_VALUE; 435 436 if (!Lock()) 437 return B_ERROR; 438 439 usb_driver_info *element = fDriverList; 440 while (element) { 441 if (strcmp(element->driver_name, driverName) == 0) { 442 // we already have an entry for this driver, just update it 443 free((char *)element->republish_driver_name); 444 element->republish_driver_name = strdup(republishDriverName); 445 446 free(element->support_descriptors); 447 size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor); 448 element->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize); 449 memcpy(element->support_descriptors, descriptors, descriptorsSize); 450 element->support_descriptor_count = descriptorCount; 451 452 Unlock(); 453 return B_OK; 454 } 455 456 element = element->link; 457 } 458 459 // this is a new driver, add it to the driver list 460 usb_driver_info *info = new(std::nothrow) usb_driver_info; 461 if (!info) { 462 Unlock(); 463 return B_NO_MEMORY; 464 } 465 466 info->driver_name = strdup(driverName); 467 info->republish_driver_name = strdup(republishDriverName); 468 469 size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor); 470 info->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize); 471 memcpy(info->support_descriptors, descriptors, descriptorsSize); 472 info->support_descriptor_count = descriptorCount; 473 474 info->notify_hooks.device_added = NULL; 475 info->notify_hooks.device_removed = NULL; 476 info->cookies = NULL; 477 info->link = NULL; 478 479 if (fDriverList) { 480 usb_driver_info *element = fDriverList; 481 while (element->link) 482 element = element->link; 483 484 element->link = info; 485 } else 486 fDriverList = info; 487 488 Unlock(); 489 return B_OK; 490 } 491 492 493 status_t 494 Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks) 495 { 496 TRACE("installing notify hooks for driver \"%s\"\n", driverName); 497 498 usb_driver_info *element = fDriverList; 499 while (element) { 500 if (strcmp(element->driver_name, driverName) == 0) { 501 if (mutex_lock(&fExploreLock) != B_OK) 502 return B_ERROR; 503 504 // inform driver about any already present devices 505 for (int32 i = 0; i < fBusManagers.Count(); i++) { 506 Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub(); 507 if (rootHub) { 508 // Report device will recurse down the whole tree 509 rootHub->ReportDevice(element->support_descriptors, 510 element->support_descriptor_count, hooks, 511 &element->cookies, true, true); 512 } 513 } 514 515 element->notify_hooks.device_added = hooks->device_added; 516 element->notify_hooks.device_removed = hooks->device_removed; 517 mutex_unlock(&fExploreLock); 518 return B_OK; 519 } 520 521 element = element->link; 522 } 523 524 return B_NAME_NOT_FOUND; 525 } 526 527 528 status_t 529 Stack::UninstallNotify(const char *driverName) 530 { 531 TRACE("uninstalling notify hooks for driver \"%s\"\n", driverName); 532 533 usb_driver_info *element = fDriverList; 534 while (element) { 535 if (strcmp(element->driver_name, driverName) == 0) { 536 if (mutex_lock(&fExploreLock) != B_OK) 537 return B_ERROR; 538 539 // trigger the device removed hook 540 for (int32 i = 0; i < fBusManagers.Count(); i++) { 541 Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub(); 542 if (rootHub) 543 rootHub->ReportDevice(element->support_descriptors, 544 element->support_descriptor_count, 545 &element->notify_hooks, &element->cookies, false, true); 546 } 547 548 element->notify_hooks.device_added = NULL; 549 element->notify_hooks.device_removed = NULL; 550 mutex_unlock(&fExploreLock); 551 return B_OK; 552 } 553 554 element = element->link; 555 } 556 557 return B_NAME_NOT_FOUND; 558 } 559