📄 pciscc.c
字号:
WriteL(chipctl.io_base+SCCBASE[chan]+CCR1,devctl[chan].ccr1);
}
devctl[chan].tx_mailbox = *iqp;
*(iqp++) = 0;
if (iqp == devctl[chan].iq_tx+CFG_IQLEN)
iqp = devctl[chan].iq_tx;
}
devctl[chan].iq_tx_next = iqp;
/* process RX queue */
pciscc_isr_receiver(chan);
iqp = devctl[chan].iq_rx_next;
while(iqp && *iqp) {
/* statistics only */
if ((*iqp & SCCIV_SCC) && (*iqp & SCCIV_RDO))
devctl[chan].stats.rx_bufferoverflow++;
if ((*iqp & SCCIV_SCC) && (*iqp & SCCIV_RFO))
devctl[chan].stats.rx_bufferoverflow++;
if ((*iqp & SCCIV_SCC) && (*iqp & SCCIV_FLEX))
devctl[chan].stats.rx_bufferoverflow++;
devctl[chan].rx_mailbox = *iqp;
*(iqp++) = 0;
if (iqp == devctl[chan].iq_rx+CFG_IQLEN)
iqp = devctl[chan].iq_rx;
}
devctl[chan].iq_rx_next = iqp;
}
enable();
if (status) {
if (chipctl.irq & 8) /* If irq > 7, send EOI to second PIC. */
outp(PIC1MODE, PICEOI);
outp(PIC0MODE, PICEOI); /* Send EOI to first PIC. */
} else
chipctl.oldvect();
}
/* ------------------------------------------------------------------------- */
/* called by interrupt handler root when RX interrupt occurred */
void pciscc_isr_receiver(int chan)
{
struct rx_desc_t *rdp;
unsigned long status;
unsigned char rdsb;
unsigned int bno;
unsigned int valid;
unsigned int rx_cnt = 0;
L1FRAME far * rx_new;
if (!devctl[chan].initialized)
return;
rdp = devctl[chan].dq_rx_next;
while (rdp->result & C) {
status = rdp->result;
bno = (status >> 16) & 0x1fff;
valid = 1; /* we assume frame valid */
if ((status & RA) || (bno < 5) || (bno > CFG_MTU) || !(status & FE) || (rdp->feptr != FP_TO_PHYS(rdp))) {
valid = 0; /* aborted or invalid length */
} else {
rdsb = rdp->l1_frame->frame[bno-1];
if (!(rdsb & SB_VFR)) /* incorrect bit length */
valid = 0;
if (rdsb & SB_RDO) /* data overflow */
valid = 0;
if (!(rdsb & SB_CRC)) /* CRC error */
valid = 0;
if (rdsb & SB_RAB) /* receive message aborted */
valid = 0;
}
/* OK, this is a little bit tricky. We have to make sure
* that every descriptor has a buffer assigned. Thus we
* can only release a buffer to the link layer if we get
* a new one in turn before. */
if (valid) {
if ((rx_new = alloc_frame()) != NULL) {
rdp->l1_frame->len = bno-1;
rdp->l1_frame->kanal = chan;
rdp->l1_frame->txdelay = 0;
*(chipctl.rx_put++) = rdp->l1_frame;
if (chipctl.rx_put == chipctl.rx_queue+CFG_L1_BUF)
chipctl.rx_put = chipctl.rx_queue;
rdp->l1_frame = rx_new;
rdp->dataptr = FP_TO_PHYS(rx_new->frame);
devctl[chan].stats.rx_frames++;
} else
devctl[chan].stats.rx_overrun++;
}
rdp->flags = CFG_MTU*NO;
rdp->result = 0;
rdp->feptr = 0;
rdp = rdp->next;
rx_cnt++;
}
devctl[chan].dq_rx_next = rdp;
/*
* tell DMAC last available descriptor - keep up one
* descriptor space for security (paranoia) (...->prev->prev)
*/
if (rx_cnt) {
switch (chan) {
case 0: WriteL(chipctl.io_base+CH0LRDA,FP_TO_PHYS(rdp->prev->prev));
break;
case 1: WriteL(chipctl.io_base+CH1LRDA,FP_TO_PHYS(rdp->prev->prev));
break;
case 2: WriteL(chipctl.io_base+CH2LRDA,FP_TO_PHYS(rdp->prev->prev));
break;
case 3: WriteL(chipctl.io_base+CH3LRDA,FP_TO_PHYS(rdp->prev->prev));
break;
}
}
}
/* ------------------------------------------------------------------------- */
/* called by IRQ handler root when a TX descriptor was completed */
void pciscc_isr_txcleanup(int chan)
{
struct tx_desc_t *tdp;
if (!devctl[chan].initialized)
return;
tdp = devctl[chan].dq_tx_cleanup;
while (tdp->result & C) {
/* clean up all (C)omplete descriptors */
free_frame(tdp->l1_frame);
tdp->l1_frame = NULL;
tdp->flags = FE | (8*NO); /* dummy */
tdp->dataptr = FP_TO_PHYS(chipctl.dma_buffers->dummy);
tdp->result = 0;
tdp = tdp->next;
devctl[chan].stats.tx_frames++;
}
devctl[chan].dq_tx_cleanup = tdp;
}
/* ------------------------------------------------------------------------- */
#pragma argsused
u16 init_device(i16 argc, char *argv[])
{
char *ch;
int i;
pstr("\nBayCom/Flexnet PCISCC>4 driver V"); pstr(version);
pstr(", (C)2001/2002 St.Koehler DH1DM\n");
chipctl.card_num = 0; chipctl.txd_scale = 10;
for (i = 1; i < argc; i++) {
ch = argv[i];
if (*ch == '-' || *ch == '/') ch++;
if (!strncmpi(ch,"c=",2))
chipctl.card_num = atoi(ch+2);
else
if (!strncmpi(ch,"t=",2))
chipctl.txd_scale = atoi(ch+2);
else
if (*ch == '?' || *ch == 'h' || *ch == 'H') {
pstr(helptext);
return 99;
} else {
pstr("\nUnknown Option: '"); pstr(ch); pstr("\'\n");
pstr(helptext);
return 1;
}
}
return pciscc_chip_init();
}
/* ------------------------------------------------------------------------- */
byte l1_ch_active(byte kanal)
{
return 1;
}
/* ------------------------------------------------------------------------- */
void l1_exit(void)
{
int chan;
for (chan=0; chan < 4; chan++)
pciscc_channel_close(chan);
pciscc_chip_close();
}
/* ------------------------------------------------------------------------- */
u16 l1_get_ch_cnt(void)
{
return 4;
}
/* ------------------------------------------------------------------------- */
byte l1_init_kanal(byte kanal, u16 baud, u16 mode)
{
return pciscc_channel_open(kanal, (unsigned long)baud * 100, mode);
}
/* ------------------------------------------------------------------------- */
char far *l1_ident(byte kanal)
{
return "PCISCC";
}
/* ------------------------------------------------------------------------- */
char far *l1_version(byte kanal)
{
return version;
}
/* ------------------------------------------------------------------------- */
L1_STATISTICS far *l1_stat(byte kanal, byte delete)
{
L1_STATISTICS *p = &devctl[kanal].stats;
if (delete)
p->tx_error = p->rx_overrun = p->rx_bufferoverflow =
p->tx_frames = p->rx_frames = p->io_error = 0;
return p;
}
/* ------------------------------------------------------------------------- */
/* report channel state (PTT/DCD) */
byte l1_ch_state(byte kanal)
{
/*
0x40 RxB RxBuffer ist nicht leer
0x20 PTT Sender ist an
0x10 DCD Empf刵ger ist aktiv
0x08 FDX Kanal ist Vollduplex, kann also immer empfangen
0x04 TBY Sender ist nicht bereit, z.B. wegen Calibrate
*/
unsigned long l;
unsigned int state = 0;
if (!devctl[kanal].initialized)
return 0;
ReadL(chipctl.io_base+SCCBASE[kanal]+STAR);
l = ReadL(chipctl.io_base+SCCBASE[kanal]+STAR);
if (!(l & CD))
state |= CH_DCD;
if (chipctl.rx_get != chipctl.rx_put)
state |= CH_RXB;
switch(devctl[kanal].txstate) {
case TX_DELAY:
case TX_XMIT:
case TX_TAIL:
state |= CH_PTT;
break;
case TX_CAL:
state |= CH_TBY | CH_PTT;
break;
case TX_RESET:
state |= CH_TBY;
break;
}
return state;
}
/* ------------------------------------------------------------------------- */
u16 l1_scale(byte kanal)
{
return devctl[kanal].scale;
}
/* ------------------------------------------------------------------------- */
void l1_tx_calib(byte kanal, byte minutes)
{
unsigned long timer;
unsigned long bits;
bits = devctl[kanal].bitrate * minutes * 60;
if (devctl[kanal].txstate == TX_RESET) {
devctl[kanal].stats.tx_error++;
return;
}
if (devctl[kanal].txstate == TX_STALL) {
WriteL(chipctl.io_base+SCCBASE[kanal]+CMDR,XRES);
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT);
devctl[kanal].txstate = TX_IDLE;
}
if ((devctl[kanal].txstate == TX_CAL) && !minutes) {
WriteL(chipctl.io_base+SCCBASE[kanal]+TIMR,MIN_FLAGS*TVALUE);
WriteL(chipctl.io_base+SCCBASE[kanal]+CMDR,STI);
}
if (minutes) {
devctl[kanal].ccr1 |= RTS;
WriteL(chipctl.io_base+SCCBASE[kanal]+CCR1,devctl[kanal].ccr1);
WriteL(chipctl.io_base+SCCBASE[kanal]+TIMR,bits*TVALUE);
WriteL(chipctl.io_base+SCCBASE[kanal]+CMDR,STI);
devctl[kanal].txstate = TX_CAL;
}
}
/* ------------------------------------------------------------------------- */
void set_led(byte kanal, byte ledcode)
{
}
/* ------------------------------------------------------------------------- */
L1FRAME far *l1_rx_frame()
{
disable();
free_frame(rx_frame);
rx_frame = NULL;
if (chipctl.rx_get != chipctl.rx_put) {
rx_frame = *(chipctl.rx_get++);
if (chipctl.rx_get == chipctl.rx_queue+CFG_L1_BUF)
chipctl.rx_get = chipctl.rx_queue;
}
enable();
return rx_frame;
}
/* ------------------------------------------------------------------------- */
L1FRAME far *l1_get_framebuf(byte kanal)
{
struct tx_desc_t *tdp;
disable();
tdp = devctl[kanal].dq_tx_last;
if (devctl[kanal].initialized && !tx_frame)
if ((tdp->next->l1_frame == NULL) && (tdp->next->next->l1_frame == NULL))
tx_frame = alloc_frame();
enable();
return tx_frame;
}
/* ------------------------------------------------------------------------- */
/* enqueue/xmit pre-allocated TX frame buffer */
byte l1_tx_frame(void)
{
struct tx_desc_t *tdp;
unsigned long txd_bits;
unsigned long timer;
int chan;
int enqueued = 0;
/* TX frame assigned ? */
if (!tx_frame)
return 0;
/* get channel number */
chan = tx_frame->kanal;
/* check if TX is in RESET state */
if (devctl[chan].txstate == TX_RESET)
devctl[chan].stats.tx_error++;
/* if data underrun, reset TX now */
if (devctl[chan].txstate == TX_STALL) {
WriteL(chipctl.io_base+SCCBASE[chan]+CMDR,XRES);
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT);
devctl[chan].txstate = TX_IDLE;
}
disable();
/* check for TX queue space */
tdp = devctl[chan].dq_tx_last->next;
if ((tdp->l1_frame == NULL) && (tdp->next->l1_frame == NULL)) {
/* insert TX frame buffer into descriptor queue */
if ((devctl[chan].txstate == TX_IDLE) ||
(devctl[chan].txstate == TX_DELAY) ||
(devctl[chan].txstate == TX_XMIT) ||
(devctl[chan].txstate == TX_TAIL)) {
tdp->l1_frame = tx_frame;
tdp->dataptr = FP_TO_PHYS(tx_frame->frame);
tdp->flags = FE | (NO * (tx_frame->len & 0x1fff));
devctl[chan].dq_tx_last = tdp;
devctl[chan].tx_enqueued++;
enqueued++;
}
/* calculate tx keyup delay */
txd_bits = devctl[chan].bitrate * tx_frame->txdelay * chipctl.txd_scale / 1000;
if (txd_bits < MIN_FLAGS) txd_bits = MIN_FLAGS;
/* TX was idle, key up and start txdelay */
if (devctl[chan].txstate == TX_IDLE) {
devctl[chan].txstate=TX_DELAY;
devctl[chan].ccr1 |= RTS;
WriteL(chipctl.io_base+SCCBASE[chan]+CCR1,devctl[chan].ccr1);
WriteL(chipctl.io_base+SCCBASE[chan]+TIMR,txd_bits*TVALUE);
WriteL(chipctl.io_base+SCCBASE[chan]+CMDR,STI);
}
/* update TX DMA register */
if (devctl[chan].txstate == TX_XMIT) {
switch (chan) {
case 0: WriteL(chipctl.io_base+CH0LTDA,FP_TO_PHYS(tdp));
break;
case 1: WriteL(chipctl.io_base+CH1LTDA,FP_TO_PHYS(tdp));
break;
case 2: WriteL(chipctl.io_base+CH2LTDA,FP_TO_PHYS(tdp));
break;
case 3: WriteL(chipctl.io_base+CH3LTDA,FP_TO_PHYS(tdp));
break;
}
}
}
if (!enqueued)
free_frame(tx_frame);
tx_frame = NULL;
enable();
return enqueued;
}
/*------------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -