/* * Copyright (c) 2021-2023, Jesse Buhagiar * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include namespace Kernel::USB { ErrorOr> Device::try_create(USBController& controller, Hub const& hub, u8 port, DeviceSpeed speed) { auto device = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) Device(controller, &hub, port, speed))); device->set_default_pipe(TRY(ControlPipe::create(controller, device, 0, 8))); TRY(controller.initialize_device(*device)); auto sysfs_node = TRY(SysFSUSBDeviceInformation::create(*device)); device->m_sysfs_device_info_node.with([&](auto& node) { node = move(sysfs_node); }); // Attempt to find a driver for this device. If one is found, we call the driver's // "probe" function, which initialises the local state for the device driver. // It is currently the driver's responsibility to search the configuration/interface // and take the appropriate action. for (auto& driver : USBManagement::available_drivers()) { // FIXME: Some devices have multiple configurations, for which we may have a better driver, // than the first we find, or we have a vendor specific driver for the device, // so we want a prioritization mechanism here auto result = driver->probe(device); if (result.is_error()) continue; dbgln_if(USB_DEBUG, "Found driver {} for device {:04x}:{:04x}!", driver->name(), device->m_vendor_id, device->m_product_id); device->set_driver(driver); break; } return device; } Device::Device(USBController const& controller, Hub const* hub, u8 port, DeviceSpeed speed) : m_device_port(port) , m_device_speed(speed) , m_address(0) , m_controller(controller) , m_hub(hub) { } Device::Device(USBController const& controller, Hub const* hub, u8 port, DeviceSpeed speed, u8 address, USBDeviceDescriptor const& descriptor) : m_device_port(port) , m_device_speed(speed) , m_address(address) , m_device_descriptor(descriptor) , m_controller(controller) , m_hub(hub) { } Device::Device(Device const& device) : m_device_port(device.port()) , m_device_speed(device.speed()) , m_address(device.address()) , m_controller_identifier(device.controller_identifier()) , m_device_descriptor(device.device_descriptor()) , m_controller(device.controller()) , m_hub(device.hub()) { // FIXME: This can definitely OOM m_configurations.ensure_capacity(device.configurations().size()); for (auto const& configuration : device.configurations()) { m_configurations.unchecked_append(configuration.copy()); m_configurations.last().set_device({}, *this); } // FIXME: Do we need to enter our selves into the hubs children list or sysfs list? } Device::~Device() = default; void Device::set_default_pipe(NonnullOwnPtr pipe) { VERIFY(!m_default_pipe); m_default_pipe = move(pipe); } ErrorOr Device::control_transfer(u8 request_type, u8 request, u16 value, u16 index, u16 length, void* data) { 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 {}; } }