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 };