* 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:
@@ -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 -
|
// #pragma mark -
|
||||||
//
|
//
|
||||||
@@ -233,48 +287,3 @@ ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value,
|
|||||||
delete transfer;
|
delete transfer;
|
||||||
return result;
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ set_feature(const void *object, uint16 selector)
|
|||||||
if (!object)
|
if (!object)
|
||||||
return B_BAD_VALUE;
|
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)
|
if (!object)
|
||||||
return B_BAD_VALUE;
|
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)
|
if (!object || !status)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
return ((ControlPipe *)object)->GetStatus(status);
|
return ((Pipe *)object)->GetStatus(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,11 @@ virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; };
|
|||||||
status_t SubmitTransfer(Transfer *transfer);
|
status_t SubmitTransfer(Transfer *transfer);
|
||||||
status_t CancelQueuedTransfers();
|
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:
|
protected:
|
||||||
Device *fDevice;
|
Device *fDevice;
|
||||||
BusManager *fBus;
|
BusManager *fBus;
|
||||||
@@ -269,11 +274,6 @@ virtual void SetDataToggle(bool toggle) {};
|
|||||||
usb_callback_func callback,
|
usb_callback_func callback,
|
||||||
void *callbackCookie);
|
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:
|
private:
|
||||||
int8 fDeviceAddress;
|
int8 fDeviceAddress;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -768,20 +768,24 @@ UHCI::FinishTransfers()
|
|||||||
transfer->first_descriptor,
|
transfer->first_descriptor,
|
||||||
transfer->last_descriptor);
|
transfer->last_descriptor);
|
||||||
|
|
||||||
size_t length = 0;
|
size_t actualLength = 0;
|
||||||
|
uint8 lastDataToggle = 0;
|
||||||
if (transfer->data_descriptor && transfer->incoming) {
|
if (transfer->data_descriptor && transfer->incoming) {
|
||||||
// data to read out
|
// data to read out
|
||||||
length = ReadDescriptorChain(
|
actualLength = ReadDescriptorChain(
|
||||||
transfer->data_descriptor,
|
transfer->data_descriptor,
|
||||||
transfer->transfer->Data(),
|
transfer->transfer->Data(),
|
||||||
transfer->transfer->DataLength());
|
transfer->transfer->DataLength(),
|
||||||
|
&lastDataToggle);
|
||||||
} else {
|
} else {
|
||||||
// read the actual length that was sent
|
// read the actual length that was sent
|
||||||
length = ReadActualLength(transfer->first_descriptor);
|
actualLength = ReadActualLength(
|
||||||
|
transfer->first_descriptor, &lastDataToggle);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeDescriptorChain(transfer->first_descriptor);
|
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;
|
transferDone = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1152,7 +1156,6 @@ UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
|
|||||||
firstDescriptor = descriptor;
|
firstDescriptor = descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipe->SetDataToggle(dataToggle);
|
|
||||||
*_firstDescriptor = firstDescriptor;
|
*_firstDescriptor = firstDescriptor;
|
||||||
*_lastDescriptor = lastDescriptor;
|
*_lastDescriptor = lastDescriptor;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -1227,10 +1230,11 @@ UHCI::WriteDescriptorChain(uhci_td *topDescriptor, const uint8 *buffer,
|
|||||||
|
|
||||||
size_t
|
size_t
|
||||||
UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer,
|
UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer,
|
||||||
size_t bufferLength)
|
size_t bufferLength, uint8 *lastDataToggle)
|
||||||
{
|
{
|
||||||
size_t actualLength = 0;
|
size_t actualLength = 0;
|
||||||
uhci_td *current = topDescriptor;
|
uhci_td *current = topDescriptor;
|
||||||
|
uint8 dataToggle = 0;
|
||||||
|
|
||||||
while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
|
while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
|
||||||
if (!current->buffer_log)
|
if (!current->buffer_log)
|
||||||
@@ -1243,9 +1247,10 @@ UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer,
|
|||||||
length = min_c(length, bufferLength);
|
length = min_c(length, bufferLength);
|
||||||
memcpy(buffer, current->buffer_log, length);
|
memcpy(buffer, current->buffer_log, length);
|
||||||
|
|
||||||
|
buffer += length;
|
||||||
bufferLength -= length;
|
bufferLength -= length;
|
||||||
actualLength += length;
|
actualLength += length;
|
||||||
buffer += length;
|
dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
|
||||||
|
|
||||||
if (current->link_phy & TD_TERMINATE)
|
if (current->link_phy & TD_TERMINATE)
|
||||||
break;
|
break;
|
||||||
@@ -1253,30 +1258,38 @@ UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer,
|
|||||||
current = (uhci_td *)current->link_log;
|
current = (uhci_td *)current->link_log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lastDataToggle)
|
||||||
|
*lastDataToggle = dataToggle;
|
||||||
|
|
||||||
TRACE(("usb_uhci: read descriptor chain (%d bytes)\n", actualLength));
|
TRACE(("usb_uhci: read descriptor chain (%d bytes)\n", actualLength));
|
||||||
return actualLength;
|
return actualLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
UHCI::ReadActualLength(uhci_td *topDescriptor)
|
UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle)
|
||||||
{
|
{
|
||||||
size_t actualLength = 0;
|
size_t actualLength = 0;
|
||||||
uhci_td *current = topDescriptor;
|
uhci_td *current = topDescriptor;
|
||||||
|
uint8 dataToggle = 0;
|
||||||
|
|
||||||
while (current && (current->status & TD_STATUS_ACTIVE) == 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;
|
size_t length = (current->status & TD_STATUS_ACTLEN_MASK) + 1;
|
||||||
if (length == TD_STATUS_ACTLEN_NULL + 1)
|
if (length == TD_STATUS_ACTLEN_NULL + 1)
|
||||||
length = 0;
|
length = 0;
|
||||||
|
|
||||||
actualLength += length;
|
actualLength += length;
|
||||||
|
dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
|
||||||
|
|
||||||
if (current->link_phy & TD_TERMINATE)
|
if (current->link_phy & TD_TERMINATE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
current = (uhci_td *)current->link_log;
|
current = (uhci_td *)current->link_log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lastDataToggle)
|
||||||
|
*lastDataToggle = dataToggle;
|
||||||
|
|
||||||
TRACE(("usb_uhci: read actual length (%d bytes)\n", actualLength));
|
TRACE(("usb_uhci: read actual length (%d bytes)\n", actualLength));
|
||||||
return actualLength;
|
return actualLength;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,8 +121,10 @@ static int32 FinishThread(void *data);
|
|||||||
size_t WriteDescriptorChain(uhci_td *topDescriptor,
|
size_t WriteDescriptorChain(uhci_td *topDescriptor,
|
||||||
const uint8 *buffer, size_t bufferLength);
|
const uint8 *buffer, size_t bufferLength);
|
||||||
size_t ReadDescriptorChain(uhci_td *topDescriptor,
|
size_t ReadDescriptorChain(uhci_td *topDescriptor,
|
||||||
uint8 *buffer, size_t bufferLength);
|
uint8 *buffer, size_t bufferLength,
|
||||||
size_t ReadActualLength(uhci_td *topDescriptor);
|
uint8 *lastDataToggle);
|
||||||
|
size_t ReadActualLength(uhci_td *topDescriptor,
|
||||||
|
uint8 *lastDataToggle);
|
||||||
|
|
||||||
// Register functions
|
// Register functions
|
||||||
inline void WriteReg8(uint32 reg, uint8 value);
|
inline void WriteReg8(uint32 reg, uint8 value);
|
||||||
|
|||||||
@@ -116,7 +116,8 @@ typedef struct
|
|||||||
// Token
|
// Token
|
||||||
#define TD_TOKEN_MAXLEN_SHIFT 21
|
#define TD_TOKEN_MAXLEN_SHIFT 21
|
||||||
#define TD_TOKEN_NULL_DATA (0x07ff << TD_TOKEN_MAXLEN_SHIFT)
|
#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_SETUP 0x2d
|
||||||
#define TD_TOKEN_IN 0x69
|
#define TD_TOKEN_IN 0x69
|
||||||
|
|||||||
Reference in New Issue
Block a user