实战DeviceIoControl 之六:访问物理端口[4]

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 bhw98 的 blog

te readportbyte(word port) { dword buf[2]; // 输入输出缓冲区 dword dwoutbytes; // ioctl输出数据长度 buf[0] = port; // 第一个dword是端口 // buf[1] = 0; // 第二个dword是数据 // 用ioctl_myport_read_byte读端口 ::deviceiocontrol(hmyport, // 设备句柄 ioctl_myport_read_byte, // 取设备属性信息 buf, sizeof(buf), // 输入数据缓冲区 buf, sizeof(buf), // 输出数据缓冲区 &dwoutbytes, // 输出数据长度 (lpoverlapped)null); // 用同步i/o return (byte)buf[1]; } // 将一个字节写到指定端口 // port: 端口 // data: 字节数据 void writeportbyte(word port, byte data) { dword buf[2]; // 输入输出缓冲区 dword dwoutbytes; // ioctl输出数据长度 buf[0] = port; // 第一个dword是端口 buf[1] = data; // 第二个dword是数据 // 用ioctl_myport_write_byte写端口 ::deviceiocontrol(hmyport, // 设备句柄 ioctl_myport_write_byte, // 取设备属性信息 buf, sizeof(buf), // 输入数据缓冲区 buf, sizeof(buf), // 输出数据缓冲区 &dwoutbytes, // 输出数据长度 (lpoverlapped)null); // 用同步i/o }

有了readportbyte和writeportbyte这两个函数,我们就能很容易地操纵cmos和speaker了(关于cmos值的含义以及定时器寄存器定义,请参考相应的硬件资料):

// 0x70是cmos索引端口(只写)
// 0x71是cmos数据端口
byte readcmos(byte index)
{
    byte data;
  
    ::writeportbyte(0x70, index);
  
    data = ::readportbyte(0x71);
  
    return data;
}
  
// 0x61是speaker控制端口
// 0x43是8253/8254定时器控制端口
// 0x42是8253/8254定时器通道2的端口
void sound(dword freq)
{
    byte data;
    if ((freq >= 20) && (freq <= 20000))
    {
        freq = 1193181 / freq;
  
        data = ::readportbyte(0x61);
  
        if ((data & 3) == 0)
        {
            ::writeportbyte(0x61, data | 3);
            ::writeportbyte(0x43, 0xb6);
        }
  
        ::writeportbyte(0x42, (byte)(freq % 256));
        ::writeportbyte(0x42, (byte)(freq / 256));
    }
}
  
void nosound(void)
{
    byte data;
    data = ::readportbyte(0x61);
    ::writeportbyte(0x61, data & 0xfc);
}

    // 以下读出cmos 128个字节
    for (int i = 0; i < 128; i++)
    {
        byte data = ::readcmos(i);
        ... ...
    }

    // 以下用c调演奏“多-来-米”
  
    // 1 = 262 hz
    ::sound(262);
    ::sleep(200);
    ::nosound();
  
    // 2 = 288 hz
    ::sound(288);
    ::sleep(200);
    ::nosound();
  
    // 3 = 320 hz
    ::sound(320);
    ::sleep(200);
    ::nosound();

q 就是个简单的端口i/o,这么麻烦才能实现,搞得俺头脑稀昏,有没有简洁明了的办法啊?

a 上面的例子,之所以从编写驱动程序,到安装驱动,到启动服务,到打开设备,到访问设备,一直到读写端口,这样一路下来,是为了揭示在nt/2000/xp中硬件访问技术的本质。假如将所有过程封装起来,只提供openmyport, closemyport, readportbyte, writeportbyte甚至更高层的readcmos、writecmos、sound、nosound给你调用,是不是会感觉清爽许多?

实际上,我们平常做的基于一定硬件的二次开发,一般会先安装驱动程序(drv)和用户接口的运行库(dll),然后在此基础上开发出我们的应用程序(app)。drv、dll、app三者分别运行在核心态、核心态/用户态联络带、用户态。比如买了一块图象采集卡,要先安装核心驱动,它的“development tool kit”,提供类似于pcv_initializ

本文关键:DeviceIoControl,物理端口,设备驱动程序,IOPM,CMOS,speaker
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top