📄 drvdispatch.c
字号:
#include "zjHMCFUsb.h"
#include "DrvIoCode.h"
/************************************************************************************************
* Function Type : private
* Parameter : fdo - ptr to our FDO
* Return Value : dx->PendingIoCount
* Description : 减少正在处理的IO计数
*************************************************************************************************/
LONG hwDecrementIoCount(IN PDEVICE_OBJECT fdo)
{
PDEVICE_EXTENSION dx;
LONG ioCount;
KIRQL oldIrql;
dx = fdo->DeviceExtension;
KeAcquireSpinLock (&dx->IoCountSpinLock, &oldIrql);
ioCount = InterlockedDecrement(&dx->PendingIoCount);
if ( ioCount == 1 )
{
// 触发没有正在处理的IO的事件
KeSetEvent(&dx->NoPendingIoEvent, 1, FALSE);
}
if ( ioCount == 0)
{
// 触发设备移除的事件
KeSetEvent(&dx->RemoveEvent, 1, FALSE);
}
KeReleaseSpinLock (&dx->IoCountSpinLock, oldIrql);
hwDbgPrint("hwDecrementIoCount() Pending io count = %x\n", ioCount);
return ioCount;
}
/************************************************************************************************
* Function Type : private
* Parameter : fdo - ptr to our FDO
* Return Value : None
* Description : 我们保存着一个正在处理的IO计数在设备扩展(dx->PendingIoCount)中
* 这个计数第一次加1表示我们新增了设备,以后每收到一个
* IRP就加1,处理完一个IRP就减1
*************************************************************************************************/
VOID hwIncrementIoCount(IN PDEVICE_OBJECT fdo)
{
PDEVICE_EXTENSION dx;
KIRQL oldIrql;
dx = fdo->DeviceExtension;
hwDbgPrint(" -->>>>>> hwIncrementIoCount() Pending io count = %x\n", dx->PendingIoCount);
KeAcquireSpinLock (&dx->IoCountSpinLock, &oldIrql);
InterlockedIncrement(&dx->PendingIoCount);
KeReleaseSpinLock (&dx->IoCountSpinLock, oldIrql);
hwDbgPrint("hwIncrementIoCount() Pending io count = %x -->>>>>\n", dx->PendingIoCount);
}
/************************************************************************************************
* Function Type : global
* Parameter : fdo - pointer to the device object for this instance of the device
* Return Value : TRUE - if can accept new io requests
* FALSE - can't accept new io requests
* Description : 检测是否可以接受IO请求
* Can't accept a new io request if device:
* 1) is removed,
* 2) has never been started,
* 3) is stopped,
* 4) has a remove request pending, or
* 5) has a stop device pending
*************************************************************************************************/
BOOLEAN hwCanAcceptIoRequests(IN PDEVICE_OBJECT fdo )
{
PDEVICE_EXTENSION dx;
BOOLEAN fCan = FALSE;
dx = fdo->DeviceExtension;
if ( !dx->DeviceRemoved && // 处理IRP_MN_REMOVE_DEVICE时这个标记会被置位
dx->DeviceStarted && // 设备已经启动
!dx->RemoveDeviceRequested && // 当成功应答IRP_MN_QUERY_REMOVE_DEVICE时这个标记被置位,表示设备可以被移除
!dx->StopDeviceRequested // 当成功应答IRP_MN_QUERY_STOP_DEVICE时这个标志被置位,表示设备可以被停止
)
{
fCan = TRUE;
}
hwDbgPrint("hwCanAcceptIoRequests() return %s\n",fCan?"TRUE":"FALSE");
return fCan;
}
/************************************************************************************************
* Function Type : private
* Parameter : fdo - pointer to the device object for this instance of the device
* FileName - file name
* Return Value : >=0 - pipe index
* -1 - error occured
* Description : 从文件名中获取管道ID
*************************************************************************************************/
int hwPipeWithName
(
IN PDEVICE_OBJECT fdo,
IN PUNICODE_STRING FileName
)
{
PDEVICE_EXTENSION dx = fdo->DeviceExtension;
ULONG i, nameLen, ix, uval , umultiplier;
int PipeIndex = -1;
nameLen = FileName->Length;
hwDbgPrint ( "-->>>>>>hwPipeWithName(fdo=0x%x,FileName=%T)\n",fdo,FileName );
if ( nameLen <= 0 )
{
PipeIndex = -1;
goto done;
}
// 获取管道ID
ix = nameLen -1; // index last char of pipe name
// 从后往前找,先跳过非数字
while( ( (FileName->Buffer[ ix ] < (WCHAR) '0') ||
(FileName->Buffer[ ix ] > (WCHAR) '9') ) && ix )
{
ix--;
}
if ( ix > 0 ) // filename better have had at least one ascii digit!
{
//------------------------------------------------------------------
// 将管道名字转为管道ID
// 将Asscii码的字符转为10进制的数字
//------------------------------------------------------------------
uval = 0;
umultiplier = 1;
// 将字符串转为数字,相当于atoi()函数
while( ( (FileName->Buffer[ ix ] >= (WCHAR) '0') &&
(FileName->Buffer[ ix ] <= (WCHAR) '9') ) && ix )
{
uval += (umultiplier * (ULONG) (FileName->Buffer[ ix ] - (WCHAR) '0'));
ix--;
umultiplier *= 10;
}
}
if ( uval >= dx->UsbInterface->NumberOfPipes )
{
PipeIndex = -1;
goto done;
}
PipeIndex = uval;
done:
hwDbgPrint ( "hwPipeWithName(PipeIndex=%d)-->>>>>>\n",PipeIndex);
return PipeIndex;
}
/************************************************************************************************
* Function Type : global
* Parameter : fdo - pointer to our FDO (Functional Device Object )
* Return Value : NT status code
* Description : This is the dispatch table routine for IRP_MJ_CLOSE.
* It handles user mode CloseHandle() calls for a pipe
* It closes the File Object for the pipe handle it represents.
*************************************************************************************************/
NTSTATUS zjHMCFUsb_Close(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
NTSTATUS actStat;
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION dx;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
PzjHMCFUsb_PIPESTATE PipeState = NULL;
int PipeIndex;
hwDbgPrint( " -->>>>>> zjHMCFUsb_Close(fdo=0x%x,Irp=0x%x)\n",fdo,Irp);
PrintCurIrql();
hwIncrementIoCount(fdo);
dx = fdo->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation (Irp);
fileObject = irpStack->FileObject;
if (!fileObject->FsContext)
goto done;
// closing pipe handle
pipeHandle = fileObject->FsContext;
PipeIndex = hwPipeWithName( fdo, &fileObject->FileName );
if ( -1 == PipeIndex )
goto done;
PipeState = &dx->PipeState[ PipeIndex ];
if ( PipeState->fPipeOpened )// set if opened
{
// may have been aborted
hwDbgPrint("Closing pipe%d ( pipeHandle = 0x%x)\n",PipeIndex, pipeHandle);
dx->OpenPipeCount--;
PipeState->fPipeOpened = FALSE;
}
else
{
// pipe was already closed; this can only be if we got a sudden REMOVE_DEVICE
hwASSERT( dx->DeviceRemoved );
hwDbgPrint( "Pipe %x was already closed\n ", pipeHandle);
}
done:
// try to power down device if this is the last pipe
actStat = hwSelfSuspendOrActivate( fdo, TRUE );
hwDbgPrint("zjHMCFUsb_Close() OpenPipeCount = %d, status = 0x%x-->>>>>>\n",
dx->OpenPipeCount, ntStatus);
hwDecrementIoCount(fdo);
return CompleteIrp( Irp, ntStatus,0,IO_NO_INCREMENT);
}
/************************************************************************************************
* Function Type : global
* Parameter : fdo - pointer to our FDO (Functional Device Object )
* Urb - pointer to an already-formatted Urb request block
* Return Value : STATUS_SUCCESS - if successful,
* STATUS_UNSUCCESSFUL - otherwise
* Description : 传递一个URB给USBD类驱动
* 客户设备驱动传递一个URB给类驱动,将Irp->MajorFunction参数
* 设置为IRP_MJ_INTERNAL_DEVICE_CONTROL,下层IRP栈位置参数
* Parameters.DeviceIoControl.IoControlCode域设置为IOCTL_INTERNAL_USB_SUBMIT_URB
*************************************************************************************************/
NTSTATUS hwCallUSBD(IN PDEVICE_OBJECT fdo, IN PURB Urb )
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PDEVICE_EXTENSION dx;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
hwDbgPrint(" -->>>>>> hwCallUSBD(fdo=0x%x,Urb=0x%x\n",fdo,Urb);
dx = fdo->DeviceExtension;
//------------------------------------------------------------------
// 构造一个IRP
//------------------------------------------------------------------
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest
(
IOCTL_INTERNAL_USB_SUBMIT_URB,
dx->LowerDeviceObject, // Points to the next-lower driver's device object
NULL, // optional input bufer; none needed here
0, // input buffer len if used
NULL, // optional output bufer; none needed here
0, // output buffer len if used
TRUE, // If InternalDeviceControl is TRUE the target driver's Dispatch
// outine for IRP_MJ_INTERNAL_DEVICE_CONTROL or IRP_MJ_SCSI
// is called; otherwise, the Dispatch routine for
// IRP_MJ_DEVICE_CONTROL is called.
&event, // event to be signalled on completion
&ioStatus // Specifies an I/O status block to be set when the request is completed the lower driver.
);
//------------------------------------------------------------------
// As an alternative, we could call KeDelayExecutionThread, wait for some
// period of time, and try again....but we keep it simple for right now
//------------------------------------------------------------------
if (!irp)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//------------------------------------------------------------------
// Call the class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//------------------------------------------------------------------
nextStack = IoGetNextIrpStackLocation(irp);
hwASSERT(nextStack != NULL);
// pass the URB to the USB driver stack
nextStack->Parameters.Others.Argument1 = Urb;
ntStatus = IoCallDriver(dx->LowerDeviceObject, irp);
hwDbgPrint("IoCallDriver() return ntStatus = 0x%x\n", ntStatus);
if (ntStatus == STATUS_PENDING)
{
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
}
else
{
ioStatus.Status = ntStatus;
}
hwDbgPrint("hwCallUSBD() URB status = %x status = %x irp status %x\n",
Urb->UrbHeader.Status, status, ioStatus.Status);
// USBD maps the error code for us
ntStatus = ioStatus.Status;
hwDbgPrint("hwCallUSBD ntStatus = 0x%x -->>>>>>\n ", ntStatus);
return ntStatus;
}
/************************************************************************************************
* Function Type : private
* Parameter : fdo - pointer to our FDO (Functional Device Object )
* PipeInfo - Ptrs to our a USBD_PIPE_INFORMATION struct
* Return Value : NT status code
* Description : Reset a given USB pipe.
* NOTES : This will reset the host to Data0 and should also reset the device to Data0
*************************************************************************************************/
NTSTATUS hwResetPipe(IN PDEVICE_OBJECT fdo,IN PUSBD_PIPE_INFORMATION PipeInfo)
{
NTSTATUS ntStatus;
PURB urb;
PDEVICE_EXTENSION dx = fdo->DeviceExtension;
hwDbgPrint("-->>>>> hwResetPipe(fdo=0x%x,PipeInfo = 0x%x\n", fdo,PipeInfo);
urb = ExAllocatePool(NonPagedPool,sizeof(struct _URB_PIPE_REQUEST));
if (urb)
{
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
urb->UrbPipeRequest.PipeHandle = PipeInfo->PipeHandle;
ntStatus = hwCallUSBD(fdo, urb);
FreeIfAllocated(urb);
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
hwDbgPrint("hwResetPipe(ntStatus=0x%x)-->>>>>\n",ntStatus);
return ntStatus;
}
/************************************************************************************************
* Function Type : global
* Parameter : fdo - pointer to our FDO (Functional Device Object )
* Return Value : STATUS_SUCCESS - if successful,
* STATUS_UNSUCCESSFUL - otherwise
* Description : returns the port status for our device
*************************************************************************************************/
NTSTATUS hwGetPortStatus(IN PDEVICE_OBJECT fdo,IN PULONG PortStatus)
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
PDEVICE_EXTENSION dx;
hwDbgPrint(" -->>>>>> hwGetPortStatus(fdo=0x%x,PortStatus=0x%x)\n",fdo,PortStatus);
dx = fdo->DeviceExtension;
*PortStatus = 0;
//------------------------------------------------------------------
// issue a synchronous request
//------------------------------------------------------------------
KeInitializeEvent(&event, NotificationEvent, FALSE);
// IoBuildDeviceIoControlRequest allocates and sets up an IRP for a device control request
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_GET_PORT_STATUS,
dx->LowerDeviceObject, //next-lower driver's device object, representing the target device.
NULL, // no input or output buffers
0,
NULL,
0,
TRUE, // internal ( use IRP_MJ_INTERNAL_DEVICE_CONTROL )
&event, // event to be signalled on completion ( we wait for it below )
&ioStatus);
//------------------------------------------------------------------
// 调用类驱动来执行这个操作,如果返回状态为
// PENDING,等待请求完成
//
// IoGetNextIrpStackLocation()获取一个高层驱动在一个IRP里访问下层驱动
// 的I/O栈位置 //------------------------------------------------------------------
nextStack = IoGetNextIrpStackLocation(irp);
hwASSERT(nextStack != NULL);
nextStack->Parameters.Others.Argument1 = PortStatus;
hwDbgPrint("calling IoCallDriver() USBD port status api\n");
ntStatus = IoCallDriver(dx->LowerDeviceObject, irp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -