📄 uh2.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 + -