#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: scr.c,v 1.40 2026/07/15 13:20:48 andvar Exp $");
#include "opt_ddb.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/types.h>
#include <sys/device.h>
#include <dev/isa/isavar.h>
#include <arm/cpufunc.h>
#ifdef SCR_DEBUG
#define KERNEL_DEBUG
#ifdef DDB
#define DEBUGGER printf("file = %s, line = %d\n",__FILE__,__LINE__);Debugger()
#else
#define DEBUGGER panic("file = %s, line = %d",__FILE__,__LINE__);
#endif
#else
#define DEBUGGER
#endif
#include <machine/kerndebug.h>
#include <dev/ic/i8253reg.h>
#include <shark/shark/hat.h>
#include <shark/shark/sequoia.h>
#include <machine/scrio.h>
#define scr_lcr scr_cfcr
#define SCRUNIT(x) (minor(x))
#ifdef SCR_DEBUG
#define KERNEL_DEBUG
#define ASSERT(f) do { if (!(f)) { DEBUGGER;} }while(0)
#define TOGGLE_TEST_PIN() scrToggleTestPin()
#define INVALID_STATE_CMD(sc,state,cmd) invalidStateCmd(sc,state,cmd,__LINE__);
#else
#define ASSERT(f)
#define TOGGLE_TEST_PIN()
#define INVALID_STATE_CMD(sc,state,cmd) sc->bigTrouble = true;
#endif
#define SCRPROBE_DEBUG_INFO 0x00000100
#define SCRATTACH_DEBUG_INFO 0x00000200
#define SCROPEN_DEBUG_INFO 0x00000400
#define SCRCLOSE_DEBUG_INFO 0x00000800
#define SCRREAD_DEBUG_INFO 0x00001000
#define SCRWRITE_DEBUG_INFO 0x00002000
#define SCRIOCTL_DEBUG_INFO 0x00004000
#define MASTER_SM_DEBUG_INFO 0x00008000
#define COLD_RESET_SM_DEBUG_INFO 0x00010000
#define ATR_SM_DEBUG_INFO 0x00020000
#define T0_RECV_BYTE_SM_DEBUG_INFO 0x00040000
#define T0_SEND_BYTE_SM_DEBUG_INFO 0x00080000
#define T0_RECV_SM_DEBUG_INFO 0x00100000
#define T0_SEND_SM_DEBUG_INFO 0x00200000
int scrdebug =
0;
#define mcOn 0x0100
#define mcT0DataSend 0x0102
#define mcT0DataRecv 0x0103
#define mcColdReset 0x0105
#define mcATR 0x0106
#define mcT0Send 0x0108
#define mcT0Recv 0x010a
#define msIdleOff 0x0200
#define msColdReset 0x0201
#define msATR 0x0202
#define msIdleOn 0x0203
#define msT0Send 0x0204
#define msT0Recv 0x0205
#define t0scStart 0x0300
#define t0scTWorkWaiting 0x0301
#define t0ssIdle 0x0400
#define t0ssSendHeader 0x0401
#define t0ssRecvProcedure 0x0402
#define t0ssSendByte 0x0403
#define t0ssSendData 0x0404
#define t0ssRecvSW1 0x0405
#define t0ssRecvSW2 0x0406
#define t0rcStart 0x0500
#define t0rcTWorkWaiting 0x0501
#define t0rsIdle 0x0600
#define t0rsSendHeader 0x0601
#define t0rsRecvProcedure 0x0602
#define t0rsRecvByte 0x0603
#define t0rsRecvData 0x0604
#define t0rsRecvSW1 0x0605
#define t0rsRecvSW2 0x0606
#define crcStart 0x0900
#define crcT2 0x0902
#define crsIdle 0x0a00
#define crsT2Wait 0x0a01
#define atrcStart 0x0b00
#define atrcT3 0x0b04
#define atrcTWorkWaiting 0x0b05
#define atrsIdle 0x0c00
#define atrsTS 0x0c01
#define atrsT0 0x0c02
#define atrsTABCD 0x0c03
#define atrsTK 0x0c04
#define atrsTCK 0x0c05
#define t0rbcStart 0x0d00
#define t0rbcAbort 0x0d01
#define t0rbcTFindStartEdge 0x0d02
#define t0rbcTFindStartMid 0x0d03
#define t0rbcTClockData 0x0d04
#define t0rbcTErrorStart 0x0d05
#define t0rbcTErrorStop 0x0d06
#define t0rbsIdle 0x0e00
#define t0rbsFindStartEdge 0x0e01
#define t0rbsFindStartMid 0x0e02
#define t0rbsClockData 0x0e03
#define t0rbsSendError 0x0e04
#define t0sbcStart 0x0f00
#define t0sbcAbort 0x0f01
#define t0sbcTGuardTime 0x0f02
#define t0sbcTClockData 0x0f03
#define t0sbcTError 0x0f04
#define t0sbcTResend 0x0f05
#define t0sbsIdle 0x1000
#define t0sbsWaitGuardTime 0x1001
#define t0sbsClockData 0x1002
#define t0sbsWaitError 0x1003
#define t0sbsWaitResend 0x1004
#define gcT0RecvByte 0x1100
#define gcT0RecvByteErr 0x1101
#define gcT0SendByte 0x1102
#define gcT0SendByteErr 0x1103
#ifdef SCR_DEBUG
#define CARD_FREQ_DEF (3579000/2)
#else
#define CARD_FREQ_DEF (3579000)
#endif
#define CONVENTION_UNKNOWN 0
#define CONVENTION_INVERSE 1
#define CONVENTION_DIRECT 2
#define CONVENIONT_INVERSE_ID 0x3f
#define CONVENTION_DIRECT_FIX 0x3b
#define CONVENTION_DIRECT_ID 0x23
#define CLK_COUNT_START (((372 * TIMER_FREQ) / sc->cardFreq) /5)
#define CLK_COUNT_DATA (((372 * TIMER_FREQ) / sc->cardFreq) )
#define START_2_DATA 5
#define N_DEFAULT 0
#define Fi_DEFAULT 372
#define Di_DEFAULT 1
#define Wi_DEFAULT 10
int FI2Fi[16] = {372, 372, 558, 744,1116,1488,1860, 0,
0, 512, 768,1024,1536,2048, 0, 0};
int DI2Di[16] = { 0, 1, 2, 4, 8, 16, 32, 0,
12, 20, 0, 0, 0, 0, 0, 0};
#define ATR_Y_TA 0x10
#define ATR_Y_TB 0x20
#define ATR_Y_TC 0x40
#define ATR_Y_TD 0x80
#define PROTOCOL_T0 0x0001
#define PROTOCOL_T1 0x0002
#define PROTOCOL_T2 0x0004
#define PROTOCOL_T3 0x0008
#define T_t2 ((300 * TIMER_FREQ) / sc->cardFreq)
#define T_t3 ((40000 * (TIMER_FREQ/1024)) / (sc->cardFreq/1024))
#define T_WORK_WAITING (((960 * sc->Wi * sc->Fi ) / (sc->cardFreq/1024)) * (TIMER_FREQ/1024))
#define PARITY_ERROR_MAX 3
#define MAX_FIQ_TIME 5
#define CMD_BUF_INS_OFF 1
#define CMD_BUF_DATA_LEN_OFF 4
typedef unsigned char BYTE;
struct scr_softc
{
int open;
int status;
int cardFreq;
int convention;
int protocolType;
int N;
int Fi;
int Di;
int Wi;
int clkCountStartRecv;
int clkCountDataRecv;
int clkCountDataSend;
int masterS ;
int t0RecvS;
int t0SendS;
int coldResetS;
int ATRS;
int t0RecvByteS;
int t0SendByteS;
int commandCount;
int dataCount;
int dataMax;
void (*t0ByteParent)(struct scr_softc *,int);
int shiftBits;
BYTE shiftByte;
BYTE dataByte;
int shiftParity;
int shiftParityCount;
int atrY;
int atrK;
int atrKCount;
int atrTABCDx;
int atrFi;
int atrDi;
int masterDone;
int bigTrouble;
ScrOn * pIoctlOn;
ScrT0 * pIoctlT0;
};
static int devices = 0;
static int tsleepIdent;
static int hatLock = false;
typedef struct callout_t
{
struct callout_t *c_next;
struct scr_softc *c_sc;
int c_arg;
void (*c_func)(struct scr_softc*,int);
int c_time;
}Callout;
#define SCR_CLK_CALLOUT_COUNT 10
static Callout scrClkCalloutArray[SCR_CLK_CALLOUT_COUNT];
static Callout *scrClkCallFree;
static Callout scrClkCallTodo;
static int scrClkEnable = 0;
static void myHatWedge(int nFIQs);
static int scrClkCount;
#define HATSTACKSIZE 1024
static unsigned char hatStack[HATSTACKSIZE];
int scrprobe(device_t, cfdata_t, void *);
void scrattach(device_t, device_t, void *);
static void initStates(struct scr_softc * sc);
static void masterSM(struct scr_softc * sc,int cmd);
static void t0SendSM(struct scr_softc * sc,int cnd);
static void t0RecvSM(struct scr_softc * sc,int cnd);
static void ATRSM(struct scr_softc * sc,int cnd);
static void coldResetSM(struct scr_softc * sc,int cnd);
static void t0SendByteSM(struct scr_softc * sc,int cnd);
static void t0RecvByteSM(struct scr_softc * sc,int cnd);
static void cardOff(struct scr_softc * sc);
static void scrClkInit(void);
static void scrClkStart(struct scr_softc* sc,int countPerTick);
static void scrClkAdj(int count);
static void scrClkStop(void);
static void hatClkIrq(int count);
static void scrTimeout(void (*func)(struct scr_softc*,int), struct scr_softc*, int arg, int count);
static void scrUntimeout(void (*func)(struct scr_softc*,int), struct scr_softc*, int arg);
#ifdef SCR_DEBUG
static void invalidStateCmd(struct scr_softc* sc,int state,int cmd, int line);
static char * getText(int x);
#endif
CFATTACH_DECL_NEW(scr, sizeof(struct scr_softc),
scrprobe, scrattach, NULL, NULL);
extern struct cfdriver scr_cd;
dev_type_open(scropen);
dev_type_close(scrclose);
dev_type_ioctl(scrioctl);
const struct cdevsw scr_cdevsw = {
.d_open = scropen,
.d_close = scrclose,
.d_read = noread,
.d_write = nowrite,
.d_ioctl = scrioctl,
.d_stop = nostop,
.d_tty = notty,
.d_poll = nopoll,
.d_mmap = nommap,
.d_kqfilter = nokqfilter,
.d_discard = nodiscard,
.d_flag = D_TTY
};
int
scrprobe(device_t parent, cfdata_t match, void *aux)
{
struct isa_attach_args *ia = aux;
int rv = 0;
KERN_DEBUG (scrdebug, SCRPROBE_DEBUG_INFO,("scrprobe: called, name = %s\n",
device_cfdata(parent)->cf_name));
if (device_is_a(parent, "ofisascr") && devices == 0)
{
devices++;
ia->ia_nio = 0;
ia->ia_niomem = 0;
ia->ia_nirq = 0;
ia->ia_ndrq = 0;
rv = 1;
KERN_DEBUG (scrdebug, SCRPROBE_DEBUG_INFO,("scrprobe: successful \n"));
}
return (rv);
}
void
scrattach(device_t parent, device_t self, void *aux)
{
struct scr_softc *sc = device_private(self);
printf("\n");
if (device_is_a(parent, "ofisascr"))
{
KERN_DEBUG (scrdebug, SCRATTACH_DEBUG_INFO,("scrattach: called \n"));
scrClkInit();
initStates(sc);
sc->open = false;
}
else
{
panic("scrattach: not on an ISA bus, attach impossible");
}
return;
}
static void initStates(struct scr_softc * sc)
{
sc->masterS = msIdleOff;
sc->t0RecvS = t0rsIdle;
sc->t0SendS = t0ssIdle;
sc->coldResetS = crsIdle;
sc->ATRS = atrsIdle;
sc->t0RecvByteS = t0rbsIdle;
sc->t0SendByteS = t0sbsIdle;
}
int scropen(dev_t dev, int flag, int mode, struct lwp *l)
{
struct scr_softc *sc;
KERN_DEBUG (scrdebug, SCROPEN_DEBUG_INFO,
("scropen: called with minor device %d and flag 0x%x\n",
SCRUNIT(dev), flag));
sc = device_lookup_private(&scr_cd, SCRUNIT(dev));
if (!sc)
{
KERN_DEBUG (scrdebug, SCROPEN_DEBUG_INFO,("\t scropen, return ENXIO\n"));
return (ENXIO);
}
#if 0
if (sc->open)
{
KERN_DEBUG (scrdebug, SCROPEN_DEBUG_INFO,("\t scropen, return EBUSY\n"));
return (EBUSY);
}
sc->open = true;
#endif
KERN_DEBUG (scrdebug, SCROPEN_DEBUG_INFO,("scropen: success \n"));
return 0;
}
int scrclose(dev_t dev, int flag, int mode, struct lwp *l)
{
#if 0
struct scr_softc *sc = device_lookup_private(&scr_cd, SCRUNIT(dev));
#endif
KERN_DEBUG (scrdebug, SCRCLOSE_DEBUG_INFO,
("scrclose: called for minor device %d flag 0x%x\n",
SCRUNIT(dev), flag));
#if 0
if (sc->open)
{
scrClkInit();
initStates(sc);
sc->open = false;
}
else
{
KERN_DEBUG (scrdebug, SCRCLOSE_DEBUG_INFO,("\t scrclose, device not open\n"));
}
#endif
KERN_DEBUG (scrdebug, SCRCLOSE_DEBUG_INFO,("scrclose exiting\n"));
return(0);
}
int
scrioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
struct scr_softc* sc = device_lookup_private(&scr_cd, SCRUNIT(dev));
int error = 0;
int masterDoneRetries= 0;
int done;
ScrStatus * pIoctlStatus;
ScrOff * pIoctlOff;
u_int savedInts;
int s;
KERN_DEBUG (scrdebug, SCRIOCTL_DEBUG_INFO,
("scrioctl: called for device 0x%x, command 0x%lx, "
"flag 0x%x\n",
SCRUNIT(dev), cmd, flag));
switch (cmd)
{
case SCRIOSTATUS:
pIoctlStatus = (ScrStatus*)data;
if (scrGetDetect())
{
savedInts = disable_interrupts(I32_bit | F32_bit);
if (sc->masterS == msIdleOn)
{
pIoctlStatus->status = CARD_ON;
}
else
{
ASSERT(sc->masterS == msIdleOff);
pIoctlStatus->status = CARD_INSERTED;
}
restore_interrupts(savedInts);
}
else
{
pIoctlStatus->status = CARD_REMOVED;
}
break;
case SCRIOON:
sc->pIoctlOn = (ScrOn*)data;
while (1)
{
s = splhigh();
if(!hatLock)
{
hatLock = true;
splx(s);
break;
}
splx(s);
tsleep(&tsleepIdent ,PZERO,"hat", 1);
}
if(!scrGetDetect())
{
initStates(sc);
cardOff(sc);
sc->pIoctlOn->status = ERROR_CARD_REMOVED;
}
else if(sc->masterS == msIdleOn)
{
sc->pIoctlOn->status = ERROR_CARD_ON;
}
else
{
sc->masterDone = false;
sc->bigTrouble = false;
scrClkStart (sc,400);
savedInts = disable_interrupts(I32_bit | F32_bit);
masterSM(sc,mcOn);
restore_interrupts(savedInts);
while (1)
{
if(masterDoneRetries >= MAX_FIQ_TIME * hz)
{
savedInts = disable_interrupts(I32_bit | F32_bit);
scrClkInit();
initStates(sc);
cardOff(sc);
sc->status = ERROR_CARD_REMOVED;
sc->masterDone = true;
restore_interrupts(savedInts);
}
masterDoneRetries++;
savedInts = disable_interrupts(I32_bit | F32_bit);
done = sc->masterDone;
restore_interrupts(savedInts);
if(done)
{
break;
}
tsleep(&tsleepIdent ,PZERO,"hat", 1);
}
scrClkStop();
if (sc->status == ERROR_OK)
{
sc->clkCountStartRecv = CLK_COUNT_START;
sc->clkCountDataRecv = sc->clkCountStartRecv * START_2_DATA;
sc->clkCountDataSend = CLK_COUNT_DATA;
}
if (sc->masterS != msIdleOn)
{
cardOff(sc);
}
sc->pIoctlOn->status = sc->status;
}
s = splhigh();
ASSERT(hatlock);
hatLock = false;
splx(s);
if (sc->pIoctlOn->status != ERROR_OK)
{
sc->pIoctlOn->atrLen = 0;
}
break;
case SCRIOOFF:
pIoctlOff = (ScrOff*)data;
initStates(sc);
cardOff(sc);
pIoctlOff->status = ERROR_OK;
break;
case SCRIOT0:
sc->pIoctlT0 = (ScrT0*)data;
while (1)
{
s = splhigh();
if(!hatLock)
{
hatLock = true;
splx(s);
break;
}
splx(s);
tsleep(&tsleepIdent ,PZERO,"hat", 1);
}
if(!scrGetDetect())
{
initStates(sc);
cardOff(sc);
sc->pIoctlT0->status = ERROR_CARD_REMOVED;
}
else if(sc->masterS == msIdleOff)
{
sc->pIoctlT0->status = ERROR_CARD_OFF;
}
else
{
sc->masterDone = false;
sc->bigTrouble = false;
scrClkStart (sc,sc->clkCountDataSend);
savedInts = disable_interrupts(I32_bit | F32_bit);
if (sc->pIoctlT0->writeBuffer)
{
masterSM(sc,mcT0DataSend);
}
else
{
masterSM(sc,mcT0DataRecv);
}
restore_interrupts(savedInts);
while (1)
{
if(masterDoneRetries >= MAX_FIQ_TIME * hz)
{
savedInts = disable_interrupts(I32_bit | F32_bit);
scrClkInit();
initStates(sc);
cardOff(sc);
sc->status = ERROR_CARD_REMOVED;
sc->masterDone = true;
restore_interrupts(savedInts);
}
masterDoneRetries++;
savedInts = disable_interrupts(I32_bit | F32_bit);
done = sc->masterDone;
restore_interrupts(savedInts);
if(done)
{
break;
}
tsleep(&tsleepIdent ,PZERO,"hat", 1);
}
scrClkStop();
sc->pIoctlT0->status = sc->status;
}
s = splhigh();
hatLock = false;
splx(s);
if (sc->pIoctlT0->status != ERROR_OK)
{
sc->pIoctlT0->dataLen = 0;
}
break;
default:
KERN_DEBUG (scrdebug, SCRIOCTL_DEBUG_INFO,("\t scrioctl: unknown command, ENOTTY \n"));
error = ENOTTY;
break;
}
KERN_DEBUG (scrdebug, SCRIOCTL_DEBUG_INFO,
("scrioctl: exiting with sc->status %d\n", error));
return (error);
}
static void masterSM(struct scr_softc * sc,int cmd)
{
if (sc->bigTrouble) return;
switch (sc->masterS)
{
case msIdleOff:
switch (cmd)
{
case mcOn:
if (scrGetDetect())
{
sc->status = 0;
sc->convention = CONVENTION_UNKNOWN;
sc->protocolType = 0;
sc->N = N_DEFAULT;
sc->Fi = Fi_DEFAULT;
sc->Di = Di_DEFAULT;
sc->Wi = Wi_DEFAULT;
sc->cardFreq = CARD_FREQ_DEF;
sc->clkCountStartRecv = CLK_COUNT_START;
sc->clkCountDataRecv = sc->clkCountStartRecv * START_2_DATA;
sc->clkCountDataSend = CLK_COUNT_DATA;
sc->masterS = msColdReset;
coldResetSM(sc,crcStart);
}
else
{
sc->status = ERROR_CARD_REMOVED;
sc->masterDone = true;
}
break;
default:
INVALID_STATE_CMD(sc,sc->masterS,cmd);
break;
}
break;
case msColdReset:
switch (cmd)
{
case mcColdReset:
sc->masterS = msATR;
ATRSM(sc,atrcStart);
break;
default:
INVALID_STATE_CMD(sc,sc->masterS,cmd);
break;
}
break;
case msATR:
switch (cmd)
{
case mcATR:
if(sc->status == ERROR_OK)
{
sc->masterS = msIdleOn;
}
else
{
sc->masterS = msIdleOff;
}
sc->masterDone = true;
break;
default:
INVALID_STATE_CMD(sc,sc->masterS,cmd);
break;
}
break;
case msIdleOn:
switch (cmd)
{
case mcT0DataSend:
sc->status = ERROR_OK;
sc->masterS = msT0Send;
t0SendSM(sc,t0scStart);
break;
case mcT0DataRecv:
sc->status = ERROR_OK;
sc->masterS = msT0Recv;
t0RecvSM(sc,t0rcStart);
break;
default:
INVALID_STATE_CMD(sc,sc->masterS,cmd);
break;
}
break;
case msT0Send:
switch (cmd)
{
case mcT0Send:
sc->masterS = msIdleOn;
sc->masterDone = true;
break;
default:
INVALID_STATE_CMD(sc,sc->masterS,cmd);
break;
}
break;
case msT0Recv:
switch (cmd)
{
case mcT0Recv:
sc->pIoctlT0->dataLen = sc->dataCount;
sc->masterS = msIdleOn;
sc->masterDone = true;
break;
default:
INVALID_STATE_CMD(sc,sc->masterS,cmd);
break;
}
break;
default:
INVALID_STATE_CMD(sc,sc->masterS,cmd);
break;
}
}
static void t0SendSM (struct scr_softc * sc, int cmd)
{
if (sc->bigTrouble) return;
if (cmd == t0scTWorkWaiting ||
cmd == gcT0RecvByteErr ||
cmd == gcT0SendByteErr
)
{
switch(cmd)
{
case t0scTWorkWaiting:
ASSERT(sc->t0SendS != t0ssIdle);
t0SendByteSM(sc,t0sbcAbort);
t0RecvByteSM(sc,t0rbcAbort);
sc->status = ERROR_WORK_WAITING;
break;
case gcT0RecvByteErr:
case gcT0SendByteErr:
scrUntimeout(t0SendSM, sc, t0scTWorkWaiting);
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendS,cmd);
break;
}
sc->t0SendS = t0ssIdle;
masterSM(sc,mcT0Send);
return;
}
switch (sc->t0SendS)
{
case t0ssIdle:
switch (cmd)
{
case t0scStart:
sc->t0SendS = t0ssSendHeader;
sc->t0ByteParent = t0SendSM;
sc->commandCount = 0;
sc->dataCount = 0;
sc->dataMax = sc->pIoctlT0->command[CMD_BUF_DATA_LEN_OFF];
sc->dataByte = sc->pIoctlT0->command[sc->commandCount];
t0SendByteSM(sc,t0sbcStart);
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendS,cmd);
break;
}
break;
case t0ssSendHeader:
switch (cmd)
{
case gcT0SendByte:
sc->commandCount++;
if (sc->commandCount < CMD_BUF_LEN)
{
sc->dataByte = sc->pIoctlT0->command[sc->commandCount];
t0SendByteSM(sc,t0sbcStart);
}
else
{
ASSERT(sc->commandCount == CMD_BUF_LEN);
sc->t0SendS = t0ssRecvProcedure;
scrTimeout(t0SendSM,sc,t0scTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendS,cmd);
break;
}
break;
case t0ssRecvProcedure:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(t0SendSM, sc,t0scTWorkWaiting);
if ( (sc->dataByte == sc->pIoctlT0->command[CMD_BUF_INS_OFF]) ||
(sc->dataByte == (sc->pIoctlT0->command[CMD_BUF_INS_OFF] ^ 0x01)) )
{
ASSERT(sc->dataCount < sc->dataMax);
sc->t0SendS = t0ssSendData;
sc->dataByte = sc->pIoctlT0->data[sc->dataCount];
t0SendByteSM(sc,t0sbcStart);
sc->dataCount++;
}
else if ((sc->dataByte == (sc->pIoctlT0->command[CMD_BUF_INS_OFF] ^ 0xFF)) ||
(sc->dataByte == (sc->pIoctlT0->command[CMD_BUF_INS_OFF] ^ 0xFE)) )
{
ASSERT(sc->dataCount < sc->dataMax);
sc->t0SendS = t0ssSendByte;
sc->dataByte = sc->pIoctlT0->data[ sc->dataCount];
t0SendByteSM(sc,t0sbcStart);
sc->dataCount++;
}
else if (sc->dataByte == 0x60)
{
t0RecvByteSM(sc,t0rbcStart);
scrTimeout(t0SendSM,sc,t0scTWorkWaiting,T_WORK_WAITING);
}
#ifdef ORIGINAL_SW1_CODE
else if ( ((sc->dataByte & 0xf0) == 0x60) || ((sc->dataByte & 0xf0) == 0x90)
&&
sc->dataByte != 0x60)
#else
else if ( ( ((sc->dataByte & 0xf0) == 0x60) || ((sc->dataByte & 0xf0) == 0x90) )
&&
sc->dataByte != 0x60)
#endif
{
sc->pIoctlT0->sw1 = sc->dataByte;
sc->t0SendS = t0ssRecvSW2;
t0RecvByteSM(sc,t0rbcStart);
scrTimeout(t0SendSM,sc,t0scTWorkWaiting,T_WORK_WAITING);
}
else
{
sc->status = ERROR_BAD_PROCEDURE_BYTE;
sc->t0SendS = t0ssIdle;
masterSM(sc,mcT0Send);
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendS,cmd);
break;
}
break;
case t0ssSendByte:
switch (cmd)
{
case gcT0SendByte:
if (sc->dataCount < sc->dataMax)
{
sc->t0SendS = t0ssRecvProcedure;
}
else
{
ASSERT(sc->dataCount == sc->dataMax);
sc->t0SendS = t0ssRecvSW1;
}
t0RecvByteSM(sc,t0rbcStart);
scrTimeout(t0SendSM,sc,t0scTWorkWaiting,T_WORK_WAITING);
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendS,cmd);
break;
}
break;
case t0ssSendData:
switch (cmd)
{
case gcT0SendByte:
if (sc->dataCount < sc->dataMax)
{
sc->t0SendS = t0ssSendData;
sc->dataByte = sc->pIoctlT0->data[ sc->dataCount];
t0SendByteSM(sc,t0sbcStart);
sc->dataCount++;
}
else
{
ASSERT(sc->dataCount == sc->dataMax);
sc->t0SendS = t0ssRecvSW1;
t0RecvByteSM(sc,t0rbcStart);
scrTimeout(t0SendSM,sc,t0scTWorkWaiting,T_WORK_WAITING);
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendS,cmd);
break;
}
break;
case t0ssRecvSW1:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(t0SendSM, sc,t0scTWorkWaiting);
sc->pIoctlT0->sw1 = sc->dataByte;
sc->t0SendS = t0ssRecvSW2;
t0RecvByteSM(sc,t0rbcStart);
scrTimeout(t0SendSM,sc,t0scTWorkWaiting,T_WORK_WAITING);
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendS,cmd);
break;
}
break;
case t0ssRecvSW2:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(t0SendSM, sc,t0scTWorkWaiting);
sc->pIoctlT0->sw2 = sc->dataByte;
sc->t0SendS = t0ssIdle;
masterSM(sc,mcT0Send);
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendS,cmd);
break;
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendS,cmd);
break;
}
}
static void t0RecvSM (struct scr_softc * sc,int cmd)
{
if (sc->bigTrouble) return;
if (cmd == t0rcTWorkWaiting ||
cmd == gcT0RecvByteErr ||
cmd == gcT0SendByteErr )
{
switch(cmd)
{
case t0rcTWorkWaiting:
ASSERT(sc->t0RecvS != t0rsIdle);
t0SendByteSM(sc,t0sbcAbort);
t0RecvByteSM(sc,t0rbcAbort);
sc->status = ERROR_WORK_WAITING;
break;
case gcT0RecvByteErr:
case gcT0SendByteErr:
scrUntimeout(t0RecvSM, sc,t0rcTWorkWaiting);
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvS,cmd);
break;
}
sc->t0RecvS = t0rsIdle;
masterSM(sc,mcT0Recv);
return;
}
switch (sc->t0RecvS)
{
case t0rsIdle:
switch (cmd)
{
case t0rcStart:
sc->t0RecvS = t0rsSendHeader;
sc->t0ByteParent = t0RecvSM;
sc->commandCount = 0;
sc->dataCount = 0;
sc->dataMax = sc->pIoctlT0->command[CMD_BUF_DATA_LEN_OFF];
if (sc->dataMax == 0)
{
sc->dataMax = 256;
}
sc->dataByte = sc->pIoctlT0->command[sc->commandCount];
t0SendByteSM(sc,t0sbcStart);
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvS,cmd);
break;
}
break;
case t0rsSendHeader:
switch (cmd)
{
case gcT0SendByte:
sc->commandCount++;
if (sc->commandCount < CMD_BUF_LEN)
{
sc->dataByte = sc->pIoctlT0->command[sc->commandCount];
t0SendByteSM(sc,t0sbcStart);
}
else
{
ASSERT(sc->commandCount == CMD_BUF_LEN);
sc->t0RecvS = t0rsRecvProcedure;
scrTimeout(t0RecvSM,sc,t0rcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvS,cmd);
break;
}
break;
case t0rsRecvProcedure:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(t0RecvSM, sc,t0rcTWorkWaiting);
if ( (sc->dataByte == sc->pIoctlT0->command[CMD_BUF_INS_OFF]) ||
(sc->dataByte == (sc->pIoctlT0->command[CMD_BUF_INS_OFF] ^ 0x01)) )
{
ASSERT(sc->dataCount < sc->dataMax);
sc->t0RecvS = t0rsRecvData;
scrTimeout(t0RecvSM,sc,t0rcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
else if ((sc->dataByte == (sc->pIoctlT0->command[CMD_BUF_INS_OFF] ^ 0xFF)) ||
(sc->dataByte == (sc->pIoctlT0->command[CMD_BUF_INS_OFF] ^ 0xFE)) )
{
ASSERT(sc->dataCount < sc->dataMax);
sc->t0RecvS = t0rsRecvByte;
scrTimeout(t0RecvSM,sc,t0rcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
else if (sc->dataByte == 0x60)
{
t0RecvByteSM(sc,t0rbcStart);
scrTimeout(t0RecvSM,sc,t0rcTWorkWaiting,T_WORK_WAITING);
}
#ifdef ORIGINAL_SW1_CODE
else if ( ((sc->dataByte & 0xf0) == 0x60) || ((sc->dataByte & 0xf0) == 0x90)
&&
sc->dataByte != 0x60)
#else
else if ( ( ((sc->dataByte & 0xf0) == 0x60) || ((sc->dataByte & 0xf0) == 0x90) )
&&
sc->dataByte != 0x60)
#endif
{
sc->pIoctlT0->sw1 = sc->dataByte;
sc->t0RecvS = t0rsRecvSW2;
t0RecvByteSM(sc,t0rbcStart);
scrTimeout(t0RecvSM,sc,t0rcTWorkWaiting,T_WORK_WAITING);
}
else
{
sc->status = ERROR_BAD_PROCEDURE_BYTE;
sc->t0RecvS = t0rsIdle;
masterSM(sc,mcT0Recv);
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvS,cmd);
break;
}
break;
case t0rsRecvByte:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(t0RecvSM, sc,t0rcTWorkWaiting);
sc->pIoctlT0->data[sc->dataCount] = sc->dataByte;
sc->dataCount++;
if (sc->dataCount < sc->dataMax)
{
sc->t0RecvS = t0rsRecvProcedure;
}
else
{
ASSERT(sc->dataCount == sc->dataMax);
sc->t0RecvS = t0rsRecvSW1;
}
scrTimeout(t0RecvSM,sc,t0rcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvS,cmd);
break;
}
break;
case t0rsRecvData:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(t0RecvSM, sc,t0rcTWorkWaiting);
sc->pIoctlT0->data[sc->dataCount] = sc->dataByte;
sc->dataCount++;
if (sc->dataCount >= sc->dataMax)
{
KERN_DEBUG (scrdebug, T0_RECV_SM_DEBUG_INFO,("\t\tt0RecvSM: changing state to t0rsRecvSW1\n"));
ASSERT(sc->dataCount == sc->dataMax);
sc->t0RecvS = t0rsRecvSW1;
}
scrTimeout(t0RecvSM,sc,t0rcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvS,cmd);
break;
}
break;
case t0rsRecvSW1:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(t0RecvSM, sc,t0rcTWorkWaiting);
sc->pIoctlT0->sw1 = sc->dataByte;
sc->t0RecvS = t0rsRecvSW2;
t0RecvByteSM(sc,t0rbcStart);
scrTimeout(t0RecvSM,sc,t0rcTWorkWaiting,T_WORK_WAITING);
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvS,cmd);
break;
}
break;
case t0rsRecvSW2:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(t0RecvSM, sc,t0rcTWorkWaiting);
sc->pIoctlT0->sw2 = sc->dataByte;
sc->t0RecvS = t0rsIdle;
masterSM(sc,mcT0Recv);
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvS,cmd);
break;
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvS,cmd);
break;
}
}
static void coldResetSM(struct scr_softc * sc,int cmd)
{
if (sc->bigTrouble) return;
switch (sc->coldResetS)
{
case crsIdle:
switch (cmd)
{
case crcStart:
scrSetReset(true);
scrSetClock(true);
scrSetDataHighZ();
scrSetPower(true);
scrTimeout(coldResetSM,sc,crcT2,T_t2);
sc->coldResetS = crsT2Wait;
break;
default:
INVALID_STATE_CMD(sc,sc->masterS,cmd);
break;
}
break;
case crsT2Wait:
switch (cmd)
{
case crcT2:
scrSetReset(false);
sc->coldResetS = crsIdle;
masterSM(sc,mcColdReset);
break;
default:
INVALID_STATE_CMD(sc,sc->masterS,cmd);
break;
}
break;
default:
INVALID_STATE_CMD(sc,sc->coldResetS,cmd);
break;
}
}
static void ATRSM (struct scr_softc * sc,int cmd)
{
int lc;
int tck;
if (sc->bigTrouble) return;
if (cmd == atrcT3 ||
cmd == atrcTWorkWaiting ||
cmd == gcT0RecvByteErr
)
{
switch(cmd)
{
case atrcT3:
scrUntimeout (ATRSM,sc,atrcTWorkWaiting);
sc->status = ERROR_ATR_T3;
t0RecvByteSM(sc,t0rbcAbort);
break;
case atrcTWorkWaiting:
scrUntimeout (ATRSM,sc,atrcT3);
sc->status = ERROR_WORK_WAITING;
t0RecvByteSM(sc,t0rbcAbort);
break;
case gcT0RecvByteErr:
scrUntimeout (ATRSM,sc,atrcT3);
scrUntimeout (ATRSM,sc,atrcTWorkWaiting);
break;
default:
INVALID_STATE_CMD(sc,sc->ATRS,cmd);
break;
}
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
return;
}
switch (sc->ATRS)
{
case atrsIdle:
switch (cmd)
{
case atrcStart:
sc->ATRS = atrsTS;
sc->pIoctlOn->atrLen = 0;
sc->t0ByteParent = ATRSM;
scrTimeout(ATRSM,sc,atrcT3,T_t3 *2);
t0RecvByteSM(sc,t0rbcStart);
break;
default:
INVALID_STATE_CMD(sc,sc->ATRS,cmd);
break;
}
break;
case atrsTS:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(ATRSM,sc,atrcT3);
sc->pIoctlOn->atrBuf[sc->pIoctlOn->atrLen] = sc->dataByte;
sc->pIoctlOn->atrLen++;
if(sc->pIoctlOn->atrLen >= ATR_BUF_MAX)
{
#ifdef SCR_DEBUG
DEBUGGER;
#endif
sc->status = ERROR_ATR_TCK;
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
}
else
{
sc->ATRS = atrsT0;
scrTimeout(ATRSM,sc,atrcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
break;
default:
INVALID_STATE_CMD(sc,sc->ATRS,cmd);
break;
}
break;
case atrsT0:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(ATRSM,sc,atrcTWorkWaiting);
sc->pIoctlOn->atrBuf[sc->pIoctlOn->atrLen] = sc->dataByte;
sc->pIoctlOn->atrLen++;
if(sc->pIoctlOn->atrLen >= ATR_BUF_MAX)
{
#ifdef SCR_DEBUG
printf("atrLen >= ATR_BUF_MAX\n");
DEBUGGER;
#endif
sc->status = ERROR_ATR_TCK;
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
}
else
{
sc->atrY = sc->dataByte & 0xf0;
sc->atrK = sc->dataByte & 0x0f;
sc->atrTABCDx = 1;
sc->atrKCount = 1;
if (!ISSET(sc->atrY,ATR_Y_TD))
{
sc->protocolType = PROTOCOL_T0;
}
if (sc->atrY)
{
sc->ATRS = atrsTABCD;
scrTimeout(ATRSM,sc,atrcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
else if (sc->atrK)
{
sc->ATRS = atrsTK;
scrTimeout(ATRSM,sc,atrcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
else if (sc->protocolType != PROTOCOL_T0)
{
sc->ATRS = atrsTCK;
scrTimeout(ATRSM,sc,atrcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
else
{
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
}
}
break;
default:
INVALID_STATE_CMD(sc,sc->ATRS,cmd);
break;
}
break;
case atrsTABCD:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(ATRSM,sc,atrcTWorkWaiting);
sc->pIoctlOn->atrBuf[sc->pIoctlOn->atrLen] = sc->dataByte;
sc->pIoctlOn->atrLen++;
if(sc->pIoctlOn->atrLen >= ATR_BUF_MAX)
{
#ifdef SCR_DEBUG
printf("atrLen >= ATR_BUF_MAX\n");
DEBUGGER;
#endif
sc->status = ERROR_ATR_TCK;
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
}
else
{
if (sc->atrY & ATR_Y_TA)
{
sc->atrY &= ~ATR_Y_TA;
if (sc->atrTABCDx == 1)
{
sc->Fi = FI2Fi[((sc->dataByte >> 4) & 0x0f)];
if (sc->Fi == 0)
{
sc->status = ERROR_ATR_FI_INVALID;
sc->Fi = Fi_DEFAULT;
}
sc->Di = DI2Di[(sc->dataByte & 0x0f)];
if (sc->Di == 0)
{
sc->status = ERROR_ATR_DI_INVALID;
sc->Di = Di_DEFAULT;
}
}
}
else if (sc->atrY & ATR_Y_TB)
{
sc->atrY &= ~ATR_Y_TB;
}
else if (sc->atrY & ATR_Y_TC)
{
sc->atrY &= ~ATR_Y_TC;
if (sc->atrTABCDx == 1)
{
sc->N = sc->dataByte;
}
if (sc->atrTABCDx == 2)
{
sc->Wi = sc->dataByte;
}
}
else
{
ASSERT(sc->atrY & ATR_Y_TD);
sc->atrY &= ~ATR_Y_TD;
sc->atrY = sc->dataByte;
sc->atrY &= 0xf0;
sc->atrTABCDx++;
sc->protocolType = (1 << (sc->dataByte &0x0f));
}
if (sc->atrY)
{
scrTimeout(ATRSM,sc,atrcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
else if (sc->atrK)
{
sc->ATRS = atrsTK;
scrTimeout(ATRSM,sc,atrcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
else if (sc->protocolType != PROTOCOL_T0)
{
sc->ATRS = atrsTCK;
scrTimeout(ATRSM,sc,atrcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
else
{
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
}
}
break;
default:
INVALID_STATE_CMD(sc,sc->ATRS,cmd);
break;
}
break;
case atrsTK:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(ATRSM,sc,atrcTWorkWaiting);
sc->pIoctlOn->atrBuf[sc->pIoctlOn->atrLen] = sc->dataByte;
sc->pIoctlOn->atrLen++;
if(sc->pIoctlOn->atrLen >= ATR_BUF_MAX)
{
#ifdef SCR_DEBUG
printf("atrLen >= ATR_BUF_MAX\n");
DEBUGGER;
#endif
sc->status = ERROR_ATR_TCK;
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
}
else
{
if (sc->atrKCount < sc->atrK)
{
sc->atrKCount++;
scrTimeout(ATRSM,sc,atrcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
else if (sc->protocolType != PROTOCOL_T0)
{
sc->ATRS = atrsTCK;
scrTimeout(ATRSM,sc,atrcTWorkWaiting,T_WORK_WAITING);
t0RecvByteSM(sc,t0rbcStart);
}
else
{
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
}
}
break;
default:
INVALID_STATE_CMD(sc,sc->ATRS,cmd);
break;
}
break;
case atrsTCK:
switch (cmd)
{
case gcT0RecvByte:
scrUntimeout(ATRSM,sc,atrcTWorkWaiting);
sc->pIoctlOn->atrBuf[sc->pIoctlOn->atrLen] = sc->dataByte;
sc->pIoctlOn->atrLen++;
if(sc->pIoctlOn->atrLen >= ATR_BUF_MAX)
{
#ifdef SCR_DEBUG
printf("atrLen >= ATR_BUF_MAX\n");
DEBUGGER;
#endif
sc->status = ERROR_ATR_TCK;
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
}
else
{
tck = 0;
for (lc = 1; lc < sc->pIoctlOn->atrLen-1; lc++)
{
tck ^= sc->pIoctlOn->atrBuf[lc];
}
if (tck == sc->pIoctlOn->atrBuf[sc->pIoctlOn->atrLen-1])
{
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
}
else
{
sc->status = ERROR_ATR_TCK;
sc->ATRS = atrsIdle;
masterSM(sc,mcATR);
}
}
break;
default:
INVALID_STATE_CMD(sc,sc->ATRS,cmd);
break;
}
break;
default:
INVALID_STATE_CMD(sc,sc->ATRS,cmd);
break;
}
}
static void t0RecvByteSM(struct scr_softc* sc,int cmd)
{
if (sc->bigTrouble) return;
if (cmd == t0rbcAbort)
{
scrUntimeout(t0RecvByteSM, sc,t0rbcTFindStartEdge);
scrUntimeout(t0RecvByteSM, sc,t0rbcTFindStartMid);
scrUntimeout(t0RecvByteSM, sc,t0rbcTClockData);
scrUntimeout(t0RecvByteSM, sc,t0rbcTErrorStart);
scrUntimeout(t0RecvByteSM, sc,t0rbcTErrorStop);
scrSetDataHighZ();
sc->t0RecvByteS = t0rbsIdle;
return;
}
switch (sc->t0RecvByteS)
{
case t0rbsIdle:
switch (cmd)
{
case t0rbcStart:
sc->shiftBits = 0;
sc->shiftByte = 0;
sc->shiftParity = 0;
sc->shiftParityCount = 0;
scrClkAdj(sc->clkCountStartRecv);
if (1)
{
scrTimeout(t0RecvByteSM,sc,t0rbcTFindStartEdge,sc->clkCountStartRecv);
sc->t0RecvByteS = t0rbsFindStartEdge;
}
else
{
scrTimeout(t0RecvByteSM,sc,t0rbcTFindStartMid,sc->clkCountStartRecv);
sc->t0RecvByteS = t0rbsFindStartMid;
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvByteS,cmd);
break;
}
break;
case t0rbsFindStartEdge:
switch (cmd)
{
case t0rbcTFindStartEdge:
if (scrGetData())
{
scrTimeout(t0RecvByteSM,sc,t0rbcTFindStartEdge,sc->clkCountStartRecv);
}
else
{
scrTimeout(t0RecvByteSM,sc,t0rbcTFindStartMid,sc->clkCountStartRecv * 2);
sc->t0RecvByteS = t0rbsFindStartMid;
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvByteS,cmd);
break;
}
break;
case t0rbsFindStartMid:
switch (cmd)
{
case t0rbcTFindStartMid:
if (scrGetData())
{
scrTimeout(t0RecvByteSM,sc,t0rbcTFindStartEdge,sc->clkCountStartRecv);
sc->t0RecvByteS = t0rbsFindStartEdge;
}
else
{
TOGGLE_TEST_PIN();
scrTimeout(t0RecvByteSM,sc,t0rbcTClockData,sc->clkCountDataRecv);
sc->t0RecvByteS = t0rbsClockData;
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvByteS,cmd);
break;
}
break;
case t0rbsClockData:
TOGGLE_TEST_PIN();
switch (cmd)
{
case t0rbcTClockData:
if (sc->shiftBits < 8)
{
if (sc->convention == CONVENTION_INVERSE ||
sc->convention == CONVENTION_UNKNOWN)
{
sc->shiftByte <<= 1;
sc->shiftByte &= 0xfe;
if (!scrGetData())
{
sc->shiftByte |= 0x01;
sc->shiftParity++;
}
}
else
{
ASSERT(sc->convention == CONVENTION_DIRECT);
sc->shiftByte = sc->shiftByte >> 1;
sc->shiftByte &= 0x7f;
if (scrGetData())
{
sc->shiftParity++;
sc->shiftByte |= 0x80;
}
}
sc->shiftBits++;
if (sc->convention == CONVENTION_UNKNOWN &&
sc->shiftBits == 3 &&
sc->shiftByte == 4 &&
sc->cardFreq == CARD_FREQ_DEF)
{
sc->cardFreq = CARD_FREQ_DEF / 2;
sc->clkCountStartRecv = sc->clkCountStartRecv *2;
sc->clkCountDataRecv = sc->clkCountDataRecv *2;
sc->clkCountDataSend = sc->clkCountDataSend *2;
sc->shiftParity = 0;
sc->shiftByte = 0;
sc->shiftBits = 1;
scrTimeout(t0RecvByteSM,sc,t0rbcTClockData,(sc->clkCountDataRecv * 3) /4);
}
else
{
scrTimeout(t0RecvByteSM,sc,t0rbcTClockData,sc->clkCountDataRecv);
}
}
else if (sc->shiftBits == 8)
{
if (sc->convention == CONVENTION_INVERSE)
{
if (!scrGetData())
{
sc->shiftParity++;
}
}
else if (sc->convention == CONVENTION_DIRECT)
{
if (scrGetData())
{
sc->shiftParity++;
}
}
else
{
ASSERT(sc->convention == CONVENTION_UNKNOWN);
if (sc->shiftByte == CONVENIONT_INVERSE_ID && scrGetData())
{
sc->convention = CONVENTION_INVERSE;
sc->shiftParity = 0;
}
else if (sc->shiftByte == CONVENTION_DIRECT_ID && scrGetData())
{
sc->shiftByte = CONVENTION_DIRECT_FIX;
sc->convention = CONVENTION_DIRECT;
sc->shiftParity = 0;
}
else
{
sc->shiftParity = 1;
}
}
if ((sc->shiftParity & 01) == 0)
{
sc->shiftBits++;
scrTimeout(t0RecvByteSM,sc,t0rbcTClockData,sc->clkCountDataRecv);
}
else
{
if (sc->shiftParityCount < PARITY_ERROR_MAX)
{
sc->shiftParityCount++;
scrTimeout(t0RecvByteSM,sc,t0rbcTErrorStart,sc->clkCountDataRecv);
sc->t0RecvByteS = t0rbsSendError;
}
else
{
sc->status = ERROR_PARITY;
sc->t0RecvByteS = t0rbsIdle;
sc->t0ByteParent(sc,gcT0RecvByteErr);
}
}
}
else
{
sc->dataByte = sc->shiftByte;
sc->t0RecvByteS = t0rbsIdle;
sc->t0ByteParent(sc,gcT0RecvByte);
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvByteS,cmd);
break;
}
break;
case t0rbsSendError:
TOGGLE_TEST_PIN();
switch (cmd)
{
case t0rbcTErrorStart:
scrSetData(false);
scrTimeout(t0RecvByteSM,sc,t0rbcTErrorStop,sc->clkCountDataRecv * 2);
break;
case t0rbcTErrorStop:
scrSetData(true);
sc->shiftBits = 0;
sc->shiftByte = 0;
sc->shiftParity = 0;
scrTimeout(t0RecvByteSM,sc,t0rbcTFindStartEdge,1);
sc->t0RecvByteS = t0rbsFindStartEdge;
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvByteS,cmd);
break;
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0RecvByteS,cmd);
break;
}
}
static void t0SendByteSM (struct scr_softc * sc,int cmd)
{
if (sc->bigTrouble) return;
if (cmd == t0sbcAbort)
{
scrUntimeout(t0SendByteSM, sc, t0sbcTGuardTime);
scrUntimeout(t0SendByteSM, sc, t0sbcTClockData);
scrUntimeout(t0SendByteSM, sc, t0sbcTError);
scrSetDataHighZ();
return;
}
switch (sc->t0SendByteS)
{
case t0sbsIdle:
switch (cmd)
{
case t0sbcStart:
sc->shiftBits = 0;
sc->shiftParity = 0;
sc->shiftParityCount = 0;
sc->shiftByte = sc->dataByte;
scrClkAdj(sc->clkCountDataSend);
if (0)
{
scrTimeout(t0SendByteSM,sc,t0sbcTClockData,sc->clkCountDataSend);
scrSetData(false);
sc->t0SendByteS = t0sbsClockData;
}
else
{
scrTimeout(t0SendByteSM,sc,t0sbcTGuardTime,sc->clkCountDataSend * (12 + sc->N));
sc->t0SendByteS = t0sbsWaitGuardTime;
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendByteS,cmd);
break;
}
break;
case t0sbsWaitGuardTime:
switch (cmd)
{
case t0sbcTGuardTime:
TOGGLE_TEST_PIN();
scrTimeout(t0SendByteSM,sc,t0sbcTClockData,sc->clkCountDataSend);
scrSetData(false);
sc->t0SendByteS = t0sbsClockData;
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendByteS,cmd);
break;
}
break;
case t0sbsClockData:
switch (cmd)
{
case t0sbcTClockData:
TOGGLE_TEST_PIN();
if (sc->shiftBits < 8)
{
if (sc->convention == CONVENTION_INVERSE)
{
if (sc->shiftByte & 0x80)
{
scrSetData(false);
sc->shiftParity++;
}
else
{
scrSetData(true);
}
sc->shiftByte = sc->shiftByte << 1;
}
else
{
ASSERT(sc->convention == CONVENTION_DIRECT);
if (sc->shiftByte & 0x01)
{
scrSetData(true);
sc->shiftParity++;
}
else
{
scrSetData(false);
}
sc->shiftByte = sc->shiftByte >> 1;
}
sc->shiftBits++;
scrTimeout(t0SendByteSM,sc,t0sbcTClockData,sc->clkCountDataSend);
}
else if (sc->shiftBits == 8)
{
if ( ((sc->shiftParity & 0x01) && (sc->convention == CONVENTION_INVERSE)) ||
(!(sc->shiftParity & 0x01) && (sc->convention == CONVENTION_DIRECT)) )
{
scrSetData(false);
}
else
{
scrSetData(true);
}
sc->shiftBits++;
scrTimeout(t0SendByteSM,sc,t0sbcTClockData,sc->clkCountDataSend);
}
else
{
ASSERT(sc->shiftBits > 8);
scrSetData(true);
scrTimeout(t0SendByteSM,sc,t0sbcTError,sc->clkCountDataSend);
sc->t0SendByteS = t0sbsWaitError;
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendByteS,cmd);
break;
}
break;
case t0sbsWaitError:
switch (cmd)
{
case t0sbcTError:
if (scrGetData())
{
sc->t0SendByteS = t0sbsIdle;
sc->t0ByteParent(sc,gcT0SendByte);
}
else
{
if (sc->shiftParityCount < PARITY_ERROR_MAX)
{
sc->shiftParityCount++;
scrTimeout(t0SendByteSM,sc,t0sbcTResend,sc->clkCountDataSend * 2);
sc->t0SendByteS = t0sbsWaitResend;
}
else
{
sc->status = ERROR_PARITY;
sc->t0SendByteS = t0sbsIdle;
sc->t0ByteParent(sc,gcT0SendByteErr);
}
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendByteS,cmd);
break;
}
break;
case t0sbsWaitResend:
switch (cmd)
{
case t0sbcTResend:
sc->shiftBits = 0;
sc->shiftParity = 0;
sc->shiftByte = sc->dataByte;
scrTimeout(t0SendByteSM,sc,t0sbcTClockData,sc->clkCountDataSend);
scrSetData(false);
sc->t0SendByteS = t0sbsClockData;
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendByteS,cmd);
break;
}
break;
default:
INVALID_STATE_CMD(sc, sc->t0SendByteS,cmd);
break;
}
}
static void cardOff (struct scr_softc * sc)
{
scrSetReset(true);
scrSetDataHighZ();
scrSetClock(false);
scrSetPower(false);
}
static void scrClkInit(void)
{
int lc;
Callout *c;
Callout *new;
scrClkCallTodo.c_next = NULL;
scrClkCallFree = &scrClkCalloutArray[0];
c = scrClkCallFree;
for (lc = 1; lc < SCR_CLK_CALLOUT_COUNT; lc++)
{
new = &scrClkCalloutArray[lc];
c->c_next = new;
c = new;
}
c->c_next = NULL;
}
static void scrClkStart(struct scr_softc * sc,int countPerTick)
{
u_int savedInts;
savedInts = disable_interrupts(I32_bit | F32_bit);
ASSERT(scrClkCallTodo.c_next == NULL);
ASSERT(!scrClkEnable);
scrClkEnable = 1;
scrClkCount = countPerTick;
hatClkOn(countPerTick,
hatClkIrq,
0xdeadbeef,
hatStack + HATSTACKSIZE - sizeof(unsigned),
myHatWedge);
restore_interrupts(savedInts);
}
static void scrClkAdj (int count)
{
u_int savedInts;
if (count != scrClkCount)
{
savedInts = disable_interrupts(I32_bit | F32_bit);
ASSERT(scrClkEnable);
scrClkCount = count;
hatClkAdjust(count);
restore_interrupts(savedInts);
}
}
static void scrClkStop(void)
{
u_int savedInts;
savedInts = disable_interrupts(I32_bit | F32_bit);
ASSERT(scrClkEnable);
scrClkEnable = 0;
ASSERT(scrClkCallTodo.c_next == NULL);
hatClkOff();
restore_interrupts(savedInts);
}
static void hatClkIrq(int x)
{
register Callout *p1;
register int needsoft =0;
register Callout *c;
register int arg;
register void (*func)(struct scr_softc*,int);
struct scr_softc * sc;
ASSERT(scrClkEnable);
for (p1 = scrClkCallTodo.c_next; p1 != NULL; p1 = p1->c_next)
{
p1->c_time -= scrClkCount;
if (p1->c_time > 0)
{
break;
}
needsoft = 1;
if (p1->c_time == 0)
{
break;
}
}
if (needsoft)
{
while ((c = scrClkCallTodo.c_next) != NULL && c->c_time <= 0)
{
func = c->c_func;
sc = c->c_sc;
arg = c->c_arg;
scrClkCallTodo.c_next = c->c_next;
c->c_next = scrClkCallFree;
scrClkCallFree = c;
(*func)(sc,arg);
}
}
}
static void myHatWedge(int nFIQs)
{
#ifdef DEBUG
printf("myHatWedge: nFIQ = %d\n",nFIQs);
#endif
}
static void
scrTimeout(
void (*ftn)(struct scr_softc*,int),
struct scr_softc* sc,
int arg,
int count)
{
register Callout *new, *p, *t;
ASSERT(scrClkEnable);
if (count <= 0)
{
count = 1;
}
if (scrClkCallFree == NULL)
{
panic("timeout table full");
}
new = scrClkCallFree;
scrClkCallFree = new->c_next;
new->c_sc = sc;
new->c_arg = arg;
new->c_func = ftn;
for (p = &scrClkCallTodo; (t = p->c_next) != NULL && count > t->c_time; p = t)
{
if (t->c_time > 0)
{
count -= t->c_time;
}
}
new->c_time = count;
if (t != NULL)
{
t->c_time -= count;
}
p->c_next = new;
new->c_next = t;
}
static void
scrUntimeout(
void (*ftn)(struct scr_softc*, int),
struct scr_softc* sc,
int arg)
{
register Callout *p, *t;
ASSERT(scrClkEnable);
for (p = &scrClkCallTodo; (t = p->c_next) != NULL; p = t)
{
if (t->c_func == ftn && t->c_sc == sc && t->c_arg == arg)
{
if (t->c_next && t->c_time > 0)
{
t->c_next->c_time += t->c_time;
}
p->c_next = t->c_next;
t->c_next = scrClkCallFree;
scrClkCallFree = t;
break;
}
}
}
#ifdef SCR_DEBUG
void invalidStateCmd (struct scr_softc* sc,int state,int cmd,int line)
{
printf("INVALID_STATE_CMD: sc = %X, state = %X, cmd = %X, line = %d\n",sc,state,cmd,line);
DEBUGGER;
}
char * getText(int x)
{
switch (x)
{
case mcOn: return "mcOn";
case mcT0DataSend: return "mcT0DataSend";
case mcT0DataRecv: return "mcT0DataRecv";
case mcColdReset: return "mcColdReset";
case mcATR: return "mcATR";
case mcT0Send: return "mcT0Send";
case mcT0Recv: return "mcT0Recv";
case msIdleOff: return "msIdleOff";
case msColdReset: return "msColdReset";
case msATR: return "msATR";
case msIdleOn: return "msIdleOn";
case msT0Send: return "msT0Send";
case msT0Recv: return "msT0Recv";
case t0scStart: return "t0scStart";
case t0scTWorkWaiting: return "t0scTWorkWaiting";
case t0ssIdle: return "t0ssIdle";
case t0ssSendHeader: return "t0ssSendHeader";
case t0ssRecvProcedure: return "t0ssRecvProcedu";
case t0ssSendByte: return "t0ssSendByte";
case t0ssSendData: return "t0ssSendData";
case t0ssRecvSW1: return "t0ssRecvSW1";
case t0ssRecvSW2: return "t0ssRecvSW2";
case t0rcStart: return "t0rcStart";
case t0rcTWorkWaiting: return "t0rcTWorkWaiting";
case t0rsIdle: return "t0rsIdle";
case t0rsSendHeader: return "t0rsSendHeader";
case t0rsRecvProcedure: return "t0rsRecvProcedure";
case t0rsRecvByte: return "t0rsRecvByte";
case t0rsRecvData: return "t0rsRecvData";
case t0rsRecvSW1: return "t0rsRecvSW1";
case t0rsRecvSW2: return "t0rsRecvSW2";
case atrcStart: return "atrcStart";
case atrcT3: return "0x0b04";
case atrcTWorkWaiting: return "atrcTWorkWaiting";
case atrsIdle: return "atrsIdle";
case atrsTS: return "atrsTS";
case atrsT0: return "atrsT0";
case atrsTABCD: return "atrsTABCD";
case atrsTK: return "atrsTK";
case atrsTCK: return "atrsTCK";
case t0rbcStart: return "t0rbcStart";
case t0rbcAbort: return "t0rbcAbort";
case t0rbcTFindStartEdge:return "t0rbcTFindStartEdge";
case t0rbcTFindStartMid: return "t0rbcTFindStartMid";
case t0rbcTClockData: return "t0rbcTClockData";
case t0rbcTErrorStart: return "t0rbcTErrorStart";
case t0rbcTErrorStop: return "t0rbcTErrorStop";
case t0rbsIdle: return "t0rbsIdle";
case t0rbsFindStartEdge: return "t0rbcFindStartEdge";
case t0rbsFindStartMid: return "t0rbcFindStartMid";
case t0rbsClockData: return "t0rbcClockData";
case t0rbsSendError: return "t0rbcSendError";
case t0sbcStart: return "t0sbcStart";
case t0sbcAbort: return "t0sbcAbort";
case t0sbcTGuardTime: return "t0sbcTGuardTime";
case t0sbcTClockData: return "t0sbcTClockData";
case t0sbcTError: return "t0sbcTError";
case t0sbcTResend: return "t0sbcTResend";
case t0sbsIdle: return "t0sbsIdle";
case t0sbsClockData: return "t0sbsClockData";
case t0sbsWaitError: return "t0sbsWaitError";
case t0sbsWaitResend: return "t0sbsWaitResend";
case t0sbsWaitGuardTime: return "t0sbsWaitGuardTime";
case gcT0RecvByte: return "gcT0RecvByte";
case gcT0RecvByteErr: return "gcT0RecvByteErr";
case gcT0SendByte: return "gcT0SendByte";
case gcT0SendByteErr: return "gcT0SendByteErr";
case crcStart: return "crcStart";
case crcT2: return "crcT2";
default:
printf("unknown case, %x\n",x);
break;
}
return "???";
}
#endif