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