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 // Acquire the device manager lock before the explore lock, to prevent lock-order inversion. 221 RecursiveLocker dmLocker(device_manager_get_lock()); 222 223 if (mutex_lock(&fExploreLock) != B_OK) 224 return; 225 226 int32 semCount = 0; 227 get_sem_count(fExploreSem, &semCount); 228 if (semCount > 0) 229 acquire_sem_etc(fExploreSem, semCount, B_RELATIVE_TIMEOUT, 0); 230 231 rescan_item *rescanList = NULL; 232 change_item *changeItem = NULL; 233 for (int32 i = 0; i < fBusManagers.Count(); i++) { 234 Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub(); 235 if (rootHub) 236 rootHub->Explore(&changeItem); 237 } 238 239 while (changeItem) { 240 NotifyDeviceChange(changeItem->device, &rescanList, changeItem->added); 241 if (!changeItem->added) { 242 // everyone possibly holding a reference is now notified so we 243 // can delete the device 244 changeItem->device->GetBusManager()->FreeDevice(changeItem->device); 245 } 246 247 change_item *next = changeItem->link; 248 delete changeItem; 249 changeItem = next; 250 } 251 252 mutex_unlock(&fExploreLock); 253 RescanDrivers(rescanList); 254 } 255 256 void 257 Stack::AddBusManager(BusManager *busManager) 258 { 259 fBusManagers.PushBack(busManager); 260 } 261 262 263 int32 264 Stack::IndexOfBusManager(BusManager *busManager) 265 { 266 return fBusManagers.IndexOf(busManager); 267 } 268 269 270 BusManager * 271 Stack::BusManagerAt(int32 index) const 272 { 273 return fBusManagers.ElementAt(index); 274 } 275 276 277 status_t 278 Stack::AllocateChunk(void **logicalAddress, phys_addr_t *physicalAddress, 279 size_t size) 280 { 281 return fAllocator->Allocate(size, logicalAddress, physicalAddress); 282 } 283 284 285 status_t 286 Stack::FreeChunk(void *logicalAddress, phys_addr_t physicalAddress, 287 size_t size) 288 { 289 return fAllocator->Deallocate(size, logicalAddress, physicalAddress); 290 } 291 292 293 area_id 294 Stack::AllocateArea(void **logicalAddress, phys_addr_t *physicalAddress, size_t size, 295 const char *name) 296 { 297 TRACE("allocating %ld bytes for %s\n", size, name); 298 299 void *logAddress; 300 size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 301 area_id area = create_area(name, &logAddress, B_ANY_KERNEL_ADDRESS, size, 302 B_32_BIT_CONTIGUOUS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 303 // TODO: Use B_CONTIGUOUS when the TODOs regarding 64 bit physical 304 // addresses are fixed (if possible). 305 306 if (area < B_OK) { 307 TRACE_ERROR("couldn't allocate area %s\n", name); 308 return B_ERROR; 309 } 310 311 physical_entry physicalEntry; 312 status_t result = get_memory_map(logAddress, size, &physicalEntry, 1); 313 if (result < B_OK) { 314 delete_area(area); 315 TRACE_ERROR("couldn't map area %s\n", name); 316 return B_ERROR; 317 } 318 319 memset(logAddress, 0, size); 320 if (logicalAddress) 321 *logicalAddress = logAddress; 322 323 if (physicalAddress) 324 *physicalAddress = (phys_addr_t)physicalEntry.address; 325 326 TRACE("area = %" B_PRId32 ", size = %" B_PRIuSIZE ", log = %p, phy = %#" 327 B_PRIxPHYSADDR "\n", area, size, logAddress, physicalEntry.address); 328 return area; 329 } 330 331 332 void 333 Stack::NotifyDeviceChange(Device *device, rescan_item **rescanList, bool added) 334 { 335 TRACE("device %s\n", added ? "added" : "removed"); 336 337 usb_driver_info *element = fDriverList; 338 while (element) { 339 status_t result = device->ReportDevice(element->support_descriptors, 340 element->support_descriptor_count, &element->notify_hooks, 341 &element->cookies, added, false); 342 343 if (result >= B_OK) { 344 const char *driverName = element->driver_name; 345 if (element->republish_driver_name) 346 driverName = element->republish_driver_name; 347 348 bool already = false; 349 rescan_item *rescanItem = *rescanList; 350 while (rescanItem) { 351 if (strcmp(rescanItem->name, driverName) == 0) { 352 // this driver is going to be rescanned already 353 already = true; 354 break; 355 } 356 rescanItem = rescanItem->link; 357 } 358 359 if (!already) { 360 rescanItem = new(std::nothrow) rescan_item; 361 if (!rescanItem) 362 return; 363 364 rescanItem->name = driverName; 365 rescanItem->link = *rescanList; 366 *rescanList = rescanItem; 367 } 368 } 369 370 element = element->link; 371 } 372 } 373 374 375 void 376 Stack::RescanDrivers(rescan_item *rescanItem) 377 { 378 while (rescanItem) { 379 // the device is supported by this driver. it either got notified 380 // already by the hooks or it is not loaded at this time. in any 381 // case we will rescan the driver so it either is loaded and can 382 // scan for supported devices or its publish_devices hook will be 383 // called to expose changed devices. 384 385 // use the private devfs API to republish a device 386 devfs_rescan_driver(rescanItem->name); 387 388 rescan_item *next = rescanItem->link; 389 delete rescanItem; 390 rescanItem = next; 391 } 392 } 393 394 395 status_t 396 Stack::RegisterDriver(const char *driverName, 397 const usb_support_descriptor *descriptors, 398 size_t descriptorCount, const char *republishDriverName) 399 { 400 TRACE("register driver \"%s\"\n", driverName); 401 if (!driverName) 402 return B_BAD_VALUE; 403 404 if (!Lock()) 405 return B_ERROR; 406 407 usb_driver_info *element = fDriverList; 408 while (element) { 409 if (strcmp(element->driver_name, driverName) == 0) { 410 // we already have an entry for this driver, just update it 411 free((char *)element->republish_driver_name); 412 element->republish_driver_name = strdup(republishDriverName); 413 414 free(element->support_descriptors); 415 size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor); 416 element->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize); 417 memcpy(element->support_descriptors, descriptors, descriptorsSize); 418 element->support_descriptor_count = descriptorCount; 419 420 Unlock(); 421 return B_OK; 422 } 423 424 element = element->link; 425 } 426 427 // this is a new driver, add it to the driver list 428 usb_driver_info *info = new(std::nothrow) usb_driver_info; 429 if (!info) { 430 Unlock(); 431 return B_NO_MEMORY; 432 } 433 434 info->driver_name = strdup(driverName); 435 info->republish_driver_name = strdup(republishDriverName); 436 437 size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor); 438 info->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize); 439 memcpy(info->support_descriptors, descriptors, descriptorsSize); 440 info->support_descriptor_count = descriptorCount; 441 442 info->notify_hooks.device_added = NULL; 443 info->notify_hooks.device_removed = NULL; 444 info->cookies = NULL; 445 info->link = NULL; 446 447 if (fDriverList) { 448 usb_driver_info *element = fDriverList; 449 while (element->link) 450 element = element->link; 451 452 element->link = info; 453 } else 454 fDriverList = info; 455 456 Unlock(); 457 return B_OK; 458 } 459 460 461 status_t 462 Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks) 463 { 464 TRACE("installing notify hooks for driver \"%s\"\n", driverName); 465 466 usb_driver_info *element = fDriverList; 467 while (element) { 468 if (strcmp(element->driver_name, driverName) == 0) { 469 if (mutex_lock(&fExploreLock) != B_OK) 470 return B_ERROR; 471 472 // inform driver about any already present devices 473 for (int32 i = 0; i < fBusManagers.Count(); i++) { 474 Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub(); 475 if (rootHub) { 476 // Report device will recurse down the whole tree 477 rootHub->ReportDevice(element->support_descriptors, 478 element->support_descriptor_count, hooks, 479 &element->cookies, true, true); 480 } 481 } 482 483 element->notify_hooks.device_added = hooks->device_added; 484 element->notify_hooks.device_removed = hooks->device_removed; 485 mutex_unlock(&fExploreLock); 486 return B_OK; 487 } 488 489 element = element->link; 490 } 491 492 return B_NAME_NOT_FOUND; 493 } 494 495 496 status_t 497 Stack::UninstallNotify(const char *driverName) 498 { 499 TRACE("uninstalling notify hooks for driver \"%s\"\n", driverName); 500 501 usb_driver_info *element = fDriverList; 502 while (element) { 503 if (strcmp(element->driver_name, driverName) == 0) { 504 if (mutex_lock(&fExploreLock) != B_OK) 505 return B_ERROR; 506 507 // trigger the device removed hook 508 for (int32 i = 0; i < fBusManagers.Count(); i++) { 509 Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub(); 510 if (rootHub) 511 rootHub->ReportDevice(element->support_descriptors, 512 element->support_descriptor_count, 513 &element->notify_hooks, &element->cookies, false, true); 514 } 515 516 element->notify_hooks.device_added = NULL; 517 element->notify_hooks.device_removed = NULL; 518 mutex_unlock(&fExploreLock); 519 return B_OK; 520 } 521 522 element = element->link; 523 } 524 525 return B_NAME_NOT_FOUND; 526 } 527 528