From 01489ae0603b930a2c14352c24138ca12c33a2d8 Mon Sep 17 00:00:00 2001 From: Salvatore Benedetto Date: Tue, 20 Nov 2007 22:16:42 +0000 Subject: [PATCH] * Remove SubmitAsyncTransfer and SubmitPeriodicTransfer * Added _SubmitControlRequest (almost implemented), _LinkDescriptors, _WriteDescriptorChain (basically copied from EHCI, and UHCI) * Renamed ohci_general_descriptor to ohci_general_td, and ohci_isochronous_descriptor to ohci_isochronous_td * Finished _CreateGeneralDescriptor and _FreeGeneralDescriptor * Added buffer_size member to ohci_general_td instead and removed last_logical_byte_address as it looked unnecessary * minor clean up git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22968 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/busses/usb/ohci.cpp | 194 ++++++++++++++++-- src/add-ons/kernel/busses/usb/ohci.h | 41 ++-- src/add-ons/kernel/busses/usb/ohci_hardware.h | 6 +- 3 files changed, 208 insertions(+), 33 deletions(-) diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp index 3dba9ce95f..e98b5f67bb 100644 --- a/src/add-ons/kernel/busses/usb/ohci.cpp +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -410,14 +410,19 @@ OHCI::SubmitTransfer(Transfer *transfer) return fRootHub->ProcessTransfer(this, transfer); uint32 type = transfer->TransferPipe()->Type(); - if ((type & USB_OBJECT_CONTROL_PIPE) || (type & USB_OBJECT_BULK_PIPE)) { - TRACE(("usb_ohci: submitting async transfer\n")); - return _SubmitAsyncTransfer(transfer); + if ((type & USB_OBJECT_CONTROL_PIPE)) { + TRACE(("usb_ohci: submitting control request\n")); + return _SubmitControlRequest(transfer); } - if ((type & USB_OBJECT_INTERRUPT_PIPE) || (type & USB_OBJECT_ISO_PIPE)) { - TRACE(("usb_ohci: submitting periodic transfer\n")); - return _SubmitPeriodicTransfer(transfer); + if ((type & USB_OBJECT_INTERRUPT_PIPE) || (type & USB_OBJECT_BULK_PIPE)) { + // TODO + return B_OK; + } + + if ((type & USB_OBJECT_ISO_PIPE)) { + TRACE(("usb_ohci: submitting isochronous transfer\n")); + return _SubmitIsochronousTransfer(transfer); } TRACE_ERROR(("usb_ohci: tried to submit transfer for unknown pipe" @@ -427,19 +432,152 @@ OHCI::SubmitTransfer(Transfer *transfer) status_t -OHCI::_SubmitAsyncTransfer(Transfer *transfer) +OHCI::_SubmitControlRequest(Transfer *transfer) +{ + usb_request_data *requestData = transfer->RequestData(); + bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0; + + ohci_general_td *setupDescriptor + = _CreateGeneralDescriptor(sizeof(usb_request_data)); + if (!setupDescriptor) { + TRACE_ERROR(("usb_ohci: failed to allocate setup descriptor\n")); + return B_NO_MEMORY; + } + // Flags set up could be moved into _CreateGeneralDescriptor + setupDescriptor->flags |= OHCI_TD_DIRECTION_PID_SETUP + | OHCI_TD_NO_CONDITION_CODE + | OHCI_TD_TOGGLE_0 + | OHCI_TD_SET_DELAY_INTERRUPT(6); // Not sure about this. + + ohci_general_td *statusDescriptor + = _CreateGeneralDescriptor(0); + if (!statusDescriptor) { + TRACE_ERROR(("usb_ohci: failed to allocate status descriptor\n")); + _FreeGeneralDescriptor(setupDescriptor); + return B_NO_MEMORY; + } + statusDescriptor->flags + |= (directionIn ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN) + | OHCI_TD_NO_CONDITION_CODE + | OHCI_TD_TOGGLE_1 + | OHCI_TD_SET_DELAY_INTERRUPT(1); + + iovec vector; + vector.iov_base = requestData; + vector.iov_len = sizeof(usb_request_data); + _WriteDescriptorChain(setupDescriptor, &vector, 1); + + if (transfer->VectorCount() > 0) { + ohci_general_td *dataDescriptor = NULL; + ohci_general_td *lastDescriptor = NULL; + status_t result = _CreateDescriptorChain(&dataDescriptor, + &lastDescriptor, + directionIn ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN, + transfer->VectorLength()); + if (result < B_OK) { + _FreeGeneralDescriptor(setupDescriptor); + _FreeGeneralDescriptor(statusDescriptor); + return result; + } + + if (!directionIn) { + _WriteDescriptorChain(dataDescriptor, transfer->Vector(), + transfer->VectorCount()); + } + + _LinkDescriptors(setupDescriptor, dataDescriptor); + _LinkDescriptors(lastDescriptor, statusDescriptor); + } else { + _LinkDescriptors(setupDescriptor, statusDescriptor); + } + + // TODO + // 1. Insert the chain descriptors to the endpoint + // 2. Clear the Skip bit in the enpoint + _WriteReg(OHCI_COMMAND_STATUS, OHCI_CONTROL_LIST_FILLED); + + return B_OK; +} + + +status_t +OHCI::_SubmitIsochronousTransfer(Transfer *transfer) { return B_ERROR; } +void +OHCI::_LinkDescriptors(ohci_general_td *first, ohci_general_td *second) +{ + first->next_physical_descriptor = second->physical_address; + first->next_logical_descriptor = second; +} + + status_t -OHCI::_SubmitPeriodicTransfer(Transfer *transfer) +OHCI::_CreateDescriptorChain(ohci_general_td **_firstDescriptor, + ohci_general_td **_lastDescriptor, uint8 direction, size_t bufferSize) { return B_ERROR; } +size_t +OHCI::_WriteDescriptorChain(ohci_general_td *topDescriptor, iovec *vector, + size_t vectorCount) +{ + ohci_general_td *current = topDescriptor; + size_t actualLength = 0; + size_t vectorIndex = 0; + size_t vectorOffset = 0; + size_t bufferOffset = 0; + + while (current) { + if (!current->buffer_logical) + break; + + while (true) { + size_t length = min_c(current->buffer_size - bufferOffset, + vector[vectorIndex].iov_len - vectorOffset); + + TRACE(("usb_ohci: copying %ld bytes to bufferOffset %ld from" + " vectorOffset %ld at index %ld of %ld\n", length, bufferOffset, + vectorOffset, vectorIndex, vectorCount)); + memcpy((uint8 *)current->buffer_logical + bufferOffset, + (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); + + actualLength += length; + vectorOffset += length; + bufferOffset += length; + + if (vectorOffset >= vector[vectorIndex].iov_len) { + if (++vectorIndex >= vectorCount) { + TRACE(("usb_ohci: wrote descriptor chain (%ld bytes, no" + " more vectors)\n", actualLength)); + return actualLength; + } + + vectorOffset = 0; + } + + if (bufferOffset >= current->buffer_size) { + bufferOffset = 0; + break; + } + } + + if (!current->next_logical_descriptor) + break; + + current = (ohci_general_td *)current->next_logical_descriptor; + } + + TRACE(("usb_ohci: wrote descriptor chain (%ld bytes)\n", actualLength)); + return actualLength; +} + + status_t OHCI::NotifyPipeChange(Pipe *pipe, usb_change change) { @@ -665,34 +803,54 @@ OHCI::_FreeEndpoint(ohci_endpoint_descriptor *endpoint) } -ohci_general_descriptor* -OHCI::_CreateGeneralDescriptor() +ohci_general_td* +OHCI::_CreateGeneralDescriptor(size_t bufferSize) { - ohci_general_descriptor *descriptor; + ohci_general_td *descriptor; void *physicalAddress; if (fStack->AllocateChunk((void **)&descriptor, &physicalAddress, - sizeof(ohci_general_descriptor)) != B_OK) { + sizeof(ohci_general_td)) != B_OK) { TRACE_ERROR(("usb_ohci: failed to allocate general descriptor\n")); return NULL; } - - // TODO: Finish methods - memset((void *)descriptor, 0, sizeof(ohci_general_descriptor)); + memset((void *)descriptor, 0, sizeof(ohci_general_td)); descriptor->physical_address = (addr_t)physicalAddress; + if (!bufferSize) { + descriptor->buffer_physical = 0; + descriptor->buffer_logical = NULL; + descriptor->last_physical_byte_address = 0; + return descriptor; + } + + if (fStack->AllocateChunk(&descriptor->buffer_logical, + (void **)&descriptor->buffer_physical, bufferSize) != B_OK) { + TRACE_ERROR(("usb_ohci: failed to allocate space for buffer\n")); + fStack->FreeChunk(descriptor, (void *)descriptor->physical_address, + sizeof(ohci_general_td)); + return NULL; + } + descriptor->last_physical_byte_address + = descriptor->buffer_physical + bufferSize - 1; + return descriptor; -} +} void -OHCI::_FreeGeneralDescriptor(ohci_general_descriptor *descriptor) +OHCI::_FreeGeneralDescriptor(ohci_general_td *descriptor) { if (!descriptor) return; + if (descriptor->buffer_logical) { + fStack->FreeChunk(descriptor->buffer_logical, + (void *)descriptor->buffer_physical, descriptor->buffer_size); + } + fStack->FreeChunk((void *)descriptor, (void *)descriptor->physical_address, - sizeof(ohci_general_descriptor)); + sizeof(ohci_general_td)); } diff --git a/src/add-ons/kernel/busses/usb/ohci.h b/src/add-ons/kernel/busses/usb/ohci.h index 1e81bac065..4af5ec48ad 100644 --- a/src/add-ons/kernel/busses/usb/ohci.h +++ b/src/add-ons/kernel/busses/usb/ohci.h @@ -31,7 +31,7 @@ typedef struct transfer_data_s { // -------------------------------------- typedef struct hcd_soft_itransfer { - ohci_isochronous_descriptor itd; + ohci_isochronous_td itd; struct hcd_soft_itransfer *nextitd; // mirrors nexttd in ITD struct hcd_soft_itransfer *dnext; // next in done list addr_t physaddr; // physical address to the host controller isonchronous transfer @@ -83,26 +83,43 @@ static int32 _InterruptHandler(void *data); static int32 _FinishThread(void *data); void _FinishTransfer(); - status_t _SubmitAsyncTransfer(Transfer *transfer); - status_t _SubmitPeriodicTransfer(Transfer *transfer); + status_t _SubmitControlRequest(Transfer *transfer); + status_t _SubmitIsochronousTransfer( + Transfer *transfer); // Endpoint related methods - status_t _InsertEndpointForPipe(Pipe *pipe); - status_t _RemoveEndpointForPipe(Pipe *pipe); - status_t _CreateEndpoint(Pipe *pipe, - bool isIsochronous); - ohci_endpoint_descriptor *_FindInterruptEndpoint(uint8 interval); ohci_endpoint_descriptor *_AllocateEndpoint(); void _FreeEndpoint( ohci_endpoint_descriptor *endpoint); + status_t _InsertEndpointForPipe(Pipe *pipe); + status_t _RemoveEndpointForPipe(Pipe *pipe); + ohci_endpoint_descriptor *_FindInterruptEndpoint(uint8 interval); // Transfer descriptor related methods - ohci_general_descriptor *_CreateGeneralDescriptor(); + ohci_general_td *_CreateGeneralDescriptor( + size_t bufferSize); + status_t _CreateDescriptorChain( + ohci_general_td **firstDescriptor, + ohci_general_td **lastDescriptor, + uint8 direction, + size_t bufferSize); + void _FreeGeneralDescriptor( - ohci_general_descriptor *descriptor); - ohci_isochronous_descriptor *_CreateIsochronousDescriptor(); + ohci_general_td *descriptor); + void _FreeDescriptorChain( + ohci_general_td *topDescriptor); + + void _LinkDescriptors(ohci_general_td *first, + ohci_general_td *second); + + ohci_isochronous_td *_CreateIsochronousDescriptor(); void _FreeIsochronousDescriptor( - ohci_isochronous_descriptor *descriptor); + ohci_isochronous_td *descriptor); + + size_t _WriteDescriptorChain( + ohci_general_td *topDescriptor, + iovec *vector, + size_t vectorCount); // Register functions inline void _WriteReg(uint32 reg, uint32 value); diff --git a/src/add-ons/kernel/busses/usb/ohci_hardware.h b/src/add-ons/kernel/busses/usb/ohci_hardware.h index eb6fce4547..1b733e93b0 100644 --- a/src/add-ons/kernel/busses/usb/ohci_hardware.h +++ b/src/add-ons/kernel/busses/usb/ohci_hardware.h @@ -333,7 +333,7 @@ typedef struct ohci_endpoint_descriptor // General transfer descriptor structure (section 4.3.1) // -------------------------------- -typedef struct ohci_general_descriptor +typedef struct ohci_general_td { // Hardware part uint32 flags; // Flags field @@ -344,7 +344,7 @@ typedef struct ohci_general_descriptor addr_t physical_address; // Physical pointer to this address void *buffer_logical; // Logical pointer to the buffer void *next_logical_descriptor; // Logical pointer next descriptor - void *last_logical_byte_address; // Logical pointer buffer end + size_t buffer_size; // Size of the buffer }; #define OHCI_BUFFER_ROUNDING 0x00040000 @@ -371,7 +371,7 @@ typedef struct ohci_general_descriptor // -------------------------------- #define OHCI_ITD_NOFFSET 8 -typedef struct ohci_isochronous_descriptor +typedef struct ohci_isochronous_td { uint32 flags; uint32 buffer_page_byte_0; // Physical page number of byte 0