赛灵思PCIE驱动DMA MSI实现02

  • 内容
  • 评论
  • 相关

1.1 什么是驱动的Dispatcher

首先我们介绍一下什么是驱动的Dispatcher
1、简单的说Dispatcher就是操作系统的回调CallBack
2、再简单的说Dispatcher就是一个函数指针,这个函数指针的定义由操作系统完成,我们仅仅需要按照这个格式进行编写即可。
当操作系统收到相关的请求时(IRP,中断,,电源管理等等),他将指定的数据转发到我们注册的回调函数上。这就是Dispatcher的过程。

1.2 主要的Dispatcher

1、即插即用(IRP_MJ_PNP )
即插即用(IRP_MJ_PNP)功能能够通过操作系统协调自动分配设备上的资源,如中断号,I/O地址,DMA资源,设备物理内存等。
WDM框架程序是分层驱动,WDM处于分层的高端,而总线驱动程序处于分层的低端。大部分即插即用IRP都会被WDM驱动发送到底层的驱动程序处理。 IRP_MJ_PNP类似于Win32中的消息,而IRP_MJ_PNP的派遣函数类似于Win32编程中的窗口函数。所有的即插即用的事件,都会引发即插即用管理器向WDM驱动程序发送一个IRP_MJ_PNP。
其中在IRP_MJ_PNP的dispatcher还存在多种类型的子请求,如下:
IRP_MN_START_DEVICE //启动设备,初始化电源管理
IRP_MN_QUERY_STOP_DEVICE // 停止设备的IRQ,这里我们要停止设备
IRP_MN_CANCEL_STOP_DEVICE //取消停止设备,一般不用,这里需要释放资源
IRP_MN_STOP_DEVICE // 停止设备,这里需要回收资源,例如中断等。
IRP_MN_QUERY_REMOVE_DEVICE // 设置PNP状态PnpStateRemovePending
IRP_MN_CANCEL_REMOVE_DEVICE // 取消设备删除操作
IRP_MN_SURPRISE_REMOVAL //删除设备失败后调用,请看代码详解
IRP_MN_REMOVE_DEVICE //删除设备
IRP_MN_QUERY_CAPABILITIES //设备容量查询时候调用,一般不做操作

代码如下:
DriverObject->MajorFunction[IRP_MJ_PNP] = HYPCIPnpDispatch;


