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