253 lines
6.3 KiB
Plaintext
253 lines
6.3 KiB
Plaintext
#help_index "Comm"
|
|
#help_file "::/LT/Doc/Comm.TXZ"
|
|
|
|
#define EXCP_TIMEOUT 0x100
|
|
#define EXCP_RESET 0x101
|
|
|
|
#define CH_XOFF 0x13
|
|
#define CH_XON 0x11
|
|
|
|
#define UART_THR 0
|
|
#define UART_RDR 0
|
|
#define UART_BRDL 0
|
|
#define UART_IER 1
|
|
#define UART_BRDH 1
|
|
#define UART_IIR 2
|
|
#define UART_LCR 3
|
|
#define UART_MCR 4
|
|
#define UART_LSR 5
|
|
#define UART_MSR 6
|
|
|
|
#define COMMf_INCOMING_XOFFED 0
|
|
#define COMMf_INCOMING_XOFFED2 1
|
|
#define COMMf_INCOMING_XOFFED3 2
|
|
#define COMMf_OUTGOING_XOFFED 3
|
|
#define COMMf_TX_XOFF 4
|
|
#define COMMf_TX_XON 5
|
|
|
|
U8 comm_base[5]={0,0x3F8,0x2F8,0x3E8,0x2E8};
|
|
U1Fifo *comm_Rx_fifos[5]={NULL,NULL,NULL,NULL,NULL};
|
|
U1Fifo *comm_Tx_fifos[5]={NULL,NULL,NULL,NULL,NULL};
|
|
U8 comm_flags[5]={0,0,0,0,0};
|
|
LTChnl *comm_chnls[5]={NULL,NULL,NULL,NULL,NULL};
|
|
|
|
public void RmtClose(LTChnl *chnl)
|
|
{
|
|
U8 base;
|
|
U8 old_flags=GetFlags;
|
|
if (!chnl || !chnl->type) return;
|
|
if (chnl->type==LCT_COMM) {
|
|
base=comm_base[chnl->port];
|
|
OutP(base+UART_IER,0);
|
|
Cli;
|
|
if (comm_Rx_fifos[chnl->port]) {
|
|
DelU1Fifo(comm_Rx_fifos[chnl->port]);
|
|
comm_Rx_fifos[chnl->port]=NULL;
|
|
}
|
|
if (comm_Tx_fifos[chnl->port]) {
|
|
DelU1Fifo(comm_Tx_fifos[chnl->port]);
|
|
comm_Tx_fifos[chnl->port]=NULL;
|
|
}
|
|
comm_chnls[chnl->port]=NULL;
|
|
SetFlags(old_flags);
|
|
}
|
|
AFree(chnl);
|
|
}
|
|
|
|
public void CommPutChar(U8 port,U1 b)
|
|
{
|
|
U8 old_flags=GetFlags;
|
|
U8 base=comm_base[port];
|
|
Cli;
|
|
if (b==CH_XOFF)
|
|
Bts(&comm_flags[port],COMMf_TX_XOFF);
|
|
else if (b==CH_XON)
|
|
Bts(&comm_flags[port],COMMf_TX_XON);
|
|
else {
|
|
if (U1FifoCnt(comm_Tx_fifos[port])>comm_Tx_fifos[port]->mask-4) {
|
|
Sti;
|
|
while (U1FifoCnt(comm_Tx_fifos[port])>comm_Tx_fifos[port]->mask>>1)
|
|
SwapInNext;
|
|
Cli;
|
|
}
|
|
if (Bt(&comm_flags[port],COMMf_OUTGOING_XOFFED)) {
|
|
Sti;
|
|
while (Bt(&comm_flags[port],COMMf_OUTGOING_XOFFED))
|
|
SwapInNext;
|
|
Cli;
|
|
}
|
|
if (comm_Tx_fifos[port])
|
|
U1FifoInsert(comm_Tx_fifos[port],b);
|
|
}
|
|
OutP(base+UART_IER,3); //Enable TX & RX IRQ
|
|
SetFlags(old_flags);
|
|
}
|
|
|
|
U8 dc_rx=0,dc_tx=0;
|
|
|
|
void CommRxTxChar(U8 port)
|
|
{
|
|
U8 i=0,ch=0,irq,base=comm_base[port];
|
|
BoolU4 have_one;
|
|
BoolU4 old_raw=Raw(ON);
|
|
if (comm_Rx_fifos[port] &&
|
|
comm_Tx_fifos[port]) {
|
|
while (i++<4) {
|
|
irq=InP(base+UART_IIR);
|
|
if ((irq & 0x07)==4) { //RX IRQ
|
|
ch=InP(base+UART_RDR);
|
|
if (ch==CH_XOFF)
|
|
Bts(&comm_flags[port],COMMf_OUTGOING_XOFFED);
|
|
else if (ch==CH_XON)
|
|
Btr(&comm_flags[port],COMMf_OUTGOING_XOFFED);
|
|
else {
|
|
U1FifoInsert(comm_Rx_fifos[port],ch);
|
|
if (U1FifoCnt(comm_Rx_fifos[port])>comm_Rx_fifos[port]->mask>>1) {
|
|
CommPutChar(port,CH_XOFF);
|
|
Bts(&comm_flags[port],COMMf_INCOMING_XOFFED2);
|
|
Bts(&comm_flags[port],COMMf_INCOMING_XOFFED3);
|
|
}
|
|
}
|
|
} else if ((irq & 0x07)==2) { //TX IRQ
|
|
have_one=TRUE;
|
|
if (Btr(&comm_flags[port],COMMf_TX_XOFF))
|
|
ch=CH_XOFF;
|
|
else if (Btr(&comm_flags[port],COMMf_TX_XON))
|
|
ch=CH_XON;
|
|
else if (!U1FifoRemove(comm_Tx_fifos[port],&ch))
|
|
have_one=FALSE;
|
|
if (have_one) {
|
|
if (ch==CH_XOFF)
|
|
Bts(&comm_flags[port],COMMf_INCOMING_XOFFED);
|
|
else if (ch==CH_XON) {
|
|
if (!Btr(&comm_flags[port],COMMf_INCOMING_XOFFED3)) {
|
|
if (!Btr(&comm_flags[port],COMMf_INCOMING_XOFFED2))
|
|
Btr(&comm_flags[port],COMMf_INCOMING_XOFFED);
|
|
else
|
|
Bts(&comm_flags[port],COMMf_TX_XON);
|
|
} else
|
|
Bts(&comm_flags[port],COMMf_TX_XON);
|
|
}
|
|
OutP(base+UART_THR,ch);
|
|
}
|
|
if (!U1FifoCnt(comm_Tx_fifos[port]) &&
|
|
!Bt(&comm_flags[port],COMMf_INCOMING_XOFFED))
|
|
OutP(base+UART_IER,1); //Enable RX IRQ
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
Raw(old_raw);
|
|
}
|
|
|
|
|
|
void Irq03Handler()
|
|
{
|
|
CommRxTxChar(2);
|
|
CommRxTxChar(4);
|
|
}
|
|
|
|
void Irq04Handler()
|
|
{
|
|
CommRxTxChar(1);
|
|
CommRxTxChar(3);
|
|
}
|
|
|
|
public U1 CommGetChar(U8 port)
|
|
{
|
|
U8 ch=0;
|
|
while (!U1FifoRemove(comm_Rx_fifos[port],&ch))
|
|
SwapInNext;
|
|
if (Bt(&comm_flags[port],COMMf_INCOMING_XOFFED) &&
|
|
U1FifoCnt(comm_Rx_fifos[port])<comm_Rx_fifos[port]->mask>>2)
|
|
CommPutChar(port,CH_XON);
|
|
return ch;
|
|
}
|
|
public BoolU4 CommScanChar(U8 port,U1 *ch)
|
|
{
|
|
U8 ch1=0;
|
|
if (U1FifoPeek(comm_Rx_fifos[port],&ch1)) {
|
|
U1FifoRemove(comm_Rx_fifos[port],&ch1);
|
|
*ch=ch1;
|
|
if (Bt(&comm_flags[port],COMMf_INCOMING_XOFFED) &&
|
|
U1FifoCnt(comm_Rx_fifos[port])<comm_Rx_fifos[port]->mask>>2)
|
|
CommPutChar(port,CH_XON);
|
|
return TRUE;
|
|
} else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void CommRmtPutChar(LTChnl *chnl,U1 b)
|
|
{
|
|
CommPutChar(chnl->port,b);
|
|
}
|
|
|
|
U1 CommRmtGetChar(LTChnl *chnl)
|
|
{
|
|
return CommGetChar(chnl->port);
|
|
}
|
|
|
|
BoolU8 CommRmtScanChar(LTChnl *chnl,U1 *ch)
|
|
{
|
|
return CommScanChar(chnl->port,ch);
|
|
}
|
|
|
|
public LTChnl *CommOpen8N1(U8 port=1,U8 baud=38400)
|
|
{
|
|
LTChnl *chnl=NULL;
|
|
U8 old_flags=GetFlags,base=comm_base[port];
|
|
Cli;
|
|
if (!port || port>4 || comm_chnls[port])
|
|
goto co_exit;
|
|
chnl=AMAllocZ(sizeof(LTChnl));
|
|
comm_chnls[port]=chnl;
|
|
chnl->type=LCT_COMM;
|
|
base=comm_base[port];
|
|
chnl->port=port;
|
|
chnl->baud=baud;
|
|
chnl->PutChar=&CommRmtPutChar;
|
|
chnl->GetChar=&CommRmtGetChar;
|
|
chnl->ScanChar=&CommRmtScanChar;
|
|
if (comm_Rx_fifos[chnl->port])
|
|
DelU1Fifo(comm_Rx_fifos[chnl->port]);
|
|
if (comm_Tx_fifos[chnl->port])
|
|
DelU1Fifo(comm_Tx_fifos[chnl->port]);
|
|
comm_flags[chnl->port]=0;
|
|
comm_Rx_fifos[chnl->port]=NewU1Fifo(0x1000,adam_tss); //must be power of 2
|
|
comm_Tx_fifos[chnl->port]=NewU1Fifo(0x1000,adam_tss); //must be power of 2
|
|
OutP(base+UART_LCR,0); //Set for IER
|
|
OutP(base+UART_IER,0);
|
|
OutP(base+UART_LCR,0x80); //Enable baud rate control
|
|
OutP(base+UART_BRDL,(0x180/(baud/300)) & 0xFF); //LSB
|
|
OutP(base+UART_BRDH,(0x180/(baud/300)) / 256); //MSB
|
|
OutP(base+UART_LCR,3); // 8-none-1
|
|
|
|
InP(base+UART_RDR); //read garbage
|
|
InP(base+UART_LSR);
|
|
|
|
OutP(base+UART_MCR,4);
|
|
OutP(base+UART_IER,0); //DIsable all IRQ
|
|
OutP(base+UART_MCR,0xA); //out2 and rts
|
|
OutP(base+UART_IER,1); //Enable RX IRQ
|
|
|
|
Bts(&comm_flags[chnl->port],COMMf_INCOMING_XOFFED);
|
|
Bts(&comm_flags[chnl->port],COMMf_INCOMING_XOFFED2);
|
|
Bts(&comm_flags[chnl->port],COMMf_INCOMING_XOFFED3);
|
|
CommPutChar(chnl->port,CH_XON);
|
|
co_exit:
|
|
SetFlags(old_flags);
|
|
return chnl;
|
|
}
|
|
|
|
public void CommClose(U8 port)
|
|
{
|
|
LTChnl *chnl=comm_chnls[port];
|
|
RmtClose(chnl);
|
|
}
|
|
|
|
ext[EXT_IRQ03]=&Irq03Handler;
|
|
ext[EXT_IRQ04]=&Irq04Handler;
|
|
|
|
#help_index ""
|
|
|