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