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