* 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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user