mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 21:47:46 +00:00
Kernel/USB: Add support for bulk transfers
This commit is contained in:
parent
6a3f959e92
commit
8a7876d65c
7 changed files with 80 additions and 0 deletions
|
@ -430,6 +430,50 @@ ErrorOr<size_t> UHCIController::submit_control_transfer(Transfer& transfer)
|
||||||
return transfer_size;
|
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)
|
size_t UHCIController::poll_transfer_queue(QueueHead& transfer_queue)
|
||||||
{
|
{
|
||||||
Transfer* transfer = transfer_queue.transfer();
|
Transfer* transfer = transfer_queue.transfer();
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
ErrorOr<void> spawn_port_process();
|
ErrorOr<void> spawn_port_process();
|
||||||
|
|
||||||
virtual ErrorOr<size_t> submit_control_transfer(Transfer& transfer) override;
|
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&);
|
void get_port_status(Badge<UHCIRootHub>, u8, HubStatus&);
|
||||||
ErrorOr<void> set_port_feature(Badge<UHCIRootHub>, u8, HubFeatureSelector);
|
ErrorOr<void> set_port_feature(Badge<UHCIRootHub>, u8, HubFeatureSelector);
|
||||||
|
|
|
@ -24,6 +24,7 @@ public:
|
||||||
virtual ErrorOr<void> start() = 0;
|
virtual ErrorOr<void> start() = 0;
|
||||||
|
|
||||||
virtual ErrorOr<size_t> submit_control_transfer(Transfer&) = 0;
|
virtual ErrorOr<size_t> submit_control_transfer(Transfer&) = 0;
|
||||||
|
virtual ErrorOr<size_t> submit_bulk_transfer(Transfer& transfer) = 0;
|
||||||
|
|
||||||
u8 allocate_address();
|
u8 allocate_address();
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/StdLibExtras.h>
|
||||||
#include <Kernel/Bus/USB/PacketTypes.h>
|
#include <Kernel/Bus/USB/PacketTypes.h>
|
||||||
#include <Kernel/Bus/USB/UHCI/UHCIController.h>
|
#include <Kernel/Bus/USB/UHCI/UHCIController.h>
|
||||||
#include <Kernel/Bus/USB/USBPipe.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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
void set_device_address(i8 addr) { m_device_address = addr; }
|
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> 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, u16 max_packet_size);
|
||||||
Pipe(USBController const& controller, Type type, Direction direction, USBEndpointDescriptor& endpoint);
|
Pipe(USBController const& controller, Type type, Direction direction, USBEndpointDescriptor& endpoint);
|
||||||
|
|
|
@ -43,4 +43,13 @@ void Transfer::set_setup_packet(USBRequestData const& request)
|
||||||
m_request = 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 {};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ public:
|
||||||
void set_complete() { m_complete = true; }
|
void set_complete() { m_complete = true; }
|
||||||
void set_error_occurred() { m_error_occurred = 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
|
// `const` here makes sure we don't blow up by writing to a physical address
|
||||||
USBRequestData const& request() const { return m_request; }
|
USBRequestData const& request() const { return m_request; }
|
||||||
Pipe const& pipe() const { return m_pipe; }
|
Pipe const& pipe() const { return m_pipe; }
|
||||||
|
@ -47,4 +49,5 @@ private:
|
||||||
bool m_complete { false }; // Has this transfer been completed?
|
bool m_complete { false }; // Has this transfer been completed?
|
||||||
bool m_error_occurred { false }; // Did an error occur during this transfer?
|
bool m_error_occurred { false }; // Did an error occur during this transfer?
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue