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