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

📄 document.html

📁 DT2851图形卡NT驱动源码
💻 HTML
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0052)http://www.vu.union.edu/~dixonw/driver/document.html -->
<HTML><HEAD><TITLE>Sample Windows NT Device Driver Documentation</TITLE>
<META content="text/html; charset=gb2312" http-equiv=Content-Type>
<META content="MSHTML 5.00.2614.3500" name=GENERATOR></HEAD>
<BODY>
<CENTER>
<H1>Walt Dixon's<BR>Sample Windows NT Device Driver<BR>Documentation </H1><A 
href="mailto:dixonw@virtual.union.edu">dixonw@virtual.union.edu</A> </CENTER>
<HR>

<H2>Why I wrote it</H2>This driver provides a gateway between the physical 
protected sub-system and the user mode process. Since the DT2851 has both a port 
I/O and memory mapped interface, the device driver must be responsible for both 
channels of communication. 
<HR>

<H2>Driver Entry</H2>Each kernel mode driver has an initialization routine 
called the DriverEntry. This routine is responsible for allocating the necessary 
resources, setting up the dispatch entry points that handle the I/O request 
packets, and optionally defining an unload routine. This unload routine is 
necessary if the driver is designed to be loaded and or replaced dynamically, 
where unloading the driver requires that claimed resources be freed. 
<P><PRE><B>
DriverEntry( IN  PDRIVER_OBJECT pDriverObject, 
             IN  PUNICODE_STRING registryPath );
</B></PRE>
<P>The DriverEntry routine is passed two arguments: a pointer to the driver 
object, which is created by the system, and a pointer to the registry entry. The 
Registry is a small database which contains information about the installed 
services and hardware configuration. For the DT2851 driver, the registry 
contains the base port and memory address for the image processing card. These 
fields can be configured using NT's registry editor, and are based on the card's 
jumper settings. If for some reason the configuration could not be found in the 
registry, the driver is set up to use default values for the base port and 
memory addresses. 
<P><PRE><B>
if (!NT_SUCCESS(RtlQueryRegistryValues(
                         RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
                         paramPath.Buffer, 
                         &para;mTable[0], 
                         NULL,                    
                         NULL)))
{
    physicalPortAddress32 = defaultportBase;
    physicalMemoryAddress32 = defaultphysicalMemoryAddress32;
}
</B></PRE>
<P>NT's protected subsystem insulate user applications from having to know 
anything about kernel mode components. NT's I/O manager works in a similar 
fashion, where the I/O manager insulates the protected subsystems from having to 
know anything about machine specific device configurations, or about the drivers 
implementation. It is for this reason the driver must set itself up to handle 
the calls from the I/O manager. Depending on the type of interaction that the 
driver is intended to have with the system and with other drivers, determines 
what type of I/O requests the driver must support. Since the DT2851 device 
driver is relatively simple, the driver only needs to support opening and 
closing of a device object, read and write I/O requests to the port and memory 
mapped interface, and dynamic unloading to free the system resources when the 
driver is stopped. In order to provide this functionality the DriverEntry 
routine is responsible for setting up a function table to handle supported I/O 
interaction. 
<P><PRE><B>
driverObject-&gt;MajorFunction[IRP_MJ_CREATE] = DT2851Dispatch;
driverObject-&gt;MajorFunction[IRP_MJ_CLOSE]  = DT2851Dispatch;
driverObject-&gt;MajorFunction[IRP_MJ_DEVICE_CONTROL] = DT2851Dispatch;
driverObject-&gt;DriverUnload	= DT2851Unload;
</B></PRE>
<P>The Driver Entry routine must also create a device object, which represents a 
physical, logical or virtual device being loaded into the system. A call is made 
to IoCreateDevice to allocate memory and initialize the object. The device 
object also has a device extension that provides the driver with space to store 
non-pageable information needing to be accessed outside the Driver Entry 
routine. The DT2851's device extension is used to store the base address of the 
port and mapped memory interface. 
<P><PRE><B>
IoCreateDevice (driverObject, 
                sizeof(DT2851_EXTENSION),
                &amp;deviceNameUnicodeString,
                DT2851_TYPE,
                0,
                TRUE,
                &amp;deviceObject);
