天天看点

34、I/O端口操作

    I/O端口操作在Windows操作系统中属于特权命令,必须在内核模式下运行。在DOS中,I/O端口操作主要通过IN/OUT指令来进行。 

一、I/O端口操作实现 

1、DDK实现I/O端口操作

READ_PORT_UCHAR

The READ_PORT_UCHAR macro reads a byte from the specified port address。

<a href="http://msdn.microsoft.com/en-us/library/ff560797%28VS.85%29.aspx">http://msdn.microsoft.com/en-us/library/ff560797%28VS.85%29.aspx</a>

2、工具软件WinIO

第三方库。5个文件。

WinIO.dll 封装了驱动程序调用函数。

WinIO.lib 用来与应用程序链接编译。

WinIO.h 提供了封装函数的声明。

使用时必须把WinIO.sys和应用程序放在同一个目录。

WinIO.VXD与95,98等相关。 

34、I/O端口操作
34、I/O端口操作

代码

#include &lt;Windows.h&gt;

#include &lt;stdio.h&gt;

#include ".\winiolib\WinIo.h"

int main()

{

//打开WinIO驱动

bool bRet = InitializeWinIo();

if (bRet)

printf("Load Dirver successfully!\n");

//对0x378端口进行输出操作,8位操作

SetPortVal(0x378,0,1);

//关闭WinIO驱动

ShutdownWinIo();

}

return 0;

示例代码 P391

3、端口操作实现

法一:利用DDK提供的6个端口操作函数

34、I/O端口操作
34、I/O端口操作

// IOCTLS.H -- IOCTL code definitions for fileio driver

// Copyright (C) 1999 by Walter Oney

// All rights reserved

#ifndef IOCTLS_H

#define IOCTLS_H

#ifndef CTL_CODE

#pragma message("CTL_CODE undefined. Include winioctl.h or wdm.h")

#endif

#define READ_PORT CTL_CODE(\

FILE_DEVICE_UNKNOWN, \

0x800, \

METHOD_BUFFERED, \

FILE_ANY_ACCESS)

#define WRITE_PORT CTL_CODE(\

0x801, \

//.h

typedef struct _DEVICE_EXTENSION {

PDEVICE_OBJECT pDevice;

UNICODE_STRING ustrDeviceName; //设备名称

UNICODE_STRING ustrSymLinkName; //符号链接名

PUCHAR buffer;//缓冲区

ULONG file_length;//模拟的文件长度,必须小于MAX_FILE_LENGTH

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

// function.cpp

#include &lt;windows.h&gt;

#include "function.h"

// DWORD ReadPort(HANDLE hDevice,DWORD port)

// {

// DWORD dwOutput;

// DWORD dwRead;

// DeviceIoControl(hDevice, IOCTL_READ_PORT_ULONG, &amp;port, 4, &amp;dwOutput, 4, &amp;dwRead, NULL);

// return dwOutput;

// }

// VOID WritePort(HANDLE hDevice,DWORD port,DWORD value)

// PVOID buffer[2];

// buffer[0] = (PVOID)port;

// buffer[1] = (PVOID)value;

// DWORD dwWrite;

// DeviceIoControl(hDevice, IOCTL_WRITE_PORT_ULONG, &amp;port, 8, NULL, 0, &amp;dwWrite, NULL);

// VOID TestDriver(HANDLE hDevice)

// DeviceIoControl(hDevice, IOCTL_TEST, NULL, 0, NULL, 0, &amp;dwOutput, NULL);

//driver.cpp

#pragma PAGEDCODE

NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,

IN PIRP pIrp)

NTSTATUS status = STATUS_SUCCESS;

KdPrint(("Enter HelloDDKDeviceIOControl\n"));

//得到当前堆栈

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);

//得到输入缓冲区大小

ULONG cbin = stack-&gt;Parameters.DeviceIoControl.InputBufferLength;

