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

📄 pciscc.c

📁 高速同步串口芯片PEB20534的驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	chipctl.iq_per_next = NULL;
	chipctl.iq_cfg_next = NULL;
}

/* ------------------------------------------------------------------------- */

/*
 * open one channel, the sequence of actions done here was carefully chosen,
 * don't mess with it unless you know exactly what you are doing...
 */
int pciscc_channel_open(int chan, long bitrate, int mode)
{
	unsigned long timer;
	unsigned long l;

	if (!bitrate)
		return 0;
	/* general chip init */
	if (!pciscc_chip_open()) {
		devctl[chan].stats.io_error++;
		return 0;
	}
	if ((bitrate == devctl[chan].bitrate) && (mode == devctl[chan].mode))
		return 1;
	/* reset channel configuration */
	pciscc_channel_close(chan);
	/* RX buffer space check */
	if (avail_frames() < CFG_RX_DESC) {
		devctl[chan].stats.rx_overrun++;
		return 0;
	}
	/* setup bitrate/mode for flexnet internal use */
	devctl[chan].mode = mode;
	devctl[chan].bitrate = bitrate;
	devctl[chan].scale = 614400 / bitrate;
	/* init interrupt and descriptor queues */
	pciscc_init_queues(chan);
	/* stop SCC */
	disable();
	WriteL(chipctl.io_base+SCCBASE[chan]+CCR1,0);
	WriteL(chipctl.io_base+SCCBASE[chan]+CCR2,0);
	WriteL(chipctl.io_base+SCCBASE[chan]+CCR0,0);
	devctl[chan].ccr0 = devctl[chan].ccr1 = devctl[chan].ccr2 = 0;
	WriteL(chipctl.io_base+SCCBASE[chan]+TIMR,0);
	/* set IQ lengths and base addresses */
	l = ReadL(chipctl.io_base+IQLENR1);
	switch (chan) {
	case 0:	WriteL(chipctl.io_base+CH0CFG,MRFI | MTFI | MRERR | MTERR);
		WriteL(chipctl.io_base+IQSCC0RXBAR,FP_TO_PHYS(devctl[chan].iq_rx));
		WriteL(chipctl.io_base+IQSCC0TXBAR,FP_TO_PHYS(devctl[chan].iq_tx));
		l &= 0x0fff0fff;
		l |= (((CFG_IQLEN/32)-1)*IQSCC0RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC0TXLEN);
		break;
	case 1:	WriteL(chipctl.io_base+CH1CFG,MRFI | MTFI | MRERR | MTERR);
		WriteL(chipctl.io_base+IQSCC1RXBAR,FP_TO_PHYS(devctl[chan].iq_rx));
		WriteL(chipctl.io_base+IQSCC1TXBAR,FP_TO_PHYS(devctl[chan].iq_tx));
		l &= 0xf0fff0ff;
		l |= (((CFG_IQLEN/32)-1)*IQSCC1RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC1TXLEN);
		break;
	case 2:	WriteL(chipctl.io_base+CH2CFG,MRFI | MTFI | MRERR | MTERR);
		WriteL(chipctl.io_base+IQSCC2RXBAR,FP_TO_PHYS(devctl[chan].iq_rx));
		WriteL(chipctl.io_base+IQSCC2TXBAR,FP_TO_PHYS(devctl[chan].iq_tx));
		l &= 0xff0fff0f;
		l |= (((CFG_IQLEN/32)-1)*IQSCC2RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC2TXLEN);
		break;
	case 3:	WriteL(chipctl.io_base+CH3CFG,MRFI | MTFI | MRERR | MTERR);
		WriteL(chipctl.io_base+IQSCC3RXBAR,FP_TO_PHYS(devctl[chan].iq_rx));
		WriteL(chipctl.io_base+IQSCC3TXBAR,FP_TO_PHYS(devctl[chan].iq_tx));
		l &= 0xfff0fff0;
		l |= (((CFG_IQLEN/32)-1)*IQSCC3RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC3TXLEN);
		break;
	}
	WriteL(chipctl.io_base+IQLENR1,l);
	enable();
	chipctl.mailbox = MAILBOX_NONE;
	WriteL(chipctl.io_base+GCMDR, AR	/* Action Request */
		| (chan == 0 ? (CFGIQSCC0RX | CFGIQSCC0TX) : 0)
		| (chan == 1 ? (CFGIQSCC1RX | CFGIQSCC1TX) : 0)
		| (chan == 2 ? (CFGIQSCC2RX | CFGIQSCC2TX) : 0)
		| (chan == 3 ? (CFGIQSCC3RX | CFGIQSCC3TX) : 0));
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		if (chipctl.mailbox) break;
	}
	if (chipctl.mailbox != MAILBOX_OK) {	/* mailbox was written by isr */
		devctl[chan].stats.io_error++;
	}
	/* initialize channel's SCC core */
	disable();
	devctl[chan].ccr0 = PU | VIS | PSD;
	devctl[chan].ccr0 |= (mode & MODE_z) ? 0 : 2*SC;
	devctl[chan].ccr0 |= (mode & MODE_r) ? 0 : 6*CM;
	devctl[chan].ccr0 |= (mode & MODE_t) ? 0 : SSEL;
	devctl[chan].ccr1 = ODS | ICD | FCTS | MDS1 | SFLAG;
	devctl[chan].ccr2 = RAC | (3*RFTH) | ITF;
	WriteL(chipctl.io_base+SCCBASE[chan]+CCR0,devctl[chan].ccr0);
	WriteL(chipctl.io_base+SCCBASE[chan]+CCR1,devctl[chan].ccr1);
	WriteL(chipctl.io_base+SCCBASE[chan]+CCR2,devctl[chan].ccr2);
	pciscc_set_baud(chan,(mode & MODE_r) ? bitrate : 16*bitrate);
	WriteL(chipctl.io_base+SCCBASE[chan]+RLCR,RCE | (CFG_MTU*RL));
	/*
	 * all sent | tx device underrun | timer int | tx message repeat |
	 * tx pool ready | rx device overflow | receive FIFO overflow |
	 * frame length exceeded => interrupt mask register
	 */
	WriteL(chipctl.io_base+SCCBASE[chan]+IMR,~(ALLS | XDU | TIN | XMR | XPR | RDO | RFO | FLEX));
	enable();
	/* wait until command executing (CEC) is clear */
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		l = ReadL(chipctl.io_base+SCCBASE[chan]+STAR);
		if (!(l & CEC)) break;
	}
	/* RX and TX SCC reset */
	WriteL(chipctl.io_base+SCCBASE[chan]+CMDR,RRES | XRES);
	devctl[chan].tx_mailbox = 0xffffffff;
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		if (devctl[chan].tx_mailbox != 0xffffffff) break;
	}
	if ((devctl[chan].tx_mailbox & 0x03ffffff) != 0x02001000) {	/* mailbox was written by isr */
		devctl[chan].stats.io_error++;
	}
	/* initialize DMAC channel's RX */
	disable();
	switch (chan) {
	case 0:	WriteL(chipctl.io_base+CH0CFG,IDR);
		WriteL(chipctl.io_base+CH0BRDA,FP_TO_PHYS(devctl[chan].dq_rx));
		WriteL(chipctl.io_base+CH0FRDA,FP_TO_PHYS(devctl[chan].dq_rx));
		WriteL(chipctl.io_base+CH0LRDA,FP_TO_PHYS(devctl[chan].dq_rx_next->prev->prev));
		break;
	case 1:	WriteL(chipctl.io_base+CH1CFG,IDR);
		WriteL(chipctl.io_base+CH1BRDA,FP_TO_PHYS(devctl[chan].dq_rx));
		WriteL(chipctl.io_base+CH1FRDA,FP_TO_PHYS(devctl[chan].dq_rx));
		WriteL(chipctl.io_base+CH1LRDA,FP_TO_PHYS(devctl[chan].dq_rx_next->prev->prev));
		break;
	case 2:	WriteL(chipctl.io_base+CH2CFG,IDR);
		WriteL(chipctl.io_base+CH2BRDA,FP_TO_PHYS(devctl[chan].dq_rx));
		WriteL(chipctl.io_base+CH2FRDA,FP_TO_PHYS(devctl[chan].dq_rx));
		WriteL(chipctl.io_base+CH2LRDA,FP_TO_PHYS(devctl[chan].dq_rx_next->prev->prev));
		break;
	case 3:	WriteL(chipctl.io_base+CH3CFG,IDR);
		WriteL(chipctl.io_base+CH3BRDA,FP_TO_PHYS(devctl[chan].dq_rx));
		WriteL(chipctl.io_base+CH3FRDA,FP_TO_PHYS(devctl[chan].dq_rx));
		WriteL(chipctl.io_base+CH3LRDA,FP_TO_PHYS(devctl[chan].dq_rx_next->prev->prev));
		break;
	}
	enable();
	chipctl.mailbox = MAILBOX_NONE;
	WriteL(chipctl.io_base+GCMDR,AR);
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		if (chipctl.mailbox) break;
	}
	if (chipctl.mailbox != MAILBOX_OK)	/* mailbox was written by isr */
		devctl[chan].stats.io_error++;
	/* mask all DMAC interrupts (needed) */
	switch (chan) {
	case 0:	WriteL(chipctl.io_base+CH0CFG,MRFI | MTFI | MRERR | MTERR);
		break;
	case 1:	WriteL(chipctl.io_base+CH1CFG,MRFI | MTFI | MRERR | MTERR);
		break;
	case 2:	WriteL(chipctl.io_base+CH2CFG,MRFI | MTFI | MRERR | MTERR);
		break;
	case 3:	WriteL(chipctl.io_base+CH3CFG,MRFI | MTFI | MRERR | MTERR);
		break;
	}
	/* wait until command executing (CEC) is clear */
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		l = ReadL(chipctl.io_base+SCCBASE[chan]+STAR);
		if (!(l & CEC)) break;
	}
	/* SCC core TX reset (again) */
	WriteL(chipctl.io_base+SCCBASE[chan]+CMDR,XRES);
	devctl[chan].tx_mailbox = 0xffffffff;
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		if (devctl[chan].tx_mailbox != 0xffffffff) break;
	}
	if ((devctl[chan].tx_mailbox & 0x03ffffff) != 0x02001000) {	/* mailbox was written by isr */
		devctl[chan].stats.io_error++;
	}
	/*
	 * initialize DMAC's TX channel, FI must stay masked all the time
	 * even during operation, see device errata 03/99
	 */
	switch (chan) {
	case 0:	WriteL(chipctl.io_base+CH0CFG,IDT | MTFI);
		WriteL(chipctl.io_base+CH0BTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		WriteL(chipctl.io_base+CH0FTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		WriteL(chipctl.io_base+CH0LTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		break;
	case 1:	WriteL(chipctl.io_base+CH1CFG,IDT | MTFI);
		WriteL(chipctl.io_base+CH1BTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		WriteL(chipctl.io_base+CH1FTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		WriteL(chipctl.io_base+CH1LTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		break;
	case 2:	WriteL(chipctl.io_base+CH2CFG,IDT | MTFI);
		WriteL(chipctl.io_base+CH2BTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		WriteL(chipctl.io_base+CH2FTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		WriteL(chipctl.io_base+CH2LTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		break;
	case 3:	WriteL(chipctl.io_base+CH3CFG,IDT | MTFI);
		WriteL(chipctl.io_base+CH3BTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		WriteL(chipctl.io_base+CH3FTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		WriteL(chipctl.io_base+CH3LTDA,FP_TO_PHYS(devctl[chan].dq_tx));
		break;
	}
	chipctl.mailbox = MAILBOX_NONE;
	WriteL(chipctl.io_base+GCMDR,AR);
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		if (chipctl.mailbox) break;
	}
	if (chipctl.mailbox == MAILBOX_OK)	/* mailbox was written by isr */
		devctl[chan].txstate=TX_IDLE;
	else
		devctl[chan].stats.io_error++;
	devctl[chan].tx_enqueued = 0;
	devctl[chan].initialized = 1;
	return 1;
}

/* ------------------------------------------------------------------------- */

/* close one channel - don't mess with it either */
void pciscc_channel_close(int chan)
{
	struct rx_desc_t *rdp;
	unsigned long timer;
	unsigned long l;

	if (!devctl[chan].initialized)
		return;
	devctl[chan].initialized=0;
	/* at first stop timer */
	WriteL(chipctl.io_base+SCCBASE[chan]+TIMR,0);
	/* wait until command executing (CEC) is clear */
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		l = ReadL(chipctl.io_base+SCCBASE[chan]+STAR);
		if (!(l & CEC)) break;
	}
	/* RX and TX SCC reset */
	WriteL(chipctl.io_base+SCCBASE[chan]+CMDR,RRES | XRES);
	devctl[chan].tx_mailbox = 0xffffffff;
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		if (devctl[chan].tx_mailbox != 0xffffffff) break;
	}
	if ((devctl[chan].tx_mailbox & 0x03ffffff) != 0x02001000) {	/* mailbox was written by isr */
		devctl[chan].stats.io_error++;
	}
	/* stop SCC core */
	WriteL(chipctl.io_base+SCCBASE[chan]+CCR1,0);
	WriteL(chipctl.io_base+SCCBASE[chan]+CCR2,0);
	WriteL(chipctl.io_base+SCCBASE[chan]+CCR0,0);
	devctl[chan].ccr0 = devctl[chan].ccr1 = devctl[chan].ccr2 = 0;
	devctl[chan].bitrate = devctl[chan].mode = 0;
	/*
	 * Give the isr some time to "refill" the rx-dq
	 * we _MUST_ guarantee that the DMAC-RX is _NOT_ in
	 * hold state when issuing the RESET command, otherwise the DMAC
	 * will crash. (DSCC-4 Rev. <= 2.1)
	 * In addition to that we may only issue a RESET if channel is
	 * currently really initialized, otherwise something horrible will
	 * result.
	 */
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT);
	/* OK, now we should be ready to put the DMAC into reset state */
	switch (chan) {
	case 0:	WriteL(chipctl.io_base+CH0CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
		break;
	case 1:	WriteL(chipctl.io_base+CH1CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
		break;
	case 2:	WriteL(chipctl.io_base+CH2CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
		break;
	case 3: WriteL(chipctl.io_base+CH3CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
		break;
	}
	chipctl.mailbox = MAILBOX_NONE;
	WriteL(chipctl.io_base+GCMDR,AR);
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		if (chipctl.mailbox) break;
	}
	if (chipctl.mailbox != MAILBOX_OK)	/* mailbox was written by isr */
		devctl[chan].stats.io_error++;
	devctl[chan].txstate = TX_RESET;
	/* clear IQs */
	l = ReadL(chipctl.io_base+IQLENR1);
	switch (chan) {
	case 0:	l &= 0x0fff0fff;
		WriteL(chipctl.io_base+IQLENR1,l);
		WriteL(chipctl.io_base+IQSCC0RXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
		WriteL(chipctl.io_base+IQSCC0TXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
		break;
	case 1: l &= 0xf0fff0ff;
		WriteL(chipctl.io_base+IQLENR1,l);
		WriteL(chipctl.io_base+IQSCC1RXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
		WriteL(chipctl.io_base+IQSCC1TXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
		break;
	case 2: l &= 0xff0fff0f;
		WriteL(chipctl.io_base+IQLENR1,l);
		WriteL(chipctl.io_base+IQSCC2RXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
		WriteL(chipctl.io_base+IQSCC2TXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
		break;
	case 3: l &= 0xfff0fff0;
		WriteL(chipctl.io_base+IQLENR1,l);
		WriteL(chipctl.io_base+IQSCC3RXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
		WriteL(chipctl.io_base+IQSCC3TXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
		break;
	}
	chipctl.mailbox = MAILBOX_NONE;
	WriteL(chipctl.io_base+GCMDR,AR
		| (chan == 0 ? (CFGIQSCC0RX | CFGIQSCC0TX) : 0)
		| (chan == 1 ? (CFGIQSCC1RX | CFGIQSCC1TX) : 0)
		| (chan == 2 ? (CFGIQSCC2RX | CFGIQSCC2TX) : 0)
		| (chan == 3 ? (CFGIQSCC3RX | CFGIQSCC3TX) : 0));
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		if (chipctl.mailbox) break;
	}
	if (chipctl.mailbox != MAILBOX_OK) {	/* mailbox was written by isr */
		devctl[chan].stats.io_error++;
	}
	rdp = devctl[chan].dq_rx;
	while(rdp->l1_frame) {
		free_frame(rdp->l1_frame);
		rdp->l1_frame = NULL;
		rdp = rdp->next;
	}
	devctl[chan].iq_rx_next=NULL;
	devctl[chan].iq_tx_next=NULL;
}

/* ------------------------------------------------------------------------- */

/* interrupt handler root */
void interrupt pciscc_isr(void)
{
	unsigned long status;
	unsigned long *iqp;
	int chan;

	disable();
	status = ReadL(chipctl.io_base+GSTAR);
	WriteL(chipctl.io_base+GSTAR,status);		/* ack' irq */
	/* process peripheral queue */
	iqp = chipctl.iq_per_next;
	while(iqp && *iqp) {
		*(iqp++) = 0;
		if (iqp == chipctl.iq_per+CFG_IQLEN)
			iqp = chipctl.iq_per;
	}
	chipctl.iq_per_next = iqp;
	/* process configuration queue */
	chipctl.mailbox = MAILBOX_NONE;
	iqp = chipctl.iq_cfg_next;
	while(iqp && *iqp) {
		if ((*iqp) & ARACK)
			chipctl.mailbox = MAILBOX_OK;
		if ((*iqp) & ARF)
			chipctl.mailbox = MAILBOX_FAILURE;
		*(iqp++) = 0;
		if (iqp == chipctl.iq_cfg+CFG_IQLEN)
			iqp = chipctl.iq_cfg;
	}
	chipctl.iq_cfg_next = iqp;
	/* poll channel queues */
	for (chan=0; chan < 4; chan++) {
		/* process TX queue */
		pciscc_isr_txcleanup(chan);
		iqp = devctl[chan].iq_tx_next;
		while(iqp && *iqp) {
			if (*iqp & TIN) {
				/* timer interrupt */
				WriteL(chipctl.io_base+SCCBASE[chan]+TIMR,0);
				/* is there something in the TX queue ? */
				if (devctl[chan].tx_enqueued) {
					devctl[chan].txstate=TX_XMIT;
					switch (chan) {
					case 0:	WriteL(chipctl.io_base+CH0LTDA,FP_TO_PHYS(devctl[chan].dq_tx_last));
						break;
					case 1:	WriteL(chipctl.io_base+CH1LTDA,FP_TO_PHYS(devctl[chan].dq_tx_last));
						break;
					case 2:	WriteL(chipctl.io_base+CH2LTDA,FP_TO_PHYS(devctl[chan].dq_tx_last));
						break;
					case 3:	WriteL(chipctl.io_base+CH3LTDA,FP_TO_PHYS(devctl[chan].dq_tx_last));
						break;
					}
				} else {
					devctl[chan].txstate=TX_IDLE;
					devctl[chan].ccr1 &= ~RTS;
					WriteL(chipctl.io_base+SCCBASE[chan]+CCR1,devctl[chan].ccr1);
				}
			}
			if (*iqp & ALLS) {
				if (devctl[chan].tx_enqueued)
					devctl[chan].tx_enqueued--;
				if (!devctl[chan].tx_enqueued) {
					devctl[chan].txstate=TX_TAIL;
					WriteL(chipctl.io_base+SCCBASE[chan]+TIMR,MIN_FLAGS*TVALUE);
					WriteL(chipctl.io_base+SCCBASE[chan]+CMDR,STI);
				}
			}
			if (*iqp & XDU) {
				/* TX data underrun */
				devctl[chan].stats.tx_error++;
				devctl[chan].txstate=TX_STALL;
				devctl[chan].ccr1 &= ~RTS;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -