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