//得到输出缓冲区大小

ULONG cbout = stack-&gt;Parameters.DeviceIoControl.OutputBufferLength;

//得到IOCTL码

ULONG code = stack-&gt;Parameters.DeviceIoControl.IoControlCode;

ULONG info = 0;

switch (code)

{ // process request

case READ_PORT:

KdPrint(("READ_PORT\n"));

//缓冲区方式IOCTL

//显示输入缓冲区数据

PULONG InputBuffer = (PULONG)pIrp-&gt;AssociatedIrp.SystemBuffer;

ULONG port = (ULONG)(*InputBuffer);

InputBuffer++;

UCHAR method = (UCHAR)(*InputBuffer);

//操作输出缓冲区

PULONG OutputBuffer = (PULONG)pIrp-&gt;AssociatedIrp.SystemBuffer;

if (method==1)//8位操作

*OutputBuffer = READ_PORT_UCHAR((PUCHAR)port);

}else if(method==2)//16位操作

*OutputBuffer = READ_PORT_USHORT((PUSHORT)port);

}else if(method==4)//32位操作

*OutputBuffer = READ_PORT_ULONG((PULONG)port);

//设置实际操作输出缓冲区长度

info = 4;

break;

case WRITE_PORT:

KdPrint(("WRITE_PORT\n"));

ULONG value = (ULONG)(*InputBuffer);

WRITE_PORT_UCHAR((PUCHAR)port,(UCHAR)value);

WRITE_PORT_USHORT((PUSHORT)port,(USHORT)value);

WRITE_PORT_ULONG((PULONG)port,(ULONG)value);

info = 0;

default:

status = STATUS_INVALID_VARIANT;

// 完成IRP

pIrp-&gt;IoStatus.Status = status;

pIrp-&gt;IoStatus.Information = info; // bytes xfered

IoCompleteRequest( pIrp, IO_NO_INCREMENT );

KdPrint(("Leave HelloDDKDeviceIOControl\n"));

return status;

//main.cpp

//使用CTL_CODE必须加入winioctl.h

#include &lt;winioctl.h&gt;

#include "..\NT_Driver\Ioctls.h"

HANDLE hDevice =

CreateFile("\\\\.\\HelloDDK",

GENERIC_READ | GENERIC_WRITE,

0, // share mode none

NULL, // no security

OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL,

NULL ); // no template

if (hDevice == INVALID_HANDLE_VALUE)

printf("Failed to obtain file handle to device: "

"%s with Win32 error code: %d\n",

"MyWDMDevice", GetLastError() );

return 1;

DWORD dwOutput ;

DWORD inputBuffer[3] =

0x378,//对0x378进行操作

1,//1代表8位操作,2代表16位操作,4代表32位操作

0//输出字节0

};

//类似于Out_8((PUCHAR)0x378,0);

DeviceIoControl(hDevice, WRITE_PORT, inputBuffer, sizeof(inputBuffer), NULL, 0, &amp;dwOutput, NULL);

CloseHandle(hDevice);

示例代码 P394

[1] 中还提供了一些其它方法

提升用户模式的方法是将应用程序的一个函数指针传递给驱动程序,在驱动程序接收到这个函数指针后,在内核模式下执行此函数。

I/O 允许位图设置可以让不具备足够权限的程序存取I/O端口。I/O允许位图设置是利用一个位代表每个I/O地址。

每个PC系统至少包含一个8253可编程时钟或等价芯片,这个时钟包含三个独立的16位时钟。时钟0用于基本系统时钟,时钟1用于PC系统上的DRAM刷新,时钟2用于一般的应用程序,如扬声器音调控制。

并口设备的操作

操作PC上的并口设备,主要也是设置和读取并口设备对应的I/O端口。数据、状态、控制寄存器。进一步的介绍可以参见[1]。

参考:

[1] Windows 驱动程序开发技术详解,张帆

继续阅读