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

📄 pciscc.c

📁 高速同步串口芯片PEB20534的驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/*****************************************************************************
 *
 * pciscc.c	This is the device driver for the PCISCC-4 card or any other
 *		board based on the Siemens PEB-20534H (DSCC-4) communication
 *              controller. The PCISCC-4 is a four-channel medium-speed (up
 *		to 10 respectively 52 Mbps/channel) synchronous serial
 *		interface controller with HDLC protocol processor and
 *		busmaster-DMA facilities.
 *
 * Author:	(c) 2001/2002 Steffen Koehler <dh1dm@qsl.net>
 *
 *****************************************************************************
 */

#include <dos.h>
#include <string.h>
#include <stdlib.h>
#include "flexdrv.h"
#include "pciscc.h"
#include "pci.h"
#include "mem32.h"

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

#define	CHIP_TIMEOUT	2		/* chip timeout (55ms intervals) */
#define	XTAL_FREQ	19660000	/* on board crystal freq. */
#define MIN_FLAGS	32		/* minimum delay/tail bits */

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

char helptext[] =
"\nUsage: PCISCC [options]\n"
"Oprions: /c=<num> select a PCISCC card if more than one is present\n"
"                  default card number is 0\n"
"         /t=<ms>  set TX delay scaling, default value is 10 ms\n";

char version[] = "0.4a";

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

/* Convert far pointer to physical address */
#define FP_TO_PHYS(x)	((long)(((long)FP_SEG(x) << 4) + FP_OFF(x)))

/* global variables */
struct chipctl_t chipctl;
struct devctl_t devctl[4];
struct buffer_t dma_buffers;

/* processed flexnet RX/TX frames */
L1FRAME far *tx_frame = NULL;
L1FRAME far *rx_frame = NULL;

/* BIOS timer */
unsigned long far *bios_tic = MK_FP(0x40,0x6c);

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

/*
 * get a frame buffer from pre-allocated driver frame memory pool and
 * mark this frame buffer as used
 */
L1FRAME far * alloc_frame(void)
{
	int i;
	for (i=0; i < CFG_L1_BUF; i++) {
		if (!chipctl.dma_buffers->frm_pool[i].valid) {
			chipctl.dma_buffers->frm_pool[i].valid = 1;
			return &chipctl.dma_buffers->frm_pool[i].l1_frame;
		}
	}
	return NULL;
}

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

/*
 * find a previosly allocated frame buffer in the driver frame memory pool
 * and mark this frame buffer as unused
 */
void free_frame(L1FRAME far * frame)
{
	int i;
	for (i=0; i < CFG_L1_BUF; i++) {
		if (&chipctl.dma_buffers->frm_pool[i].l1_frame == frame) {
			chipctl.dma_buffers->frm_pool[i].valid = 0;
			break;
		}
	}
}

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

/*
 * get the number of available (unused) frame buffers in the driver
 * pre-allocated frame memory pool
 */
int avail_frames(void)
{
	int i;
	int cnt = 0;
	for (i=0; i < CFG_L1_BUF; i++)
		if (!chipctl.dma_buffers->frm_pool[i].valid) cnt++;
	return cnt;
}

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

