2 * Copyright 2003-2008, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Michael Lotz <mmlr@mlotz.ch>
12 #include <util/kernel_cpp.h>
13 #include "usb_private.h"
14 #include "PhysicalMemoryAllocator.h"
16 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
22 fFirstExploreDone(false),
26 fObjectMaxCount(1024),
30 TRACE("stack init\n");
32 mutex_init(&fStackLock
, "usb stack lock");
33 mutex_init(&fExploreLock
, "usb explore lock");
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");
42 memset(fObjectArray
, 0, objectArraySize
);
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");
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
[] = {
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
]);
74 usb_host_controller_info
*module
= NULL
;
75 if (get_module(moduleNames
[i
], (module_info
**)&module
) != B_OK
)
78 TRACE("adding module %s\n", moduleNames
[i
]);
79 if (module
->add_to(this) < B_OK
) {
80 put_module(moduleNames
[i
]);
84 TRACE("module %s successfully loaded\n", moduleNames
[i
]);
87 if (fBusManagers
.Count() == 0) {
88 TRACE_ERROR("no bus managers available\n");
92 fExploreThread
= spawn_kernel_thread(ExploreThread
, "usb explore",
93 B_LOW_PRIORITY
, this);
94 resume_thread(fExploreThread
);
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
99 while (!fFirstExploreDone
)
108 wait_for_thread(fExploreThread
, &result
);
110 mutex_lock(&fStackLock
);
111 mutex_destroy(&fStackLock
);
112 mutex_lock(&fExploreLock
);
113 mutex_destroy(&fExploreLock
);
115 // Release the bus modules
116 for (Vector
<BusManager
*>::Iterator i
= fBusManagers
.Begin();
117 i
!= fBusManagers
.End(); i
++) {
129 if (fBusManagers
.Count() == 0)
138 return (mutex_lock(&fStackLock
) == B_OK
);
145 mutex_unlock(&fStackLock
);
150 Stack::GetUSBID(Object
*object
)
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
;
165 id
= (id
+ 1) % fObjectMaxCount
;
168 TRACE_ERROR("the stack did run out of usb_ids\n");
175 Stack::PutUSBID(usb_id id
)
180 if (id
>= fObjectMaxCount
) {
181 TRACE_ERROR("tried to put an invalid usb_id\n");
186 fObjectArray
[id
] = NULL
;
192 Stack::GetObject(usb_id id
)
197 if (id
>= fObjectMaxCount
) {
198 TRACE_ERROR("tried to get object with invalid usb_id\n");
203 Object
*result
= fObjectArray
[id
];
211 Stack::GetObjectNoLock(usb_id id
) const
213 if (id
>= fObjectMaxCount
)
215 return fObjectArray
[id
];
220 Stack::ExploreThread(void *data
)
222 Stack
*stack
= (Stack
*)data
;
224 while (!stack
->fStopThreads
) {
225 if (mutex_lock(&stack
->fExploreLock
) != B_OK
)
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();
233 rootHub
->Explore(&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
);
244 change_item
*next
= changeItem
->link
;
249 stack
->fFirstExploreDone
= true;
250 mutex_unlock(&stack
->fExploreLock
);
251 stack
->RescanDrivers(rescanList
);
252 snooze(USB_DELAY_HUB_EXPLORE
);
260 Stack::AddBusManager(BusManager
*busManager
)
262 fBusManagers
.PushBack(busManager
);
267 Stack::IndexOfBusManager(BusManager
*busManager
)
269 return fBusManagers
.IndexOf(busManager
);
274 Stack::BusManagerAt(int32 index
) const
276 return fBusManagers
.ElementAt(index
);
281 Stack::AllocateChunk(void **logicalAddress
, void **physicalAddress
, size_t size
)
283 return fAllocator
->Allocate(size
, logicalAddress
, physicalAddress
);
288 Stack::FreeChunk(void *logicalAddress
, void *physicalAddress
, size_t size
)
290 return fAllocator
->Deallocate(size
, logicalAddress
, physicalAddress
);
295 Stack::AllocateArea(void **logicalAddress
, void **physicalAddress
, size_t size
,
298 // TODO: physicalAddress should be a phys_addr_t*!
299 TRACE("allocating %ld bytes for %s\n", size
, name
);
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).
309 TRACE_ERROR("couldn't allocate area %s\n", name
);
313 physical_entry physicalEntry
;
314 status_t result
= get_memory_map(logAddress
, size
, &physicalEntry
, 1);
317 TRACE_ERROR("couldn't map area %s\n", name
);
321 memset(logAddress
, 0, size
);
323 *logicalAddress
= logAddress
;
326 *physicalAddress
= (void*)(addr_t
)physicalEntry
.address
;
328 TRACE("area = %ld, size = %ld, log = %p, phy = %#" B_PRIxPHYSADDR
"\n",
329 area
, size
, logAddress
, physicalEntry
.address
);
335 Stack::NotifyDeviceChange(Device
*device
, rescan_item
**rescanList
, bool added
)
337 TRACE("device %s\n", added
? "added" : "removed");
339 usb_driver_info
*element
= fDriverList
;
341 status_t result
= device
->ReportDevice(element
->support_descriptors
,
342 element
->support_descriptor_count
, &element
->notify_hooks
,
343 &element
->cookies
, added
, false);
345 if (result
>= B_OK
) {
346 const char *driverName
= element
->driver_name
;
347 if (element
->republish_driver_name
)
348 driverName
= element
->republish_driver_name
;
350 bool already
= false;
351 rescan_item
*rescanItem
= *rescanList
;
353 if (strcmp(rescanItem
->name
, driverName
) == 0) {
354 // this driver is going to be rescanned already
358 rescanItem
= rescanItem
->link
;
362 rescanItem
= new(std::nothrow
) rescan_item
;
366 rescanItem
->name
= driverName
;
367 rescanItem
->link
= *rescanList
;
368 *rescanList
= rescanItem
;
372 element
= element
->link
;
378 Stack::RescanDrivers(rescan_item
*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.
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
));
393 // use the private devfs API under Haiku
394 devfs_rescan_driver(rescanItem
->name
);
397 rescan_item
*next
= rescanItem
->link
;
405 Stack::RegisterDriver(const char *driverName
,
406 const usb_support_descriptor
*descriptors
,
407 size_t descriptorCount
, const char *republishDriverName
)
409 TRACE("register driver \"%s\"\n", driverName
);
416 usb_driver_info
*element
= fDriverList
;
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
);
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
;
433 element
= element
->link
;
436 // this is a new driver, add it to the driver list
437 usb_driver_info
*info
= new(std::nothrow
) usb_driver_info
;
443 info
->driver_name
= strdup(driverName
);
444 info
->republish_driver_name
= strdup(republishDriverName
);
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
;
451 info
->notify_hooks
.device_added
= NULL
;
452 info
->notify_hooks
.device_removed
= NULL
;
453 info
->cookies
= NULL
;
457 usb_driver_info
*element
= fDriverList
;
458 while (element
->link
)
459 element
= element
->link
;
461 element
->link
= info
;
471 Stack::InstallNotify(const char *driverName
, const usb_notify_hooks
*hooks
)
473 TRACE("installing notify hooks for driver \"%s\"\n", driverName
);
475 usb_driver_info
*element
= fDriverList
;
477 if (strcmp(element
->driver_name
, driverName
) == 0) {
478 if (mutex_lock(&fExploreLock
) != B_OK
)
481 // inform driver about any already present devices
482 for (int32 i
= 0; i
< fBusManagers
.Count(); i
++) {
483 Hub
*rootHub
= fBusManagers
.ElementAt(i
)->GetRootHub();
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);
492 element
->notify_hooks
.device_added
= hooks
->device_added
;
493 element
->notify_hooks
.device_removed
= hooks
->device_removed
;
494 mutex_unlock(&fExploreLock
);
498 element
= element
->link
;
501 return B_NAME_NOT_FOUND
;
506 Stack::UninstallNotify(const char *driverName
)
508 TRACE("uninstalling notify hooks for driver \"%s\"\n", driverName
);
510 usb_driver_info
*element
= fDriverList
;
512 if (strcmp(element
->driver_name
, driverName
) == 0) {
513 if (mutex_lock(&fExploreLock
) != B_OK
)
516 // trigger the device removed hook
517 for (int32 i
= 0; i
< fBusManagers
.Count(); i
++) {
518 Hub
*rootHub
= fBusManagers
.ElementAt(i
)->GetRootHub();
520 rootHub
->ReportDevice(element
->support_descriptors
,
521 element
->support_descriptor_count
,
522 &element
->notify_hooks
, &element
->cookies
, false, true);
525 element
->notify_hooks
.device_added
= NULL
;
526 element
->notify_hooks
.device_removed
= NULL
;
527 mutex_unlock(&fExploreLock
);
531 element
= element
->link
;
534 return B_NAME_NOT_FOUND
;