📄 p2681.c
字号:
/************************************************************* * File: lib/p2681.c * Purpose: PMON Driver for the 2681 DUART * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 980618 Created from p2681.s */#include <mips.h>#include <terms.h>#define inb(a) (*((volatile Uchar *)(a)))#define outb(a,v) (*((volatile Uchar *)(a))=(v))#define DELAY 5 /* delay used between writes */#define IACR 0xf0 /* initial value for ACR acr[7] timer=7 *//* offsets and bit field definitions for the 2681 duart */#define SR 1#define RXRDY 0x01#define TXRDY 0x04#define CSR 1#define CMD 2#define RHR 3#define THR 3#define ACR 4#define IMR 5#define TXINT 0x01#define RXINT 0x02#define CNTINT 0x08#define ISR 5#define ITXRDY 0x01#define IRXRDY 0x02#define CNTRDY 0x08#define CTU 6#define CTL 7/* chanB registers start at 8 */#define SETOCR 14#define STARTCNT 14#define STOPCNT 15#define CLROCR 15static struct { char reg; char val; } inittab[] = { {IMR,0x00}, /* mask off all ints */ /* resets: dis tx&rx, reset MR ptr, reset rx, reset tx */ {CMD,0x0a},{CMD,0x10},{CMD,0x20},{CMD,0x30}, {CMD+8,0x0a},{CMD+8,0x10},{CMD+8,0x20},{CMD+8,0x30}, /* MRs: no parity, 8 bits data, 1 stop bit */ {0,0x13},{0,0x07},{8,0x13},{8,0x07},#if 0 /* timer: mode=timer val=11,520 (0.1 secs) */ {ACR,IACR},{CTU,0x2d},{CTL,0x00},#endif /* enable status outputs: reset all op bits */ /* set OP7. required on ATMizer */ {13,0x00},{15,0xff},{14,0x80}, {CMD,0x05},{CMD+8,0x05}, /* enable rxs& txs */ /* {IMR,0x2a}, /* enable ints, rx A&B + timer */ {255,255}}; /* list terminator */struct BtabRec { Uchar csr; Uchar acr7; };/* * if CSR == 255 baud rate not supported * if CSR == 254 end of table * if ACR7 == 2 then that bit is don't care */static struct BtabRec btab[] = { {255,2}, /* B0 */ {0,0}, /* B50 */ {0,1}, /* B75 */ {1,2}, /* B110 */ {2,2}, /* B134 */ {3,1}, /* B150 */ {3,0}, /* B200 */ {4,2}, /* B300 */ {5,2}, /* B600 */ {6,2}, /* B1200 */ {10,1}, /* B1800 */ {8,2}, /* B2400 */ {9,2}, /* B4800 */ {11,2}, /* B9600 */ {12,1}, /* B19200 */ {12,0}, /* B38400 */ {254}};extern void *_clkinfo;static long _time;static int _ticks;static int clkfunc(int op,long value);static clkisr();/************************************************************** p2681(op,siodat,chan,ch)*/p2681(op,siodat,chan,ch)int op,chan,ch;void *siodat;{struct p2681info *info = siodat;Ulong base = info->siobase;int brate = ch;int gap = info->gap;int i,j;Ulong t0,t1,t7,t8,v,m;struct BtabRec *t4,*t6;#ifdef MIPSEBbase += info->beoffs;#endifswitch (op) { case OP_RXRDY : if (inb(base+(((chan*8)+SR)*gap))&RXRDY) return(1); break; case OP_RX : return inb(base+(((chan*8)+RHR)*gap)); break; case OP_TXRDY : if (inb(base+(((chan*8)+SR)*gap))&TXRDY) return(1); break; case OP_TX : outb(base+(((chan*8)+THR)*gap),ch); break; case OP_INIT : for (i=0;inittab[i].reg != 255;i++) { outb(base+(inittab[i].reg*gap),inittab[i].val); for (j=0;j<DELAY;j++) ; } /* set the initial value of CURACR */ info->curacr = IACR; break; case OP_BAUD : /* check brate <= 15 */ if (brate > 15) return(1); /* baud rate too large */ t4 = &btab[brate]; if (t4->csr == 255) return(1); /* unsupported baud rate */ /* See if it's an allowed combination. * chanA and ChanB share a baudrate table selection bit * (acr7). So you need to make sure that the two * baudrates are in the same table. */ /* find existing brate for other channel */ t6 = &btab[info->brate[(chan)?0:1]]; /* if ACRs add up to 1 it's not allowed */ if ((t6->acr7 + t4->acr7) == 1) return(1); /* we're going to change something, so disable rx and tx */ outb(base+(((chan*8)+CMD)*gap),0x0a); /* do we need to change ACR? */ /* Change if: mine not don't care, and his != mine */ if (t4->acr7 != 2 && t4->acr7 != t6->acr7) { /* need to change ACR7 */ /* read existing ACR value from memory copy */ t7 = info->curacr; /* or in our bit ACR7 */ t7 &= 0x7f; /* clear it first */ t7 |= (t4->acr7<<7); /* set it */ /* wait a while */ for (i=0;i<DELAY;i++) ; /* write new ACR */ outb(base+(ACR*gap),t7); /* update memory copy */ info->curacr = t7; } /* need duplicate values for rx and tx */ t7 = (t4->csr<<4)|t4->csr; /* wait a while */ for (i=0;i<DELAY;i++) ; /* base[chan+CSR] = rate */ outb(base+(((chan*8)+CSR)*gap),t7); /* wait a while */ for (i=0;i<DELAY;i++) ; /* reenable rx and tx */ outb(base+(((chan*8)+CMD)*gap),0x05); /* update memory copy */ info->brate[chan] = ch; break; case OP_CLKINIT : break; case OP_DELAY : return(0); break; case OP_BAUDRATES : /* list the supported baudrates */ m = 1; for (i=v=0;btab[i].csr != 254;i++) { if (btab[i].csr != 255) v |= m; m <<= 1; } return(v); /* one bit per baudrate */ break; }return(0);}#define TIMER_RELOAD 1152 /* 10ms *//**************************************************************/static int clkfunc(int op,long value){switch (op) { case 1 : _time = value; return(value); case 2 : return(_time); case 3 : return(_time*1000000)+(_ticks*10000); }}/**************************************************************/Func *clkinit_2681(){Ulong t8,t0,t1,intmask,msk;struct p2681info *info = _clkinfo;Ulong base = info->siobase;int gap = info->gap;int i,intnum;#ifdef MIPSEBbase += info->beoffs;#endift8 = mfc0(C0_SR);mtc0(C0_SR,t8&~SR_IEC); /* disable ints in SR */outb(base+(IMR*gap),0); /* disable clkints in IMR *//* prog timer for short period */outb(base+(CTL*gap),4); outb(base+(CTU*gap),0);t0 = mfc0(C0_CAUSE);outb(base+(IMR*gap),CNTINT); /* enable clkints in IMR */for (i=0;i<100000;i++) { /* timeout value */ t1 = mfc0(C0_CAUSE); if (t1 != t0) break; }intmask = SR_IMASK&(t0^t1);for (intnum=0,msk=0x100;intnum<8;intnum++,msk<<=1) if (intmask&msk) break;if (intnum > 7) { mtc0(C0_SR,t8); return(0); }outb(base+(IMR*gap),CNTINT); /* enable clkints in IMR */t8 |= (SR_INT0|SR_IEC); /* new SR value *//* reprogram timer for 10ms */outb(base+(CTL*gap),TIMER_RELOAD&0xff);outb(base+(CTU*gap),TIMER_RELOAD>>8);/* attach isr */IRQInstall(intnum,clkisr);mtc0(C0_SR,t8); /* restore SR */return(clkfunc);}/**************************************************************/static clkisr(){struct p2681info *info = _clkinfo;Ulong base = info->siobase;int gap = info->gap;#ifdef MIPSEBbase += info->beoffs;#endifinb(base+(STOPCNT*gap)); /* ack timer int */_ticks++;if (_ticks >= 100) { _time++; _ticks=0; }return(1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -