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

📄 pciscc_drv.c

📁 高速同步串口芯片PEB20534的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	WriteL(pLDI,SCCBASE[2]+IMR,0xffffffff);
	WriteL(pLDI,SCCBASE[3]+IMR,0xffffffff);
	/* queues no longer exist */
	pLDI->iq_per_next = NULL;
	pLDI->iq_cfg_next = NULL;
	/* Shut down ISR routine */
	IoDisconnectInterrupt(pLDI->IrqObject);
	/* Unmap memory */
	MmUnmapIoSpace(pLDI->MappedAddress,pLDI->AddrLen);
	/* Release buffers */
	pciscc_free(pLDI->DmaBuffers);
	/* Print debug message */
	DbgPrint("PCISCC: Interrupt queue error (pciscc_chip_open)\n");
	return STATUS_IO_TIMEOUT;
}

/*
 * close chip, called when last device (channel) of a chip was closed.
 * don't mess up.
 */
VOID pciscc_chip_close(
	IN PLOCAL_DEVICE_INFO pLDI
	)
{
	ULONG chan;

	if (!pLDI->initialized)
		return;
	/* close channels */
	for (chan = 0; chan < 4; chan++)
		pciscc_channel_close(pLDI,chan);
	pLDI->initialized = 0;
	/* global configuration to reset state */
	WriteL(pLDI,GMODE,(4 * PERCFG) | (3 * LCD) | CMODE | OSCPD);
	/* mask all DMAC interrupts */
	WriteL(pLDI,CH0CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(pLDI,CH1CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(pLDI,CH2CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(pLDI,CH3CFG,(MRFI | MTFI | MRERR | MTERR));
	/* SCC cores to reset state */
	WriteL(pLDI,SCCBASE[0]+CCR0,0x00000000);
	WriteL(pLDI,SCCBASE[1]+CCR0,0x00000000);
	WriteL(pLDI,SCCBASE[2]+CCR0,0x00000000);
	WriteL(pLDI,SCCBASE[3]+CCR0,0x00000000);
	/* mask all SCC interrupts */
	WriteL(pLDI,SCCBASE[0]+IMR,0xffffffff);
	WriteL(pLDI,SCCBASE[1]+IMR,0xffffffff);
	WriteL(pLDI,SCCBASE[2]+IMR,0xffffffff);
	WriteL(pLDI,SCCBASE[3]+IMR,0xffffffff);
	/* queues no longer exist */
	pLDI->iq_per_next = NULL;
	pLDI->iq_cfg_next = NULL;
	/* Shut down ISR routine */
	IoDisconnectInterrupt(pLDI->IrqObject);
	/* Unmap memory */
	MmUnmapIoSpace(pLDI->MappedAddress,pLDI->AddrLen);
	/* Release buffers */
	pciscc_free(pLDI->DmaBuffers);
	/* Realease pending RX frames */
	pciscc_clear_rxpending(pLDI);
	pciscc_clear_rxlist(pLDI);
}

/*
 * 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...
 */
NTSTATUS pciscc_channel_open(
	PLOCAL_DEVICE_INFO pLDI,
	ULONG chan,
	ULONG bitrate,
	ULONG mode
	)
{
	PCHANNEL_INFO pChan;
	NTSTATUS Status;
	LARGE_INTEGER	time;
	LARGE_INTEGER	time_expire;
	ULONG l;

	if (!pLDI->initialized)
		return STATUS_NO_SUCH_DEVICE;
	if (!bitrate)
		return STATUS_INVALID_PARAMETER;
	pChan = &pLDI->Channel[chan];
	/* nothing to change */
	if ((bitrate == pChan->bitrate) && (mode == pChan->mode))
		return STATUS_SUCCESS;
	/* reset channel configuration */
	pciscc_channel_close(pLDI,chan);
	/* initialize DMA queues */
	Status = pciscc_init_queues(pLDI,chan);
	if (!NT_SUCCESS(Status))
		return Status;
	/* set bitrate/mode */
	pChan->mode = mode;
	pChan->bitrate = bitrate;
	/* stop SCC */
	WriteL(pLDI,SCCBASE[chan]+CCR1,0);
	WriteL(pLDI,SCCBASE[chan]+CCR2,0);
	WriteL(pLDI,SCCBASE[chan]+CCR0,0);
	pChan->ccr0 = pChan->ccr1 = pChan->ccr2 = 0;
	WriteL(pLDI,SCCBASE[chan]+TIMR,0);
	/* set IQ lengths and base addresses */
	l = ReadL(pLDI,IQLENR1);
	switch (chan) {
	case 0:	WriteL(pLDI,CH0CFG,MRFI | MTFI | MRERR | MTERR);
			WriteL(pLDI,IQSCC0RXBAR,VirtToPhys(pChan->iq_rx));
			WriteL(pLDI,IQSCC0TXBAR,VirtToPhys(pChan->iq_tx));
			l &= 0x0fff0fff;
			l |= (((CFG_IQLEN/32)-1)*IQSCC0RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC0TXLEN);
			break;
	case 1:	WriteL(pLDI,CH1CFG,MRFI | MTFI | MRERR | MTERR);
			WriteL(pLDI,IQSCC1RXBAR,VirtToPhys(pChan->iq_rx));
			WriteL(pLDI,IQSCC1TXBAR,VirtToPhys(pChan->iq_tx));
			l &= 0xf0fff0ff;
			l |= (((CFG_IQLEN/32)-1)*IQSCC1RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC1TXLEN);
			break;
	case 2:	WriteL(pLDI,CH2CFG,MRFI | MTFI | MRERR | MTERR);
			WriteL(pLDI,IQSCC2RXBAR,VirtToPhys(pChan->iq_rx));
			WriteL(pLDI,IQSCC2TXBAR,VirtToPhys(pChan->iq_tx));
			l &= 0xff0fff0f;
			l |= (((CFG_IQLEN/32)-1)*IQSCC2RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC2TXLEN);
			break;
	case 3:	WriteL(pLDI,CH3CFG,MRFI | MTFI | MRERR | MTERR);
			WriteL(pLDI,IQSCC3RXBAR,VirtToPhys(pChan->iq_rx));
			WriteL(pLDI,IQSCC3TXBAR,VirtToPhys(pChan->iq_tx));
			l &= 0xfff0fff0;
			l |= (((CFG_IQLEN/32)-1)*IQSCC3RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC3TXLEN);
			break;
	}
	WriteL(pLDI,IQLENR1,l);
	pLDI->mailbox = MAILBOX_NONE;
	WriteL(pLDI,GCMDR, AR	/* Action Request */
			| (chan == 0 ? (CFGIQSCC0RX | CFGIQSCC0TX) : 0)
			| (chan == 1 ? (CFGIQSCC1RX | CFGIQSCC1TX) : 0)
			| (chan == 2 ? (CFGIQSCC2RX | CFGIQSCC2TX) : 0)
			| (chan == 3 ? (CFGIQSCC3RX | CFGIQSCC3TX) : 0));
	/* wait for interrupt handler */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		if (pLDI->mailbox) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	/* mailbox was written by isr */
	if (pLDI->mailbox != MAILBOX_OK) {
		DbgPrint("PCISCC: TX/RX interrupt queue error (pciscc_channel_open)\n");
		pChan->stats.io_error++;
	}
	/* initialize channel's SCC core */
	pChan->ccr0 = PU | VIS | PSD;
	pChan->ccr0 |= (mode & MODE_z) ? 0 : 2*SC;
	pChan->ccr0 |= (mode & MODE_r) ? 0 : 6*CM;
	pChan->ccr0 |= (mode & MODE_t) ? 0 : SSEL;
	pChan->ccr1 = ODS | ICD | FCTS | MDS1 | SFLAG;
	pChan->ccr2 = RAC | (3*RFTH) | ITF;
	WriteL(pLDI,SCCBASE[chan]+CCR0,pChan->ccr0);
	WriteL(pLDI,SCCBASE[chan]+CCR1,pChan->ccr1);
	WriteL(pLDI,SCCBASE[chan]+CCR2,pChan->ccr2);
	pciscc_set_baud(pLDI,chan,(mode & MODE_r) ? bitrate : 16*bitrate);
	WriteL(pLDI,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(pLDI,SCCBASE[chan]+IMR,~(ALLS | XDU | TIN | XMR | XPR | RDO | RFO | FLEX));
	/* wait until command executing (CEC) is clear */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		l = ReadL(pLDI,SCCBASE[chan]+STAR);
		if (!(l & CEC)) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	if (l & CEC)
		DbgPrint("PCISCC: Timeout waiting for SCC being ready for reset.\n");
	/* RX and TX SCC reset */
	pChan->tx_mailbox = 0xffffffff;
	WriteL(pLDI,SCCBASE[chan]+CMDR,RRES | XRES);
	/* wait for interrupt handler */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		if (pChan->tx_mailbox!=0xffffffff) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	/* mailbox was written by isr */
	if ((pChan->tx_mailbox & 0x03ffffff) != 0x02001000) {
		DbgPrint("PCISCC: TX/RX reset error (pciscc_channel_open)\n");
		pChan->stats.io_error++;
	}
	/* initialize DMAC channel's RX */
	switch (chan) {
	case 0:	WriteL(pLDI,CH0CFG,IDR);
			WriteL(pLDI,CH0BRDA,VirtToPhys(pChan->dq_rx));
			WriteL(pLDI,CH0FRDA,VirtToPhys(pChan->dq_rx));
			WriteL(pLDI,CH0LRDA,VirtToPhys(pChan->dq_rx_next->prev->prev));
			break;
	case 1:	WriteL(pLDI,CH1CFG,IDR);
			WriteL(pLDI,CH1BRDA,VirtToPhys(pChan->dq_rx));
			WriteL(pLDI,CH1FRDA,VirtToPhys(pChan->dq_rx));
			WriteL(pLDI,CH1LRDA,VirtToPhys(pChan->dq_rx_next->prev->prev));
			break;
	case 2:	WriteL(pLDI,CH2CFG,IDR);
			WriteL(pLDI,CH2BRDA,VirtToPhys(pChan->dq_rx));
			WriteL(pLDI,CH2FRDA,VirtToPhys(pChan->dq_rx));
			WriteL(pLDI,CH2LRDA,VirtToPhys(pChan->dq_rx_next->prev->prev));
			break;
	case 3:	WriteL(pLDI,CH3CFG,IDR);
			WriteL(pLDI,CH3BRDA,VirtToPhys(pChan->dq_rx));
			WriteL(pLDI,CH3FRDA,VirtToPhys(pChan->dq_rx));
			WriteL(pLDI,CH3LRDA,VirtToPhys(pChan->dq_rx_next->prev->prev));
			break;
	}
	pLDI->mailbox = MAILBOX_NONE;
	WriteL(pLDI,GCMDR,AR);
	/* wait for interrupt handler */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		if (pLDI->mailbox) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	/* mailbox was written by isr */
	if (pLDI->mailbox != MAILBOX_OK) {
		DbgPrint("PCISCC: RX DMAC config error (pciscc_channel_open)\n");
		pChan->stats.io_error++;
	}
	/* mask all DMAC interrupts (needed) */
	switch (chan) {
	case 0:	WriteL(pLDI,CH0CFG,MRFI | MTFI | MRERR | MTERR);
			break;
	case 1:	WriteL(pLDI,CH1CFG,MRFI | MTFI | MRERR | MTERR);
			break;
	case 2:	WriteL(pLDI,CH2CFG,MRFI | MTFI | MRERR | MTERR);
			break;
	case 3:	WriteL(pLDI,CH3CFG,MRFI | MTFI | MRERR | MTERR);
			break;
	}
	/* wait until command executing (CEC) is clear */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		l = ReadL(pLDI,SCCBASE[chan]+STAR);
		if (!(l & CEC)) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	if (l & CEC)
		DbgPrint("PCISCC: Timeout waiting for SCC being ready for reset.\n");
	/* SCC core TX reset (again) */
	pChan->tx_mailbox = 0xffffffff;
	WriteL(pLDI,SCCBASE[chan]+CMDR,XRES);
	/* wait for interrupt handler */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		if (pChan->tx_mailbox!=0xffffffff) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	/* mailbox was written by isr */
	if ((pChan->tx_mailbox & 0x03ffffff) != 0x02001000) {
		DbgPrint("PCISCC: TX reset error (pciscc_channel_open)\n");
		pChan->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(pLDI,CH0CFG,IDT | MTFI);
			WriteL(pLDI,CH0BTDA,VirtToPhys(pChan->dq_tx));
			WriteL(pLDI,CH0FTDA,VirtToPhys(pChan->dq_tx));
			WriteL(pLDI,CH0LTDA,VirtToPhys(pChan->dq_tx));
			break;
	case 1:	WriteL(pLDI,CH1CFG,IDT | MTFI);
			WriteL(pLDI,CH1BTDA,VirtToPhys(pChan->dq_tx));
			WriteL(pLDI,CH1FTDA,VirtToPhys(pChan->dq_tx));
			WriteL(pLDI,CH1LTDA,VirtToPhys(pChan->dq_tx));
			break;
	case 2:	WriteL(pLDI,CH2CFG,IDT | MTFI);
			WriteL(pLDI,CH2BTDA,VirtToPhys(pChan->dq_tx));
			WriteL(pLDI,CH2FTDA,VirtToPhys(pChan->dq_tx));
			WriteL(pLDI,CH2LTDA,VirtToPhys(pChan->dq_tx));
			break;
	case 3:	WriteL(pLDI,CH3CFG,IDT | MTFI);
			WriteL(pLDI,CH3BTDA,VirtToPhys(pChan->dq_tx));
			WriteL(pLDI,CH3FTDA,VirtToPhys(pChan->dq_tx));
			WriteL(pLDI,CH3LTDA,VirtToPhys(pChan->dq_tx));
			break;
	}
	pLDI->mailbox = MAILBOX_NONE;
	WriteL(pLDI,CMDR,AR);
	/* wait for interrupt handler */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		if (pLDI->mailbox) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	/* mailbox was written by isr */
	if (pLDI->mailbox != MAILBOX_OK) {
		DbgPrint("PCISCC: TX DMAC config error (pciscc_channel_open)\n");
		pChan->stats.io_error++;
	} else
		pChan->txstate=TX_IDLE;
	/* initialization complete */
	pChan->initialized = 1;
	return STATUS_SUCCESS;
}

/* close one channel - don't mess with it either */
VOID pciscc_channel_close(
	PLOCAL_DEVICE_INFO pLDI,
	ULONG chan
	)
{
	PCHANNEL_INFO pChan;
	struct rx_desc *rdp;
	LARGE_INTEGER	time;
	LARGE_INTEGER	time_expire;
	ULONG i,l;

	pChan = &pLDI->Channel[chan];
	/* check init state */
	if (!pChan->initialized)
		return;
	pChan->initialized = 0;
	/* at first stop timer */
	WriteL(pLDI,SCCBASE[chan]+TIMR,0);
	/* wait until command executing (CEC) is clear */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		l = ReadL(pLDI,SCCBASE[chan]+STAR);
		if (!(l & CEC)) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	if (l & CEC)
		DbgPrint("PCISCC: Timeout waiting for SCC being ready for reset.\n");
	/* RX and TX SCC reset */
	pChan->tx_mailbox = 0xffffffff;
	WriteL(pLDI,SCCBASE[chan]+CMDR,RRES | XRES);
	/* wait for interrupt handler */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		if (pChan->tx_mailbox!=0xffffffff) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	/* mailbox was written by isr */
	if ((pChan->tx_mailbox & 0x03ffffff) != 0x02001000) {
		DbgPrint("PCISCC: TX/RX reset error (pciscc_channel_close)\n");
		pChan->stats.io_error++;
	}
	pChan->txstate = TX_RESET;
	/* stop SCC core */
	WriteL(pLDI,SCCBASE[chan]+CCR1,0);
	WriteL(pLDI,SCCBASE[chan]+CCR2,0);
	WriteL(pLDI,SCCBASE[chan]+CCR0,0);
	pChan->ccr0 = pChan->ccr1 = pChan->ccr2 = 0;
	pChan->bitrate = pChan->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.
	 */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	/* OK, now we should be ready to put the DMAC into reset state */
	switch (chan) {
	case 0:	WriteL(pLDI,CH0CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
			break;
	case 1:	WriteL(pLDI,CH1CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
			break;
	case 2:	WriteL(pLDI,CH2CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
			break;
	case 3: WriteL(pLDI,CH3CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
			break;
	}
	pLDI->mailbox = MAILBOX_NONE;
	WriteL(pLDI,GCMDR,AR);
	/* wait for interrupt handler */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		if (pLDI->mailbox) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	/* mailbox was written by isr */
	if (pLDI->mailbox != MAILBOX_OK) {
		DbgPrint("PCISCC: DMAC reset error (pciscc_channel_close)\n");
		pChan->stats.io_error++;
	}
	/* clear IQs */
	l = ReadL(pLDI,IQLENR1);
	switch (chan) {
	case 0:	l &= 0x0fff0fff;
			WriteL(pLDI,IQLENR1,l);
			WriteL(pLDI,IQSCC0RXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
			WriteL(pLDI,IQSCC0TXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
			break;
	case 1: l &= 0xf0fff0ff;
			WriteL(pLDI,IQLENR1,l);
			WriteL(pLDI,IQSCC1RXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
			WriteL(pLDI,IQSCC1TXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
			break;
	case 2: l &= 0xff0fff0f;
			WriteL(pLDI,IQLENR1,l);
			WriteL(pLDI,IQSCC2RXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
			WriteL(pLDI,IQSCC2TXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
			break;
	case 3: l &= 0xfff0fff0;
			WriteL(pLDI,IQLENR1,l);
			WriteL(pLDI,IQSCC3RXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
			WriteL(pLDI,IQSCC3TXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
			break;
	}
	pLDI->mailbox = MAILBOX_NONE;
	WriteL(pLDI,GCMDR,AR
			| (chan == 0 ? (CFGIQSCC0RX | CFGIQSCC0TX) : 0)
			| (chan == 1 ? (CFGIQSCC1RX | CFGIQSCC1TX) : 0)
			| (chan == 2 ? (CFGIQSCC2RX | CFGIQSCC2TX) : 0)
			| (chan == 3 ? (CFGIQSCC3RX | CFGIQSCC3TX) : 0));
	/* wait for interrupt handler */
	KeQuerySystemTime(&time);
	time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
	do {
		if (pLDI->mailbox) break;
		KeQuerySystemTime(&time);
	} while RtlLargeIntegerLessThan(time,time_expire);
	/* mailbox was written by isr */
	if (pLDI->mailbox != MAILBOX_OK) {
		DbgPrint("PCISCC: Interrupt queue reset error (pciscc_channel_close)");
		pChan->stats.io_error++;
	}
	/* queues no longer exist */
	pChan->iq_rx_next=NULL;
	pChan->iq_tx_next=NULL;
	/* release RX frames from queue */
	for (i=0; i < CFG_RX_DESC; i++)

⌨️ 快捷键说明

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