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 memset(fObjectArray, 0, objectArraySize); 37 38 fAllocator = new(std::nothrow) PhysicalMemoryAllocator("USB Stack Allocator", 39 8, B_PAGE_SIZE * 4, 64); 40 if (!fAllocator || fAllocator->InitCheck() < B_OK) { 41 TRACE_ERROR(("USB Stack: failed to allocate the allocator\n")); 42 delete fAllocator; 43 fAllocator = NULL; 44 return; 45 } 46 47 // Check for host controller modules 48 // While using a fixed list of names is inflexible it allows us to control 49 // the order in which we try modules. There are controllers/BIOSes that 50 // require UHCI/OHCI to be initialized before EHCI or otherwise they 51 // refuse to publish any high-speed devices. 52 // On other systems the ordering is probably ensured because the EHCI 53 // controller is required to have a higher PCI function number than the 54 // companion host controllers (per the EHCI specs) and it would therefore 55 // be enumerated as the last item. As this does not apply to us we have to 56 // ensure ordering using another method. 57 const char *moduleNames[] = { 58 "busses/usb/uhci", 59 "busses/usb/ohci", 60 "busses/usb/ehci", 61 NULL 62 }; 63 64 TRACE(("USB Stack: looking for host controller modules\n")); 65 for (uint32 i = 0; moduleNames[i]; i++) { 66 TRACE(("USB Stack: looking for module %s\n", moduleNames[i])); 67 68 usb_host_controller_info *module = NULL; 69 if (get_module(moduleNames[i], (module_info **)&module) != B_OK) 70 continue; 71 72 TRACE(("USB Stack: adding module %s\n", moduleNames[i])); 73 if (module->add_to(this) < B_OK) 74 continue; 75 76 TRACE(("USB Stack: module %s successfully loaded\n", moduleNames[i])); 77 } 78 79 if (fBusManagers.Count() == 0) { 80 TRACE_ERROR(("USB Stack: no bus managers available\n")); 81 return; 82 } 83 84 fExploreThread = spawn_kernel_thread(ExploreThread, "usb explore", 85 B_LOW_PRIORITY, this); 86 resume_thread(fExploreThread); 87 88 // wait for the first explore to complete. this ensures that a driver that 89 // is opening the module does not get rescanned while or before installing 90 // its hooks. 91 while (!fFirstExploreDone) 92 snooze(100000); 93 } 94 95 96 Stack::~Stack() 97 { 98 int32 result; 99 fStopThreads = true; 100 wait_for_thread(fExploreThread, &result); 101 102 mutex_lock(&fStackLock); 103 mutex_destroy(&fStackLock); 104 mutex_lock(&fExploreLock); 105 mutex_destroy(&fExploreLock); 106 107 //Release the bus modules 108 for (Vector<BusManager *>::Iterator i = fBusManagers.Begin(); 109 i != fBusManagers.End(); i++) { 110 delete (*i); 111 } 112 113 delete fAllocator; 114 } 115 116 117 status_t 118 Stack::InitCheck() 119 { 120 if (fBusManagers.Count() == 0) 121 return ENODEV; 122 return B_OK; 123 } 124 125 126 bool 127 Stack::Lock() 128 { 129 return (mutex_lock(&fStackLock) == B_OK); 130 } 131 132 133 void 134 Stack::Unlock() 135 { 136 mutex_unlock(&fStackLock); 137 } 138 139 140 usb_id 141 Stack::GetUSBID(Object *object) 142 { 143 if (!Lock()) 144 return 0; 145 146 uint32 id = fObjectIndex; 147 uint32 tries = fObjectMaxCount; 148 while (tries-- > 0) { 149 if (fObjectArray[id] == NULL) { 150 fObjectIndex = (id + 1) % fObjectMaxCount; 151 fObjectArray[id] = object; 152 Unlock(); 153 return (usb_id)id; 154 } 155 156 id = (id + 1) % fObjectMaxCount; 157 } 158 159 TRACE_ERROR(("USB Stack: the stack did run out of usb_ids\n")); 160 Unlock(); 161 return 0; 162 } 163 164 165 void 166 Stack::PutUSBID(usb_id id) 167 { 168 if (!Lock()) 169 return; 170 171 if (id >= fObjectMaxCount) { 172 TRACE_ERROR(("USB Stack: tried to put an invalid usb_id\n")); 173 Unlock(); 174 return; 175 } 176 177 fObjectArray[id] = NULL; 178 Unlock(); 179 } 180 181 182 Object * 183 Stack::GetObject(usb_id id) 184 { 185 if (!Lock()) 186 return NULL; 187 188 if (id >= fObjectMaxCount) { 189 TRACE_ERROR(("USB Stack: tried to get object with invalid usb_id\n")); 190 Unlock(); 191 return NULL; 192 } 193 194 Object *result = fObjectArray[id]; 195 196 Unlock(); 197 return result; 198 } 199 200 201 int32 202 Stack::ExploreThread(void *data) 203 { 204 Stack *stack = (Stack *)data; 205 206 while (!stack->fStopThreads) { 207 if (mutex_lock(&stack->fExploreLock) != B_OK) 208 break; 209 210 rescan_item *rescanList = NULL; 211 change_item *changeItem = NULL; 212 for (int32 i = 0; i < stack->fBusManagers.Count(); i++) { 213 Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub(); 214 if (rootHub) 215 rootHub->Explore(&changeItem); 216 } 217 218 while (changeItem) { 219 stack->NotifyDeviceChange(changeItem->device, &rescanList, changeItem->added); 220 if (!changeItem->added) { 221 // everyone possibly holding a reference is now notified so we 222 // can delete the device 223 changeItem->device->GetBusManager()->FreeDevice(changeItem->device); 224 } 225 226 change_item *next = changeItem->link; 227 delete changeItem; 228 changeItem = next; 229 } 230 231 stack->fFirstExploreDone = true; 232 mutex_unlock(&stack->fExploreLock); 233 stack->RescanDrivers(rescanList); 234 snooze(USB_DELAY_HUB_EXPLORE); 235 } 236 237 return B_OK; 238 } 239 240 241 void 242 Stack::AddBusManager(BusManager *busManager) 243 { 244 fBusManagers.PushBack(busManager); 245 } 246 247 248 int32 249 Stack::IndexOfBusManager(BusManager *busManager) 250 { 251 return fBusManagers.IndexOf(busManager); 252 } 253 254 255 BusManager * 256 Stack::BusManagerAt(int32 index) 257 { 258 return fBusManagers.ElementAt(index); 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_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 (mutex_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 mutex_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 (mutex_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 mutex_unlock(&fExploreLock); 507 return B_OK; 508 } 509 510 element = element->link; 511 } 512 513 return B_NAME_NOT_FOUND; 514 } 515