Skip to content

Commit

Permalink
Kernel/USB: Add and use a shared function to set a device's interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Hendiadyoin1 committed Oct 14, 2024
1 parent 829102b commit af8975b
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 12 deletions.
5 changes: 1 addition & 4 deletions Kernel/Bus/USB/Drivers/HID/MouseDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,8 @@ ErrorOr<void> 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));
Expand Down
9 changes: 2 additions & 7 deletions Kernel/Bus/USB/Drivers/MassStorage/MassStorageDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,11 @@ ErrorOr<void> MassStorageDriver::probe(USB::Device& device)
ErrorOr<void> 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(
Expand Down Expand Up @@ -151,9 +148,7 @@ ErrorOr<void> 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<u8> command_pipe_endpoint_number;
u16 command_max_packet_size;
Expand Down
33 changes: 33 additions & 0 deletions Kernel/Bus/USB/USBDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,37 @@ ErrorOr<size_t> 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<void> 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<void> 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 {};
}

}
10 changes: 10 additions & 0 deletions Kernel/Bus/USB/USBDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <AK/Badge.h>
#include <AK/OwnPtr.h>
#include <AK/SetOnce.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <Kernel/Bus/USB/Drivers/USBDriver.h>
Expand Down Expand Up @@ -76,6 +77,8 @@ class Device : public AtomicRefCounted<Device> {
m_driver = nullptr;
}

ErrorOr<void> set_configuration_and_interface(USBInterface const& interface);

SpinlockProtected<RefPtr<SysFSUSBDeviceInformation>, LockRank::None>& sysfs_device_info_node(Badge<USB::Hub>) { return m_sysfs_device_info_node; }

template<DerivedFrom<USBController> Controller>
Expand Down Expand Up @@ -105,6 +108,7 @@ class Device : public AtomicRefCounted<Device> {

protected:
void set_default_pipe(NonnullOwnPtr<ControlPipe> pipe);
ErrorOr<void> 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
Expand All @@ -121,6 +125,12 @@ class Device : public AtomicRefCounted<Device> {
Hub const* m_hub { nullptr };
OwnPtr<ControlPipe> 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<Driver> m_driver;

private:
Expand Down
2 changes: 1 addition & 1 deletion Kernel/Bus/USB/USBHub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ ErrorOr<void> 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 {};
Expand Down
1 change: 1 addition & 0 deletions Kernel/Bus/USB/USBRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit af8975b

Please sign in to comment.