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