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

📄 uh2.c

📁 TDI的USB HOST芯片UHC124的编程手册和固件驱动源代码
💻 C
字号:
/*
	UH2.C: UHC124 Programming Interface Library (Level 2)

(C) Copyright TransDimension, Inc.  All rights reserved.             
                                                                   
Modification history
====================
17Aug2000 Original Release
23Oct2000 test/modified TC
31Jan2001 modifided JW/TC
10Apr2001 modified by JW

*/

#include "types.h"
#include "uhc124.h"
#include "uh1.h"
#include "usb.h"
#include "enr.h"
#include "err.h"

#define MAX_ERR		3

#define STATE_SETUP	0
#define STATE_DATA	1
#define STATE_DATA1	2
#define STATE_STATUS	3
#define STATE_PROC	4

#define AREA_SETUP	0x800
#define AREA_DATA	(AREA_SETUP + 0x10)

#define STP_NONE	0

static U8 xferxd = 0;
static U16 xferdata = MDAT_BASE;

/*	select a transaction descriptor */

U8 UH_XactDesc(void)
{
	return(xferxd);
}

void UH_SetXactDesc(U8 xd)
{
	xferxd = xd;
}

/*	select data buffer address */

U16 UH_BufAddr(void)
{
	return(xferdata);
}

void UH_SetBufAddr(U16 addr)
{
	xferdata = addr;
}

/*	control transfer */

I16 UH_XferCtl(U8 dev, U8 ep, U8 *setup, U8 *data, U8 (*abort)())
{
	ENR *enr;
	U16 len, dlen, cnt, count, c; 
	I16 r;
	U8 seq, err, spd, ovfl, dir, prev, state, mode;
	U8 UHC124_01 = 0;	/* contact JW for details */
    
	/* check if pipe is valid */
	if (!(enr = UH_EnrGet(dev, ep, -1))) 
		return(ERR_DEVEP);

	mode = enr->mode;

	/* check if pipe is valid */
	if ((mode & ENR_XFER) != ENR_CTL) return(ERR_EPTYPE);

	/* data length for optional data stage */
	dlen = setup[SP_wLengthMSB];
	dlen = (dlen << 8) | setup[SP_wLengthLSB];

	/* check if there is a buf area for the data phase */
	if (dlen & !data) return(ERR_NOBUF);

	/* device speed and data stage xfer dir */
	spd = mode & ENR_SPD;
	dir = setup[SP_bmRequestType] & RT_XFER_DIR;

	/* state machine, abort and err count intialization */
	state = STATE_SETUP;
	if (abort) (*abort)(0);
	err = 0;

	while (1) {
		switch(state) {
		case STATE_SETUP:
			/* prepare transaction (setup) */
			UH_BlkWrite(xferdata, setup, SP_SIZE);
			UH_DispSetup(xferxd, dev, ep, xferdata,
						STP_NONE, spd);

			/* place the transaction into a batch */
			UH_SetTransSel(1 << xferxd);

			/* dispatch the batch */
			UH_ClrIntpStatus(IntpBatchCompl);
			if (r = UH_DispBatch()) return(r);

			prev = STATE_SETUP; state = STATE_PROC;
			break;
		case STATE_STATUS:
			/* xfer dir for the status stage */
			if (prev != STATE_STATUS)		/* V.0.86 To fix the bug that when dev naks */
				dir = !dir || !dlen;		/* host can not change the status direction */

			/* prepare transaction */
			UH_DispData(xferxd, dev, ep, NULL, 0,
        			(U8) ((dir) ? CTL_IN : CTL_DATA1), 
				STP_NONE, spd);

			/* dispatch batch */
			UH_SetTransSel(1 << xferxd);
			UH_ClrIntpStatus(IntpBatchCompl);
			if (r = UH_DispBatch()) return(r);

			prev = STATE_STATUS; state = STATE_PROC;

			/* JW: if lsp, out, set UHC124_01 */
			if (!dir && spd) UHC124_01 = 1;
			break;
		case STATE_DATA:
			cnt = 0; ovfl = 0;
			if (!(len = dlen)) { 
				state = STATE_STATUS; break; 
			}
			seq = CTL_DATA1;
			state = STATE_DATA1;
		case STATE_DATA1:
			/* max num of bytes to be xfered in this xact */
			count = enr->bsize;

			/* if output, copy data into Uh124 data mem */
			if (!dir) {
        			if (len < count) count = len;
        			UH_BlkWrite(xferdata, data, count);
			}

			/* prepare transaction */
			UH_DispData(xferxd, dev, ep, xferdata, count,
        				(U8) ((dir) ? CTL_IN : seq), 
					STP_NONE, spd);

			/* dispatch batch */
			UH_SetTransSel(1 << xferxd);
			UH_ClrIntpStatus(IntpBatchCompl);
			if (r = UH_DispBatch()) return(r);

			prev = STATE_DATA1; state = STATE_PROC;
		case STATE_PROC:
			/* wait until the batch is completed */
			if (UH_EndBatch()) return(ERR_SYS2);
            
			/* xact status and xfer count */
			r = UH_XDStatus(xferxd); 

			/* if endpoint is stalled and not UHC124_01 */
			if ((r & XDStsStall) && !UHC124_01)
				return(ERR_STL);

			/* if timeout or error, 3 strikes you are out */
			if (r & (XDStsError | XDStsTimeout)) {
				if (err++ >= MAX_ERR)
					return(ERR_TOERR);
				else {
					state = prev; break;
				}
			}

			/* if NAKed too many times */
			if (r & XDStsNak) {
				if (abort && (*abort)(1)) 
					return(ERR_NAK);
				else {
					state = prev; break;
				}
			}

			/* if transaction was setup stage */
			if (prev == STATE_SETUP) {
				state = (r & XDStsAck) ? STATE_DATA :
						STATE_SETUP; 
				break;
			}

			/* if transaction was for the status stage */
			if (prev == STATE_STATUS) { 
				/* with an IN data stage */
				if (!dir && (r & XDStsAck) ||
							UHC124_01)
					return(ovfl ? ERR_OVFL : cnt);
				/* w/o or with an OUT data stage */
				else if (dir && (r & XDStsSeq)) {
					return(cnt);
				} else {
					state = STATE_STATUS;
					break;
				}
			}

			/* out xact for data stage: no ack - impossible */
			if (!dir && !(r & XDStsAck))
				return(ERR_ACK);

			/* in xact for data stage: out of seq */
			if (dir && !log_eq((U8) (r & XDStsSeq), seq)) {
				state = STATE_DATA1; break;
			}

			/* xact for data stage: successful */
			count -= (c = UH_XDXferCnt(xferxd));

			/* if input, copy data */
			if (dir) UH_BlkRead(xferdata, data, count);

			/* advance data sequence */
			seq ^= CTL_SEQ;

			/* advance data */
			len -= count; data += count; cnt += count;

			/* reset err count */
			err = 0;

			/* go to status stage if overflowed or data done */
			if (r & XDStsOverflow) {
				ovfl = 1; state = STATE_STATUS;
			} else if (!len || c)
				state = STATE_STATUS;
			else 
				state = STATE_DATA1;
			break;
		defult:
			return(ERR_SYS1);
		}

	/* if low speed, do not rush for another transaction */
	if (spd) UH_Wait(1);

	}
}