</B></PRE>
<P>After creating the device object, the driver now needs to map the port, and 
memory mapped interface to physical address space. A call is made to 
HalTranslateBusAddress, converting these base physical addresses to a virtual 
addresses in system space. On the Intel architecture, where the port interface 
is separate from the memory address space, HalTranslateBusAddress is the only 
call that needs to be made to map a port address into physical space. 
<P><PRE><B>
HalTranslateBusAddress ( Isa,                // device on ISA bus
                         0,                  //  bus number 0
                         physicalAddress64,  // physical address
                         &amp;memType,           // address space
                         &amp;mappedAddress64);  // translated address         
</B></PRE>
<P>For the memory mapped interface; however, the translated system address is 
then used in the call to MmMapIoSpace, which maps a range of addresses into 
system space. 
<P><PRE><B>	
MmMapIoSpace ( mappedAddress64,
               addressSpace,
               FALSE);        // don't cache
</B></PRE>
<P>After preserving the translated base port and memory addresses in the driver 
extension, the Driver Entry routine is complete. The routine allocated a driver 
object, set up the required dispatch function tables, and mapped the physical 
addresses of the port and memory mapped interface into system address space. 
<HR>

<H2>Driver Dispatch</H2>The DriverDispatch routine is called by the I/O manager 
with a requested operation. It is this routine's responsibility to service the 
I/O request packet, by either processing the IRP itself or by calling the 
appropriate routine to handle the operation. 
<P><PRE><B>
DT2851Dispatch( IN    PDEVICE_OBJECT pDeviceObject,
                IN    PIRP pIORequestPacket );
</B></PRE>
<P>When the I/O manager calls a driver dispatch routine, it uses the function 
table set up in the driver entry routine. The I/O manager also passes a pointer 
to the current I/O request packet (IRP), which is a data structure passed to 
device drivers. This structure is created by the I/O manager, or subsystem that 
is responsible for high level I/O. The dispatch routine must then locate the 
current IRP stack frame, with a call to IoGetCurrentIrpStackLocation. 
<P><PRE><B>	
pIORequestPacket = IoGetCurrentIrpStackLocation(pIORequestPacket);
</B></PRE>
<P>In general the a device driver consists of several layers, where the driver 
must be aware of the bracketed layers, continually setting up the stack location 
for the next driver layer. Once the dispatch routine has access to the current 
IRP stack location, the driver must determine what operation is being requested. 
The DT2851Dispatch routine simply switches on 
pIORequestPacketStack-&gt;MajorFunction. 
<P><PRE><B>	
switch (pIORequestPacketStack-&gt;MajorFunction)
{
    case IRP_MJ_CREATE:
    case IRP_MJ_CLOSE:
    case IRP_MJ_DEVICE_CONTROL: //  Dispatch on IOCTL
        switch (pIORequestPacketStack
                -&gt;Parameters.DeviceIoControl.IoControlCode)
        {
            case IOCTL_DT2851_READ_PORT:
            case IOCTL_DT2851_WRITE_PORT:
            case IOCTL_DT2851_READ_MEMORY:
            case IOCTL_DT2851_WRITE_MEMORY:
            case IOCTL_DT2851_FILL_MEMORY:
        }
}
</B></PRE>
<P>The IRP_MJ_CREATE and IRP_MJ_CLOSE cases do nothing special in the 
DT2851Dispatch routine. Upon decoding these requests the dispatch routine simply 
return SUCCESS. The major responsibility of the dispatch routine is to handle 
the case of IRP_MJ_DEVICE_CONTROL. Upon receiving this request, the driver must 
then determine what type of I/O request to process. The type of I/O request is 
based on the driver defined IOCTL operations. The driver then calls the 
appropriate function to process the IOCTL request, and control returns to the 
user process. 
<P>Separate routines have been written to handle the supported IOCTL requests. 
Each receive a pointer to the DT2851's device extension, a pointer to the 
current I/O request packet, and a pointer to the IRP stack. By accessing the 
AssociatedIrp.SystemBuffer member of the IRP structure, the kernel mode driver 
has access to copies of the user supplied I/O buffers. 
<P><PRE><B>	
DT2851ReadPort( IN  PDT2851_EXTENSION pLDI,
                IN  PIRP pIORequestPacket,
                IN  PIO_STACK_LOCATION pIrpStack );


