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 #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 mutex_init(&fStackLock, "usb stack lock"); 32 mutex_init(&fExploreLock, "usb explore lock"); 33 34 size_t objectArraySize = fObjectMaxCount * sizeof(Object *); 35 fObjectArray = (Object **)malloc(objectArraySize); 36 if (fObjectArray == NULL) { 37 TRACE_ERROR(("USB Stack: failed to allocate object array\n")); 38 return; 39 } 40 41 memset(fObjectArray, 0, objectArraySize); 42 43 fAllocator = new(std::nothrow) PhysicalMemoryAllocator("USB Stack Allocator", 44 8, B_PAGE_SIZE * 4, 64); 45 if (!fAllocator || fAllocator->InitCheck() < B_OK) { 46 TRACE_ERROR(("USB Stack: failed to allocate the allocator\n")); 47 delete fAllocator; 48 fAllocator = NULL; 49 return; 50 } 51 52 // Check for host controller modules 53 // While using a fixed list of names is inflexible it allows us to control 54 // the order in which we try modules. There are controllers/BIOSes that 55 // require UHCI/OHCI to be initialized before EHCI or otherwise they 56 // refuse to publish any high-speed devices. 57 // On other systems the ordering is probably ensured because the EHCI 58 // controller is required to have a higher PCI function number than the 59 // companion host controllers (per the EHCI specs) and it would therefore 60 // be enumerated as the last item. As this does not apply to us we have to 61 // ensure ordering using another method. 62 const char *moduleNames[] = { 63 "busses/usb/uhci", 64 "busses/usb/ohci", 65 "busses/usb/ehci", 66 NULL 67 }; 68 69 TRACE(("USB Stack: looking for host controller modules\n")); 70 for (uint32 i = 0; moduleNames[i]; i++) { 71 TRACE(("USB Stack: looking for module %s\n", moduleNames[i])); 72 73 usb_host_controller_info *module = NULL; 74 if (get_module(moduleNames[i], (module_info **)&module) != B_OK) 75 continue; 76 77 TRACE(("USB Stack: adding module %s\n", moduleNames[i])); 78 if (module->add_to(this) < B_OK) { 79 put_module(moduleNames[i]); 80 continue; 81 } 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 mutex_lock(&fStackLock); 110 mutex_destroy(&fStackLock); 111 mutex_lock(&fExploreLock); 112 mutex_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 free(fObjectArray); 122 } 123 124 125 status_t 126 Stack::InitCheck() 127 { 128 if (fBusManagers.Count() == 0) 129 return ENODEV; 130 return B_OK; 131 } 132 133 134 bool 135 Stack::Lock() 136 { 137 return (mutex_lock(&fStackLock) == B_OK); 138 } 139 140 141 void 142 Stack::Unlock() 143 { 144 mutex_unlock(&fStackLock); 145 } 146 147 148 usb_id 149 Stack::GetUSBID(Object *object) 150 { 151 if (!Lock()) 152 return 0; 153 154 uint32 id = fObjectIndex; 155 uint32 tries = fObjectMaxCount; 156 while (tries-- > 0) { 157 if (fObjectArray[id] == NULL) { 158 fObjectIndex = (id + 1) % fObjectMaxCount; 159 fObjectArray[id] = object; 160 Unlock(); 161 return (usb_id)id; 162 } 163 164 id = (id + 1) % fObjectMaxCount; 165 } 166 167 TRACE_ERROR(("USB Stack: the stack did run out of usb_ids\n")); 168 Unlock(); 169 return 0; 170 } 171 172 173 void 174 Stack::PutUSBID(usb_id id) 175 { 176 if (!Lock()) 177 return; 178 179 if (id >= fObjectMaxCount) { 180 TRACE_ERROR(("USB Stack: tried to put an invalid usb_id\n")); 181 Unlock(); 182 return; 183 } 184 185 fObjectArray[id] = NULL; 186 Unlock(); 187 } 188 189 190 Object * 191 Stack::GetObject(usb_id id) 192 { 193 if (!Lock()) 194 return NULL; 195 196 if (id >= fObjectMaxCount) { 197 TRACE_ERROR(("USB Stack: tried to get object with invalid usb_id\n")); 198 Unlock(); 199 return NULL; 200 } 201 202 Object *result = fObjectArray[id]; 203 204 Unlock(); 205 return result; 206 } 207 208 209 int32 210 Stack::ExploreThread(void *data) 211 { 212 Stack *stack = (Stack *)data; 213 214 while (!stack->fStopThreads) { 215 if (mutex_lock(&stack->fExploreLock) != B_OK) 216 break; 217 218 rescan_item *rescanList = NULL; 219 change_item *changeItem = NULL; 220 for (int32 i = 0; i < stack->fBusManagers.Count(); i++) { 221 Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub(); 222 if (rootHub) 223 rootHub->Explore(&changeItem); 224 } 225 226 while (changeItem) { 227 stack->NotifyDeviceChange(changeItem->device, &rescanList, changeItem->added); 228 if (!changeItem->added) { 229 // everyone possibly holding a reference is now notified so we 230 // can delete the device 231 changeItem->device->GetBusManager()->FreeDevice(changeItem->device); 232 } 233 234 change_item *next = changeItem->link; 235 delete changeItem; 236 changeItem = next; 237 } 238 239 stack->fFirstExploreDone = true; 240 mutex_unlock(&stack->fExploreLock); 241 stack->RescanDrivers(rescanList); 242 snooze(USB_DELAY_HUB_EXPLORE); 243 } 244 245 return B_OK; 246 } 247 248 249 void 250 Stack::AddBusManager(BusManager *busManager) 251 { 252 fBusManagers.PushBack(busManager); 253 } 254 255 256 int32 257 Stack::IndexOfBusManager(BusManager *busManager) 258 { 259 return fBusManagers.IndexOf(busManager); 260 } 261 262 263 BusManager * 264 Stack::BusManagerAt(int32 index) 265 { 266 return fBusManagers.ElementAt(index); 267 } 268 269 270 status_t 271 Stack::AllocateChunk(void **logicalAddress, void **physicalAddress, size_t size) 272 { 273 return fAllocator->Allocate(size, logicalAddress, physicalAddress); 274 } 275 276 277 status_t 278 Stack::FreeChunk(void *logicalAddress, void *physicalAddress, size_t size) 279 { 280 return fAllocator->Deallocate(size, logicalAddress, physicalAddress); 281 } 282 283 284 area_id 285 Stack::AllocateArea(void **logicalAddress, void **physicalAddress, size_t size, 286 const char *name) 287 { 288 TRACE(("USB Stack: allocating %ld bytes for %s\n", size, name)); 289 290 void *logAddress; 291 size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 292 area_id area = create_area(name, &logAddress, B_ANY_KERNEL_ADDRESS, size, 293 B_CONTIGUOUS, 0); 294 295 if (area < B_OK) { 296 TRACE_ERROR(("USB Stack: couldn't allocate area %s\n", name)); 297 return B_ERROR; 298 } 299 300 physical_entry physicalEntry; 301 status_t result = get_memory_map(logAddress, size, &physicalEntry, 1); 302 if (result < B_OK) { 303 delete_area(area); 304 TRACE_ERROR(("USB Stack: couldn't map area %s\n", name)); 305 return B_ERROR; 306 } 307 308 memset(logAddress, 0, size); 309 if (logicalAddress) 310 *logicalAddress = logAddress; 311 312 if (physicalAddress) 313 *physicalAddress = physicalEntry.address; 314 315 TRACE(("USB Stack: area = 0x%08lx, size = %ld, log = 0x%08lx, phy = 0x%08lx\n", 316 area, size, logAddress, physicalEntry.address)); 317 return area; 318 } 319 320 321 void 322 Stack::NotifyDeviceChange(Device *device, rescan_item **rescanList, bool added) 323 { 324 TRACE(("USB Stack: device %s\n", added ? "added" : "removed")); 325 326 usb_driver_info *element = fDriverList; 327 while (element) { 328 status_t result = device->ReportDevice(element->support_descriptors, 329 element->support_descriptor_count, &element->notify_hooks, 330 &element->cookies, added, false); 331 332 if (result >= B_OK) { 333 const char *driverName = element->driver_name; 334 if (element->republish_driver_name) 335 driverName = element->republish_driver_name; 336 337 bool already = false; 338 rescan_item *rescanItem = *rescanList; 339 while (rescanItem) { 340 if (strcmp(rescanItem->name, driverName) == 0) { 341 // this driver is going to be rescanned already 342 already = true; 343 break; 344 } 345 rescanItem = rescanItem->link; 346 } 347 348 if (!already) { 349 rescanItem = new(std::nothrow) rescan_item; 350 if (!rescanItem) 351 return; 352 353 rescanItem->name = driverName; 354 rescanItem->link = *rescanList; 355 *rescanList = rescanItem; 356 } 357 } 358 359 element = element->link; 360 } 361 } 362 363 364 void 365 Stack::RescanDrivers(rescan_item *rescanItem) 366 { 367 while (rescanItem) { 368 // the device is supported by this driver. it either got notified 369 // already by the hooks or it is not loaded at this time. in any 370 // case we will rescan the driver so it either is loaded and can 371 // scan for supported devices or its publish_devices hook will be 372 // called to expose changed devices. 373 374 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 375 // the R5 way to republish a device in devfs 376 int devFS = open("/dev", O_WRONLY); 377 write(devFS, rescanItem->name, strlen(rescanItem->name)); 378 close(devFS); 379 #else 380 // use the private devfs API under Haiku 381 devfs_rescan_driver(rescanItem->name); 382 #endif 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(("USB Stack: 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(("USB Stack: 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(("USB Stack: 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