/*	in data transfer */

I16 UH_InData(U8 dev, U8 ep, U8 *data, U16 len, U8 (*abort)()) 
{
	ENR *enr = UH_EnrGet(dev, ep, ENR_IN);
	U16 count, cnt, c;
	I16 r;
	U8 err, iso, seq, spd, xfer;

	/* check if endpoint is valid */
	if (!enr) return(ERR_DEVEP);
	if ((enr->mode & ENR_XFER) == ENR_CTL) 
		return(ERR_EPTYPE);
 
	/* check if there is a data buffer */ 
	if (len && !data) return(ERR_NOBUF);

	/* device and pipe characteristics */
	spd = (enr->mode & ENR_SPD) ? DEV_LSP : DEV_FSP;
	seq = (enr->mode & ENR_SEQ) ? CTL_DATA1 : CTL_DATA0;
	xfer = enr->mode & ENR_XFER;
	iso = (xfer == ENR_ISO) ? CTL_ISO : 0; 

	/* initialize abort, xfer count, and err count */
	if (abort) (*abort)(0);
	cnt = 0; err = 0;

	/* start transfer */
	while (1) {
		/* do not rush for a low spd transaction */
		if (spd) UH_Wait(1);

		/* data sequence */
		seq = (enr->mode & ENR_SEQ) ? CTL_DATA1 : CTL_DATA0;

		/* num of bytes to be transferred */
		count = enr->bsize;

		/* prepare transaction */
		UH_DispData(xferxd, dev, ep, xferdata, count, 
				(U8) (CTL_IN | iso), STP_NONE, spd);
		
		/* dispatch batch */
		UH_ClrIntpStatus(IntpBatchCompl);
		UH_SetTransSel(1 << xferxd);
		if (r = UH_DispBatch()) return(r);

		/* wait until the batch is completed */
		if (UH_EndBatch()) return(ERR_SYS3);

		/* read transaction status */
		r = UH_XDStatus(xferxd);

		/* if an intp xfer returns NAK, done */
		if (xfer == ENR_INT && (r & XDStsNak))
			return(ERR_INTNAK);

		/* if endpoint stalled */
		if (r & XDStsStall) return(ERR_STL);

		/* if too many nak's */
		if (r & XDStsNak) {
			if (abort && (*abort)(1)) 
				return(ERR_NAK);
			continue;
		}

		/* if timeout or error */
		if (r & (XDStsTimeout | XDStsError)) {
			if (err++ > MAX_ERR) 
				return(ERR_TOERR);
			continue;
		}

		/* transfer count */
		c = UH_XDXferCnt(xferxd);

		/* if non-iso and out of sequence, ignore data */
		if (!iso && !log_eq(seq, r & XDStsSeq))
			continue;

		/* actual number of bytes transferred */
		count -= c; 

		/* read data */
		if (count && data)
			UH_BlkRead(xferdata, data, count);

		/* advance data */
		len -= count; cnt += count; data += count;

		/* if non-iso, advance data sequence */
		if (!iso) enr->mode ^= ENR_SEQ;

		/* check if overflowed */
		if (r & XDStsOverflow) return(ERR_OVFL);

		/* xfer done, return num of bytes xfered */
		if (!len || c) return(cnt);

		/* reset err count */
		err = 0;
	}
}

