* 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
This commit is contained in:
Michael Lotz
2006-08-20 01:07:15 +00:00
parent 5b0ec61f97
commit 1e8c0b3649
7 changed files with 148 additions and 46 deletions
@@ -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;
}
@@ -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 -
//
@@ -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);
}
+2 -1
View File
@@ -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);
}
+15 -4
View File
@@ -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;
+84 -34
View File
@@ -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;
+2 -2
View File
@@ -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);