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