/*	out data xfer */

I16 UH_OutData(U8 dev, U8 ep, U8 *data, U16 len, U8 (*abort)()) 
{
	ENR *enr = UH_EnrGet(dev, ep, ENR_OUT);
	U16 count, cnt, c;
	I16 r;
	U8 err, iso, ctl, seq, spd;

	/* check if endpoint is valid */
	if (!enr) return(ERR_DEVEP);
	if ((enr->mode & ENR_XFER) == ENR_CTL) 
		return(ERR_EPTYPE);
 
	/* check if there is a data buffer */ 
	if (len && !data) return(ERR_NOBUF);

	/* device and pipe characteristics */
	spd = (enr->mode & ENR_SPD) ? DEV_LSP : DEV_FSP;
	seq = (enr->mode & ENR_SEQ) ? CTL_DATA1 : CTL_DATA0;
	iso = ((enr->mode & ENR_XFER) == ENR_ISO) ? CTL_ISO : 0; 

	/* initialize abort, xfer count and err count */
	if (abort) (*abort)(0);
	cnt = 0; err = 0;

	ctl = iso;

	/* start transfer */
	while (1) {
		/* do not rush for a low spd transaction */
		if (spd) UH_Wait(1);

		/* data sequence */
		seq = (enr->mode & ENR_SEQ) ? CTL_DATA1 : CTL_DATA0;

		/* modify control word for an out transaction */
		ctl = ctl & ~CTL_SEQ | seq;

		/* num of bytes to be transferred */
		count = enr->bsize;
		if (len < count) count = len;

		/* prepare transaction */
		UH_DispData(xferxd, dev, ep, xferdata, count, 
				ctl, STP_NONE, spd);
		UH_BlkWrite(xferdata, data, count);

		/* dispatch batch */
		UH_ClrIntpStatus(IntpBatchCompl);
		UH_SetTransSel(1 << xferxd);
		if (r = UH_DispBatch()) return(r);

		/* wait until the batch is completed */
		if (UH_EndBatch()) return(ERR_SYS4);

		/* read transaction status */
		r = UH_XDStatus(xferxd);

		/* transaction processing */
		if (r & XDStsStall) return(ERR_STL);

		/* if Naked */
		if (r & XDStsNak) {
			if (abort && (*abort)(1)) 
				return(ERR_NAK);
			continue;
		}
	
		/* if timeout or error */
		if (r & (XDStsTimeout | XDStsError)) {
			if (err++ > MAX_ERR)
				return(ERR_TOERR);
			continue;
		}

		/* xfer count */
		if (UH_XDXferCnt(xferxd)) return(ERR_SYS3);

		/* non-iso xact with no err nor ack */
		if (!iso && !(r & XDStsAck)) return(ERR_ACK);

		/* advance data */
		len -= count; cnt += count; data += count;

		/* advance data sequence */
		if (!iso) enr->mode ^= ENR_SEQ;

		/* xfer done, return num of bytes xfered */
		if (!len) return(cnt);

		/* reset err count */
		err = 0;
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -