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

📄 pci_sample.c

📁 PCI硬件的驱动程序范例
💻 C
📖 第 1 页 / 共 3 页
字号:
#endif        
        //
        // Clean up the mess
        //
        OsrReturnPool(configInfo, deviceDescription, resources);

        OsrUnload(DriverObj);

        //
        // Indicate load failure to the I/O manager
        //
        return(code);
    }

#if DBG
    //
    // For curiosity and debugging purposes, display the resources that were
    // allocated for our use.
    //
    OsrPrintResourceList(resources);

    portStart.LowPart = 0;
    portLength = 0;
    interruptLevel = 0;
    interruptVector = 0;

#endif
    
    //
    // Decode the returned resources
    //
    // For our device, we know to expect an interrupt resource, and ONE set
    // I/O space port resources.  We expect, and we attempt to handle, no
    // other resources.
    //
    for (index = 0; index < resources->Count; index++)  {
        ULONG index2;
        
        for (index2 = 0;
             index2 < resources->List[index].PartialResourceList.Count;
             index2++) {

            PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
            
            prd = &resources->List[index].PartialResourceList.PartialDescriptors[index2];

            switch (prd->Type) {
                
                case CmResourceTypePort:

                    //
                    // Our port resources are in I/O space.  And our port
                    // space is 64. bytes long.
                    //
                    ASSERT(prd->Flags == CM_RESOURCE_PORT_IO);
                    ASSERT(prd->u.Port.Length == 64);

                    portStart.HighPart = 0;
                    portStart.LowPart  =  prd->u.Port.Start.LowPart;
                    portLength =  prd->u.Port.Length;
                    break;

                case CmResourceTypeInterrupt:

                    //
                    // PCI interrupts are level sensitive
                    //
                    ASSERT(prd->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE);

                    interruptLevel = prd->u.Interrupt.Level;
                    interruptVector = prd->u.Interrupt.Vector;
                    break;

#if DBG
                case CmResourceTypeMemory:
                    DbgPrint("...Unexpected memory resource!\n");
                    break;

                case CmResourceTypeDma:
                    DbgPrint("...Unexpected DMA resource!\n");
                    break;

                case CmResourceTypeDeviceSpecific:
                    DbgPrint("...Unexpected device specific resource!\n");
                    break;
#endif
                default:
                    DbgPrint("Unexpected and unknown resource type\n");
                    break;
            }
            
        }

    }

    //
    // We NEED the interrupt info AND one port
    //
    ASSERT(interruptLevel && interruptVector && portStart.LowPart && portLength);

    //
    // Indciate that the resigsters are in port space on this card
    //
    addressSpace = 0x01;

    //
    // Get the HAL to translate our bus-relative port base address, to an
    // unambiguous address to be used for device access.  If we're returned
    // FALSE, the call failed.
    //
    if (!HalTranslateBusAddress(PCIBus,
                               devExt->BusNumber,
                               portStart,
                               &addressSpace,
                               &address))  {
        //
        // Print an appropriate error string.
        //
#if DBG
        DbgPrint("HalAssignSlotResourced failed\n");
#endif

        //
        // Clean up the mess
        //
        OsrReturnPool(configInfo, deviceDescription, resources);

        OsrUnload(DriverObj);

        //
        //
        return(STATUS_UNSUCCESSFUL);
    }
    
    //
    // If this card's I/O space registers actually appear in memory space on
    // this processor, we need to map them with some kernel virtual addresses
    // so we can access them. This may be the case on, for example, some RISC
    // processors. NOTE HOWEVER, that regardless of the addressSpace returned,
    // since the registers on the card are in PORT I/O space, we will ALWAYS
    // access them in the driver using WRITE_PORT_xxx and READ_PORT_xxx.
    //
    if (addressSpace == 0x0) {
        ULONG lengthInBytes;

#if DBG
        DbgPrint("Address space for port is MEMORY\n");
#endif

        lengthInBytes =
           resources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Length;

        //
        // Maps a potentially 64 bit physical address to a 32 bit virtual address.
        //
        devExt->AmccBaseRegisterAddress = MmMapIoSpace(address,
                                                       lengthInBytes,
                                                       FALSE);

    } else {

        ASSERT(addressSpace == 0x01);

#if DBG
        DbgPrint("Address space is port\n");
#endif
        //
        // Port I/O space is only 16 bits long, so we can grab the low 32 bits
        // of the address only.
        //
        devExt->AmccBaseRegisterAddress = (PULONG)address.LowPart;

    }
    
#if DBG
    DbgPrint("OSRPCI Registers start at 0x%x", devExt->AmccBaseRegisterAddress);
#endif
    //
    // Register our DpcforISR routine.  This is the routine which will
    // be used to complete our interrupt processing.
    //
    IoInitializeDpcRequest(devObj, OsrDpcForIsr);
    
    //
    // Like port and memory addresses, interrupts also have to be "translated"
    // from bus-specific values.
    //
    mappedSystemVector = HalGetInterruptVector(PCIBus,
                                                devExt->BusNumber,
                                                interruptLevel,
                                                interruptVector,
                                                &irql,
                                                &affinity);
#if DBG
    DbgPrint("HalGetInterruptVector returned vector 0x%x, IRQL 0x%0x, Affinity 0x%0x\n",
                    mappedSystemVector,
                    irql,
                    affinity);
#endif

    //
    // 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,
                              NULL,
                              mappedSystemVector,
                              irql,
                              irql,
                              LevelSensitive,
                              TRUE,
                              affinity,
                              FALSE);
    if (!NT_SUCCESS(code))  {

#if DBG
        DbgPrint("IoConnectInterrupt failed with error 0x%x", code);
#endif

        //
        // Clean up the mess
        //
        OsrReturnPool(configInfo, deviceDescription, resources);

        OsrUnload(DriverObj);

        //
        // Indicate load failure to the I/O manager; driver image is deleted...
        //
        return(code);
    }
    
    //
    // Now we reset the adapter card.
    //
    OsrResetAdapter(devObj, FALSE);

    //
    // Finally, we get our adapter objects from the HAL. When we do this,
    // we describe out device to the HAL in pretty gory detail.   In return,
    // he gives us a pointer to our adapter object, and tells us the maximum
    // number of mapping registers we should ever use.  This is based on
    // the maximum transfer size that we support, yet limited by the number
    // of available map registers on HALs where real map registers are used.
    // 
    // Note that since this device is capable of performing reads and writes
    // in parallel we allocate TWO ADAPTER OBJECTS.  We use the same device
    // description structure for both, since the device's READ DMA ability is
    // identical to its WRITE DMA ability.
    // 
    deviceDescription = ExAllocatePoolWithTag(PagedPool,
                                            sizeof(DEVICE_DESCRIPTION), 'dRSO');

    //
    // Important: Zero out the entire structure first!
    //
    RtlZeroMemory(deviceDescription, sizeof(DEVICE_DESCRIPTION));

    deviceDescription->Version = DEVICE_DESCRIPTION_VERSION;
    deviceDescription->Master = TRUE;
    deviceDescription->ScatterGather = FALSE;
    deviceDescription->Dma32BitAddresses = TRUE;
    deviceDescription->BusNumber = devExt->BusNumber;
    deviceDescription->InterfaceType = PCIBus;

    //
    // Maximum size of transfer that we support on this device.
    //
    deviceDescription->MaximumLength = OSR_PCI_MAX_TXFER;

    devExt->ReadAdapter = HalGetAdapter(deviceDescription, &devExt->ReadMapRegsGot);

    if(!devExt->ReadAdapter)  {

#if DBG
        DbgPrint("HalGetAdapter for READ FAILED!!\n");    
#endif
        //
        // Clean up the mess
        //
        OsrReturnPool(configInfo, deviceDescription, resources);

        OsrUnload(DriverObj);

        return(STATUS_UNSUCCESSFUL);
    }

#if DBG
    DbgPrint("Map Registers got for read = %d.\n", devExt->ReadMapRegsGot);
#endif

    //
    // Get ANOTHER Adapter Object for use with WRITE transfers
    //
    devExt->WriteAdapter = HalGetAdapter(deviceDescription, &devExt->WriteMapRegsGot);

    if(!devExt->WriteAdapter)  {

#if DBG
        DbgPrint("HalGetAdapter for WRITE FAILED!!\n");    
#endif
        //
        // Clean up the mess
        //
        OsrReturnPool(configInfo, deviceDescription, resources);

        OsrUnload(DriverObj);

        return(STATUS_UNSUCCESSFUL);
    }

#if DBG
    DbgPrint("Map Registers got for write = %d.\n", devExt->WriteMapRegsGot);
#endif

    //
    // Initialize the watchdog timer.  This timer causes a "soft reset"
    // on the device, in a particular direction, if an in-progress IRP
    // hangs around too long.
    //
    IoInitializeTimer(devObj, OsrWatchdogTimer, NULL);
    IoStartTimer(devObj);

    //
    // Return the memory allocated from pool during initialization
    //
    ExFreePool(configInfo);
    ExFreePool(deviceDescription);    
    
    //
    // Don't forget to free the CM_RESOURCE_LIST structure!
    // Even though HalAssignSlotResources(...) allocated it, we're
    // responsible for freeing it!!
    //
    ExFreePool(resources); 

#if DBG
    DbgPrint("DriverEntry: done\n");
#endif
    
    return(STATUS_SUCCESS);
    
}

///////////////////////////////////////////////////////////////////////////////
//
//  OsrUnload
//
//      This routine is our dynamic unload entry point.  We are called here when
//    the OS wants to unload our driver.  It is our responsibility to release any
//    resources we allocated.
//
//  INPUTS:
//
//      DriverObj - Address of our DRIVER_OBJECT.
//
//  OUTPUTS:
//
//      None.
//
//  RETURNS:
//
//      None.
//
//  IRQL:
//
//    This routine is called at IRQL_PASSIVE_LEVEL.
//
//  NOTES:
//
//    No doubt we pool leak at this entry point by not properly returning everything.
//
///////////////////////////////////////////////////////////////////////////////
static VOID
OsrUnload(PDRIVER_OBJECT DriverObject)
{
    POSR_DEVICE_EXT devExt;
    PDEVICE_OBJECT devObj;
    IO_RESOURCE_REQUIREMENTS_LIST reqList;
    NTSTATUS code;
    UNICODE_STRING linkName;
    CM_RESOURCE_LIST returnResources;
    BOOLEAN conflictDetected;
            
#if DBG
    DbgPrint("SAMPLE-PCI: UNLOAD called.\n");
#endif

    //
    // For THIS driver, there will only ever be a single device object.
    // Because of this, we just get it from the DriverObj.  If this were
    // a multiple device driver, we would do this in a while loop...
    //
    devObj = DriverObject->DeviceObject;

    if (!devObj) {

        return;
    }

    devExt= (POSR_DEVICE_EXT)devObj->DeviceExtension;

    RtlInitUnicodeString(&linkName, L"\\??\\OSRPCI");

    IoDeleteSymbolicLink(&linkName);

    //
    // Reset the adapter card
    //
    OsrResetAdapter(devObj, FALSE);

    if (devExt->InterruptObject) {
        //
        // Disconnect the interrupt.
        //
        IoDisconnectInterrupt(devExt->InterruptObject);
    }

    //
    // Set up a "special" reasource list, that indicates NO RESOURCES.
    // This will result in our resouces being returned.
    //
    returnResources.Count = 0;

    code = IoReportResourceUsage(NULL,
                                DriverObject,
                                NULL,
                                0,
                                devObj,
                                &returnResources,
                                sizeof(returnResources),
                                FALSE,
                                &conflictDetected);

    if(!NT_SUCCESS(code))  {
        
#if DBG
        DbgPrint("UNLOAD: IoReportResourceUsage failed.  Status = 0x%0x\n",
                        code);
#endif
    }                          

⌨️ 快捷键说明

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