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