Introduce some extensions to the USB v3 module API that allow for device

enumeration (getting roothubs, enumerating child devices and detecting device
topology) and hub port management (resetting and disabling ports). These were
laying around for quite some time.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27768 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2008-09-28 13:42:59 +00:00
parent abe717da05
commit 7e1490e0ad
2 changed files with 143 additions and 4 deletions

View File

@ -129,7 +129,7 @@ struct usb_module_info {
/* Get the nth supported configuration of a device*/
const usb_configuration_info *(*get_nth_configuration)(usb_device device,
uint index);
uint32 index);
/* Get the current configuration */
const usb_configuration_info *(*get_configuration)(usb_device device);
@ -211,9 +211,47 @@ struct usb_module_info {
/* Cancel all pending async requests in a pipe */
status_t (*cancel_queued_transfers)(usb_pipe pipe);
/* tuning, timeouts, etc */
/* Tuning, configuration of timeouts, etc */
status_t (*usb_ioctl)(uint32 opcode, void *buffer,
size_t bufferSize);
/*
* Enumeration of device topology - With these commands you can enumerate
* the roothubs and enumerate child devices of hubs. Note that the index
* provided to get_nth_child does not map to the port where the child
* device is attached to. To get this information you would call
* get_device_parent which provides you with the parent hub and the port
* index of a device. To test whether an enumerated child is a hub you
* can either examine the device descriptor or you can call get_nth_child
* and check the returned status. A value of B_OK indicates that the call
* succeeded and the returned info is valid, B_ENTRY_NOT_FOUND indicates
* that you have reached the last index. Any other error indicates that
* the provided arguments are invalid (i.e. not a hub or invalid pointers)
* or an internal error occured. Note that there are no guarantees that
* the device handle you get stays valid while you are using it. If it gets
* invalid any further use will simply return an error. You should install
* notify hooks to avoid such situations.
*/
status_t (*get_nth_roothub)(uint32 index,
usb_device *rootHub);
status_t (*get_nth_child)(usb_device hub,
uint8 index, usb_device *childDevice);
status_t (*get_device_parent)(usb_device device,
usb_device *parentHub,
uint8 *portIndex);
/*
* Hub interaction - These commands are only valid when used with a hub
* device handle. Use reset_port to trigger a reset of the port with index
* portIndex. This will cause a disconnect event for the attached device.
* With disable_port you can specify that the port at portIndex shall be
* disabled. This will also cause a disconnect event for the attached
* device. Use reset_port to reenable a previously disabled port.
*/
status_t (*reset_port)(usb_device hub,
uint8 portIndex);
status_t (*disable_port)(usb_device hub,
uint8 portIndex);
};

View File

@ -119,7 +119,7 @@ get_device_descriptor(usb_device device)
const usb_configuration_info *
get_nth_configuration(usb_device device, uint index)
get_nth_configuration(usb_device device, uint32 index)
{
TRACE(("usb_module: get_nth_configuration(%ld, %d)\n", device, index));
Object *object = gUSBStack->GetObject(device);
@ -355,6 +355,102 @@ usb_ioctl(uint32 opcode, void *buffer, size_t bufferSize)
}
status_t
get_nth_roothub(uint32 index, usb_device *rootHub)
{
if (!rootHub)
return B_BAD_VALUE;
BusManager *busManager = gUSBStack->BusManagerAt(index);
if (!busManager)
return B_ENTRY_NOT_FOUND;
Hub *hub = busManager->GetRootHub();
if (!hub)
return B_NO_INIT;
*rootHub = hub->USBID();
return B_OK;
}
status_t
get_nth_child(usb_device _hub, uint8 index, usb_device *childDevice)
{
if (!childDevice)
return B_BAD_VALUE;
Object *object = gUSBStack->GetObject(_hub);
if (!object || (object->Type() & USB_OBJECT_HUB) == 0)
return B_DEV_INVALID_PIPE;
Hub *hub = (Hub *)object;
for (uint8 i = 0; i < 8; i++) {
if (hub->ChildAt(i) == NULL)
continue;
if (index-- > 0)
continue;
*childDevice = hub->ChildAt(i)->USBID();
return B_OK;
}
return B_ENTRY_NOT_FOUND;
}
status_t
get_device_parent(usb_device _device, usb_device *parentHub, uint8 *portIndex)
{
if (!parentHub || !portIndex)
return B_BAD_VALUE;
Object *object = gUSBStack->GetObject(_device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_DEV_INVALID_PIPE;
Object *parent = object->Parent();
if (!parent || (parent->Type() & USB_OBJECT_HUB) == 0)
return B_ENTRY_NOT_FOUND;
Hub *hub = (Hub *)parent;
for (uint8 i = 0; i < 8; i++) {
if (hub->ChildAt(i) == object) {
*portIndex = i;
*parentHub = hub->USBID();
return B_OK;
}
}
return B_ERROR;
}
status_t
reset_port(usb_device _hub, uint8 portIndex)
{
Object *object = gUSBStack->GetObject(_hub);
if (!object || (object->Type() & USB_OBJECT_HUB) == 0)
return B_DEV_INVALID_PIPE;
Hub *hub = (Hub *)object;
return hub->ResetPort(portIndex);
}
status_t
disable_port(usb_device _hub, uint8 portIndex)
{
Object *object = gUSBStack->GetObject(_hub);
if (!object || (object->Type() & USB_OBJECT_HUB) == 0)
return B_DEV_INVALID_PIPE;
Hub *hub = (Hub *)object;
return hub->DisablePort(portIndex);
}
/*
This module exports the USB API v3
*/
@ -389,7 +485,12 @@ struct usb_module_info gModuleInfoV3 = {
queue_request, // queue_request
set_pipe_policy, // set_pipe_policy
cancel_queued_transfers, // cancel_queued_transfers
usb_ioctl // usb_ioctl
usb_ioctl, // usb_ioctl
get_nth_roothub, // get_nth_roothub
get_nth_child, // get_nth_child
get_device_parent, // get_device_parent
reset_port, // reset_port
disable_port // disable_port
};