📄 pciscc.c
字号:
/*****************************************************************************
*
* 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 + -