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