34、I/O端口操作

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

一、I/O端口操作实现 

1DDK实现I/O端口操作

READ_PORT_UCHAR

The READ_PORT_UCHAR macro reads a byte from the specified port address

http://msdn.microsoft.com/en-us/library/ff560797%28VS.85%29.aspx

2、工具软件WinIO

第三方库。5个文件。

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

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

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

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

WinIO.VXD9598等相关。 

代码
 
    
#include < Windows.h >
#include
< stdio.h >

#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个端口操作函数

 

代码
 
    
// 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(\
FILE_DEVICE_UNKNOWN, \
0x801 , \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)


#endif

// .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 < windows.h >
#include
< stdio.h >

#include
" function.h "

// DWORD ReadPort(HANDLE hDevice,DWORD port)
// {
// DWORD dwOutput;
// DWORD dwRead;
// DeviceIoControl(hDevice, IOCTL_READ_PORT_ULONG, &port, 4, &dwOutput, 4, &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, &port, 8, NULL, 0, &dwWrite, NULL);
// }
// VOID TestDriver(HANDLE hDevice)
// {
// DWORD dwOutput;
// DeviceIoControl(hDevice, IOCTL_TEST, NULL, 0, NULL, 0, &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 -> Parameters.DeviceIoControl.InputBufferLength;
// 得到输出缓冲区大小
ULONG cbout = stack -> Parameters.DeviceIoControl.OutputBufferLength;
// 得到IOCTL码
ULONG code = stack -> Parameters.DeviceIoControl.IoControlCode;

ULONG info
= 0 ;

switch (code)
{
// process request
case READ_PORT:
{
KdPrint((
" READ_PORT\n " ));
// 缓冲区方式IOCTL
// 显示输入缓冲区数据
PULONG InputBuffer = (PULONG)pIrp -> AssociatedIrp.SystemBuffer;
ULONG port
= (ULONG)( * InputBuffer);
InputBuffer
++ ;
UCHAR method
= (UCHAR)( * InputBuffer);

// 操作输出缓冲区
PULONG OutputBuffer = (PULONG)pIrp -> 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 " ));
// 缓冲区方式IOCTL
// 显示输入缓冲区数据
PULONG InputBuffer = (PULONG)pIrp -> AssociatedIrp.SystemBuffer;
ULONG port
= (ULONG)( * InputBuffer);
InputBuffer
++ ;
UCHAR method
= (UCHAR)( * InputBuffer);
InputBuffer
++ ;
ULONG value
= (ULONG)( * InputBuffer);

// 操作输出缓冲区
PULONG OutputBuffer = (PULONG)pIrp -> AssociatedIrp.SystemBuffer;

if (method == 1 ) // 8位操作
{
WRITE_PORT_UCHAR((PUCHAR)port,(UCHAR)value);
}
else if (method == 2 ) // 16位操作
{
WRITE_PORT_USHORT((PUSHORT)port,(USHORT)value);
}
else if (method == 4 ) // 32位操作
{
WRITE_PORT_ULONG((PULONG)port,(ULONG)value);
}

// 设置实际操作输出缓冲区长度
info = 0 ;
break ;
}


default :
status
= STATUS_INVALID_VARIANT;
}

// 完成IRP
pIrp -> IoStatus.Status = status;
pIrp
-> IoStatus.Information = info; // bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );

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

return status;
}

// main.cpp
#include < windows.h >
#include
< stdio.h >
// 使用CTL_CODE必须加入winioctl.h
#include < winioctl.h >
#include
" ..\NT_Driver\Ioctls.h "

int main()
{
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 , & dwOutput, NULL);

CloseHandle(hDevice);

return 0 ;
}

示例代码 P394

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

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

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

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

并口设备的操作

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

参考:

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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值