zoukankan      html  css  js  c++  java
  • 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 驱动程序开发技术详解,张帆

     

  • 相关阅读:
    渲染你刚刚上传的图片,再进行二次上传
    详情页需要显示图片
    上传图片
    毛利率保留俩位小数
    去除input的前后的空格
    vue下载模板、导出excle
    如何从一个对象里面拿数据
    登录注册
    ajax发送请求的数据类型
    WampServer修改MySQL密码
  • 原文地址:https://www.cnblogs.com/mydomain/p/1897316.html
Copyright © 2011-2022 走看看