Completely redesign the USB explore process. Replaces the scary race conditions of the previous locking mechanism and simplifies handling of device changes by a more centralized approach.
Changes are now collected during explore and notifications as well as rescans are done at once. Through this a driver is also not rescanned multiple times anymore. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22929 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
d3625d72ed
commit
13508e8bd0
@ -269,7 +269,7 @@ BusManager::SubmitTransfer(Transfer *transfer)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BusManager::CancelQueuedTransfers(Pipe *pipe)
|
BusManager::CancelQueuedTransfers(Pipe *pipe, bool force)
|
||||||
{
|
{
|
||||||
// virtual function to be overridden
|
// virtual function to be overridden
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
@ -15,6 +15,7 @@ Device::Device(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
|
|||||||
: Object(parent),
|
: Object(parent),
|
||||||
fDeviceDescriptor(desc),
|
fDeviceDescriptor(desc),
|
||||||
fInitOK(false),
|
fInitOK(false),
|
||||||
|
fAvailable(true),
|
||||||
fConfigurations(NULL),
|
fConfigurations(NULL),
|
||||||
fCurrentConfiguration(NULL),
|
fCurrentConfiguration(NULL),
|
||||||
fSpeed(speed),
|
fSpeed(speed),
|
||||||
@ -252,10 +253,29 @@ Device::InitCheck()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Device::Changed(change_item **changeList, bool added)
|
||||||
|
{
|
||||||
|
fAvailable = added;
|
||||||
|
change_item *changeItem = new(std::nothrow) change_item;
|
||||||
|
if (!changeItem)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
changeItem->added = added;
|
||||||
|
changeItem->device = this;
|
||||||
|
changeItem->link = *changeList;
|
||||||
|
*changeList = changeItem;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Device::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
|
Device::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
|
||||||
void *data, size_t dataLength, size_t *actualLength)
|
void *data, size_t dataLength, size_t *actualLength)
|
||||||
{
|
{
|
||||||
|
if (!fAvailable)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
return fDefaultPipe->SendRequest(
|
return fDefaultPipe->SendRequest(
|
||||||
USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type
|
USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type
|
||||||
USB_REQUEST_GET_DESCRIPTOR, // request
|
USB_REQUEST_GET_DESCRIPTOR, // request
|
||||||
@ -304,6 +324,8 @@ Device::SetConfiguration(const usb_configuration_info *configuration)
|
|||||||
status_t
|
status_t
|
||||||
Device::SetConfigurationAt(uint8 index)
|
Device::SetConfigurationAt(uint8 index)
|
||||||
{
|
{
|
||||||
|
if (!fAvailable)
|
||||||
|
return B_ERROR;
|
||||||
if (index >= fDeviceDescriptor.num_configurations)
|
if (index >= fDeviceDescriptor.num_configurations)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
if (&fConfigurations[index] == fCurrentConfiguration)
|
if (&fConfigurations[index] == fCurrentConfiguration)
|
||||||
@ -382,7 +404,7 @@ Device::Unconfigure(bool atDeviceLevel)
|
|||||||
// another configuration unconfigure will be called with
|
// another configuration unconfigure will be called with
|
||||||
// atDevice = false. otherwise we explicitly want to unconfigure
|
// atDevice = false. otherwise we explicitly want to unconfigure
|
||||||
// the device and have to send it the corresponding request.
|
// the device and have to send it the corresponding request.
|
||||||
if (atDeviceLevel) {
|
if (atDeviceLevel && fAvailable) {
|
||||||
status_t result = fDefaultPipe->SendRequest(
|
status_t result = fDefaultPipe->SendRequest(
|
||||||
USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD, // type
|
USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD, // type
|
||||||
USB_REQUEST_SET_CONFIGURATION, // request
|
USB_REQUEST_SET_CONFIGURATION, // request
|
||||||
@ -426,7 +448,7 @@ Device::DeviceDescriptor() const
|
|||||||
status_t
|
status_t
|
||||||
Device::ReportDevice(usb_support_descriptor *supportDescriptors,
|
Device::ReportDevice(usb_support_descriptor *supportDescriptors,
|
||||||
uint32 supportDescriptorCount, const usb_notify_hooks *hooks,
|
uint32 supportDescriptorCount, const usb_notify_hooks *hooks,
|
||||||
usb_driver_cookie **cookies, bool added)
|
usb_driver_cookie **cookies, bool added, bool recursive)
|
||||||
{
|
{
|
||||||
TRACE(("USB Device %d: reporting device\n", fDeviceAddress));
|
TRACE(("USB Device %d: reporting device\n", fDeviceAddress));
|
||||||
bool supported = false;
|
bool supported = false;
|
||||||
@ -526,6 +548,9 @@ Device::BuildDeviceName(char *string, uint32 *index, size_t bufferSize,
|
|||||||
status_t
|
status_t
|
||||||
Device::SetFeature(uint16 selector)
|
Device::SetFeature(uint16 selector)
|
||||||
{
|
{
|
||||||
|
if (!fAvailable)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
return fDefaultPipe->SendRequest(
|
return fDefaultPipe->SendRequest(
|
||||||
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
|
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
|
||||||
USB_REQUEST_SET_FEATURE,
|
USB_REQUEST_SET_FEATURE,
|
||||||
@ -541,6 +566,9 @@ Device::SetFeature(uint16 selector)
|
|||||||
status_t
|
status_t
|
||||||
Device::ClearFeature(uint16 selector)
|
Device::ClearFeature(uint16 selector)
|
||||||
{
|
{
|
||||||
|
if (!fAvailable)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
return fDefaultPipe->SendRequest(
|
return fDefaultPipe->SendRequest(
|
||||||
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
|
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
|
||||||
USB_REQUEST_CLEAR_FEATURE,
|
USB_REQUEST_CLEAR_FEATURE,
|
||||||
@ -556,6 +584,9 @@ Device::ClearFeature(uint16 selector)
|
|||||||
status_t
|
status_t
|
||||||
Device::GetStatus(uint16 *status)
|
Device::GetStatus(uint16 *status)
|
||||||
{
|
{
|
||||||
|
if (!fAvailable)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
return fDefaultPipe->SendRequest(
|
return fDefaultPipe->SendRequest(
|
||||||
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_IN,
|
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_IN,
|
||||||
USB_REQUEST_GET_STATUS,
|
USB_REQUEST_GET_STATUS,
|
||||||
|
@ -30,11 +30,6 @@ Hub::Hub(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
|
|||||||
// Set to false again for the hub init.
|
// Set to false again for the hub init.
|
||||||
fInitOK = false;
|
fInitOK = false;
|
||||||
|
|
||||||
if (benaphore_init(&fLock, "usb hub lock") < B_OK) {
|
|
||||||
TRACE_ERROR(("USB Hub %d: failed to create hub lock\n", DeviceAddress()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fDeviceDescriptor.device_class != 9) {
|
if (fDeviceDescriptor.device_class != 9) {
|
||||||
TRACE_ERROR(("USB Hub %d: wrong class! bailing out\n", DeviceAddress()));
|
TRACE_ERROR(("USB Hub %d: wrong class! bailing out\n", DeviceAddress()));
|
||||||
return;
|
return;
|
||||||
@ -97,36 +92,26 @@ Hub::Hub(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
|
|||||||
|
|
||||||
Hub::~Hub()
|
Hub::~Hub()
|
||||||
{
|
{
|
||||||
Lock();
|
|
||||||
benaphore_destroy(&fLock);
|
|
||||||
|
|
||||||
// Remove all child devices
|
|
||||||
for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
|
|
||||||
if (!fChildren[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i]));
|
|
||||||
rescan_item *rescanList = NULL;
|
|
||||||
GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false);
|
|
||||||
GetBusManager()->FreeDevice(fChildren[i]);
|
|
||||||
GetStack()->RescanDrivers(rescanList);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete fInterruptPipe;
|
delete fInterruptPipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
status_t
|
||||||
Hub::Lock()
|
Hub::Changed(change_item **changeList, bool added)
|
||||||
{
|
{
|
||||||
return (benaphore_lock(&fLock) == B_OK);
|
status_t result = Device::Changed(changeList, added);
|
||||||
}
|
if (added || result < B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
|
||||||
|
if (fChildren[i] == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
void
|
fChildren[i]->Changed(changeList, false);
|
||||||
Hub::Unlock()
|
fChildren[i] = NULL;
|
||||||
{
|
}
|
||||||
benaphore_unlock(&fLock);
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -189,7 +174,7 @@ Hub::ResetPort(uint8 index)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Hub::Explore()
|
Hub::Explore(change_item **changeList)
|
||||||
{
|
{
|
||||||
for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
|
for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
|
||||||
status_t result = UpdatePortStatus(i);
|
status_t result = UpdatePortStatus(i);
|
||||||
@ -209,7 +194,6 @@ Hub::Explore()
|
|||||||
USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1,
|
USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1,
|
||||||
0, NULL, 0, NULL);
|
0, NULL, 0, NULL);
|
||||||
|
|
||||||
rescan_item *rescanList = NULL;
|
|
||||||
if (fPortStatus[i].status & PORT_STATUS_CONNECTION) {
|
if (fPortStatus[i].status & PORT_STATUS_CONNECTION) {
|
||||||
// new device attached!
|
// new device attached!
|
||||||
TRACE(("USB Hub %d: new device connected\n", DeviceAddress()));
|
TRACE(("USB Hub %d: new device connected\n", DeviceAddress()));
|
||||||
@ -234,18 +218,8 @@ Hub::Explore()
|
|||||||
|
|
||||||
if (fChildren[i]) {
|
if (fChildren[i]) {
|
||||||
TRACE_ERROR(("USB Hub %d: new device on a port that is already in use\n", DeviceAddress()));
|
TRACE_ERROR(("USB Hub %d: new device on a port that is already in use\n", DeviceAddress()));
|
||||||
|
fChildren[i]->Changed(changeList, false);
|
||||||
// Remove previous device first
|
fChildren[i] = NULL;
|
||||||
TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i]));
|
|
||||||
GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false);
|
|
||||||
|
|
||||||
if (Lock()) {
|
|
||||||
GetBusManager()->FreeDevice(fChildren[i]);
|
|
||||||
fChildren[i] = NULL;
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
GetStack()->RescanDrivers(rescanList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_speed speed = USB_SPEED_FULLSPEED;
|
usb_speed speed = USB_SPEED_FULLSPEED;
|
||||||
@ -256,15 +230,10 @@ Hub::Explore()
|
|||||||
|
|
||||||
Device *newDevice = GetBusManager()->AllocateDevice(this, speed);
|
Device *newDevice = GetBusManager()->AllocateDevice(this, speed);
|
||||||
|
|
||||||
if (newDevice && Lock()) {
|
if (newDevice) {
|
||||||
|
newDevice->Changed(changeList, true);
|
||||||
fChildren[i] = newDevice;
|
fChildren[i] = newDevice;
|
||||||
Unlock();
|
|
||||||
GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, true);
|
|
||||||
GetStack()->RescanDrivers(rescanList);
|
|
||||||
} else {
|
} else {
|
||||||
if (newDevice)
|
|
||||||
GetBusManager()->FreeDevice(newDevice);
|
|
||||||
|
|
||||||
// the device failed to setup correctly, disable the port
|
// the device failed to setup correctly, disable the port
|
||||||
// so that the device doesn't get in the way of future
|
// so that the device doesn't get in the way of future
|
||||||
// addressing.
|
// addressing.
|
||||||
@ -277,15 +246,8 @@ Hub::Explore()
|
|||||||
TRACE(("USB Hub %d: device removed\n", DeviceAddress()));
|
TRACE(("USB Hub %d: device removed\n", DeviceAddress()));
|
||||||
if (fChildren[i]) {
|
if (fChildren[i]) {
|
||||||
TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i]));
|
TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i]));
|
||||||
GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false);
|
fChildren[i]->Changed(changeList, false);
|
||||||
|
fChildren[i] = NULL;
|
||||||
if (Lock()) {
|
|
||||||
GetBusManager()->FreeDevice(fChildren[i]);
|
|
||||||
fChildren[i] = NULL;
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
GetStack()->RescanDrivers(rescanList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -325,7 +287,7 @@ Hub::Explore()
|
|||||||
if (!fChildren[i] || (fChildren[i]->Type() & USB_OBJECT_HUB) == 0)
|
if (!fChildren[i] || (fChildren[i]->Type() & USB_OBJECT_HUB) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
((Hub *)fChildren[i])->Explore();
|
((Hub *)fChildren[i])->Explore(changeList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,28 +319,26 @@ Hub::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
|
|||||||
status_t
|
status_t
|
||||||
Hub::ReportDevice(usb_support_descriptor *supportDescriptors,
|
Hub::ReportDevice(usb_support_descriptor *supportDescriptors,
|
||||||
uint32 supportDescriptorCount, const usb_notify_hooks *hooks,
|
uint32 supportDescriptorCount, const usb_notify_hooks *hooks,
|
||||||
usb_driver_cookie **cookies, bool added)
|
usb_driver_cookie **cookies, bool added, bool recursive)
|
||||||
{
|
{
|
||||||
TRACE(("USB Hub %d: reporting hub\n", DeviceAddress()));
|
TRACE(("USB Hub %d: reporting hub\n", DeviceAddress()));
|
||||||
|
|
||||||
// Report ourselfs first
|
// Report ourselfs first
|
||||||
status_t result = Device::ReportDevice(supportDescriptors,
|
status_t result = Device::ReportDevice(supportDescriptors,
|
||||||
supportDescriptorCount, hooks, cookies, added);
|
supportDescriptorCount, hooks, cookies, added, recursive);
|
||||||
|
|
||||||
// Then report all of our children
|
if (!recursive)
|
||||||
if (!Lock())
|
return result;
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
|
for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
|
||||||
if (!fChildren[i])
|
if (!fChildren[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (fChildren[i]->ReportDevice(supportDescriptors,
|
if (fChildren[i]->ReportDevice(supportDescriptors,
|
||||||
supportDescriptorCount, hooks, cookies, added) == B_OK)
|
supportDescriptorCount, hooks, cookies, added, true) == B_OK)
|
||||||
result = B_OK;
|
result = B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Unlock();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ Pipe::Pipe(Object *parent, int8 deviceAddress, uint8 endpointAddress,
|
|||||||
|
|
||||||
Pipe::~Pipe()
|
Pipe::~Pipe()
|
||||||
{
|
{
|
||||||
CancelQueuedTransfers();
|
CancelQueuedTransfers(true);
|
||||||
GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED);
|
GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,9 +40,9 @@ Pipe::SubmitTransfer(Transfer *transfer)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Pipe::CancelQueuedTransfers()
|
Pipe::CancelQueuedTransfers(bool force)
|
||||||
{
|
{
|
||||||
return GetBusManager()->CancelQueuedTransfers(this);
|
return GetBusManager()->CancelQueuedTransfers(this, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -309,7 +309,7 @@ ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value,
|
|||||||
if (actualLength)
|
if (actualLength)
|
||||||
*actualLength = 0;
|
*actualLength = 0;
|
||||||
|
|
||||||
CancelQueuedTransfers();
|
CancelQueuedTransfers(false);
|
||||||
return B_TIMED_OUT;
|
return B_TIMED_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,13 @@ Stack::Stack()
|
|||||||
{
|
{
|
||||||
TRACE(("USB Stack: stack init\n"));
|
TRACE(("USB Stack: stack init\n"));
|
||||||
|
|
||||||
if (benaphore_init(&fLock, "usb stack lock") < B_OK) {
|
if (benaphore_init(&fStackLock, "usb stack lock") < B_OK) {
|
||||||
TRACE_ERROR(("USB Stack: failed to create benaphore lock\n"));
|
TRACE_ERROR(("USB Stack: failed to create stack lock\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (benaphore_init(&fExploreLock, "usb explore lock") < B_OK) {
|
||||||
|
TRACE_ERROR(("USB Stack: failed to create explore lock\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,8 +90,10 @@ Stack::~Stack()
|
|||||||
fStopThreads = true;
|
fStopThreads = true;
|
||||||
wait_for_thread(fExploreThread, &result);
|
wait_for_thread(fExploreThread, &result);
|
||||||
|
|
||||||
Lock();
|
benaphore_lock(&fStackLock);
|
||||||
benaphore_destroy(&fLock);
|
benaphore_destroy(&fStackLock);
|
||||||
|
benaphore_lock(&fExploreLock);
|
||||||
|
benaphore_destroy(&fExploreLock);
|
||||||
|
|
||||||
//Release the bus modules
|
//Release the bus modules
|
||||||
for (Vector<BusManager *>::Iterator i = fBusManagers.Begin();
|
for (Vector<BusManager *>::Iterator i = fBusManagers.Begin();
|
||||||
@ -111,14 +118,14 @@ Stack::InitCheck()
|
|||||||
bool
|
bool
|
||||||
Stack::Lock()
|
Stack::Lock()
|
||||||
{
|
{
|
||||||
return (benaphore_lock(&fLock) == B_OK);
|
return (benaphore_lock(&fStackLock) == B_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Stack::Unlock()
|
Stack::Unlock()
|
||||||
{
|
{
|
||||||
benaphore_unlock(&fLock);
|
benaphore_unlock(&fStackLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -189,13 +196,33 @@ Stack::ExploreThread(void *data)
|
|||||||
Stack *stack = (Stack *)data;
|
Stack *stack = (Stack *)data;
|
||||||
|
|
||||||
while (!stack->fStopThreads) {
|
while (!stack->fStopThreads) {
|
||||||
|
if (benaphore_lock(&stack->fExploreLock) != B_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
rescan_item *rescanList = NULL;
|
||||||
|
change_item *changeItem = NULL;
|
||||||
for (int32 i = 0; i < stack->fBusManagers.Count(); i++) {
|
for (int32 i = 0; i < stack->fBusManagers.Count(); i++) {
|
||||||
Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub();
|
Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub();
|
||||||
if (rootHub)
|
if (rootHub)
|
||||||
rootHub->Explore();
|
rootHub->Explore(&changeItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (changeItem) {
|
||||||
|
stack->NotifyDeviceChange(changeItem->device, &rescanList, changeItem->added);
|
||||||
|
if (!changeItem->added) {
|
||||||
|
// everyone possibly holding a reference is now notified so we
|
||||||
|
// can delete the device
|
||||||
|
changeItem->device->GetBusManager()->FreeDevice(changeItem->device);
|
||||||
|
}
|
||||||
|
|
||||||
|
change_item *next = changeItem->link;
|
||||||
|
delete changeItem;
|
||||||
|
changeItem = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack->fFirstExploreDone = true;
|
stack->fFirstExploreDone = true;
|
||||||
|
benaphore_unlock(&stack->fExploreLock);
|
||||||
|
stack->RescanDrivers(rescanList);
|
||||||
snooze(USB_DELAY_HUB_EXPLORE);
|
snooze(USB_DELAY_HUB_EXPLORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,19 +304,33 @@ Stack::NotifyDeviceChange(Device *device, rescan_item **rescanList, bool added)
|
|||||||
while (element) {
|
while (element) {
|
||||||
status_t result = device->ReportDevice(element->support_descriptors,
|
status_t result = device->ReportDevice(element->support_descriptors,
|
||||||
element->support_descriptor_count, &element->notify_hooks,
|
element->support_descriptor_count, &element->notify_hooks,
|
||||||
&element->cookies, added);
|
&element->cookies, added, false);
|
||||||
|
|
||||||
if (result >= B_OK) {
|
if (result >= B_OK) {
|
||||||
rescan_item *item = new(std::nothrow) rescan_item;
|
const char *driverName = element->driver_name;
|
||||||
if (!item)
|
|
||||||
return;
|
|
||||||
|
|
||||||
item->name = element->driver_name;
|
|
||||||
if (element->republish_driver_name)
|
if (element->republish_driver_name)
|
||||||
item->name = element->republish_driver_name;
|
driverName = element->republish_driver_name;
|
||||||
|
|
||||||
item->link = *rescanList;
|
bool already = false;
|
||||||
*rescanList = item;
|
rescan_item *rescanItem = *rescanList;
|
||||||
|
while (rescanItem) {
|
||||||
|
if (strcmp(rescanItem->name, driverName) == 0) {
|
||||||
|
// this driver is going to be rescanned already
|
||||||
|
already = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rescanItem = rescanItem->link;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!already) {
|
||||||
|
rescanItem = new(std::nothrow) rescan_item;
|
||||||
|
if (!rescanItem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rescanItem->name = driverName;
|
||||||
|
rescanItem->link = *rescanList;
|
||||||
|
*rescanList = rescanItem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
element = element->link;
|
element = element->link;
|
||||||
@ -403,6 +444,9 @@ Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks)
|
|||||||
usb_driver_info *element = fDriverList;
|
usb_driver_info *element = fDriverList;
|
||||||
while (element) {
|
while (element) {
|
||||||
if (strcmp(element->driver_name, driverName) == 0) {
|
if (strcmp(element->driver_name, driverName) == 0) {
|
||||||
|
if (benaphore_lock(&fExploreLock) != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
// inform driver about any already present devices
|
// inform driver about any already present devices
|
||||||
for (int32 i = 0; i < fBusManagers.Count(); i++) {
|
for (int32 i = 0; i < fBusManagers.Count(); i++) {
|
||||||
Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub();
|
Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub();
|
||||||
@ -410,12 +454,13 @@ Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks)
|
|||||||
// Report device will recurse down the whole tree
|
// Report device will recurse down the whole tree
|
||||||
rootHub->ReportDevice(element->support_descriptors,
|
rootHub->ReportDevice(element->support_descriptors,
|
||||||
element->support_descriptor_count, hooks,
|
element->support_descriptor_count, hooks,
|
||||||
&element->cookies, true);
|
&element->cookies, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
element->notify_hooks.device_added = hooks->device_added;
|
element->notify_hooks.device_added = hooks->device_added;
|
||||||
element->notify_hooks.device_removed = hooks->device_removed;
|
element->notify_hooks.device_removed = hooks->device_removed;
|
||||||
|
benaphore_unlock(&fExploreLock);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,17 +479,21 @@ Stack::UninstallNotify(const char *driverName)
|
|||||||
usb_driver_info *element = fDriverList;
|
usb_driver_info *element = fDriverList;
|
||||||
while (element) {
|
while (element) {
|
||||||
if (strcmp(element->driver_name, driverName) == 0) {
|
if (strcmp(element->driver_name, driverName) == 0) {
|
||||||
|
if (benaphore_lock(&fExploreLock) != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
// trigger the device removed hook
|
// trigger the device removed hook
|
||||||
for (int32 i = 0; i < fBusManagers.Count(); i++) {
|
for (int32 i = 0; i < fBusManagers.Count(); i++) {
|
||||||
Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub();
|
Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub();
|
||||||
if (rootHub)
|
if (rootHub)
|
||||||
rootHub->ReportDevice(element->support_descriptors,
|
rootHub->ReportDevice(element->support_descriptors,
|
||||||
element->support_descriptor_count,
|
element->support_descriptor_count,
|
||||||
&element->notify_hooks, &element->cookies, false);
|
&element->notify_hooks, &element->cookies, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
element->notify_hooks.device_added = NULL;
|
element->notify_hooks.device_added = NULL;
|
||||||
element->notify_hooks.device_removed = NULL;
|
element->notify_hooks.device_removed = NULL;
|
||||||
|
benaphore_unlock(&fExploreLock);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ cancel_queued_transfers(usb_pipe pipe)
|
|||||||
if (!object || (object->Type() & USB_OBJECT_PIPE) == 0)
|
if (!object || (object->Type() & USB_OBJECT_PIPE) == 0)
|
||||||
return B_DEV_INVALID_PIPE;
|
return B_DEV_INVALID_PIPE;
|
||||||
|
|
||||||
return ((Pipe *)object)->CancelQueuedTransfers();
|
return ((Pipe *)object)->CancelQueuedTransfers(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +60,13 @@ struct usb_driver_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct change_item {
|
||||||
|
bool added;
|
||||||
|
Device *device;
|
||||||
|
change_item *link;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct rescan_item {
|
struct rescan_item {
|
||||||
const char *name;
|
const char *name;
|
||||||
rescan_item *link;
|
rescan_item *link;
|
||||||
@ -141,7 +148,8 @@ static int32 ExploreThread(void *data);
|
|||||||
bool fFirstExploreDone;
|
bool fFirstExploreDone;
|
||||||
bool fStopThreads;
|
bool fStopThreads;
|
||||||
|
|
||||||
benaphore fLock;
|
benaphore fStackLock;
|
||||||
|
benaphore fExploreLock;
|
||||||
PhysicalMemoryAllocator *fAllocator;
|
PhysicalMemoryAllocator *fAllocator;
|
||||||
|
|
||||||
uint32 fObjectIndex;
|
uint32 fObjectIndex;
|
||||||
@ -178,7 +186,8 @@ virtual status_t Start();
|
|||||||
virtual status_t Stop();
|
virtual status_t Stop();
|
||||||
|
|
||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
virtual status_t CancelQueuedTransfers(Pipe *pipe);
|
virtual status_t CancelQueuedTransfers(Pipe *pipe,
|
||||||
|
bool force);
|
||||||
|
|
||||||
virtual status_t NotifyPipeChange(Pipe *pipe,
|
virtual status_t NotifyPipeChange(Pipe *pipe,
|
||||||
usb_change change);
|
usb_change change);
|
||||||
@ -260,7 +269,7 @@ virtual bool DataToggle() { return fDataToggle; };
|
|||||||
virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; };
|
virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; };
|
||||||
|
|
||||||
status_t SubmitTransfer(Transfer *transfer);
|
status_t SubmitTransfer(Transfer *transfer);
|
||||||
status_t CancelQueuedTransfers();
|
status_t CancelQueuedTransfers(bool force);
|
||||||
|
|
||||||
// Convenience functions for standard requests
|
// Convenience functions for standard requests
|
||||||
virtual status_t SetFeature(uint16 selector);
|
virtual status_t SetFeature(uint16 selector);
|
||||||
@ -414,6 +423,9 @@ virtual ~Device();
|
|||||||
|
|
||||||
status_t InitCheck();
|
status_t InitCheck();
|
||||||
|
|
||||||
|
virtual status_t Changed(change_item **changeList,
|
||||||
|
bool added);
|
||||||
|
|
||||||
virtual uint32 Type() { return USB_OBJECT_DEVICE; };
|
virtual uint32 Type() { return USB_OBJECT_DEVICE; };
|
||||||
|
|
||||||
ControlPipe *DefaultPipe() { return fDefaultPipe; };
|
ControlPipe *DefaultPipe() { return fDefaultPipe; };
|
||||||
@ -437,7 +449,7 @@ virtual status_t ReportDevice(
|
|||||||
uint32 supportDescriptorCount,
|
uint32 supportDescriptorCount,
|
||||||
const usb_notify_hooks *hooks,
|
const usb_notify_hooks *hooks,
|
||||||
usb_driver_cookie **cookies,
|
usb_driver_cookie **cookies,
|
||||||
bool added);
|
bool added, bool recursive);
|
||||||
virtual status_t BuildDeviceName(char *string,
|
virtual status_t BuildDeviceName(char *string,
|
||||||
uint32 *index, size_t bufferSize,
|
uint32 *index, size_t bufferSize,
|
||||||
Device *device);
|
Device *device);
|
||||||
@ -452,6 +464,7 @@ protected:
|
|||||||
bool fInitOK;
|
bool fInitOK;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool fAvailable;
|
||||||
usb_configuration_info *fConfigurations;
|
usb_configuration_info *fConfigurations;
|
||||||
usb_configuration_info *fCurrentConfiguration;
|
usb_configuration_info *fCurrentConfiguration;
|
||||||
usb_speed fSpeed;
|
usb_speed fSpeed;
|
||||||
@ -468,8 +481,8 @@ public:
|
|||||||
usb_speed speed);
|
usb_speed speed);
|
||||||
virtual ~Hub();
|
virtual ~Hub();
|
||||||
|
|
||||||
bool Lock();
|
virtual status_t Changed(change_item **changeList,
|
||||||
void Unlock();
|
bool added);
|
||||||
|
|
||||||
virtual uint32 Type() { return USB_OBJECT_DEVICE | USB_OBJECT_HUB; };
|
virtual uint32 Type() { return USB_OBJECT_DEVICE | USB_OBJECT_HUB; };
|
||||||
|
|
||||||
@ -480,7 +493,7 @@ virtual status_t GetDescriptor(uint8 descriptorType,
|
|||||||
|
|
||||||
status_t UpdatePortStatus(uint8 index);
|
status_t UpdatePortStatus(uint8 index);
|
||||||
status_t ResetPort(uint8 index);
|
status_t ResetPort(uint8 index);
|
||||||
void Explore();
|
void Explore(change_item **changeList);
|
||||||
static void InterruptCallback(void *cookie,
|
static void InterruptCallback(void *cookie,
|
||||||
status_t status, void *data,
|
status_t status, void *data,
|
||||||
size_t actualLength);
|
size_t actualLength);
|
||||||
@ -490,14 +503,12 @@ virtual status_t ReportDevice(
|
|||||||
uint32 supportDescriptorCount,
|
uint32 supportDescriptorCount,
|
||||||
const usb_notify_hooks *hooks,
|
const usb_notify_hooks *hooks,
|
||||||
usb_driver_cookie **cookies,
|
usb_driver_cookie **cookies,
|
||||||
bool added);
|
bool added, bool recursive);
|
||||||
virtual status_t BuildDeviceName(char *string,
|
virtual status_t BuildDeviceName(char *string,
|
||||||
uint32 *index, size_t bufferSize,
|
uint32 *index, size_t bufferSize,
|
||||||
Device *device);
|
Device *device);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
benaphore fLock;
|
|
||||||
|
|
||||||
InterruptPipe *fInterruptPipe;
|
InterruptPipe *fInterruptPipe;
|
||||||
usb_hub_descriptor fHubDescriptor;
|
usb_hub_descriptor fHubDescriptor;
|
||||||
|
|
||||||
|
@ -864,7 +864,7 @@ EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
EHCI::CancelQueuedTransfers(Pipe *pipe)
|
EHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
|
||||||
{
|
{
|
||||||
if (!Lock())
|
if (!Lock())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@ -879,7 +879,13 @@ EHCI::CancelQueuedTransfers(Pipe *pipe)
|
|||||||
descriptor = (ehci_qtd *)descriptor->next_log;
|
descriptor = (ehci_qtd *)descriptor->next_log;
|
||||||
}
|
}
|
||||||
|
|
||||||
current->transfer->Finished(B_CANCELED, 0);
|
if (!force) {
|
||||||
|
// if the transfer is canceled by force, the one causing the
|
||||||
|
// cancel is probably not the one who initiated the transfer
|
||||||
|
// and the callback is likely not safe anymore
|
||||||
|
current->transfer->Finished(B_CANCELED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
current->canceled = true;
|
current->canceled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ public:
|
|||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
status_t SubmitPeriodicTransfer(Transfer *transfer);
|
status_t SubmitPeriodicTransfer(Transfer *transfer);
|
||||||
status_t SubmitAsyncTransfer(Transfer *transfer);
|
status_t SubmitAsyncTransfer(Transfer *transfer);
|
||||||
virtual status_t CancelQueuedTransfers(Pipe *pipe);
|
virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force);
|
||||||
|
|
||||||
virtual status_t NotifyPipeChange(Pipe *pipe,
|
virtual status_t NotifyPipeChange(Pipe *pipe,
|
||||||
usb_change change);
|
usb_change change);
|
||||||
|
@ -791,7 +791,7 @@ OHCI::_ReadReg(uint32 reg)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
OHCI::CancelQueuedTransfers(Pipe *pipe)
|
OHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
|
||||||
{
|
{
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,8 @@ public:
|
|||||||
|
|
||||||
status_t Start();
|
status_t Start();
|
||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
virtual status_t CancelQueuedTransfers(Pipe *pipe);
|
virtual status_t CancelQueuedTransfers(Pipe *pipe,
|
||||||
|
bool force);
|
||||||
status_t SubmitRequest(Transfer *transfer);
|
status_t SubmitRequest(Transfer *transfer);
|
||||||
|
|
||||||
virtual status_t NotifyPipeChange(Pipe *pipe,
|
virtual status_t NotifyPipeChange(Pipe *pipe,
|
||||||
|
@ -603,7 +603,7 @@ UHCI::SubmitTransfer(Transfer *transfer)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
UHCI::CancelQueuedTransfers(Pipe *pipe)
|
UHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
|
||||||
{
|
{
|
||||||
if (pipe->Type() & USB_OBJECT_ISO_PIPE)
|
if (pipe->Type() & USB_OBJECT_ISO_PIPE)
|
||||||
return CancelQueuedIsochronousTransfers(pipe);
|
return CancelQueuedIsochronousTransfers(pipe);
|
||||||
@ -621,7 +621,13 @@ UHCI::CancelQueuedTransfers(Pipe *pipe)
|
|||||||
descriptor = (uhci_td *)descriptor->link_log;
|
descriptor = (uhci_td *)descriptor->link_log;
|
||||||
}
|
}
|
||||||
|
|
||||||
current->transfer->Finished(B_CANCELED, 0);
|
if (!force) {
|
||||||
|
// if the transfer is canceled by force, the one causing the
|
||||||
|
// cancel is probably not the one who initiated the transfer
|
||||||
|
// and the callback is likely not safe anymore
|
||||||
|
current->transfer->Finished(B_CANCELED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
current->canceled = true;
|
current->canceled = true;
|
||||||
}
|
}
|
||||||
current = current->link;
|
current = current->link;
|
||||||
|
@ -91,7 +91,7 @@ public:
|
|||||||
|
|
||||||
status_t Start();
|
status_t Start();
|
||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
virtual status_t CancelQueuedTransfers(Pipe *pipe);
|
virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force);
|
||||||
status_t CancelQueuedIsochronousTransfers(Pipe *pipe);
|
status_t CancelQueuedIsochronousTransfers(Pipe *pipe);
|
||||||
status_t SubmitRequest(Transfer *transfer);
|
status_t SubmitRequest(Transfer *transfer);
|
||||||
status_t SubmitIsochronous(Transfer *transfer);
|
status_t SubmitIsochronous(Transfer *transfer);
|
||||||
|
Loading…
Reference in New Issue
Block a user