diff --git a/Kernel/Bus/USB/Drivers/HID/MouseDriver.cpp b/Kernel/Bus/USB/Drivers/HID/MouseDriver.cpp index 2ec950a848c1df..63152e7b62e6df 100644 --- a/Kernel/Bus/USB/Drivers/HID/MouseDriver.cpp +++ b/Kernel/Bus/USB/Drivers/HID/MouseDriver.cpp @@ -60,11 +60,8 @@ ErrorOr MouseDriver::initialize_device(USB::Device& device, USBInterface c { if (interface.endpoints().size() != 1) return ENOTSUP; - auto const& configuration = interface.configuration(); // FIXME: Should we check other configurations? - TRY(device.control_transfer( - USB_REQUEST_RECIPIENT_DEVICE | USB_REQUEST_TYPE_STANDARD | USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE, - USB_REQUEST_SET_CONFIGURATION, configuration.configuration_id(), 0, 0, nullptr)); + TRY(device.set_configuration_and_interface(interface)); auto const& endpoint_descriptor = interface.endpoints()[0]; auto interrupt_in_pipe = TRY(USB::InterruptInPipe::create(device.controller(), device, endpoint_descriptor.endpoint_address & 0xf, endpoint_descriptor.max_packet_size, 10)); diff --git a/Kernel/Bus/USB/Drivers/MassStorage/MassStorageDriver.cpp b/Kernel/Bus/USB/Drivers/MassStorage/MassStorageDriver.cpp index 5ceab96d6119e8..5bddf93638f634 100644 --- a/Kernel/Bus/USB/Drivers/MassStorage/MassStorageDriver.cpp +++ b/Kernel/Bus/USB/Drivers/MassStorage/MassStorageDriver.cpp @@ -84,14 +84,11 @@ ErrorOr MassStorageDriver::probe(USB::Device& device) ErrorOr MassStorageDriver::initialise_bulk_only_device(USB::Device& device, USBInterface const& interface) { auto const& descriptor = interface.descriptor(); - auto const& configuration = interface.configuration(); if (descriptor.interface_sub_class_code != to_underlying(MassStorage::SubclassCode::SCSI_transparent)) return ENOTSUP; - TRY(device.control_transfer( - USB_REQUEST_RECIPIENT_DEVICE | USB_REQUEST_TYPE_STANDARD | USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE, - USB_REQUEST_SET_CONFIGURATION, configuration.configuration_id(), 0, 0, nullptr)); + TRY(device.set_configuration_and_interface(interface)); u8 max_luns; TRY(device.control_transfer( @@ -151,9 +148,7 @@ ErrorOr MassStorageDriver::initialise_uas_device(USB::Device& device, USBI if (descriptor.interface_sub_class_code != to_underlying(MassStorage::SubclassCode::SCSI_transparent)) return ENOTSUP; - TRY(device.control_transfer( - USB_REQUEST_RECIPIENT_DEVICE | USB_REQUEST_TYPE_STANDARD | USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE, - USB_REQUEST_SET_CONFIGURATION, configuration.configuration_id(), 0, 0, nullptr)); + TRY(device.set_configuration_and_interface(interface)); Optional command_pipe_endpoint_number; u16 command_max_packet_size; diff --git a/Kernel/Bus/USB/USBDevice.cpp b/Kernel/Bus/USB/USBDevice.cpp index 05b626f397cd36..2551dcb21c9f99 100644 --- a/Kernel/Bus/USB/USBDevice.cpp +++ b/Kernel/Bus/USB/USBDevice.cpp @@ -97,4 +97,37 @@ ErrorOr Device::control_transfer(u8 request_type, u8 request, u16 value, return TRY(m_default_pipe->submit_control_transfer(request_type, request, value, index, length, data)); } +ErrorOr Device::set_configuration(USBConfiguration const& configuration) +{ + if (m_was_configured.was_set() && m_current_configuration != configuration.configuration_id()) + return EALREADY; + + if (!m_was_configured.was_set()) { + m_was_configured.set(); + m_current_configuration = configuration.configuration_id(); + + TRY(control_transfer(USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD | USB_REQUEST_RECIPIENT_DEVICE, USB_REQUEST_SET_CONFIGURATION, + m_current_configuration, 0, 0, nullptr)); + + // FIXME: On xHCI we should set up the all endpoints for the configuration here + // Currently we set them up on the first transfer, which works good enough for now + } + + return {}; +} + +ErrorOr Device::set_configuration_and_interface(USBInterface const& interface) +{ + auto const& configuration = interface.configuration(); + TRY(set_configuration(configuration)); + + // FIXME: When we use the default alternate_setting of interface/the current alternate setting, we don't need to SET_INTERFACE it + // but that gets a bit difficult to track + TRY(control_transfer(USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE, USB_REQUEST_SET_INTERFACE, + interface.descriptor().alternate_setting, interface.descriptor().interface_id, 0, nullptr)); + // FIXME: As in activate_configuration, we should set up changed endpoints on xHCI here + + return {}; +} + } diff --git a/Kernel/Bus/USB/USBDevice.h b/Kernel/Bus/USB/USBDevice.h index 5715e75c2984a2..014de85262bcfb 100644 --- a/Kernel/Bus/USB/USBDevice.h +++ b/Kernel/Bus/USB/USBDevice.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -76,6 +77,8 @@ class Device : public AtomicRefCounted { m_driver = nullptr; } + ErrorOr set_configuration_and_interface(USBInterface const& interface); + SpinlockProtected, LockRank::None>& sysfs_device_info_node(Badge) { return m_sysfs_device_info_node; } template Controller> @@ -105,6 +108,7 @@ class Device : public AtomicRefCounted { protected: void set_default_pipe(NonnullOwnPtr pipe); + ErrorOr set_configuration(USBConfiguration const& configuration); u8 m_device_port { 0 }; // What port is this device attached to. NOTE: This is 1-based. DeviceSpeed m_device_speed; // What speed is this device running at @@ -121,6 +125,12 @@ class Device : public AtomicRefCounted { Hub const* m_hub { nullptr }; OwnPtr m_default_pipe; // Default communication pipe (endpoint0) used during enumeration + // The current configuration is behind a SetOnce, this is the easiest way to + // guarantee that when a driver is attached, another driver cannot choose a different configuration + // using a different interface in the same configuration is fine, though + SetOnce m_was_configured; + u8 m_current_configuration { 0 }; + LockRefPtr m_driver; private: diff --git a/Kernel/Bus/USB/USBHub.cpp b/Kernel/Bus/USB/USBHub.cpp index 61796d4cf95023..eb5916739ccd5b 100644 --- a/Kernel/Bus/USB/USBHub.cpp +++ b/Kernel/Bus/USB/USBHub.cpp @@ -78,7 +78,7 @@ ErrorOr Hub::enumerate_and_power_on_hub() return EINVAL; // FIXME: Which configuration should we choose if there is more than one? - TRY(control_transfer(USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD | USB_REQUEST_RECIPIENT_DEVICE, USB_REQUEST_SET_CONFIGURATION, m_configurations[0].configuration_id(), 0, 0, nullptr)); + TRY(set_configuration(m_configurations[0])); } USBHubDescriptor descriptor {}; diff --git a/Kernel/Bus/USB/USBRequest.h b/Kernel/Bus/USB/USBRequest.h index 09c73f2b891b25..e22aff3405125f 100644 --- a/Kernel/Bus/USB/USBRequest.h +++ b/Kernel/Bus/USB/USBRequest.h @@ -41,6 +41,7 @@ static constexpr u8 USB_REQUEST_GET_DESCRIPTOR = 0x06; static constexpr u8 USB_REQUEST_SET_DESCRIPTOR = 0x07; static constexpr u8 USB_REQUEST_GET_CONFIGURATION = 0x08; static constexpr u8 USB_REQUEST_SET_CONFIGURATION = 0x09; +static constexpr u8 USB_REQUEST_SET_INTERFACE = 0x0B; // Table 9-6 static constexpr u16 USB_FEATURE_DEVICE_REMOTE_WAKEUP = 1;