www.pudn.com > usbhost_source.rar > SL811HST.C


/** 
*	sl811.c 
*	USBホストチップドライバ 
*	サイプレスSL811HS 
* 
*	Copyright (c)2004 Junichi Tomaru 
*/ 
#include	"h8hst.h" 
 
#define USB_ACK		1 
#define USB_NAK		2 
#define USB_STALL	4 
 
 
/** 
*	指定レジスタのデータ読む 
*/ 
byte	sl_read( char addr ) 
{ 
	SL811ADDR = addr;		/* アドレスセット */ 
	return	SL811DATA;		/* データ読み出し */ 
} 
 
 
/** 
*	指定レジスタにデータ書く 
*/ 
void	sl_write( char addr, byte data ) 
{ 
	SL811ADDR = addr;		/* アドレスセット */ 
	SL811DATA = data;		/* データ書き込み */ 
} 
 
 
/** 
*	指定アドレスより連続データ読む 
*	アドレスはIC側でオートインクリメント 
*/ 
void	sl_burstread( char addr, char *buf, int size ) 
{ 
	int	i; 
 
	if( size <= 0 ){ 
		return; 
	} 
	SL811ADDR = addr;		/* 先頭アドレスセット */ 
	for( i = 0; i < size; i++ ){ 
		*( buf + i ) = SL811DATA; 
	} 
} 
 
 
/** 
*	指定アドレスより連続データ書く 
*	アドレスはIC側でオートインクリメント 
*/ 
void	sl_burstwrite( char addr, char *buf, int size ) 
{ 
	int	i; 
 
	if( size <= 0 ){ 
		return; 
	} 
	SL811ADDR = addr;		/* 先頭アドレスセット */ 
	for( i = 0; i < size; i++ ){	/* データの書き込み */ 
		SL811DATA = *( buf + i ); 
	} 
} 
 
 
/** 
*	SL811HS初期化 
*/ 
void	sl_init( void ) 
{ 
	usbspeed = NOSPEED; 
	P9DR &= 0xef; 
	wait10us( );				/* USBチップリセットパルス */ 
	P9DR |= 0x10; 
	waitms( 1 ); 
	sl_write( SL_CTRLREG2, 0xae );		/* マスタモード,極性切り替えなし+カウンタ2EH */ 
} 
 
 
/** 
*	SETUPパケット書き込み 
*	ret:ACK/NAK/STALL 
*/ 
int	send_setup( char *data ) 
{ 
	byte	sts, ret; 
 
	sl_burstwrite( 0x10, data, 8 );		/* データ転送 */ 
	sl_write( SL_BASEADDRA, 0x10 );		/* 転送開始アドレス */ 
	sl_write( SL_BASELENA, 8 );		/* データ長さ */ 
	sl_write( SL_DEVADDRA, info.addr );	/* 通信相手のデバイスアドレス */ 
	sl_write( SL_PIDDEVEPA, PID_SETUP + 0 );/* セットアップパケット */ 
	sl_write( SL_HOSTCTRLA, ARM + ENABLE + DIRECTION );	/* データ0で送信 */ 
	wait100us( ); 
	wait100us( ); 
	while(( sl_read( SL_INTSTATUS ) & INT_USBADONE ) == 0 ){	/* 送信終了待ち */ 
	} 
	sts = sl_read( SL_USBSTSA ); 
	ret = 0; 
	if(( sts & ACK ) == ACK ){ 
		ret |= USB_ACK; 
	} 
	if(( sts & NAK ) == NAK ){ 
		ret |= USB_NAK; 
	} 
	if(( sts & STALL ) == STALL ){ 
		ret |= USB_STALL; 
	} 
 
	return ret; 
} 
 
 
/** 
*	SL811HSにデータ書き込む 
*/ 
int	sl_writedata( char *data, int size ) 
{ 
	byte	sts, tgl, ret; 
 
	if( size < 2 ){ 
		return 0; 
	} 
	sl_burstwrite( 0x10, data + 2, size - 2 ); 
	sl_write( SL_BASEADDRA, 0x10 ); 
	sl_write( SL_BASELENA, size - 2 ); 
	sl_write( SL_DEVADDRA, info.addr ); 
	sl_write( SL_PIDDEVEPA, PID_OUT | info.txep ); 
	tgl = ARM + ENABLE + DIRECTION; 
	if( info.tgl == 1 ){ 
		tgl += DATATGL; 
	} 
	sl_write( SL_HOSTCTRLA, tgl ); 
	wait100us( ); 
	wait100us( ); 
	while(( sl_read( SL_INTSTATUS ) & INT_USBADONE ) == 0 ){	/* 送信完了待ち */ 
	} 
	sts = sl_read( SL_USBSTSA ); 
	ret = 0; 
	if(( sts & ACK ) == ACK ){ 
		ret |= USB_ACK; 
	} 
	if(( sts & NAK ) == NAK ){ 
		ret |= USB_NAK; 
	} 
	if(( sts & STALL ) == STALL ){ 
		ret |= USB_STALL; 
	} 
	return ret; 
} 
 
 
/** 
*	SL811HSよりデータ読み出す 
*/ 
int	sl_readdata( char *data, int size ) 
{ 
	byte	sts, tgl, ret; 
	int	i; 
 
	if( size < 0 ){ 
		return 0; 
	} 
	sl_write( SL_BASEADDRA, 0x10 ); 
	sl_write( SL_BASELENA, size ); 
	sl_write( SL_DEVADDRA, info.addr );		/* 対象デバイスアドレス */ 
	sl_write( SL_PIDDEVEPA, PID_IN + info.txep );	/* INパケット */ 
	tgl = ARM + ENABLE; 
	if( info.tgl == 1 ){ 
		tgl += DATATGL; 
	} 
	for( i = 0; i < 200; i++ ){ 
		sl_write( SL_HOSTCTRLA, tgl ); 
		wait100us( ); 
		wait100us( ); 
		while(( sl_read( SL_INTSTATUS ) & INT_USBADONE ) == 0 ){	/* 送信終了待ち */ 
		} 
		sts = sl_read( SL_USBSTSA ); 
		if(( sts & NAK ) == 0 ){	/* NAKでなければ抜ける */ 
			break; 
		} 
	} 
	ret = 0; 
	if(( sts & ACK ) == ACK ){ 
		sl_burstread( 0x10, data, size ); 
		ret |= USB_ACK; 
	} 
	if(( sts & NAK ) == NAK ){ 
		ret |= USB_NAK; 
	} 
	if(( sts & STALL ) == STALL ){ 
		ret |= USB_STALL; 
	} 
	return ret; 
} 
 
 
/** 
*	デバイスチェック 
*/ 
bool	checkdevice( void ) 
{ 
	byte	sts; 
	bool	ret; 
 
	sl_write( SL_INTSTATUS, 0xff );		/* すべての割り込みビットクリア */ 
	sts = sl_read( SL_INTSTATUS ); 
	if(( sts & 0x40 ) == 0x40 ){	/* ビットが立っているとデバイスなし */ 
		return	FALSE; 
	} 
	else{ 
		if(( sts & 0x80 ) == 0x80 ){		/* フルスピード */ 
			usbspeed = FULLSPEED; 
			dispmessage( 7 ); 
		} 
		else{ 
			usbspeed = LOWSPEED; 
			dispmessage( 8 ); 
		} 
	} 
 
	return	TRUE; 
} 
 
 
/** 
*	デバイス検出→プラグ&プレイ 
*/ 
bool	plugnplay( void ) 
{ 
	byte	sts, tp; 
	byte	buf[10]; 
	char	i, tmp[4]; 
	const char	getdesc[8] = { 
		 DEV2HOST + TYPESTD + RXDEVICE,	/* bmRequestType */ 
		 GET_DESCRIPTOR,		/* bRequest */ 
		 0, DEVICE,			/* wValue */ 
		 0, 0,				/* wIndex */ 
		 8, 0				/* Data */ 
	}; 
	const char	setaddr[8] = { 
		HOST2DEV + TYPESTD + RXDEVICE,	/* bmRequestType */ 
		SET_ADDRESS,			/* bRequest */ 
		2, 0,				/* wValue */ 
		0, 0,				/* wIndex */ 
		0, 0				/* Data */ 
	}; 
 
	waitms( 100 );				/* デバイス発見→100msディレイ */ 
	info.addr = info.txep = info.rxep = 0; 
	info.tgl = 1; 
	sl_write( SL_CTRLREG2, 0xae );		/* マスタモード,極性切り替えなし+カウンタ2EH */ 
	sl_write( SL_SOFCNTLOW, 0xe0 ); 
	sl_write( SL_CTRLREG1, 0x8 );		/* バスリセット */ 
	waitms( 20 );				/* MIN10ms */ 
	if( usbspeed == FULLSPEED ){		/* フルスピード */ 
		sl_write( SL_CTRLREG2, 0xae );	/* データ反転なし */ 
		sl_write( SL_CTRLREG1, 0x1 );	/* ほんとは5? */ 
	} 
	else{					/* ロースピード */ 
		sl_write( SL_CTRLREG2, 0xee );	/* データ反転あり */ 
		sl_write( SL_CTRLREG1, 0x21 ); 
	} 
	sl_write( SL_PIDDEVEPA, 0x50 ); 
	sl_write( SL_DEVADDRA, 0x00 );		/* 相手デバイスは0 *//* 1でない? */ 
	sl_write( SL_IER, INT_USBADONE + INT_USBBDONE + INT_SOFTIM + INT_INSREM );/* 割り込みセット */ 
	sl_write( SL_HOSTCTRLA, 1 );		/* SOFイネーブル */ 
	waitms( 30 ); 
	sl_write( SL_INTSTATUS, 0xff ); 
	if(( send_setup( (char *)getdesc ) & USB_ACK ) == 0 ){	/* デバイスディスクリプタ */ 
		return FALSE; 
	} 
	if(( sl_readdata( buf, 8 ) & USB_ACK ) == 0 ){	/* デバイスディスクリプタ受信 */ 
		return FALSE; 
	} 
	devdesc.length = buf[0]; 
	devdesc.type = buf[1]; 
	devdesc.usbver = (((int)buf[3] << 8 ) & 0xff00 ); 
	devdesc.usbver |= ( (int)buf[2] & 0x00ff ); 
	devdesc.class = buf[4]; 
	devdesc.subclass = buf[5]; 
	devdesc.protocol = buf[6]; 
	devdesc.maxsize = buf[7]; 
/**/	lcdlocate( 12, 0 ); 
/**/	lcdputch( 'v' ); 
/**/	lcdputch( buf[3] + 0x30 ); 
/**/	lcdputch( '.' ); 
/**/	lcdputch( ((( buf[2] >> 4 ) & 0xf ) + 0x30 )); 
/**/	for( i = 0; i < 8; i++ ){ 
/**/		lcdprint( i*2, 1, uctoahz( buf[i], tmp ) ); 
/**/	} 
	if(( send_setup( (char *)setaddr ) & USB_ACK ) == 0 ){	/*  セットアドレス */ 
		return FALSE; 
	} 
	info.addr = 2; 
 
	return	TRUE; 
}  
 
 
/* end of sl811hst.c */