/* initialize channel queues */
void pciscc_init_queues(int chan)
{
	struct rx_desc_t *first_rdp = NULL;
	struct rx_desc_t *curr_rdp = NULL;
	struct rx_desc_t *last_rdp = NULL;
	struct tx_desc_t *first_tdp = NULL;
	struct tx_desc_t *curr_tdp = NULL;
	struct tx_desc_t *last_tdp = NULL;
	unsigned int i;

	/* initialize TX/RX IQs */
	devctl[chan].iq_rx = chipctl.dma_buffers->iq_rx[chan];
	devctl[chan].iq_tx = chipctl.dma_buffers->iq_tx[chan];
	memset(devctl[chan].iq_rx, 0, 4*CFG_IQLEN);
	memset(devctl[chan].iq_tx, 0, 4*CFG_IQLEN);
	devctl[chan].iq_rx_next = devctl[chan].iq_rx;
	devctl[chan].iq_tx_next = devctl[chan].iq_tx;
	/*
	 * Prepare circular RX and TX descriptor queues ("FIFO" rings)
	 * Attention:
	 * This beast gets _very_ angry if you try to hand it a
	 * descriptor with a data length of 0. In fact it crashes
	 * the system by asserting /SERR or something.
	 */
	devctl[chan].dq_rx = chipctl.dma_buffers->dq_rx[chan];
	first_rdp = devctl[chan].dq_rx;
	for (i=0, curr_rdp = first_rdp; i < CFG_RX_DESC; i++, curr_rdp++) {
		if (i > 0) {
			curr_rdp->prev = last_rdp;
			last_rdp->next = curr_rdp;
			last_rdp->nextptr = FP_TO_PHYS(curr_rdp);
		}
		disable(); curr_rdp->l1_frame = alloc_frame(); enable();
		curr_rdp->dataptr = FP_TO_PHYS(curr_rdp->l1_frame->frame);
		curr_rdp->flags = CFG_MTU*NO;
		curr_rdp->feptr = 0;
		curr_rdp->result = 0;
		last_rdp = curr_rdp;
	}
	last_rdp->next = first_rdp;			/* close ring structure */
	last_rdp->nextptr = FP_TO_PHYS(first_rdp);
	first_rdp->prev = last_rdp;
	devctl[chan].dq_rx_next = first_rdp;		/* first descriptor to be processed = "first" descriptor in chain */
	/* TX queue */
	devctl[chan].dq_tx = chipctl.dma_buffers->dq_tx[chan];
	first_tdp = devctl[chan].dq_tx;
	for (i=0, curr_tdp = first_tdp; i < CFG_TX_DESC; i++, curr_tdp++) {
		if (i > 0) {
			curr_tdp->prev = last_tdp;
			last_tdp->next = curr_tdp;
			last_tdp->nextptr = FP_TO_PHYS(curr_tdp);
		}
		curr_tdp->l1_frame = NULL;
		curr_tdp->dataptr = FP_TO_PHYS(chipctl.dma_buffers->dummy);
		curr_tdp->flags = FE | (8*NO);
		curr_tdp->result = 0;
		last_tdp = curr_tdp;
	}
	last_tdp->next = first_tdp;			/* close ring structure */
	last_tdp->nextptr = FP_TO_PHYS(first_tdp);
	first_tdp->prev = last_tdp;
	devctl[chan].dq_tx_last = first_tdp;		/* last descriptor to be transmitted */
	devctl[chan].dq_tx_cleanup = first_tdp;		/* first descriptor to be cleaned */
}

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

/* find best BRG N and M match for given bitrate */
static void pciscc_set_baud(int chan, long rate)
{
	long brg_best_n	= 0;
	long brg_best_m	= 0;
	long brg_tmp,m,n;
	unsigned long brg_error	= XTAL_FREQ;
	unsigned long brg_tmp_error;

	for (m=0; m<16; m++) {
		for (n=0; n<63; n++) {
			brg_tmp = (n+1)*(1<<m);
			brg_tmp_error = labs(XTAL_FREQ/brg_tmp - rate);
			if (brg_tmp_error < brg_error) {
				brg_best_m = m;
				brg_best_n = n;
				brg_error = brg_tmp_error;
			}
		}
	}
	WriteL(chipctl.io_base+SCCBASE[chan]+BRR,(brg_best_m*BRM) | (brg_best_n*BRN));
}

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

/* detect/initialize PCISCC chip, called from init_device() function */
int pciscc_chip_init(void)
{
	unsigned char pci_devfn;
	unsigned char pci_bus;
	unsigned int cmd;
	char hexstr[10];

	/* make sure PCI BIOS is avaliable */
	if(!PCIBiosPresent()) {
		pstr("PCISCC: No PCI bios present.\n");
		return 1;
	}
	pstr("PCISCC: Card "); pnum(chipctl.card_num); pstr(" selected.\n");
	if (!(FindPCIDevice(PCI_DEVICE_ID, PCI_VENDOR_ID, chipctl.card_num, &pci_bus, &pci_devfn))) {
		pstr("PCISCC: PEB-20534H (DSCC4) card not found.\n");
		return 1;
	}
	/* read chip configuration */
	ReadConfigurationDword(pci_bus, pci_devfn, PCI_CS_BASE_ADDRESS_0, &chipctl.io_base);
	ReadConfigurationByte(pci_bus, pci_devfn, PCI_CS_INTERRUPT_LINE, &chipctl.irq);
	/* enable chip fixups */
	ReadConfigurationWord(pci_bus, pci_devfn, PCI_CS_COMMAND, &cmd);
	cmd |= PCI_COMMAND_MASTER;
	cmd |= PCI_COMMAND_PARITY;
	cmd |= PCI_COMMAND_SERR;
	cmd &= ~PCI_COMMAND_FAST_BACK;
	WriteConfigurationWord(pci_bus, pci_devfn, PCI_CS_COMMAND, cmd);
	WriteConfigurationByte(pci_bus, pci_devfn, PCI_CS_MASTER_LATENCY, 0xF8);
	/* show probed hardware parameters */
	pstr("PCISCC: Found PEB-20534H chip at mem=0x");
	ltoa(chipctl.io_base, hexstr, 16); pstr(hexstr);
	pstr(", irq="); pnum(chipctl.irq); pstr(".\n");
	/* display TX delay scaling */
	pstr("PCISCC: TX delay scaling set to ");
	pnum(chipctl.txd_scale); pstr(" ms.\n");
	return 0;
}

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

/*
 * initialize chip, called from pciscc_channel_open() function
 * action sequency was carefully chosen, don't mess with it
 */
int pciscc_chip_open(void)
{
	unsigned int nvec, mask;
	unsigned long timer;
	unsigned long i;

	if (!chipctl.io_base || !chipctl.irq)
		return 0;
	if (chipctl.initialized)
		return 1;
	/* align buffer memory address */
	chipctl.dma_buffers = (void*)(((long)&dma_buffers & 0xfffffffc) + 4);
	/* clear frame buffer pool */
	for (i=0; i < CFG_L1_BUF; i++)
		chipctl.dma_buffers->frm_pool[i].valid = 0;
	/* init rx frame queue */
	chipctl.rx_get = chipctl.rx_put = chipctl.rx_queue;
	/* install IRQ service routine */
	if (chipctl.irq & 8)
		nvec = chipctl.irq + 0x68;
	else
		nvec = chipctl.irq + 0x08;
	chipctl.oldvect = getvect(nvec);
	setvect(nvec, pciscc_isr);
	/* save PIC state */
	chipctl.oldpic[0] = inportb(PIC0MASK);
	chipctl.oldpic[1] = inportb(PIC1MASK);
	/* enable IRQ line at interrupt controllers */
	mask = 1 << chipctl.irq;
	outportb(PIC0MASK, inportb(PIC0MASK) & ~mask);
	mask >>= 8;
	outportb(PIC1MASK, inportb(PIC1MASK) & ~mask);
	/* initialize peripheral queue */
	chipctl.iq_per = chipctl.dma_buffers->iq_per;
	memset(chipctl.iq_per, 0, 4*CFG_IQLEN);
	chipctl.iq_per_next = chipctl.iq_per;
	/* configuration interrupt queue */
	chipctl.iq_cfg = chipctl.dma_buffers->iq_cfg;
	memset(chipctl.iq_cfg, 0, 4*CFG_IQLEN);
	chipctl.iq_cfg_next = chipctl.iq_cfg;
	/* global hardware initialization */
	disable();
	WriteL(chipctl.io_base+GMODE, (4 * PERCFG) | (3 * LCD) | CMODE);
	WriteL(chipctl.io_base+IQPBAR,FP_TO_PHYS(chipctl.iq_per));
	WriteL(chipctl.io_base+IQCFGBAR,FP_TO_PHYS(chipctl.iq_cfg));
	WriteL(chipctl.io_base+IQLENR2,(((CFG_IQLEN/32)-1)*IQCFGLEN) | (((CFG_IQLEN/32)-1)*IQPLEN));
	WriteL(chipctl.io_base+FIFOCR1,((32/4)*TFSIZE0)
		| ((32/4)*TFSIZE1)
		| ((32/4)*TFSIZE2)
		| ((32/4)*TFSIZE3));
	WriteL(chipctl.io_base+FIFOCR2,((24/4)*TFRTHRES0)
		| ((24/4)*TFRTHRES1)
		| ((24/4)*TFRTHRES2)
		| ((24/4)*TFRTHRES3)
		| M4_0 | M4_1 | M4_2 | M4_3);
	WriteL(chipctl.io_base+FIFOCR3,CFG_FIFO_RX_T);
	WriteL(chipctl.io_base+FIFOCR4,(20*TFFTHRES0)
		| (20*TFFTHRES1)
		| (20*TFFTHRES2)
		| (20*TFFTHRES3));
	/* mask out all DMAC interrupts */
	WriteL(chipctl.io_base+CH0CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(chipctl.io_base+CH1CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(chipctl.io_base+CH2CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(chipctl.io_base+CH3CFG,(MRFI | MTFI | MRERR | MTERR));
	/* all SCC cores in reset state */
	WriteL(chipctl.io_base+SCCBASE[0]+CCR0,0x00000000);
	WriteL(chipctl.io_base+SCCBASE[1]+CCR0,0x00000000);
	WriteL(chipctl.io_base+SCCBASE[2]+CCR0,0x00000000);
	WriteL(chipctl.io_base+SCCBASE[3]+CCR0,0x00000000);
	/* mask out all SCC interrupts */
	WriteL(chipctl.io_base+SCCBASE[0]+IMR,0xffffffff);
	WriteL(chipctl.io_base+SCCBASE[1]+IMR,0xffffffff);
	WriteL(chipctl.io_base+SCCBASE[2]+IMR,0xffffffff);
	WriteL(chipctl.io_base+SCCBASE[3]+IMR,0xffffffff);
	/* peripheral configuration */
	WriteL(chipctl.io_base+LCONF,(BTYP*3));
	WriteL(chipctl.io_base+SSCCON,0x00000000);
	WriteL(chipctl.io_base+SSCIM,0x00000000);
	WriteL(chipctl.io_base+GPDIR,0x000000ff);
	WriteL(chipctl.io_base+GPDATA,0x00000000);
	WriteL(chipctl.io_base+GPIM,0x00000000);
	enable();
	/* initialize configuration and peripheral IQs */
	chipctl.mailbox = MAILBOX_NONE;
	WriteL(chipctl.io_base+GCMDR, CFGIQCFG | CFGIQP | AR);
	timer = *bios_tic;
	while((*bios_tic - timer) < CHIP_TIMEOUT) {
		if (chipctl.mailbox) break;
	}
	if (chipctl.mailbox == MAILBOX_OK) {	/* mailbox was written by isr */
		chipctl.initialized = 1;
		return 1;
	}
	/* global configuration to reset state */
	disable();
	WriteL(chipctl.io_base+GMODE, (4 * PERCFG) | (3 * LCD) | CMODE | OSCPD);
	/* mask all DMAC interrupts */
	WriteL(chipctl.io_base+CH0CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(chipctl.io_base+CH1CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(chipctl.io_base+CH2CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(chipctl.io_base+CH3CFG,(MRFI | MTFI | MRERR | MTERR));
	/* SCC cores to reset state */
	WriteL(chipctl.io_base+SCCBASE[0]+CCR0,0x00000000);
	WriteL(chipctl.io_base+SCCBASE[1]+CCR0,0x00000000);
	WriteL(chipctl.io_base+SCCBASE[2]+CCR0,0x00000000);
	WriteL(chipctl.io_base+SCCBASE[3]+CCR0,0x00000000);
	/* mask all SCC interrupts */
	WriteL(chipctl.io_base+SCCBASE[0]+IMR,0xffffffff);
	WriteL(chipctl.io_base+SCCBASE[1]+IMR,0xffffffff);
	WriteL(chipctl.io_base+SCCBASE[2]+IMR,0xffffffff);
	WriteL(chipctl.io_base+SCCBASE[3]+IMR,0xffffffff);
	enable();
	/* restore PIC state */
	outportb(PIC0MASK, chipctl.oldpic[0]);
	outportb(PIC1MASK, chipctl.oldpic[1]);
	/* restore previous vector */
	if (chipctl.irq & 8)
		nvec = chipctl.irq + 0x68;
	else
		nvec = chipctl.irq + 0x08;
	setvect(nvec, chipctl.oldvect);
	chipctl.iq_per_next = NULL;
	chipctl.iq_cfg_next = NULL;
	return 0;
}

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

/*
 * close chip, called when last device (channel) of a chip was closed.
 * don't mess up.
 */
void pciscc_chip_close(void)
{
	int nvec;

	if (!chipctl.initialized)
		return;
	chipctl.initialized = 0;
	/* global configuration to reset state */
	disable();
	WriteL(chipctl.io_base+GMODE, (4 * PERCFG) | (3 * LCD) | CMODE | OSCPD);
	/* mask all DMAC interrupts */
	WriteL(chipctl.io_base+CH0CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(chipctl.io_base+CH1CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(chipctl.io_base+CH2CFG,(MRFI | MTFI | MRERR | MTERR));
	WriteL(chipctl.io_base+CH3CFG,(MRFI | MTFI | MRERR | MTERR));
	/* SCC cores to reset state */
	WriteL(chipctl.io_base+SCCBASE[0]+CCR0,0x00000000);
	WriteL(chipctl.io_base+SCCBASE[1]+CCR0,0x00000000);
	WriteL(chipctl.io_base+SCCBASE[2]+CCR0,0x00000000);
	WriteL(chipctl.io_base+SCCBASE[3]+CCR0,0x00000000);
	/* mask all SCC interrupts */
	WriteL(chipctl.io_base+SCCBASE[0]+IMR,0xffffffff);
	WriteL(chipctl.io_base+SCCBASE[1]+IMR,0xffffffff);
	WriteL(chipctl.io_base+SCCBASE[2]+IMR,0xffffffff);
	WriteL(chipctl.io_base+SCCBASE[3]+IMR,0xffffffff);
	enable();
	/* restore PIC state */
	outportb(PIC0MASK, chipctl.oldpic[0]);
	outportb(PIC1MASK, chipctl.oldpic[1]);
	/* restore previous vector */
	if (chipctl.irq & 8)
		nvec = chipctl.irq + 0x68;
	else
		nvec = chipctl.irq + 0x08;
	setvect(nvec, chipctl.oldvect);

⌨️ 快捷键说明

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