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