📄 uartaxp.c
字号:
/* * Avanstar Xp pci uart driver */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"#include "uartaxp.i"typedef struct Cc Cc;typedef struct Ccb Ccb;typedef struct Ctlr Ctlr;typedef struct Gcb Gcb;/* * Global Control Block. * Service Request fields must be accessed using XCHG. */struct Gcb { u16int gcw; /* Global Command Word */ u16int gsw; /* Global Status Word */ u16int gsr; /* Global Service Request */ u16int abs; /* Available Buffer Space */ u16int bt; /* Board Type */ u16int cpv; /* Control Program Version */ u16int ccbn; /* Ccb count */ u16int ccboff; /* Ccb offset */ u16int ccbsz; /* Ccb size */ u16int gcw2; /* Global Command Word 2 */ u16int gsw2; /* Global Status Word 2 */ u16int esr; /* Error Service Request */ u16int isr; /* Input Service Request */ u16int osr; /* Output Service Request */ u16int msr; /* Modem Service Request */ u16int csr; /* Command Service Request */};/* * Channel Control Block. */struct Ccb { u16int br; /* Baud Rate */ u16int df; /* Data Format */ u16int lp; /* Line Protocol */ u16int ibs; /* Input Buffer Size */ u16int obs; /* Output Buffer Size */ u16int ibtr; /* Ib Trigger Rate */ u16int oblw; /* Ob Low Watermark */ u8int ixon[2]; /* IXON characters */ u16int ibhw; /* Ib High Watermark */ u16int iblw; /* Ib Low Watermark */ u16int cc; /* Channel Command */ u16int cs; /* Channel Status */ u16int ibsa; /* Ib Start Addr */ u16int ibea; /* Ib Ending Addr */ u16int obsa; /* Ob Start Addr */ u16int obea; /* Ob Ending Addr */ u16int ibwp; /* Ib write pointer (RO) */ u16int ibrp; /* Ib read pointer (R/W) */ u16int obwp; /* Ob write pointer (R/W) */ u16int obrp; /* Ob read pointer (RO) */ u16int ces; /* Communication Error Status */ u16int bcp; /* Bad Character Pointer */ u16int mc; /* Modem Control */ u16int ms; /* Modem Status */ u16int bs; /* Blocking Status */ u16int crf; /* Character Received Flag */ u8int ixoff[2]; /* IXOFF characters */ u16int cs2; /* Channel Status 2 */ u8int sec[2]; /* Strip/Error Characters */};enum { /* br */ Br76800 = 0xFF00, Br115200 = 0xFF01,};enum { /* df */ Db5 = 0x0000, /* Data Bits - 5 bits/byte */ Db6 = 0x0001, /* 6 bits/byte */ Db7 = 0x0002, /* 7 bits/byte */ Db8 = 0x0003, /* 8 bits/byte */ DbMASK = 0x0003, Sb1 = 0x0000, /* 1 Stop Bit */ Sb2 = 0x0004, /* 2 Stop Bit */ SbMASK = 0x0004, Np = 0x0000, /* No Parity */ Op = 0x0008, /* Odd Parity */ Ep = 0x0010, /* Even Parity */ Mp = 0x0020, /* Mark Parity */ Sp = 0x0030, /* Space Parity */ PMASK = 0x0038, Cmn = 0x0000, /* Channel Mode Normal */ Cme = 0x0040, /* CM Echo */ Cmll = 0x0080, /* CM Local Loopback */ Cmrl = 0x00C0, /* CM Remote Loopback */};enum { /* lp */ Ixon = 0x0001, /* Obey IXON/IXOFF */ Ixany = 0x0002, /* Any character retarts Tx */ Ixgen = 0x0004, /* Generate IXON/IXOFF */ Cts = 0x0008, /* CTS controls Tx */ Dtr = 0x0010, /* Rx controls DTR */ ½d = 0x0020, /* RTS off during Tx */ Rts = 0x0040, /* generate RTS */ Emcs = 0x0080, /* Enable Modem Control */ Ecs = 0x1000, /* Enable Character Stripping */ Eia422 = 0x2000, /* EIA422 */};enum { /* cc */ Ccu = 0x0001, /* Configure Channel and UART */ Cco = 0x0002, /* Configure Channel Only */ Fib = 0x0004, /* Flush Input Buffer */ Fob = 0x0008, /* Flush Output Buffer */ Er = 0x0010, /* Enable Receiver */ Dr = 0x0020, /* Disable Receiver */ Et = 0x0040, /* Enable Transmitter */ Dt = 0x0080, /* Disable Transmitter */};enum { /* ces */ Oe = 0x0001, /* Overrun Error */ Pe = 0x0002, /* Parity Error */ Fe = 0x0004, /* Framing Error */ Br = 0x0008, /* Break Received */};enum { /* mc */ Adtr = 0x0001, /* Assert DTR */ Arts = 0x0002, /* Assert RTS */ Ab = 0x0010, /* Assert BREAK */};enum { /* ms */ Scts = 0x0001, /* Status od CTS */ Sdsr = 0x0002, /* Status of DSR */ Sri = 0x0004, /* Status of RI */ Sdcd = 0x0008, /* Status of DCD */};enum { /* bs */ Rd = 0x0001, /* Receiver Disabled */ Td = 0x0002, /* Transmitter Disabled */ Tbxoff = 0x0004, /* Tx Blocked by XOFF */ Tbcts = 0x0008, /* Tx Blocked by CTS */ Rbxoff = 0x0010, /* Rx Blocked by XOFF */ Rbrts = 0x0020, /* Rx Blocked by RTS */};enum { /* Local Configuration */ Range = 0x00, Remap = 0x04, Region = 0x18, Mb0 = 0x40, /* Mailbox 0 */ Ldb = 0x60, /* PCI to Local Doorbell */ Pdb = 0x64, /* Local to PCI Doorbell */ Ics = 0x68, /* Interrupt Control/Status */ Mcc = 0x6C, /* Misc. Command and Control */};enum { /* Mb0 */ Edcc = 1, /* exec. downloaded code cmd */ Aic = 0x10, /* adapter init'zed correctly */ Cpr = 1ul << 31, /* control program ready */};enum { /* Mcc */ Rcr = 1ul << 29, /* reload config. reg.s */ Asr = 1ul << 30, /* pci adapter sw reset */ Lis = 1ul << 31, /* local init status */};typedef struct Cc Cc;typedef struct Ccb Ccb;typedef struct Ctlr Ctlr;/* * Channel Control, one per uart. * Devuart communicates via the PhysUart functions with * a Uart* argument. Uart.regs is filled in by this driver * to point to a Cc, and Cc.ctlr points to the Axp board * controller. */struct Cc { int uartno; Ccb* ccb; Ctlr* ctlr; Rendez; Uart;};typedef struct Ctlr { char* name; Pcidev* pcidev; int ctlrno; Ctlr* next; u32int* reg; uchar* mem; Gcb* gcb; int im; /* interrupt mask */ Cc cc[16];} Ctlr;#define csr32r(c, r) (*((c)->reg+((r)/4)))#define csr32w(c, r, v) (*((c)->reg+((r)/4)) = (v))static Ctlr* axpctlrhead;static Ctlr* axpctlrtail;extern PhysUart axpphysuart;static intaxpccdone(void* ccb){ return !((Ccb*)ccb)->cc; /* hw sets ccb->cc to zero */}static voidaxpcc(Cc* cc, int cmd){ Ccb *ccb; int timeo; u16int cs; ccb = cc->ccb; ccb->cc = cmd; if(!cc->ctlr->im) for(timeo = 0; timeo < 1000000; timeo++){ if(!ccb->cc) break; microdelay(1); } else tsleep(cc, axpccdone, ccb, 1000); cs = ccb->cs; if(ccb->cc || cs){ print("%s: cmd %#ux didn't terminate: %#ux %#ux\n", cc->name, cmd, ccb->cc, cs); if(cc->ctlr->im) error(Eio); }}static longaxpstatus(Uart* uart, void* buf, long n, long offset){ char *p; Ccb *ccb; u16int bs, fstat, ms; ccb = ((Cc*)(uart->regs))->ccb; p = malloc(READSTR); bs = ccb->bs; fstat = ccb->df; ms = ccb->ms; snprint(p, READSTR, "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n" "dev(%d) type(%d) framing(%d) overruns(%d) " "berr(%d) serr(%d)%s%s%s%s\n", uart->baud, uart->hup_dcd, ms & Sdsr, uart->hup_dsr, (fstat & DbMASK) + 5, 0, (fstat & PMASK) ? ((fstat & Ep) == Ep? 'e': 'o'): 'n', (bs & Rbrts) ? 1 : 0, (fstat & Sb2) ? 2 : 1, 0, uart->dev, uart->type, uart->ferr, uart->oerr, uart->berr, uart->serr, (ms & Scts) ? " cts" : "", (ms & Sdsr) ? " dsr" : "", (ms & Sdcd) ? " dcd" : "", (ms & Sri) ? " ring" : "" ); n = readstr(offset, buf, n, p); free(p); return n;}static voidaxpfifo(Uart*, int){}static voidaxpdtr(Uart* uart, int on){ Ccb *ccb; u16int mc; ccb = ((Cc*)(uart->regs))->ccb; mc = ccb->mc; if(on) mc |= Adtr; else mc &= ~Adtr; ccb->mc = mc;}/* * can be called from uartstageinput() during an input interrupt, * with uart->rlock ilocked or the uart qlocked, sometimes both. */static voidaxprts(Uart* uart, int on){ Ccb *ccb; u16int mc; ccb = ((Cc*)(uart->regs))->ccb; mc = ccb->mc; if(on) mc |= Arts; else mc &= ~Arts; ccb->mc = mc;}static voidaxpmodemctl(Uart* uart, int on){ Ccb *ccb; u16int lp; ccb = ((Cc*)(uart->regs))->ccb; ilock(&uart->tlock); lp = ccb->lp; if(on){ lp |= Cts|Rts; lp &= ~Emcs; uart->cts = ccb->ms & Scts; } else{ lp &= ~(Cts|Rts); lp |= Emcs; uart->cts = 1; } uart->modem = on; iunlock(&uart->tlock); ccb->lp = lp; axpcc(uart->regs, Ccu);}static intaxpparity(Uart* uart, int parity){ Ccb *ccb; u16int df; switch(parity){ default: return -1; case 'e': parity = Ep; break; case 'o': parity = Op; break; case 'n': parity = Np; break; } ccb = ((Cc*)(uart->regs))->ccb; df = ccb->df & ~PMASK; ccb->df = df|parity; axpcc(uart->regs, Ccu); return 0;}static intaxpstop(Uart* uart, int stop){ Ccb *ccb; u16int df; switch(stop){ default: return -1; case 1: stop = Sb1; break; case 2: stop = Sb2; break; } ccb = ((Cc*)(uart->regs))->ccb; df = ccb->df & ~SbMASK; ccb->df = df|stop; axpcc(uart->regs, Ccu); return 0;}static intaxpbits(Uart* uart, int bits){ Ccb *ccb; u16int df; bits -= 5; if(bits < 0 || bits > 3) return -1; ccb = ((Cc*)(uart->regs))->ccb; df = ccb->df & ~DbMASK; ccb->df = df|bits; axpcc(uart->regs, Ccu); return 0;}static intaxpbaud(Uart* uart, int baud){ Ccb *ccb; int i, ibtr; /* * Set baud rate (high rates are special - only 16 bits). */ if(baud <= 0) return -1; uart->baud = baud; ccb = ((Cc*)(uart->regs))->ccb; switch(baud){ default: ccb->br = baud; break; case 76800: ccb->br = Br76800; break; case 115200: ccb->br = Br115200; break; } /* * Set trigger level to about 50 per second. */ ibtr = baud/500; i = (ccb->ibea - ccb->ibsa)/2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -