📄 usbhost.c.c
字号:
/* 2005.05.20
****************************************
** Copyright (C) W.ch 1999-2003 **
** Web: http://www.winchiphead.com **
****************************************
** USB HOST software interface **
** C, TC2.0 **
****************************************
UHCI的BIOS/DOS接口库 V1.0
南京沁恒电子有限公司 作者: W.ch 2005.05
运行环境: BIOS, DOS
*/
/*
\TC\TCC -ms -O -r -Z -c USBHOST.C
\TC\TLIB USBHOST +USBHOST.OBJ
*/
/*#define DEBUG*/
#include <dos.h>
#ifdef DEBUG
#include <stdio.h>
#endif
#define THIS_VERSION 0x10
#include "USBHOST.H"
#define UHCI_NULL_DATA_SIZE 0x07FF /* for UHCI controller TD */
#define UHCI_PTR_BITS 0x000F
#define UHCI_PTR_TERM 0x0001
#define UHCI_PTR_QH 0x0002
#define UHCI_PTR_DEPTH 0x0004
typedef struct UHCI_TD {
unsigned short Terminate :1;
unsigned short QHS :1;
unsigned short Depth :1;
unsigned short reserved1 :1;
unsigned short pLinkL :12;
unsigned short pLinkH;
unsigned short ActLen :11;
unsigned short reserved2 :5;
/* unsigned short reserved3 :1;
unsigned short BitstuErr :1;
unsigned short Crc_Tout :1;
unsigned short NAK :1;
unsigned short BabbleDetc :1;
unsigned short BufferErr :1;
unsigned short Stalled :1;*/
unsigned short Status :7;
unsigned short Active :1;
unsigned short IOC :1;
unsigned short IOS :1;
unsigned short LS :1;
unsigned short C_ERR :2;
unsigned short SPD :1;
unsigned short reserved4 :2;
unsigned short PID :8;
unsigned short DevAddr :7;
unsigned short EndPt :4;
unsigned short DataTog :1;
unsigned short reserved5 :1;
unsigned short MaxLen :11;
unsigned long pBuffer; /* 指向数据缓冲区地址 */
unsigned long reserved9[4];
unsigned char Buffer[ USB_ENDP_MAX_SIZE ]; /* 数据缓冲区 */
} mUHCI_TD;
typedef struct UHCI_QH {
unsigned short Terminate :1;
unsigned short QHS :1;
unsigned short reserved1 :2;
unsigned short QHLPL :12; /* 水平连接,指向下一个QH */
unsigned short QHLPH;
unsigned short QE_Term :1;
unsigned short QE_QHS :1;
unsigned short reserved2 :2;
unsigned short QELPL :12; /* 垂直连接,指向一个TD */
unsigned short QELPH;
unsigned long reserved9[2];
} mUHCI_QH;
#define UHCI_NUM_FRAMES 1024 /* in the frame list [array] */
typedef struct FRAME_LIST {
unsigned long FLP[ UHCI_NUM_FRAMES ]; /* 指向一个QH */
} mFRAME_LIST;
void USB_DelayuS( USHORT delay ); /* 以微秒为单位延时 */
mPUHCI_IO_REG USB_CheckUHCI( /* 读取配置空间判断是否UHCI, 是则返回I/O基址, 否则返回0 */
USHORT iPciAddr ); /* PCI地址 */
void USB_SetupQH( /* 设置帧列表及QH */
mPUSB_DEVICE UsbDevice ); /* 指向USB设备信息 */
void USB_SetupTD( /* 设置事务传输中的TD */
mPUSB_DEVICE UsbDevice, /* 指向USB设备信息 */
mPUSB_TRANS UsbTrans ); /* 指向USB传输信息 */
void USB_EnableTD( /* 允许TD运行 */
mPUSB_DEVICE UsbDevice ); /* 指向USB设备信息 */
void USB_DisableTD( /* 禁止TD运行 */
mPUSB_DEVICE UsbDevice ); /* 指向USB设备信息 */
UCHAR USB_WaitTrans( /* 等待USB事务完成, 返回状态, 为0则成功, 为ERR_TRANS_TOUT则超时 */
mPUSB_DEVICE UsbDevice, /* 指向USB设备信息 */
mPUSB_TRANS UsbTrans ); /* 指向USB传输信息 */
UCHAR USB_GetVersion( /* 获取库的版本号 */
UCHAR what ) /* 参数0 */
{
if ( what ) return( THIS_VERSION );
return( THIS_VERSION );
}
void USB_DelayuS( /* 以微秒为单位延时 */
USHORT delay )
{
int i;
while( delay -- ) for ( i = 0; i < 4; i++ ) inportb(0x70);
}
void USB_DelaymS( /* 以毫秒为单位延时 */
USHORT delay )
{
int i;
while( delay -- ) for ( i = 0; i < 4000; i++ ) inportb(0x70);
}
USHORT PCI_ReadCfgWord( /* 从配置空间读取一个字数据,返回读取的字数据 */
USHORT iPciAddr, /* PCI地址 */
USHORT iOffset ) /* 指定偏移地址 */
{
X86REG mReg;
mReg.x.bx = iPciAddr;
mReg.x.ax = 0xB109;
mReg.x.di = iOffset;
mReg.x.cx = 0;
int86 ( 0x1A, &mReg, &mReg ); /* 调用PCI的BIOS */
return( mReg.x.cx ); /* 返回数据 */
}
mPUHCI_IO_REG USB_CheckUHCI( /* 读取配置空间判断是否UHCI, 是则返回I/O基址, 否则返回0 */
USHORT iPciAddr ) /* PCI地址 */
{
USHORT data;
data = PCI_ReadCfgWord( iPciAddr, mOFFSET( mPCI_CONFIG, mPcSubClass ) ); /* 检查设备类 */
if ( data == 0x0C03 ) {
data = PCI_ReadCfgWord( iPciAddr, mOFFSET( mPCI_CONFIG, mPcRevisionId ) ); /* 检查设备类 */
if ( ( data & 0xFF00 ) == 0x0000 ) { /* UHCI */
data = PCI_ReadCfgWord( iPciAddr, mOFFSET( mPCI_CONFIG, mPcBaseAddr4 ) ); /* 获取基址 */
return( (mPUHCI_IO_REG)( data & 0xFFFE ) );
}
}
return( (mPUHCI_IO_REG)0 );
}
void USB_SetupQH( /* 设置帧列表及QH */
mPUSB_DEVICE UsbDevice ) /* 指向USB设备信息 */
{
USHORT i;
ULONG mLineAddr;
mFRAME_LIST far *pFrameList;
mUHCI_QH far *pQH0;
mUHCI_TD far *pTD0;
pFrameList = GET_SEG_OFS( UsbDevice -> FrameBaseAddr ); /* 帧列表基址,远指针 */
mLineAddr = UsbDevice -> FrameBaseAddr + sizeof( mFRAME_LIST ); /* QH的线性地址 */
for ( i = 0; i < UHCI_NUM_FRAMES; i++ ) pFrameList -> FLP[ i ] = mLineAddr | UHCI_PTR_QH;
pQH0 = GET_SEG_OFS( mLineAddr ); /* 队列头 */
for ( i = 0; i < sizeof( mUHCI_QH )/2; i++ ) *( (FPUSHORT)pQH0 + i ) = 0;
pQH0 -> Terminate = 0; /* 继续 */
pQH0 -> QHS = 1; /* 指向下一个QH */
pQH0 -> QHLPL = mLineAddr >> 4; /* 水平连接,指向下一个QH */
pQH0 -> QHLPH = mLineAddr >> 16;
mLineAddr = UsbDevice -> FrameBaseAddr + sizeof( mFRAME_LIST ) + sizeof( mUHCI_QH ) * 8; /* TD的线性地址 */
pQH0 -> QE_Term = 1; /* TD队列无效 */
pQH0 -> QE_QHS = 0; /* 指向TD */
pQH0 -> QELPL = mLineAddr >> 4; /* 垂直连接,指向一个TD */
pQH0 -> QELPH = mLineAddr >> 16;
pTD0 = GET_SEG_OFS( mLineAddr ); /* 传输描述符 */
for ( i = 0; i < mOFFSET( mUHCI_TD, Buffer )/2; i++ ) *( (FPUSHORT)pTD0 + i ) = 0;
pTD0 -> Terminate = 1;
}
void USB_SetupTD( /* 设置事务传输中的TD */
mPUSB_DEVICE UsbDevice, /* 指向USB设备信息 */
mPUSB_TRANS UsbTrans ) /* 指向USB传输信息 */
{
UCHAR i;
ULONG mLineAddr;
mUHCI_TD far *pTD0;
mLineAddr = UsbDevice -> FrameBaseAddr + sizeof( mFRAME_LIST ) + sizeof( mUHCI_QH ) * 8; /* TD的线性地址 */
pTD0 = GET_SEG_OFS( mLineAddr ); /* 传输描述符 */
for ( i = 0; i < mOFFSET( mUHCI_TD, Buffer )/2; i++ ) *( (FPUSHORT)pTD0 + i ) = 0;
pTD0 -> Terminate = 1;
pTD0 -> C_ERR = 3; /* 设置错误重试次数 */
pTD0 -> SPD = 1; /* 设置短包有效 */
pTD0 -> PID = UsbTrans -> PID; /* 设置传输PID */
pTD0 -> DevAddr = UsbDevice -> DevAddr; /* 设置设备地址 */
pTD0 -> EndPt = UsbDevice -> EndpInfo[ UsbTrans -> EndpIndex ].EndpAddr & USB_ENDP_ADDR_MASK; /* 设置端点号 */
pTD0 -> DataTog = UsbDevice -> EndpInfo[ UsbTrans -> EndpIndex ].DataTog; /* 数据同步控制位 */
pTD0 -> MaxLen = ( UsbTrans -> Len - 1 ) & UHCI_NULL_DATA_SIZE; /* 设置数据长度 */
mLineAddr += mOFFSET( mUHCI_TD, Buffer );
pTD0 -> pBuffer = mLineAddr; /* 指向数据缓冲区地址 */
if ( UsbTrans -> PID != DEF_USB_PID_IN ) { /* 不是IN */
for ( i = 0; i != UsbTrans -> Len; i++ ) pTD0 -> Buffer[ i ] = UsbTrans -> Buffer[ i ]; /* 将输出数据复制到缓冲区 */
}
#ifdef DEBUG
printf( "TD: Endp=%02XH, Len=%02XH, PID=%s\n", (USHORT)( UsbDevice -> EndpInfo[ UsbTrans -> EndpIndex ].EndpAddr ), (USHORT)( UsbTrans -> Len ), \
( UsbTrans -> PID == DEF_USB_PID_IN ? "IN" : ( UsbTrans -> PID == DEF_USB_PID_OUT ? "OUT" : ( UsbTrans -> PID == DEF_USB_PID_SETUP ? "SETUP" : "OTHER" ) ) ) );
#endif
pTD0 -> Active = 1; /* 设置活动标志 */
}
void USB_EnableTD( /* 允许TD运行 */
mPUSB_DEVICE UsbDevice ) /* 指向USB设备信息 */
{
ULONG mLineAddr;
mUHCI_QH far *pQH0;
mLineAddr = UsbDevice -> FrameBaseAddr + sizeof( mFRAME_LIST );
pQH0 = GET_SEG_OFS( mLineAddr ); /* 队列头 */
mLineAddr = UsbDevice -> FrameBaseAddr + sizeof( mFRAME_LIST ) + sizeof( mUHCI_QH ) * 8; /* TD的线性地址 */
pQH0 -> QE_QHS = 0; /* 指向TD */
pQH0 -> QELPL = mLineAddr >> 4; /* 垂直连接,指向一个TD */
pQH0 -> QELPH = mLineAddr >> 16;
pQH0 -> QE_Term = 0; /* TD队列有效 */
}
void USB_DisableTD( /* 禁止TD运行 */
mPUSB_DEVICE UsbDevice ) /* 指向USB设备信息 */
{
ULONG mLineAddr;
mUHCI_QH far *pQH0;
mLineAddr = UsbDevice -> FrameBaseAddr + sizeof( mFRAME_LIST );
pQH0 = GET_SEG_OFS( mLineAddr ); /* 队列头 */
pQH0 -> QE_Term = 1; /* TD队列无效 */
}
UCHAR USB_WaitTrans( /* 等待USB事务完成, 返回状态, 为0则成功, 为ERR_TRANS_TOUT则超时 */
mPUSB_DEVICE UsbDevice, /* 指向USB设备信息 */
mPUSB_TRANS UsbTrans ) /* 指向USB传输信息 */
{
UCHAR i;
USHORT Timeout;
ULONG mLineAddr;
mPUHCI_IO_REG IoBaseAddr;
mUHCI_TD far *pTD0;
mLineAddr = UsbDevice -> FrameBaseAddr + sizeof( mFRAME_LIST ) + sizeof( mUHCI_QH ) * 8; /* TD的线性地址 */
pTD0 = GET_SEG_OFS( mLineAddr ); /* 传输描述符 */
for ( Timeout = ( UsbTrans -> Timeout << 2 ) + 1; Timeout != 0 || UsbTrans -> Timeout == 0; Timeout-- ) {
USB_DelayuS( 250 );
IoBaseAddr = UsbDevice -> IoBaseAddr;
if ( PortInWord( & ( IoBaseAddr -> mUSBSTS ) ) ) break; /* 如果状态不为0跳出 */
if ( ( PortInWord( & ( IoBaseAddr -> mUSBCMD ) ) & USBCMD_RS ) == 0 ) break; /* 如果停机跳出 */
if ( pTD0 -> Active == 0 ) break; /* 事务处理结束跳出 */
}
#ifdef DEBUG
printf( "CMD=%04XH, STS=%04XH, TD->Status=%02XH, TD->ActLen=%02XH, Timeout=%d\n", \
PortInWord( & ( UsbDevice -> IoBaseAddr -> mUSBCMD ) ), PortInWord( & ( UsbDevice -> IoBaseAddr -> mUSBSTS ) ), \
(USHORT)( pTD0 -> Status ), (USHORT)( pTD0 -> ActLen ), ( UsbTrans -> Timeout << 2 ) + 1 - Timeout );
#endif
if ( Timeout == 0 ) return( ERR_TRANS_TOUT );
if ( ( pTD0 -> Status & 0x7E ) == 0x00 ) {
if ( UsbTrans -> PID == DEF_USB_PID_IN ) { /* 是IN */
for ( i = 0; i != UsbTrans -> Len; i++ ) UsbTrans -> Buffer[ i ] = pTD0 -> Buffer[ i ]; /* 从缓冲区复制输入数据 */
}
UsbTrans -> Len = (UCHAR)( pTD0 -> ActLen + 1 );
}
return( pTD0 -> Status & 0x7E );
}
UCHAR USB_CheckDevice( /* 检测有无USB设备连接 */
mPUSB_DEVICE UsbDevice ) /* 指向USB设备信息, 成员PortIndex指定端口序号, 0FFH则搜索第一个 */
{
UCHAR Index;
USHORT PciAddr, HubStatus;
mPUHCI_IO_REG IoBaseAddr;
Index = 0;
for ( PciAddr = 0; PciAddr <= 0x0400; PciAddr++ ) {
IoBaseAddr = USB_CheckUHCI( PciAddr ); /* 读取配置空间判断是否UHCI */
if ( IoBaseAddr ) {
if ( UsbDevice -> PortIndex == 0xFF || UsbDevice -> PortIndex == Index ) {
HubStatus = PortInWord( & ( IoBaseAddr -> mPORTSC1 ) );
if ( ( HubStatus & USBPORTSC_CCS ) && ( HubStatus & USBPORTSC_LSDA ) == 0 ) break; /* 全速设备存在 */
}
Index++;
if ( UsbDevice -> PortIndex == 0xFF || UsbDevice -> PortIndex == Index ) {
HubStatus = PortInWord( & ( IoBaseAddr -> mPORTSC2 ) );
if ( ( HubStatus & USBPORTSC_CCS ) && ( HubStatus & USBPORTSC_LSDA ) == 0 ) break; /* 全速设备存在 */
}
Index++;
}
}
if ( PciAddr >= 0x0400 ) {
if ( UsbDevice -> PortIndex < Index ) return( ERR_NO_DEVICE );
return( ERR_NO_HOST );
}
#ifdef DEBUG
printf( "PCI=%04XH, Base=%04XH, Index=%02XH, Hub=%04XH\n", PciAddr, IoBaseAddr, (USHORT)Index, HubStatus );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -