diff --git a/headers/os/device/USBKit.h b/headers/os/device/USBKit.h index f415bc00e1..9758942f12 100644 --- a/headers/os/device/USBKit.h +++ b/headers/os/device/USBKit.h @@ -204,7 +204,8 @@ friend class BUSBDevice; mutable char * fConfigurationString; - uint32 fReserved[10]; + usb_configuration_descriptor* fFullDescriptor; + uint32 fReserved[9]; }; diff --git a/src/add-ons/kernel/drivers/bus/usb/usb_raw.cpp b/src/add-ons/kernel/drivers/bus/usb/usb_raw.cpp index d430080f19..fae00ac8d5 100644 --- a/src/add-ons/kernel/drivers/bus/usb/usb_raw.cpp +++ b/src/add-ons/kernel/drivers/bus/usb/usb_raw.cpp @@ -300,23 +300,36 @@ usb_raw_ioctl(void *cookie, uint32 op, void *buffer, size_t length) } case B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR: + case B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC: { if (length < sizeof(command->config)) return B_BUFFER_OVERFLOW; + size_t descriptorLength = sizeof(usb_configuration_descriptor); + if (op == B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC) { + if (length < sizeof(command->config_etc)) + return B_BUFFER_OVERFLOW; + + descriptorLength = command->config_etc.length; + } + const usb_configuration_info *configurationInfo = usb_raw_get_configuration(device, command->config.config_index, &command->config.status); if (configurationInfo == NULL) return B_OK; - if (user_memcpy(command->config.descriptor, - configurationInfo->descr, - sizeof(usb_configuration_descriptor)) != B_OK) { + const usb_configuration_descriptor* descriptor + = configurationInfo->descr; + if (user_memcpy(command->config.descriptor, descriptor, + min_c(descriptorLength, descriptor->total_length)) != B_OK) { return B_BAD_ADDRESS; } - - command->config.status = B_USB_RAW_STATUS_SUCCESS; + if (op == B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC + && descriptor->total_length > descriptorLength) + command->config.status = B_USB_RAW_STATUS_NO_MEMORY; + else + command->config.status = B_USB_RAW_STATUS_SUCCESS; return B_OK; } diff --git a/src/add-ons/kernel/drivers/bus/usb/usb_raw.h b/src/add-ons/kernel/drivers/bus/usb/usb_raw.h index 54112c2202..fc41654029 100644 --- a/src/add-ons/kernel/drivers/bus/usb/usb_raw.h +++ b/src/add-ons/kernel/drivers/bus/usb/usb_raw.h @@ -22,10 +22,11 @@ typedef enum { B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX, + B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC, B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR_ETC, - + B_USB_RAW_COMMAND_SET_CONFIGURATION = 0x3000, B_USB_RAW_COMMAND_SET_FEATURE, B_USB_RAW_COMMAND_CLEAR_FEATURE, @@ -74,6 +75,13 @@ typedef union { uint32 config_index; } config; + struct { + status_t status; + usb_configuration_descriptor *descriptor; + uint32 config_index; + size_t length; + } config_etc; + struct { status_t status; uint32 alternate_info; diff --git a/src/kits/device/USBConfiguration.cpp b/src/kits/device/USBConfiguration.cpp index cf158a06e2..1751cd2573 100644 --- a/src/kits/device/USBConfiguration.cpp +++ b/src/kits/device/USBConfiguration.cpp @@ -8,9 +8,12 @@ #include #include -#include -#include + #include +#include +#include +#include + BUSBConfiguration::BUSBConfiguration(BUSBDevice *device, uint32 index, int rawFD) @@ -18,14 +21,36 @@ BUSBConfiguration::BUSBConfiguration(BUSBDevice *device, uint32 index, int rawFD fIndex(index), fRawFD(rawFD), fInterfaces(NULL), - fConfigurationString(NULL) + fConfigurationString(NULL), + fFullDescriptor(NULL) { usb_raw_command command; command.config.descriptor = &fDescriptor; command.config.config_index = fIndex; - if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, &command, - sizeof(command)) || command.config.status != B_USB_RAW_STATUS_SUCCESS) + + if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, + &command, sizeof(command)) + || command.config.status != B_USB_RAW_STATUS_SUCCESS) { memset(&fDescriptor, 0, sizeof(fDescriptor)); + } else { + // Got the descriptor header, retrieve the whole descriptor + size_t length = fDescriptor.total_length; + fFullDescriptor = (usb_configuration_descriptor*)malloc(length); + + if (fFullDescriptor != NULL) { + command.config_etc.descriptor = fFullDescriptor; + command.config_etc.config_index = fIndex; + command.config_etc.length = length; + + if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC, + &command, sizeof(command)) + || command.config_etc.status != B_USB_RAW_STATUS_SUCCESS) { + + free(fFullDescriptor); + fFullDescriptor = NULL; + } + } + } fInterfaces = new(std::nothrow) BUSBInterface *[ fDescriptor.number_interfaces]; @@ -41,6 +66,8 @@ BUSBConfiguration::BUSBConfiguration(BUSBDevice *device, uint32 index, int rawFD BUSBConfiguration::~BUSBConfiguration() { + free(fFullDescriptor); + delete[] fConfigurationString; if (fInterfaces != NULL) { for (int32 i = 0; i < fDescriptor.number_interfaces; i++) @@ -85,7 +112,7 @@ BUSBConfiguration::ConfigurationString() const const usb_configuration_descriptor * BUSBConfiguration::Descriptor() const { - return &fDescriptor; + return (fFullDescriptor != NULL) ? fFullDescriptor : &fDescriptor; }