diff --git a/headers/libs/usb/USBKit.h b/headers/libs/usb/USBKit.h index d74dbd0cc8..c10a9e4f52 100644 --- a/headers/libs/usb/USBKit.h +++ b/headers/libs/usb/USBKit.h @@ -1,9 +1,6 @@ /* - * Copyright 2007, Haiku Inc. All rights reserved. + * Copyright 2007-2008, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. - * - * Authors: - * Michael Lotz */ #ifndef _USBKIT_H @@ -240,12 +237,25 @@ public: uint32 CountEndpoints() const; const BUSBEndpoint *EndpointAt(uint32 index) const; + // Using CountAlternates() you can retrieve the number of alternate + // interfaces at this interface index. Note that this interface itself + // counts as an alternate so an alternate count of one really means + // that you are currently using the sole interface present. + // With SetAlternate() you can switch this BUSBInterface object to the + // alternate at the specified index. Note that all endpoints retrieved + // through EndpointAt() will become invalid and be deleted as soon as + // you set an alternate. + uint32 CountAlternates() const; + status_t SetAlternate(uint32 alternateIndex); + private: friend class BUSBConfiguration; BUSBInterface(BUSBConfiguration *config, uint32 index, int rawFD); ~BUSBInterface(); + void _UpdateDescriptorAndEndpoints(); + BUSBConfiguration *fConfiguration; uint32 fIndex; int fRawFD; @@ -305,6 +315,11 @@ public: usb_iso_packet_descriptor *packetDescriptors, uint32 packetCount) const; + // These are convenience methods for getting and clearing the halt + // state of an endpoint. They use the control pipe of the device to + // send the corresponding requests. + bool IsStalled() const; + status_t ClearStall() const; private: friend class BUSBInterface; BUSBEndpoint(BUSBInterface *interface, diff --git a/src/libs/usb/USBEndpoint.cpp b/src/libs/usb/USBEndpoint.cpp index 3317008e0d..8000436748 100644 --- a/src/libs/usb/USBEndpoint.cpp +++ b/src/libs/usb/USBEndpoint.cpp @@ -213,3 +213,23 @@ BUSBEndpoint::IsochronousTransfer(void *data, size_t length, return command.isochronous.length; } + + +bool +BUSBEndpoint::IsStalled() const +{ + uint16 status = 0; + Device()->ControlTransfer(USB_REQTYPE_ENDPOINT_IN, + USB_REQUEST_GET_STATUS, USB_FEATURE_ENDPOINT_HALT, + fDescriptor.endpoint_address & 0x0f, sizeof(status), &status); + return status != 0; +} + + +status_t +BUSBEndpoint::ClearStall() const +{ + return Device()->ControlTransfer(USB_REQTYPE_ENDPOINT_OUT, + USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, + fDescriptor.endpoint_address & 0x0f, 0, NULL); +} diff --git a/src/libs/usb/USBInterface.cpp b/src/libs/usb/USBInterface.cpp index decdc858cc..c69047e379 100644 --- a/src/libs/usb/USBInterface.cpp +++ b/src/libs/usb/USBInterface.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2007, Haiku Inc. All rights reserved. + * Copyright 2007-2008, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Michael Lotz + * Salvatore Benedetto */ #include @@ -19,18 +20,7 @@ BUSBInterface::BUSBInterface(BUSBConfiguration *config, uint32 index, int rawFD) fEndpoints(NULL), fInterfaceString(NULL) { - raw_command command; - command.interface.descriptor = &fDescriptor; - command.interface.config_index = fConfiguration->Index(); - command.interface.interface_index = fIndex; - if (ioctl(fRawFD, RAW_COMMAND_GET_INTERFACE_DESCRIPTOR, &command, sizeof(command)) - || command.interface.status != RAW_STATUS_SUCCESS) { - memset(&fDescriptor, 0, sizeof(fDescriptor)); - } - - fEndpoints = new BUSBEndpoint *[fDescriptor.num_endpoints]; - for (int32 i = 0; i < fDescriptor.num_endpoints; i++) - fEndpoints[i] = new BUSBEndpoint(this, i, fRawFD); + _UpdateDescriptorAndEndpoints(); } @@ -148,3 +138,62 @@ BUSBInterface::EndpointAt(uint32 index) const return fEndpoints[index]; } + + +uint32 +BUSBInterface::CountAlternates() const +{ + uint32 alternateCount; + raw_command command; + command.alternate.alternate_count = &alternateCount; + command.alternate.config_index = fConfiguration->Index(); + command.alternate.interface_index = fIndex; + if (ioctl(fRawFD, RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) + || command.alternate.status != RAW_STATUS_SUCCESS) { + return 1; + } + + return alternateCount; +} + + +status_t +BUSBInterface::SetAlternate(uint32 alternateIndex) +{ + raw_command command; + command.alternate.config_index = fConfiguration->Index(); + command.alternate.interface_index = fIndex; + command.alternate.alternate_index = alternateIndex; + if (ioctl(fRawFD, RAW_COMMAND_SET_ALT_INTERFACE, &command, sizeof(command)) + || command.alternate.status != RAW_STATUS_SUCCESS) { + return B_ERROR; + } + + _UpdateDescriptorAndEndpoints(); + return B_OK; +} + + +void +BUSBInterface::_UpdateDescriptorAndEndpoints() +{ + raw_command command; + command.interface.descriptor = &fDescriptor; + command.interface.config_index = fConfiguration->Index(); + command.interface.interface_index = fIndex; + if (ioctl(fRawFD, RAW_COMMAND_GET_INTERFACE_DESCRIPTOR, &command, sizeof(command)) + || command.interface.status != RAW_STATUS_SUCCESS) { + memset(&fDescriptor, 0, sizeof(fDescriptor)); + } + + if (fEndpoints) { + // Delete old endpoints + for (int32 i = 0; i < fDescriptor.num_endpoints; i++) + delete fEndpoints[i]; + delete fEndpoints; + } + + fEndpoints = new BUSBEndpoint *[fDescriptor.num_endpoints]; + for (int32 i = 0; i < fDescriptor.num_endpoints; i++) + fEndpoints[i] = new BUSBEndpoint(this, i, fRawFD); +}