From 7e1490e0ad111a858589c95cc80bdde85424e530 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sun, 28 Sep 2008 13:42:59 +0000 Subject: [PATCH] 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 --- headers/os/drivers/USB3.h | 42 +++++++- src/add-ons/kernel/bus_managers/usb/usb.cpp | 105 +++++++++++++++++++- 2 files changed, 143 insertions(+), 4 deletions(-) diff --git a/headers/os/drivers/USB3.h b/headers/os/drivers/USB3.h index 7e0d196c15..88d9002d4e 100644 --- a/headers/os/drivers/USB3.h +++ b/headers/os/drivers/USB3.h @@ -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); }; diff --git a/src/add-ons/kernel/bus_managers/usb/usb.cpp b/src/add-ons/kernel/bus_managers/usb/usb.cpp index 12bec77296..cae209e560 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb.cpp +++ b/src/add-ons/kernel/bus_managers/usb/usb.cpp @@ -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 };