DT2851WritePort( IN  PDT2851_EXTENSION pLDI,
                 IN  PIRP pIORequestPacket,
                 IN  PIO_STACK_LOCATION pIrpStack );


DT2851ReadMemory( IN  PDT2851_EXTENSION pLDI,
                  IN  PIRP pIORequestPacket,
                  IN  PIO_STACK_LOCATION pIrpStack );


DT2851WriteMemory( IN  PDT2851_EXTENSION pLDI,
                   IN  PIRP pIORequestPacket,
                   IN  PIO_STACK_LOCATION pIrpStack );


DT2851FillMemory( IN  PDT2851_EXTENSION pLDI,
                  IN  PIRP pIORequestPacket,
                  IN  PIO_STACK_LOCATION pIrpStack );
</B></PRE>
<P>The I/O manager supports both buffered and direct I/O operations between a 
user process and device driver. Using Buffered I/O, the driver reads and writes 
to an address space allocated by the I/O manager, rather than directly to the 
buffer supplied to the driver by the user mode process. The main advantage that 
buffered I/O has over direct I/O is that in NT, there is no guarantee that an 
I/O request will complete while the user process is still in context. Buffering 
the I/O ensures that the device driver has access to information regardless of 
process context. The system allocated buffers are automatically locked down, and 
are available to the driver for the duration of the driver entry routine. Before 
entering the driver dispatch routine, the I/O manager copies the user supplied 
input buffer into a system allocated buffer, and after servicing the driver 
dispatch routine, the I/O manager copies the system output buffer into the 
supplied user buffer. 
<P>Reading and writing to the port using buffered I/O works well. The buffers 
are small, so the overhead of buffering the I/O is negligible. However, the 
mapped memory interface uses a 256 Kbytes buffer to transfer information between 
the user mode process and the driver. Although not unreasonable to replicate a 
buffer of this size in system space, the driver can be written to avoid the 
extra copying. The memory mapped interface still uses buffered I/O, however the 
buffer supplied to the driver dispatch routine contains a pointer to the 
user-supplied video image buffer. Because this driver is not layered, the user 
supplied buffer is guaranteed not to switch out of context. The only danger that 
exists is the chance that the user-supplied buffer is invalid. To eliminate the 
possibility of the kernel mode process from accessing an illegal memory address, 
a call to MmProbeAndLockPages is made. This call verifies the integrity of the 
supplied buffer, and also locks the pages down. Layers could be added to the 
driver, without worrying about process context switching. 
<P><PRE><B>
MmProbeAndLockPages( IN memoryDescriptorList,
                     IN accessMode,
                     IN operation);
</B></PRE>
<P>The driver must call MmUlockPages before returning control to the user 
process. 
<P><PRE><B>
MmProbeAndLockPages(IN memoryDescriptorList);
</B></PRE>
<P>
<HR>

<H2>Driver Unload</H2>Every driver that has registry configurable entries, or 
that can be stopped once started, needs to have an unload routine. This routine 
is responsible for deallocating any driver allocated resources, and deleting the 
device object. The DT2851Unload routine un-maps the memory mapped interface from 
system space by calling MmUnmapIoSpcae. 
<P><PRE><B>
MmUnmapIoSpace(extension-&gt;baseAddress, MEMORY_SIZE);
</B></PRE>
<P>The unload routine then deletes the device object. With all resources 
un-mapped, and the device object destroyed, the I/O manager can then delete the 
driver object without leaving dangling resources. </P></BODY></HTML>

⌨️ 快捷键说明

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