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