* Fixed data toggle handling. It must be taken after the transfer finished and from the last transmitted transfer descriptor (which in case of a short packet is not neccessarily the last descriptor of the chain)

* Moved convenience endpoint requests from ControlPipe to Pipe

With this change, bulk transfers are fairly stable now. See here for evidence: http://haiku.mlotz.ch/haiku-usb01.png ;). Those are pictures from my Canon Digital Ixus 750 downloaded with Exposure using the PTP plugin. I of course navigated Haiku with my USB Logitech iFeel mouse which works nice since some days.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18510 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2006-08-14 19:26:51 +00:00
parent a6eda7a04f
commit 49617128ca
6 changed files with 91 additions and 66 deletions
+54 -45
View File
@@ -55,6 +55,60 @@ Pipe::CancelQueuedTransfers()
}
status_t
Pipe::SetFeature(uint16 selector)
{
if (!fDevice)
return B_ERROR;
return fDevice->SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
USB_REQUEST_SET_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
Pipe::ClearFeature(uint16 selector)
{
if (!fDevice)
return B_ERROR;
return fDevice->SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
USB_REQUEST_CLEAR_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
Pipe::GetStatus(uint16 *status)
{
if (!fDevice)
return B_ERROR;
return fDevice->SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN,
USB_REQUEST_GET_STATUS,
0,
0,
2,
(void *)status,
2,
NULL);
}
//
// #pragma mark -
//
@@ -233,48 +287,3 @@ ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value,
delete transfer;
return result;
}
status_t
ControlPipe::SetFeature(uint16 selector)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
USB_REQUEST_SET_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
ControlPipe::ClearFeature(uint16 selector)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
USB_REQUEST_CLEAR_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
ControlPipe::GetStatus(uint16 *status)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN,
USB_REQUEST_GET_STATUS,
0,
0,
2,
(void *)status,
2,
NULL);
}
+3 -3
View File
@@ -146,7 +146,7 @@ set_feature(const void *object, uint16 selector)
if (!object)
return B_BAD_VALUE;
return ((ControlPipe *)object)->SetFeature(selector);
return ((Pipe *)object)->SetFeature(selector);
}
@@ -157,7 +157,7 @@ clear_feature(const void *object, uint16 selector)
if (!object)
return B_BAD_VALUE;
return ((ControlPipe *)object)->ClearFeature(selector);
return ((Pipe *)object)->ClearFeature(selector);
}
@@ -168,7 +168,7 @@ get_status(const void *object, uint16 *status)
if (!object || !status)
return B_BAD_VALUE;
return ((ControlPipe *)object)->GetStatus(status);
return ((Pipe *)object)->GetStatus(status);
}
+5 -5
View File
@@ -167,6 +167,11 @@ virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; };
status_t SubmitTransfer(Transfer *transfer);
status_t CancelQueuedTransfers();
// Convenience functions for standard requests
virtual status_t SetFeature(uint16 selector);
virtual status_t ClearFeature(uint16 selector);
virtual status_t GetStatus(uint16 *status);
protected:
Device *fDevice;
BusManager *fBus;
@@ -269,11 +274,6 @@ virtual void SetDataToggle(bool toggle) {};
usb_callback_func callback,
void *callbackCookie);
// Convenience functions for standard requests
virtual status_t SetFeature(uint16 selector);
virtual status_t ClearFeature(uint16 selector);
virtual status_t GetStatus(uint16 *status);
private:
int8 fDeviceAddress;
};
+23 -10
View File
@@ -768,20 +768,24 @@ UHCI::FinishTransfers()
transfer->first_descriptor,
transfer->last_descriptor);
size_t length = 0;
size_t actualLength = 0;
uint8 lastDataToggle = 0;
if (transfer->data_descriptor && transfer->incoming) {
// data to read out
length = ReadDescriptorChain(
actualLength = ReadDescriptorChain(
transfer->data_descriptor,
transfer->transfer->Data(),
transfer->transfer->DataLength());
transfer->transfer->DataLength(),
&lastDataToggle);
} else {
// read the actual length that was sent
length = ReadActualLength(transfer->first_descriptor);
actualLength = ReadActualLength(
transfer->first_descriptor, &lastDataToggle);
}
FreeDescriptorChain(transfer->first_descriptor);
transfer->transfer->Finished(B_USB_STATUS_SUCCESS, length);
transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
transfer->transfer->Finished(B_USB_STATUS_SUCCESS, actualLength);
transferDone = true;
break;
}
@@ -1152,7 +1156,6 @@ UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
firstDescriptor = descriptor;
}
pipe->SetDataToggle(dataToggle);
*_firstDescriptor = firstDescriptor;
*_lastDescriptor = lastDescriptor;
return B_OK;
@@ -1227,10 +1230,11 @@ UHCI::WriteDescriptorChain(uhci_td *topDescriptor, const uint8 *buffer,
size_t
UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer,
size_t bufferLength)
size_t bufferLength, uint8 *lastDataToggle)
{
size_t actualLength = 0;
uhci_td *current = topDescriptor;
uint8 dataToggle = 0;
while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
if (!current->buffer_log)
@@ -1243,9 +1247,10 @@ UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer,
length = min_c(length, bufferLength);
memcpy(buffer, current->buffer_log, length);
buffer += length;
bufferLength -= length;
actualLength += length;
buffer += length;
dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
if (current->link_phy & TD_TERMINATE)
break;
@@ -1253,30 +1258,38 @@ UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer,
current = (uhci_td *)current->link_log;
}
if (lastDataToggle)
*lastDataToggle = dataToggle;
TRACE(("usb_uhci: read descriptor chain (%d bytes)\n", actualLength));
return actualLength;
}
size_t
UHCI::ReadActualLength(uhci_td *topDescriptor)
UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle)
{
size_t actualLength = 0;
uhci_td *current = topDescriptor;
uint8 dataToggle = 0;
while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
TRACE(("usb_uhci: reading actual length from status 0x%08x\n", current->status));
size_t length = (current->status & TD_STATUS_ACTLEN_MASK) + 1;
if (length == TD_STATUS_ACTLEN_NULL + 1)
length = 0;
actualLength += length;
dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
if (current->link_phy & TD_TERMINATE)
break;
current = (uhci_td *)current->link_log;
}
if (lastDataToggle)
*lastDataToggle = dataToggle;
TRACE(("usb_uhci: read actual length (%d bytes)\n", actualLength));
return actualLength;
}
+4 -2
View File
@@ -121,8 +121,10 @@ static int32 FinishThread(void *data);
size_t WriteDescriptorChain(uhci_td *topDescriptor,
const uint8 *buffer, size_t bufferLength);
size_t ReadDescriptorChain(uhci_td *topDescriptor,
uint8 *buffer, size_t bufferLength);
size_t ReadActualLength(uhci_td *topDescriptor);
uint8 *buffer, size_t bufferLength,
uint8 *lastDataToggle);
size_t ReadActualLength(uhci_td *topDescriptor,
uint8 *lastDataToggle);
// Register functions
inline void WriteReg8(uint32 reg, uint8 value);
@@ -116,7 +116,8 @@ typedef struct
// Token
#define TD_TOKEN_MAXLEN_SHIFT 21
#define TD_TOKEN_NULL_DATA (0x07ff << TD_TOKEN_MAXLEN_SHIFT)
#define TD_TOKEN_DATA1 (1 << 19)
#define TD_TOKEN_DATA_TOGGLE_SHIFT 19
#define TD_TOKEN_DATA1 (1 << TD_TOKEN_DATA_TOGGLE_SHIFT)
#define TD_TOKEN_SETUP 0x2d
#define TD_TOKEN_IN 0x69