From c35f9ac12ce1b4ada6fa52887455fd2d439fde20 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 15 Sep 1993 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1993-09-15 --- carrera/io.h | 4 + carrera/main.c | 4 +- carrera/mmu.c | 11 +- carrera/segment.h | 9 +- pc/adaptec.c | 116 ++++------- pc/clock.c | 28 +-- pc/dat.h | 52 ++--- pc/devfloppy.c | 47 +++-- pc/devhard.c | 44 ++-- pc/devincon.c | 37 +++- pc/devrtc.c | 10 +- pc/devuart.c | 504 ++++++++++++++++++++++++---------------------- pc/devvga.c | 21 +- pc/dma.c | 40 +++- pc/ether.h | 13 +- pc/ether2000.c | 121 ++++++----- pc/ether503.c | 6 + pc/ether509.c | 374 +++++++++++++++++----------------- pc/ether8003.c | 214 ++++++++++---------- pc/ether8390.c | 224 ++++++++++++--------- pc/fault386.c | 9 +- pc/fns.h | 17 +- pc/kbd.c | 82 +++++++- pc/l.s | 158 ++++++--------- pc/main.c | 283 +++++++++++++++++++------- pc/mem.h | 5 +- pc/mmu.c | 119 +++++------ pc/scsi.c | 84 ++++++++ pc/trap.c | 164 ++++++++------- pc/ultrastor.c | 484 ++++++++++++++++++++++++++++++++++++++++++++ port/portdat.h | 2 +- port/portfns.h | 2 +- power/main.c | 2 +- 33 files changed, 2092 insertions(+), 1198 deletions(-) create mode 100644 pc/scsi.c create mode 100644 pc/ultrastor.c diff --git a/carrera/io.h b/carrera/io.h index 7a5ee5ab7cb6b222775c463c913a7fcda770af21..5c87af7f69c0db4d77a7d87969a756d246a32d59 100644 --- a/carrera/io.h +++ b/carrera/io.h @@ -1,5 +1,8 @@ /* * These register addresses have already been adjusted for BE operation + * + * The EISA memory address is completely fictional. Look at mmu.c for + * a translation of Eisamphys into a 33 bit address. */ enum { @@ -35,6 +38,7 @@ enum I386ack = 0xE000023f, EisaControl = 0xE0010000, /* Second 64K Page from Devicevirt */ Eisamphys = 0x91000000, + Eisavgaphys = Eisamphys+0xA0000, Eisamvirt = 0xE0300000, /* Second 1M page entry from Intctl */ Intctlphys = 0xF0000000, Intctlvirt = 0xE0200000, diff --git a/carrera/main.c b/carrera/main.c index 497f97b1db697b4a71b918f64a440df8d069a03a..98f195101c7f6245b029d8bb284bd6c33d8258a8 100644 --- a/carrera/main.c +++ b/carrera/main.c @@ -51,8 +51,8 @@ main(void) pageinit(); procinit0(); initseg(); + links(); chandevreset(); - rootfiles(); swapinit(); userinit(); schedinit(); @@ -179,7 +179,7 @@ ioinit(void) * Map Interrupt control & Eisa memory */ intphys = IOPTE|PPN(Intctlphys); - isamphys = IOPTE|PPN(Eisamphys); + isamphys = /* IOPTE|PPN(Eisamphys) */ PTEGLOBL; puttlbx(2, Intctlvirt, intphys, isamphys, PGSZ1M); diff --git a/carrera/mmu.c b/carrera/mmu.c index 637a72ce013f973c7a29d3bd579c61a68cc5bb80..258376d5c82812bfb1ee9c4ae33cab682f3f42d1 100644 --- a/carrera/mmu.c +++ b/carrera/mmu.c @@ -3,6 +3,7 @@ #include "mem.h" #include "dat.h" #include "fns.h" +#include "io.h" /* * tlb entry 0 is used only by mmuswitch() to set the current tlb pid. @@ -258,16 +259,24 @@ newtlbpid(Proc *p) void putmmu(ulong tlbvirt, ulong tlbphys, Page *pg) { + int s; short tp; char *ctl; Softtlb *entry; - int s; s = splhi(); tp = up->pidonmach[m->machno]; if(tp == 0) tp = newtlbpid(up); + /* + * Fix up EISA memory address which are greater + * than 32 bits physical: 0x100000000 + */ + if((tlbphys&0xffff0000) == PPN(Eisamphys)) { + tlbphys &= ~PPN(Eisamphys); + tlbphys |= 0x04000000; + } tlbvirt |= PTEPID(tp); if((tlbphys & PTEALGMASK) != PTEUNCACHED) { tlbphys &= ~PTEALGMASK; diff --git a/carrera/segment.h b/carrera/segment.h index f71f019956f3423edc1787db22a79d2684b7e251..b21cc36b6c408c85ac2ab37ef4a34f4bed63ff70 100644 --- a/carrera/segment.h +++ b/carrera/segment.h @@ -4,8 +4,9 @@ Physseg physseg[] = { - { SG_SHARED, "shared", 0, SEGMAXSIZE, 0, 0 }, - { SG_BSS, "memory", 0, SEGMAXSIZE, 0, 0 }, - { SG_PHYSICAL, "eisaio", Eisaphys, 64*1024, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, + { SG_SHARED, "shared", 0, SEGMAXSIZE, 0, 0 }, + { SG_BSS, "memory", 0, SEGMAXSIZE, 0, 0 }, + { SG_PHYSICAL, "eisaio", Eisaphys, 64*1024, 0, 0 }, + { SG_PHYSICAL, "eisavga", Eisavgaphys, 128*1024, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, }; diff --git a/pc/adaptec.c b/pc/adaptec.c index 632a1cb512ab063c2a57767423a28e2a4a717155..8c9ff7088a0f647ee23303676b07fd855a581563 100644 --- a/pc/adaptec.c +++ b/pc/adaptec.c @@ -1,5 +1,9 @@ /* - * Adaptec AHA-154[02]B Intelligent Host Adapter. + * Adaptec AHA-154[02][BC] Intelligent Host Adapter. + * Needs work: + * handle multiple controllers; + * set options from user-level; + * split out to handle ultrastor too; */ #include "u.h" #include "../port/lib.h" @@ -11,12 +15,6 @@ #include "ureg.h" -/* - * Uniprocessors can't (don't need to) lock. - */ -#define lock(l) -#define unlock(l) - enum { NCtlr = 1, NTarget = 8, /* targets per controller */ @@ -314,7 +312,8 @@ scsiio(int bus, Scsi *p, int rw) * requests off the queue in any order. */ s = splhi(); - lock(ctlr); + if(active.machs > 1) + lock(ctlr); tp->done = 0; tp->active = ctlr->active; @@ -334,7 +333,8 @@ scsiio(int bus, Scsi *p, int rw) if(ctlr->mbox >= &ctlr->mb[NTarget]) ctlr->mbox = ctlr->mb; - unlock(ctlr); + if(active.machs > 1) + unlock(ctlr); splx(s); /* @@ -364,8 +364,8 @@ scsiio(int bus, Scsi *p, int rw) return status; } -int -scsiexec(Scsi *p, int rw) +static int +aha1542exec(Scsi *p, int rw) { Ctlr *ctlr = &softctlr[0]; @@ -387,7 +387,8 @@ interrupt(Ureg *ur) USED(ur); - lock(ctlr); + if(active.machs > 1) + lock(ctlr); /* * Save and clear the interrupt(s). The only @@ -430,7 +431,8 @@ interrupt(Ureg *ur) ctlr->mbix = &ctlr->mb[NTarget]; } - unlock(ctlr); + if(active.machs > 1) + unlock(ctlr); } static void @@ -465,83 +467,39 @@ reset(Ctlr *ctlr, ulong port, ulong id) issue(ctlr); } -void -resetscsi(void) +static ISAConf aha1542 = { + "aha1542", + Port, + Irq, + 0, + 0, +}; + +int (* +aha1542reset(void))(Scsi*, int) { - ulong port; + ISAConf *isa = &aha1542; /* - * For the moment assume the factory default settings. + * See if we have any configuration info. + * Only one controller for now. */ - port = Port; + if(isaconfig("scsi", 0, &aha1542) == 0) + return 0; /* - * Attempt to soft-reset the board and reset + * Attempt to hard-reset the board and reset * the SCSI bus. If the board state doesn't settle to * idle with mailbox initialisation required, either * it isn't an Adaptec or it's broken. */ - outb(port+Rc, Srst|Scrst); + outb(isa->port+Rc, Hrst|Scrst); delay(500); - if(inb(port+Rs) != (Init|Idle)) - return; - - setvec(Int0vec+Irq, interrupt); - reset(&softctlr[0], port, CtlrID); -} - -/* - * Known to devscsi.c. - */ -int scsidebugs[8]; -int scsiownid = CtlrID; - -void -initscsi(void) -{ -} - -/* - * Quick hack. Need to do a better job of dynamic initialisation - * for machines with peculiar memory/cache restictions. - * Also, what about 16Mb address limit on the Adaptec? - */ -static ulong bufdatasize; - -void -scsibufreset(ulong datasize) -{ - bufdatasize = datasize; -} - -Scsibuf * -scsibuf(void) -{ - Scsibuf *b; + if(inb(isa->port+Rs) != (Init|Idle)) + return 0; - b = smalloc(sizeof(*b)); - b->virt = smalloc(bufdatasize); - b->phys = (void *)(PADDR(b->virt)); - return b; -} - -void -scsifree(Scsibuf *b) -{ - free(b->virt); - free(b); -} - -/* - * Hack for devvid - */ -Scsibuf * -scsialloc(ulong n) -{ - Scsibuf *b; + setvec(Int0vec+isa->irq, interrupt); + reset(&softctlr[0], isa->port, CtlrID); - b = smalloc(sizeof(*b)); - b->virt = smalloc(n); - b->phys = (void *)(PADDR(b->virt)); - return b; + return aha1542exec; } diff --git a/pc/clock.c b/pc/clock.c index 88f815a8253ef35d0a464c92fa48c95a4182e64d..190bcc22eadb5f61859f1f0a981a959e16e5e6a1 100644 --- a/pc/clock.c +++ b/pc/clock.c @@ -72,7 +72,7 @@ clockinit(void) x -= y; /* - * fix count, the factor of 2 is a hack + * fix count */ delayloop = (delayloop*1193*10)/x; if(delayloop == 0) @@ -104,20 +104,14 @@ clock(Ureg *ur) nrun = (nrdy+nrun)*1000; MACHP(0)->load = (MACHP(0)->load*19+nrun)/20; - if(u && p && p->state==Running){ - /* - * preemption - */ - if(anyready()){ - if(p->hasspin) - p->hasspin = 0; - else - sched(); - } - if((ur->cs&0xffff) == UESEL){ - spllo(); /* in case we fault */ - (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1); /* profiling clock */ - splhi(); - } - } + if(up == 0 || (ur->cs&0xffff) != UESEL || up->state != Running) + return; + + if(anyready()) + sched(); + + /* user profiling clock */ + spllo(); /* in case we fault */ + (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1); + splhi(); } diff --git a/pc/dat.h b/pc/dat.h index 2828a30835d3def6aa7536efbc3975e4548a02ae..9cd3e86fdf765bd4883302344d69ac3a6e94fb13 100644 --- a/pc/dat.h +++ b/pc/dat.h @@ -1,5 +1,6 @@ typedef struct Conf Conf; typedef struct FPsave FPsave; +typedef struct ISAConf ISAConf; typedef struct Label Label; typedef struct Lock Lock; typedef struct MMU MMU; @@ -9,7 +10,6 @@ typedef struct Page Page; typedef struct PMMU PMMU; typedef struct Segdesc Segdesc; typedef struct Ureg Ureg; -typedef struct User User; #define MACHP(n) (n==0? &mach0 : *(Mach**)0) @@ -88,6 +88,7 @@ struct Conf */ #define MAXMMU 4 #define MAXSMMU 1 +#define NCOLOR 1 struct PMMU { Page *mmutop; /* 1st level table */ @@ -131,36 +132,6 @@ typedef void KMap; #define kmap(p) (KMap*)((p)->pa|KZERO) #define kunmap(k) -#define NERR 15 -#define NNOTE 5 -struct User -{ - Proc *p; - FPsave fpsave; /* address of this is known by vdb */ - int scallnr; /* sys call number - known by db */ - Sargs s; /* address of this is known by db */ - int nerrlab; - Label errlab[NERR]; - char error[ERRLEN]; - char elem[NAMELEN]; /* last name element from namec */ - Chan *slash; - Chan *dot; - /* - * Rest of structure controlled by devproc.c and friends. - * lock(&p->debug) to modify. - */ - Note note[NNOTE]; - short nnote; - short notified; /* sysnoted is due */ - Note lastnote; - int (*notify)(void*, char*); - void *ureg; - void *dbgreg; /* User registers for debugging in proc */ - ulong svcs; /* cs before a notify */ - ulong svss; /* ss before a notify */ - ulong svflags; /* flags before a notify */ -}; - /* * segment descriptor/gate */ @@ -192,11 +163,20 @@ struct PCArch int (*extvga)(int); /* 1 == external, 0 == internal */ }; -extern Mach *m; -extern User *u; +struct ISAConf { + char type[NAMELEN]; + ulong port; + ulong irq; + ulong mem; + ulong size; + uchar ea[6]; +}; -extern int flipD[]; /* for flipping bitblt destination polarity */ +#define MAXPCMCIA 8 /* maximum number of PCMCIA cards */ +#define BOOTLINE ((char *)0x80000100) /* bootline passed by boot program */ -#define BOOTLINE ((char *)0x80000100) /* bootline passed by boot program */ +extern int flipD[]; /* for flipping bitblt destination polarity */ +extern PCArch *arch; /* PC architecture */ -extern PCArch *arch; /* PC architecture */ +extern Mach *m; +extern Proc *up; diff --git a/pc/devfloppy.c b/pc/devfloppy.c index 305bfa543b200e863526a9bab0885c0807643afa..a1cab6659fdcb7c8df378f4d844d527e326523b9 100644 --- a/pc/devfloppy.c +++ b/pc/devfloppy.c @@ -440,12 +440,33 @@ changed(Chan *c, Drive *dp) error(Eio); } +static int +readtrack(Drive *dp, int cyl, int head) +{ + int i, nn, sofar; + ulong pos; + + nn = dp->t->tsize; + if(dp->ccyl==cyl && dp->chead==head) + return nn; + pos = (cyl*dp->t->heads+head) * nn; + for(sofar = 0; sofar < nn; sofar += i){ + dp->ccyl = -1; + i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar); + if(i <= 0) + return -1; + } + dp->ccyl = cyl; + dp->chead = head; + return nn; +} + long floppyread(Chan *c, void *a, long n, ulong offset) { Drive *dp; - long rv, i; - int nn, sec, head, cyl; + long rv; + int sec, head, cyl; long len; uchar *aa; @@ -468,7 +489,7 @@ floppyread(Chan *c, void *a, long n, ulong offset) changed(c, dp); for(rv = 0; rv < n; rv += len){ /* - * truncate xfer at track boundary + * all xfers come out of the track cache */ dp->len = n - rv; floppypos(dp, offset+rv); @@ -476,24 +497,8 @@ floppyread(Chan *c, void *a, long n, ulong offset) head = dp->thead; len = dp->len; sec = dp->tsec; - nn = dp->t->tsize; - - /* - * read the track - */ - if(dp->ccyl!=cyl || dp->chead!=head){ - dp->ccyl = -1; - i = floppyxfer(dp, Fread, dp->cache, - (cyl*dp->t->heads+head)*nn, nn); - if(i != nn){ - if(i == 0) - break; - len = 0; - continue; - } - dp->ccyl = cyl; - dp->chead = head; - } + if(readtrack(dp, cyl, head) < 0) + break; memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len); } qunlock(&fl); diff --git a/pc/devhard.c b/pc/devhard.c index 5a22656dc50d50d17eb11ae187829f4492aed3fb..da3627193d8a791e345f45e21325f1665ae3de61 100644 --- a/pc/devhard.c +++ b/pc/devhard.c @@ -155,7 +155,7 @@ hardgen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp) name[NAMELEN] = 0; qid.path = MKQID(drive, s); l = (pp->end - pp->start) * dp->bytes; - devdir(c, qid, name, l, eve, 0666, dirp); + devdir(c, qid, name, l, eve, 0660, dirp); return 1; } @@ -447,7 +447,7 @@ hardxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf) Controller *cp; long lblk; int cyl, sec, head; - int loop, s; + int loop, s, stat; if(dp->online == 0) error(Eio); @@ -502,12 +502,15 @@ hardxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf) outb(cp->pbase+Pcmd, cmd); if(cmd == Cwrite){ loop = 0; - while((inb(cp->pbase+Pstatus) & Sdrq) == 0) + while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0) if(++loop > 10000) panic("hardxfer"); outss(cp->pbase+Pdata, cp->buf, dp->bytes/2); - } + } else + stat = 0; splx(s); + if(stat & Serr) + error(Eio); /* * wait for command to complete. if we get a note, @@ -856,15 +859,30 @@ hardpart(Drive *dp) } /* - * read partition table from disk, null terminate + * read last sector from disk, null terminate. This used + * to be the sector we used for the partition tables. + * However, this sector is special on some PC's so we've + * started to use the second last sector as the partition + * table instead. To avoid reconfiguring all our old systems + * we first look to see if there is a valid partition + * table in the last sector. If so, we use it. Otherwise + * we switch to the second last. */ hardxfer(dp, pp, Cread, 0, dp->bytes, buf); buf[dp->bytes-1] = 0; + n = getfields(buf, line, Npart+1, '\n'); + if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ + dp->p[0].end--; + dp->p[1].start--; + dp->p[1].end--; + hardxfer(dp, pp, Cread, 0, dp->bytes, buf); + buf[dp->bytes-1] = 0; + n = getfields(buf, line, Npart+1, '\n'); + } /* * parse partition table. */ - n = getfields(buf, line, Npart+1, '\n'); if(n && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ for(i = 1; i < n; i++){ pp++; @@ -946,13 +964,6 @@ hardintr(Ureg *ur) break; case Cread: case Cident: - loop = 0; - while((inb(cp->pbase+Pstatus) & Sdrq) == 0) - if(++loop > 10000) { - DPRINT("cmd=%lux status=%lux\n", - cp->cmd, inb(cp->pbase+Pstatus)); - panic("hardintr: read/ident"); - } if(cp->status & Serr){ cp->lastcmd = cp->cmd; cp->cmd = 0; @@ -960,6 +971,13 @@ hardintr(Ureg *ur) wakeup(&cp->r); return; } + loop = 0; + while((inb(cp->pbase+Pstatus) & Sdrq) == 0) + if(++loop > 10000) { + DPRINT("cmd=%lux status=%lux\n", + cp->cmd, inb(cp->pbase+Pstatus)); + panic("hardintr: read/ident"); + } addr = cp->buf; if(addr){ addr += cp->sofar*dp->bytes; diff --git a/pc/devincon.c b/pc/devincon.c index 21afbea0c30c7cd3fffe68ed5f4bfd57943d7b76..65b8dfb1264920c1de987fbad2bcd0dfe03aec38 100644 --- a/pc/devincon.c +++ b/pc/devincon.c @@ -183,6 +183,19 @@ Dirtab incondir[]={ }; #define NINCON (sizeof incondir/sizeof incondir[0]) +static void +nop(void) +{ +} + +static int +slowinb(int x) +{ + nop(); + nop(); + return inb(x); +} + static void reset(int dev) /* hardware reset */ { @@ -261,9 +274,9 @@ irdstatus(Incon *ip) /* read status at interrupt level */ outb(dev+Qdlr, 0x01); outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); - data = (inb(dev+Qpsr)&0xf8)<<2; + data = (slowinb(dev+Qpsr)&0xf8)<<2; outb(dev+Qpcr, Finitbar|Faf|Fsi); - data |= inb(dev+Qpsr)>>3; + data |= slowinb(dev+Qpsr)>>3; if(data&(OVERFLOW|CRC_ERROR)){ if(data&OVERFLOW) ip->overflow++; @@ -281,9 +294,9 @@ irddata(int dev) /* read data at interrupt level */ outb(dev+Qdlr, 0x00); outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe); - data = (inb(dev+Qpsr)&0xf8)<<2; + data = (slowinb(dev+Qpsr)&0xf8)<<2; outb(dev+Qpcr, Finitbar|Faf|Fsi); - data |= inb(dev+Qpsr)>>3; + data |= slowinb(dev+Qpsr)>>3; return data; } @@ -311,6 +324,7 @@ irdnop(int dev, int pcr) /* read nop (mux reset) */ int Irdnext(int); #define irdnext Irdnext +/**/ /* * set the incon parameters @@ -366,11 +380,6 @@ inconsetctl(Incon *ip, Block *bp) freeb(bp); } -static void -nop(void) -{ -} - /* * poll for a station number */ @@ -472,6 +481,14 @@ void inconreset(void) { int i; + char *p; + + /* + * get incondev from p9rc + */ + p = getconf("incondev"); + if(p) + incondev = atoi(p); /* * state is Selected if we used incon as the boot device @@ -1089,6 +1106,8 @@ inconintr(Ureg *ur) USED(ur); ip = &incon[0]; pcr = inb(ip->dev+Qpcr); + if(!(pcr & Fie)) + return; status = irdstatus(ip); if(incondebug){ kprint("pcr=%2.2x status=%2.2x\n", pcr, status); diff --git a/pc/devrtc.c b/pc/devrtc.c index ccb1c8a5bafd884fab3a13f8370e3537e05c0174..99fb56d9b8c7f7cd6fca051e1987d8d726eb17c4 100644 --- a/pc/devrtc.c +++ b/pc/devrtc.c @@ -23,7 +23,7 @@ enum { Status= 0x0A, Nvoff= 128, /* where usable nvram lives */ - Nvsize= 128, + Nvsize= 256, Nbcd= 6, }; @@ -48,8 +48,8 @@ enum{ #define NRTC 2 Dirtab rtcdir[]={ - "nvram", {Qnvram, 0}, Nvsize, 0666, - "rtc", {Qrtc, 0}, 0, 0666, + "nvram", {Qnvram, 0}, Nvsize, 0664, + "rtc", {Qrtc, 0}, 0, 0664, }; ulong rtc2sec(Rtc*); @@ -96,11 +96,11 @@ rtcopen(Chan *c, int omode) omode = openmode(omode); switch(c->qid.path){ case Qrtc: - if(strcmp(u->p->user, eve)!=0 && omode!=OREAD) + if(strcmp(up->user, eve)!=0 && omode!=OREAD) error(Eperm); break; case Qnvram: - if(strcmp(u->p->user, eve)!=0) + if(strcmp(up->user, eve)!=0) error(Eperm); } return devopen(c, omode, rtcdir, NRTC, devgen); diff --git a/pc/devuart.c b/pc/devuart.c index d2ea4c28a00980f795f2c65e2783eea2e1e62a9c..2575cf488c735157fe903557569be2aa4dcf1425 100644 --- a/pc/devuart.c +++ b/pc/devuart.c @@ -7,7 +7,7 @@ #include "../port/error.h" #include "devtab.h" - +#define nelem(x) (sizeof(x)/sizeof(x[0])) /* * Driver for an NS16450 serial port */ @@ -17,12 +17,12 @@ enum * register numbers */ Data= 0, /* xmit/rcv buffer */ - Iena= 1, /* interrupt enable */ + Iena= 1, /* interrdpt enable */ Ircv= (1<<0), /* for char rcv'd */ Ixmt= (1<<1), /* for xmit buffer empty */ Irstat=(1<<2), /* for change in rcv'er status */ Imstat=(1<<3), /* for change in modem status */ - Istat= 2, /* interrupt flag (read) */ + Istat= 2, /* interrdpt flag (read) */ Tctl= 2, /* test control (write) */ Format= 3, /* byte format */ Bits8= (3<<0), /* 8 bits/byte */ @@ -36,7 +36,7 @@ enum Dtr= (1<<0), /* data terminal ready */ Rts= (1<<1), /* request to send */ Ri= (1<<2), /* ring */ - Inton= (1<<3), /* turn on interrupts */ + Inton= (1<<3), /* turn on interrdpts */ Loop= (1<<4), /* loop back */ Lstat= 5, /* line status */ Inready=(1<<0), /* receive buffer full */ @@ -86,9 +86,12 @@ struct Uart ulong overrun; }; -Uart uart[2]; +Uart uart[34]; +int Nuart; /* total no of uarts in the machine */ +int Nscard; /* number of serial cards */ +ISAConf scard[5]; /* configs for the serial card */ -#define UartFREQ 1846200 +#define UartFREQ 1843200 #define uartwrreg(u,r,v) outb((u)->port + r, (u)->sticky[r] | (v)) #define uartrdreg(u,r) inb((u)->port + r) @@ -96,6 +99,7 @@ Uart uart[2]; void uartintr(Uart*); void uartintr0(Ureg*); void uartintr1(Ureg*); +void uartintr2(Ureg*); void uartsetup(void); /* @@ -104,135 +108,136 @@ void uartsetup(void); * baud rates. */ void -uartsetbaud(Uart *up, int rate) +uartsetbaud(Uart *dp, int rate) { ulong brconst; brconst = (UartFREQ+8*rate-1)/(16*rate); - uartwrreg(up, Format, Dra); - outb(up->port+Dmsb, (brconst>>8) & 0xff); - outb(up->port+Dlsb, brconst & 0xff); - uartwrreg(up, Format, 0); + uartwrreg(dp, Format, Dra); + outb(dp->port+Dmsb, (brconst>>8) & 0xff); + outb(dp->port+Dlsb, brconst & 0xff); + uartwrreg(dp, Format, 0); } /* * toggle DTR */ void -uartdtr(Uart *up, int n) +uartdtr(Uart *dp, int n) { if(n) - up->sticky[Mctl] |= Dtr; + dp->sticky[Mctl] |= Dtr; else - up->sticky[Mctl] &= ~Dtr; - uartwrreg(up, Mctl, 0); + dp->sticky[Mctl] &= ~Dtr; + uartwrreg(dp, Mctl, 0); } /* * toggle RTS */ void -uartrts(Uart *up, int n) +uartrts(Uart *dp, int n) { if(n) - up->sticky[Mctl] |= Rts; + dp->sticky[Mctl] |= Rts; else - up->sticky[Mctl] &= ~Rts; - uartwrreg(up, Mctl, 0); + dp->sticky[Mctl] &= ~Rts; + uartwrreg(dp, Mctl, 0); } /* * send break */ void -uartbreak(Uart *up, int ms) +uartbreak(Uart *dp, int ms) { if(ms == 0) ms = 200; - uartwrreg(up, Format, Break); - tsleep(&u->p->sleep, return0, 0, ms); - uartwrreg(up, Format, 0); + uartwrreg(dp, Format, Break); + tsleep(&dp->sleep, return0, 0, ms); + uartwrreg(dp, Format, 0); } /* * set bits/char */ void -uartbits(Uart *up, int bits) +uartbits(Uart *dp, int bits) { if(bits < 5 || bits > 8) error(Ebadarg); - up->sticky[Format] &= ~3; - up->sticky[Format] |= bits-5; - uartwrreg(up, Format, 0); + dp->sticky[Format] &= ~3; + dp->sticky[Format] |= bits-5; + uartwrreg(dp, Format, 0); } /* * set parity */ void -uartparity(Uart *up, int c) +uartparity(Uart *dp, int c) { switch(c&0xff){ case 'e': - up->sticky[Format] |= Pena|Peven; + dp->sticky[Format] |= Pena|Peven; break; case 'o': - up->sticky[Format] &= ~Peven; - up->sticky[Format] |= Pena; + dp->sticky[Format] &= ~Peven; + dp->sticky[Format] |= Pena; break; default: - up->sticky[Format] &= ~(Pena|Peven); + dp->sticky[Format] &= ~(Pena|Peven); break; } - uartwrreg(up, Format, 0); + uartwrreg(dp, Format, 0); } /* * set stop bits */ void -uartstop(Uart *up, int n) +uartstop(Uart *dp, int n) { switch(n){ case 1: - up->sticky[Format] &= ~Stop2; + dp->sticky[Format] &= ~Stop2; break; case 2: default: - up->sticky[Format] |= Stop2; + dp->sticky[Format] |= Stop2; break; } - uartwrreg(up, Format, 0); + uartwrreg(dp, Format, 0); } /* * modem flow control on/off (rts/cts) */ void -uartmflow(Uart *up, int n) +uartmflow(Uart *dp, int n) { if(n){ - up->sticky[Iena] |= Imstat; - uartwrreg(up, Iena, 0); - up->cts = uartrdreg(up, Mstat) & Cts; + dp->sticky[Iena] |= Imstat; + uartwrreg(dp, Iena, 0); + dp->cts = uartrdreg(dp, Mstat) & Cts; } else { - up->sticky[Iena] &= ~Imstat; - uartwrreg(up, Iena, 0); - up->cts = 1; + dp->sticky[Iena] &= ~Imstat; + uartwrreg(dp, Iena, 0); + dp->cts = 1; } } /* - * default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts, - * transmit and receive enabled, interrupts disabled. + * default is 9600 baud, 1 stop bit, 8 bit chars, no interrdpts, + * transmit and receive enabled, interrdpts disabled. */ void uartsetup(void) { - Uart *up; + Uart *dp; + int i, j, baddr; static int already; if(already) @@ -246,21 +251,34 @@ uartsetup(void) uart[1].port = 0x2F8; setvec(Uart0vec, uartintr0); setvec(Uart1vec, uartintr1); - - for(up = uart; up < &uart[2]; up++){ - memset(up->sticky, 0, sizeof(up->sticky)); - + Nuart = 2; + for(i = 0; isaconfig("serial", i, &scard[i]) && i < nelem(scard); i++) { + /* + * mem gives base port address for uarts + * irq is interrdpt + * port is the polling port + * size is the number of serial ports on the same polling port + */ + setvec(Int0vec + scard[i].irq, uartintr2); + baddr = scard[i].mem; + for(j=0, dp = &uart[Nuart]; j < scard[i].size; baddr += 8, j++, dp++) + dp->port = baddr; + Nuart += scard[i].size; + } + Nscard = i; + for(dp = uart; dp < &uart[Nuart]; dp++){ + memset(dp->sticky, 0, sizeof(dp->sticky)); /* * set rate to 9600 baud. * 8 bits/character. * 1 stop bit. - * interrupts enabled. + * interrdpts enabled. */ - uartsetbaud(up, 9600); - up->sticky[Format] = Bits8; - uartwrreg(up, Format, 0); - up->sticky[Mctl] |= Inton; - uartwrreg(up, Mctl, 0x0); + uartsetbaud(dp, 9600); + dp->sticky[Format] = Bits8; + uartwrreg(dp, Format, 0); + dp->sticky[Mctl] |= Inton; + uartwrreg(dp, Mctl, 0x0); } } @@ -271,7 +289,7 @@ uartsetup(void) void uartputs(IOQ *cq, char *s, int n) { - Uart *up = cq->ptr; + Uart *dp = cq->ptr; int ch, x, multiprocessor; int tries; @@ -280,14 +298,14 @@ uartputs(IOQ *cq, char *s, int n) if(multiprocessor) lock(cq); puts(cq, s, n); - if(up->printing == 0){ + if(dp->printing == 0){ ch = getc(cq); if(ch >= 0){ - up->printing = 1; - for(tries = 0; tries<10000 && !(uartrdreg(up, Lstat)&Outready); + dp->printing = 1; + for(tries = 0; tries<10000 && !(uartrdreg(dp, Lstat)&Outready); tries++) ; - outb(up->port + Data, ch); + outb(dp->port + Data, ch); } } if(multiprocessor) @@ -296,10 +314,10 @@ uartputs(IOQ *cq, char *s, int n) } /* - * a uart interrupt (a damn lot of work for one character) + * a uart interrdpt (a damn lot of work for one character) */ void -uartintr(Uart *up) +uartintr(Uart *dp) { int ch; IOQ *cq; @@ -307,19 +325,19 @@ uartintr(Uart *up) multiprocessor = active.machs > 1; for(;;){ - s = uartrdreg(up, Istat); + s = uartrdreg(dp, Istat); switch(s){ case 6: /* receiver line status */ - l = uartrdreg(up, Lstat); + l = uartrdreg(dp, Lstat); if(l & Ferror) - up->frame++; + dp->frame++; if(l & Oerror) - up->overrun++; + dp->overrun++; break; case 4: /* received data available */ - ch = uartrdreg(up, Data) & 0xff; - cq = up->iq; + ch = uartrdreg(dp, Data) & 0xff; + cq = dp->iq; if(cq == 0) break; if(cq->putc) @@ -329,41 +347,41 @@ uartintr(Uart *up) break; case 2: /* transmitter empty */ - cq = up->oq; + cq = dp->oq; if(cq == 0) break; if(multiprocessor) lock(cq); - if(up->cts == 0) - up->printing = 0; + if(dp->cts == 0) + dp->printing = 0; else { ch = getc(cq); if(ch < 0){ - up->printing = 0; - wakeup(&cq->r); + dp->printing = 0; + wakedp(&cq->r); }else - outb(up->port + Data, ch); + outb(dp->port + Data, ch); } if(multiprocessor) unlock(cq); break; case 0: /* modem status */ - ch = uartrdreg(up, Mstat); + ch = uartrdreg(dp, Mstat); if(ch & Ctsc){ - up->cts = ch & Cts; - cq = up->oq; + dp->cts = ch & Cts; + cq = dp->oq; if(cq == 0) break; if(multiprocessor) lock(cq); - if(up->cts && up->printing == 0){ + if(dp->cts && dp->printing == 0){ ch = getc(cq); if(ch >= 0){ - up->printing = 1; - outb(up->port + Data, getc(cq)); + dp->printing = 1; + outb(dp->port + Data, getc(cq)); } else - wakeup(&cq->r); + wakedp(&cq->r); } if(multiprocessor) unlock(cq); @@ -373,7 +391,7 @@ uartintr(Uart *up) default: if(s&1) return; - print("weird modem interrupt\n"); + print("weird modem interrdpt #%2.2ux\n", s); break; } } @@ -390,125 +408,142 @@ uartintr1(Ureg *ur) USED(ur); uartintr(&uart[1]); } +void +uartintr2(Ureg *ur) +{ + uchar i, j, nuart, n; + + USED(ur); + for(nuart=2, j = 0; j < Nscard; nuart += scard[j].size, j++) { + n = ~inb(scard[j].port); + if(n == 0) + continue; + for(i = 0; n; i++){ + if(n & 1) + uartintr(&uart[nuart + i]); + n >>= 1; + } + } +} void uartclock(void) { - Uart *up; + Uart *dp; IOQ *cq; - for(up = uart; up < &uart[2]; up++){ - cq = up->iq; - if(up->wq && cangetc(cq)) - wakeup(&cq->r); + for(dp = uart; dp < &uart[Nuart]; dp++){ + cq = dp->iq; + if(dp->wq && cangetc(cq)) + wakedp(&cq->r); } } /* - * turn on a port's interrupts. set DTR and RTS + * turn on a port's interrdpts. set DTR and RTS */ void -uartenable(Uart *up) +uartenable(Uart *dp) { /* * turn on power to the port */ - if(up == &uart[Serial]){ - if(serial(1) < 0) - print("can't turn on serial port power\n"); - } else { + if(dp == &uart[Modem]){ if(modem(1) < 0) print("can't turn on modem speaker\n"); + } else { + if(serial(1) < 0) + print("can't turn on serial port power\n"); } /* - * set up i/o routines + * set dp i/o routines */ - if(up->oq){ - up->oq->puts = uartputs; - up->oq->ptr = up; + if(dp->oq){ + dp->oq->puts = uartputs; + dp->oq->ptr = dp; } - if(up->iq){ - up->iq->ptr = up; + if(dp->iq){ + dp->iq->ptr = dp; } - up->enabled = 1; + dp->enabled = 1; /* - * turn on interrupts + * turn on interrdpts */ - up->sticky[Iena] = Ircv | Ixmt | Irstat; - uartwrreg(up, Iena, 0); + dp->sticky[Iena] = Ircv | Ixmt | Irstat; + uartwrreg(dp, Iena, 0); /* * turn on DTR and RTS */ - uartdtr(up, 1); - uartrts(up, 1); + uartdtr(dp, 1); + uartrts(dp, 1); /* * assume we can send */ - up->cts = 1; + dp->cts = 1; } /* * turn off the uart */ void -uartdisable(Uart *up) +uartdisable(Uart *dp) { /* - * turn off interrupts + * turn off interrdpts */ - up->sticky[Iena] = 0; - uartwrreg(up, Iena, 0); + dp->sticky[Iena] = 0; + uartwrreg(dp, Iena, 0); /* * revert to default settings */ - up->sticky[Format] = Bits8; - uartwrreg(up, Format, 0); + dp->sticky[Format] = Bits8; + uartwrreg(dp, Format, 0); /* * turn off DTR and RTS */ - uartdtr(up, 0); - uartrts(up, 0); - up->enabled = 0; + uartdtr(dp, 0); + uartrts(dp, 0); + dp->enabled = 0; /* * turn off power */ - if(up == &uart[Serial]){ - if(serial(0) < 0) - print("can't turn off serial power\n"); - } else { + if(dp == &uart[Modem]){ if(modem(0) < 0) print("can't turn off modem speaker\n"); + } else { + if(serial(0) < 0) + print("can't turn off serial power\n"); } } /* - * set up an uart port as something other than a stream + * set dp an uart port as something other than a stream */ void uartspecial(int port, IOQ *oq, IOQ *iq, int baud) { - Uart *up = &uart[port]; + Uart *dp = &uart[port]; uartsetup(); - up->special = 1; - up->oq = oq; - up->iq = iq; - uartenable(up); + dp->special = 1; + dp->oq = oq; + dp->iq = iq; + uartenable(dp); if(baud) - uartsetbaud(up, baud); + uartsetbaud(dp, baud); if(iq){ /* - * Stupid HACK to undo a stupid hack + * Stdpid HACK to undo a stdpid hack */ if(iq == &kbdq) kbdq.putc = kbdcr2nl; @@ -532,57 +567,57 @@ Qinfo uartinfo = static void uartstopen(Queue *q, Stream *s) { - Uart *up; + Uart *dp; char name[NAMELEN]; - up = &uart[s->id]; - up->iq->putc = 0; - uartenable(up); + dp = &uart[s->id]; + dp->iq->putc = 0; + uartenable(dp); - qlock(up); - up->wq = WR(q); - WR(q)->ptr = up; - RD(q)->ptr = up; - qunlock(up); + qlock(dp); + dp->wq = WR(q); + WR(q)->ptr = dp; + RD(q)->ptr = dp; + qunlock(dp); - if(up->kstarted == 0){ - up->kstarted = 1; + if(dp->kstarted == 0){ + dp->kstarted = 1; sprint(name, "uart%d", s->id); - kproc(name, uartkproc, up); + kproc(name, uartkproc, dp); } } static void uartstclose(Queue *q) { - Uart *up = q->ptr; + Uart *dp = q->ptr; - if(up->special) + if(dp->special) return; - uartdisable(up); + uartdisable(dp); - qlock(up); - kprint("uartstclose: q=0x%ux, id=%d\n", q, up-uart); - up->wq = 0; - up->iq->putc = 0; + qlock(dp); + kprint("uartstclose: q=0x%ux, id=%d\n", q, dp-uart); + dp->wq = 0; + dp->iq->putc = 0; WR(q)->ptr = 0; RD(q)->ptr = 0; - qunlock(up); + qunlock(dp); } static void uartoput(Queue *q, Block *bp) { - Uart *up = q->ptr; + Uart *dp = q->ptr; IOQ *cq; int n, m; - if(up == 0){ + if(dp == 0){ freeb(bp); return; } - cq = up->oq; + cq = dp->oq; if(waserror()){ freeb(bp); nexterror(); @@ -594,35 +629,37 @@ uartoput(Queue *q, Block *bp) switch(*bp->rptr){ case 'B': case 'b': - uartsetbaud(up, n); + if(n <= 0) + error(Ebadctl); + uartsetbaud(dp, n); break; case 'D': case 'd': - uartdtr(up, n); + uartdtr(dp, n); break; case 'K': case 'k': - uartbreak(up, n); + uartbreak(dp, n); break; case 'L': case 'l': - uartbits(up, n); + uartbits(dp, n); break; case 'm': case 'M': - uartmflow(up, n); + uartmflow(dp, n); break; case 'P': case 'p': - uartparity(up, *(bp->rptr+1)); + uartparity(dp, *(bp->rptr+1)); break; case 'R': case 'r': - uartrts(up, n); + uartrts(dp, n); break; case 'S': case 's': - uartstop(up, n); + uartstop(dp, n); break; } }else while((m = BLEN(bp)) > 0){ @@ -639,13 +676,13 @@ uartoput(Queue *q, Block *bp) } /* - * process to send bytes upstream for a port + * process to send bytes dpstream for a port */ static void uartkproc(void *a) { - Uart *up = a; - IOQ *cq = up->iq; + Uart *dp = a; + IOQ *cq = dp->iq; Block *bp; int n; ulong frame, overrun; @@ -661,44 +698,33 @@ uartkproc(void *a) sleep(&cq->r, cangetc, cq); if((ints++ & 0x1f) == 0) lights((ints>>5)&1); - qlock(up); - if(up->wq == 0){ + qlock(dp); + if(dp->wq == 0){ cq->out = cq->in; }else{ n = cangetc(cq); bp = allocb(n); bp->flags |= S_DELIM; bp->wptr += gets(cq, bp->wptr, n); - PUTNEXT(RD(up->wq), bp); + PUTNEXT(RD(dp->wq), bp); } - qunlock(up); - if(up->frame != frame){ - kprint("uart%d: %d framing\n", up-uart, up->frame); - frame = up->frame; + qunlock(dp); + if(dp->frame != frame){ + kprint("uart%d: %d framing\n", dp-uart, dp->frame); + frame = dp->frame; } - if(up->overrun != overrun){ - kprint("uart%d: %d overruns\n", up-uart, up->overrun); - overrun = up->overrun; + if(dp->overrun != overrun){ + kprint("uart%d: %d overruns\n", dp-uart, dp->overrun); + overrun = dp->overrun; } } } enum{ Qdir= 0, - Qeia0= STREAMQID(0, Sdataqid), - Qeia0ctl= STREAMQID(0, Sctlqid), - Qeia1= STREAMQID(1, Sdataqid), - Qeia1ctl= STREAMQID(1, Sctlqid), -}; - -Dirtab uartdir[]={ - "eia0", {Qeia0}, 0, 0666, - "eia0ctl", {Qeia0ctl}, 0, 0666, - "eia1", {Qeia1}, 0, 0666, - "eia1ctl", {Qeia1ctl}, 0, 0666, }; -#define NUart (sizeof uartdir/sizeof(Dirtab)) +Dirtab uartdir[2*nelem(uart)]; /* * allocate the queues if no one else has @@ -706,28 +732,41 @@ Dirtab uartdir[]={ void uartreset(void) { - Uart *up; + Uart *dp; uartsetup(); - for(up = uart; up < &uart[2]; up++){ - if(up->special) + for(dp = uart; dp < &uart[Nuart]; dp++){ + if(dp->special) continue; - up->iq = xalloc(sizeof(IOQ)); - initq(up->iq); - up->oq = xalloc(sizeof(IOQ)); - initq(up->oq); + dp->iq = xalloc(sizeof(IOQ)); + initq(dp->iq); + dp->oq = xalloc(sizeof(IOQ)); + initq(dp->oq); } } void uartinit(void) { + int i; + + for(i=0; i < 2*Nuart; ++i) { + if(i & 1 != 0) { + sprint(uartdir[i].name, "eia%dctl", i/2); + uartdir[i].qid.path = STREAMQID(i/2, Sctlqid); + } else { + sprint(uartdir[i].name, "eia%d", i/2); + uartdir[i].qid.path = STREAMQID(i/2, Sdataqid); + } + uartdir[i].length = 0; + uartdir[i].perm = 0666; + } } Chan* -uartattach(char *upec) +uartattach(char *dpec) { - return devattach('t', upec); + return devattach('t', dpec); } Chan* @@ -739,50 +778,40 @@ uartclone(Chan *c, Chan *nc) int uartwalk(Chan *c, char *name) { - return devwalk(c, name, uartdir, NUart, devgen); + return devwalk(c, name, uartdir, Nuart * 2, devgen); } void -uartstat(Chan *c, char *dp) +uartstat(Chan *c, char *dir) { - switch(c->qid.path){ - case Qeia0: - streamstat(c, dp, uartdir[0].name, uartdir[0].perm); - break; - case Qeia1: - streamstat(c, dp, uartdir[2].name, uartdir[2].perm); - break; - default: - devstat(c, dp, uartdir, NUart, devgen); - break; - } + int i; + + for(i=0; i < 2*Nuart; i += 2) + if(c->qid.path == uartdir[i].qid.path) { + streamstat(c, dir, uartdir[i].name, uartdir[i].perm); + return; + } + devstat(c, dir, uartdir, Nuart * 2, devgen); } Chan* uartopen(Chan *c, int omode) { - Uart *up; + Uart *dp; + int i; - switch(c->qid.path){ - case Qeia0: - case Qeia0ctl: - up = &uart[0]; - break; - case Qeia1: - case Qeia1ctl: - up = &uart[1]; - break; - default: - up = 0; - break; - } + dp = 0; + for(i=0; i < 2*Nuart; ++i) + if(c->qid.path == uartdir[i].qid.path) { + dp = &uart[i/2]; + break; + } - if(up && up->special) + if(dp && dp->special) error(Einuse); - if((c->qid.path & CHDIR) == 0) streamopen(c, &uartinfo); - return devopen(c, omode, uartdir, NUart, devgen); + return devopen(c, omode, uartdir, Nuart * 2, devgen); } void @@ -800,15 +829,15 @@ uartclose(Chan *c) } long -uartstatus(Uart *up, void *buf, long n, ulong offset) +uartstatus(Uart *dp, void *buf, long n, ulong offset) { uchar mstat; uchar tstat; char str[128]; str[0] = 0; - tstat = up->sticky[Mctl]; - mstat = uartrdreg(up, Mstat); + tstat = dp->sticky[Mctl]; + mstat = uartrdreg(dp, Mstat); if(mstat & Cts) strcat(str, " cts"); if(mstat & Dsr) @@ -827,15 +856,16 @@ uartstatus(Uart *up, void *buf, long n, ulong offset) long uartread(Chan *c, void *buf, long n, ulong offset) { + int i; + long qpath; + USED(offset); - switch(c->qid.path&~CHDIR){ - case Qdir: - return devdirread(c, buf, n, uartdir, NUart, devgen); - case Qeia1ctl: - return uartstatus(&uart[1], buf, n, offset); - case Qeia0ctl: - return uartstatus(&uart[0], buf, n, offset); - } + qpath = c->qid.path & ~CHDIR; + if(qpath == Qdir) + return devdirread(c, buf, n, uartdir, Nuart * 2, devgen); + for(i=1; i < 2*Nuart; i += 2) + if(qpath == uartdir[i].qid.path) + return uartstatus(&uart[i/2], buf, n, offset); return streamread(c, buf, n); } @@ -854,8 +884,8 @@ uartremove(Chan *c) } void -uartwstat(Chan *c, char *dp) +uartwstat(Chan *c, char *dir) { - USED(c, dp); + USED(c, dir); error(Eperm); } diff --git a/pc/devvga.c b/pc/devvga.c index 2eb005a2d66746f5ec51e12fdc7e2cebf8c6113e..db28de120dc3cd88ba3d484556676f70ee6cf34e 100644 --- a/pc/devvga.c +++ b/pc/devvga.c @@ -103,7 +103,7 @@ VGAmode mode13 = static Rectangle mbb; static Rectangle NULLMBB = {10000, 10000, -10000, -10000}; static void nopage(int), tsengpage(int), tridentpage(int), parapage(int); -static void atipage(int); +static void atipage(int), cirruspage(int); static void vgaupdate(void); /* @@ -122,6 +122,7 @@ enum Pvga1a, /* paradise */ Trident, /* Trident 8900 */ Tseng, /* tseng labs te4000 */ + Cirrus, /* Cirrus CLGD542X */ Generic, }; @@ -131,6 +132,7 @@ Vgacard vgachips[] = [Pvga1a] { "pvga1a", parapage, }, [Trident] { "trident", tridentpage, }, [Tseng] { "tseng", tsengpage, }, +[Cirrus] { "cirrus", cirruspage, }, [Generic] { "generic", nopage, }, { 0, 0, }, }; @@ -659,7 +661,7 @@ atipage(int page) static void tridentpage(int page) { - srout(0x0e, (srin(0x0e)&0xf0) | page^0x02); + srout(0xe, (srin(0xe)&0xf0) | page^0x2); } static void tsengpage(int page) @@ -667,9 +669,14 @@ tsengpage(int page) outb(0x3cd, (page<<4)|page); } static void +cirruspage(int page) +{ + grout(0x9, page<<4); +} +static void parapage(int page) { - grout(9, page<<4); + grout(0x9, page<<4); } /* @@ -918,18 +925,16 @@ setcolor(ulong p, ulong r, ulong g, ulong b) return ~0; } -int -hwcursset(uchar *s, uchar *c, int ox, int oy) +void +hwcursset(ulong *s, ulong *c, int ox, int oy) { USED(s, c, ox, oy); - return 0; } -int +void hwcursmove(int x, int y) { USED(x, y); - return 0; } /* diff --git a/pc/dma.c b/pc/dma.c index eab296752d4b011683ada39ec2ba448b798ebbff..9fbbd4608845aa14b6a6c17463159cfae303aa55 100644 --- a/pc/dma.c +++ b/pc/dma.c @@ -33,7 +33,7 @@ enum */ struct DMAxfer { - Page *pg; /* page used by dma */ + Page pg; /* page used by dma */ void *va; /* virtual address destination/src */ long len; /* bytes to be transferred */ int isread; @@ -78,6 +78,27 @@ DMA dma[2] = { 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde }, }; +/* + * DMA must be in the first 16 meg. This gets called early by main() to + * ensure that. + */ +void +dmainit(void) +{ + int i, chan; + DMA *dp; + DMAxfer *xp; + + for(i = 0; i < 2; i++){ + dp = &dma[i]; + for(chan = 0; chan < 4; chan++){ + xp = &dp->x[chan]; + xp->pg.pa = (ulong)xspanalloc(BY2PG, BY2PG, 0); + xp->pg.va = KZERO|xp->pg.pa; + } + } +} + /* * setup a dma transfer. if the destination is not in kernel * memory, allocate a page for the transfer. @@ -101,22 +122,21 @@ dmasetup(int chan, void *va, long len, int isread) xp = &dp->x[chan]; /* - * if this isn't kernel memory (or crossing 64k boundary), - * allocate a page for the DMA. + * if this isn't kernel memory or crossing 64k boundary or above 16 meg + * use the allocated low memory page. */ - pa = ((ulong)va) & ~KZERO; + pa = PADDR(va); if((((ulong)va)&0xF0000000) != KZERO - || (pa&0xFFFF0000) != ((pa+len)&0xFFFF0000)){ - if(xp->pg == 0) - xp->pg = newpage(1, 0, 0); + || (pa&0xFFFF0000) != ((pa+len)&0xFFFF0000) + || pa > 16*MB){ if(len > BY2PG) len = BY2PG; if(!isread) - memmove((void*)(KZERO|xp->pg->pa), va, len); + memmove((void*)(xp->pg.va), va, len); xp->va = va; xp->len = len; xp->isread = isread; - pa = xp->pg->pa; + pa = xp->pg.pa; } else xp->len = 0; @@ -168,6 +188,6 @@ dmaend(int chan) /* * copy out of temporary page */ - memmove(xp->va, (void*)(KZERO|xp->pg->pa), xp->len); + memmove(xp->va, (void*)(xp->pg.va), xp->len); xp->len = 0; } diff --git a/pc/ether.h b/pc/ether.h index 9ad2545d7575a9c6baea655b9c8cb4809d4cd7c5..d4fcf00ae96b96ce795b5352f532ca0003997513 100644 --- a/pc/ether.h +++ b/pc/ether.h @@ -10,7 +10,7 @@ typedef struct Ctlr Ctlr; * Hardware interface. */ struct Card { - char id[NAMELEN]; /* type of card */ + ISAConf; int (*reset)(Ctlr*); void (*init)(Ctlr*); @@ -26,13 +26,8 @@ struct Card { void (*watch)(Ctlr*); void (*overflow)(Ctlr*); - ulong io; /* card I/O base address */ - uchar irq; /* interrupt level */ uchar bit16; /* true if a 16 bit interface */ - uchar ram; /* true if card has shared memory */ - ulong ramstart; /* card shared memory address start */ - ulong ramstop; /* card shared memory address end */ ulong dp8390; /* I/O address of 8390 (if any) */ ulong data; /* I/O data port if no shared memory */ @@ -85,6 +80,8 @@ enum { */ struct Ctlr { QLock; + int ctlrno; + Ctlr *next; Card card; /* hardware info */ int present; @@ -140,6 +137,7 @@ struct Ctlr { extern void dp8390reset(Ctlr*); extern void dp8390attach(Ctlr*); extern void dp8390mode(Ctlr*, int); +extern void dp8390getea(Ctlr*); extern void dp8390setea(Ctlr*); extern void *dp8390read(Ctlr*, void*, ulong, ulong); extern void *dp8390write(Ctlr*, ulong, void*, ulong); @@ -166,3 +164,6 @@ extern void dp8390outb(ulong, uchar); enum { Dp8390BufSz = 256, /* hardware ring buffer size */ }; + + +extern void addethercard(char*, int (*)(Ctlr*)); diff --git a/pc/ether2000.c b/pc/ether2000.c index c286b2bc809a811659a00de4d01beaa77ed7c9e9..af37329ae92a2af6335dfad892914c0843cc112f 100644 --- a/pc/ether2000.c +++ b/pc/ether2000.c @@ -25,44 +25,68 @@ enum { Reset = 0x18, /* offset from I/O base of reset port */ }; -static int -reset(Ctlr *ctlr) +int +ne2000reset(Ctlr *ctlr) { ushort buf[16]; int i; /* - * We look for boards. - * We look for boards to make us barf. + * Set up the software configuration. + * Use defaults for port, irq, mem and size + * if not specified. */ - for(ctlr->card.io = 0x300; ctlr->card.io < 0x380; ctlr->card.io += 0x20){ - /* - * Reset the board. This is done by doing a read - * followed by a write to the Reset address. - */ - buf[0] = inb(ctlr->card.io+Reset); - delay(2); - outb(ctlr->card.io+Reset, buf[0]); + if(ctlr->card.port == 0) + ctlr->card.port = 0x300; + if(ctlr->card.irq == 0) + ctlr->card.irq = 2; + if(ctlr->card.mem == 0) + ctlr->card.mem = 0x4000; + if(ctlr->card.size == 0) + ctlr->card.size = 16*1024; - /* - * Init the (possible) chip, then use the (possible) - * chip to read the (possible) PROM for ethernet address - * and a marker byte. - * We could just look at the DP8390 command register after - * initialisation has been tried, but that wouldn't be - * enough, there are other ethernet boards which could - * match. - */ - ctlr->card.dp8390 = ctlr->card.io; - ctlr->card.data = ctlr->card.io+Data; - dp8390reset(ctlr); - memset(buf, 0, sizeof(buf)); - dp8390read(ctlr, buf, 0, sizeof(buf)); - if((buf[0x0E] & 0xFF) == 0x57 && (buf[0x0F] & 0xFF) == 0x57) - break; - } - if(ctlr->card.io >= 0x380) + ctlr->card.reset = ne2000reset; + ctlr->card.attach = dp8390attach; + ctlr->card.mode = dp8390mode; + ctlr->card.read = dp8390read; + ctlr->card.write = dp8390write; + ctlr->card.receive = dp8390receive; + ctlr->card.transmit = dp8390transmit; + ctlr->card.intr = dp8390intr; + ctlr->card.watch = dp8390watch; + ctlr->card.overflow = dp8390overflow; + + ctlr->card.bit16 = 1; + ctlr->card.dp8390 = ctlr->card.port; + ctlr->card.data = ctlr->card.port+Data; + + ctlr->card.tstart = HOWMANY(ctlr->card.mem, Dp8390BufSz); + ctlr->card.pstart = ctlr->card.tstart + HOWMANY(sizeof(Etherpkt), Dp8390BufSz); + ctlr->card.pstop = ctlr->card.tstart + HOWMANY(ctlr->card.size, Dp8390BufSz); + + /* + * Reset the board. This is done by doing a read + * followed by a write to the Reset address. + */ + buf[0] = inb(ctlr->card.port+Reset); + delay(2); + outb(ctlr->card.port+Reset, buf[0]); + + /* + * Init the (possible) chip, then use the (possible) + * chip to read the (possible) PROM for ethernet address + * and a marker byte. + * We could just look at the DP8390 command register after + * initialisation has been tried, but that wouldn't be + * enough, there are other ethernet boards which could + * match. + */ + dp8390reset(ctlr); + memset(buf, 0, sizeof(buf)); + dp8390read(ctlr, buf, 0, sizeof(buf)); + if((buf[0x0E] & 0xFF) != 0x57 || (buf[0x0F] & 0xFF) != 0x57) return -1; + /* * Stupid machine. We asked for shorts, we got shorts, * although the PROM is a byte array. @@ -75,35 +99,8 @@ reset(Ctlr *ctlr) return 0; } -Card ether2000 = { - "NE2000", /* ident */ - - reset, /* reset */ - 0, /* init */ - dp8390attach, /* attach */ - dp8390mode, /* mode */ - - dp8390read, /* read */ - dp8390write, /* write */ - - dp8390receive, /* receive */ - dp8390transmit, /* transmit */ - dp8390intr, /* interrupt */ - dp8390watch, /* watch */ - dp8390overflow, /* overflow */ - - 0x300, /* addr */ - 2, /* irq */ - 1, /* bit16 */ - - 0, /* ram */ - 0x4000, /* ramstart */ - 0x4000+16*1024, /* ramstop */ - - 0x300, /* dp8390 */ - 0x300+Data, /* data */ - 0, /* software bndry */ - 0x4000/Dp8390BufSz, /* tstart */ - 0x4600/Dp8390BufSz, /* pstart */ - 0x8000/Dp8390BufSz, /* pstop */ -}; +void +ether2000link(void) +{ + addethercard("NE2000", ne2000reset); +} diff --git a/pc/ether503.c b/pc/ether503.c index 3bf42086cce33ec06d9496413df9f00432d64d6a..563702cc7f7f8d42bf9e7f36c707e682e17522f9 100644 --- a/pc/ether503.c +++ b/pc/ether503.c @@ -338,3 +338,9 @@ Card ether503 = { (RamOffset+0x600)/Dp8390BufSz, /* pstart */ (RamOffset+8*1024)/Dp8390BufSz, /* pstop */ }; + +void +ether503link(void) +{ + addethercard("3C503", ccc503reset); +} diff --git a/pc/ether509.c b/pc/ether509.c index 7f60b39608f21da87cac650f954de738f012a7ac..cc28b2d40d2890f1d2562b21bbff540fb61df071 100644 --- a/pc/ether509.c +++ b/pc/ether509.c @@ -84,145 +84,14 @@ enum { RxReceiving = 0x8000, /* RX Receiving */ }; -#define COMMAND(ctlr, cmd, a) outs(ctlr->card.io+Command, ((cmd)<<11)|(a)) - -/* - * Write two 0 bytes to identify the IDport and then reset the - * ID sequence. Then send the ID sequence to the card to get - * the card into command state. - */ -static void -idseq(void) -{ - int i; - uchar al; - - outb(IDport, 0); - outb(IDport, 0); - for(al = 0xFF, i = 0; i < 255; i++){ - outb(IDport, al); - if(al & 0x80){ - al <<= 1; - al ^= 0xCF; - } - else - al <<= 1; - } -} - -/* - * Get configuration parameters. - */ -static int -reset(Ctlr *ctlr) -{ - int i, ea; - ushort x, acr; - - /* - * Do the little configuration dance. We only look - * at the first card that responds, if we ever have more - * than one we'll need to modify this sequence. - * - * 2. get to command state, reset, then return to command state - */ - idseq(); - outb(IDport, 0xC1); - delay(2); - idseq(); - - /* - * 3. Read the Product ID from the EEPROM. - * This is done by writing the IDPort with 0x83 (0x80 - * is the 'read EEPROM command, 0x03 is the offset of - * the Product ID field in the EEPROM). - * The data comes back 1 bit at a time. - * We seem to need a delay here between reading the bits. - * - * If the ID doesn't match the 3C509 ID code, the adapter - * probably isn't there, so barf. - */ - outb(IDport, 0x83); - for(x = 0, i = 0; i < 16; i++){ - delay(5); - x <<= 1; - x |= inb(IDport) & 0x01; - } - if((x & 0xF0FF) != 0x9050) - return -1; - - /* - * 3. Read the Address Configuration from the EEPROM. - * The Address Configuration field is at offset 0x08 in the EEPROM). - * 6. Activate the adapter by writing the Activate command - * (0xFF). - */ - outb(IDport, 0x88); - for(acr = 0, i = 0; i < 16; i++){ - delay(20); - acr <<= 1; - acr |= inb(IDport) & 0x01; - } - outb(IDport, 0xFF); - - /* - * 8. Now we can talk to the adapter's I/O base addresses. - * We get the I/O base address from the acr just read. - * - * Enable the adapter. - */ - ctlr->card.io = (acr & 0x1F)*0x10 + 0x200; - outb(ctlr->card.io+ConfigControl, 0x01); - - /* - * Read the IRQ from the Resource Configuration Register - * and the ethernet address from the EEPROM. - * The EEPROM command is 8bits, the lower 6 bits being - * the address offset. - */ - ctlr->card.irq = (ins(ctlr->card.io+ResourceConfig)>>12) & 0x0F; - for(ea = 0, i = 0; i < 3; i++, ea += 2){ - while(ins(ctlr->card.io+EEPROMcmd) & 0x8000) - ; - outs(ctlr->card.io+EEPROMcmd, (2<<6)|i); - while(ins(ctlr->card.io+EEPROMcmd) & 0x8000) - ; - x = ins(ctlr->card.io+EEPROMdata); - ctlr->ea[ea] = (x>>8) & 0xFF; - ctlr->ea[ea+1] = x & 0xFF; - } - - /* - * Finished with window 0. Now set the ethernet address - * in window 2. - * Commands have the format 'CCCCCAAAAAAAAAAA' where C - * is a bit in the command and A is a bit in the argument. - */ - COMMAND(ctlr, SelectWindow, 2); - for(i = 0; i < 6; i++) - outb(ctlr->card.io+i, ctlr->ea[i]); - - /* - * Finished with window 2. - * Set window 1 for normal operation. - */ - COMMAND(ctlr, SelectWindow, 1); - - /* - * If we have a 10BASE2 transceiver, start the DC-DC - * converter. Wait > 800 microseconds. - */ - if(((acr>>14) & 0x03) == 0x03){ - COMMAND(ctlr, StartCoax, 0); - delay(1); - } - - return 0; -} +#define COMMAND(port, cmd, a) outs(port+Command, ((cmd)<<11)|(a)) static void attach(Ctlr *ctlr) { + ulong port; + + port = ctlr->card.port; /* * Set the receiver packet filter for our own and * and broadcast addresses, set the interrupt masks @@ -231,20 +100,23 @@ attach(Ctlr *ctlr) * is the receiver interrupt. If the transmit FIFO fills up, * we will also see TxAvailable interrupts. */ - COMMAND(ctlr, SetRxFilter, Broadcast|MyEtherAddr); - COMMAND(ctlr, SetReadZeroMask, AllIntr|Latch); - COMMAND(ctlr, SetIntrMask, AllIntr|Latch); - COMMAND(ctlr, RxEnable, 0); - COMMAND(ctlr, TxEnable, 0); + COMMAND(port, SetRxFilter, Broadcast|MyEtherAddr); + COMMAND(port, SetReadZeroMask, AllIntr|Latch); + COMMAND(port, SetIntrMask, AllIntr|Latch); + COMMAND(port, RxEnable, 0); + COMMAND(port, TxEnable, 0); } static void mode(Ctlr *ctlr, int on) { + ulong port; + + port = ctlr->card.port; if(on) - COMMAND(ctlr, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr); + COMMAND(port, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr); else - COMMAND(ctlr, SetRxFilter, Broadcast|MyEtherAddr); + COMMAND(port, SetRxFilter, Broadcast|MyEtherAddr); } static void @@ -253,8 +125,10 @@ receive(Ctlr *ctlr) ushort status; RingBuf *rb; int len; + ulong port; - while(((status = ins(ctlr->card.io+RxStatus)) & RxEmpty) == 0){ + port = ctlr->card.port; + while(((status = ins(port+RxStatus)) & RxEmpty) == 0){ /* * If we had an error, log it and continue * without updating the ring. @@ -295,9 +169,9 @@ receive(Ctlr *ctlr) * doubleword. We can pick them out 16-bits * at a time (can try 32-bits at a time * later). - insl(ctlr->card.io+Fifo, rb->pkt, HOWMANY(len, 4)); + insl(port+Fifo, rb->pkt, HOWMANY(len, 4)); */ - inss(ctlr->card.io+Fifo, rb->pkt, HOWMANY(len, 2)); + inss(port+Fifo, rb->pkt, HOWMANY(len, 2)); /* * Update the ring. @@ -311,8 +185,8 @@ receive(Ctlr *ctlr) * Discard the packet as we're done with it. * Wait for discard to complete. */ - COMMAND(ctlr, RxDiscard, 0); - while(ins(ctlr->card.io+Status) & CmdInProgress) + COMMAND(port, RxDiscard, 0); + while(ins(port+Status) & CmdInProgress) ; } } @@ -322,7 +196,9 @@ transmit(Ctlr *ctlr) { RingBuf *tb; ushort len; + ulong port; + port = ctlr->card.port; for(tb = &ctlr->tb[ctlr->ti]; tb->owner == Interface; tb = &ctlr->tb[ctlr->ti]){ /* * If there's no room in the FIFO for this packet, @@ -331,8 +207,8 @@ transmit(Ctlr *ctlr) * we need 4 bytes for the preamble. */ len = ROUNDUP(tb->len, 4); - if(len+4 > ins(ctlr->card.io+TxFreeBytes)){ - COMMAND(ctlr, SetTxAvailable, len); + if(len+4 > ins(port+TxFreeBytes)){ + COMMAND(port, SetTxAvailable, len); break; } @@ -340,9 +216,9 @@ transmit(Ctlr *ctlr) * There's room, copy the packet to the FIFO and free * the buffer back to the host. */ - outs(ctlr->card.io+Fifo, tb->len); - outs(ctlr->card.io+Fifo, 0); - outss(ctlr->card.io+Fifo, tb->pkt, len/2); + outs(port+Fifo, tb->len); + outs(port+Fifo, 0); + outss(port+Fifo, tb->pkt, len/2); tb->owner = Host; ctlr->ti = NEXT(ctlr->ti, ctlr->ntb); } @@ -352,10 +228,12 @@ static ushort getdiag(Ctlr *ctlr) { ushort bytes; + ulong port; - COMMAND(ctlr, SelectWindow, 4); - bytes = ins(ctlr->card.io+FIFOdiag); - COMMAND(ctlr, SelectWindow, 1); + port = ctlr->card.port; + COMMAND(port, SelectWindow, 4); + bytes = ins(port+FIFOdiag); + COMMAND(port, SelectWindow, 1); return bytes & 0xFFFF; } @@ -364,8 +242,10 @@ interrupt(Ctlr *ctlr) { ushort status, diag; uchar txstatus, x; + ulong port; - status = ins(ctlr->card.io+Status); + port = ctlr->card.port; + status = ins(port+Status); if(status & Failure){ /* @@ -379,12 +259,12 @@ interrupt(Ctlr *ctlr) print("ether509: status #%ux, diag #%ux\n", status, diag); if(diag & TxOverrun){ - COMMAND(ctlr, TxReset, 0); - COMMAND(ctlr, TxEnable, 0); + COMMAND(port, TxReset, 0); + COMMAND(port, TxEnable, 0); } if(diag & RxUnderrun){ - COMMAND(ctlr, RxReset, 0); + COMMAND(port, RxReset, 0); attach(ctlr); } @@ -409,14 +289,14 @@ interrupt(Ctlr *ctlr) */ txstatus = 0; do{ - if(x = inb(ctlr->card.io+TxStatus)) - outb(ctlr->card.io+TxStatus, 0); + if(x = inb(port+TxStatus)) + outb(port+TxStatus, 0); txstatus |= x; - }while(ins(ctlr->card.io+Status) & TxComplete); + }while(ins(port+Status) & TxComplete); if(txstatus & (TxJabber|TxUnderrun)) - COMMAND(ctlr, TxReset, 0); - COMMAND(ctlr, TxEnable, 0); + COMMAND(port, TxReset, 0); + COMMAND(port, TxEnable, 0); ctlr->oerrs++; } @@ -425,7 +305,7 @@ interrupt(Ctlr *ctlr) * Reset the Tx FIFO threshold. */ if(status & TxAvailable) - COMMAND(ctlr, AckIntr, TxAvailable); + COMMAND(port, AckIntr, TxAvailable); transmit(ctlr); wakeup(&ctlr->tr); status &= ~(TxAvailable|TxComplete); @@ -439,23 +319,157 @@ interrupt(Ctlr *ctlr) if(status & AllIntr) panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(ctlr)); - COMMAND(ctlr, AckIntr, Latch); + COMMAND(port, AckIntr, Latch); } -Card ether509 = { - "3Com509", /* ident */ +/* + * Write two 0 bytes to identify the IDport and then reset the + * ID sequence. Then send the ID sequence to the card to get + * the card into command state. + */ +static void +idseq(void) +{ + int i; + uchar al; - reset, /* reset */ - 0, /* init */ - attach, /* attach */ - mode, /* mode */ + outb(IDport, 0); + outb(IDport, 0); + for(al = 0xFF, i = 0; i < 255; i++){ + outb(IDport, al); + if(al & 0x80){ + al <<= 1; + al ^= 0xCF; + } + else + al <<= 1; + } +} - 0, /* read */ - 0, /* write */ +/* + * Get configuration parameters. + */ +int +ccc509reset(Ctlr *ctlr) +{ + int i, ea; + ushort x, acr; + ulong port; - 0, /* receive */ - transmit, /* transmit */ - interrupt, /* interrupt */ - 0, /* watch */ - 0, /* overflow */ -}; + /* + * Do the little configuration dance. We only look + * at the first card that responds, if we ever have more + * than one we'll need to modify this sequence. + * + * 2. get to command state, reset, then return to command state + */ + idseq(); + outb(IDport, 0xC1); + delay(2); + idseq(); + + /* + * 3. Read the Product ID from the EEPROM. + * This is done by writing the IDPort with 0x83 (0x80 + * is the 'read EEPROM command, 0x03 is the offset of + * the Product ID field in the EEPROM). + * The data comes back 1 bit at a time. + * We seem to need a delay here between reading the bits. + * + * If the ID doesn't match the 3C509 ID code, the adapter + * probably isn't there, so barf. + */ + outb(IDport, 0x83); + for(x = 0, i = 0; i < 16; i++){ + delay(5); + x <<= 1; + x |= inb(IDport) & 0x01; + } + if((x & 0xF0FF) != 0x9050) + return -1; + + /* + * 3. Read the Address Configuration from the EEPROM. + * The Address Configuration field is at offset 0x08 in the EEPROM). + * 6. Activate the adapter by writing the Activate command + * (0xFF). + */ + outb(IDport, 0x88); + for(acr = 0, i = 0; i < 16; i++){ + delay(20); + acr <<= 1; + acr |= inb(IDport) & 0x01; + } + outb(IDport, 0xFF); + + /* + * 8. Now we can talk to the adapter's I/O base addresses. + * We get the I/O base address from the acr just read. + * + * Enable the adapter. + */ + ctlr->card.port = (acr & 0x1F)*0x10 + 0x200; + port = ctlr->card.port; + outb(port+ConfigControl, 0x01); + + /* + * Read the IRQ from the Resource Configuration Register + * and the ethernet address from the EEPROM. + * The EEPROM command is 8bits, the lower 6 bits being + * the address offset. + */ + ctlr->card.irq = (ins(port+ResourceConfig)>>12) & 0x0F; + for(ea = 0, i = 0; i < 3; i++, ea += 2){ + while(ins(port+EEPROMcmd) & 0x8000) + ; + outs(port+EEPROMcmd, (2<<6)|i); + while(ins(port+EEPROMcmd) & 0x8000) + ; + x = ins(port+EEPROMdata); + ctlr->ea[ea] = (x>>8) & 0xFF; + ctlr->ea[ea+1] = x & 0xFF; + } + + /* + * Finished with window 0. Now set the ethernet address + * in window 2. + * Commands have the format 'CCCCCAAAAAAAAAAA' where C + * is a bit in the command and A is a bit in the argument. + */ + COMMAND(port, SelectWindow, 2); + for(i = 0; i < 6; i++) + outb(port+i, ctlr->ea[i]); + + /* + * Finished with window 2. + * Set window 1 for normal operation. + */ + COMMAND(port, SelectWindow, 1); + + /* + * If we have a 10BASE2 transceiver, start the DC-DC + * converter. Wait > 800 microseconds. + */ + if(((acr>>14) & 0x03) == 0x03){ + COMMAND(port, StartCoax, 0); + delay(1); + } + + /* + * Set up the software configuration. + */ + ctlr->card.reset = ccc509reset; + ctlr->card.attach = attach; + ctlr->card.mode = mode; + ctlr->card.transmit = transmit; + ctlr->card.intr = interrupt; + ctlr->card.bit16 = 1; + + return 0; +} + +void +ether509link(void) +{ + addethercard("3C509", ccc509reset); +} diff --git a/pc/ether8003.c b/pc/ether8003.c index f90da4385e3ac59705cc70f018fd296a75c7c49f..6343fbc86c6e6098558933c290b609c7a0ee1c4a 100644 --- a/pc/ether8003.c +++ b/pc/ether8003.c @@ -57,17 +57,89 @@ static int intrmap[] = { 9, 3, 5, 7, 10, 11, 15, 4, }; +static void* +read(Ctlr *ctlr, void *to, ulong from, ulong len) +{ + /* + * In this case, 'from' is an index into the shared memory. + */ + memmove(to, (void*)(ctlr->card.mem+from), len); + return to; +} + +static void* +write(Ctlr *ctlr, ulong to, void *from, ulong len) +{ + /* + * In this case, 'to' is an index into the shared memory. + */ + memmove((void*)(ctlr->card.mem+to), from, len); + return (void*)to; +} + +static void +watch(Ctlr *ctlr) +{ + uchar msr; + int s; + + s = splhi(); + msr = inb(ctlr->card.port+Msr); + /* + * If the card has reset itself, + * start again. + */ + if((msr & Menb) == 0){ + delay(100); + + dp8390reset(ctlr); + etherinit(); + + wakeup(&ctlr->tr); + wakeup(&ctlr->rr); + } + splx(s); +} + /* * Get configuration parameters, enable memory. * There are opportunities here for buckets of code. * We'll try to resist. */ -static int -reset(Ctlr *ctlr) +int +wd8003reset(Ctlr *ctlr) { int i; uchar ic[8], sum; + ulong wd8003; + /* + * Set up the software configuration. + * Use defaults for port, irq, mem and size if not specified. + * Defaults are set for the dumb 8003E which can't be + * autoconfigured. + */ + if(ctlr->card.port == 0) + ctlr->card.port = 0x280; + if(ctlr->card.irq == 0) + ctlr->card.irq = 3; + if(ctlr->card.mem == 0) + ctlr->card.mem = 0xD0000; + if(ctlr->card.size == 0) + ctlr->card.size = 8*1024; + + ctlr->card.reset = wd8003reset; + ctlr->card.attach = dp8390attach; + ctlr->card.mode = dp8390mode; + ctlr->card.read = read; + ctlr->card.write = write; + ctlr->card.receive = dp8390receive; + ctlr->card.transmit = dp8390transmit; + ctlr->card.intr = dp8390intr; + ctlr->card.watch = watch; + ctlr->card.ram = 1; + + wd8003 = ctlr->card.port; /* * Look for the interface. We read the LAN address ROM * and validate the checksum - the sum of all 8 bytes @@ -75,19 +147,15 @@ reset(Ctlr *ctlr) * While we're at it, get the (possible) interface chip * registers, we'll use them to check for aliasing later. */ - for(ctlr->card.io = 0x200; ctlr->card.io < 0x400; ctlr->card.io += 0x20){ - sum = 0; - for(i = 0; i < sizeof(ctlr->ea); i++){ - ctlr->ea[i] = inb(ctlr->card.io+Lar+i); - sum += ctlr->ea[i]; - ic[i] = inb(ctlr->card.io+i); - } - sum += inb(ctlr->card.io+Id); - sum += inb(ctlr->card.io+Cksum); - if(sum == 0xFF) - break; + sum = 0; + for(i = 0; i < sizeof(ctlr->ea); i++){ + ctlr->ea[i] = inb(wd8003+Lar+i); + sum += ctlr->ea[i]; + ic[i] = inb(wd8003+i); } - if(ctlr->card.io >= 0x400) + sum += inb(wd8003+Id); + sum += inb(wd8003+Cksum); + if(sum != 0xFF) return -1; /* @@ -101,7 +169,7 @@ reset(Ctlr *ctlr) */ if(memcmp(&ctlr->ea[1], &ic[1], 5) == 0){ memset(ic, 0, sizeof(ic)); - ic[Msr] = (((ulong)ctlr->card.ramstart)>>13) & 0x3F; + ic[Msr] = (((ulong)ctlr->card.mem)>>13) & 0x3F; ctlr->card.watch = 0; } else{ @@ -110,13 +178,12 @@ reset(Ctlr *ctlr) * the 83C584 interface chip, but has 2 real registers, write Gp2 and if * it reads back the same, it's not an 8013EBT. */ - outb(ctlr->card.io+Gp2, 0xAA); - inb(ctlr->card.io+Msr); /* wiggle bus */ - if(inb(ctlr->card.io+Gp2) != 0xAA){ + outb(wd8003+Gp2, 0xAA); + inb(wd8003+Msr); /* wiggle bus */ + if(inb(wd8003+Gp2) != 0xAA){ memset(ic, 0, sizeof(ic)); - ic[Msr] = (((ulong)ctlr->card.ramstart)>>13) & 0x3F; + ic[Msr] = (((ulong)ctlr->card.mem)>>13) & 0x3F; ctlr->card.watch = 0; - ctlr->card.irq = 2; /* special */ } else ctlr->card.irq = intrmap[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)]; @@ -126,46 +193,43 @@ reset(Ctlr *ctlr) * If Bit16 is read/write, then we have an 8-bit card. * If Bit16 is set, we're in a 16-bit slot. */ - outb(ctlr->card.io+Icr, ic[Icr]^Bit16); - inb(ctlr->card.io+Msr); /* wiggle bus */ - if((inb(ctlr->card.io+Icr) & Bit16) == (ic[Icr] & Bit16)){ + outb(wd8003+Icr, ic[Icr]^Bit16); + inb(wd8003+Msr); /* wiggle bus */ + if((inb(wd8003+Icr) & Bit16) == (ic[Icr] & Bit16)){ ctlr->card.bit16 = 1; ic[Icr] &= ~Bit16; } - outb(ctlr->card.io+Icr, ic[Icr]); + outb(wd8003+Icr, ic[Icr]); - if(ctlr->card.bit16 && (inb(ctlr->card.io+Icr) & Bit16) == 0) + if(ctlr->card.bit16 && (inb(wd8003+Icr) & Bit16) == 0) ctlr->card.bit16 = 0; } - ctlr->card.ramstart = KZERO|((ic[Msr] & 0x3F)<<13); + ctlr->card.mem = KZERO|((ic[Msr] & 0x3F)<<13); if(ctlr->card.bit16) - ctlr->card.ramstart |= (ic[Laar] & 0x1F)<<19; + ctlr->card.mem |= (ic[Laar] & 0x1F)<<19; else - ctlr->card.ramstart |= 0x80000; + ctlr->card.mem |= 0x80000; if(ic[Icr] & (1<<3)) - ctlr->card.ramstop = 32*1024; - else - ctlr->card.ramstop = 8*1024; + ctlr->card.size = 32*1024; if(ctlr->card.bit16) - ctlr->card.ramstop <<= 1; - ctlr->card.ramstop += ctlr->card.ramstart; + ctlr->card.size <<= 1; /* * Set the DP8390 ring addresses. */ - ctlr->card.dp8390 = ctlr->card.io+0x10; - ctlr->card.pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz); - ctlr->card.pstop = HOWMANY(ctlr->card.ramstop-ctlr->card.ramstart, Dp8390BufSz); + ctlr->card.dp8390 = wd8003+0x10; ctlr->card.tstart = 0; + ctlr->card.pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz); + ctlr->card.pstop = HOWMANY(ctlr->card.size, Dp8390BufSz); /* * Enable interface RAM, set interface width. */ - outb(ctlr->card.io+Msr, ic[Msr]|Menb); + outb(wd8003+Msr, ic[Msr]|Menb); if(ctlr->card.bit16) - outb(ctlr->card.io+Laar, ic[Laar]|L16en|M16en|ZeroWS16); + outb(wd8003+Laar, ic[Laar]|L16en|M16en|ZeroWS16); /* * Finally, init the 8390 and set the @@ -177,76 +241,8 @@ reset(Ctlr *ctlr) return 0; } -static void* -read(Ctlr *ctlr, void *to, ulong from, ulong len) -{ - /* - * In this case, 'from' is an index into the shared memory. - */ - memmove(to, (void*)(ctlr->card.ramstart+from), len); - return to; -} - -static void* -write(Ctlr *ctlr, ulong to, void *from, ulong len) -{ - /* - * In this case, 'to' is an index into the shared memory. - */ - memmove((void*)(ctlr->card.ramstart+to), from, len); - return (void*)to; -} - -static void -watch(Ctlr *ctlr) +void +ether8003link(void) { - uchar msr; - int s; - - s = splhi(); - msr = inb(ctlr->card.io+Msr); - /* - * If the card has reset itself, - * start again. - */ - if((msr & Menb) == 0){ - delay(100); - - dp8390reset(ctlr); - etherinit(); - - wakeup(&ctlr->tr); - wakeup(&ctlr->rr); - } - splx(s); + addethercard("WD8003", wd8003reset); } - -/* - * Defaults are set for the dumb 8003E - * which can't be autoconfigured. - */ -Card ether8003 = { - "WD8003", /* ident */ - - reset, /* reset */ - 0, /* init */ - dp8390attach, /* attach */ - dp8390mode, /* mode */ - - read, /* read */ - write, /* write */ - - dp8390receive, /* receive */ - dp8390transmit, /* transmit */ - dp8390intr, /* interrupt */ - watch, /* watch */ - 0, /* overflow */ - - 0x280, /* io */ - 3, /* irq */ - 0, /* bit16 */ - - 1, /* ram */ - 0xD0000, /* ramstart */ - 0xD0000+8*1024, /* ramstop */ -}; diff --git a/pc/ether8390.c b/pc/ether8390.c index 475e8aed96fd3bd9821f791c86dc42cd0089a0d1..18ec2d01af016f40da887ab9f9596de4e64c980b 100644 --- a/pc/ether8390.c +++ b/pc/ether8390.c @@ -149,8 +149,10 @@ typedef struct { static void dp8390disable(Ctlr *ctlr) { + ulong dp8390; int timo; + dp8390 = ctlr->card.dp8390; /* * Stop the chip. Set the Stp bit and wait for the chip * to finish whatever was on its tiny mind before it sets @@ -159,23 +161,26 @@ dp8390disable(Ctlr *ctlr) * chip there if this is called when probing for a device * at boot. */ - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp); - dp8390outb(ctlr->card.dp8390+Rbcr0, 0); - dp8390outb(ctlr->card.dp8390+Rbcr1, 0); - for(timo = 10000; (dp8390inb(ctlr->card.dp8390+Isr) & Rst) == 0 && timo; timo--) + dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp); + dp8390outb(dp8390+Rbcr0, 0); + dp8390outb(dp8390+Rbcr1, 0); + for(timo = 10000; (dp8390inb(dp8390+Isr) & Rst) == 0 && timo; timo--) ; } static void dp8390ring(Ctlr *ctlr) { - dp8390outb(ctlr->card.dp8390+Pstart, ctlr->card.pstart); - dp8390outb(ctlr->card.dp8390+Pstop, ctlr->card.pstop); - dp8390outb(ctlr->card.dp8390+Bnry, ctlr->card.pstop-1); + ulong dp8390; - dp8390outb(ctlr->card.dp8390+Cr, Page1|RDMAabort|Stp); - dp8390outb(ctlr->card.dp8390+Curr, ctlr->card.pstart); - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp); + dp8390 = ctlr->card.dp8390; + dp8390outb(dp8390+Pstart, ctlr->card.pstart); + dp8390outb(dp8390+Pstop, ctlr->card.pstop); + dp8390outb(dp8390+Bnry, ctlr->card.pstop-1); + + dp8390outb(dp8390+Cr, Page1|RDMAabort|Stp); + dp8390outb(dp8390+Curr, ctlr->card.pstart); + dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp); ctlr->card.nxtpkt = ctlr->card.pstart; } @@ -183,6 +188,9 @@ dp8390ring(Ctlr *ctlr) void dp8390reset(Ctlr *ctlr) { + ulong dp8390; + + dp8390 = ctlr->card.dp8390; /* * This is the initialisation procedure described * as 'mandatory' in the datasheet, with references @@ -190,15 +198,15 @@ dp8390reset(Ctlr *ctlr) */ dp8390disable(ctlr); if(ctlr->card.bit16) - dp8390outb(ctlr->card.dp8390+Dcr, Ft4|Ls|Wts); + dp8390outb(dp8390+Dcr, Ft4|Ls|Wts); else - dp8390outb(ctlr->card.dp8390+Dcr, Ft4|Ls); + dp8390outb(dp8390+Dcr, Ft4|Ls); - dp8390outb(ctlr->card.dp8390+Rbcr0, 0); - dp8390outb(ctlr->card.dp8390+Rbcr1, 0); + dp8390outb(dp8390+Rbcr0, 0); + dp8390outb(dp8390+Rbcr1, 0); - dp8390outb(ctlr->card.dp8390+Tcr, 0); - dp8390outb(ctlr->card.dp8390+Rcr, Mon); + dp8390outb(dp8390+Tcr, 0); + dp8390outb(dp8390+Rcr, Mon); /* * Init the ring hardware and software ring pointers. @@ -206,16 +214,16 @@ dp8390reset(Ctlr *ctlr) * it yet. */ dp8390ring(ctlr); - dp8390outb(ctlr->card.dp8390+Tpsr, ctlr->card.tstart); + dp8390outb(dp8390+Tpsr, ctlr->card.tstart); - dp8390outb(ctlr->card.dp8390+Isr, 0xFF); - dp8390outb(ctlr->card.dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); + dp8390outb(dp8390+Isr, 0xFF); + dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); /* * Leave the chip initialised, * but in monitor mode. */ - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta); + dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta); } void @@ -246,9 +254,33 @@ dp8390mode(Ctlr *ctlr, int on) void dp8390setea(Ctlr *ctlr) { + ulong dp8390; + uchar cr; + int i; + + dp8390 = ctlr->card.dp8390; + /* + * Set the ethernet address into the chip. + * Take care to restore the command register + * afterwards. We don't care about multicast + * addresses as we never set the multicast + * enable. + */ + cr = dp8390inb(dp8390+Cr) & ~Txp; + dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr)); + for(i = 0; i < sizeof(ctlr->ea); i++) + dp8390outb(dp8390+Par0+i, ctlr->ea[i]); + dp8390outb(dp8390+Cr, cr); +} + +void +dp8390getea(Ctlr *ctlr) +{ + ulong dp8390; uchar cr; int i; + dp8390 = ctlr->card.dp8390; /* * Set the ethernet address into the chip. * Take care to restore the command register @@ -256,43 +288,45 @@ dp8390setea(Ctlr *ctlr) * addresses as we never set the multicast * enable. */ - cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp; - dp8390outb(ctlr->card.dp8390+Cr, Page1|(~(Ps1|Ps0) & cr)); + cr = dp8390inb(dp8390+Cr) & ~Txp; + dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr)); for(i = 0; i < sizeof(ctlr->ea); i++) - dp8390outb(ctlr->card.dp8390+Par0+i, ctlr->ea[i]); - dp8390outb(ctlr->card.dp8390+Cr, cr); + ctlr->ea[i] = dp8390inb(dp8390+Par0+i); + dp8390outb(dp8390+Cr, cr); } void* dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len) { + ulong dp8390; uchar cr; int timo; + dp8390 = ctlr->card.dp8390; /* * Read some data at offset 'from' in the card's memory * using the DP8390 remote DMA facility, and place it at * 'to' in main memory, via the I/O data port. */ - cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp; - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta); - dp8390outb(ctlr->card.dp8390+Isr, Rdc); + cr = dp8390inb(dp8390+Cr) & ~Txp; + dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta); + dp8390outb(dp8390+Isr, Rdc); /* * Set up the remote DMA address and count. */ if(ctlr->card.bit16) len = ROUNDUP(len, 2); - dp8390outb(ctlr->card.dp8390+Rbcr0, len & 0xFF); - dp8390outb(ctlr->card.dp8390+Rbcr1, (len>>8) & 0xFF); - dp8390outb(ctlr->card.dp8390+Rsar0, from & 0xFF); - dp8390outb(ctlr->card.dp8390+Rsar1, (from>>8) & 0xFF); + dp8390outb(dp8390+Rbcr0, len & 0xFF); + dp8390outb(dp8390+Rbcr1, (len>>8) & 0xFF); + dp8390outb(dp8390+Rsar0, from & 0xFF); + dp8390outb(dp8390+Rsar1, (from>>8) & 0xFF); /* * Start the remote DMA read and suck the data * out of the I/O port. */ - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAread|Sta); + dp8390outb(dp8390+Cr, Page0|RDMAread|Sta); if(ctlr->card.bit16) inss(ctlr->card.data, to, len/2); else @@ -305,28 +339,29 @@ dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len) * to the miracles of the bus, we could get this far * and still be talking to a slot full of nothing. */ - for(timo = 10000; (dp8390inb(ctlr->card.dp8390+Isr) & Rdc) == 0 && timo; timo--) + for(timo = 10000; (dp8390inb(dp8390+Isr) & Rdc) == 0 && timo; timo--) ; - dp8390outb(ctlr->card.dp8390+Isr, Rdc); - dp8390outb(ctlr->card.dp8390+Cr, cr); + dp8390outb(dp8390+Isr, Rdc); + dp8390outb(dp8390+Cr, cr); return to; } void* dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len) { + ulong dp8390, crda; uchar cr; - ulong crda; + dp8390 = ctlr->card.dp8390; /* * Write some data to offset 'to' in the card's memory * using the DP8390 remote DMA facility, reading it at * 'from' in main memory, via the I/O data port. */ - cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp; - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta); - dp8390outb(ctlr->card.dp8390+Isr, Rdc); + cr = dp8390inb(dp8390+Cr) & ~Txp; + dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta); + dp8390outb(dp8390+Isr, Rdc); if(ctlr->card.bit16) len = ROUNDUP(len, 2); @@ -337,24 +372,24 @@ dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len) * the initial set up for read. */ crda = to-1-ctlr->card.bit16; - dp8390outb(ctlr->card.dp8390+Rbcr0, (len+1+ctlr->card.bit16) & 0xFF); - dp8390outb(ctlr->card.dp8390+Rbcr1, ((len+1+ctlr->card.bit16)>>8) & 0xFF); - dp8390outb(ctlr->card.dp8390+Rsar0, crda & 0xFF); - dp8390outb(ctlr->card.dp8390+Rsar1, (crda>>8) & 0xFF); - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAread|Sta); + dp8390outb(dp8390+Rbcr0, (len+1+ctlr->card.bit16) & 0xFF); + dp8390outb(dp8390+Rbcr1, ((len+1+ctlr->card.bit16)>>8) & 0xFF); + dp8390outb(dp8390+Rsar0, crda & 0xFF); + dp8390outb(dp8390+Rsar1, (crda>>8) & 0xFF); + dp8390outb(dp8390+Cr, Page0|RDMAread|Sta); for(;;){ - crda = dp8390inb(ctlr->card.dp8390+Crda0); - crda |= dp8390inb(ctlr->card.dp8390+Crda1)<<8; + crda = dp8390inb(dp8390+Crda0); + crda |= dp8390inb(dp8390+Crda1)<<8; if(crda == to){ /* * Start the remote DMA write and make sure * the registers are correct. */ - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAwrite|Sta); + dp8390outb(dp8390+Cr, Page0|RDMAwrite|Sta); - crda = dp8390inb(ctlr->card.dp8390+Crda0); - crda |= dp8390inb(ctlr->card.dp8390+Crda1)<<8; + crda = dp8390inb(dp8390+Crda0); + crda |= dp8390inb(dp8390+Crda1)<<8; if(crda != to) panic("crda write %d to %d\n", crda, to); @@ -375,28 +410,28 @@ dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len) * a timeout here if this ever gets called before * we know there really is a chip there. */ - while((dp8390inb(ctlr->card.dp8390+Isr) & Rdc) == 0) + while((dp8390inb(dp8390+Isr) & Rdc) == 0) ; - dp8390outb(ctlr->card.dp8390+Isr, Rdc); - dp8390outb(ctlr->card.dp8390+Cr, cr); + dp8390outb(dp8390+Isr, Rdc); + dp8390outb(dp8390+Cr, cr); return (void*)to; } static uchar -getcurr(Ctlr *ctlr) +getcurr(ulong dp8390) { uchar cr, curr; - cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp; - dp8390outb(ctlr->card.dp8390+Cr, Page1|(~(Ps1|Ps0) & cr)); - curr = dp8390inb(ctlr->card.dp8390+Curr); - dp8390outb(ctlr->card.dp8390+Cr, cr); + cr = dp8390inb(dp8390+Cr) & ~Txp; + dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr)); + curr = dp8390inb(dp8390+Curr); + dp8390outb(dp8390+Cr, cr); return curr; } static void -cldaquiet(Ctlr *ctlr) +cldaquiet(ulong dp8390) { uchar a, b, c; @@ -409,11 +444,11 @@ cldaquiet(Ctlr *ctlr) */ for(;;delay(10)){ - a = dp8390inb(ctlr->card.dp8390+Clda0); - b = dp8390inb(ctlr->card.dp8390+Clda0); + a = dp8390inb(dp8390+Clda0); + b = dp8390inb(dp8390+Clda0); if(a != b) continue; - c = dp8390inb(ctlr->card.dp8390+Clda0); + c = dp8390inb(dp8390+Clda0); if(c != b) continue; break; @@ -426,11 +461,12 @@ dp8390receive(Ctlr *ctlr) RingBuf *ring; uchar curr, len1, *pkt; Hdr hdr; - ulong data, len; + ulong dp8390, data, len; - for(curr = getcurr(ctlr); ctlr->card.nxtpkt != curr; curr = getcurr(ctlr)){ + dp8390 = ctlr->card.dp8390; + for(curr = getcurr(dp8390); ctlr->card.nxtpkt != curr; curr = getcurr(dp8390)){ if(strcmp(arch->id, "NCRD.0") == 0) - cldaquiet(ctlr); + cldaquiet(dp8390); ctlr->inpackets++; @@ -458,9 +494,9 @@ dp8390receive(Ctlr *ctlr) || len < 60 || len > sizeof(Etherpkt)){ print("H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d|", hdr.status, hdr.next, hdr.len0, hdr.len1, len); - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp); + dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp); dp8390ring(ctlr); - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta); + dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta); return; } @@ -500,7 +536,7 @@ dp8390receive(Ctlr *ctlr) hdr.next--; if(hdr.next < ctlr->card.pstart) hdr.next = ctlr->card.pstop-1; - dp8390outb(ctlr->card.dp8390+Bnry, hdr.next); + dp8390outb(dp8390+Bnry, hdr.next); } } @@ -510,8 +546,10 @@ dp8390receive(Ctlr *ctlr) void dp8390transmit(Ctlr *ctlr) { + ulong dp8390; RingBuf *ring; + dp8390 = ctlr->card.dp8390; ring = &ctlr->tb[ctlr->ti]; if(ctlr->tbusy == 0 && ring->owner == Interface){ @@ -519,41 +557,43 @@ dp8390transmit(Ctlr *ctlr) (*ctlr->card.write)(ctlr, ctlr->card.tstart*Dp8390BufSz, ring->pkt, ring->len); - dp8390outb(ctlr->card.dp8390+Tbcr0, ring->len & 0xFF); - dp8390outb(ctlr->card.dp8390+Tbcr1, (ring->len>>8) & 0xFF); - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Txp|Sta); + dp8390outb(dp8390+Tbcr0, ring->len & 0xFF); + dp8390outb(dp8390+Tbcr1, (ring->len>>8) & 0xFF); + dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta); } } void dp8390overflow(Ctlr *ctlr) { + ulong dp8390; uchar txp; int resend; + dp8390 = ctlr->card.dp8390; /* * The following procedure is taken from the DP8390[12D] datasheet, * it seems pretty adamant that this is what has to be done. */ - txp = dp8390inb(ctlr->card.dp8390+Cr) & Txp; - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp); + txp = dp8390inb(dp8390+Cr) & Txp; + dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp); delay(2); - dp8390outb(ctlr->card.dp8390+Rbcr0, 0); - dp8390outb(ctlr->card.dp8390+Rbcr1, 0); + dp8390outb(dp8390+Rbcr0, 0); + dp8390outb(dp8390+Rbcr1, 0); resend = 0; - if(txp && (dp8390inb(ctlr->card.dp8390+Isr) & (Txe|Ptx)) == 0) + if(txp && (dp8390inb(dp8390+Isr) & (Txe|Ptx)) == 0) resend = 1; - dp8390outb(ctlr->card.dp8390+Tcr, Lb); - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta); + dp8390outb(dp8390+Tcr, Lb); + dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta); (*ctlr->card.receive)(ctlr); - dp8390outb(ctlr->card.dp8390+Isr, Ovw); + dp8390outb(dp8390+Isr, Ovw); wakeup(&ctlr->rr); - dp8390outb(ctlr->card.dp8390+Tcr, 0); + dp8390outb(dp8390+Tcr, 0); if(resend) - dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Txp|Sta); + dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta); } void @@ -577,20 +617,22 @@ dp8390watch(Ctlr *ctlr) void dp8390intr(Ctlr *ctlr) { + ulong dp8390; RingBuf *ring; uchar isr, r; + dp8390 = ctlr->card.dp8390; /* * While there is something of interest, * clear all the interrupts and process. */ - dp8390outb(ctlr->card.dp8390+Imr, 0x00); - while(isr = dp8390inb(ctlr->card.dp8390+Isr)){ + dp8390outb(dp8390+Imr, 0x00); + while(isr = dp8390inb(dp8390+Isr)){ if(isr & Ovw){ if(ctlr->card.overflow) (*ctlr->card.overflow)(ctlr); - dp8390outb(ctlr->card.dp8390+Isr, Ovw); + dp8390outb(dp8390+Isr, Ovw); ctlr->overflows++; } @@ -601,7 +643,7 @@ dp8390intr(Ctlr *ctlr) */ if(isr & (Rxe|Prx)){ (*ctlr->card.receive)(ctlr); - dp8390outb(ctlr->card.dp8390+Isr, Rxe|Prx); + dp8390outb(dp8390+Isr, Rxe|Prx); wakeup(&ctlr->rr); } @@ -611,14 +653,14 @@ dp8390intr(Ctlr *ctlr) * and wake the output routine. */ if(isr & (Txe|Ptx)){ - r = dp8390inb(ctlr->card.dp8390+Tsr); + r = dp8390inb(dp8390+Tsr); if(isr & Txe){ if((r & (Cdh|Fu|Crs|Abt)) && ctlr->debug) print("Tsr#%2.2ux|", r); ctlr->oerrs++; } - dp8390outb(ctlr->card.dp8390+Isr, Txe|Ptx); + dp8390outb(dp8390+Isr, Txe|Ptx); if(isr & Ptx) ctlr->outpackets++; @@ -632,11 +674,11 @@ dp8390intr(Ctlr *ctlr) } if(isr & Cnt){ - ctlr->frames += dp8390inb(ctlr->card.dp8390+Cntr0); - ctlr->crcs += dp8390inb(ctlr->card.dp8390+Cntr1); - ctlr->buffs += dp8390inb(ctlr->card.dp8390+Cntr2); - dp8390outb(ctlr->card.dp8390+Isr, Cnt); + ctlr->frames += dp8390inb(dp8390+Cntr0); + ctlr->crcs += dp8390inb(dp8390+Cntr1); + ctlr->buffs += dp8390inb(dp8390+Cntr2); + dp8390outb(dp8390+Isr, Cnt); } } - dp8390outb(ctlr->card.dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); + dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); } diff --git a/pc/fault386.c b/pc/fault386.c index 26ec224499e4c3fe3b3e51ea21e77a3684bb90e7..04f6bf1f9ffa1b4a01fd492c3302cc110c9197d5 100644 --- a/pc/fault386.c +++ b/pc/fault386.c @@ -18,24 +18,25 @@ fault386(Ureg *ur) int insyscall; char buf[ERRLEN]; - insyscall = u->p->insyscall; - u->p->insyscall = 1; + insyscall = up->insyscall; + up->insyscall = 1; addr = getcr2(); read = !(ur->ecode & 2); user = (ur->cs&0xffff) == UESEL; spllo(); +/* print("F%d:A#%lux:U%d:R%d|", up->pid, addr, user, read);/**/ n = fault(addr, read); if(n < 0){ if(user){ sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr); - postnote(u->p, 1, buf, NDebug); + postnote(up, 1, buf, NDebug); return; } dumpregs(ur); panic("fault: 0x%lux", addr); } - u->p->insyscall = insyscall; + up->insyscall = insyscall; } void diff --git a/pc/fns.h b/pc/fns.h index 41061c4e82128f8b1b9e66eab302b2856e31d312..d9e874d2d017c5bd24d86dbacd2aba9e0a8e195f 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -1,6 +1,6 @@ #include "../port/portfns.h" -void meminit(void); +void addconf(char*, char*); void bbinit(void); void bigcursor(void); void bootargs(ulong); @@ -11,6 +11,7 @@ void config(int); int cpuspeed(int); void delay(int); void dmaend(int); +void dmainit(void); long dmasetup(int, void*, long, int); #define evenaddr(x) /* 386 doesn't care */ void fault386(Ureg*); @@ -25,6 +26,7 @@ void fpsave(FPsave*); ulong fpstatus(void); ulong getcr0(void); ulong getcr2(void); +char* getconf(char*); void i8042a20(void); void i8042reset(void); void ident(void); @@ -33,13 +35,17 @@ int inb(int); void insb(int, void*, int); ushort ins(int); void inss(int, void*, int); +ulong inl(int); void insl(int, void*, int); +int isaconfig(char*, int, ISAConf*); ulong isamem(int); void kbdinit(void); void* l0update(uchar*, uchar*, long); void* l1update(uchar*, uchar*, long); void* l2update(uchar*, uchar*, long); +long* mapaddr(ulong); void mathinit(void); +void meminit(void); void mmuinit(void); #define mmunewpage(x) int modem(int); @@ -49,12 +55,19 @@ void outb(int, int); void outsb(int, void*, int); void outs(int, ushort); void outss(int, void*, int); +void outl(int, ulong); void outsl(int, void*, int); void pcicreset(void); +int pcmio(int, ISAConf*); +long pcmread(int, int, void*, long, ulong); +int pcmspecial(int); +void pcmspecialclose(int); +long pcmwrite(int, int, void*, long, ulong); void prhex(ulong); void procrestore(Proc*); void procsave(Proc*); void procsetup(Proc*); +void ps2poll(void); void putgdt(Segdesc*, int); void putidt(Segdesc*, int); void putcr3(ulong); @@ -73,7 +86,7 @@ void uartclock(void); void uartintr0(Ureg*); void uartspecial(int, IOQ*, IOQ*, int); void vgainit(void); -#define waserror() (u->nerrlab++, setlabel(&u->errlab[u->nerrlab-1])) +#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1])) #define kmapperm(x) kmap(x) #define getcallerpc(x) (*(ulong*)(x)) #define KADDR(a) ((void*)((ulong)(a)|KZERO)) diff --git a/pc/kbd.c b/pc/kbd.c index d3bc85b21f6998f63704c5b2b20e0c0aebe51077..b4f61ee727f90ef3f6031efea6bbe61d041fd570 100644 --- a/pc/kbd.c +++ b/pc/kbd.c @@ -25,6 +25,17 @@ enum { Cmd= 0x64, /* command port (write only) */ + CTdata= 0x0, /* chips & Technologies ps2 data port */ + CTstatus= 0x1, /* chips & Technologies ps2 status port */ + Enable= 1<<7, + Clear= 1<<6, + Error= 1<<5, + Intenable= 1<<4, + Reset= 1<<3, + Tready= 1<<2, + Rready= 1<<1, + Idle= 1<<0, + Spec= 0x80, PF= Spec|0x20, /* num pad function key */ @@ -112,6 +123,7 @@ KIOQ kbdq; static int keybuttons; static uchar ccc; static int shift; +ulong ctport; enum { @@ -125,6 +137,7 @@ enum }; static void kbdintr(Ureg*); +static void ctps2intr(Ureg*); static int ps2mouseputc(IOQ*, int); /* @@ -171,7 +184,7 @@ mousecmd(int cmd) c = 0; tries = 0; do{ - if(tries++ > 5) + if(tries++ > 2) break; if(outready() < 0) break; @@ -227,6 +240,7 @@ i8042reset(void) outready(); } + void kbdinit(void) { @@ -279,6 +293,54 @@ serialmouse(int port, char *type, int setspeed) mousetype = Mouseserial; } +static void nop(void){}; + +/* + * look for a chips & technologies 82c710 ps2 mouse on a TI travelmate + */ +static int +ct82c710(void) +{ + int c; + + /* on non-C&T 2fa and 3fa are input only ports */ + /* get chips attention */ + outb(0x2fa, 0x55); nop(); nop(); + outb(0x3fa, ~0x55); nop(); nop(); + outb(0x3fa, 0x36); nop(); nop(); + + /* tell it where its config register should be */ + outb(0x3fa, 0x390>>2); nop(); nop(); + outb(0x2fa, ~(0x390>>2)); nop(); nop(); + + /* see if this is really a 710 */ + outb(0x390, 0xf); nop(); nop(); + if(inb(0x391) != (0x390>>2)) + return -1; + + /* get data port address */ + outb(0x390, 0xd); nop(); nop(); + c = inb(0x391); + if(c == 0 || c == 0xff) + return -1; + ctport = c<<2; + + /* turn off config mode */ + outb(0x390, 0xf); nop(); nop(); + outb(0x391, 0xf); + + setvec(Mousevec, ctps2intr); + + /* enable for interrupts */ + c = inb(ctport + CTstatus); + c &= ~(Clear|Reset); + c |= Enable|Intenable; + outb(ctport + CTstatus, c); + + mousetype = MousePS2; + return 0; +} + /* * set up a ps2 mouse */ @@ -290,6 +352,9 @@ ps2mouse(void) if(mousetype) error(Emouseset); + if(ct82c710() == 0) + return; + /* enable kbd/mouse xfers and interrupts */ setvec(Mousevec, kbdintr); x = splhi(); @@ -563,3 +628,18 @@ kbdintr(Ureg *ur) USED(ur); kbdintr0(); } + +void +ctps2intr(Ureg *ur) +{ + uchar c; + + USED(ur); + c = inb(ctport + CTstatus); + if(c & Error) + return; + if((c & Rready) == 0) + return; + c = inb(ctport + CTdata); + ps2mouseputc(&mouseq, c); +} diff --git a/pc/l.s b/pc/l.s index 754e1cd3b2695e9e15a5c79a82e69573f9e1a0bc..9a1cbb636811e4be238803a631c31290387e63af 100644 --- a/pc/l.s +++ b/pc/l.s @@ -1,89 +1,16 @@ #include "mem.h" #define OP16 BYTE $0x66 +#define NOP XCHGL AX,AX /* - * about to walk all over ms/dos - turn off interrupts + * We assume that b.com got us into 32 bit mode already. We are now + * running with a PC == origin & ~KZERO. */ TEXT origin(SB),$0 CLI -#ifdef BOOT -/* - * This part of l.s is used only in the boot kernel. - * It assumes that we are in real address mode, i.e., - * that we look like an 8086. - */ -/* - * relocate everything to a half meg and jump there - * - looks wierd because it is being assembled by a 32 bit - * assembler for a 16 bit world - */ - MOVL $0,BX - INCL BX - SHLL $15,BX - MOVL BX,CX - MOVW BX,ES - MOVL $0,SI - MOVL SI,DI - CLD; REP; MOVSL -/* JMPFAR 0X8000:$lowcore(SB) /**/ - BYTE $0xEA - WORD $lowcore(SB) - WORD $0X8000 - -TEXT lowcore(SB),$0 - -/* - * now that we're in low core, update the DS - */ - - MOVW BX,DS - -/* - * goto protected mode - */ -/* MOVL tgdtptr(SB),GDTR /**/ - BYTE $0x0f - BYTE $0x01 - BYTE $0x16 - WORD $tgdtptr(SB) - MOVL CR0,AX - ORL $1,AX - MOVL AX,CR0 - -/* - * clear prefetch queue (weird code to avoid optimizations) - */ - CLC - JCC flush - MOVL AX,AX -flush: - -/* - * set all segs - */ -/* MOVW $SELECTOR(1, SELGDT, 0),AX /**/ - BYTE $0xc7 - BYTE $0xc0 - WORD $SELECTOR(1, SELGDT, 0) - MOVW AX,DS - MOVW AX,SS - MOVW AX,ES - MOVW AX,FS - MOVW AX,GS - -/* JMPFAR SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/ - BYTE $0x66 - BYTE $0xEA - LONG $mode32bit-KZERO(SB) - WORD $SELECTOR(2, SELGDT, 0) - -TEXT mode32bit(SB),$0 - -#endif BOOT - /* * Clear BSS */ @@ -104,8 +31,8 @@ TEXT mode32bit(SB),$0 LEAL tpt-KZERO(SB),AX /* get phys addr of temporary page table */ ADDL $(BY2PG-1),AX /* must be page alligned */ ANDL $(~(BY2PG-1)),AX /* ... */ - MOVL $(4*1024),CX /* pte's per page */ - MOVL $((((4*1024)-1)<>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX) - ADDL $BY2PG,BX - MOVL BX,4(AX) - MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX) - ADDL $BY2PG,BX - MOVL BX,8(AX) - MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX) - ADDL $BY2PG,BX - MOVL BX,12(AX) - MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX) /* * point processor to top level page & turn on paging @@ -155,7 +73,7 @@ TEXT tokzero(SB),$0 MOVL SP,m(SB) MOVL $0,0(SP) ADDL $(MACHSIZE-4),SP /* start stack under machine struct */ - MOVL $0, u(SB) + MOVL $0, up(SB) /* * clear flags @@ -172,7 +90,7 @@ loop: GLOBL mach0+0(SB), $MACHSIZE GLOBL u(SB), $4 GLOBL m(SB), $4 -GLOBL tpt(SB), $(BY2PG*6) +GLOBL tpt(SB), $(BY2PG*3) /* * gdt to get us to 32-bit/segmented/unpaged mode @@ -251,7 +169,6 @@ TEXT ins(SB), $0 OP16; INL RET - /* * input a string of shorts from a port */ @@ -263,6 +180,16 @@ TEXT inss(SB),$0 CLD; REP; OP16; INSL RET +/* + * input a long from a port + */ +TEXT inl(SB), $0 + + MOVL p+0(FP), DX + XORL AX, AX + INL + RET + /* * input a string of longs from a port */ @@ -294,6 +221,15 @@ TEXT outss(SB),$0 CLD; REP; OP16; OUTSL RET +/* + * output a long to a port + */ +TEXT outl(SB), $0 + MOVL p+0(FP), DX + MOVL s+4(FP), AX + OUTL + RET + /* * output a string of longs to a port */ @@ -553,10 +489,12 @@ intrcommon: CALL trap(SB) POPL AX POPAL + NOP POPL GS POPL FS POPL ES POPL DS + NOP ADDL $8,SP /* error code and trap type */ IRETL @@ -574,10 +512,12 @@ intrscommon: CALL trap(SB) POPL AX POPAL + NOP POPL GS POPL FS POPL ES POPL DS + NOP ADDL $8,SP /* error code and trap type */ IRETL @@ -794,3 +734,39 @@ TEXT dp8390outb(SB), $0 _dp8390outb0: RET + +/* + * dsp outb string called from devdsp.c + */ + TEXT dspoutb+0(SB), $0 + + MOVL a+4(FP), BX + MOVL n+8(FP), CX + + MOVL base+0(FP), DX + ADDL $2, DX /* Pcontrol */ + + MOVL c2+12(FP), DI + MOVL c3+16(FP), SI + +dsploop: + MOVL DI, AX /* normal */ + OUTB + + SUBL $1, CX + CMPL CX, $0 + JLT dspout + + SUBL $2, DX /* Pdata */ + MOVB (BX), AX + ADDL $1, BX + OUTB + + ADDL $2, DX /* Pcontrol */ + MOVL SI, AX /* strobe */ + OUTB + + JMP dsploop + +dspout: + RET diff --git a/pc/main.c b/pc/main.c index 9c49ff2f71532b44ef1f9db41589055f1bf0857a..db0ae715c73bd2f3818ed7bb75af5d75342fc7d4 100644 --- a/pc/main.c +++ b/pc/main.c @@ -26,10 +26,15 @@ PCArch *knownarch[] = #define BOOTARGSLEN 1024 #define MAXCONF 32 +char bootdisk[NAMELEN]; char *confname[MAXCONF]; char *confval[MAXCONF]; int nconf; +/* memory map */ +#define MAXMEG 64 +char mmap[MAXMEG+2]; + void main(void) { @@ -40,6 +45,7 @@ main(void) active.machs = 1; confinit(); xinit(); + dmainit(); screeninit(); printinit(); mmuinit(); @@ -51,8 +57,8 @@ main(void) kbdinit(); procinit0(); initseg(); + links(); chandevreset(); - streaminit(); swapinit(); userinit(); schedinit(); @@ -94,10 +100,10 @@ init0(void) int i; char tstr[32]; - u->nerrlab = 0; - m->proc = u->p; - u->p->state = Running; - u->p->mach = m; + up->nerrlab = 0; + m->proc = up->p; + up->state = Running; + up->mach = m; spllo(); @@ -105,21 +111,23 @@ init0(void) * These are o.k. because rootinit is null. * Then early kproc's will have a root and dot. */ - u->slash = (*devtab[0].attach)(0); - u->dot = clone(u->slash, 0); + up->slash = namec("#/", Atodir, 0, 0); + up->dot = clone(up->slash, 0); - kproc("alarm", alarmkproc, 0); + iallocinit(); chandevinit(); if(!waserror()){ - for(i = 0; i < nconf; i++) - ksetenv(confname[i], confval[i]); strcpy(tstr, arch->id); strcat(tstr, " %s"); ksetterm(tstr); ksetenv("cputype", "386"); + for(i = 0; i < nconf; i++) + if(confname[i]) + ksetenv(confname[i], confval[i]); poperror(); } + kproc("alarm", alarmkproc, 0); touser(sp); } @@ -152,21 +160,12 @@ userinit(void) * 4 bytes for gotolabel's return PC */ p->sched.pc = (ulong)init0; - p->sched.sp = USERADDR + BY2PG - 4; - p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF)); - - /* - * User - */ - k = kmap(p->upage); - up = (User*)VA(k); - up->p = p; - kunmap(k); + p->sched.sp = (ulong)p->kstack+KSTACK-(1+MAXSYSARG)*BY2WD; /* * User Stack */ - s = newseg(SG_STACK, USTKTOP-BY2PG, 1); + s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); p->seg[SSEG] = s; pg = newpage(1, 0, USTKTOP-BY2PG); segpage(s, pg); @@ -178,8 +177,11 @@ userinit(void) * Text */ s = newseg(SG_TEXT, UTZERO, 1); + s->flushme++; p->seg[TSEG] = s; - segpage(s, newpage(1, 0, UTZERO)); + pg = newpage(1, 0, UTZERO); + memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); + segpage(s, pg); k = kmap(s->map[0]->pages[0]); memmove((ulong*)VA(k), initcode, sizeof initcode); kunmap(k); @@ -213,13 +215,30 @@ bootargs(ulong base) av[ac++] = pusharg("/386/9safari"); av[ac++] = pusharg("-p"); cp[64] = 0; + buf[0] = 0; if(strncmp(cp, "fd!", 3) == 0){ sprint(buf, "local!#f/fd%ddisk", atoi(cp+3)); av[ac++] = pusharg(buf); + } else if(strncmp(cp, "h!", 2) == 0){ + sprint(buf, "local!#H/hd%dfs", atoi(cp+2)); + av[ac++] = pusharg(buf); } else if(strncmp(cp, "hd!", 3) == 0){ - sprint(buf, "local!#h/hd%ddisk", atoi(cp+3)); + sprint(buf, "local!#H/hd%ddisk", atoi(cp+3)); + av[ac++] = pusharg(buf); + } else if(strncmp(cp, "s!", 2) == 0){ + sprint(buf, "local!#w/sd%dfs", atoi(cp+2)); + av[ac++] = pusharg(buf); + } else if(strncmp(cp, "sd!", 3) == 0){ + sprint(buf, "local!#w/sd%ddisk", atoi(cp+3)); av[ac++] = pusharg(buf); } + if(buf[0]){ + cp = strchr(buf, '!'); + if(cp){ + strcpy(bootdisk, cp+1); + addconf("bootdisk", bootdisk); + } + } /* 4 byte word align stack */ sp = (uchar*)((ulong)sp & ~3); @@ -235,10 +254,31 @@ bootargs(ulong base) Conf conf; +void +addconf(char *name, char *val) +{ + if(nconf >= MAXCONF) + return; + confname[nconf] = name; + confval[nconf] = val; + nconf++; +} + +char* +getconf(char *name) +{ + int i; + + for(i = 0; i < nconf; i++) + if(strcmp(confname[i], name) == 0) + return confval[i]; + return 0; +} + void confinit(void) { - long x, i, j, n, *l; + long x, i, j, n; int pcnt; ulong ktop; char *cp; @@ -249,7 +289,7 @@ confinit(void) /* * parse configuration args from dos file p9rc */ - cp = BOOTARGS; /* where b.com leaves it's config */ + cp = BOOTARGS; /* where b.com leaves its config */ cp[BOOTARGSLEN-1] = 0; n = getfields(cp, line, MAXCONF, '\n'); for(j = 0; j < n; j++){ @@ -268,60 +308,83 @@ confinit(void) pcnt = 100 - atoi(confval[nconf]); nconf++; } - /* - * the first 640k is the standard useful memory - * the next 128K is the display, I/O mem, and BIOS - * the last 256k belongs to the roms and other devices - */ - conf.npage0 = 640/4; - conf.base0 = 0; - - /* - * size the non-standard memory + * size memory above 1 meg. Kernel sits at 1 meg. We + * only recognize MB size chunks. */ + memset(mmap, ' ', sizeof(mmap)); x = 0x12345678; - for(i=2; i<17; i++){ + for(i = 1; i <= MAXMEG; i++){ /* - * write the word + * write the first & last word in a megabyte of memory */ - l = (long*)(KZERO|(i*MB)); - l--; - *l = x; + *mapaddr(KZERO|(i*MB)) = x; + *mapaddr(KZERO|((i+1)*MB-BY2WD)) = x; + /* - * take care of wraps + * write the first and last word in all previous megs to + * handle address wrap around */ for(j = 1; j < i; j++){ - l = (long*)(KZERO|(j*MB)); - l--; - *l = ~x; + *mapaddr(KZERO|(j*MB)) = ~x; + *mapaddr(KZERO|((j+1)*MB-BY2WD)) = ~x; } + /* - * check + * check for correct value */ - l = (long*)(KZERO|(i*MB)); - l--; - if(*l != x) - break; - memset((char*)(KZERO|((i-1)*MB)), 0, MB); + if(*mapaddr(KZERO|(i*MB)) == x && *mapaddr(KZERO|((i+1)*MB-BY2WD)) == x){ + mmap[i] = 'x'; + /* + * zero memory to set ECC but skip over the kernel + */ + if(i != 1) + for(j = 0; j < MB/BY2PG; j += BY2PG) + memset(mapaddr(KZERO|(i*MB+j)), 0, BY2PG); + } x += 0x3141526; } - i--; - conf.base1 = 1*MB; - conf.npage1 = (i*MB - conf.base1)/BY2PG; + /* + * bank0 usually goes from the end of kernel bss to the end of memory + */ + ktop = PGROUND((ulong)end); + ktop = PADDR(ktop); + conf.base0 = ktop; + for(i = 1; mmap[i] == 'x'; i++) + ; + conf.npage0 = (i*MB - ktop)/BY2PG; + conf.topofmem = i*MB; + + /* + * bank1 usually goes from the end of BOOTARGS to 640k + */ + conf.base1 = (ulong)(BOOTARGS+BOOTARGSLEN); + conf.base1 = PGROUND(conf.base1); + conf.base1 = PADDR(conf.base1); + conf.npage1 = (640*1024-conf.base1)/BY2PG; + + /* + * if there is a hole in memory (due to a shadow BIOS) make the + * memory after the hole be bank 1. The memory from 0 to 640k + * is lost. + */ + for(; i <= MAXMEG; i++) + if(mmap[i] == 'x'){ + conf.base1 = i*MB; + for(j = i+1; mmap[j] == 'x'; j++) + ; + conf.npage1 = (j - i)*MB/BY2PG; + conf.topofmem = j*MB; + break; + } + conf.npage = conf.npage0 + conf.npage1; conf.ldepth = 0; if(pcnt < 10) pcnt = 70; conf.upages = (conf.npage*pcnt)/100; - ktop = PGROUND((ulong)end); - ktop = PADDR(ktop); - conf.npage0 -= ktop/BY2PG; - conf.base0 += ktop; - - conf.topofmem = i*MB; - conf.nproc = 30 + i*5; + conf.nproc = 30 + ((conf.npage*BY2PG)/MB)*5; conf.monitor = 1; conf.nswap = conf.nproc*80; conf.nimage = 50; @@ -363,24 +426,24 @@ matherror(Ureg *ur) /* * save floating point state to check out error */ - fpenv(&u->fpsave); - status = u->fpsave.status; + fpenv(&up->fpsave); + status = up->fpsave.status; msg = 0; for(i = 0; i < 8; i++) if((1<fpsave.pc); - postnote(u->p, 1, note, NDebug); + sprint(note, "sys: fp: %s fppc=0x%lux", msg, up->fpsave.pc); + postnote(up->p, 1, note, NDebug); break; } if(msg == 0){ - sprint(note, "sys: fp: unknown fppc=0x%lux", u->fpsave.pc); - postnote(u->p, 1, note, NDebug); + sprint(note, "sys: fp: unknown fppc=0x%lux", up->fpsave.pc); + postnote(up->p, 1, note, NDebug); } if(ur->pc & KZERO) panic("fp: status %lux fppc=0x%lux pc=0x%lux", status, - u->fpsave.pc, ur->pc); + up->fpsave.pc, ur->pc); } /* @@ -390,14 +453,14 @@ void mathemu(Ureg *ur) { USED(ur); - switch(u->p->fpstate){ + switch(up->fpstate){ case FPinit: fpinit(); - u->p->fpstate = FPactive; + up->fpstate = FPactive; break; case FPinactive: - fprestore(&u->fpsave); - u->p->fpstate = FPactive; + fprestore(&up->fpsave); + up->fpstate = FPactive; break; case FPactive: panic("math emu", 0); @@ -412,7 +475,7 @@ void mathover(Ureg *ur) { USED(ur); -print("sys: fp: math overrun pc 0x%lux pid %d\n", ur->pc, u->p->pid); +print("sys: fp: math overrun pc 0x%lux pid %d\n", ur->pc, up->pid); pexit("math overrun", 0); } @@ -445,7 +508,7 @@ procsave(Proc *p) if(p->state == Moribund) fpoff(); else - fpsave(&u->fpsave); + fpsave(&up->fpsave); p->fpstate = FPinactive; } } @@ -473,8 +536,12 @@ exit(int ispanic) { u = 0; print("exiting\n"); - if(ispanic) - for(;;); + if(ispanic){ + if(cpuflag) + delay(10000); + else + for(;;); + } (*arch->reset)(); } @@ -541,3 +608,69 @@ modem(int onoff) else return 0; } + +static int +parseether(uchar *to, char *from) +{ + char nip[4]; + char *p; + int i; + + p = from; + for(i = 0; i < 6; i++){ + if(*p == 0) + return -1; + nip[0] = *p++; + if(*p == 0) + return -1; + nip[1] = *p++; + nip[2] = 0; + to[i] = strtoul(nip, 0, 16); + if(*p == ':') + p++; + } + return 0; +} + +int +isaconfig(char *class, int ctlrno, ISAConf *isa) +{ + char cc[NAMELEN], *p, *q; + int n; + + sprint(cc, "%s%d", class, ctlrno); + for(n = 0; n < nconf; n++){ + if(strncmp(confname[n], cc, NAMELEN)) + continue; + p = confval[n]; + while(*p){ + while(*p == ' ' || *p == '\t') + p++; + if(*p == '\0') + break; + if(strncmp(p, "type=", 5) == 0){ + p += 5; + for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){ + if(*p == '\0' || *p == ' ' || *p == '\t') + break; + *q = *p++; + } + *q = '\0'; + } + else if(strncmp(p, "port=", 5) == 0) + isa->port = strtoul(p+5, &p, 0); + else if(strncmp(p, "irq=", 4) == 0) + isa->irq = strtoul(p+4, &p, 0); + else if(strncmp(p, "mem=", 4) == 0) + isa->mem = strtoul(p+4, &p, 0); + else if(strncmp(p, "size=", 5) == 0) + isa->size = strtoul(p+5, &p, 0); + else if(strncmp(p, "ea=", 3) == 0) + parseether(isa->ea, p+3); + while(*p && *p != ' ' && *p != '\t') + p++; + } + return 1; + } + return 0; +} diff --git a/pc/mem.h b/pc/mem.h index a8c10f527529ae14a0ff3cc62eb7d38ef20246de..f29cda42312856dbc2ffe89b5e7140b6e2a27ba0 100644 --- a/pc/mem.h +++ b/pc/mem.h @@ -42,12 +42,11 @@ #define UTZERO (UZERO+BY2PG) /* first address in user text */ #define KZERO 0x80000000 /* base of kernel address space */ #define KTZERO KZERO /* first address in kernel text */ -#define USERADDR 0xC0000000 /* struct User */ -#define UREGADDR (USERADDR+BY2PG-4*19) -#define TSTKTOP USERADDR /* end of new stack in sysexec */ +#define TSTKTOP 0xC0000000 /* end of new stack in sysexec */ #define TSTKSIZ 10 #define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */ #define USTKSIZE (16*1024*1024 - TSTKSIZ*BY2PG) /* size of user stack */ +#define KSTACK 4096 /* Size of kernel stack */ #define ROMBIOS (KZERO|0xF0000) #define ISAMEMSIZE (4*MB) /* mem space reserved for ISA */ diff --git a/pc/mmu.c b/pc/mmu.c index 9f21f9cc16f7fd09ba0ef00ddf5e7d407585a41f..c4ca0088078dd3c1728f8bda562607ca4b7f0552 100644 --- a/pc/mmu.c +++ b/pc/mmu.c @@ -71,7 +71,6 @@ Segdesc gdt[] = static Page ktoppg; /* prototype top level page table * containing kernel mappings */ static ulong *kpt; /* 2nd level page tables for kernel mem */ -static ulong *upt; /* 2nd level page table for struct User */ #define ROUNDUP(s,v) (((s)+(v-1))&~(v-1)) /* @@ -96,6 +95,21 @@ struct ulong end; /* one past available isa bus memory */ } isamemalloc; +/* + * Change current page table and the stack to use for exceptions + * (traps & interrupts). The exception stack comes from the tss. + * Since we use only one tss, (we hope) there's no need for a + * puttr(). + */ +static void +taskswitch(ulong pagetbl, ulong stack) +{ + putcr3(pagetbl); + tss.ss0 = KDSEL; + tss.sp0 = stack; + tss.cr3 = pagetbl; +} + /* * Create a prototype page map that maps all of memory into * kernel (KZERO) space. This is the default map. It is used @@ -147,21 +161,11 @@ mmuinit(void) for(i = 0; i < nkpt; i++) top[x+i] = (y+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE; - /* page table for u-> */ - upt = xspanalloc(BY2PG, BY2PG, 0); - x = TOPOFF(USERADDR); - y = ((ulong)upt)&~KZERO; - top[x] = y | PTEVALID | PTEKERNEL | PTEWRITE; - - putcr3(ktoppg.pa); - /* * set up the task segment */ memset(&tss, 0, sizeof(tss)); - tss.sp0 = USERADDR+BY2PG; - tss.ss0 = KDSEL; - tss.cr3 = ktoppg.pa; + taskswitch(ktoppg.pa, BY2BG + (ulong)m); puttr(TSSSEL); } @@ -174,28 +178,22 @@ flushmmu(void) int s; s = splhi(); - if(u){ - u->p->newtlb = 1; - mapstack(u->p); - } else - putcr3(ktoppg.pa); + up->newtlb = 1; + mmuswitch(up); splx(s); } /* * Switch to a process's memory map. If the process doesn't * have a map yet, just use the prototype one that contains - * mappings for only the kernel and the User struct. + * mappings for only the kernel. */ void -mapstack(Proc *p) +mmuswitch(Proc *p) { Page *pg; ulong *top; - if(p->upage->va != (USERADDR|(p->pid&0xFFFF)) && p->pid != 0) - panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va); - if(p->newtlb){ /* * newtlb set means that they are inconsistent @@ -218,17 +216,11 @@ mapstack(Proc *p) p->newtlb = 0; } - /* map in u area */ - upt[0] = PPN(p->upage->pa) | PTEVALID | PTEKERNEL | PTEWRITE; - /* tell processor about new page table (flushes cached entries) */ if(p->mmutop) - pg = p->mmutop; + taskswitch(p->mmutop->pa, p->kstack+KSTACK); else - pg = &ktoppg; - putcr3(pg->pa); - - u = (User*)USERADDR; + taskswitch(ktoppg.pa, p->kstack+KSTACK); } /* @@ -241,8 +233,8 @@ mmurelease(Proc *p) Page *pg; Page *next; - /* point 386 to protoype page map */ - putcr3(ktoppg.pa); + /* point 386 to protoype page map and m->stack */ + taskswitch(ktoppg.pa, BY2PG + (ulong)m); /* give away page table pages */ for(pg = p->mmufree; pg; pg = next){ @@ -269,24 +261,19 @@ putmmu(ulong va, ulong pa, Page *pg) int topoff; ulong *top; ulong *pt; - Proc *p; int s; - if(u==0) - panic("putmmu"); - p = u->p; - /* * create a top level page if we don't already have one. * copy the kernel top level page into it for kernel mappings. */ - if(p->mmutop == 0){ + if(up->mmutop == 0){ pg = newpage(0, 0, 0); pg->va = VA(kmap(pg)); memmove((void*)pg->va, (void*)ktoppg.va, BY2PG); - p->mmutop = pg; + up->mmutop = pg; } - top = (ulong*)p->mmutop->va; + top = (ulong*)up->mmutoup->va; topoff = TOPOFF(va); /* @@ -295,20 +282,20 @@ putmmu(ulong va, ulong pa, Page *pg) */ s = splhi(); if(PPN(top[topoff]) == 0){ - if(p->mmufree == 0){ + if(up->mmufree == 0){ spllo(); pg = newpage(1, 0, 0); pg->va = VA(kmap(pg)); splhi(); } else { - pg = p->mmufree; - p->mmufree = pg->next; + pg = up->mmufree; + up->mmufree = pg->next; memset((void*)pg->va, 0, BY2PG); } top[topoff] = PPN(pg->pa) | PTEVALID | PTEUSER | PTEWRITE; pg->daddr = topoff; - pg->next = p->mmuused; - p->mmuused = pg; + pg->next = up->mmuused; + up->mmuused = pg; } /* @@ -318,20 +305,10 @@ putmmu(ulong va, ulong pa, Page *pg) pt[BTMOFF(va)] = pa | PTEUSER; /* flush cached mmu entries */ - putcr3(p->mmutop->pa); + taskswitch(up->mmutoup->pa, up->kstack); splx(s); } -void -invalidateu(void) -{ - /* unmap u area */ - upt[0] = 0; - - /* flush cached mmu entries */ - putcr3(ktoppg.pa); -} - /* * allocate some address space (already mapped into the kernel) * for ISA bus memory. @@ -351,3 +328,33 @@ isamem(int len) unlock(&isamemalloc); return a; } + +/* + * used to map a page into 16 meg - BY2PG for confinit(). tpt is the temporary + * page table set up by l.s. + */ +long* +mapaddr(ulong addr) +{ + ulong base; + ulong off; + static ulong *pte, top; + extern ulong tpt[]; + + if(pte == 0){ + top = (((ulong)tpt)+(BY2PG-1))&~(BY2PG-1); + pte = (ulong*)top; + top &= ~KZERO; + top += BY2PG; + pte += (4*1024*1024-BY2PG)>>PGSHIFT; + } + + base = off = addr; + base &= ~(KZERO|(BY2PG-1)); + off &= BY2PG-1; + + *pte = base|PTEVALID|PTEKERNEL|PTEWRITE; /**/ + putcr3((ulong)top); + + return (long*)(KZERO | 4*1024*1024-BY2PG | off); +} diff --git a/pc/scsi.c b/pc/scsi.c new file mode 100644 index 0000000000000000000000000000000000000000..c2bc14283c34ac333000776fe6869683850726be --- /dev/null +++ b/pc/scsi.c @@ -0,0 +1,84 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +/* + * Known to devscsi.c. +int scsidebugs[8]; +int scsiownid = CtlrID; + */ + +void +initscsi(void) +{ +} + +/* + * Quick hack. Need to do a better job of dynamic initialisation + * for machines with peculiar memory/cache restictions. + * Also, what about 16Mb address limit on the Adaptec? + */ +static ulong bufdatasize; + +void +scsibufreset(ulong datasize) +{ + bufdatasize = datasize; +} + +Scsibuf * +scsibuf(void) +{ + Scsibuf *b; + + b = smalloc(sizeof(*b)); + b->virt = smalloc(bufdatasize); + b->phys = (void *)(PADDR(b->virt)); + return b; +} + +void +scsifree(Scsibuf *b) +{ + free(b->virt); + free(b); +} + +/* + * Hack for devvid + */ +Scsibuf * +scsialloc(ulong n) +{ + Scsibuf *b; + + b = smalloc(sizeof(*b)); + b->virt = smalloc(n); + b->phys = (void *)(PADDR(b->virt)); + return b; +} + +extern int (*aha1542reset(void))(Scsi*, int); +extern int (*ultra14freset(void))(Scsi*, int); + +static int (*exec)(Scsi*, int); + +int +scsiexec(Scsi *p, int rflag) +{ + if(exec == 0) + error(Enonexist); + return (*exec)(p, rflag); +} + +void +resetscsi(void) +{ + if(exec = aha1542reset()) + return; + exec = ultra14freset(); +} diff --git a/pc/trap.c b/pc/trap.c index dff6cfb9059a016274397dffe5d45df445f97275..b5ef247bd18f1e6d9a83ea3f41f81a64cb99d2dc 100644 --- a/pc/trap.c +++ b/pc/trap.c @@ -98,12 +98,12 @@ debugbpt(Ureg *ur) { char buf[ERRLEN]; - if(u == 0) + if(up == 0) panic("kernel bpt"); /* restore pc to instruction that caused the trap */ ur->pc--; sprint(buf, "sys: breakpoint"); - postnote(u->p, 1, buf, NDebug); + postnote(up->p, 1, buf, NDebug); } /* @@ -218,6 +218,9 @@ char *excname[] = [13] "general protection violation", }; +Ureg lasttrap, *lastur; + + /* * All traps */ @@ -233,7 +236,7 @@ trap(Ureg *ur) user = ((ur->cs)&0xffff)!=KESEL && v!=Syscallvec; if(user) - u->dbgreg = ur; + up->dbgreg = ur; /* * tell the 8259 that we're done with the @@ -248,6 +251,8 @@ trap(Ureg *ur) } if(v>=256 || (h = halloc.ivec[v]) == 0){ +lasttrap = *ur; +lastur = ur; /* an old 386 generates these fairly often, no idea why */ if(v == 13) return; @@ -256,7 +261,7 @@ trap(Ureg *ur) if(v <= 16){ if(user){ sprint(buf, "sys: trap: %s", excname[v]); - postnote(u->p, 1, buf, NDebug); + postnote(up->p, 1, buf, NDebug); return; } else { dumpregs(ur); @@ -267,7 +272,7 @@ trap(Ureg *ur) if(v >= Int0vec || v < Int0vec+16){ /* an unknown interrupts */ v -= Int0vec; - if(badintr[v]++ == 0 || (badintr[v]%1000) == 0) + if(badintr[v]++ == 0 || (badintr[v]%100000) == 0) print("unknown interrupt %d pc=0x%lux: total %d\n", v, ur->pc, badintr[v]); } else { @@ -284,21 +289,24 @@ trap(Ureg *ur) } while(h); /* check user since syscall does its own notifying */ - if(user && (u->p->procctl || u->nnote)) + splhi(); + if(user && (up->procctl || up->nnote)) notify(ur); +lasttrap = *ur; +lastur = ur; } /* * dump registers */ void -dumpregs(Ureg *ur) +dumpregs2(Ureg *ur) { - if(u) - print("registers for %s %d\n", u->p->text, u->p->pid); + if(up) + print("registers for %s %d\n", up->text, up->pid); else print("registers for kernel\n"); - print("FLAGS=%lux ECODE=%lux CS=%lux PC=%lux", ur->flags, + print("FLAGS=%lux TRAP=%lux ECODE=%lux CS=%lux PC=%lux", ur->flags, ur->trap, ur->ecode, ur->cs&0xff, ur->pc); if(ur == (Ureg*)UREGADDR) print(" SS=%lux USP=%lux\n", ur->ss&0xff, ur->usp); @@ -310,6 +318,16 @@ dumpregs(Ureg *ur) ur->si, ur->di, ur->bp); print(" DS %4.4ux ES %4.4ux FS %4.4ux GS %4.4ux\n", ur->ds&0xffff, ur->es&0xffff, ur->fs&0xffff, ur->gs&0xffff); + +} + +void +dumpregs(Ureg *ur) +{ + dumpregs2(ur); + print(" ur %lux\n", ur); + dumpregs2(&lasttrap); + print(" lastur %lux\n", lastur); } void @@ -318,11 +336,11 @@ dumpstack(void) ulong l, v, i; extern ulong etext; - if(u == 0) + if(up == 0) return; i = 0; - for(l=(ulong)&l; lkstack+BY2PG; l+=4){ v = *(ulong*)l; if(KTZERO < v && v < (ulong)&etext){ print("%lux ", v); @@ -369,52 +387,52 @@ syscall(Ureg *ur) long ret; int i; - u->p->insyscall = 1; - u->p->pc = ur->pc; + up->insyscall = 1; + up->pc = ur->pc; if((ur->cs)&0xffff == KESEL) panic("recursive system call"); - u->scallnr = ur->ax; - if(u->scallnr == RFORK && u->p->fpstate == FPactive){ + up->scallnr = ur->ax; + if(up->scallnr == RFORK && up->fpstate == FPactive){ /* * so that the child starts out with the * same registers as the parent */ splhi(); - if(u->p->fpstate == FPactive){ - fpsave(&u->fpsave); - u->p->fpstate = FPinactive; + if(up->fpstate == FPactive){ + fpsave(&up->fpsave); + up->fpstate = FPinactive; } spllo(); } sp = ur->usp; - u->nerrlab = 0; + up->nerrlab = 0; ret = -1; if(!waserror()){ - if(u->scallnr >= sizeof systab/BY2WD){ - pprint("bad sys call number %d pc %lux\n", u->scallnr, ur->pc); - postnote(u->p, 1, "sys: bad sys call", NDebug); + if(up->scallnr >= sizeof systab/BY2WD){ + pprint("bad sys call number %d pc %lux\n", up->scallnr, ur->pc); + postnote(up->p, 1, "sys: bad sys call", NDebug); error(Ebadarg); } if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-(1+MAXSYSARG)*BY2WD)) validaddr(sp, (1+MAXSYSARG)*BY2WD, 0); - u->s = *((Sargs*)(sp+1*BY2WD)); - u->p->psstate = sysctab[u->scallnr]; + up->s = *((Sargs*)(sp+1*BY2WD)); + up->psstate = sysctab[up->scallnr]; - ret = (*systab[u->scallnr])(u->s.args); + ret = (*systab[up->scallnr])(up->s.args); poperror(); } - if(u->nerrlab){ - print("bad errstack [%d]: %d extra\n", u->scallnr, u->nerrlab); + if(up->nerrlab){ + print("bad errstack [%d]: %d extra\n", up->scallnr, up->nerrlab); for(i = 0; i < NERR; i++) - print("sp=%lux pc=%lux\n", u->errlab[i].sp, u->errlab[i].pc); + print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc); panic("error stack"); } - u->p->insyscall = 0; - u->p->psstate = 0; + up->insyscall = 0; + up->psstate = 0; /* * Put return value in frame. On the safari the syscall is @@ -424,11 +442,11 @@ syscall(Ureg *ur) */ ur->ax = ret; - if(u->scallnr == NOTED) + if(up->scallnr == NOTED) noted(ur, *(ulong*)(sp+BY2WD)); splhi(); /* avoid interrupts during the iret */ - if(u->scallnr!=RFORK && (u->p->procctl || u->nnote)) + if(up->scallnr!=RFORK && (up->procctl || up->nnote)) notify(ur); return ret; @@ -445,61 +463,61 @@ notify(Ureg *ur) ulong s, sp; Note *n; - if(u->p->procctl) - procctl(u->p); - if(u->nnote == 0) + if(up->procctl) + procctl(up->p); + if(up->nnote == 0) return 0; s = spllo(); - qlock(&u->p->debug); - u->p->notepending = 0; - n = &u->note[0]; + qlock(&up->debug); + up->notepending = 0; + n = &up->note[0]; if(strncmp(n->msg, "sys:", 4) == 0){ l = strlen(n->msg); if(l > ERRLEN-15) /* " pc=0x12345678\0" */ l = ERRLEN-15; sprint(n->msg+l, " pc=0x%.8lux", ur->pc); } - if(n->flag!=NUser && (u->notified || u->notify==0)){ + if(n->flag!=NUser && (up->notified || up->notify==0)){ + qunlock(&up->debug); if(n->flag == NDebug) pprint("suicide: %s\n", n->msg); - qunlock(&u->p->debug); pexit(n->msg, n->flag!=NDebug); } sent = 0; - if(!u->notified){ - if(!u->notify){ - qunlock(&u->p->debug); + if(!up->notified){ + if(!up->notify){ + qunlock(&up->debug); pexit(n->msg, n->flag!=NDebug); } sent = 1; - u->svcs = ur->cs; - u->svss = ur->ss; - u->svflags = ur->flags; + up->svcs = ur->cs; + up->svss = ur->ss; + up->svflags = ur->flags; sp = ur->usp; sp -= sizeof(Ureg); - if(!okaddr((ulong)u->notify, 1, 0) + if(!okaddr((ulong)up->notify, 1, 0) || !okaddr(sp-ERRLEN-3*BY2WD, sizeof(Ureg)+ERRLEN-3*BY2WD, 0)){ + qunlock(&up->debug); pprint("suicide: bad address in notify\n"); - qunlock(&u->p->debug); pexit("Suicide", 0); } - u->ureg = (void*)sp; + up->ureg = (void*)sp; memmove((Ureg*)sp, ur, sizeof(Ureg)); sp -= ERRLEN; - memmove((char*)sp, u->note[0].msg, ERRLEN); + memmove((char*)sp, up->note[0].msg, ERRLEN); sp -= 3*BY2WD; *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ - *(ulong*)(sp+1*BY2WD) = (ulong)u->ureg; /* arg 1 is ureg* */ + *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg; /* arg 1 is ureg* */ *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ ur->usp = sp; - ur->pc = (ulong)u->notify; - u->notified = 1; - u->nnote--; - memmove(&u->lastnote, &u->note[0], sizeof(Note)); - memmove(&u->note[0], &u->note[1], u->nnote*sizeof(Note)); + ur->pc = (ulong)up->notify; + up->notified = 1; + up->nnote--; + memmove(&up->lastnote, &up->note[0], sizeof(Note)); + memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); } - qunlock(&u->p->debug); + qunlock(&up->debug); splx(s); return sent; } @@ -512,43 +530,43 @@ noted(Ureg *ur, ulong arg0) { Ureg *nur; - nur = u->ureg; /* pointer to user returned Ureg struct */ - if(nur->cs!=u->svcs || nur->ss!=u->svss - || (nur->flags&0xff00)!=(u->svflags&0xff00)){ + nur = up->ureg; /* pointer to user returned Ureg struct */ + if(nur->cs!=up->svcs || nur->ss!=up->svss + || (nur->flags&0xff00)!=(up->svflags&0xff00)){ pprint("bad noted ureg cs %ux ss %ux flags %ux\n", nur->cs, nur->ss, nur->flags); Die: pexit("Suicide", 0); } - qlock(&u->p->debug); - if(!u->notified){ + qlock(&up->debug); + if(!up->notified){ pprint("call to noted() when not notified\n"); - qunlock(&u->p->debug); + qunlock(&up->debug); return; } - u->notified = 0; - nur->flags = (u->svflags&0xffffff00) | (nur->flags&0xff); + up->notified = 0; + nur->flags = (up->svflags&0xffffff00) | (nur->flags&0xff); memmove(ur, nur, sizeof(Ureg)); switch(arg0){ case NCONT: if(!okaddr(nur->pc, 1, 0) || !okaddr(nur->usp, BY2WD, 0)){ pprint("suicide: trap in noted\n"); - qunlock(&u->p->debug); + qunlock(&up->debug); goto Die; } - qunlock(&u->p->debug); + qunlock(&up->debug); return; default: pprint("unknown noted arg 0x%lux\n", arg0); - u->lastnote.flag = NDebug; + up->lastnote.flag = NDebug; /* fall through */ case NDFLT: - if(u->lastnote.flag == NDebug) - pprint("suicide: %s\n", u->lastnote.msg); - qunlock(&u->p->debug); - pexit(u->lastnote.msg, u->lastnote.flag!=NDebug); + if(up->lastnote.flag == NDebug) + pprint("suicide: %s\n", up->lastnote.msg); + qunlock(&up->debug); + pexit(up->lastnote.msg, up->lastnote.flag!=NDebug); } } diff --git a/pc/ultrastor.c b/pc/ultrastor.c new file mode 100644 index 0000000000000000000000000000000000000000..b1812378a0ae7e12a50bc517f1d913f305e4645d --- /dev/null +++ b/pc/ultrastor.c @@ -0,0 +1,484 @@ +/* + * Ultrastor [13]4f SCSI Host Adapter. + * Originally written by Charles Forsyth, forsyth@minster.york.ac.uk. + * Needs work: + * handle multiple controllers; + * set options from user-level; + * split out to handle adaptec too; + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#include "ureg.h" + +typedef struct Ctlr Ctlr; +typedef struct Mailbox Mailbox; +typedef struct Scatter Scatter; + +enum { + Nctl = 1, /* only support one */ + Nmbox = 8, /* number of Mailboxes; up to 16? */ + Nscatter = 33, /* s/g list limit fixed by Ultrastor controller */ + + Port = 0x330, /* factory defaults: I/O port */ + CtlrID = 7, /* adapter SCSI id */ + Irq = 14, /* interrupt request level */ +}; + +struct Scatter { + ulong start; /* physical address; Intel byte order */ + ulong len; /* length in bytes; Intel byte order */ +}; + +/* + * Ultrastor mailbox pointers point to one of these structures + */ +struct Mailbox { + uchar op; /* Adapter operation */ + uchar addr; /* lun, chan, scsi ID */ + uchar datap[4]; /* transfer data phys. pointer */ + uchar datalen[4]; /* transfer data length */ + uchar cmdlink[4]; /* command link phys. pointer */ + uchar linkid; /* SCSI command link ID */ + uchar nscatter; /* scatter/gather length (8 bytes per entry) */ + uchar senselen; /* length of sense data */ + uchar cmdlen; /* length of CDB */ + uchar cmd[12]; /* SCSI command */ + uchar adapterstatus; + uchar targetstatus; + uchar sensep[4]; /* sense data phys. pointer */ + + /* the remainder is used by software, not the device */ + uchar sensedata[64]; /* enough for AdapterInquiry data too */ + Scatter sglist[Nscatter]; + Rendez iodone; + int busy; /* interrupt pending */ + ulong physaddr; /* physical address of this Mailbox */ + int p9status; /* p9 status value */ + Mailbox *next; /* next Mailbox in free list */ +}; + +/* pack pointer as Intel order bytes (can simply assign) */ +#define PL(buf,p) (*(ulong*)(buf)=(ulong)(p)) + +enum { + /* bits in Mailbox.op[0] */ + /* 3 bit opcode */ + OpAdapter = 0x01, /* adapter command, not SCSI command */ + OpTarget = 0x02, /* SCSI command for device */ + OpReset = 0x04, /* device reset */ + /* 2 bit transfer direction */ + CmdDirection = 0<<3, /* transfer direction determined by SCSI command */ + DataIn = 1<<3, /* SCSI Data In */ + DataOut = 2<<3, /* SCSI Data Out */ + NoTransfer = 3<<3, + Nodiscon= 1<<5, /* disable disconnect */ + Usecache= 1<<6, /* use adapter cache (if available) */ + Scattered= 1<<7, /* transfer pointer refers to S/G list */ + + /* OpAdapter commands in Mailbox.cmd[0] */ + AdapterInquiry = 0x01, + AdapterSelftest = 0x02, + AdapterRead = 0x03, /* read adapter's buffer */ + AdapterWrite = 0x04, /* write to adapter's buffer */ + + /* IO port offsets and bits */ + AdapterMask = 0x00, /* local doorbell mask register */ + OGMIntEnable = 0x01, + SoftResetEnable = 0x40, + AdapterReady = 0xe1, /* adapter ready for work when all these set */ + AdapterIntr = 0x01, /* adapter interrupt/status; set by host, reset by adapter */ + SignalAdapter = 0x01, /* tell adapter to read OGMpointer */ + BusReset = 0x20, /* SCSI Bus Reset */ + SoftReset = 0x40, /* Adapter Soft Reset */ + HostMask = 0x02, /* host doorbell mask register */ + ICMIntEnable = 0x01, /* incoming mail enable */ + SIntEnable = 0x80, /* enable interrupt from HostIntr reg */ + HostIntr = 0x03, /* host doorbell interrupt/status; set by adapter, reset by host */ + IntPending = 0x80, /* interrupt pending for host */ + SignalHost = 0x01, /* Incoming Mail Interrupt */ + ProductID = 0x04, /* two byte product ID */ + Config1 = 0x06, + Config2 = 0x07, + OGMpointer = 0x08, /* pointer to Outgoing Mail */ + ICMpointer = 0x0c, /* pointer to Incoming Mail */ +}; + +#define OUT(c,v) outb(ctlr->io+(c), (v)) +#define IN(c) inb(ctlr->io+(c)) + +struct Ctlr { + Lock; + QLock; + int io; /* io port */ + int irq; /* interrupt vector */ + int dma; /* DMA channel */ + int ownid; /* adapter's SCSI ID */ + Mailbox mbox[Nmbox]; + Mailbox *free; /* next free Mailbox */ + Rendez mboxes; /* wait for free mbox */ + QLock mboxq; /* mutex for mboxes */ + Rendez ogm; /* wait for free OGM slot with Ctlr qlocked */ +}; + +static Ctlr ultra[Nctl]; + +int scsidebugs[8] = {0}; +int scsiownid = 7; + +static void +prmbox(Mailbox *m) +{ + int i; + + print("scsi %lx: op=%2.2x dir=%x cmd=%d [", m->physaddr, m->op&07, (m->op>>3)&3, m->cmdlen); + for(i=0; icmdlen; i++) + print(" %2.2x", m->cmd[i]); + print("] id=%d lun=%d chan=%d", m->addr&7, (m->addr>>5)&7, (m->addr>>3)&3); + print(" dlen=%lx dptr=%lx\n", *(long*)m->datalen, *(long*)m->datap); + print(" astat=%2.2x dstat=%2.2x sc=%d [", m->adapterstatus, m->targetstatus, m->nscatter); + for(i=0; inscatter; i++) + print(" %lx,%ld", m->sglist[i].start, m->sglist[i].len); + print("]\n"); + /*for(i=0; i<10; i++) + print(" %2.2x", m->sensedata[i]);*/ + print("\n"); +} + +static void +resetadapter(int busreset) +{ + Ctlr *ctlr = &ultra[0]; + int i; + + if(IN(AdapterMask) & SoftResetEnable){ + OUT(AdapterIntr, SoftReset|busreset); + for(i=50000; IN(AdapterIntr) & (SoftReset|busreset);) + if(--i<0) { + print("Ultrastor reset timed out\n"); + break; + } + } +} + +static void +freebox(Ctlr *ctlr, Mailbox *m) +{ + lock(ctlr); + if((m->next = ctlr->free) == 0) + wakeup(&ctlr->mboxes); + ctlr->free = m; + unlock(ctlr); +} + +static int +boxavail(void *a) +{ + return ((Ctlr*)a)->free != 0; +} + +static int +scatter(Scatter *list, void *va, ulong nb) +{ + char *p = (char *)va; + Scatter *sp = list; + int limit = Nscatter; + + for(; nb != 0; sp++){ + if(--limit < 0) + panic("Ultrastor I/O too scattered"); + sp->start = PADDR(p); + sp->len = BY2PG - (sp->start&(BY2PG-1)); /* the rest of that page */ + if(sp->len > nb) + sp->len = nb; + nb -= sp->len; + p += sp->len; + } + return sp - list; +} + +static int +isready(void *a) +{ + Ctlr *ctlr = (Ctlr*)a; + + return (IN(AdapterIntr) & SignalAdapter) == 0; +} + +static int +isdone(void *a) +{ + return ((Mailbox*)a)->busy == 0; +} + +static int +ultra14fexec(Scsi *p, int rflag) +{ + Ctlr *ctlr = &ultra[0]; + Mailbox *m; + long n; + uchar *cp; + + if (p == 0 || ctlr->io == 0) + return 0x0200; /* device not available */ + + /* + * get a free Mailbox and build an Ultrastor command + */ + while(lock(ctlr), (m = ctlr->free) == 0){ + unlock(ctlr); + qlock(&ctlr->mboxq); + if(waserror()){ + qunlock(&ctlr->mboxq); + nexterror(); + } + sleep(&ctlr->mboxes, boxavail, ctlr); + poperror(); + qunlock(&ctlr->mboxq); + } + ctlr->free = m->next; + unlock(ctlr); + p->rflag = rflag; + m->p9status = 0; + m->op = OpTarget | CmdDirection | Usecache; /* BUG? is it safe always to Usecache? */ + m->addr = p->target | (p->lun<<5); + if(p->cmd.lim - p->cmd.ptr > sizeof(m->cmd)) + panic("scsiexec"); + m->cmdlen = p->cmd.lim - p->cmd.ptr; + for(cp = m->cmd; p->cmd.ptr < p->cmd.lim;) + *cp++ = *p->cmd.ptr++; + n = p->data.lim - p->data.ptr; + if(n){ + PL(m->datap, PADDR(m->sglist)); + m->op |= Scattered; + m->nscatter = scatter(m->sglist, p->data.ptr, n); + } else { + m->nscatter = 0; /* controller will not allow s/g when n==0 */ + PL(m->datap, 0); + } + PL(m->datalen, n); + m->adapterstatus = 0; + m->targetstatus = 0; + + /* + * send the command to the host adapter + */ + while(lock(ctlr), IN(AdapterIntr) & SignalAdapter) { /* adapter busy: infrequent? */ + static int fred; + if(fred == 0){ + print("ultrastor busy\n"); + fred = 1; + } + unlock(ctlr); + qlock(ctlr); + if(waserror()) { + freebox(ctlr, m); + qunlock(ctlr); + nexterror(); + } + sleep(&ctlr->ogm, isready, ctlr); + poperror(); + qunlock(ctlr); + } + m->busy = 1; + outl(ctlr->io+OGMpointer, m->physaddr); + OUT(AdapterIntr, SignalAdapter); + unlock(ctlr); + + /* + * wait for reply + */ + while(waserror()) + ; /* could send MSCP abort request to adapter */ + while(m->busy) + sleep(&m->iodone, isdone, m); + poperror(); + p->status = m->p9status; + if(scsidebugs[2]) + prmbox(m); + if(p->status == 0x6000) + p->data.ptr = p->data.lim; /* can only assume no residue */ + freebox(ctlr, m); + return p->status; +} + +static void +scsimoan(char *msg, Mailbox *m) +{ + /*int i;*/ + + print("SCSI error: %s:", msg); + print("id=%d cmd=%2.2x status=%2.2x adapter=%2.2x", m->addr&7, m->cmd[0], m->targetstatus, m->adapterstatus); + /*print(" sense:"); + for(i=0; i<10; i++) + print(" %2.2x", m->sensedata[i]);*/ + print("\n"); +} + +static void +interrupt(Ureg *ur) +{ + Ctlr *ctlr = &ultra[0]; + Mailbox *m; + ulong pa; + + USED(ur); + if(ctlr->ogm.p && (IN(AdapterIntr) & SignalAdapter) == 0) + wakeup(&ctlr->ogm); + if((IN(HostIntr) & SignalHost) == 0) + return; /* no incoming mail */ + pa = inl(ctlr->io+ICMpointer); + OUT(HostIntr, SignalHost); /* release ICM slot */ + for(m = &ctlr->mbox[0]; m->physaddr != pa;) + if(++m >= &ctlr->mbox[Nmbox]) { + /* these sometimes happen in response to a scsi bus reset; ignore them */ + print("ultrastor: invalid ICM pointer #%lux\n", pa); + return; + } + if(scsidebugs[1]) + prmbox(m); + + m->p9status = 0x1000 | m->adapterstatus; + switch(m->adapterstatus){ + default: + scsimoan("adapter", m); + if(m->adapterstatus >= 0x92) /* ie, scsi command protocol error */ + resetadapter(BusReset); + /* might adapter reset be required in other cases? */ + break; + + case 0x91: /* selection timed out */ + m->p9status = 0x0200; + if(scsidebugs[0]) + scsimoan("timeout", m); + break; + + case 0xA3: + scsimoan("SCSI bus reset error", m); + break; + + case 0x00: + m->p9status = 0x6000 | m->targetstatus; + if(m->targetstatus && scsidebugs[0]) + scsimoan("device", m); + break; + } + m->busy = 0; + wakeup(&m->iodone); +} + +static ISAConf ultra14f = { + "ultra14f", + Port, + Irq, + 0, + 0, +}; + +static int irq[4] = { + 15, 14, 11, 10, +}; + +int (* +ultra14freset(void))(Scsi*, int) +{ + ISAConf *isa = &ultra14f; + Ctlr *ctlr = &ultra[0]; + Mailbox *m; + int i, model; + + /* + * See if we have any configuration info + * and check it is an Ultrastor [13]4f. + * Only one controller for now. + */ + if(isaconfig("scsi", 0, &ultra14f) == 0) + return 0; + memset(ctlr, 0, sizeof(Ctlr)); + ctlr->io = isa->port; + + if(IN(ProductID) != 0x56) + return 0; + model = IN(ProductID+1); + switch(model){ + + case 0x40: + model = 14; + break; + + case 0x41: + model = 34; + break; + + default: + return 0; + } + + i = IN(Config1); + ctlr->irq = irq[((i>>4)&03)]; + if(model == 14) + ctlr->dma = 5 + ((i>>6)&03); + ctlr->ownid = IN(Config2)&07; + /*print("Ultrastor %dF id %d io 0x%x irq %d dma %d\n", + model, ctlr->ownid, ctlr->io, ctlr->irq, ctlr->dma);*/ + + /* + * set the DMA controller to cascade mode for bus master + */ + switch(ctlr->dma){ + case 5: + outb(0xd6, 0xc1); outb(0xd4, 1); break; + case 6: + outb(0xd6, 0xc2); outb(0xd4, 2); break; + case 7: + outb(0xd6, 0xc3); outb(0xd4, 3); break; + } + + resetadapter(0); + ctlr->free = 0; + for(i=0; imbox[i]; + memset(m, 0, sizeof(*m)); + m->physaddr = PADDR(m); + PL(m->sensep, 0); /* DON'T collect sense data automatically: messes up scuzz? */ + m->senselen = 0; + m->next = ctlr->free; + ctlr->free = m; + } + + setvec(Int0vec+ctlr->irq, interrupt); + + /* + * issue AdapterInquiry command to check it's alive + * -- could check enquiry data + */ + OUT(HostMask, 0); /* mask interrupts */ + m = &ctlr->mbox[0]; + m->op = OpAdapter | CmdDirection; + m->addr = ctlr->ownid; + m->cmdlen = 1; + m->cmd[0] = AdapterInquiry; + PL(m->datap, PADDR(m->sensedata)); + PL(m->datalen, 38); + while(IN(AdapterIntr) & SignalAdapter) + ; + outl(ctlr->io+OGMpointer, m->physaddr); + OUT(AdapterIntr, SignalAdapter); + for(i=100000; (IN(HostIntr)&SignalHost)==0;) + if(--i < 0){ + print("No response to UltraStor Inquiry\n"); + ctlr->io = 0; + return 0; + } + OUT(HostIntr, SignalHost); + + OUT(HostMask, ICMIntEnable|SIntEnable); + scsiownid = ctlr->ownid; + + return ultra14fexec; +} diff --git a/port/portdat.h b/port/portdat.h index c3fe10c49ec52a54b572b4494b62db3ca33792af..b77042a0858dad697de0c694636b5e1a57114036 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -488,7 +488,7 @@ enum */ enum { - SSEG, TSEG, DSEG, BSEG, ESEG, LSEG, SEG1, SEG2, NSEG + SSEG, TSEG, DSEG, BSEG, ESEG, LSEG, SEG1, SEG2, SEG3, SEG4, NSEG }; enum diff --git a/port/portfns.h b/port/portfns.h index 4c542623c99f42083931ef573b417d1f7cabea9b..aa8828ca40ff2acef759f43443316dcdb06e61e0 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -113,6 +113,7 @@ void kproftimer(ulong); void ksetenv(char*, char*); long latin1(uchar*); void lights(int); +void links(void); void lock(Lock*); void lockinit(void); Page* lookpage(Image*, ulong); @@ -199,7 +200,6 @@ void resetscsi(void); void resrcwait(char*); int return0(void*); void rlock(RWlock*); -void rootfiles(void); void rootrecover(Path*, char*); void rootreq(Chan*, Mnt*); void runlock(RWlock*); diff --git a/power/main.c b/power/main.c index 99a973c17525cc77e62d359d7205ea1676fb611a..2118870135398f980b82a1064ca1f66660faec02 100644 --- a/power/main.c +++ b/power/main.c @@ -38,8 +38,8 @@ main(void) initseg(); clockinit(); ioboardinit(); + links(); chandevreset(); - rootfiles(); swapinit(); userinit(); launchinit();