summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Buhagiar <jooster669@gmail.com>2022-04-15 01:11:15 +1000
committerAndreas Kling <kling@serenityos.org>2022-04-22 15:16:56 +0200
commit300dcb6f5e2c548fa3339947ff531d3fa17cbd38 (patch)
tree7143a12f2c1b9c71075dc78ce1f57021d3200748
parentd313fa98ecd2ebd68c8c50bd803105de1517fcff (diff)
downloadserenity-300dcb6f5e2c548fa3339947ff531d3fa17cbd38.zip
Kernel/USB: Get all interface descriptors on enumeration
This creates all interfaces when the device is enumerated, with a link to the configuration that it is a part of. As such, a new class, `USBInterface` has been introduced to express this state.
-rw-r--r--Kernel/Bus/USB/USBConfiguration.cpp77
-rw-r--r--Kernel/Bus/USB/USBConfiguration.h14
-rw-r--r--Kernel/Bus/USB/USBDevice.cpp1
-rw-r--r--Kernel/Bus/USB/USBInterface.h32
-rw-r--r--Kernel/CMakeLists.txt1
5 files changed, 121 insertions, 4 deletions
diff --git a/Kernel/Bus/USB/USBConfiguration.cpp b/Kernel/Bus/USB/USBConfiguration.cpp
new file mode 100644
index 0000000000..572cf2a581
--- /dev/null
+++ b/Kernel/Bus/USB/USBConfiguration.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2022, Jesse Buhagiar <jesse.buhagiar@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/FixedArray.h>
+#include <Kernel/Bus/USB/USBClasses.h>
+#include <Kernel/Bus/USB/USBConfiguration.h>
+#include <Kernel/Bus/USB/USBInterface.h>
+#include <Kernel/Bus/USB/USBRequest.h>
+
+namespace Kernel::USB {
+
+ErrorOr<void> USBConfiguration::get_interfaces()
+{
+ auto descriptor_hierarchy_buffer = TRY(FixedArray<u8>::try_create(m_descriptor.total_length)); // Buffer for us to store the entire hierarchy into
+
+ // The USB spec is a little bit janky here... Interface and Endpoint descriptors aren't fetched
+ // through a `GET_DESCRIPTOR` request to the device. Instead, the _entire_ hierarchy is returned
+ // to us in one go.
+ auto transfer_length = TRY(m_device.control_transfer(USB_REQUEST_TRANSFER_DIRECTION_DEVICE_TO_HOST, USB_REQUEST_GET_DESCRIPTOR, (DESCRIPTOR_TYPE_CONFIGURATION << 8), 0, m_descriptor.total_length, descriptor_hierarchy_buffer.data()));
+
+ // FIXME: Why does transfer length return the actual size +8 bytes?
+ if (transfer_length < m_descriptor.total_length)
+ return EIO;
+
+ u8* interface_descriptors_base = descriptor_hierarchy_buffer.data() + sizeof(USBConfigurationDescriptor);
+ USBInterfaceDescriptor* interface_descriptor = reinterpret_cast<USBInterfaceDescriptor*>(interface_descriptors_base);
+ Vector<USBEndpointDescriptor> endpoint_descriptors;
+ for (auto interface = 0u; interface < m_descriptor.number_of_interfaces; interface++) {
+ endpoint_descriptors.ensure_capacity(interface_descriptor->number_of_endpoints);
+
+ if constexpr (USB_DEBUG) {
+ dbgln("Interface Descriptor {}", interface);
+ dbgln("interface_id: {:02x}", interface_descriptor->interface_id);
+ dbgln("alternate_setting: {:02x}", interface_descriptor->alternate_setting);
+ dbgln("number_of_endpoints: {:02x}", interface_descriptor->number_of_endpoints);
+ dbgln("interface_class_code: {:02x}", interface_descriptor->interface_class_code);
+ dbgln("interface_sub_class_code: {:02x}", interface_descriptor->interface_sub_class_code);
+ dbgln("interface_protocol: {:02x}", interface_descriptor->interface_protocol);
+ dbgln("interface_string_descriptor_index: {}", interface_descriptor->interface_string_descriptor_index);
+ }
+
+ // Get all the endpoint descriptors
+ for (auto endpoint = 0u; endpoint < interface_descriptor->number_of_endpoints; endpoint++) {
+ u8* raw_endpoint_descriptor_offset = interface_descriptors_base + sizeof(USBInterfaceDescriptor) + (endpoint * sizeof(USBEndpointDescriptor));
+
+ // FIXME: It looks like HID descriptors come BEFORE the endpoint descriptors for a HID device, so we should load
+ // these too eventually.
+ // See here: https://www.usb.org/defined-class-codes
+ if (interface_descriptor->interface_class_code == USB_CLASS_HID)
+ raw_endpoint_descriptor_offset += sizeof(USBHIDDescriptor); // Skip the HID descriptor (this was worked out via buffer inspection)
+
+ USBEndpointDescriptor endpoint_descriptor;
+ memcpy(&endpoint_descriptor, raw_endpoint_descriptor_offset, sizeof(USBEndpointDescriptor));
+
+ if constexpr (USB_DEBUG) {
+ dbgln("Endpoint Descriptor {}", endpoint);
+ dbgln("Endpoint Address: {}", endpoint_descriptor.endpoint_address);
+ dbgln("Endpoint Attribute Bitmap: {:08b}", endpoint_descriptor.endpoint_attributes_bitmap);
+ dbgln("Endpoint Maximum Packet Size: {}", endpoint_descriptor.max_packet_size);
+ dbgln("Endpoint Poll Interval (in frames): {}", endpoint_descriptor.poll_interval_in_frames);
+ }
+
+ endpoint_descriptors.append(endpoint_descriptor);
+ }
+
+ USBInterface device_interface(*this, *interface_descriptor, endpoint_descriptors);
+ m_interfaces.append(device_interface);
+ interface_descriptor += interface_descriptor->number_of_endpoints * sizeof(USBEndpointDescriptor);
+ }
+
+ return {};
+}
+
+}
diff --git a/Kernel/Bus/USB/USBConfiguration.h b/Kernel/Bus/USB/USBConfiguration.h
index 3fba019ef8..7173d93d74 100644
--- a/Kernel/Bus/USB/USBConfiguration.h
+++ b/Kernel/Bus/USB/USBConfiguration.h
@@ -9,6 +9,7 @@
#include <AK/Vector.h>
#include <Kernel/Bus/USB/USBDescriptors.h>
#include <Kernel/Bus/USB/USBDevice.h>
+#include <Kernel/Bus/USB/USBInterface.h>
namespace Kernel::USB {
@@ -17,22 +18,27 @@ class Device;
class USBConfiguration {
public:
USBConfiguration() = delete;
- USBConfiguration(Device& device, USBConfigurationDescriptor const configuration_descriptor)
+ USBConfiguration(Device& device, USBConfigurationDescriptor const descriptor)
: m_device(device)
- , m_descriptor(configuration_descriptor)
+ , m_descriptor(descriptor)
{
+ m_interfaces.ensure_capacity(descriptor.number_of_interfaces);
}
Device const& device() const { return m_device; }
+ USBConfigurationDescriptor const& descriptor() const { return m_descriptor; }
u8 interface_count() const { return m_descriptor.number_of_interfaces; }
u8 configuration_id() const { return m_descriptor.configuration_value; }
u8 attributes() const { return m_descriptor.attributes_bitmap; }
u16 max_power_ma() const { return m_descriptor.max_power_in_ma * 2u; } // Note: "Power" is used incorrectly here, however it's what it's called in the descriptor/documentation
+ ErrorOr<void> get_interfaces();
+
private:
- Device& m_device; // Reference to the device linked to this configuration
- USBConfigurationDescriptor m_descriptor; // Descriptor that backs this configuration
+ Device& m_device; // Reference to the device linked to this configuration
+ USBConfigurationDescriptor const m_descriptor; // Descriptor that backs this configuration
+ Vector<USBInterface> m_interfaces; // Interfaces for this device
};
}
diff --git a/Kernel/Bus/USB/USBDevice.cpp b/Kernel/Bus/USB/USBDevice.cpp
index 695b9c4b3d..4db695f129 100644
--- a/Kernel/Bus/USB/USBDevice.cpp
+++ b/Kernel/Bus/USB/USBDevice.cpp
@@ -132,6 +132,7 @@ ErrorOr<void> Device::enumerate_device()
}
USBConfiguration device_configuration(*this, configuration_descriptor);
+ TRY(device_configuration.get_interfaces());
m_configurations.append(device_configuration);
}
diff --git a/Kernel/Bus/USB/USBInterface.h b/Kernel/Bus/USB/USBInterface.h
new file mode 100644
index 0000000000..d0131464cd
--- /dev/null
+++ b/Kernel/Bus/USB/USBInterface.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022, Jesse Buhagiar <jesse.buhagiar@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Vector.h>
+
+namespace Kernel::USB {
+
+class USBConfiguration;
+
+class USBInterface final {
+public:
+ USBInterface() = delete;
+ USBInterface(USBConfiguration const& configuration, USBInterfaceDescriptor const descriptor, Vector<USBEndpointDescriptor> const& endpoint_descriptors)
+ : m_configuration(configuration)
+ , m_descriptor(descriptor)
+ , m_endpoint_descriptors(endpoint_descriptors)
+ {
+ m_endpoint_descriptors.ensure_capacity(descriptor.number_of_endpoints);
+ }
+
+private:
+ USBConfiguration const& m_configuration; // Configuration that this interface belongs to
+ USBInterfaceDescriptor const m_descriptor; // Descriptor backing this interface
+ Vector<USBEndpointDescriptor> m_endpoint_descriptors; // Endpoint descriptors for this interface (that we can use to open an endpoint)
+};
+
+}
diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt
index 8461f7e715..002b977a2e 100644
--- a/Kernel/CMakeLists.txt
+++ b/Kernel/CMakeLists.txt
@@ -30,6 +30,7 @@ set(KERNEL_SOURCES
Bus/USB/SysFSUSB.cpp
Bus/USB/UHCI/UHCIController.cpp
Bus/USB/UHCI/UHCIRootHub.cpp
+ Bus/USB/USBConfiguration.cpp
Bus/USB/USBController.cpp
Bus/USB/USBDevice.cpp
Bus/USB/USBHub.cpp