///////////////////////////////////////////////////////////////////////////////////////////////////
//  HYPCIPnpDispatch
//      Dispatch routine to handle PnP requests
//
//  Arguments:
//      IN  DeviceObject
//              pointer to our device object
//
//      IN  Irp
//              pointer to the PnP IRP
//
//  Return Value:
//      NT status code
//
NTSTATUS HYPCIPnpDispatch(
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
    )
{
    PHYPCI_DEVICE_EXTENSION    DeviceExtension;
    PIO_STACK_LOCATION              irpStack;
    NTSTATUS                        status;
    PDEVICE_CAPABILITIES            deviceCapabilities;
    ULONG                           requestCount;
    ULONG                           index;
    PPNP_DEVICE_STATE               deviceState;
    POWER_STATE                     powerState;

  
    // Get our device extension from the device object
    DeviceExtension = (PHYPCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension;

    // Get our current IRP stack location
    irpStack = IoGetCurrentIrpStackLocation(Irp);

    // Make sure we can accept IRPs
    if (!HYPCIAcquireRemoveLock(DeviceExtension))
    {
        status = STATUS_NO_SUCH_DEVICE;

        Irp->IoStatus.Status = status;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return status;
    }

    switch (irpStack->MinorFunction) 
    {
    case IRP_MN_START_DEVICE:

        // The device stack must be started from the bottom up.  
        // So, we send the IRP down the stack and wait so that 
        // all devices below ours have started before we process 
        // this IRP and start ourselves.
        status = HYPCISubmitIrpSync(DeviceExtension->LowerDeviceObject, Irp);
        if (!NT_SUCCESS(status))
        {
			DbgPrint("status = HYPCISubmitIrpSync(DeviceExtension->LowerDeviceObject, Irp);");
            break;
        }

        // Lower drivers have finished their start operation, so now
        // we process ours.

        // Start is an implicit power-up so 
        // we set our device power state accordingly 
        DeviceExtension->DevicePowerState = PowerDeviceD0;
        powerState.DeviceState = DeviceExtension->DevicePowerState;

        PoSetPowerState(DeviceExtension->DeviceObject, DevicePowerState, powerState);

        status = HYPCIGetDeviceCapabilities(DeviceExtension);
        if (!NT_SUCCESS(status))
        {
            HYPCIFreeResources(DeviceExtension);
            break;
        }

        status = HYPCIStartDevice(DeviceExtension, Irp);
        if (!NT_SUCCESS(status))
        {
            HYPCIFreeResources(DeviceExtension);
            break;
        }

        // Enable the device interface. 
        status = IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, TRUE);
        if (!NT_SUCCESS(status))
        {
            HYPCIFreeResources(DeviceExtension);
            break;
        }

        // Update our PnP state
        DeviceExtension->PnpState = PnpStateStarted;

        // restart any stalled queues
        HYPCIRestartQueues(DeviceExtension);
        break;

    case IRP_MN_QUERY_STOP_DEVICE:

        if (HYPCIIsStoppable(DeviceExtension)) 
        {
            // Device is stoppable.

            // pause io request processing
            HYPCIStallQueues(DeviceExtension);

            // Update our PnP state
            DeviceExtension->PreviousPnpState = DeviceExtension->PnpState;
            DeviceExtension->PnpState = PnpStateStopPending;

            // We must set Irp->IoStatus.Status to STATUS_SUCCESS before
            // passing it down.
            Irp->IoStatus.Status = STATUS_SUCCESS;
            IoSkipCurrentIrpStackLocation (Irp);
            status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);

            // Decrement the active I/O count
            HYPCIReleaseRemoveLock(DeviceExtension);
            return status;
        }
        else
        {
            // device is not currently stoppable, fail the request
            status = STATUS_UNSUCCESSFUL;
        }

        break;

   case IRP_MN_CANCEL_STOP_DEVICE:

	   DbgPrint("IRP_MN_CANCEL_STOP_DEVICE");
        // Send this IRP down and wait for it to come back,
        // restart our stall fifo,
        // and process all the previously queued up IRPs.

        // First check to see whether we received a query before this
        // cancel. This could happen if someone above us failed a query
        // and passed down the subsequent cancel.
        if (DeviceExtension->PnpState == PnpStateStopPending) 
        {
            status = HYPCISubmitIrpSync(DeviceExtension->LowerDeviceObject,Irp);
            if (NT_SUCCESS(status))
            {
                // restore previous pnp state
                DeviceExtension->PnpState = DeviceExtension->PreviousPnpState;

                // restart the queues
                HYPCIRestartQueues(DeviceExtension);
            } 
            else 
            {
                // Somebody below us failed the cancel
                // this is a fatal error.
                ASSERTMSG("Cancel stop failed!", FALSE);
            }
        } 
        else 
        {
            // Spurious cancel so we just complete the request.
            status = STATUS_SUCCESS;
        }

        break;

    case IRP_MN_STOP_DEVICE:

		DbgPrint("IRP_MN_STOP_DEVICE");
        // Mark the device as stopped.
        DeviceExtension->PnpState = PnpStateStopped;

        // release our resources
        HYPCIFreeResources(DeviceExtension);

        // send the request down, and we are done
        Irp->IoStatus.Status = STATUS_SUCCESS;
        IoSkipCurrentIrpStackLocation (Irp);
        status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);

        HYPCIReleaseRemoveLock(DeviceExtension);
        return status;

    case IRP_MN_QUERY_REMOVE_DEVICE:

        if (HYPCIIsRemovable(DeviceExtension)) 
        {
            // pause io request processing
            HYPCIStallQueues(DeviceExtension);

            // Update our PnP state
            DeviceExtension->PreviousPnpState = DeviceExtension->PnpState;
            DeviceExtension->PnpState = PnpStateRemovePending;

            // Now just send the request down and we are done
            Irp->IoStatus.Status = STATUS_SUCCESS;
            IoSkipCurrentIrpStackLocation (Irp);

            status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);

            // decrement the I/O count
            HYPCIReleaseRemoveLock(DeviceExtension);
            return status;
        }
        else
        {
            // Our device is not removable, just fail the request
            status = STATUS_UNSUCCESSFUL;
        }

        break;

    case IRP_MN_CANCEL_REMOVE_DEVICE:

        // First check to see whether we have received a prior query
        // remove request. It could happen that we did not if
        // someone above us failed a query remove and passed down the
        // subsequent cancel remove request.
        if (PnpStateRemovePending == DeviceExtension->PnpState)
        {
            status = HYPCISubmitIrpSync(DeviceExtension->LowerDeviceObject, Irp);

            if (NT_SUCCESS(status))
            {
                // restore pnp state, since remove was canceled
                DeviceExtension->PnpState = DeviceExtension->PreviousPnpState;

                // restart the queues
                HYPCIRestartQueues(DeviceExtension);
            }
            else
            {
                // Nobody can fail this IRP. This is a fatal error.
                ASSERTMSG("IRP_MN_CANCEL_REMOVE_DEVICE failed. Fatal error!", FALSE);
            }
        }
        else
        {
            // Spurious cancel remove request so we just complete it
            status = STATUS_SUCCESS;
        }

        break;

   case IRP_MN_SURPRISE_REMOVAL:

        // The device has been unexpectedly removed from the machine
        // and is no longer available for I/O.
        // We must return device and memory resources,
        // disable interfaces. We will defer failing any outstanding
        // request to IRP_MN_REMOVE.

        // stall all the queues
        HYPCIStallQueues(DeviceExtension);

        // Clear out all of the queues
        for (index = 0; index < NUMBER_OF_QUEUES; ++index)
        {
            HYPCIInvalidateQueue(DeviceExtension->QueueArray[index], STATUS_NO_SUCH_DEVICE);
        }

        // flush pending io list
        HYPCIInvalidateIo(&DeviceExtension->IoLock, STATUS_NO_SUCH_DEVICE);

        // update pnp state
        DeviceExtension->PnpState = PnpStateSurpriseRemoved;

        // disable our interface
        IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, FALSE);

        // Return any resources acquired during device startup.
        HYPCIFreeResources(DeviceExtension);

        // We must set Irp->IoStatus.Status to STATUS_SUCCESS before
        // passing it down.
        Irp->IoStatus.Status = STATUS_SUCCESS;
        IoSkipCurrentIrpStackLocation (Irp);
        
        status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);

        // Adjust the active I/O count
        HYPCIReleaseRemoveLock(DeviceExtension);
        return status;

   case IRP_MN_REMOVE_DEVICE:
	   DbgPrint("IRP_MN_STOP_DEVICE"); 
        // The Plug & Play system has dictated the removal of this device.  We
        // have no choice but to detach and delete the device object.

        if (DeviceExtension->PnpState != PnpStateSurpriseRemoved)
        {
            // Clear out all of the queues
            for (index = 0; index < NUMBER_OF_QUEUES; ++index)
            {
                HYPCIInvalidateQueue(DeviceExtension->QueueArray[index], STATUS_NO_SUCH_DEVICE);
            }

            // flush pending io list
            HYPCIInvalidateIo(&DeviceExtension->IoLock, STATUS_NO_SUCH_DEVICE);

            IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, FALSE);

            HYPCIFreeResources(DeviceExtension);
        }

        // Update our PnP state
        DeviceExtension->PnpState = PnpStateRemoved;

        HYPCIReleaseRemoveLock(DeviceExtension);
        HYPCIWaitForSafeRemove(DeviceExtension);

        // Send the remove IRP down the stack.
        Irp->IoStatus.Status = STATUS_SUCCESS;
        IoSkipCurrentIrpStackLocation (Irp);
        status = IoCallDriver (DeviceExtension->LowerDeviceObject, Irp);

        // Detach our device object from the device stack
        IoDetachDevice(DeviceExtension->LowerDeviceObject);

        // free InterfaceName memory
        RtlFreeUnicodeString(&DeviceExtension->InterfaceName);

        // free power work item
        IoFreeWorkItem(DeviceExtension->PowerWorkItem);

        // attempt to delete our device object
        IoDeleteDevice(DeviceExtension->DeviceObject);
        return status;

    case IRP_MN_QUERY_CAPABILITIES:

        // Check the device capabilities struct
        deviceCapabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;

        if (deviceCapabilities->Version != 1 ||  deviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES))
        {
            // We don't support this version. Fail the request
            break;
        }

        // Pass the IRP down
        status = HYPCISubmitIrpSync(DeviceExtension->LowerDeviceObject, Irp);

        // Lower drivers have finished their operation, so now
        // we can finish ours.
        if (NT_SUCCESS(status)) 
        {
            //*****************************************************************
            //*****************************************************************
            // TODO: Override the device capabilities 
            //       set by the underlying drivers here.
            //*****************************************************************
            //*****************************************************************
        }

        break;

    default:
        // Pass down any unknown requests.
        IoSkipCurrentIrpStackLocation(Irp);
        status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);

        // Adjust our active I/O count
        HYPCIReleaseRemoveLock(DeviceExtension);
        return status;
    }

    Irp->IoStatus.Status = status;
    IoCompleteRequest (Irp, IO_NO_INCREMENT);

    // Adjust the active I/O count
    HYPCIReleaseRemoveLock(DeviceExtension);

    return status;
}

好了,下一篇我们介绍下一个dispatcher

评论

0条评论

发表评论

电子邮件地址不会被公开。