summaryrefslogtreecommitdiff
path: root/Kernel/Bus
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/Bus')
-rw-r--r--Kernel/Bus/USB/UHCI/UHCIController.cpp44
-rw-r--r--Kernel/Bus/USB/UHCI/UHCIController.h1
-rw-r--r--Kernel/Bus/USB/USBController.h1
-rw-r--r--Kernel/Bus/USB/USBPipe.cpp21
-rw-r--r--Kernel/Bus/USB/USBPipe.h1
-rw-r--r--Kernel/Bus/USB/USBTransfer.cpp9
-rw-r--r--Kernel/Bus/USB/USBTransfer.h3
7 files changed, 80 insertions, 0 deletions
diff --git a/Kernel/Bus/USB/UHCI/UHCIController.cpp b/Kernel/Bus/USB/UHCI/UHCIController.cpp
index 488e3b59c4..aa35a8e0c4 100644
--- a/Kernel/Bus/USB/UHCI/UHCIController.cpp
+++ b/Kernel/Bus/USB/UHCI/UHCIController.cpp
@@ -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();
diff --git a/Kernel/Bus/USB/UHCI/UHCIController.h b/Kernel/Bus/USB/UHCI/UHCIController.h
index 66279b510e..a0d2dec5c6 100644
--- a/Kernel/Bus/USB/UHCI/UHCIController.h
+++ b/Kernel/Bus/USB/UHCI/UHCIController.h
@@ -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);
diff --git a/Kernel/Bus/USB/USBController.h b/Kernel/Bus/USB/USBController.h
index f5f8d561f8..7ff30819e3 100644
--- a/Kernel/Bus/USB/USBController.h
+++ b/Kernel/Bus/USB/USBController.h
@@ -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();
diff --git a/Kernel/Bus/USB/USBPipe.cpp b/Kernel/Bus/USB/USBPipe.cpp
index 940b0f5178..982cc14093 100644
--- a/Kernel/Bus/USB/USBPipe.cpp
+++ b/Kernel/Bus/USB/USBPipe.cpp
@@ -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;
+}
+
}
diff --git a/Kernel/Bus/USB/USBPipe.h b/Kernel/Bus/USB/USBPipe.h
index 3e9db8e272..0371f80517 100644
--- a/Kernel/Bus/USB/USBPipe.h
+++ b/Kernel/Bus/USB/USBPipe.h
@@ -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);
diff --git a/Kernel/Bus/USB/USBTransfer.cpp b/Kernel/Bus/USB/USBTransfer.cpp
index 62dc28e116..e664e7ced9 100644
--- a/Kernel/Bus/USB/USBTransfer.cpp
+++ b/Kernel/Bus/USB/USBTransfer.cpp
@@ -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 {};
+}
+
}
diff --git a/Kernel/Bus/USB/USBTransfer.h b/Kernel/Bus/USB/USBTransfer.h
index 78487da9fc..914a3c6d72 100644
--- a/Kernel/Bus/USB/USBTransfer.h
+++ b/Kernel/Bus/USB/USBTransfer.h
@@ -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?
};
+
}