📄 ch365dos.c
字号:
/* 2003.09.10
****************************************
** Copyright (C) W.ch 1999-2003 **
** Web: http://www.winchiphead.com **
****************************************
** DOS for PCI interface chip CH365 **
** C, TC2.0 **
****************************************
PCI总线接口芯片CH365的DOS接口库 V1.1
南京沁恒电子有限公司 作者: W.ch 2003.09
CH365-DOS V1.1 , Support: IO/MEM/INT
运行环境: DOS
*/
#include <dos.h>
#include <stddef.h>
#include "CH365DOS.H"
USHORT dosCH365PciAddr = 0; /* CH365的PCI地址,即总线/设备/功能号 */
mPCH365_IO_REG dosIoBaseAddr = NULL; /* CH365输入输出端口基址 */
ULONG dosMemBaseAddr = NULL; /* CH365存储器基址,线性地址 */
USHORT dosIntLine = 0; /* CH365中断号 */
PINTERRUPT_ROUTINE dosOldInterrupt = NULL; /* 保存原中断向量 */
USHORT CH365CheckDevice( ) /* 检测CH365设备,检测到CH365则返回其PCI地址,即总线/设备/功能号,出错则返回0 */
{
/* UCHAR mByte; */
X86REG mReg;
mReg.x.ax = 0xb102;
mReg.x.cx = 0x5049; /* 设备ID */
mReg.x.dx = 0x4348; /* 厂商ID */
mReg.x.si = 0; /* 搜索第一个 */
int86 ( 0x1a, &mReg, &mReg ); /* 调用PCI的BIOS */
if ( mReg.h.ah == 0 ) { /* 调用成功 */
dosCH365PciAddr = mReg.x.bx; /* 检测到CH365 */
/* 通过读取配置空间的芯片版本号,识别芯片是CH361或者CH365
mByte = CH365ReadCfgByte( mOFFSET( mPCI_CONFIG, mPcRevisionId ) );
if ( mByte == 0 ) 版本为0则是CH361;
else if ( mByte == 0x10 ) 版本为10则是CH365;
*/
return( mReg.x.bx ); /* 返回PCI地址 */
}
else return( 0 ); /* 没有检测到CH365 */
}
UCHAR CH365ReadCfgByte( /* 从配置空间读取一个字节数据,返回读取的字节数据 */
USHORT iOffset ) /* 指定偏移地址 */
{
X86REG mReg;
mReg.x.bx = dosCH365PciAddr;
mReg.x.ax = 0xb108;
mReg.x.di = iOffset;
int86 ( 0x1a, &mReg, &mReg ); /* 调用PCI的BIOS */
return( mReg.h.cl ); /* 返回数据 */
}
VOID CH365WriteCfgByte( /* 向配置空间写入一个字节数据 */
USHORT iOffset, /* 指定偏移地址 */
UCHAR iByte ) /* 待写入的字节数据 */
{
X86REG mReg;
mReg.x.bx = dosCH365PciAddr;
mReg.x.ax = 0xb10b;
mReg.x.di = iOffset;
mReg.h.cl = iByte;
int86 ( 0x1a, &mReg, &mReg ); /* 调用PCI的BIOS */
}
USHORT CH365ReadCfgWord( /* 从配置空间读取一个字数据,返回读取的字数据 */
USHORT iOffset ) /* 指定偏移地址 */
{
X86REG mReg;
mReg.x.bx = dosCH365PciAddr;
mReg.x.ax = 0xb109;
mReg.x.di = iOffset;
int86 ( 0x1a, &mReg, &mReg ); /* 调用PCI的BIOS */
return( mReg.x.cx ); /* 返回数据 */
}
VOID CH365WriteCfgWord( /* 向配置空间写入一个字数据 */
USHORT iOffset, /* 指定偏移地址 */
USHORT iWord ) /* 待写入的字数据 */
{
X86REG mReg;
mReg.x.bx = dosCH365PciAddr;
mReg.x.ax = 0xb10c;
mReg.x.di = iOffset;
mReg.x.cx = iWord;
int86 ( 0x1a, &mReg, &mReg ); /* 调用PCI的BIOS */
}
mPCH365_IO_REG CH365GetIoBaseAddr( ) /* 获取I/O端口的基址,返回I/O端口基址 */
{
USHORT mWord;
mWord = CH365ReadCfgWord( mOFFSET( mPCI_CONFIG, mPcBaseAddr0 ) ); /* 读取配置空间 */
dosIoBaseAddr = (mPCH365_IO_REG) ( mWord & 0xfffe );
return( dosIoBaseAddr ); /* 返回数据 */
}
BOOL CH365SetIoBaseAddr( /* 设定I/O端口的基址 */
mPCH365_IO_REG iIoBaseAddr ) /* 指定I/O端口基址 */
{
CH365WriteCfgWord( mOFFSET( mPCI_CONFIG, mPcBaseAddr0 ), (USHORT)iIoBaseAddr ); /* 写入配置空间 */
if ( CH365GetIoBaseAddr( ) == iIoBaseAddr ) return( TRUE ); /* 重读后比较正确 */
else return( FALSE );
}
ULONG CH365GetMemBaseAddr( ) /* 获取存储器的基址,返回存储器基址 */
{
USHORT mWord;
ULONG mDword;
mDword = CH365ReadCfgWord( mOFFSET( mPCI_CONFIG, mPcBaseAddr1 ) ); /* 读取配置空间 */
mWord = CH365ReadCfgWord( mOFFSET( mPCI_CONFIG, mPcBaseAddr1 ) + sizeof( USHORT ) ); /* 读取配置空间 */
mDword |= (ULONG)mWord << 16;
dosMemBaseAddr = mDword & 0xfffffff0;
return( dosMemBaseAddr ); /* 返回数据 */
}
BOOL CH365SetMemBaseAddr( /* 设定存储器的基址 */
ULONG iMemBaseAddr ) /* 指定存储器基址,为0则关闭存储器,为-1则自动设定 */
{
USHORT mSeg, i;
USHORT far *mpWord;
if ( iMemBaseAddr == 0 ) { /* 基址为0则关闭存储器 */
dosMemBaseAddr = 0; /* 清除映射地址 */
CH365WriteCfgWord( mOFFSET( mPCI_CONFIG, mPcBaseAddr1 ), 0 ); /* 写入配置空间 */
CH365WriteCfgWord( mOFFSET( mPCI_CONFIG, mPcBaseAddr1 ) + sizeof( USHORT ), 0 ); /* 写入配置空间 */
return( TRUE );
}
else if ( iMemBaseAddr == mCH365_MEM_BASE_AUTO ) { /* 基址为特殊值则自动设置存储器基址 */
for ( mSeg = 0xd000; mSeg < 0xe000; mSeg += 0x0800 ) { /* 扩展ROM基址/存储器物理地址 */
mpWord = MK_FP( mSeg, 0 );
for ( i = 0; i < 0x8000 / sizeof( USHORT ); ++i, ++mpWord ) /* 检查地址 */
if ( *mpWord != 0xffff ) break; /* 检查当前物理内存地址是否已经被占用 */
if ( i >= 0x8000 / sizeof( USHORT ) ) break; /* 找到一块未被占用的物理内存地址 */
}
if ( mSeg < 0xe000 ) dosMemBaseAddr = (ULONG)mSeg << 4; /* 物理内存地址空闲,将段地址转换为线性地址 */
else { /* 没有找到空闲的物理内存地址 */
dosMemBaseAddr = 0;
return( FALSE ); /* 操作失败 */
}
}
else dosMemBaseAddr = iMemBaseAddr; /* 指定存储器基址 */
dosMemBaseAddr++; /* 使能ROM空间 */
CH365WriteCfgWord( mOFFSET( mPCI_CONFIG, mPcBaseAddr1 ) + sizeof( USHORT ), (USHORT)( dosMemBaseAddr >> 16 ) ); /* 写入配置空间 */
CH365WriteCfgWord( mOFFSET( mPCI_CONFIG, mPcBaseAddr1 ), (USHORT)dosMemBaseAddr ); /* 写入配置空间 */
dosMemBaseAddr--;
if ( dosMemBaseAddr == CH365GetMemBaseAddr( ) ) return( TRUE ); /* 重读后比较正确 */
else return( FALSE );
}
USHORT CH365GetIntLine( ) /* 获取中断号,返回中断号,为0则无效 */
{
UCHAR mByte;
mByte = CH365ReadCfgByte( mOFFSET( mPCI_CONFIG, mPcInterPin ) ); /* 读取配置空间 */
if ( mByte == 0 ) return( 0 ); /* 中断功能未启用 */
dosIntLine = CH365ReadCfgByte( mOFFSET( mPCI_CONFIG, mPcInterLine ) ); /* 读取配置空间 */
return( dosIntLine );
}
BOOL CH365SetIntLine( /* 设定中断号 */
USHORT iIntLine ) /* 指定中断号,为0则关闭中断,为-1则自动检测并设定 */
{
UCHAR mIntMask;
USHORT mIntPort;
X86REG mReg;
X86SREG mSegReg;
if ( iIntLine == 0 ) { /* 中断号为0则关闭中断 */
if ( dosIntLine && dosOldInterrupt ) { /* 中断已被连接 */
setvect( mHARDWARE_INTERRUPT( dosIntLine ), dosOldInterrupt ); /* 解除中断,恢复原中断向量 */
dosIntLine = 0; /* 清除中断号 */
dosOldInterrupt = NULL;
}
return( TRUE );
}
else if ( iIntLine == mCH365_INT_LINE_AUTO ) { /* 中断号为特殊值则自动设置中断号 */
dosIntLine = CH365GetIntLine( ); /* 获取中断号 */
if ( dosIntLine == 0 ) return( FALSE ); /* 返回操作失败信息 */
}
else { /* 指定中断号 */
mSegReg.ds = 0xf000;
mReg.x.bx = dosCH365PciAddr;
mReg.x.ax = 0xb10f; /* 设定硬件中断IRQ */
mReg.h.cl = 0x0a; /* INTA */
mReg.h.ch = iIntLine; /* 指定的新中断号,数值可以是0至15 */
int86x ( 0x1a, &mReg, &mReg, &mSegReg ); /* 调用PCI的BIOS */
if ( mReg.h.ah == 0 ) { /* 调用成功 */
CH365WriteCfgByte( mOFFSET( mPCI_CONFIG, mPcInterLine ), iIntLine ); /* 写入配置空间 */
dosIntLine = iIntLine; /* 指定中断号 */
}
else return( FALSE ); /* 操作失败 */
}
/* 以下程序设置8259的中断允许位 */
mIntPort = dosIntLine < 8 ? 0x21 : 0xa1; /* 中断屏蔽设置端口 */
mIntMask = inportb( mIntPort ); /* 保存原中断屏蔽字节 */
outportb( mIntPort, mIntMask & ~ ( 0x01 << ( dosIntLine & 0x07 ) ) ); /* 允许中断 */
dosOldInterrupt = getvect( mHARDWARE_INTERRUPT( dosIntLine ) ); /* 保存原中断向量 */
return( TRUE );
}
BOOL CH365SetIntRoutine( /* 设定中断服务程序 */
PINTERRUPT_ROUTINE iIntRoutine ) /* 指定中断服务程序,为NULL则取消中断服务,否则在中断时调用该程序 */
{
UCHAR mIntMask;
USHORT mIntPort;
if ( iIntRoutine ) { /* 设定中断服务程序 */
if ( dosIntLine == 0 ) if ( CH365SetIntLine( mCH365_MEM_BASE_AUTO ) == FALSE ) return( FALSE ); /* 尚未检测中断号则自动检测,失败则返回 */
if ( dosOldInterrupt == NULL ) getvect( mHARDWARE_INTERRUPT( dosIntLine ) ); /* 保存原中断向量 */
setvect( mHARDWARE_INTERRUPT( dosIntLine ), iIntRoutine ); /* 设定新的中断向量 */
mIntPort = dosIntLine < 8 ? 0x21 : 0xa1; /* 中断屏蔽设置端口 */
mIntMask = inportb( mIntPort ); /* 保存原中断屏蔽字节 */
outportb( mIntPort, mIntMask & ~ ( 0x01 << ( dosIntLine & 0x07 ) ) ); /* 允许中断 */
return( TRUE );
}
else { /* 取消中断服务程序 */
if ( dosIntLine && dosOldInterrupt ) { /* 中断已被连接 */
setvect( mHARDWARE_INTERRUPT( dosIntLine ), dosOldInterrupt ); /* 解除中断,恢复原中断向量 */
dosIntLine = 0; /* 清除中断号 */
dosOldInterrupt = NULL;
}
return( TRUE );
}
}
UCHAR CH365ReadI2C( /* 从I2C接口读取一个字节数据,返回读取的字节数据 */
UCHAR iDevice, /* 低7位指定I2C设备地址 */
UCHAR iAddr ) /* 指定数据单元的地址 */
{
UCHAR mByte;
int i;
outportb( (USHORT) & dosIoBaseAddr -> mCh365I2cDev, iDevice << 1 | 0x01 ); /* 设备地址和命令 */
outportb( (USHORT) & dosIoBaseAddr -> mCh365I2cAddr, iAddr ); /* 设定地址 */
mByte = inportb( (USHORT) & dosIoBaseAddr -> mCh365I2cCtrl ); /* 读取控制和状态 */
mByte |= 0x01; /* 位0置1则启动操作 */
outportb( (USHORT) & dosIoBaseAddr -> mCh365I2cCtrl, mByte ); /* 开始读操作 */
while( mByte & 0x01 ) mByte = inportb( (USHORT) & dosIoBaseAddr -> mCh365I2cCtrl ); /* 等待读操作完成 */
mByte = inportb( (USHORT) & dosIoBaseAddr -> mCh365I2cData ); /* 读取I2C读操作的结果 */
CH365DelayUS( 4 ); /* 延时4uS作为两次I2C操作的间隔 */
return( mByte ); /* 返回读取的数据 */
}
VOID CH365WriteI2C( /* 向I2C接口写入一个字节数据 */
UCHAR iDevice, /* 低7位指定I2C设备地址 */
UCHAR iAddr, /* 指定数据单元的地址 */
UCHAR iByte ) /* 待写入的字节数据 */
{
UCHAR mByte;
outportb( (USHORT) & dosIoBaseAddr -> mCh365I2cDev, iDevice << 1 | 0x00 ); /* 设备地址和命令 */
outportb( (USHORT) & dosIoBaseAddr -> mCh365I2cAddr, iAddr ); /* 设定地址 */
outportb( (USHORT) & dosIoBaseAddr -> mCh365I2cData, iByte ); /* 待写入的数据 */
mByte = inportb( (USHORT) & dosIoBaseAddr -> mCh365I2cCtrl ); /* 读取控制和状态 */
mByte |= 0x01; /* 位0置1则启动操作 */
outportb( (USHORT) & dosIoBaseAddr -> mCh365I2cCtrl, mByte ); /* 开始写操作 */
while( mByte & 0x01 ) mByte = inportb( (USHORT) & dosIoBaseAddr -> mCh365I2cCtrl ); /* 等待写操作完成 */
CH365DelayUS( 4 ); /* 延时4uS作为两次I2C操作的间隔 */
}
VOID CH365DelayUS( /* 延时指定微秒 */
ULONG iDelay ) /* 指定要延时的微秒数,如果延时小于10则误差较大 */
{
UCHAR mTime;
USHORT ms, us;
ms = iDelay / 983; /* 计算硬件计时周期, 983.04uS, 近似1毫秒 */
us = iDelay % 983; /* 计算剩余微秒数 */
while ( ms -- ) { /* CH365硬件循环计数周期 */
mTime = inportb( (USHORT) & dosIoBaseAddr -> mCh365IoTime ); /* 读取硬件循环计数寄存器 */
while ( inportb( (USHORT) & dosIoBaseAddr -> mCh365IoTime ) == mTime ); /* 等待计数开始 */
while ( inportb( (USHORT) & dosIoBaseAddr -> mCh365IoTime ) != mTime ); /* 等待一个计数周期 */
}
if ( us > 10 ) { /* 剩余微秒数大于10 */
mTime = ( us * 50 ) / ( 3.84 * 50 ); /* 计算硬件计时数, 3.84uS */
mTime += inportb( (USHORT) & dosIoBaseAddr -> mCh365IoTime ); /* 加上起始值为计数终值 */
while ( inportb( (USHORT) & dosIoBaseAddr -> mCh365IoTime ) != mTime ); /* 等待计数结束 */
}
else { /* 剩余微秒数小于10 */
while ( us -- ) { /* 每个周期近似1uS */
inportb( (USHORT) & dosIoBaseAddr -> mCh365IoTime ); /* 读取硬件循环计数寄存器 */
inportb( (USHORT) & dosIoBaseAddr -> mCh365IoTime );
inportb( (USHORT) & dosIoBaseAddr -> mCh365IoTime );
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -