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

📄 pciscc.c

📁 高速同步串口芯片PEB20534的驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
				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 + -