#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "devtab.h" /* * Stargate's Avanstar serial board. There are ISA, EISA, microchannel * versions. We only handle the ISA one. */ typedef struct Astar Astar; typedef struct Astarchan Astarchan; enum { /* ISA control ports */ ISAid= 0, /* Id port and its values */ ISAid0= 0xEC, ISAid1= 0x13, ISActl1= 1, /* board control */ ISAien= 1<<7, /* interrupt enable */ ISAirq= 7<<4, /* mask for irq code */ ISAdl= 1<<1, /* download bit (1 == 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= 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) */ Maxcard= 8, Pramsize= 64*1024, /* size of program ram */ Footshift= 14, /* footprint of card mem in ISA space */ Footprint= 1<>16)&0xff) #define CHAN(x) ((((x)&~CHDIR)>>8)&0xff) #define QID(b,c,t) (((b)<<16)|((c)<<8)|(t)) static int astarsetup(Astar*); int astargen(Chan *c, Dirtab *tab, int ntab, int i, Dir *db) { int dev, sofar, ch, t; extern ulong kerndate; USED(tab, ntab); sofar = 0; for(dev = 0; dev < nastar; dev++){ if(sofar == i){ sprint(db->name, "atar%dmem", astar[dev]->id); db->qid.path = QID(dev, 0, Qmem); db->mode = 0660; break; } sofar++; if(sofar == i){ sprint(db->name, "atar%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", dev, ch); db->mode = astar[dev]->c[ch].perm; db->qid.path = QID(dev, 0, Qdata); break; case 1: sprint(db->name, "eia%d%2.2dctl", dev, ch); db->mode = astar[dev]->c[ch].perm; db->qid.path = QID(dev, 0, Qctl); break; case 2: sprint(db->name, "eia%d%2.2dstat", dev, ch); db->mode = 0444; db->qid.path = QID(dev, 0, Qstat); break; } break; } sofar += 3*astar[dev]->nchan; } if(dev == nastar) return -1; db->atime = seconds(); db->mtime = kerndate; db->hlength = 0; db->length = 0; /* update ???? */ memmove(db->uid, eve, NAMELEN); memmove(db->gid, eve, NAMELEN); db->type = devchar[c->type]; db->dev = c->dev; if(c->flag&CMSG) db->mode |= CHMOUNT; return 1; } void astarreset(void) { int i; Astar *a; for(i = 0; i < Maxcard; i++){ a = astar[nastar] = xalloc(sizeof(Astar)); if(isaconfig("serial", i, a) == 0){ xfree(a); astar[nastar] = 0; break; } if(strcmp(a->type, "a100i") == 0 || strcmp(a->type,"A100I") == 0) a->ramsize = 16*1024; else if(strcmp(a->type, "a200i") == 0 || strcmp(a->type,"A200I") == 0) a->ramsize = 256*1024; else continue; if(a->mem == 0) a->mem = 0xD4000; if(a->irq == 0) a->irq = 15; a->id = i; if(astarsetup(a) < 0){ xfree(a); astar[nastar] = 0; continue; } print("serial%d avanstar addr %lux irq %d\n", i, a->addr, a->irq); nastar++; } } /* isa ports an ax00i can appear at */ int isaport[] = { 0x200, 0x208, 0x300, 0x308, 0x600, 0x608, 0x700, 0x708, 0 }; static int astarprobe(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); } static int astarsetup(Astar *a) { int i, found; /* see if the card exists */ found = 0; if(a->port == 0) for(i = 0; isaport[i]; i++){ a->port = isaport[i]; found = astarprobe(isaport[i]); if(found){ isaport[i] = -1; break; } } else found = astarprobe(a->port); if(!found){ print("avanstar %d not found\n", a->id); return -1; } /* set memory address */ outb(a->port + ISAmaddr, (a->mem>>12) & 0xfc); a->gbc = (GCB*)(KZERO | a->mem); a->addr = (char*)(KZERO | a->mem); /* set interrupt level */ if(isairqcode[a->irq] == -1){ print("Avanstar %d bad irq %d\n", a->id, a->irq); return -1; } return 0; } void astarinit(void) { } Chan* astarattach(char *spec) { return devattach('g', spec); } Chan* astarclone(Chan *c, Chan *nc) { return devclone(c, nc); } int astarwalk(Chan *c, char *name) { return devwalk(c, name, 0, 0, astargen); } void astarstat(Chan *c, char *dp) { devstat(c, dp, 0, 0, astargen); } Chan* astaropen(Chan *c, int omode) { Astar *a; c = devopen(c, omode, 0, 0, astargen); switch(TYPE(c->qid.path)){ case Qmem: case Qbctl: if(!iseve()) error(Eperm); break; } return c; } void astarclose(Chan *c) { Astar *a; int i; switch(TYPE(c->qid.path)){ case Qmem: a = astar[BOARD(c->qid.path)]; qlock(a); if(--a->opens == 0){ /* take board out of download mode and enable IRQ */ outb(a->port + ISActl1, ISAien|isairqcode[a->irq]); /* enable ISA access to first 16k */ outb(a->port + ISActl2, ISAmen|0); /* wait for program ready */ for(i = 0; i < 21; i++){ if(inb(a->port + ISActl1) & ISApr) break; tsleep(&r, return0, 0, 500); } if((inb(a->port + ISActl1) & ISApr) == 0) print("astar%d program not ready\n", a->id); } qunlock(a); break; } } long astarread(Chan *c, void *buf, long n, ulong offset) { int i; Astar *a; char *to, *from, *e; char status[128]; if(c->qid.path & CHDIR) return devdirread(c, buf, n, 0, 0, astargen); switch(TYPE(c->qid.path)){ case Qmem: a = astar[BOARD(c->qid.path)]; if(offset+n > Pramsize){ if(offset >= Pramsize) return 0; n = Pramsize - offset; } if(waserror()){ qunlock(a); nexterror(); } qlock(a); from = buf; while(n > 0){ /* map in right piece of memory */ outb(a->port + ISActl2, ISAmen|(offset>>Footshift)); i = offset%Footprint; to = a->addr + i; i = Footprint - i; if(i > n) i = n; /* byte at a time so endian doesn't matter */ for(e = from + i; from < e;) *to++ = *from++; n -= i; } qunlock(a); poperror(); break; case Qbctl: a = astar[BOARD(c->qid.path)]; sprint(status, "id %2.2ux%2.2ux ctl1 %2.2ux ctl2 %2.2ux maddr %2.2ux stat %2.2ux%2.2ux", inb(a->port+ISAid), inb(a->port+ISAid), inb(a->port+ISActl1), inb(a->port+ISActl2), inb(a->port+ISAmaddr), inb(a->port+ISAstat2), inb(a->port+ISAstat1)); n = readstr(offset, buf, n, status); break; } return 0; } long astarwrite(Chan *c, void *buf, long n, ulong offset) { Astar *a; char *to, *from, *e; int i; char cmsg[32]; if(c->qid.path & CHDIR) error(Eperm); switch(TYPE(c->qid.path)){ case Qmem: a = astar[BOARD(c->qid.path)]; if(offset+n > Pramsize){ if(offset >= Pramsize) return 0; n = Pramsize - offset; } if(waserror()){ qunlock(a); nexterror(); } qlock(a); to = buf; while(n > 0){ /* map in right piece of memory */ outb(a->port + ISActl2, ISAmen|(offset>>Footshift)); i = offset%Footprint; from = a->addr + i; i = Footprint - i; if(i > n) i = n; /* byte at a time so endian doesn't matter */ for(e = from + i; from < e;) *to++ = *from++; n -= i; } qunlock(a); poperror(); break; case Qbctl: if(n > sizeof cmsg) n = sizeof(cmsg) - 1; memmove(cmsg, buf, n); cmsg[n] = 0; if(waserror()){ qunlock(a); nexterror(); } qlock(a); if(strncmp(cmsg, "download", 8) == 0){ /* put board in download mode */ outb(a->port + ISActl1, ISAdl); /* enable ISA access to first 16k */ outb(a->port + ISActl2, ISAmen); } else if(strncmp(cmsg, "run", 3) == 0){ /* take board out of download mode and enable IRQ */ outb(a->port + ISActl1, ISAien|isairqcode[a->irq]); /* enable ISA access to first 16k */ outb(a->port + ISActl2, ISAmen); /* wait for control program to signal life */ for(i = 0; i < 21; i++){ if(inb(a->port + ISActl1) & ISApr) break; tsleep(&a->r, return0, 0, 500); } if((inb(a->port + ISActl1) & ISApr) == 0) print("astar%d program not ready\n", a->id); } else error(Ebadarg); qunlock(a); poperror(); break; } return 0; } void astarcreate(Chan *c, char *name, int omode, ulong perm) { USED(c, name, omode, perm); error(Eperm); } void astarremove(Chan *c) { USED(c); error(Eperm); } void astarwstat(Chan *c, char *dp) { USED(c, dp); error(Eperm); }