Serenity Operating System
at master 163 lines 7.8 kB view raw
1/* 2 * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com> 3 * Copyright (c) 2022, blackcat <b14ckcat@protonmail.com> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/StdLibExtras.h> 9#include <Kernel/Bus/USB/PacketTypes.h> 10#include <Kernel/Bus/USB/UHCI/UHCIController.h> 11#include <Kernel/Bus/USB/USBPipe.h> 12#include <Kernel/Bus/USB/USBTransfer.h> 13 14namespace Kernel::USB { 15 16Pipe::Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer) 17 : m_controller(controller) 18 , m_type(type) 19 , m_direction(direction) 20 , m_device_address(device_address) 21 , m_endpoint_address(endpoint_address) 22 , m_max_packet_size(max_packet_size) 23 , m_data_toggle(false) 24 , m_dma_buffer(move(dma_buffer)) 25{ 26} 27 28ErrorOr<NonnullOwnPtr<ControlPipe>> ControlPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size) 29{ 30 auto dma_buffer = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB device DMA buffer"sv, Memory::Region::Access::ReadWrite)); 31 return adopt_nonnull_own_or_enomem(new (nothrow) ControlPipe(controller, endpoint_address, max_packet_size, device_address, move(dma_buffer))); 32} 33 34ControlPipe::ControlPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer) 35 : Pipe(controller, Type::Control, Direction::Bidirectional, endpoint_address, max_packet_size, device_address, move(dma_buffer)) 36{ 37} 38 39ErrorOr<size_t> ControlPipe::submit_control_transfer(u8 request_type, u8 request, u16 value, u16 index, size_t length, void* data) 40{ 41 VERIFY(length <= m_dma_buffer->size()); 42 43 MutexLocker lock(m_dma_buffer_lock); 44 45 USBRequestData usb_request; 46 47 usb_request.request_type = request_type; 48 usb_request.request = request; 49 usb_request.value = value; 50 usb_request.index = index; 51 usb_request.length = length; 52 53 auto transfer = TRY(Transfer::create(*this, length, *m_dma_buffer)); 54 transfer->set_setup_packet(usb_request); 55 56 dbgln_if(USB_DEBUG, "ControlPipe: Transfer allocated @ {}", transfer->buffer_physical()); 57 auto transfer_length = TRY(m_controller->submit_control_transfer(*transfer)); 58 59 // TODO: Check transfer for completion and copy data from transfer buffer into data 60 if (length > 0) 61 memcpy(reinterpret_cast<u8*>(data), transfer->buffer().as_ptr() + sizeof(USBRequestData), length); 62 63 dbgln_if(USB_DEBUG, "Pipe: Control Transfer complete!"); 64 return transfer_length; 65} 66 67ErrorOr<NonnullOwnPtr<BulkInPipe>> BulkInPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size) 68{ 69 VERIFY(buffer_size >= max_packet_size); 70 auto dma_buffer = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB pipe DMA buffer"sv, Memory::Region::Access::ReadWrite)); 71 return adopt_nonnull_own_or_enomem(new (nothrow) BulkInPipe(controller, endpoint_address, max_packet_size, device_address, move(dma_buffer))); 72} 73 74BulkInPipe::BulkInPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer) 75 : Pipe(controller, Pipe::Type::Bulk, Direction::In, endpoint_address, max_packet_size, device_address, move(dma_buffer)) 76{ 77} 78 79ErrorOr<size_t> BulkInPipe::submit_bulk_in_transfer(size_t length, void* data) 80{ 81 VERIFY(length <= m_dma_buffer->size()); 82 83 MutexLocker lock(m_dma_buffer_lock); 84 85 size_t transfer_length = 0; 86 87 auto transfer = TRY(Transfer::create(*this, length, *m_dma_buffer)); 88 89 dbgln_if(USB_DEBUG, "Pipe: Bulk in transfer allocated @ {}", transfer->buffer_physical()); 90 transfer_length = TRY(m_controller->submit_bulk_transfer(*transfer)); 91 memcpy(data, transfer->buffer().as_ptr(), min(length, transfer_length)); 92 dbgln_if(USB_DEBUG, "Pipe: Bulk in transfer complete!"); 93 94 return transfer_length; 95} 96 97ErrorOr<NonnullOwnPtr<BulkOutPipe>> BulkOutPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size) 98{ 99 VERIFY(buffer_size >= max_packet_size); 100 auto dma_buffer = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB pipe DMA buffer"sv, Memory::Region::Access::ReadWrite)); 101 return adopt_nonnull_own_or_enomem(new (nothrow) BulkOutPipe(controller, endpoint_address, max_packet_size, device_address, move(dma_buffer))); 102} 103 104BulkOutPipe::BulkOutPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer) 105 : Pipe(controller, Type::Bulk, Direction::Out, endpoint_address, max_packet_size, device_address, move(dma_buffer)) 106 107{ 108} 109 110ErrorOr<size_t> BulkOutPipe::submit_bulk_out_transfer(size_t length, void* data) 111{ 112 VERIFY(length <= m_dma_buffer->size()); 113 114 MutexLocker lock(m_dma_buffer_lock); 115 116 size_t transfer_length = 0; 117 auto transfer = TRY(Transfer::create(*this, length, *m_dma_buffer)); 118 119 TRY(transfer->write_buffer(length, data)); 120 dbgln_if(USB_DEBUG, "Pipe: Bulk out transfer allocated @ {}", transfer->buffer_physical()); 121 transfer_length = TRY(m_controller->submit_bulk_transfer(*transfer)); 122 dbgln_if(USB_DEBUG, "Pipe: Bulk out transfer complete!"); 123 124 return transfer_length; 125} 126 127ErrorOr<NonnullOwnPtr<InterruptInPipe>> InterruptInPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, size_t buffer_size) 128{ 129 VERIFY(buffer_size >= max_packet_size); 130 auto dma_buffer = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB pipe DMA buffer"sv, Memory::Region::Access::ReadWrite)); 131 return adopt_nonnull_own_or_enomem(new (nothrow) InterruptInPipe(controller, endpoint_address, max_packet_size, device_address, poll_interval, move(dma_buffer))); 132} 133 134InterruptInPipe::InterruptInPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, NonnullOwnPtr<Memory::Region> dma_buffer) 135 : Pipe(controller, Type::Interrupt, Direction::In, endpoint_address, max_packet_size, device_address, move(dma_buffer)) 136 , m_poll_interval(poll_interval) 137{ 138} 139 140ErrorOr<NonnullLockRefPtr<Transfer>> InterruptInPipe::submit_interrupt_in_transfer(size_t length, u16 ms_interval, USBAsyncCallback callback) 141{ 142 VERIFY(length <= m_dma_buffer->size()); 143 144 auto transfer = TRY(Transfer::create(*this, length, *m_dma_buffer, move(callback))); 145 dbgln_if(USB_DEBUG, "Pipe: Interrupt in transfer allocated @ {}", transfer->buffer_physical()); 146 TRY(m_controller->submit_async_interrupt_transfer(transfer, ms_interval)); 147 return transfer; 148} 149 150ErrorOr<NonnullOwnPtr<InterruptOutPipe>> InterruptOutPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, size_t buffer_size) 151{ 152 VERIFY(buffer_size >= max_packet_size); 153 auto dma_buffer = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB pipe DMA buffer"sv, Memory::Region::Access::ReadWrite)); 154 return adopt_nonnull_own_or_enomem(new (nothrow) InterruptOutPipe(controller, endpoint_address, max_packet_size, device_address, poll_interval, move(dma_buffer))); 155} 156 157InterruptOutPipe::InterruptOutPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, NonnullOwnPtr<Memory::Region> dma_buffer) 158 : Pipe(controller, Type::Interrupt, Direction::In, endpoint_address, max_packet_size, device_address, move(dma_buffer)) 159 , m_poll_interval(poll_interval) 160{ 161} 162 163}