Patches by Salvatore Benedetto to fix changes made by me and also the underlaying problem that caused high CPU usage in the isochronous finisher thread. Also includes patches to support isochronous support through USBKit / usb_raw. Thanks!
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21636 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#define _USBKIT_H
|
#define _USBKIT_H
|
||||||
|
|
||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
#include <USB3.h>
|
||||||
#include <USB_spec.h>
|
#include <USB_spec.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -257,7 +258,7 @@ mutable char *fInterfaceString;
|
|||||||
|
|
||||||
|
|
||||||
/* The BUSBEndpoint represent a device endpoint that can be used to send or
|
/* The BUSBEndpoint represent a device endpoint that can be used to send or
|
||||||
receive data. It also alows to query endpoint characteristics like
|
receive data. It also allows to query endpoint characteristics like
|
||||||
endpoint type or direction. */
|
endpoint type or direction. */
|
||||||
class BUSBEndpoint {
|
class BUSBEndpoint {
|
||||||
public:
|
public:
|
||||||
@@ -299,6 +300,10 @@ public:
|
|||||||
size_t length) const;
|
size_t length) const;
|
||||||
ssize_t BulkTransfer(void *data,
|
ssize_t BulkTransfer(void *data,
|
||||||
size_t length) const;
|
size_t length) const;
|
||||||
|
ssize_t IsochronousTransfer(void *data,
|
||||||
|
size_t length,
|
||||||
|
usb_iso_packet_descriptor *packetDescriptors,
|
||||||
|
uint32 packetCount) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class BUSBInterface;
|
friend class BUSBInterface;
|
||||||
|
|||||||
@@ -304,6 +304,8 @@ UHCI::UHCI(pci_info *info, Stack *stack)
|
|||||||
fStopFinishThread(false),
|
fStopFinishThread(false),
|
||||||
fFirstIsochronousTransfer(NULL),
|
fFirstIsochronousTransfer(NULL),
|
||||||
fLastIsochronousTransfer(NULL),
|
fLastIsochronousTransfer(NULL),
|
||||||
|
fFinishIsochronousThread(-1),
|
||||||
|
fStopFinishIsochronousThread(false),
|
||||||
fRootHub(NULL),
|
fRootHub(NULL),
|
||||||
fRootHubAddress(0),
|
fRootHubAddress(0),
|
||||||
fPortResetChange(0)
|
fPortResetChange(0)
|
||||||
@@ -396,9 +398,18 @@ UHCI::UHCI(pci_info *info, Stack *stack)
|
|||||||
// Create the array that will keep bandwidth information
|
// Create the array that will keep bandwidth information
|
||||||
fFrameBandwidth = new(std::nothrow) uint16[NUMBER_OF_FRAMES];
|
fFrameBandwidth = new(std::nothrow) uint16[NUMBER_OF_FRAMES];
|
||||||
|
|
||||||
// Create lists for managing isochronous transfer descriptors
|
// create lists for managing isochronous transfer descriptors
|
||||||
fFirstIsochronousDescriptor = new(std::nothrow) uhci_td *[NUMBER_OF_FRAMES];
|
fFirstIsochronousDescriptor = new(std::nothrow) uhci_td *[NUMBER_OF_FRAMES];
|
||||||
|
if (!fFirstIsochronousDescriptor) {
|
||||||
|
TRACE_ERROR(("usb_uhci: cannot allocate memory\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
fLastIsochronousDescriptor = new(std::nothrow) uhci_td *[NUMBER_OF_FRAMES];
|
fLastIsochronousDescriptor = new(std::nothrow) uhci_td *[NUMBER_OF_FRAMES];
|
||||||
|
if (!fLastIsochronousDescriptor) {
|
||||||
|
TRACE_ERROR(("usb_uhci: cannot allocate memory\n"));
|
||||||
|
delete [] fFirstIsochronousDescriptor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int32 i = 0; i < NUMBER_OF_FRAMES; i++) {
|
for (int32 i = 0; i < NUMBER_OF_FRAMES; i++) {
|
||||||
fFrameList[i] = fQueues[UHCI_INTERRUPT_QUEUE]->PhysicalAddress()
|
fFrameList[i] = fQueues[UHCI_INTERRUPT_QUEUE]->PhysicalAddress()
|
||||||
@@ -426,6 +437,20 @@ UHCI::UHCI(pci_info *info, Stack *stack)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create semaphore the isochronous finisher thread will wait for
|
||||||
|
fFinishIsochronousTransfersSem = create_sem(0,
|
||||||
|
"UHCI Isochronous Finish Transfers");
|
||||||
|
if (fFinishIsochronousTransfersSem < B_OK) {
|
||||||
|
TRACE_ERROR(("usb_uhci: failed to create semaphore\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the isochronous finisher service thread
|
||||||
|
fFinishIsochronousThread = spawn_kernel_thread(FinishIsochronousThread,
|
||||||
|
"uhci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY,
|
||||||
|
(void *)this);
|
||||||
|
resume_thread(fFinishIsochronousThread);
|
||||||
|
|
||||||
// Install the interrupt handler
|
// Install the interrupt handler
|
||||||
TRACE(("usb_uhci: installing interrupt handler\n"));
|
TRACE(("usb_uhci: installing interrupt handler\n"));
|
||||||
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
|
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
|
||||||
@@ -444,8 +469,11 @@ UHCI::~UHCI()
|
|||||||
{
|
{
|
||||||
int32 result = 0;
|
int32 result = 0;
|
||||||
fStopFinishThread = true;
|
fStopFinishThread = true;
|
||||||
|
fStopFinishIsochronousThread = true;
|
||||||
delete_sem(fFinishTransfersSem);
|
delete_sem(fFinishTransfersSem);
|
||||||
|
delete_sem(fFinishIsochronousTransfersSem);
|
||||||
wait_for_thread(fFinishThread, &result);
|
wait_for_thread(fFinishThread, &result);
|
||||||
|
wait_for_thread(fFinishIsochronousThread, &result);
|
||||||
|
|
||||||
LockIsochronous();
|
LockIsochronous();
|
||||||
isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer;
|
isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer;
|
||||||
@@ -627,7 +655,7 @@ UHCI::CancelQueuedIsochronousTransfers(Pipe *pipe)
|
|||||||
// Set the active bit off on every descriptor in order to prevent
|
// Set the active bit off on every descriptor in order to prevent
|
||||||
// the controller from processing them. Then set off the is_active
|
// the controller from processing them. Then set off the is_active
|
||||||
// field of the transfer in order to make the finisher thread skip
|
// field of the transfer in order to make the finisher thread skip
|
||||||
// the transfer. FinishIsochronousTransfers will do the rest.
|
// the transfer. The FinishIsochronousThread will do the rest.
|
||||||
for (int32 i = 0; i < packetCount; i++)
|
for (int32 i = 0; i < packetCount; i++)
|
||||||
current->descriptors[i]->status &= ~TD_STATUS_ACTIVE;
|
current->descriptors[i]->status &= ~TD_STATUS_ACTIVE;
|
||||||
current->is_active = false;
|
current->is_active = false;
|
||||||
@@ -815,10 +843,6 @@ UHCI::SubmitIsochronous(Transfer *transfer)
|
|||||||
TRACE(("usb_uhci: isochronous transfer descriptor bandwdith = %d\n",
|
TRACE(("usb_uhci: isochronous transfer descriptor bandwdith = %d\n",
|
||||||
bandwidth));
|
bandwidth));
|
||||||
|
|
||||||
// TODO: If direction is out set every descriptor data
|
|
||||||
if (!directionIn)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
// The following holds the list of transfer descriptor of the
|
// The following holds the list of transfer descriptor of the
|
||||||
// isochronous request. It is used to quickly remove all the isochronous
|
// isochronous request. It is used to quickly remove all the isochronous
|
||||||
// descriptors from the frame list, as descriptors are not link to each
|
// descriptors from the frame list, as descriptors are not link to each
|
||||||
@@ -841,15 +865,22 @@ UHCI::SubmitIsochronous(Transfer *transfer)
|
|||||||
isoRequest[isochronousData->packet_count - 1]->token &= ~TD_TOKEN_DATA1;
|
isoRequest[isochronousData->packet_count - 1]->token &= ~TD_TOKEN_DATA1;
|
||||||
isoRequest[isochronousData->packet_count - 1]->status |= TD_CONTROL_IOC;
|
isoRequest[isochronousData->packet_count - 1]->status |= TD_CONTROL_IOC;
|
||||||
|
|
||||||
TRACE(("usb_uhci: isochronous submitted size=%ld bytes, TDs=%ld, "
|
// If direction is out set every descriptor data
|
||||||
"packetSize=%ld, restSize=%ld\n", transfer->DataLength(),
|
if (!directionIn) {
|
||||||
isochronousData->packet_count, packetSize, restSize));
|
iovec *vector = transfer->Vector();
|
||||||
|
WriteIsochronousDescriptorChain(isoRequest,
|
||||||
|
isochronousData->packet_count, vector);
|
||||||
|
} else {
|
||||||
// Initialize the packet descriptors
|
// Initialize the packet descriptors
|
||||||
for (uint32 i = 0; i < isochronousData->packet_count; i++) {
|
for (uint32 i = 0; i < isochronousData->packet_count; i++) {
|
||||||
isochronousData->packet_descriptors[i].actual_length = 0;
|
isochronousData->packet_descriptors[i].actual_length = 0;
|
||||||
isochronousData->packet_descriptors[i].status = B_NO_INIT;
|
isochronousData->packet_descriptors[i].status = B_NO_INIT;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(("usb_uhci: isochronous submitted size=%ld bytes, TDs=%ld, "
|
||||||
|
"packetSize=%ld, restSize=%ld\n", transfer->DataLength(),
|
||||||
|
isochronousData->packet_count, packetSize, restSize));
|
||||||
|
|
||||||
// Find the entry where to start inserting the first Isochronous descriptor
|
// Find the entry where to start inserting the first Isochronous descriptor
|
||||||
if (isochronousData->flags & USB_ISO_ASAP ||
|
if (isochronousData->flags & USB_ISO_ASAP ||
|
||||||
@@ -911,6 +942,9 @@ UHCI::SubmitIsochronous(Transfer *transfer)
|
|||||||
currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
|
currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wake up the isochronous finisher thread
|
||||||
|
release_sem_etc(fFinishIsochronousTransfersSem, 1, B_DO_NOT_RESCHEDULE);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -991,9 +1025,6 @@ UHCI::FinishTransfers()
|
|||||||
if (semCount > 0)
|
if (semCount > 0)
|
||||||
acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
|
acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
|
||||||
|
|
||||||
// give the isochronous transfers a chance
|
|
||||||
FinishIsochronousTransfers();
|
|
||||||
|
|
||||||
if (!Lock())
|
if (!Lock())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1155,51 +1186,68 @@ UHCI::FinishTransfers()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
UHCI::FinishIsochronousThread(void *data)
|
||||||
|
{
|
||||||
|
((UHCI *)data)->FinishIsochronousTransfers();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
UHCI::FinishIsochronousTransfers()
|
UHCI::FinishIsochronousTransfers()
|
||||||
{
|
{
|
||||||
if (!LockIsochronous())
|
/* This thread stays one position behind the controller and processes every
|
||||||
|
* isochronous descriptor. Once it finds the last isochronous descriptor
|
||||||
|
* of a transfer, it processes the entire transfer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (!fStopFinishIsochronousThread) {
|
||||||
|
// Go to sleep if there are not isochronous transfer to process
|
||||||
|
if (acquire_sem(fFinishIsochronousTransfersSem) < B_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (uint16 frame = 0; frame < NUMBER_OF_FRAMES; frame++) {
|
bool transferDone = false;
|
||||||
uhci_td *current = fFirstIsochronousDescriptor[frame];
|
uint16 currentFrame = ReadReg16(UHCI_FRNUM);
|
||||||
|
|
||||||
while (current) {
|
// Process the frame list until one transfer is processed
|
||||||
if (current->status & TD_STATUS_ACTIVE) {
|
while (!transferDone) {
|
||||||
// The transfer descriptor is still active
|
// wait 1ms in order to be sure to be one position behind
|
||||||
current = (uhci_td *)current->link_log;
|
// the controller
|
||||||
continue;
|
if (currentFrame == ReadReg16(UHCI_FRNUM))
|
||||||
}
|
snooze(1000);
|
||||||
|
|
||||||
UnlinkIsochronousDescriptor(current, frame);
|
// Process the frame till it has isochronous descriptors in it.
|
||||||
if (!(current->status & TD_CONTROL_IOC)) {
|
while (!(fFrameList[currentFrame] & FRAMELIST_NEXT_IS_QH)) {
|
||||||
current = (uhci_td *)current->link_log;
|
uhci_td *current = fFirstIsochronousDescriptor[currentFrame];
|
||||||
continue;
|
UnlinkIsochronousDescriptor(current, currentFrame);
|
||||||
}
|
|
||||||
|
|
||||||
// Process the transfer if we found the last descriptor
|
// Process the transfer if we found the last descriptor
|
||||||
|
if (current->status & TD_CONTROL_IOC) {
|
||||||
isochronous_transfer_data *transfer
|
isochronous_transfer_data *transfer
|
||||||
= FindIsochronousTransfer(current);
|
= FindIsochronousTransfer(current);
|
||||||
|
|
||||||
// The following should NEVER happen
|
// The following should NEVER happen
|
||||||
if (!transfer) {
|
if (!transfer) {
|
||||||
TRACE_ERROR(("usb_uhci: Isochronous transfer not found in"
|
TRACE_ERROR(("usb_uhci: Isochronous transfer not found"
|
||||||
" the finisher thread!\n"));
|
" in the finisher thread!\n"));
|
||||||
return;
|
return;
|
||||||
} else if (transfer->is_active
|
|
||||||
&& (current->status & TD_TOKEN_IN)) {
|
|
||||||
// Process the descriptors only if it is still active and
|
// Process the descriptors only if it is still active and
|
||||||
// belongs to an inbound transfer. If the transfer is not
|
// belongs to an inbound transfer. If the transfer is not
|
||||||
// active, it means the request has been removed, so simply
|
// active, it means the request has been removed, so simply
|
||||||
// remove the descriptors.
|
// remove the descriptors.
|
||||||
|
} else if (transfer->is_active
|
||||||
|
&& (current->status & TD_TOKEN_IN)) {
|
||||||
iovec *vector = transfer->transfer->Vector();
|
iovec *vector = transfer->transfer->Vector();
|
||||||
transfer->transfer->PrepareKernelAccess();
|
transfer->transfer->PrepareKernelAccess();
|
||||||
ReadIsochronousDescriptorChain(transfer, vector);
|
ReadIsochronousDescriptorChain(transfer, vector);
|
||||||
|
|
||||||
// Remove the transfer
|
// Remove the transfer
|
||||||
if (transfer == fFirstIsochronousTransfer) {
|
if (LockIsochronous()) {
|
||||||
|
if (transfer == fFirstIsochronousTransfer)
|
||||||
fFirstIsochronousTransfer = transfer->link;
|
fFirstIsochronousTransfer = transfer->link;
|
||||||
} else {
|
else {
|
||||||
isochronous_transfer_data *temp
|
isochronous_transfer_data *temp
|
||||||
= fFirstIsochronousTransfer;
|
= fFirstIsochronousTransfer;
|
||||||
while (transfer != temp->link)
|
while (transfer != temp->link)
|
||||||
@@ -1210,27 +1258,30 @@ UHCI::FinishIsochronousTransfers()
|
|||||||
temp->link = temp->link->link;
|
temp->link = temp->link->link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnlockIsochronous();
|
||||||
|
}
|
||||||
|
|
||||||
transfer->transfer->Finished(B_OK, 0);
|
transfer->transfer->Finished(B_OK, 0);
|
||||||
} else if (!transfer->is_active)
|
|
||||||
transfer->transfer->Finished(B_CANCELED, 0);
|
|
||||||
|
|
||||||
uint32 packetCount =
|
uint32 packetCount =
|
||||||
transfer->transfer->IsochronousData()->packet_count;
|
transfer->transfer->IsochronousData()->packet_count;
|
||||||
for (uint32 i = 0; i < packetCount; i++)
|
for (uint32 i = 0; i < packetCount; i++)
|
||||||
FreeDescriptor(transfer->descriptors[i]);
|
FreeDescriptor(transfer->descriptors[i]);
|
||||||
|
|
||||||
uint16 bandwidth = transfer->transfer->Bandwidth() / packetCount;
|
|
||||||
fFrameBandwidth[frame] += bandwidth;
|
|
||||||
|
|
||||||
delete [] transfer->descriptors;
|
delete [] transfer->descriptors;
|
||||||
delete transfer->transfer;
|
delete transfer->transfer;
|
||||||
delete transfer;
|
delete transfer;
|
||||||
|
transferDone = true;
|
||||||
current = (uhci_td *)current->link_log;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure to reset the frame bandwidth
|
||||||
|
fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
|
||||||
|
currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnlockIsochronous();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1889,6 +1940,20 @@ UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UHCI::WriteIsochronousDescriptorChain(uhci_td **isoRequest, uint32 packetCount,
|
||||||
|
iovec *vector)
|
||||||
|
{
|
||||||
|
size_t vectorOffset = 0;
|
||||||
|
for (uint32 i = 0; i < packetCount; i++) {
|
||||||
|
size_t bufferSize = isoRequest[i]->buffer_size;
|
||||||
|
memcpy((uint8 *)isoRequest[i]->buffer_log,
|
||||||
|
(uint8 *)vector->iov_base + vectorOffset, bufferSize);
|
||||||
|
vectorOffset += bufferSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
UHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer,
|
UHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer,
|
||||||
iovec *vector)
|
iovec *vector)
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ static int32 FinishThread(void *data);
|
|||||||
uhci_qh **_transferQueue);
|
uhci_qh **_transferQueue);
|
||||||
|
|
||||||
// Isochronous transfer functions
|
// Isochronous transfer functions
|
||||||
|
static int32 FinishIsochronousThread(void *data);
|
||||||
void FinishIsochronousTransfers();
|
void FinishIsochronousTransfers();
|
||||||
isochronous_transfer_data *FindIsochronousTransfer(uhci_td *descriptor);
|
isochronous_transfer_data *FindIsochronousTransfer(uhci_td *descriptor);
|
||||||
|
|
||||||
@@ -173,6 +174,10 @@ static int32 FinishThread(void *data);
|
|||||||
uint8 *lastDataToggle);
|
uint8 *lastDataToggle);
|
||||||
size_t ReadActualLength(uhci_td *topDescriptor,
|
size_t ReadActualLength(uhci_td *topDescriptor,
|
||||||
uint8 *lastDataToggle);
|
uint8 *lastDataToggle);
|
||||||
|
void WriteIsochronousDescriptorChain(
|
||||||
|
uhci_td **isoRequest,
|
||||||
|
uint32 packetCount,
|
||||||
|
iovec *vector);
|
||||||
void ReadIsochronousDescriptorChain(
|
void ReadIsochronousDescriptorChain(
|
||||||
isochronous_transfer_data *transfer,
|
isochronous_transfer_data *transfer,
|
||||||
iovec *vector);
|
iovec *vector);
|
||||||
@@ -219,7 +224,10 @@ static pci_module_info *sPCIModule;
|
|||||||
// Maintain a linked list of isochronous transfers
|
// Maintain a linked list of isochronous transfers
|
||||||
isochronous_transfer_data *fFirstIsochronousTransfer;
|
isochronous_transfer_data *fFirstIsochronousTransfer;
|
||||||
isochronous_transfer_data *fLastIsochronousTransfer;
|
isochronous_transfer_data *fLastIsochronousTransfer;
|
||||||
|
sem_id fFinishIsochronousTransfersSem;
|
||||||
|
thread_id fFinishIsochronousThread;
|
||||||
benaphore fIsochronousLock;
|
benaphore fIsochronousLock;
|
||||||
|
bool fStopFinishIsochronousThread;
|
||||||
|
|
||||||
// Root hub
|
// Root hub
|
||||||
UHCIRootHub *fRootHub;
|
UHCIRootHub *fRootHub;
|
||||||
|
|||||||
@@ -467,7 +467,8 @@ usb_raw_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case RAW_COMMAND_INTERRUPT_TRANSFER:
|
case RAW_COMMAND_INTERRUPT_TRANSFER:
|
||||||
case RAW_COMMAND_BULK_TRANSFER: {
|
case RAW_COMMAND_BULK_TRANSFER:
|
||||||
|
case RAW_COMMAND_ISOCHRONOUS_TRANSFER: {
|
||||||
const usb_configuration_info *configurationInfo =
|
const usb_configuration_info *configurationInfo =
|
||||||
gUSBModule->get_configuration(device->device);
|
gUSBModule->get_configuration(device->device);
|
||||||
if (!configurationInfo) {
|
if (!configurationInfo) {
|
||||||
@@ -506,10 +507,16 @@ usb_raw_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
|
|||||||
status = gUSBModule->queue_interrupt(endpointInfo->handle,
|
status = gUSBModule->queue_interrupt(endpointInfo->handle,
|
||||||
command->transfer.data, command->transfer.length,
|
command->transfer.data, command->transfer.length,
|
||||||
usb_raw_callback, device);
|
usb_raw_callback, device);
|
||||||
} else {
|
} else if (op == RAW_COMMAND_BULK_TRANSFER) {
|
||||||
status = gUSBModule->queue_bulk(endpointInfo->handle,
|
status = gUSBModule->queue_bulk(endpointInfo->handle,
|
||||||
command->transfer.data, command->transfer.length,
|
command->transfer.data, command->transfer.length,
|
||||||
usb_raw_callback, device);
|
usb_raw_callback, device);
|
||||||
|
} else {
|
||||||
|
status = gUSBModule->queue_isochronous(endpointInfo->handle,
|
||||||
|
command->isochronous.data, command->isochronous.length,
|
||||||
|
command->isochronous.packet_descriptors,
|
||||||
|
command->isochronous.packet_count, NULL, 0,
|
||||||
|
usb_raw_callback, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ typedef enum {
|
|||||||
|
|
||||||
RAW_COMMAND_CONTROL_TRANSFER = 0x4000,
|
RAW_COMMAND_CONTROL_TRANSFER = 0x4000,
|
||||||
RAW_COMMAND_INTERRUPT_TRANSFER,
|
RAW_COMMAND_INTERRUPT_TRANSFER,
|
||||||
RAW_COMMAND_BULK_TRANSFER
|
RAW_COMMAND_BULK_TRANSFER,
|
||||||
|
RAW_COMMAND_ISOCHRONOUS_TRANSFER
|
||||||
} raw_command_id;
|
} raw_command_id;
|
||||||
|
|
||||||
|
|
||||||
@@ -127,6 +128,16 @@ typedef union {
|
|||||||
void *data;
|
void *data;
|
||||||
size_t length;
|
size_t length;
|
||||||
} transfer;
|
} transfer;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
status_t status;
|
||||||
|
uint32 interface;
|
||||||
|
uint32 endpoint;
|
||||||
|
void *data;
|
||||||
|
size_t length;
|
||||||
|
usb_iso_packet_descriptor *packet_descriptors;
|
||||||
|
uint32 packet_count;
|
||||||
|
} isochronous;
|
||||||
} raw_command;
|
} raw_command;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -189,3 +189,27 @@ BUSBEndpoint::BulkTransfer(void *data, size_t length) const
|
|||||||
|
|
||||||
return command.transfer.length;
|
return command.transfer.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
BUSBEndpoint::IsochronousTransfer(void *data, size_t length,
|
||||||
|
usb_iso_packet_descriptor *packetDescriptors, uint32 packetCount) const
|
||||||
|
{
|
||||||
|
if (length > 0 && data == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
raw_command command;
|
||||||
|
command.isochronous.interface = fInterface->Index();
|
||||||
|
command.isochronous.endpoint = fIndex;
|
||||||
|
command.isochronous.data = data;
|
||||||
|
command.isochronous.length = length;
|
||||||
|
command.isochronous.packet_descriptors = packetDescriptors;
|
||||||
|
command.isochronous.packet_count = packetCount;
|
||||||
|
|
||||||
|
if (ioctl(fRawFD, RAW_COMMAND_ISOCHRONOUS_TRANSFER, &command, sizeof(command))
|
||||||
|
|| command.isochronous.status != RAW_STATUS_SUCCESS) {
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return command.isochronous.length;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user