📄 cusbintf.cpp
字号:
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::IsoTransferComplete
//
// This is a completion routine for asynchronous isochronous transfer requests.
// It calculates the size transfered, and then calls the user completion routine
//
NTSTATUS CUsbInterface::IsoTransferComplete(PIRP p_irp, PREAD_CONTEXT p_read_context)
{
NTSTATUS status = STATUS_SUCCESS;
struct _URB_ISOCH_TRANSFER *pIso = (struct _URB_ISOCH_TRANSFER *)p_read_context->pUrb;
//Get the total transfer size by adding the sizes of any individual packets
ULONG transfer_size = 0;
for(ULONG i = 0; i < pIso->NumberOfPackets; i++)
{
if (!NT_SUCCESS(pIso->IsoPacket[i].Status))
{
if((USBD_STATUS_XACT_ERROR != pIso->IsoPacket[i].Status) &&
(USBD_STATUS_ISO_NOT_ACCESSED_BY_HW != pIso->IsoPacket[i].Status))
{
status = pIso->IsoPacket[i].Status; // Send the result back to the caller
break;
}
}
transfer_size += pIso->IsoPacket[i].Length;
}
p_irp->IoStatus.Information = transfer_size;
//Call the user's completion routine
if(p_read_context->pCompletion)
{
(*p_read_context->pCompletion)(
p_read_context->UserContext,
status,
transfer_size,
p_read_context);
}
//NOTE: Even though it would seem logical to return STATUS_SUCCESS at this point,
// there seems to be a bug in the W98 NTKERN where it will try to call
// IoCompleteRequest on the IRP after returning from here. Since I allocated
// the IRP and I need to free it, it makes no sense for NTKERN to do this.
// Returning STATUS_MORE_PROCESSING_REQUIRED prevents NTKERN from doing this.
return (STATUS_MORE_PROCESSING_REQUIRED); //Must return this or Windows will crash!
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::UsbReadComplete
//
//This is a completion routine for asynchronous bulk/interrupt transfer requests.
//
NTSTATUS CUsbInterface::UsbReadComplete(IRP* p_irp, PREAD_CONTEXT p_read_context)
{
NTSTATUS status = STATUS_SUCCESS;
struct _URB_BULK_OR_INTERRUPT_TRANSFER* p_bulk = (struct _URB_BULK_OR_INTERRUPT_TRANSFER *)p_read_context->pUrb;
p_irp->IoStatus.Information = p_bulk->TransferBufferLength;
ULONG transfer_size = p_bulk->TransferBufferLength;
status = p_irp->IoStatus.Status; // Send the result back to the caller
//Flag an error if we got a 'Device data error'
if(STATUS_DEVICE_DATA_ERROR == status)
{
_error_occured = TRUE;
DbgLogError(( "CUsbInterface::UsbReadComplete() : STATUS_DEVICE_DATA_ERROR\n"));
}
//Call the user's completion routine
if(p_read_context->pCompletion)
{
(*p_read_context->pCompletion)(
p_read_context->UserContext,
status,
transfer_size,
p_read_context);
}
//NOTE: Even though it would seem logical to return STATUS_SUCCESS at this point,
// there seems to be a bug in the W98 NTKERN where it will try to call
// IoCompleteRequest on the IRP after returning from here. Since I allocated
// the IRP and I need to free it, it makes no sense for NTKERN to do this.
// Returning STATUS_MORE_PROCESSING_REQUIRED prevents NTKERN from doing this.
return (STATUS_MORE_PROCESSING_REQUIRED); //Must return this or Windows will crash!
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::UsbAsyncIo_ISO
//
// Send a URB to the device to perform an isochronous transfer.
//
// Parameters
// pipe_number - USB pipe number to use for the transfer
// interface_number - USB interface to use for the transfer
// p_buffer - Buffer to receive the data from the transfer (Or containing data to send)
// buffer_size - Size of the buffer in pBuff
// p_read_context - User context - specifies the IRP, URB, and user completion routine
//
NTSTATUS CUsbInterface::UsbAsyncIo_ISO(DWORD pipe_number,
UCHAR interface_number,
PBYTE p_buffer,
DWORD buffer_size,
PREAD_CONTEXT p_read_context)
{
struct _URB_ISOCH_TRANSFER* p_iso = (struct _URB_ISOCH_TRANSFER *)p_read_context->pUrb;
//Return immediately if an error occured previously.
if (_error_occured)
{
DbgLogError(("CUsbInterface::UsbAsyncIo_ISO() : device IO error occured before, need to reset device!!"));
NTSTATUS status = STATUS_SUCCESS;
if(UsbGetStatusPipe(pipe_number, interface_number) != STATUS_SUCCESS)
{
// abort MPEG data pipe
status = UsbAbortPipe(pipe_number,interface_number); //PIPE_STREAMING
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbAsyncIo_ISO, Failed to abort firmware download pipe %x\n", status));
}
// reset MPEG data pipe
status = UsbResetPipe(pipe_number,interface_number); //PIPE_STREAMING
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbAsyncIo_ISO, Failed to reset firmware download pipe %x\n", status));
}
}
if (!NT_SUCCESS(status))
{
return (STATUS_DEVICE_DATA_ERROR);
}
}
//Get the pipe
PUSBD_PIPE_INFORMATION p_pipe = getPipe(interface_number, pipe_number);
if(!p_pipe)
{
DbgLogError(("CUsbInterface::UsbAsyncIo_ISO(): Invalid Interface Info"));
return STATUS_UNSUCCESSFUL;
}
//Make sure the pipe type is isochronous
if(UsbdPipeTypeIsochronous != p_pipe->PipeType)
{
DbgLogError(("CUsbInterface::UsbAsyncIo_ISO(): Invalid Pipe Type"));
return STATUS_UNSUCCESSFUL;
}
//Make sure we have a handle to the pipe
if(!p_pipe->PipeHandle)
{
DbgLogError(("CUsbInterface::UsbAsyncIo_ISO(): Invalid pipe handle or no memory"));
return STATUS_UNSUCCESSFUL;
}
//Get some parameters needed to fill in the URB
DWORD packet_size = p_pipe->MaximumPacketSize;
DWORD num_packets = buffer_size / packet_size;
DWORD transfer_flags = USBD_SHORT_TRANSFER_OK | USBD_START_ISO_TRANSFER_ASAP;
if (USB_ENDPOINT_DIRECTION_IN(p_pipe->EndpointAddress))
{
transfer_flags |= USBD_TRANSFER_DIRECTION_IN;
}
USHORT urb_size = (USHORT)GET_ISO_URB_SIZE(num_packets);
//Zero the URB
RtlZeroMemory(p_iso, urb_size);
//Fill in the URB parameters
p_iso->Hdr.Length = urb_size;
p_iso->Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
p_iso->Hdr.Status = 0x0;
p_iso->PipeHandle = p_pipe->PipeHandle;
p_iso->TransferFlags = transfer_flags;
p_iso->TransferBufferLength = num_packets * packet_size;
p_iso->TransferBuffer = p_buffer;
p_iso->TransferBufferMDL = NULL;
p_iso->NumberOfPackets = num_packets;
DWORD i;
for ( i = 0; i < num_packets; i++)
{
p_iso->IsoPacket[i].Offset = i * packet_size;
p_iso->IsoPacket[i].Length = packet_size;
}
// Save context information.
p_read_context->pUsb = this;
p_read_context->Pipe = pipe_number;
p_read_context->Interface = (DWORD)interface_number & 0xff;
p_read_context->dwXferSize = p_iso->TransferBufferLength;
// re-initialize the Irp
IoInitializeIrp(p_read_context->pIrp, p_read_context->pIrp->Size, _pdo->StackSize);
//Set up information for lower-level driver.
IO_STACK_LOCATION* p_stack = IoGetNextIrpStackLocation(p_read_context->pIrp);
p_stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
p_stack->Parameters.Others.Argument1 = p_read_context->pUrb;
p_stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
//Set our completion routine
IoSetCompletionRoutine(p_read_context->pIrp, staticIsoTransferComplete, p_read_context, TRUE, TRUE, TRUE);
//Send the IRP to the USB bus driver
return IoCallDriver(_pdo, p_read_context->pIrp);
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::UsbAsyncIo_BULK_SYNC
//
// Start a SYNCHRONOUS bulk transfer using the asynchronous read_context callback routine
//
// Parameters
// pipe_number - pipe to do the transfer on
// interface_number - interface the pipe belongs to
// p_buffer - buffer to transfer
// buffer_size - size of the buffer to transfer
// p_read_context - context structure containing the URB and callback routine
//
NTSTATUS CUsbInterface::UsbAsyncIo_BULK_SYNC(DWORD pipe_number,
UCHAR interface_number,
PBYTE p_buffer,
DWORD buffer_size,
PREAD_CONTEXT p_read_context)
{
DbgLog(("UsbAsyncIo_BULK_SYNC\n"));
NTSTATUS status;
if (_error_occured)
{
DbgLogError(("UsbAsyncIo_BULK_SYNC() : device IO error occured before!!\n"));
return (STATUS_DEVICE_DATA_ERROR);
}
//UsbSendMcCmd sends a bulk or interrupt command synchronously
status = UsbSendMcCmd(pipe_number, interface_number, p_buffer, buffer_size);
//Call the user's completion routine
if(p_read_context->pCompletion)
{
(p_read_context->pCompletion)(
p_read_context->UserContext,
status,
buffer_size,
p_read_context);
}
return (status);
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::UsbAsyncIo_BULK
//
// Start an asynchronous bulk transfer
//
// Parameters:
// pipe_number - pipe to do the transfer on
// interface_number - interface the pipe belongs to
// p_buffer - buffer to transfer
// buffer_size - size of the buffer in bytes
// p_read_context - context containing a URB and a callback routine.
//
NTSTATUS CUsbInterface::UsbAsyncIo_BULK(DWORD pipe_number,
UCHAR interface_number,
PBYTE p_buffer,
DWORD buffer_size,
PREAD_CONTEXT p_read_context)
{
if(_error_occured)
{
DbgLogError(("UsbAsyncIo_BULK() : device IO error occured before!!\n"));
NTSTATUS status = STATUS_SUCCESS;
if(UsbGetStatusPipe(pipe_number, interface_number) != STATUS_SUCCESS)
{
// abort MPEG data pipe
status = UsbAbortPipe(pipe_number,interface_number); //PIPE_STREAMING
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbAsyncIo_BULK, Failed to abort firmware download pipe %x\n", status));
}
// reset MPEG data pipe
status = UsbResetPipe(pipe_number,interface_number); //PIPE_STREAMING
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbAsyncIo_BULK, Failed to reset firmware download pipe %x\n", status));
}
}
if (!NT_SUCCESS(status))
{
return (STATUS_DEVICE_DATA_ERROR);
}
}
//Check that the pipe is valid
PUSBD_PIPE_INFORMATION p_pipe = getPipe(interface_number, pipe_number);
if(!p_pipe)
{
DbgLogError(("UsbAsyncIo_BULK: Invalid pipe; interface = %x, pipe = %x\n", interface_number, pipe_number));
return STATUS_UNSUCCESSFUL;
}
//Check that the pipe type is bulk or interrupt
if ((UsbdPipeTypeBulk != p_pipe->PipeType) &&
(UsbdPipeTypeInterrupt != p_pipe->PipeType))
{
DbgLogError(("UsbAsyncIo_BULK: Invalid pipe type; interface = %x, pipe = %x\n", interface_number, pipe_number));
return STATUS_UNSUCCESSFUL;
}
//Check that we have a valid pipe handle
if(!p_pipe->PipeHandle)
{
DbgLogError(("UsbAsyncIo_BULK: Invalid pipe handle; interface = %x, pipe = %x\n", interface_number, pipe_number));
return STATUS_UNSUCCESSFUL;
}
//Build the URB
DWORD transfer_flags = USBD_SHORT_TRANSFER_OK;
if (USB_ENDPOINT_DIRECTION_IN(p_pipe->EndpointAddress))
{
transfer_flags |= USBD_TRANSFER_DIRECTION_IN;
}
UsbBuildInterruptOrBulkTransferRequest(
p_read_context->pUrb, // ptr to urb
(USHORT)sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), // size of urb
p_pipe->PipeHandle, // usbd pipe handle
p_buffer, // TransferBuffer
NULL, // mdl
buffer_size, // bufferlength
transfer_flags, // flags
NULL); // link
// Save context information.
p_read_context->pUsb = this;
p_read_context->Pipe = pipe_number;
p_read_context->Interface = (DWORD)interface_number & 0xff;
p_read_context->dwXferSize = buffer_size;
// re-initialize the Irp
IoInitializeIrp(p_read_context->pIrp, p_read_context->pIrp->Size, _pdo->StackSize);
//Set up information for lower-level driver.
PIO_STACK_LOCATION p_stack = IoGetNextIrpStackLocation(p_read_context->pIrp);
p_stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
p_stack->Parameters.Others.Argument1 = p_read_context->pUrb;
p_stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(
p_read_context->pIrp,
staticUsbReadComplete,
p_read_context,
TRUE,
TRUE,
TRUE);
//Send the IRP to the USB bus driver
return IoCallDriver(_pdo, p_read_context->pIrp);
}
/////////////////////////////////////////////////////////////////////////////////////////
void CUsbInterface::DumpUsbDevDescriptor(USB_DEVICE_DESCRIPTOR* p_descriptor)
{
DbgLogTrace((" USB_DEVICE_DESCRIPTOR 0x%08p\n", p_descriptor));
DbgLogTrace((" bLength %u\n", p_descriptor->bLength));
DbgLogTrace((" bDescriptorType %u\n", p_descriptor->bDescriptorType));
DbgLogTrace((" bcdUSB %04X\n", p_descriptor->bcdUSB));
DbgLogTrace((" bDeviceClass %u\n", p_descriptor->bDeviceClass));
DbgLogTra
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -