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