mirror of
https://github.com/fergalmoran/ladybird.git
synced 2025-12-26 11:20:03 +00:00
This removes Pipes dependency on the UHCIController by introducing a controller base class. This will be used to implement other controllers such as OHCI. Additionally, there can be multiple instances of a UHCI controller. For example, multiple UHCI instances can be required for systems with EHCI controllers. EHCI relies on using multiple of either UHCI or OHCI controllers to drive USB 1.x devices. This means UHCIController can no longer be a singleton. Multiple instances of it can now be created and passed to the device and then to the pipe. To handle finding and creating these instances, USBManagement has been introduced. It has the same pattern as the other management classes such as NetworkManagement.
88 lines
2.8 KiB
C++
88 lines
2.8 KiB
C++
/*
|
|
* Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <Kernel/Bus/USB/PacketTypes.h>
|
|
#include <Kernel/Bus/USB/UHCIController.h>
|
|
#include <Kernel/Bus/USB/USBPipe.h>
|
|
#include <Kernel/Bus/USB/USBTransfer.h>
|
|
|
|
namespace Kernel::USB {
|
|
|
|
KResultOr<NonnullOwnPtr<Pipe>> Pipe::try_create_pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, i8 device_address, u8 poll_interval)
|
|
{
|
|
auto pipe = adopt_own_if_nonnull(new (nothrow) Pipe(controller, type, direction, endpoint_address, max_packet_size, device_address, poll_interval));
|
|
if (!pipe)
|
|
return ENOMEM;
|
|
|
|
return pipe.release_nonnull();
|
|
}
|
|
|
|
Pipe::Pipe(USBController const& controller, Type type, Pipe::Direction direction, u16 max_packet_size)
|
|
: m_controller(controller)
|
|
, m_type(type)
|
|
, m_direction(direction)
|
|
, m_endpoint_address(0)
|
|
, m_max_packet_size(max_packet_size)
|
|
, m_poll_interval(0)
|
|
, m_data_toggle(false)
|
|
{
|
|
}
|
|
|
|
Pipe::Pipe(USBController const& controller, Type type, Direction direction, USBEndpointDescriptor& endpoint [[maybe_unused]])
|
|
: m_controller(controller)
|
|
, m_type(type)
|
|
, m_direction(direction)
|
|
{
|
|
// TODO: decode endpoint structure
|
|
}
|
|
|
|
Pipe::Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, u8 poll_interval, i8 device_address)
|
|
: m_controller(controller)
|
|
, m_type(type)
|
|
, m_direction(direction)
|
|
, m_device_address(device_address)
|
|
, m_endpoint_address(endpoint_address)
|
|
, m_max_packet_size(max_packet_size)
|
|
, m_poll_interval(poll_interval)
|
|
, m_data_toggle(false)
|
|
{
|
|
}
|
|
|
|
KResultOr<size_t> Pipe::control_transfer(u8 request_type, u8 request, u16 value, u16 index, u16 length, void* data)
|
|
{
|
|
USBRequestData usb_request;
|
|
|
|
usb_request.request_type = request_type;
|
|
usb_request.request = request;
|
|
usb_request.value = value;
|
|
usb_request.index = index;
|
|
usb_request.length = length;
|
|
|
|
auto transfer = Transfer::try_create(*this, length);
|
|
|
|
if (!transfer)
|
|
return ENOMEM;
|
|
|
|
transfer->set_setup_packet(usb_request);
|
|
|
|
dbgln_if(USB_DEBUG, "Pipe: Transfer allocated @ {}", transfer->buffer_physical());
|
|
auto transfer_len_or_error = m_controller->submit_control_transfer(*transfer);
|
|
|
|
if (transfer_len_or_error.is_error())
|
|
return transfer_len_or_error.error();
|
|
|
|
auto transfer_length = transfer_len_or_error.release_value();
|
|
|
|
// TODO: Check transfer for completion and copy data from transfer buffer into data
|
|
if (length > 0)
|
|
memcpy(reinterpret_cast<u8*>(data), transfer->buffer().as_ptr() + sizeof(USBRequestData), length);
|
|
|
|
dbgln_if(USB_DEBUG, "Pipe: Control Transfer complete!");
|
|
return transfer_length;
|
|
}
|
|
|
|
}
|