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