From 1e8c0b3649ff4915369402f2e005b486ef6e7dfb Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sun, 20 Aug 2006 01:07:15 +0000 Subject: [PATCH] * Implemented iovec based data handling in Transfer and UHCI * Implemented QueueBulkV of the v3 API that uses it git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18540 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/bus_managers/usb/Hub.cpp | 1 + src/add-ons/kernel/bus_managers/usb/Pipe.cpp | 18 +++ .../kernel/bus_managers/usb/Transfer.cpp | 31 ++++- src/add-ons/kernel/bus_managers/usb/usb.cpp | 3 +- src/add-ons/kernel/bus_managers/usb/usb_p.h | 19 ++- src/add-ons/kernel/busses/usb/uhci.cpp | 118 +++++++++++++----- src/add-ons/kernel/busses/usb/uhci.h | 4 +- 7 files changed, 148 insertions(+), 46 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index ceafcf4087..7f5038aab1 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -207,6 +207,7 @@ Hub::Explore() TRACE(("USB Hub Explore(): Device removed\n")); if (fChildren[i]) { GetStack()->NotifyDeviceChange(fChildren[i], false); + GetStack()->PutUSBID(fChildren[i]->USBID()); delete fChildren[i]; fChildren[i] = NULL; } diff --git a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp index a3e75c47d2..fcf33d2968 100644 --- a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp @@ -184,6 +184,24 @@ BulkPipe::QueueBulk(void *data, size_t dataLength, usb_callback_func callback, } +status_t +BulkPipe::QueueBulkV(iovec *vector, size_t vectorCount, + usb_callback_func callback, void *callbackCookie) +{ + Transfer *transfer = new(std::nothrow) Transfer(this); + if (!transfer) + return B_NO_MEMORY; + + transfer->SetVector(vector, vectorCount); + transfer->SetCallback(callback, callbackCookie); + + status_t result = SubmitTransfer(transfer); + if (result < B_OK) + delete transfer; + return result; +} + + // // #pragma mark - // diff --git a/src/add-ons/kernel/bus_managers/usb/Transfer.cpp b/src/add-ons/kernel/bus_managers/usb/Transfer.cpp index faa592a03a..9f1f7da9f3 100644 --- a/src/add-ons/kernel/bus_managers/usb/Transfer.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Transfer.cpp @@ -11,8 +11,8 @@ Transfer::Transfer(Pipe *pipe) : fPipe(pipe), - fData(NULL), - fDataLength(0), + fVector(&fData), + fVectorCount(0), fCallback(NULL), fCallbackCookie(NULL), fRequestData(NULL) @@ -38,8 +38,29 @@ Transfer::SetRequestData(usb_request_data *data) void Transfer::SetData(uint8 *data, size_t dataLength) { - fData = data; - fDataLength = dataLength; + fData.iov_base = data; + fData.iov_len = dataLength; + + if (data && dataLength > 0) + fVectorCount = 1; +} + + +void +Transfer::SetVector(iovec *vector, size_t vectorCount) +{ + fVector = vector; + fVectorCount = vectorCount; +} + + +size_t +Transfer::VectorLength() +{ + size_t length = 0; + for (int32 i = 0; i < fVectorCount; i++) + length += fVector[i].iov_len; + return length; } @@ -55,5 +76,5 @@ void Transfer::Finished(uint32 status, size_t actualLength) { if (fCallback) - fCallback(fCallbackCookie, status, fData, actualLength); + fCallback(fCallbackCookie, status, fVector[0].iov_base, actualLength); } diff --git a/src/add-ons/kernel/bus_managers/usb/usb.cpp b/src/add-ons/kernel/bus_managers/usb/usb.cpp index 171a684f3b..263ae9b284 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb.cpp +++ b/src/add-ons/kernel/bus_managers/usb/usb.cpp @@ -267,7 +267,8 @@ queue_bulk_v(usb_pipe pipe, iovec *vector, size_t vectorCount, if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0) return B_BAD_VALUE; - return B_ERROR; + return ((BulkPipe *)object)->QueueBulkV(vector, vectorCount, callback, + callbackCookie); } diff --git a/src/add-ons/kernel/bus_managers/usb/usb_p.h b/src/add-ons/kernel/bus_managers/usb/usb_p.h index d8343c5b38..c6c6a02c33 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_p.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_p.h @@ -300,6 +300,10 @@ virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_BULK_PIPE; }; size_t dataLength, usb_callback_func callback, void *callbackCookie); + status_t QueueBulkV(iovec *vector, + size_t vectorCount, + usb_callback_func callback, + void *callbackCookie); }; @@ -451,8 +455,13 @@ public: usb_request_data *RequestData() { return fRequestData; }; void SetData(uint8 *buffer, size_t length); - uint8 *Data() { return fData; }; - size_t DataLength() { return fDataLength; }; + uint8 *Data() { return (uint8 *)fData.iov_base; }; + size_t DataLength() { return fData.iov_len; }; + + void SetVector(iovec *vector, size_t vectorCount); + iovec *Vector() { return fVector; }; + size_t VectorCount() { return fVectorCount; }; + size_t VectorLength(); void SetCallback(usb_callback_func callback, void *cookie); @@ -462,8 +471,10 @@ public: private: // Data that is related to the transfer Pipe *fPipe; - uint8 *fData; - size_t fDataLength; + iovec fData; + iovec *fVector; + size_t fVectorCount; + usb_callback_func fCallback; void *fCallbackCookie; diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 6a7749f144..0f4e4a3f52 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -523,7 +523,7 @@ UHCI::SubmitTransfer(Transfer *transfer) if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) return SubmitRequest(transfer); - if (!transfer->Data() || transfer->DataLength() == 0) + if (transfer->VectorCount() == 0) return B_BAD_VALUE; Pipe *pipe = transfer->TransferPipe(); @@ -533,7 +533,7 @@ UHCI::SubmitTransfer(Transfer *transfer) uhci_td *lastDescriptor = NULL; status_t result = CreateDescriptorChain(pipe, &firstDescriptor, &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, - transfer->DataLength()); + transfer->VectorLength()); if (result < B_OK) return result; @@ -545,8 +545,8 @@ UHCI::SubmitTransfer(Transfer *transfer) lastDescriptor->link_log = 0; if (!directionIn) { - WriteDescriptorChain(firstDescriptor, transfer->Data(), - transfer->DataLength()); + WriteDescriptorChain(firstDescriptor, transfer->Vector(), + transfer->VectorCount()); } Queue *queue = fQueues[3]; @@ -592,8 +592,10 @@ UHCI::SubmitRequest(Transfer *transfer) return B_NO_MEMORY; } - WriteDescriptorChain(setupDescriptor, (const uint8 *)requestData, - sizeof(usb_request_data)); + iovec vector; + vector.iov_base = requestData; + vector.iov_len = sizeof(usb_request_data); + WriteDescriptorChain(setupDescriptor, &vector, 1); statusDescriptor->status |= TD_CONTROL_IOC; statusDescriptor->token |= TD_TOKEN_DATA1; @@ -601,11 +603,11 @@ UHCI::SubmitRequest(Transfer *transfer) statusDescriptor->link_log = NULL; uhci_td *dataDescriptor = NULL; - if (transfer->Data() && transfer->DataLength() > 0) { + if (transfer->VectorCount() > 0) { uhci_td *lastDescriptor = NULL; status_t result = CreateDescriptorChain(pipe, &dataDescriptor, &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, - transfer->DataLength()); + transfer->VectorLength()); if (result < B_OK) { FreeDescriptor(setupDescriptor); @@ -614,8 +616,8 @@ UHCI::SubmitRequest(Transfer *transfer) } if (!directionIn) { - WriteDescriptorChain(dataDescriptor, transfer->Data(), - transfer->DataLength()); + WriteDescriptorChain(dataDescriptor, transfer->Vector(), + transfer->VectorCount()); } LinkDescriptors(setupDescriptor, dataDescriptor); @@ -759,8 +761,8 @@ UHCI::FinishTransfers() // data to read out actualLength = ReadDescriptorChain( transfer->data_descriptor, - transfer->transfer->Data(), - transfer->transfer->DataLength(), + transfer->transfer->Vector(), + transfer->transfer->VectorCount(), &lastDataToggle); } else { // read the actual length that was sent @@ -1186,22 +1188,45 @@ UHCI::LinkDescriptors(uhci_td *first, uhci_td *second) size_t -UHCI::WriteDescriptorChain(uhci_td *topDescriptor, const uint8 *buffer, - size_t bufferLength) +UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector, + size_t vectorCount) { - size_t actualLength = 0; uhci_td *current = topDescriptor; + size_t actualLength = 0; + size_t vectorIndex = 0; + size_t vectorOffset = 0; + size_t bufferOffset = 0; while (current) { if (!current->buffer_log) break; - size_t length = min_c(current->buffer_size, bufferLength); - memcpy(current->buffer_log, buffer, length); + while (true) { + size_t length = min_c(current->buffer_size - bufferOffset, + vector[vectorIndex].iov_len - vectorOffset); - bufferLength -= length; - actualLength += length; - buffer += length; + TRACE(("usb_uhci: copying %d bytes to bufferOffset %d from vectorOffset %d at index %d of %d\n", length, bufferOffset, vectorOffset, vectorIndex, vectorCount)); + memcpy((uint8 *)current->buffer_log + 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_uhci: wrote descriptor chain (%d bytes, no more vectors)\n", actualLength)); + return actualLength; + } + + vectorOffset = 0; + } + + if (bufferOffset >= current->buffer_size) { + bufferOffset = 0; + break; + } + } if (current->link_phy & TD_TERMINATE) break; @@ -1215,28 +1240,53 @@ UHCI::WriteDescriptorChain(uhci_td *topDescriptor, const uint8 *buffer, size_t -UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer, - size_t bufferLength, uint8 *lastDataToggle) +UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector, + size_t vectorCount, uint8 *lastDataToggle) { - size_t actualLength = 0; - uhci_td *current = topDescriptor; uint8 dataToggle = 0; + uhci_td *current = topDescriptor; + size_t actualLength = 0; + size_t vectorIndex = 0; + size_t vectorOffset = 0; + size_t bufferOffset = 0; while (current && (current->status & TD_STATUS_ACTIVE) == 0) { if (!current->buffer_log) break; - size_t length = (current->status & TD_STATUS_ACTLEN_MASK) + 1; - if (length == TD_STATUS_ACTLEN_NULL + 1) - length = 0; - - length = min_c(length, bufferLength); - memcpy(buffer, current->buffer_log, length); - - buffer += length; - bufferLength -= length; - actualLength += length; dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01; + size_t bufferSize = (current->status & TD_STATUS_ACTLEN_MASK) + 1; + if (bufferSize == TD_STATUS_ACTLEN_NULL + 1) + bufferSize = 0; + + while (true) { + size_t length = min_c(bufferSize - bufferOffset, + vector[vectorIndex].iov_len - vectorOffset); + + TRACE(("usb_uhci: copying %d bytes to vectorOffset %d from bufferOffset %d at index %d of %d\n", length, vectorOffset, bufferOffset, vectorIndex, vectorCount)); + memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, + (uint8 *)current->buffer_log + bufferOffset, length); + + actualLength += length; + vectorOffset += length; + bufferOffset += length; + + if (vectorOffset >= vector[vectorIndex].iov_len) { + if (++vectorIndex >= vectorCount) { + TRACE(("usb_uhci: read descriptor chain (%d bytes, no more vectors)\n", actualLength)); + if (lastDataToggle) + *lastDataToggle = dataToggle; + return actualLength; + } + + vectorOffset = 0; + } + + if (bufferOffset >= bufferSize) { + bufferOffset = 0; + break; + } + } if (current->link_phy & TD_TERMINATE) break; diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index f627c4e6ca..247893f502 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -116,9 +116,9 @@ static int32 FinishThread(void *data); uhci_td *second); size_t WriteDescriptorChain(uhci_td *topDescriptor, - const uint8 *buffer, size_t bufferLength); + iovec *vector, size_t vectorCount); size_t ReadDescriptorChain(uhci_td *topDescriptor, - uint8 *buffer, size_t bufferLength, + iovec *vector, size_t vectorCount, uint8 *lastDataToggle); size_t ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle);