📄 pci_sample.c
字号:
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 1995 - 1997 OSR Open Systems Resources, Inc.
// All Rights Reserved
//
// This sofware is supplied for instructional purposes only.
//
// OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty
// for this software. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
// THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR
// PURPOSE. THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS
// WITH YOU. OSR's entire liability and your exclusive remedy shall not
// exceed the price paid for this material. In no event shall OSR or its
// suppliers be liable for any damages whatsoever (including, without
// limitation, damages for loss of business profit, business interruption,
// loss of business information, or any other pecuniary loss) arising out
// of the use or inability to use this software, even if OSR has been
// advised of the possibility of such damages. Because some states/
// jurisdictions do not allow the exclusion or limitation of liability for
// consequential or incidental damages, the above limitation may not apply
// to you.
//
// OSR Open Systems Resources, Inc.
// 105 Route 101A Suite 19
// Amherst, NH 03031 (603) 595-6500 FAX: (603) 595-6503
// email bugs to: bugs@osr.com
//
//
// This driver is the example Busmaster DMA device driver that
// accompanies the book Windows NT Device Driver Development, by
// Peter Viscarola and W. Anthony Mason, (c) 1998 OSR Open Systems
// Resources, Inc. and published by MacMillan Technical Publishing
// ISBN 1578700582.
//
// MODULE:
//
// PCI_SAMPLE.C
//
// ABSTRACT:
//
// This file contains the initial entry point for the OSR Sample
// PCI Busmaster DMA device driver for the AMCC 5933 chip.
//
// AUTHOR(S):
//
// OSR Open Systems Resources, Inc.
//
// REVISION:
//
// V1.1 Fix to typo in OsrWrite() to correctly set cancel
// routine to NULL when completing a request that's
// been cancelled very early in its processing.
//
//
///////////////////////////////////////////////////////////////////////////////
//#include <ntddk.h>
#include "osr-pci.h"
//
// Forward Declarations
//
NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObj, PUNICODE_STRING RegistryPath);
static VOID OsrUnload(PDRIVER_OBJECT DriverObject);
static VOID OsrReturnPool(PPCI_COMMON_CONFIG configInfo, PDEVICE_DESCRIPTION
deviceDescription, PCM_RESOURCE_LIST resources);
#if DBG
static VOID OsrPrintResourceList(PCM_RESOURCE_LIST);
static VOID OsrPrintConfig(PPCI_COMMON_CONFIG configInfo);
#endif
//
// The following pragma allows the DriverEntry code to be discarded once
// initialization is completed
//
#pragma alloc_text(INIT,DriverEntry)
///////////////////////////////////////////////////////////////////////////////
//
// DriverEntry
//
// This routine is called by NT when the driver is first loaded. It is the
// responsibility of this routine to find it's device and create whatever
// device objects it needs.
//
// INPUTS:
//
// DriverObj - Address of the DRIVER_OBJECT created by NT for this driver.
//
// RegistryPath - UNICODE_STRING which represents this drivers KEY in the
// Registry.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_SUCCESS. Otherwise an error indicating why the driver could not
// Load.
//
// IRQL:
//
// This routine is called at IRQL_PASSIVE_LEVEL.
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObj, PUNICODE_STRING RegistryPath)
{
NTSTATUS code;
PPCI_COMMON_CONFIG configInfo = NULL;
ULONG busNumber;
ULONG deviceNumber;
ULONG AddressSpace;
PCI_SLOT_NUMBER slotNumber;
ULONG length;
BOOLEAN moreBuses;
BOOLEAN adapterFound;
ULONG index;
ULONG addressSpace;
PHYSICAL_ADDRESS address;
POSR_DEVICE_EXT devExt;
PDEVICE_OBJECT devObj;
UNICODE_STRING devName, linkName;
PDEVICE_DESCRIPTION deviceDescription = NULL;
PCM_RESOURCE_LIST resources = NULL;
ULONG interruptLevel;
ULONG interruptVector;
ULONG mappedSystemVector;
PHYSICAL_ADDRESS portStart;
ULONG portLength;
KIRQL irql;
KAFFINITY affinity;
DbgPrint("\nOSR PCI Sample Driver -- Compiled %s %s\n",__DATE__, __TIME__);
DbgPrint("(c) 1997 OSR Open Systems Resources, Inc.\n\n");
//
// Establish dispatch entry points for the functions we support
//
DriverObj->MajorFunction[IRP_MJ_CREATE] = OsrCreateClose;
DriverObj->MajorFunction[IRP_MJ_CLOSE] = OsrCreateClose;
DriverObj->MajorFunction[IRP_MJ_READ] = OsrRead;
DriverObj->MajorFunction[IRP_MJ_WRITE] = OsrWrite;
DriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = OsrDeviceControl;
//
// Unload function
//
DriverObj->DriverUnload = OsrUnload;
//
// Allocate space for a configuration information structure
//
configInfo = ExAllocatePoolWithTag(PagedPool,
sizeof(PCI_COMMON_CONFIG),
'pRSO');
if (!configInfo) {
//
// Clean up the mess
//
OsrReturnPool(configInfo, deviceDescription, resources);
//
// Indicate load failure to the I/O manager
//
return(STATUS_INSUFFICIENT_RESOURCES);
}
//
// Search for our device on all the PCI busses in the system
//
// We do this by ennumerating the configuration information for each
// slot on each PCI bus in the system, until we find a device with
// our Vendor ID and Device ID.
//
// Since this sample driver supports only a single card, we stop looking as
// soon as we find one device. Drivers that support multiple cards would
// ennumerate all the busses and slots, finding as many devices as exist.
//
// Since our device is not a PCI "multifunction" device, we don't search
// each function in each slot.
//
//
adapterFound = FALSE;
moreBuses = TRUE;
for (busNumber = 0; !adapterFound && moreBuses; busNumber++) {
//
// Ennumerate all the devices on this bus
//
for (deviceNumber = 0;
!adapterFound && deviceNumber < PCI_MAX_DEVICES;
deviceNumber++) {
//
// For PCI buses, the logical slot number is a PCI_SLOT_NUMBER
// structure, comprising a combination of the device number and the
// function number on the card. The Reserved section MUST be set
// to zero.
//
// Note that since we're not a multifunction device, we only look
// at FunctionNumber 0 in each slot.
//
slotNumber.u.bits.Reserved = 0;
slotNumber.u.bits.DeviceNumber = deviceNumber;
slotNumber.u.bits.FunctionNumber = 0;
//
// Get the configuration space for the adapter in this slot
//
length = HalGetBusData(PCIConfiguration,
busNumber,
slotNumber.u.AsULONG,
configInfo,
sizeof(PCI_COMMON_CONFIG) );
//
// A return value of zero indicates no more PCI buses on the system
//
if (length == 0) {
#if DBG
DbgPrint("Reached end of PCI bus list\n");
#endif
moreBuses = FALSE;
break;
}
//
// If there's nothing in this slot, PCI_INVALID_VENDORID is returned
// as the vendor ID. If this is the case, just continue running
// the bus.
//
if (configInfo->VendorID == PCI_INVALID_VENDORID) {
continue;
}
//
// Dump out information about the device found.
//
#if DBG
DbgPrint("Found a PCI device at Bus %d. Device %d.\n",
busNumber,
deviceNumber);
DbgPrint("Vendor id = 0x%0x, Device id = 0x%0x\n",
(int)configInfo->VendorID,
(int)configInfo->DeviceID);
#endif // DBG
//
// Is this the PCI device for which we've been searching? It is
// if both the vendor and device ID match
//
if ( (configInfo->VendorID == OSR_PCI_VID) &&
(configInfo->DeviceID == OSR_PCI_DID) ) {
ULONG index;
//
// FOUND IT! No need to keep searching. We support only
// one device.
//
adapterFound = TRUE;
#if DBG
DbgPrint("*** Found OUR PCI ADAPTER ***");
//
// Just for the sake of interest, let's dump some of the
// configuration information for our device.
//
OsrPrintConfig(configInfo);
#endif
}
}
}
//
// If we didn't find our adapter, we bail out here, thereby aborting
// the driver load process. The I/O Manager will delete our driver
// object.
//
if (!adapterFound) {
#if DBG
DbgPrint("OSR PCI Sample device was not found!? -- EXITING.\n");
#endif
//
// Clean up the mess
//
OsrReturnPool(configInfo, deviceDescription, resources);
//
// Indicate load failure to the I/O manager; driver image is deleted...
//
return(STATUS_NO_SUCH_DEVICE);
}
//
// ***************************************************************
//
// Hooray! We've found our device!
//
// Lets create a device object for it
//
//
// Initialize the UNICODE device name. This will be the "native NT" name
// for our device.
//
RtlInitUnicodeString(&devName, L"\\Device\\OSRPCI");
//
// Ask the I/O Manager to create the device object and
// device extension
//
code = IoCreateDevice(DriverObj,
sizeof(OSR_DEVICE_EXT),
&devName,
FILE_DEVICE_OSR,
0,
FALSE,
&devObj);
if(!NT_SUCCESS(code)) {
#if DBG
DbgPrint("IoCreateDevice failed. Status = 0x%0x\n", code);
#endif
return(STATUS_UNSUCCESSFUL);
}
//
// Get a pointer to our device extension
//
devExt = (POSR_DEVICE_EXT)devObj->DeviceExtension;
//
// Zero out the device extension. While not strictly necessary
// (the documentation says the device extension is zeroed) it's
// better to be safe.
//
RtlZeroMemory(devExt, sizeof(OSR_DEVICE_EXT));
//
// Save the device object pointer away for future reference
//
devExt->DeviceObject = devObj;
//
// Store the bus and slot number away for the device we found
//
devExt->BusNumber = busNumber-1;
devExt->SlotNumber = slotNumber;
//
// Next, make the device accessible from user-mode applications.
// Note that this name can be either the same or different from
// the native "kernel mode" name of the device object, given above.
//
RtlInitUnicodeString(&linkName, L"\\??\\OSRPCI");
code = IoCreateSymbolicLink(&linkName, &devName);
if (!NT_SUCCESS(code))
{
#if DBG
DbgPrint("IoCreateSymbolicLink failed. Status = 0x%x\n", 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);
}
//
// Initialize our IRP queues
//
InitializeListHead(&devExt->ReadQueue);
InitializeListHead(&devExt->WriteQueue);
//
// Initialize our Spin Locks
//
KeInitializeSpinLock(&devExt->ReadQueueLock);
KeInitializeSpinLock(&devExt->WriteQueueLock);
//
// Ask the I/O Manager to use describe user read/write buffers using MDLs
//
devObj->Flags |= DO_DIRECT_IO;
//
// Next, get the HAL to tell us about the resources the device will use.
// These resources include ports, shared memory regions, interrupts, and
// the like. The resources will be resevered for us in the registry (so
// we do not have to call either IoReportResourceUsage or IoAssignResources).
//
code = HalAssignSlotResources(RegistryPath,
NULL,
DriverObj,
devObj,
PCIBus,
devExt->BusNumber,
devExt->SlotNumber.u.AsULONG,
&resources);
//
// On return from this call, all resources are identified and assigned for
// use by our device.
//
if (!NT_SUCCESS(code)) {
//
// log an appropriate error string.
//
#if DBG
DbgPrint("HalAssignSlotResourced failed! Status = 0x%0x", code);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -