Kernel/USB: Add support for bulk transfers

This commit is contained in:
b14ckcat 2022-05-08 01:36:20 -04:00 committed by Andreas Kling
parent 6a3f959e92
commit 8a7876d65c
7 changed files with 80 additions and 0 deletions

View file

@ -430,6 +430,50 @@ ErrorOr<size_t> UHCIController::submit_control_transfer(Transfer& transfer)
return transfer_size;
}
ErrorOr<size_t> UHCIController::submit_bulk_transfer(Transfer& transfer)
{
Pipe& pipe = transfer.pipe();
dbgln_if(UHCI_DEBUG, "UHCI: Received bulk transfer for address {}. Root Hub is at address {}.", pipe.device_address(), m_root_hub->device_address());
// Create a new descriptor chain
TransferDescriptor* last_data_descriptor;
TransferDescriptor* data_descriptor_chain;
auto buffer_address = Ptr32<u8>(transfer.buffer_physical().as_ptr());
TRY(create_chain(pipe, transfer.pipe().direction() == Pipe::Direction::In ? PacketID::IN : PacketID::OUT, buffer_address, pipe.max_packet_size(), transfer.transfer_data_size(), &data_descriptor_chain, &last_data_descriptor));
last_data_descriptor->terminate();
if constexpr (UHCI_VERBOSE_DEBUG) {
if (data_descriptor_chain) {
dbgln("Data TD");
data_descriptor_chain->print();
}
}
QueueHead* transfer_queue = allocate_queue_head();
if (!transfer_queue) {
free_descriptor_chain(data_descriptor_chain);
return 0;
}
transfer_queue->attach_transfer_descriptor_chain(data_descriptor_chain);
transfer_queue->set_transfer(&transfer);
m_bulk_qh->attach_transfer_queue(*transfer_queue);
size_t transfer_size = 0;
while (!transfer.complete()) {
transfer_size = poll_transfer_queue(*transfer_queue);
dbgln_if(USB_DEBUG, "Transfer size: {}", transfer_size);
}
free_descriptor_chain(transfer_queue->get_first_td());
transfer_queue->free();
m_queue_head_pool->release_to_pool(transfer_queue);
return transfer_size;
}
size_t UHCIController::poll_transfer_queue(QueueHead& transfer_queue)
{
Transfer* transfer = transfer_queue.transfer();

View file

@ -45,6 +45,7 @@ public:
ErrorOr<void> spawn_port_process();
virtual ErrorOr<size_t> submit_control_transfer(Transfer& transfer) override;
virtual ErrorOr<size_t> submit_bulk_transfer(Transfer& transfer) override;
void get_port_status(Badge<UHCIRootHub>, u8, HubStatus&);
ErrorOr<void> set_port_feature(Badge<UHCIRootHub>, u8, HubFeatureSelector);

View file

@ -24,6 +24,7 @@ public:
virtual ErrorOr<void> start() = 0;
virtual ErrorOr<size_t> submit_control_transfer(Transfer&) = 0;
virtual ErrorOr<size_t> submit_bulk_transfer(Transfer& transfer) = 0;
u8 allocate_address();

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/StdLibExtras.h>
#include <Kernel/Bus/USB/PacketTypes.h>
#include <Kernel/Bus/USB/UHCI/UHCIController.h>
#include <Kernel/Bus/USB/USBPipe.h>
@ -71,4 +72,24 @@ ErrorOr<size_t> Pipe::control_transfer(u8 request_type, u8 request, u16 value, u
return transfer_length;
}
ErrorOr<size_t> Pipe::bulk_transfer(u16 length, void* data)
{
size_t transfer_length = 0;
auto transfer = TRY(Transfer::try_create(*this, length));
if (m_direction == Direction::In) {
dbgln_if(USB_DEBUG, "Pipe: Bulk in transfer allocated @ {}", transfer->buffer_physical());
transfer_length = TRY(m_controller->submit_bulk_transfer(*transfer));
memcpy(data, transfer->buffer().as_ptr(), min(length, transfer_length));
dbgln_if(USB_DEBUG, "Pipe: Bulk in transfer complete!");
} else if (m_direction == Direction::Out) {
TRY(transfer->write_buffer(length, data));
dbgln_if(USB_DEBUG, "Pipe: Bulk out transfer allocated @ {}", transfer->buffer_physical());
transfer_length = TRY(m_controller->submit_bulk_transfer(*transfer));
dbgln_if(USB_DEBUG, "Pipe: Bulk out transfer complete!");
}
return transfer_length;
}
}

View file

@ -57,6 +57,7 @@ public:
void set_device_address(i8 addr) { m_device_address = addr; }
ErrorOr<size_t> control_transfer(u8 request_type, u8 request, u16 value, u16 index, u16 length, void* data);
ErrorOr<size_t> bulk_transfer(u16 length, void* data);
Pipe(USBController const& controller, Type type, Direction direction, u16 max_packet_size);
Pipe(USBController const& controller, Type type, Direction direction, USBEndpointDescriptor& endpoint);

View file

@ -43,4 +43,13 @@ void Transfer::set_setup_packet(USBRequestData const& request)
m_request = request;
}
ErrorOr<void> Transfer::write_buffer(u16 len, void* data)
{
VERIFY(len <= m_data_buffer->size());
m_transfer_data_size = len;
memcpy(buffer().as_ptr(), data, len);
return {};
}
}

View file

@ -28,6 +28,8 @@ public:
void set_complete() { m_complete = true; }
void set_error_occurred() { m_error_occurred = true; }
ErrorOr<void> write_buffer(u16 len, void* data);
// `const` here makes sure we don't blow up by writing to a physical address
USBRequestData const& request() const { return m_request; }
Pipe const& pipe() const { return m_pipe; }
@ -47,4 +49,5 @@ private:
bool m_complete { false }; // Has this transfer been completed?
bool m_error_occurred { false }; // Did an error occur during this transfer?
};
}