📄 devastar.c
字号:
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"/* * Stargate's Avanstar serial board. There are ISA, EISA, microchannel * versions. We only handle the ISA one. * * At the expense of performance, I've tried to be careful about * endian-ness to make this convertable to other ISA bus machines. * However, xchgw() is in assembler and will have to be translated. */#define LENDIAN 1/* unsigned short little endian representation */#ifdef LENDIAN#define LEUS(x) (x)#else#define LEUS(x) ( (((x)<<8)&0xff00) | (((x)>>8)&0xff) )#endif LENDIANtypedef struct Astar Astar;typedef struct Astarchan Astarchan;enum{ /* ISA control ports */ ISAid= 0, /* Id port and its values */ ISAid0= 0xEC, ISAid1= 0x13, ISAid0x= 0x69, ISAid1x= 0x96, ISActl1= 1, /* board control */ ISAien= 1<<7, /* interrupt enable */ ISAirq= 7<<4, /* mask for irq code */ ISAnotdl= 1<<1, /* download bit (0 == download) */ ISApr= 1<<0, /* program ready */ ISActl2= 2, /* board control */ ISA186ien= 1<<7, /* I186 irq enable bit state */ ISA186idata= 1<<6, /* I186 irq data bit state */ ISAmen= 1<<4, /* enable memory to respond to ISA cycles */ ISAmbank= 0xf<<0, /* shift for 4 bit memory bank */ ISAmaddr= 3, /* bits 14-19 of the boards mem address */ ISAstat1= 4, /* board status (1 bit per channel) */ ISAstat2= 5, /* board status (1 bit per channel) */ Pageshift= 14, /* footprint of card mem in ISA space */ Pagesize= 1<<Pageshift, Pagemask= Pagesize-1, PCIrange= 0x00, PCIremap= 0x04, PCIregion= 0x18, PCImailbox= 0x40, PCIdoorbell0= 0x60, PCIdoorbell1= 0x64, PCIcontrol= 0x68, /* write */ PCIstatus= 0x68, /* read */ PCIcommand= 0x6C, Maxcard= 8, Pramsize= 64*1024, /* size of program ram */};#define APAGE(x) ((x)>>Pageshift)#define LOCKPAGE(a, o) if((a)->needpage){ilock(&(a)->pagelock);setpage(a, o);}#define UNLOCKPAGE(a) if((a)->needpage)iunlock(&(a)->pagelock)/* IRQ codes */static int isairqcode[16] ={ -1, -1, -1, 0<<4, 1<<4, 2<<4, -1, -1, -1, 3<<4, 4<<4, 5<<4, 6<<4, -1, -1, 7<<4,};/* control program global control block */typedef struct GCB GCB;struct GCB{ ushort cmd; /* command word */ ushort status; /* status word */ ushort serv; /* service request, must be accessed via exchange 'X' */ ushort avail; /* available buffer space */ ushort type; /* board type */ ushort cpvers; /* control program version */ ushort ccbn; /* control channel block count */ ushort ccboff; /* control channel block offset */ ushort ccbsz; /* control channel block size */ ushort cmd2; /* command word 2 */ ushort status2; /* status word 2 */ ushort errserv; /* comm error service request 'X' */ ushort inserv; /* input buffer service request 'X' */ ushort outserv; /* output buffer service request 'X' */ ushort modemserv; /* modem change service request 'X' */ ushort cmdserv; /* channel command service request 'X' */};enum{ /* GCB.cmd commands/codes */ Greadycmd= 0, Gdiagcmd= 1, Gresetcmd= 2, /* GCB.status values */ Gready= 0, Gstopped= 1, Gramerr= 2, Gbadcmd= 3, Gbusy= 4, /* GCB.type values */ Gx00m= 0x6, G100e= 0xA, Gx00i= 0xC, /* GCB.cmd2 bit */ Gintack= 0x1, /* GCB.status2 bits */ Ghas232= (1<<0), Ghas422= (1<<1), Ghasmodems= (1<<2), Ghasrj11s= (1<<7), Ghasring= (1<<8), Ghasdcd= (1<<9), Ghasdtr= (1<<10), Ghasdsr= (1<<11), Ghascts= (1<<12), Ghasrts= (1<<13),};/* control program channel control block */typedef struct CCB CCB;struct CCB{ ushort baud; /* baud rate */ ushort format; /* data format */ ushort proto; /* line protocol */ ushort insize; /* input buffer size */ ushort outsize; /* output buffer size */ ushort intrigger; /* input buffer trigger rate */ ushort outlow; /* output buffer low water mark */ char xon[2]; /* xon characters */ ushort inhigh; /* input buffer high water mark */ ushort inlow; /* input buffer low water mark */ ushort cmd; /* channel command */ ushort status; /* channel status */ ushort inbase; /* input buffer start addr */ ushort inlim; /* input buffer ending addr */ ushort outbase; /* output buffer start addr */ ushort outlim; /* output buffer ending addr */ ushort inwp; /* input read and write pointers */ ushort inrp; ushort outwp; /* output read and write pointers */ ushort outrp; ushort errstat; /* error status */ ushort badp; /* bad character pointer */ ushort mctl; /* modem control */ ushort mstat; /* modem status */ ushort bstat; /* blocking status */ ushort rflag; /* character received flag */ char xoff[2]; /* xoff characters */ ushort status2; char strip[2]; /* strip/error characters */};enum{ /* special baud rate codes for CCB.baud */ Cb76800= 0xff00, Cb115200= 0xff01, /* CCB.format fields */ Clenmask= 3<<0, /* data bits */ C1stop= 0<<2, /* stop bits */ C2stop= 1<<2, Cnopar= 0<<3, /* parity */ Coddpar= 1<<3, Cevenpar= 3<<3, Cmarkpar= 5<<3, Cspacepar= 7<<3, Cparmask= 7<<3, Cnormal= 0<<6, /* normal mode */ Cecho= 1<<6, /* echo mode */ Clloop= 2<<6, /* local loopback */ Crloop= 3<<6, /* remote loopback */ /* CCB.proto fields */ Cobeyxon= 1<<0, /* obey received xoff/xon controls */ Canyxon= 1<<1, /* any rcvd character restarts xmit */ Cgenxon= 1<<2, /* generate xoff/xon controls */ Cobeycts= 1<<3, /* obey hardware flow ctl */ Cgendtr= 1<<4, /* dtr off when uart rcvr full */ C½duplex= 1<<5, /* rts off while xmitting */ Cgenrts= 1<<6, /* generate hardware flow ctl */ Cmctl= 1<<7, /* direct modem control via CCB.mctl */ Cstrip= 1<<12, /* to strip out characters */ Ceia422= 1<<13, /* to select eia 422 lines */ /* CCB.cmd fields */ Cconfall= 1<<0, /* configure channel and UART */ Cconfchan= 1<<1, /* configure just channel */ Cflushin= 1<<2, /* flush input buffer */ Cflushout= 1<<3, /* flush output buffer */ Crcvena= 1<<4, /* enable receiver */ Crcvdis= 1<<5, /* disable receiver */ Cxmtena= 1<<6, /* enable transmitter */ Cxmtdis= 1<<7, /* disable transmitter */ Cmreset= 1<<9, /* reset modem */ /* CCB.errstat fields */ Coverrun= 1<<0, Cparity= 1<<1, Cframing= 1<<2, Cbreak= 1<<3, /* CCB.mctl fields */ Cdtrctl= 1<<0, Crtsctl= 1<<1, Cbreakctl= 1<<4, /* CCB.mstat fields */ Cctsstat= 1<<0, Cdsrstat= 1<<1, Cristat= 1<<2, Cdcdstat= 1<<3, /* CCB.bstat fields */ Cbrcvoff= 1<<0, Cbxmtoff= 1<<1, Clbxoff= 1<<2, /* transmitter blocked by XOFF */ Clbcts= 1<<3, /* transmitter blocked by CTS */ Crbxoff= 1<<4, /* remote blocked by xoff */ Crbrts= 1<<4, /* remote blocked by rts */};/* host per controller info */struct Astar{ QLock; /* lock for rendez */ Rendez r; /* waiting for command completion */ ISAConf; Pcidev* pci; Lock pagelock; /* lock for setting page */ int page; /* page currently mapped */ int id; /* from plan9.ini */ int nchan; /* number of channels */ Astarchan *c; /* channels */ int ramsize; /* 16k or 256k */ int memsize; /* size of memory currently mapped */ int needpage; int pagebase; /* pci */ GCB *gcb; /* global board comm area */ uchar *addr; /* base of memory area */ int running;};/* host per channel info */struct Astarchan{ QLock; /* lock for rendez */ Rendez r; /* waiting for command completion */ Astar *a; /* controller */ CCB *ccb; /* channel control block */ int perm; int opens; int baud; /* baud rate */ int framing; /* framing errors */ int overrun; /* overruns */ int hup_dsr; /* hangup when dsr goes away */ int hup_dcd; /* hangup when dcd goes away */ int dtr; /* non-zero means dtr on */ int rts; /* non-zero means rts on */ int dsr; /* non-zero means dsr on */ int dcd; /* non-zero means dcd on */ Queue *iq; Queue *oq;};Astar *astar[Maxcard];static int nastar;enum{ Qmem= 1, Qbctl, Qdata, Qctl, Qstat,};#define TYPE(x) ((x)&0xff)#define BOARD(x) (((x)>>16)&0xff)#define CHAN(x) (((x)>>8)&0xff)#define QID(b,c,t) (((b)<<16)|((c)<<8)|(t))static int astarsetup(Astar*);static void astarintr(Ureg*, void*);static void astarkick(void*);static void astarkickin(void*);static void enable(Astarchan*);static void disable(Astarchan*);static void astarctl(Astarchan*, char*);/* * Only 16k maps into ISA space */static voidsetpage(Astar *a, ulong offset){ int i; if(a->pci){ print("#G%d: setpage caller pc %luX\n", a->id, getcallerpc(&a)); return; } i = APAGE(offset); if(i == a->page) return; outb(a->port+ISActl2, ISAmen|i); a->page = i;}/* * generate the astar directory entries */static intastargen(Chan *c, Dirtab *, int , int i, Dir *db){ int dev, sofar, ch, t; extern ulong kerndate; memset(db, 0, sizeof(Dir)); sofar = 0; if(i == DEVDOTDOT){ devdir(c, (Qid){CHDIR, 0}, "#G", 0, eve, 0555, db); return 1; } for(dev = 0; dev < nastar; dev++){ if(sofar == i){ sprint(db->name, "astar%dmem", astar[dev]->id); db->qid.path = QID(dev, 0, Qmem); db->mode = 0660; db->length = astar[dev]->memsize; break; } sofar++; if(sofar == i){ sprint(db->name, "astar%dctl", astar[dev]->id); db->qid.path = QID(dev, 0, Qbctl); db->mode = 0660; break; } sofar++; if(i - sofar < 3*astar[dev]->nchan){ i -= sofar; ch = i/3; t = i%3; switch(t){ case 0: sprint(db->name, "eia%d%2.2d", astar[dev]->id, ch); db->mode = astar[dev]->c[ch].perm; db->qid.path = QID(dev, ch, Qdata); db->length = qlen(astar[dev]->c[ch].iq); break; case 1: sprint(db->name, "eia%d%2.2dctl", astar[dev]->id, ch); db->mode = astar[dev]->c[ch].perm; db->qid.path = QID(dev, ch, Qctl); break; case 2: sprint(db->name, "eia%d%2.2dstat", astar[dev]->id, ch); db->mode = 0444; db->qid.path = QID(dev, ch, Qstat); break; } break; } sofar += 3*astar[dev]->nchan; } if(dev == nastar) return -1; db->qid.vers = 0; db->atime = seconds(); db->mtime = kerndate; memmove(db->uid, eve, NAMELEN); memmove(db->gid, eve, NAMELEN); db->type = devtab[c->type]->dc; db->dev = c->dev; if(c->flag&CMSG) db->mode |= CHMOUNT; return 1;}static voidastarreset(void){ int i, x; Astar *a; Pcidev *p; char name[8]; p = nil; for(i = 0; i < Maxcard; i++){ a = astar[nastar] = xalloc(sizeof(Astar)); if(isaconfig("serial", i, a) == 0){ xfree(a); astar[nastar] = 0; continue; } a->ramsize = 0; /* check all possible names */ if(cistrcmp(a->type, "a100i") == 0) a->ramsize = 16*1024; else if(cistrcmp(a->type, "a200i") == 0 || cistrcmp(a->type,"A200I") == 0 || cistrcmp(a->type, "a16i") == 0) a->ramsize = 256*1024; else if(cistrcmp(a->type, "AvanstarXp") == 0){ if(p = pcimatch(p, 0x114F, 0x6001)){ a->pci = p; /* * It's really 128KB, but split into * two 64KB chunks. */ a->ramsize = 64*1024; } } if(a->ramsize == 0){ xfree(a); astar[nastar] = 0; continue; } a->id = i; if(a->pci){ a->irq = p->intl; a->port = p->mem[1].bar & ~0x03; a->mem = upamalloc(p->mem[2].bar & ~0x0F, p->mem[2].size, 0); a->addr = (uchar*)a->mem; a->gcb = (GCB*)(a->mem+0x10000); sprint(name, "astar%d", i); if(ioalloc(a->port, p->mem[1].size, 0, name) < 0){ print("#G%d: port 0x%lux in use\n", a->id, a->port); xfree(a); astar[nastar] = 0; continue; } /* * Toggle the software reset and wait for * the adapter local init status to indicate done. */ outl(a->port+PCIremap, 0xA0000001); x = inl(a->port+PCIcommand); outl(a->port+PCIcommand, 0x40000000|x); microdelay(1); outl(a->port+PCIcommand, x); delay(100); for(x = 0; x < 10000; x++){ if(inl(a->port+PCIcommand) & 0x80000000) break; } if(!(inl(a->port+PCIcommand) & 0x80000000)) print("#G%d: didn't reset\n", a->id); /* * So the memory can be read before any other * initialisation takes place. */ a->memsize = a->ramsize; } else{ /* defaults */ if(a->irq == 0) a->irq = 15; a->mem = umbmalloc(a->mem, Pagesize, Pagesize); if(a->mem == 0) panic("astarreset: %lux", a->mem); a->mem = PADDR(a->mem); if(astarsetup(a) < 0){ xfree(a); astar[nastar] = 0; continue; } print("\tctl1 %ux ctl2 %ux maddr %ux stat1 %ux stat2 %ux\n", inb(a->port+ISActl1), inb(a->port+ISActl2), inb(a->port+ISAmaddr), inb(a->port+ISAstat1), inb(a->port+ISAstat2)); } print("#G%d: %s port 0x%luX addr 0x%luX irq %lud\n", a->id, a->type, a->port, a->addr, a->irq); nastar++; }}/* isa ports an ax00i can appear at */static int isaport[] = { 0x200, 0x208, 0x300, 0x308, 0x600, 0x608, 0x700, 0x708, 0 };static intastarprobe(int port){ uchar c, c1; if(port < 0) return 0; c = inb(port+ISAid); c1 = inb(port+ISAid); return (c == ISAid0 && c1 == ISAid1) || (c == ISAid1 && c1 == ISAid0) || (c == ISAid0x && c1 == ISAid1x) || (c == ISAid1x && c1 == ISAid0x);}static intastarsetup(Astar *a){ int i, found; char name[8]; /* see if the card exists */ found = 0; if(a->port == 0) for(i = 0; isaport[i]; i++){ a->port = isaport[i]; sprint(name, "astar%d", a->id); if(ioalloc(a->port, 6, 0, name) < 0) continue; found = astarprobe(isaport[i]); if(found){ isaport[i] = -1; break; } } else { sprint(name, "astar%d", a->id);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -