⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pnp.c

📁 PCI驱动编程实例
💻 C
📖 第 1 页 / 共 4 页
字号:
            // driver
            //

            //
            // Wait until all active requests on the device have
            // completed...
            //
            OsrWaitForStop(devExt);
            
            //
            // There are NO ACTIVE IRPs on the device at this point.
            //

            //
            // Return any resources we're using.
            //
            OsrReturnResources(devExt);

            //
            // NOTE: We DO NOT delete our device object here.  This is
            // one difference between a _STOP_DEVICE and _REMOVE_DEVICE.
            //
#if DBG
            DbgPrint("OsrPnp: Passing along request\n");
#endif

            //
            // Pass this request on down to the bus driver
            //
            IoSkipCurrentIrpStackLocation(Irp);
            
            //
            // We're cool with the stop...
            //
            Irp->IoStatus.Status = STATUS_SUCCESS;

            code = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
            break;        


        //
        // STATE:   STOP_PENDING
        // IRP_MN:  _CANCEL_STOP_DEVICE
        //
        // We're here because we've already received a QUERY_STOP,
        // that we've agreed to.  We've completed any pending I/O
        // requests.  Now we've received a CANCEL_STOP_DEVICE
        // IRP, that sort of says "never mind" about that stop.
        //
        // We restart our queues and return to Started state.
        //
        case STATE_STOP_PENDING + IRP_MN_CANCEL_STOP_DEVICE:
#if DBG
            DbgPrint("OsrPnp: PROCESSING CANCEL_STOP\n");
#endif

            //
            // fall through...
            //

        //
        // STATE:   REMOVE_PENDING
        // IRP_MN:  _CANCEL_REMOVE_DEVICE
        //
        // We're here because we've already received a QUERY_REMOVE,
        // that we've agreed to.  We've completed any pending I/O
        // requests.  Now we've received a CANCEL_REMOVE_DEVICE
        // IRP, that sort of says "never mind" about that remove.
        //
        // We restart our queues and return to Started state.
        //
        case STATE_REMOVE_PENDING + IRP_MN_CANCEL_REMOVE_DEVICE:

#if DBG
            if( devExt->State == STATE_REMOVE_PENDING) {
            
                DbgPrint("OsrPnp: PROCESSING CANCEL_REMOVE\n");
       
            }
#endif

            //
            // The Underlying BUS DRIVER must handle these IRPs
            // before we do...
            //

            //
            // We need to wait for the underlying bus driver to
            // get restarted, before we can continue processing.
            //
            IoCopyCurrentIrpStackLocationToNext(Irp);

            IoSetCompletionRoutine(Irp,
                                   OsrPnpComplete,
                                   &eventWaitLowerDrivers,
                                   TRUE,
                                   TRUE,
                                   TRUE);

            code = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);

            if(code == STATUS_PENDING) {

                KeWaitForSingleObject(&eventWaitLowerDrivers,
                                      Executive,
                                      KernelMode,
                                      FALSE,
                                      NULL);
            }


            //
            // We're now in STARTED state
            //
            devExt->State = STATE_STARTED;

            //
            // Go see if there's a request that we can start now
            //
            OsrProcessQueuedRequests(devExt);

            code = STATUS_SUCCESS;

            Irp->IoStatus.Status = code;

            Irp->IoStatus.Information = 0;

            IoCompleteRequest(Irp, IO_NO_INCREMENT);

            break;

        default:

            //
            // DEFAULT CASE
            // Just pass the request to the lower driver
            //
#if DBG
            DbgPrint("OsrPnp: Default case: Just pass it along...\n");
#endif
            IoSkipCurrentIrpStackLocation (Irp);

            code = IoCallDriver (devExt->DeviceToSendIrpsTo, Irp);

            break;
    }

    //
    // Adjust in-progress request count
    //
    OsrRequestDecrement(devExt);

#if DBG
    DbgPrint("OsrPnp: Leaving with new state ");

    OsrPrintState(devExt);

    DbgPrint("OsrPnp: exit (%d.).\n", devExt->OutstandingIO);
#endif

    //
    // We always finish our work in this function
    //
    ASSERT(code != STATUS_PENDING);

    return(code);
}

//
// OsrPnpComplete
// 
// This is the completion routine for IRP_MJ_PNP requests
//
NTSTATUS
OsrPnpComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
    PIO_STACK_LOCATION  iostack;
    PKEVENT pEvent = (PKEVENT) Context;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER (DeviceObject);

    iostack = IoGetCurrentIrpStackLocation (Irp);

//
// Driver Writers, please note:
//
//  The following code is only necessary IF (a) WE have a completion
//  routine, AND (b) WE return STATUS_PENDING from our dispatch entry
//  point after re-claiming the IRP.  Since neither of these things
//  is true... this code does not belong here.
//
//    if (Irp->PendingReturned) {
//
//        IoMarkIrpPending( Irp );
//
//    }

    switch (iostack->MajorFunction) {

        case IRP_MJ_PNP:

            KeSetEvent(pEvent, 0, FALSE);

            //
            // Take the IRP back so that we can continue using it during
            // the IRP_MN_START_DEVICE dispatch routine.
            // NB: we will have to call IoCompleteRequest
            //
            return STATUS_MORE_PROCESSING_REQUIRED;

            break;

        case IRP_MJ_POWER:
#if DBG
            DbgPrint("OsrPnpComplete: NOT MJ_POWER support in this driver!\n");
#endif

            break;

        default:
#if DBG
            DbgPrint("OsrPnpComplete: NOT MJ_PNP or MJ_POWER IRP??\n");
#endif

            break;
    }

    return status;
}

///////////////////////////////////////////////////////////////////////////////
//
// OsrStartDevice
//
//      This function is called from the DispatchPnp Entry Point to
//      actually start the hardware.
//
//  INPUTS:
//
//      DevExt  - Address of our device extension.
//      IoStackLocation -- Pointer to I/O Stack Location containing
//                  configuration information
//
//  OUTPUTS:
//
//      None.
//
//  RETURNS:
//
//    STATUS_SUCCESS;
//
//  IRQL:
//
//
//  NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS
OsrStartDevice(IN POSR_DEVICE_EXT DevExt,
               IN PIO_STACK_LOCATION IoStackLocation)
{
    NTSTATUS code = STATUS_SUCCESS;
    ULONG index;
    PDEVICE_DESCRIPTION deviceDescription;
    PCM_RESOURCE_LIST pResourceList, pResourceListTranslated;
    PCM_PARTIAL_RESOURCE_LIST prl, prlTranslated;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR prd, prdTranslated;
    PCM_FULL_RESOURCE_DESCRIPTOR frd, frdTranslated;

    pResourceList = IoStackLocation->Parameters.StartDevice.AllocatedResources;
    pResourceListTranslated = IoStackLocation->Parameters.StartDevice.AllocatedResourcesTranslated;

    frd = &pResourceList->List[0];
    frdTranslated = &pResourceListTranslated->List[0];

    prl = &frd->PartialResourceList;
    prlTranslated = &frdTranslated->PartialResourceList;

#if DBG
    OsrPrintResourceList(pResourceList);
    OsrPrintResourceList(pResourceListTranslated);
#endif

    //
    // Ensure the base address starts as NULL
    //
    DevExt->AmccBaseRegisterAddress = NULL;

    //
    // Walk through the partial resource descriptors to find the
    // hardware resources that have been allocated to us
    //
    // We need one range of port addresses (0x40 bytes long) and
    // and interrupt resource.
    //
    for (index = 0,
         prd = &prl->PartialDescriptors[index],
         prdTranslated = &prlTranslated->PartialDescriptors[index];
         index < prl->Count && NT_SUCCESS(code);
         index++, prd++, prdTranslated++) {

        switch (prd->Type) {

            case CmResourceTypePort:

                //
                // Newer AMCC Demo Boards have more than just one BAR
                // programmed in the PCI configuration ROM.  We want
                // the FIRST BAR, which is the base address of the
                // device itself.  So, we ignore any ports reported to
                // us after the first one.
                //
                if (DevExt->AmccBaseRegisterAddress) {
#if DBG
                    DbgPrint("Ignoring additional port resource ...\n");

                    if(prdTranslated->Type == CmResourceTypePort) {
                        DbgPrint("(Translated port 0x%0x)\n",
                         prdTranslated->u.Port.Start.LowPart);


                    } else {
                        DbgPrint("(Translated memory 0x%0x)\n",
                         prdTranslated->u.Memory.Start);
                    }

#endif
                    break;                    
                }

#if DBG
                DbgPrint("Configuring port resource ...\n");
#endif
                //
                // Should only get ONE port resources
                //
                ASSERT(DevExt->AmccBaseRegisterAddress == NULL);

                //
                // Our port space on this card is 0x40 bytes longs
                //
                ASSERT(prd->u.Memory.Length == 0x40);

                //
                // Do the device ports appear in port I/O space or
                // in memory space on this machine.
                //
                if(prdTranslated->Type == CmResourceTypePort) {

                    //
                    // The port is in port space on this machine.  Just
                    // store away the address
                    //
                    DevExt->MappedPorts = FALSE;

                    DevExt->AmccBaseRegisterAddress =
                        (PVOID) prdTranslated->u.Port.Start.LowPart;

#if DBG
                    DbgPrint("Translated resource is a port at 0x%0x\n",
                                DevExt->AmccBaseRegisterAddress);
#endif

                } else {


                    ASSERT(prdTranslated->Type == CmResourceTypeMemory);

                    //
                    // The port is in memory space on this machine.  We
                    // need to map some virtual addresses over the physical
                    // address provided us, and remember to do an UNMAP
                    // if/when we have to return the resources.
                    //
                    DevExt->MappedPorts = TRUE;

                    DevExt->AmccBaseRegisterAddress =
                        MmMapIoSpace(prdTranslated->u.Memory.Start,
                                      prdTranslated->u.Memory.Length,
                                      MmNonCached);


#if DBG
                    DbgPrint("Translated resource is MEMORY at 0x%0x\n",
                                DevExt->AmccBaseRegisterAddress);
#endif

                }

                break;


            case CmResourceTypeInterrupt:

#if DBG
                DbgPrint("Configuring Interrupt resource ...\n");
#endif
                //
                // Be sure we get only ONE interrupt resource
                //
                ASSERT(DevExt->InterruptLevel == 0);

                //
                // Again, assume that the translated and raw resources
                // are in the same order and number
                //
                ASSERT(CmResourceTypeInterrupt == prdTranslated->Type);

                DevExt->InterruptLevel       = (UCHAR)prdTranslated->u.Interrupt.Level;
                DevExt->InterruptVector      = prdTranslated->u.Interrupt.Vector;
                DevExt->InterruptAffinity    = prdTranslated->u.Interrupt.Affinity;
                
                if (prdTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
                
                    DevExt->InterruptMode = Latched;

                } else {
                
                    DevExt->InterruptMode = LevelSensitive;
                }

                //
                // Because this is a PCI device, we KNOW it must be
                // a LevelSensitive Interrupt
                //
                ASSERT(DevExt->InterruptMode == LevelSensitive);

#if DBG
                DbgPrint("Interrupt level: 0x%0x, Vector: 0x%0x, Affinity: 0x%0x\n",
                            DevExt->InterruptLevel,
                            DevExt->InterruptVector,
                            DevExt->InterruptAffinity);
#endif
                break;

            default:
#if DBG
                DbgPrint("OSRPCI: Unhandled Resource -- CmResourceType received 0x%x\n", prd->Type);
#endif
                break;
        }
    }

    //
    // We NEED the interrupt info AND one port
    //
    ASSERT(DevExt->InterruptLevel && DevExt->AmccBaseRegisterAddress);

    //
    // Register our DPCforISR routine.  This is the routine which will
    // be used to complete our interrupt processing.
    //
    IoInitializeDpcRequest(DevExt->FunctionalDeviceObject, OsrDpcForIsr);

    //
    // Connect to interrupt from the device.  After this call,
    // interrupts from the device will result in calls to our OsrHandleInterrupt
    // function.
    //
    code = IoConnectInterrupt(&DevExt->InterruptObject,
                              OsrHandleInterrupt,
                              DevExt,                   // ISR Context
                              NULL,
                              DevExt->InterruptVector,
                              DevExt->InterruptLevel,
                              DevExt->InterruptLevel,
                              DevExt->InterruptMode,
                              TRUE,
                              DevExt->InterruptAffinity,
                              FALSE);

    if (!NT_SUCCESS(code))  {

#if DBG
        DbgPrint("IoConnectInterrupt failed with error 0x%x", code);
#endif
        //
        // We're outa here 
        //
        return(code);
    }
    
    //
    // Now we reset the adapter card.
    //
    OsrResetAdapter(DevExt->FunctionalDeviceObject, FALSE);

    //
    // Finally, we get our adapter object from the HAL.  When we do this,
    // we describe out device to the HAL, in pretty gory detail.  In
    // return, the HAL gives us a pointer to our adapter object, and
    // tells us the maximum number of mapping registers we can ever
    // hope to get.
    // 
    deviceDescription = ExAllocatePoolWithTag(PagedPool,
                                            sizeof(DEVICE_DESCRIPTION), 
                                            'pRSO');

    //
    // Important: Zero out the entire structure first!

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -