📄 cusbintf.cpp
字号:
// This sends a bulk or interrupt data transfer and waits for it to complete.
// The name is misleading.
//
// Parameters
// pipe_number - pipe to send the transfer on
// interface_number - interface to use
// p_data - data to send
// transfer_size - size of data to send in bytes
//
NTSTATUS CUsbInterface::UsbSendMcCmd(DWORD pipe_number,
UCHAR interface_number,
void* p_data,
DWORD transfer_size)
{
USBD_PIPE_INFORMATION* p_pipe = getPipe(interface_number, pipe_number);
DbgLog(("CUsbInterface::UsbSendMcCmd:interface_num=%d,pip_num=%d\n",interface_number,pipe_number));
// if device is surprise removed then we should not allow any call further below
if(_bSurpriseRemoval)
{
DbgLogError(("CUsbInterface::UsbCall_GSPN() : Device Surprise Removal!!\n"));
return (STATUS_DEVICE_DATA_ERROR);
}
//Make sure the pipe is valid
if(!p_pipe)
{
DbgLogError(("UsbSendMcCmd on invalid pipe, interface = %x, pipe = %x\n", interface_number, pipe_number));
return STATUS_UNSUCCESSFUL;
}
//Only accept commands on bulk or interrupt pipes
if((p_pipe->PipeType != UsbdPipeTypeBulk) &&
(p_pipe->PipeType != UsbdPipeTypeInterrupt))
{
DbgLogError(("UsbSendMcCmd: invalid pipe type. Pipe type = %x\n", p_pipe->PipeType));
return STATUS_UNSUCCESSFUL;
}
//Make sure the pipe has a valid handle
if(!p_pipe->PipeHandle)
{
DbgLogError(("UsbSendMcCmd: invalid pipe handle.\n"));
return STATUS_UNSUCCESSFUL;
}
//Allocate a URB
PURB p_urb = (PURB) new _URB_BULK_OR_INTERRUPT_TRANSFER;
if(!p_urb)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(p_urb, sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER));
DWORD transfer_flags = USBD_SHORT_TRANSFER_OK;
if (USB_ENDPOINT_DIRECTION_IN(p_pipe->EndpointAddress))
{
transfer_flags |= USBD_TRANSFER_DIRECTION_IN;
}
UsbBuildInterruptOrBulkTransferRequest(
p_urb, // ptr to urb
(USHORT)sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), // size of urb
p_pipe->PipeHandle, // usbd pipe handle
p_data, // TransferBuffer
0, // mdl
transfer_size, // bufferlength
transfer_flags, // flags
NULL); // link
//Send the URB
NTSTATUS status = UsbCall_GSPN(p_urb);
delete p_urb;
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::UsbSendRecvCmd
//
// This sends a bulk or interrupt data transfer and waits for it to complete.
// The name is misleading.
//
// This function's purpose is not to create URB multiple times, and resuse the same
// URB repeatedly, so that we can save allocation and deletion times of URB although
// it is fast.
//
// Parameters
// pipe_number - pipe to send the transfer on
// interface_number - interface to use
// p_data - data to send
// transfer_size - size of data to send in bytes
//
NTSTATUS CUsbInterface::UsbSendRecvCmd( DWORD pipe_number,
UCHAR interface_number,
void* p_data,
DWORD transfer_size)
{
USBD_PIPE_INFORMATION* p_pipe = getPipe(interface_number, pipe_number);
// if device is surprise removed then we should not allow any call further below
if(_bSurpriseRemoval)
{
DbgLogError(("CUsbInterface::UsbCall_GSPN() : Device Surprise Removal!!\n"));
return (STATUS_DEVICE_DATA_ERROR);
}
//Make sure the pipe is valid
if(!p_pipe)
{
DbgLogError(("UsbSendMcCmd on invalid pipe, interface = %x, pipe = %x\n", interface_number, pipe_number));
return STATUS_UNSUCCESSFUL;
}
//Only accept commands on bulk or interrupt pipes
if((p_pipe->PipeType != UsbdPipeTypeBulk) &&
(p_pipe->PipeType != UsbdPipeTypeInterrupt))
{
DbgLogError(("UsbSendMcCmd: invalid pipe type. Pipe type = %x\n", p_pipe->PipeType));
return STATUS_UNSUCCESSFUL;
}
//Make sure the pipe has a valid handle
if(!p_pipe->PipeHandle)
{
DbgLogError(("UsbSendMcCmd: invalid pipe handle.\n"));
return STATUS_UNSUCCESSFUL;
}
// check for URB
PURB p_urb = (PURB) _p_cmd_urb;
if(!p_urb)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(p_urb, sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER));
DWORD transfer_flags = USBD_SHORT_TRANSFER_OK;
if (USB_ENDPOINT_DIRECTION_IN(p_pipe->EndpointAddress))
{
transfer_flags |= USBD_TRANSFER_DIRECTION_IN;
}
UsbBuildInterruptOrBulkTransferRequest(
p_urb, // ptr to urb
(USHORT)sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), // size of urb
p_pipe->PipeHandle, // usbd pipe handle
p_data, // TransferBuffer
0, // mdl
transfer_size, // bufferlength
transfer_flags, // flags
NULL); // link
//Send the URB
NTSTATUS status = UsbCall_GSPN(p_urb);
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::UsbAsyncIo
//
// Start an asynchronous data transfer
//
// Parameters:
// pipe_number - pipe to use
// interface_number - interface to use
// p_data - data buffer to send or receive
// data_size - number of bytes to send or recieve
// p_mdl - unused
// p_read_context - context structure describing the URB and callback routine
//
NTSTATUS CUsbInterface::UsbAsyncIo(DWORD pipe_number,
UCHAR interface_number,
PBYTE p_data,
DWORD data_size,
PMDL p_mdl,
PREAD_CONTEXT p_read_context)
{
USBD_PIPE_INFORMATION* p_pipe = getPipe(interface_number, pipe_number);
// if device is surprise removed then we should not allow any call further below
if(_bSurpriseRemoval)
{
DbgLogError(("CUsbInterface::UsbCall_GSPN() : Device Surprise Removal!!\n"));
return (STATUS_DEVICE_DATA_ERROR);
}
if(!p_pipe)
{
DbgLogError(("UsbAsyncIo on invalid pipe, interface = %x, pipe = %x\n", interface_number, pipe_number));
return STATUS_UNSUCCESSFUL;
}
switch(p_pipe->PipeType)
{
case UsbdPipeTypeIsochronous:
return UsbAsyncIo_ISO(pipe_number, interface_number, p_data, data_size, p_read_context);
case UsbdPipeTypeBulk:
case UsbdPipeTypeInterrupt:
return UsbAsyncIo_BULK(pipe_number, interface_number, p_data, data_size, p_read_context);
default:
return UsbAsyncIo_BULK_SYNC(pipe_number, interface_number, p_data, data_size, p_read_context);
}
UNREFERENCED_PARAMETER(p_mdl);
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::UsbResetPipe
//
// Reset a pipe.
//
// Parameters:
// pipe_number - pipe to reset
// interface_number - interface the pipe is in
//
NTSTATUS CUsbInterface::UsbResetPipe(DWORD pipe_number, UCHAR interface_number)
{
USBD_PIPE_INFORMATION* p_pipe = getPipe(interface_number, pipe_number);
if(!p_pipe)
{
DbgLogError(("UsbResetPipe on invalid pipe, interface = %x, pipe = %x\n", interface_number, pipe_number));
return STATUS_UNSUCCESSFUL;
}
PURB p_urb = (PURB) new BYTE[sizeof(struct _URB_PIPE_REQUEST)];
if(!p_urb)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(p_urb, sizeof(struct _URB_PIPE_REQUEST));
p_urb->UrbHeader.Length = (USHORT)sizeof(struct _URB_PIPE_REQUEST);
p_urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
p_urb->UrbPipeRequest.PipeHandle = p_pipe->PipeHandle;
NTSTATUS status = SendCmdAndWait(p_urb);
delete [] (BYTE *)p_urb;
return status;
}
NTSTATUS CUsbInterface::SendCmdAndWait(PURB p_urb)
{
NTSTATUS status;
// if device is surprise removed then we should not allow any call further below
if(_bSurpriseRemoval)
{
DbgLogError(("CUsbInterface::SendCmdAndWait : Device Surprise Removal!!\n"));
return (STATUS_DEVICE_DATA_ERROR);
}
//We can't send the URB if we don't have an IRP
if(!_p_irp)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//We must run at passive level to acquire the mutex and wait.
if(KeGetCurrentIrql() != PASSIVE_LEVEL)
{
return STATUS_UNSUCCESSFUL;
}
//Get the mutex
KeWaitForSingleObject(&_mutex, Executive, KernelMode, FALSE, NULL);
//Set up the IRP
PIRP pIrp = _p_irp;
IoInitializeIrp(pIrp, pIrp->Size, _pdo->StackSize);
KeClearEvent(&_event);
//Get the next IRP stack location and set it up for the USB bus driver.
PIO_STACK_LOCATION pNextStack= IoGetNextIrpStackLocation(pIrp); //Setup request to lower-level driver.
pNextStack->MajorFunction= IRP_MJ_INTERNAL_DEVICE_CONTROL;
pNextStack->Parameters.DeviceIoControl.IoControlCode= IOCTL_INTERNAL_USB_SUBMIT_URB;
pNextStack->Parameters.Others.Argument1= p_urb;
//Set our completion routine
IoSetCompletionRoutine(pIrp, staticUsbCallCompletion, &_event, TRUE, TRUE, TRUE);
//Send the IRP to the USB bus driver
status = IoCallDriver(_pdo, pIrp);
//If the IRP is pending, wait for it to complete.
if(STATUS_PENDING == status)
{
LARGE_INTEGER timeout_period;
timeout_period.QuadPart = -10000 * 5000;
status = KeWaitForSingleObject(
&_event,
Executive,
KernelMode,
0,
&timeout_period);
if(STATUS_TIMEOUT == status)
{
//If we timed out, try to cancel the IRP
IoCancelIrp(pIrp);
KeWaitForSingleObject(
&_event,
Executive,
KernelMode,
0,
NULL);
status = STATUS_IO_TIMEOUT;
DbgLogError(( "CUsbInterface::SendCmdAndWait : Cancelled IRP !!\n"));
}
else
{
status = pIrp->IoStatus.Status;
}
}
//Flag an error if we weren't successful
if (!NT_SUCCESS(status))
{
if ((STATUS_DEVICE_DATA_ERROR == status) ||
(STATUS_IO_TIMEOUT == status) ||
(STATUS_DEVICE_NOT_CONNECTED == status))
{
_error_occured = TRUE;
DbgLogError(( "CUsbInterface::SendCmdAndWait : Error Status = %x!!\n", status));
}
}
KeReleaseMutex(&_mutex, FALSE);
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::UsbAbortPipe
//
// Call this function to abort all outstanding requests on a pipe.
//
NTSTATUS CUsbInterface::UsbAbortPipe(DWORD pipe_number, UCHAR interface_number)
{
DbgLog(("usbabortpipe\n"));
USBD_PIPE_INFORMATION* p_pipe = getPipe(interface_number, pipe_number);
if(!p_pipe)
{
DbgLogError(("UsbAbortPipe on invalid pipe, interface = %x, pipe = %x\n", interface_number, pipe_number));
return STATUS_UNSUCCESSFUL;
}
PURB p_urb = (PURB) new BYTE[sizeof(struct _URB_PIPE_REQUEST)];
if(!p_urb)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(p_urb, sizeof(struct _URB_PIPE_REQUEST));
p_urb->UrbHeader.Length = (USHORT)sizeof(struct _URB_PIPE_REQUEST);
p_urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
p_urb->UrbPipeRequest.PipeHandle = p_pipe->PipeHandle;
NTSTATUS status = SendCmdAndWait(p_urb);
delete [] (BYTE *)p_urb;
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::UsbGetStatusPipe
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -