⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch365dos.c

📁 南京沁恒电子有限公司USB通用设备接口芯片资料
💻 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 + -