D pc/adaptec.c => pc/adaptec.c +0 -505
@@ 1,505 0,0 @@
-/*
- * 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"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-#include "ureg.h"
-
-enum {
- NCtlr = 1,
- NTarget = 8, /* targets per controller */
-
- Port = 0x330, /* factory defaults: I/O port */
- CtlrID = 7, /* adapter SCSI id */
- Irq = 11, /* interrupt request level */
-};
-
-enum { /* registers */
- Rc = 0, /* WO: control */
- Rs = 0, /* RO: status */
- Rcdo = 1, /* WO: command/data out */
- Rdi = 1, /* RO: data in */
- Rif = 2, /* RO: interrupt flags */
-};
-
-enum { /* Rc */
- Scrst = 0x10, /* SCSI bus reset */
- Irst = 0x20, /* interrupt reset */
- Srst = 0x40, /* soft reset */
- Hrst = 0x80, /* hard reset */
-};
-
-enum { /* Rs */
- Invdcmd = 0x01, /* invalid host adapter command */
- Df = 0x04, /* data in port full */
- Cdf = 0x08, /* command/data port full */
- Idle = 0x10, /* SCSI host adapter idle */
- Init = 0x20, /* mailbox initialisation required */
- Diagf = 0x40, /* internal diagnostic failure */
- Stst = 0x80, /* self testing in progress */
-};
-
-enum { /* Rcdo */
- Cnop = 0x00, /* no operation */
- Cmbinit = 0x01, /* mailbox initialisation */
- Cstart = 0x02, /* start SCSI command */
- Cbios = 0x03, /* start PC/AT BIOS command */
- Cinquiry = 0x04, /* adapter inquiry */
- Cmboie = 0x05, /* enable mailbox out available interrupt */
- Cselection = 0x06, /* set selection timeout */
- Cbuson = 0x07, /* set bus-on time */
- Cbusoff = 0x08, /* set bus-off time */
- Ctransfer = 0x09, /* set transfer speed */
- Cdevices = 0x0A, /* return installed devices */
- Cconfiguration = 0x0B, /* return configuration data */
- Ctenable = 0x0C, /* enable target mode */
- Csetup = 0x0D, /* return setup data */
- Cwbuff = 0x1A, /* write adapter channel 2 buffer */
- Crbuff = 0x1B, /* read adapter channel 2 buffer */
- Cwfifo = 0x1C, /* write adapter FIFO buffer */
- Crfifo = 0x1D, /* read adapter FIFO buffer */
- Cecho = 0x1F, /* ECHO command data */
- Cdiag = 0x20, /* adapter diagnostic */
- Coptions = 0x21, /* set host adapter options */
-};
-
-enum { /* Rif */
- Mbif = 0x01, /* mailbox in full */
- Mboa = 0x02, /* mailbox out available */
- Hacc = 0x04, /* host adapter command complete */
- Scrd = 0x08, /* SCSI reset detected */
- Ai = 0x80, /* any interrupt */
-};
-
-typedef struct {
- uchar cmd; /* command */
- uchar msb; /* CCB pointer MSB */
- uchar mid; /* CCB pointer MID */
- uchar lsb; /* CCB pointer LSB */
-} Mbox;
-
-enum { /* mailbox commands */
- Mbfree = 0x00, /* mailbox is free */
-
- Mbostart = 0x01, /* start SCSI or adapter command */
- Mboabort = 0x02, /* abort SCSI or adapter command */
-
- Mbiok = 0x01, /* CCB completed without error */
- Mbiabort = 0x02, /* CCB aborted by host */
- Mbinx = 0x03, /* aborted CCB not found */
- Mbierror = 0x04, /* CCB completed with error */
-};
-
-typedef struct {
- uchar op; /* command control block operation code */
- uchar ctl; /* address and direction control */
- uchar cmdlen; /* SCSI command length */
- uchar reqlen; /* request sense allocation length */
- uchar datalen[3]; /* data length (MSB, MID, LSB) */
- uchar dataptr[3]; /* data pointer (MSB, MID, LSB) */
- uchar linkptr[3]; /* link pointer (MSB, MID, LSB) */
- uchar linkid; /* command linking identifier */
- uchar hastat; /* host adapter status */
- uchar tarstat; /* target device status */
- uchar reserved[2];
- uchar cs[12+0xFF]; /* SCSI command and sense bytes */
-} Ccb;
-
-enum { /* op */
- OInitiator = 0x00, /* initiator CCB */
- OTarget = 0x01, /* target CCB */
- Osg = 0x02, /* initiator CCB with scatter/gather */
- Ordl = 0x03, /* initiator CCB, residual data length returned */
- Osgrdl = 0x04, /* initiator CCB, both of the above */
- Obdr = 0x81, /* bus device reset */
-};
-
-enum { /* ctl */
- CCBdatain = 0x08, /* inbound data transfer, length is checked */
- CCBdataout = 0x10, /* outbound data transfer, length is checked */
-};
-
-enum { /* hastat */
- Eok = 0x00, /* no host adapter detected error */
- Etimeout = 0x11, /* selection timeout */
- Elength = 0x12, /* data over/under run */
- Ebusfree = 0x13, /* unexpected bus free */
- Ephase = 0x14, /* target bus phase sequence error */
- Eopcode = 0x16, /* invalid CCB opcode */
- Elink = 0x17, /* linked CCB does not have same LUN */
- Edirection = 0x18, /* invalid target direction received from host */
- Eduplicate = 0x19, /* duplicate CCB received in target mode */
- Esegment = 0x1A, /* invalid CCB or segment list parameter */
-};
-
-enum { /* tarstat */
- Sgood = 0x00, /* good status */
- Scheck = 0x02, /* check status */
- Sbusy = 0x08, /* LUN busy */
-};
-
-typedef struct Target Target;
-typedef struct Ctlr Ctlr;
-
-struct Target {
- QLock;
- Rendez;
-
- Ccb ccb;
- ulong paddr; /* physical address of ccb */
- uchar *sense; /* address of returned sense data */
-
- int done;
- Target *active; /* link on active list */
-};
-
-struct Ctlr {
- Lock;
-
- ulong port; /* I/O port */
- ulong id; /* adapter SCSI id */
-
- uchar cmd[5]; /* adapter command out */
- uchar cmdlen; /* adapter command out length */
- uchar data[256]; /* adapter command data in */
- uchar datalen; /* adapter command data in length */
-
- Mbox mb[NTarget+NTarget]; /* mailbox out + mailbox in */
-
- Mbox *mbox; /* current mailbox out index into mb */
- Mbox *mbix; /* current mailbox in index into mb */
-
- Target target[NTarget];
- Target *active; /* link on active list */
-};
-
-static Ctlr softctlr[NCtlr];
-
-/*
- * Issue a command to the controller. The command and its length is
- * contained in ctlr->cmd and ctlr->cmdlen. If any data is to be
- * returned, ctlr->datalen should be non-0, and the returned data will
- * be placed in ctlr->data.
- * If we see Hacc set, bail out, we'll process
- * the invalid command at interrupt time.
- */
-static void
-issue(Ctlr *ctlr)
-{
- int len;
-
- len = 0;
- while(len < ctlr->cmdlen){
- if((inb(ctlr->port+Rs) & Cdf) == 0){
- outb(ctlr->port+Rcdo, ctlr->cmd[len]);
- len++;
- }
-
- if(inb(ctlr->port+Rif) & Hacc)
- return;
- }
-
- if(ctlr->datalen){
- len = 0;
- while(len < ctlr->datalen){
- if(inb(ctlr->port+Rs) & Df){
- ctlr->data[len] = inb(ctlr->port+Rdi);
- len++;
- }
-
- if(inb(ctlr->port+Rif) & Hacc)
- return;
- }
- }
-}
-
-static int
-done(void *arg)
-{
- return ((Target*)arg)->done;
-}
-
-static int
-scsiio(int bus, Scsi *p, int rw)
-{
- Ctlr *ctlr;
- Target *tp;
- ushort status;
- ulong len, s;
-
- /*
- * Wait for the target to become free,
- * then set it up. The Adaptec will allow us to
- * queue multiple transactions per target, but
- * gives no guarantee about ordering, so we just
- * allow one per target.
- */
- ctlr = &softctlr[bus];
- tp = &ctlr->target[p->target];
-
- qlock(tp);
- if(waserror()){
- qunlock(tp);
- nexterror();
- }
-
- /*
- * If this is a request-sense and we have valid sense data
- * from the last command, return it immediately.
- * A pox on these weird enum names and the WD33C93A status
- * codes.
- */
- if(p->cmd.base[0] == ScsiExtsens && tp->sense){
- len = 8+tp->sense[7];
- memmove(p->data.ptr, tp->sense, len);
- p->data.ptr += len;
- tp->sense = 0;
-
- qunlock(tp);
- poperror();
- return 0x6000;
- }
- tp->sense = 0;
-
- /*
- * Fill in the ccb.
- */
- tp->ccb.op = Ordl;
- tp->ccb.ctl = (p->target<<5)|p->lun;
-
- len = p->cmd.lim - p->cmd.base;
- tp->ccb.cmdlen = len;
- memmove(tp->ccb.cs, p->cmd.base, len);
-
- tp->ccb.reqlen = 0xFF;
-
- len = p->data.lim - p->data.base;
- tp->ccb.datalen[0] = (len>>16) & 0xFF;
- tp->ccb.datalen[1] = (len>>8) & 0xFF;
- tp->ccb.datalen[2] = len;
- if(len == 0)
- tp->ccb.ctl |= CCBdataout|CCBdatain;
- else if(rw == ScsiIn)
- tp->ccb.ctl |= CCBdatain;
- else
- tp->ccb.ctl |= CCBdataout;
-
- len = PADDR(p->data.base);
- tp->ccb.dataptr[0] = (len>>16) & 0xFF;
- tp->ccb.dataptr[1] = (len>>8) & 0xFF;
- tp->ccb.dataptr[2] = len;
-
- tp->ccb.linkptr[0] = tp->ccb.linkptr[1] = tp->ccb.linkptr[2] = 0;
- tp->ccb.linkid = 0;
-
- tp->ccb.hastat = tp->ccb.tarstat = 0;
- tp->ccb.reserved[0] = tp->ccb.reserved[1] = 0;
-
- /*
- * Link the target onto the beginning of the
- * ctlr active list and start the request.
- * The interrupt routine has to be able to take
- * requests off the queue in any order.
- */
- s = splhi();
- if(active.machs > 1)
- lock(ctlr);
-
- tp->done = 0;
- tp->active = ctlr->active;
- ctlr->active = tp;
-
- ctlr->mbox->msb = (tp->paddr>>16) & 0xFF;
- ctlr->mbox->mid = (tp->paddr>>8) & 0xFF;
- ctlr->mbox->lsb = tp->paddr & 0xFF;
- ctlr->mbox->cmd = Mbostart;
-
- ctlr->cmd[0] = Cstart;
- ctlr->cmdlen = 1;
- ctlr->datalen = 0;
- issue(ctlr);
-
- ctlr->mbox++;
- if(ctlr->mbox >= &ctlr->mb[NTarget])
- ctlr->mbox = ctlr->mb;
-
- if(active.machs > 1)
- unlock(ctlr);
- splx(s);
-
- /*
- * Wait for the request to complete
- * and return the status.
- */
- tsleep(tp, done, tp, 60*5*1000);
- if(done(tp) == 0)
- print("adaptec%d: timeout cmd=#%2.2ux\n", p->target, tp->ccb.cs[0]);
-
- if((status = (tp->ccb.hastat<<8)) == 0)
- status = 0x6000;
- status |= tp->ccb.tarstat;
- len = (tp->ccb.datalen[0]<<16)|(tp->ccb.datalen[1]<<8)|tp->ccb.datalen[2];
- p->data.ptr = p->data.lim - len;
-
- /*
- * If the command returned sense data, keep a note
- * of where it is for a subsequent request-sense command.
- */
- if(tp->ccb.tarstat == Scheck && tp->ccb.hastat == Eok)
- tp->sense = &tp->ccb.cs[tp->ccb.cmdlen];
-
- qunlock(tp);
- poperror();
-
- return status;
-}
-
-static int
-aha1542exec(Scsi *p, int rw)
-{
- Ctlr *ctlr = &softctlr[0];
-
- if(ctlr->port == 0)
- error(Enodev);
- if(p->target == CtlrID)
- return 0x6002;
-
- return p->status = scsiio(0, p, rw);
-}
-
-static void
-interrupt(Ureg *ur)
-{
- Ctlr *ctlr = &softctlr[0];
- uchar rif, rs;
- Target *tp, **l;
- ulong paddr;
-
- USED(ur);
-
- if(active.machs > 1)
- lock(ctlr);
-
- /*
- * Save and clear the interrupt(s). The only
- * interrupts expected are Hacc, which we ignore,
- * and Mbif which means something completed.
- */
- rif = inb(ctlr->port+Rif);
- rs = inb(ctlr->port+Rs);
- outb(ctlr->port+Rc, Irst);
- if(rif & ~(Ai|Hacc|Mbif))
- print("adaptec%d: interrupt #%2.2ux\n", 0, rif);
- if((rif & Hacc) && (rs & Invdcmd))
- print("adaptec%d: invdcmd #%2.2ux, len %d\n", 0, ctlr->cmd[0], ctlr->cmdlen);
-
- /*
- * Look for something in the mail.
- * If there is, try to find the recipient from the
- * ccb address, take it off the active list and
- * wakeup whoever.
- */
- while(ctlr->mbix->cmd){
- paddr = (ctlr->mbix->msb<<16)|(ctlr->mbix->mid<<8)|ctlr->mbix->lsb;
- l = &ctlr->active;
- for(tp = *l; tp; tp = tp->active){
- if(tp->paddr == paddr)
- break;
- l = &tp->active;
- }
- if(tp == 0)
- panic("adaptec%d: no target for ccb #%lux\n", 0, paddr);
- *l = tp->active;
-
- ctlr->mbix->cmd = 0;
-
- tp->done = 1;
- wakeup(tp);
-
- ctlr->mbix++;
- if(ctlr->mbix >= &ctlr->mb[NTarget+NTarget])
- ctlr->mbix = &ctlr->mb[NTarget];
- }
-
- if(active.machs > 1)
- unlock(ctlr);
-}
-
-static void
-reset(Ctlr *ctlr, ulong port, ulong id)
-{
- ulong paddr;
- int i;
-
- /*
- * Initialise the software controller and set the board
- * scanning the mailboxes.
- * Need code here to tidy things up if we're
- * resetting after being active.
- */
- memset(ctlr, 0, sizeof(Ctlr));
- ctlr->port = port;
- ctlr->id = id;
- for(i = 0; i < NTarget; i++){
- ctlr->target[i].paddr = PADDR(&ctlr->target[i].ccb);
- ctlr->mbox = ctlr->mb;
- ctlr->mbix = &ctlr->mb[NTarget];
- }
-
- ctlr->cmd[0] = Cmbinit;
- paddr = PADDR(ctlr->mb);
- ctlr->cmd[1] = NTarget;
- ctlr->cmd[2] = (paddr>>16) & 0xFF;
- ctlr->cmd[3] = (paddr>>8) & 0xFF;
- ctlr->cmd[4] = paddr & 0xFF;
- ctlr->cmdlen = 5;
- ctlr->datalen = 0;
- issue(ctlr);
-}
-
-static ISAConf aha1542 = {
- "aha1542",
- Port,
- Irq,
- 0,
- 0,
-};
-
-int (*
-aha1542reset(void))(Scsi*, int)
-{
- ISAConf *isa = &aha1542;
-
- /*
- * See if we have any configuration info.
- * Only one controller for now.
- */
- if(isaconfig("scsi", 0, &aha1542) == 0)
- return 0;
-
- /*
- * 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(isa->port+Rc, Hrst|Scrst);
- delay(500);
- if(inb(isa->port+Rs) != (Init|Idle))
- return 0;
-
- setvec(Int0vec+isa->irq, interrupt);
- reset(&softctlr[0], isa->port, CtlrID);
-
- return aha1542exec;
-}
M pc/bbmalloc.c => pc/bbmalloc.c +30 -32
@@ 5,24 5,31 @@
#include "fns.h"
#include "io.h"
+#define LINEWORDS (0)
+
/*
* Allocate memory for use in kernel bitblts.
+ * The allocated memory must have a flushed instruction
+ * cache, and the data cache must be flushed by bbdflush().
+ * To avoid the need for frequent cache flushes, the memory
+ * is allocated out of an arena, and the i-cache is only
+ * flushed when it has to be reused
*
* This code will have to be interlocked if we ever get
* a multiprocessor with a bitmapped display.
*/
-/* a 0->3 bitblt can take 800 longs */
+/* a 0->3 bitblt can take 900 words */
enum {
narena=2, /* put interrupt time stuff in separate arena */
nbbarena=4096 /* number of words in an arena */
};
-static ulong *bbarena[narena];
-static ulong *bbcur[narena];
-static ulong *bblast[narena];
+static ulong bbarena[narena][nbbarena+LINEWORDS];
+static ulong *bbcur[narena] = {&bbarena[0][0], &bbarena[1][0]};
+static ulong *bblast[narena] = {0, 0};
-#define INTENABLED(v) ((v)&(1<<9))
+#define INTLEVEL(v) (((v)&(1<<9)) == 0)
void *
bbmalloc(int nbytes)
{
@@ 32,52 39,43 @@ bbmalloc(int nbytes)
nw = nbytes/sizeof(long);
s = splhi();
- a = INTENABLED(s) ? 0 : 1;
- if(bbcur[a] + nw > bbarena[a] + nbbarena)
+ a = INTLEVEL(s)? 1 : 0;
+ if(bbcur[a] + nw > &bbarena[a][nbbarena])
ans = bbarena[a];
else
ans = bbcur[a];
- bbcur[a] = ans + nw;
- bblast[a] = ans;
+ bbcur[a] = ans + nw + (LINEWORDS);
splx(s);
- return ans;
-}
-
-void
-bbinit(void)
-{
- int i;
- if(bbarena[0])
- return;
- for(i = 0; i < narena; i++){
- bbarena[i] = xalloc(nbbarena * sizeof(long));
- bbcur[i] = bbarena[i];
- bblast[i] = 0;
- }
+ bblast[a] = ans;
+ return ans;
}
-
void
bbfree(void *p, int n)
{
int a, s;
s = splhi();
- a = INTENABLED(s) ? 0 : 1;
+ a = INTLEVEL(s)? 1 : 0;
if(p == bblast[a])
- bbcur[a] = (ulong *)(((char *)bblast[a]) + n);
+ bbcur[a] = (ulong *)(((char *)bblast[a]) + n + LINEWORDS*sizeof(long));
splx(s);
}
-void
-bbdflush(void *p, int n)
-{
- USED(p, n);
-}
-
int
bbonstack(void)
{
+ /*if(u)
+ return 1;*/
return 0;
}
+
+void
+bbexec(void (*memstart)(void), int len, int onstack)
+{
+ memstart();
+ if(onstack)
+ return;
+ bbfree(memstart, len);
+}
M pc/clock.c => pc/clock.c +0 -1
@@ 88,7 88,6 @@ clock(Ureg *ur)
m->ticks++;
checkalarms();
- uartclock();
mouseclock();
/*
M pc/devether.c => pc/devether.c +111 -481
@@ 3,46 3,42 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
-#include "../port/error.h"
#include "io.h"
-#include "devtab.h"
+#include "ureg.h"
+#include "../port/error.h"
+#include "../port/netif.h"
-#include "ether.h"
+#include "etherif.h"
-/*
- * Half-arsed attempt at a general top-level
- * ethernet driver. Needs work:
- * handle multiple controllers
- * much tidying
- * set ethernet address
- * need a ctl file passed down to card drivers
- * so we can set options.
- */
-extern Card ether8003, ether503, ether2000;
-extern Card ether509;
+static Ether *ether[MaxEther];
-/*
- * The ordering here is important for those cards
- * using the DP8390 (WD8003, 3Com503 and NE2000) as
- * attempting to determine if a card is a NE2000
- * cannot be done passively, so it must be last to
- * prevent scrogging one of the others.
- */
-static Card *cards[] = {
- ðer8003,
- ðer503,
- ðer2000,
+void
+etherinit(void)
+{
+}
- ðer509,
- 0
-};
+Chan*
+etherattach(char *spec)
+{
+ ulong ctlrno;
+ char *p;
+ Chan *c;
-enum {
- NCtlr = 1,
-};
+ ctlrno = 0;
+ if(spec && *spec){
+ ctlrno = strtoul(spec, &p, 0);
+ if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
+ error(Ebadarg);
+ }
+ if(ether[ctlrno] == 0)
+ error(Enodev);
-/*static */struct Ctlr *softctlr[NCtlr];
-static int nctlr;
+ c = devattach('l', spec);
+ c->dev = ctlrno;
+ if(ether[ctlrno]->attach)
+ (*ether[ctlrno]->attach)(ether[ctlrno]);
+ return c;
+}
Chan*
etherclone(Chan *c, Chan *nc)
@@ 53,530 49,164 @@ etherclone(Chan *c, Chan *nc)
int
etherwalk(Chan *c, char *name)
{
- return netwalk(c, name, &softctlr[0]->net);
+ return netifwalk(ether[c->dev], c, name);
}
void
etherstat(Chan *c, char *dp)
{
- netstat(c, dp, &softctlr[0]->net);
+ netifstat(ether[c->dev], c, dp);
}
Chan*
etheropen(Chan *c, int omode)
{
- return netopen(c, omode, &softctlr[0]->net);
+ return netifopen(ether[c->dev], c, omode);
}
void
ethercreate(Chan *c, char *name, int omode, ulong perm)
{
USED(c, name, omode, perm);
- error(Eperm);
}
void
etherclose(Chan *c)
{
- if(c->stream)
- streamclose(c);
+ netifclose(ether[c->dev], c);
}
long
-etherread(Chan *c, void *a, long n, ulong offset)
+etherread(Chan *c, void *buf, long n, ulong offset)
{
- return netread(c, a, n, offset, &softctlr[0]->net);
-}
-
-long
-etherwrite(Chan *c, char *a, long n, ulong offset)
-{
- USED(offset);
- return streamwrite(c, a, n, 0);
+ return netifread(ether[c->dev], c, buf, n, offset);
}
void
etherremove(Chan *c)
{
USED(c);
- error(Eperm);
}
void
etherwstat(Chan *c, char *dp)
{
- netwstat(c, dp, &softctlr[0]->net);
+ netifwstat(ether[c->dev], c, dp);
}
-static int
-isobuf(void *arg)
-{
- Ctlr *ctlr = arg;
-
- return ctlr->tb[ctlr->th].owner == Host;
-}
-
-static void
-etheroput(Queue *q, Block *bp)
+long
+etherwrite(Chan *c, void *buf, long n, ulong offset)
{
- Ctlr *ctlr;
- Type *type;
- Etherpkt *pkt;
- RingBuf *ring;
- int len, n, s;
- Block *nbp;
+ Ether *ctlr;
- type = q->ptr;
- ctlr = type->ctlr;
- if(bp->type == M_CTL){
- qlock(ctlr);
- if(streamparse("connect", bp)){
- if(type->type == -1)
- ctlr->all--;
- type->type = strtol((char*)bp->rptr, 0, 0);
- if(type->type == -1)
- ctlr->all++;
- }
- else if(streamparse("promiscuous", bp)) {
- type->prom = 1;
- ctlr->prom++;
- if(ctlr->prom == 1)
- (*ctlr->card.mode)(ctlr, 1);
- }
- qunlock(ctlr);
- freeb(bp);
- return;
- }
+ USED(offset);
+ if(n > ETHERMAXTU)
+ error(Ebadarg);
+ ctlr = ether[c->dev];
- /*
- * Give packet a local address, return upstream if destined for
- * this machine.
- */
- if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0)
- return;
- pkt = (Etherpkt*)bp->rptr;
- memmove(pkt->s, ctlr->ea, sizeof(ctlr->ea));
- if(memcmp(ctlr->ea, pkt->d, sizeof(ctlr->ea)) == 0){
- len = blen(bp);
- if(bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){
- putq(&ctlr->lbq, bp);
- wakeup(&ctlr->rr);
- }
- return;
- }
- if(memcmp(ctlr->ba, pkt->d, sizeof(ctlr->ba)) == 0 || ctlr->prom || ctlr->all){
- len = blen(bp);
- nbp = copyb(bp, len);
- if(nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU)){
- nbp->wptr = nbp->rptr+len;
- putq(&ctlr->lbq, nbp);
- wakeup(&ctlr->rr);
- }
- }
+ if(NETTYPE(c->qid.path) != Ndataqid)
+ return netifwrite(ctlr, c, buf, n);
- /*
- * Only one transmitter at a time.
- */
qlock(&ctlr->tlock);
if(waserror()){
qunlock(&ctlr->tlock);
- freeb(bp);
nexterror();
}
-
- /*
- * Wait till we get an output buffer.
- * should try to restart.
- */
- if(isobuf(ctlr) == 0){
- tsleep(&ctlr->tr, isobuf, ctlr, 3*1000);
- if(isobuf(ctlr) == 0){
- qunlock(&ctlr->tlock);
- freeb(bp);
- poperror();
- return;
- }
- }
-
- ring = &ctlr->tb[ctlr->th];
-
- /*
- * Copy message into buffer.
- */
- len = 0;
- for(nbp = bp; nbp; nbp = nbp->next){
- if(sizeof(Etherpkt) - len >= (n = BLEN(nbp))){
- memmove(ring->pkt+len, nbp->rptr, n);
- len += n;
- }
- if(bp->flags & S_DELIM)
- break;
- }
-
- /*
- * Pad the packet (zero the pad).
- */
- if(len < ETHERMINTU){
- memset(ring->pkt+len, 0, ETHERMINTU-len);
- len = ETHERMINTU;
- }
-
- /*
- * Set up the transmit buffer and
- * start the transmission.
- */
- s = splhi();
- ring->len = len;
- ring->owner = Interface;
- ctlr->th = NEXT(ctlr->th, ctlr->ntb);
- (*ctlr->card.transmit)(ctlr);
- splx(s);
-
- qunlock(&ctlr->tlock);
- freeb(bp);
+ n = (*ctlr->write)(ctlr, buf, n);
poperror();
-}
-
-/*
- * Open an ether line discipline.
- */
-static void
-etherstopen(Queue *q, Stream *s)
-{
- Ctlr *ctlr = softctlr[0];
- Type *type;
-
- type = &ctlr->type[s->id];
- RD(q)->ptr = WR(q)->ptr = type;
- type->type = 0;
- type->q = RD(q);
- type->inuse = 1;
- type->ctlr = ctlr;
-}
+ qunlock(&ctlr->tlock);
-/*
- * Close ether line discipline.
- *
- * The locking is to synchronize changing the ethertype with
- * sending packets up the stream on interrupts.
- */
-static int
-isclosed(void *arg)
-{
- return ((Type*)arg)->q == 0;
+ return n;
}
static void
-etherstclose(Queue *q)
+etherintr(Ureg *ur)
{
- Type *type = (Type*)(q->ptr);
- Ctlr *ctlr = type->ctlr;
-
- if(type->prom){
- qlock(ctlr);
- ctlr->prom--;
- if(ctlr->prom == 0)
- (*ctlr->card.mode)(ctlr, 0);
- qunlock(ctlr);
- }
- if(type->type == -1){
- qlock(ctlr);
- ctlr->all--;
- qunlock(ctlr);
- }
+ int i, irq;
/*
- * Mark as closing and wait for kproc
- * to close us.
+ * Call all ethernet interrupt routines on this IRQ.
+ * Might be better if setvec() took an argument which
+ * was passed down to the interrupt routine when
+ * called. This would let us easily distinguish multiple
+ * controllers. A hack by any other name...
*/
- lock(&ctlr->clock);
- type->clist = ctlr->clist;
- ctlr->clist = type;
- unlock(&ctlr->clock);
- wakeup(&ctlr->rr);
- sleep(&type->cr, isclosed, type);
-
- type->type = 0;
- type->prom = 0;
- type->inuse = 0;
- netdisown(type);
- type->ctlr = 0;
-}
-
-static Qinfo info = {
- nullput,
- etheroput,
- etherstopen,
- etherstclose,
- "ether"
-};
-
-static int
-clonecon(Chan *c)
-{
- Ctlr *ctlr = softctlr[0];
- Type *type;
-
- USED(c);
- for(type = ctlr->type; type < &ctlr->type[NType]; type++){
- qlock(type);
- if(type->inuse || type->q){
- qunlock(type);
- continue;
- }
- type->inuse = 1;
- netown(type, u->p->user, 0);
- qunlock(type);
- return type - ctlr->type;
+ irq = ur->trap-Int0vec;
+ for(i = 0; i < MaxEther; i++){
+ if(ether[i] && ether[i]->irq == irq)
+ (*ether[i]->interrupt)(ether[i]);
}
- exhausted("ether channels");
- return 0;
-}
-
-static void
-statsfill(Chan *c, char *p, int n)
-{
- Ctlr *ctlr = softctlr[0];
- char buf[256];
-
- USED(c);
- sprint(buf, "in: %d\nout: %d\ncrc errs %d\noverflows: %d\nframe errs %d\nbuff errs: %d\noerrs %d\naddr: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x\n",
- ctlr->inpackets, ctlr->outpackets, ctlr->crcs,
- ctlr->overflows, ctlr->frames, ctlr->buffs, ctlr->oerrs,
- ctlr->ea[0], ctlr->ea[1], ctlr->ea[2],
- ctlr->ea[3], ctlr->ea[4], ctlr->ea[5]);
- strncpy(p, buf, n);
}
-static void
-typefill(Chan *c, char *p, int n)
-{
- char buf[16];
- Type *type;
-
- type = &softctlr[0]->type[STREAMID(c->qid.path)];
- sprint(buf, "%d", type->type);
- strncpy(p, buf, n);
-}
-
-static void
-etherup(Ctlr *ctlr, Etherpkt *pkt, int len)
-{
- int t;
- Type *type;
- Block *bp;
-
- t = (pkt->type[0]<<8)|pkt->type[1];
- for(type = &ctlr->type[0]; type < &ctlr->type[NType]; type++){
-
- /*
- * Check for open, the right type, and flow control.
- */
- if(type->q == 0)
- continue;
- if(t != type->type && type->type != -1)
- continue;
- if(type->q->next->len > Streamhi)
- continue;
-
- /*
- * Only a trace channel gets packets destined for other machines.
- */
- if(type->type != -1 && pkt->d[0] != 0xFF
- && (*pkt->d != *ctlr->ea || memcmp(pkt->d, ctlr->ea, sizeof(pkt->d))))
- continue;
-
- if(waserror() == 0){
- bp = allocb(len);
- memmove(bp->rptr, pkt, len);
- bp->wptr += len;
- bp->flags |= S_DELIM;
- PUTNEXT(type->q, bp);
- poperror();
- }
- }
-}
-
-static int
-isinput(void *arg)
-{
- Ctlr *ctlr = arg;
-
- return ctlr->lbq.first || ctlr->rb[ctlr->rh].owner == Host || ctlr->clist;
-}
-
-static void
-etherkproc(void *arg)
-{
- Ctlr *ctlr = arg;
- RingBuf *ring;
- Block *bp;
- Type *type;
-
- if(waserror()){
- print("%s noted\n", ctlr->name);
- /* fix
- if(ctlr->card.reset)
- (*ctlr->card.reset)(ctlr);
- */
- ctlr->kproc = 0;
- nexterror();
- }
-
- for(;;){
- tsleep(&ctlr->rr, isinput, ctlr, 500);
- if(ctlr->card.watch)
- (*ctlr->card.watch)(ctlr);
-
- /*
- * Process any internal loopback packets.
- */
- while(bp = getq(&ctlr->lbq)){
- ctlr->inpackets++;
- etherup(ctlr, (Etherpkt*)bp->rptr, BLEN(bp));
- freeb(bp);
- }
-
- /*
- * Process any received packets.
- */
- while(ctlr->rb[ctlr->rh].owner == Host){
- ctlr->inpackets++;
- ring = &ctlr->rb[ctlr->rh];
- etherup(ctlr, (Etherpkt*)ring->pkt, ring->len);
- ring->owner = Interface;
- ctlr->rh = NEXT(ctlr->rh, ctlr->nrb);
- }
-
- /*
- * Close Types requesting it.
- */
- if(ctlr->clist){
- lock(&ctlr->clock);
- for(type = ctlr->clist; type; type = type->clist){
- type->q = 0;
- wakeup(&type->cr);
- }
- ctlr->clist = 0;
- unlock(&ctlr->clock);
- }
- }
-}
+#define NCARD 32
+static struct {
+ char *type;
+ int (*reset)(Ether*);
+} cards[NCARD+1];
-static void
-etherintr(Ureg *ur)
+void
+addethercard(char *t, int (*r)(Ether*))
{
- Ctlr *ctlr = softctlr[0];
+ static int ncard;
- USED(ur);
- (*ctlr->card.intr)(ctlr);
+ if(ncard == NCARD)
+ panic("too many ether cards");
+ cards[ncard].type = t;
+ cards[ncard].reset = r;
+ ncard++;
}
void
etherreset(void)
{
- Ctlr *ctlr;
- Card **card;
- int i;
+ Ether *ctlr;
+ int i, n, ctlrno;
+ ulong irqmask;
- if(nctlr >= NCtlr)
- return;
- if(softctlr[nctlr] == 0)
- softctlr[nctlr] = xalloc(sizeof(Ctlr));
- ctlr = softctlr[nctlr];
- for(card = cards; *card; card++){
- memset(ctlr, 0, sizeof(Ctlr));
- ctlr->card = **card;
- if((*ctlr->card.reset)(ctlr) == 0){
- ctlr->present = 1;
+ irqmask = 0;
+ for(ctlr = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
+ if(ctlr == 0)
+ ctlr = malloc(sizeof(Ether));
+ memset(ctlr, 0, sizeof(Ether));
+ if(isaconfig("ether", ctlrno, ctlr) == 0)
+ continue;
+ for(n = 0; cards[n].type; n++){
+ if(strcmp(cards[n].type, ctlr->type))
+ continue;
+ if((*cards[n].reset)(ctlr))
+ break;
/*
* IRQ2 doesn't really exist, it's used to gang the interrupt
* controllers together. A device set to IRQ2 will appear on
* the second interrupt controller as IRQ9.
+ * If there are multiple controllers on the same IRQ, only
+ * call setvec() for one of them, etherintr() will scan through
+ * all the controllers looking for those at the IRQ it was
+ * called with. This is a hack, see the comments in etherintr().
*/
- if(ctlr->card.irq == 2)
- ctlr->card.irq = 9;
- setvec(Int0vec + ctlr->card.irq, etherintr);
- break;
- }
- }
- if(ctlr->present == 0)
- return;
-
- print("ether%d: %s: I/O addr %lux width %d addr %lux size %d irq %d:",
- nctlr, ctlr->card.id,
- ctlr->card.io, ctlr->card.bit16 ? 16: 8, ctlr->card.ramstart,
- ctlr->card.ramstop-ctlr->card.ramstart, ctlr->card.irq);
- for(i = 0; i < sizeof(ctlr->ea); i++)
- print(" %2.2ux", ctlr->ea[i]);
- print("\n");
-
- nctlr++;
-
- if(ctlr->nrb == 0)
- ctlr->nrb = Nrb;
- ctlr->rb = xalloc(sizeof(RingBuf)*ctlr->nrb);
- if(ctlr->ntb == 0)
- ctlr->ntb = Ntb;
- ctlr->tb = xalloc(sizeof(RingBuf)*ctlr->ntb);
-
- memset(ctlr->ba, 0xFF, sizeof(ctlr->ba));
-
- ctlr->net.name = "ether";
- ctlr->net.nconv = NType;
- ctlr->net.devp = &info;
- ctlr->net.protop = 0;
- ctlr->net.listen = 0;
- ctlr->net.clone = clonecon;
- ctlr->net.ninfo = 2;
- ctlr->net.info[0].name = "stats";
- ctlr->net.info[0].fill = statsfill;
- ctlr->net.info[1].name = "type";
- ctlr->net.info[1].fill = typefill;
- for(i = 0; i < NType; i++)
- netadd(&ctlr->net, &ctlr->type[i], i);
-}
-
-void
-etherinit(void)
-{
- int ctlrno = 0;
- Ctlr *ctlr = softctlr[ctlrno];
- int i;
-
- if(ctlr->present == 0)
- return;
-
- ctlr->rh = 0;
- ctlr->ri = 0;
- for(i = 0; i < ctlr->nrb; i++)
- ctlr->rb[i].owner = Interface;
+ if(ctlr->irq == 2)
+ ctlr->irq = 9;
+ if((irqmask & (1<<ctlr->irq)) == 0){
+ setvec(Int0vec+ctlr->irq, etherintr);
+ irqmask |= 1<<ctlr->irq;
+ }
- ctlr->th = 0;
- ctlr->ti = 0;
- for(i = 0; i < ctlr->ntb; i++)
- ctlr->tb[i].owner = Host;
-}
+ print("ether%d: %s: port %lux irq %d addr %lux size %d:",
+ ctlrno, ctlr->type, ctlr->port, ctlr->irq, ctlr->mem, ctlr->size);
+ for(i = 0; i < sizeof(ctlr->ea); i++)
+ print(" %2.2ux", ctlr->ea[i]);
+ print("\n");
-Chan*
-etherattach(char *spec)
-{
- int ctlrno = 0;
- Ctlr *ctlr = softctlr[ctlrno];
+ netifinit(ctlr, "ether", Ntypes, 32*1024);
+ ctlr->alen = Eaddrlen;
+ memmove(ctlr->addr, ctlr->ea, sizeof(ctlr->ea));
+ memmove(ctlr->bcast, etherbcast, sizeof(etherbcast));
- if(ctlr->present == 0)
- error(Enodev);
-
- /*
- * Enable the interface
- * and start the kproc.
- */
- (*ctlr->card.attach)(ctlr);
- if(ctlr->kproc == 0){
- sprint(ctlr->name, "ether%dkproc", ctlrno);
- ctlr->kproc = 1;
- kproc(ctlr->name, etherkproc, ctlr);
+ ether[ctlrno] = ctlr;
+ ctlr = 0;
+ }
}
- return devattach('l', spec);
+ if(ctlr)
+ free(ctlr);
}
D pc/devincon.c => pc/devincon.c +0 -1140
@@ 1,1140 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "devtab.h"
-
-#include "io.h"
-
-/* Centronix parallel (printer) port */
-
-typedef struct Lptinfo Lptinfo;
-
-struct Lptinfo
-{
- int base; /* port number */
- int ivec; /* interrupt number */
-};
-
-static Lptinfo lptinfo[] = {
- 0x3bc, Parallelvec, /* lpt1 (safari) */
- 0x378, Parallelvec, /* lpt1 (`official') */
- 0x278, Int0vec+5, /* lpt2 (`official') */
-};
-#define NDEV (sizeof lptinfo/sizeof lptinfo[0])
-
-extern int incondev; /* from config */
-
-/* offsets, and bits in the registers */
-enum
-{
- /* data latch register */
- Qdlr= 0x0,
- /* printer status register */
- Qpsr= 0x1,
- Fbusy= 0x80,
- Fintbar= 0x40,
- /* printer control register */
- Qpcr= 0x2,
- Fie= 0x10,
- Fsi= 0x08,
- Finitbar= 0x04,
- Faf= 0x02,
- Fstrobe= 0x01,
-
- /* other `registers' */
- Qstats= 0x03,
- Qdebug= 0x04
-};
-
-/*
- * af si dlr<7:0>
- * 0 x xxxxxxxx wr ctl/data char (si is dcto)
- * 1 0 xxxxxxxx wr cmd
- * 1 1 xxxxxx00 rd ctl/data char
- * 1 1 xxxxxx01 rd status
- * 1 1 xxxxxx11 nop (multiplexer to normal state)
- *
- * psr<7:3> multiplexed as follows:
- *
- * bc7 bc6 bc5 bc4 bc3
- * rd, st- low bsy d8 d7 d6 d5
- * rd, st- high d4 d3 d2 d1 d0
- * other bsy int-
- */
-
-typedef struct Incon Incon;
-
-#define NOW (MACHP(0)->ticks*MS2HZ)
-
-#define DPRINT if(incondebug)kprint
-
-static void inconintr(Ureg *ur);
-
-enum {
- Minstation= 2, /* lowest station # to poll */
- Maxstation= 15, /* highest station # to poll */
- Nincon= 1, /* number of incons */
- Nin= 32, /* Blocks in the input ring */
- Bsize= 128, /* size of an input ring block */
- Mfifo= 0xff /* a mask, must be 2^n-1, must be > Nin */
-};
-
-struct Incon {
- QLock;
-
- QLock xmit; /* transmit lock */
- QLock reslock; /* reset lock */
- int dev; /* base address of port */
- int station; /* station number */
- int state; /* chip state */
- Rendez r; /* output process */
- Rendez kr; /* input kernel process */
- ushort chan; /* current input channel */
- Queue *rq; /* read queue */
- int kstarted; /* true if kernel process started */
-
- /* input blocks */
-
- Block *inb[Nin];
- ushort wi;
- ushort ri;
-
- /* statistics */
-
- ulong overflow; /* overflow errors */
- ulong pack0; /* channel 0 */
- ulong crc; /* crc errors */
- ulong in; /* bytes in */
- ulong out; /* bytes out */
- ulong wait; /* wait time in milliseconds */
-};
-
-Incon incon[Nincon];
-
-/*
- * chip state
- */
-enum {
- Selecting,
- Selected,
- Notliving,
-};
-
-/*
- * internal chip registers
- */
-#define sel_polln 0
-#define sel_station 1
-#define sel_poll0 2
-#define sel_rcv_cnt 3
-#define sel_rcv_tim 4
-#define sel_tx_cnt 5
-
-/*
- * CSR bits
- */
-#define INCON_RUN 0x80
-#define INCON_STOP 0x00
-#define ENABLE_IRQ 0x40
-#define ENABLE_TX_IRQ 0x20
-#define INCON_ALIVE 0x80
-#define TX_FULL 0x10
-#define TX_EMPTY 0x08
-#define RCV_EMPTY 0x04
-#define OVERFLOW 0x02
-#define CRC_ERROR 0x01
-
-/*
- * polling constants
- */
-#define HT_GNOT 0x30
-#define HT_UNIX 0x31
-#define ST_UNIX 0x04
-#define NCHAN 64
-
-static void inconkproc(void*);
-
-/*
- * incon stream module definition
- */
-static void inconoput(Queue*, Block*);
-static void inconstopen(Queue*, Stream*);
-static void inconstclose(Queue*);
-Qinfo inconinfo =
-{
- nullput,
- inconoput,
- inconstopen,
- inconstclose,
- "incon"
-};
-
-int incondebug = 0;
-
-Dirtab incondir[]={
- "dlr", {Qdlr}, 1, 0666,
- "psr", {Qpsr}, 5, 0444,
- "pcr", {Qpcr}, 0, 0666,
- "stats", {Qstats}, 0, 0444,
- "debug", {Qdebug}, 0, 0666,
-};
-#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 */
-{
- outb(dev+Qpcr, Finitbar);
- outb(dev+Qpcr, 0);
- outb(dev+Qpcr, Finitbar);
-}
-
-static void
-wrctl(int dev, int data) /* write control character */
-{
- outb(dev+Qpcr, Finitbar); /* no interrupts, please */
- outb(dev+Qdlr, data);
- outb(dev+Qpcr, Finitbar|Fstrobe);
- outb(dev+Qpcr, Finitbar|Fie);
-}
-
-static void
-wrdata(int dev, int data) /* write data character */
-{
- outb(dev+Qpcr, Finitbar|Fsi);
- outb(dev+Qdlr, data);
- outb(dev+Qpcr, Finitbar|Fsi|Fstrobe);
- outb(dev+Qpcr, Finitbar|Fsi|Fie);
-}
-
-static void
-wrcmd(int dev, int data) /* write command */
-{
- outb(dev+Qpcr, Finitbar|Faf);
- outb(dev+Qdlr, data);
- outb(dev+Qpcr, Finitbar|Faf|Fstrobe);
- outb(dev+Qpcr, Finitbar|Faf|Fie);
-}
-
-static int
-rdstatus(Incon *ip) /* read status */
-{
- int dev, data;
-
- dev = ip->dev;
-
- outb(dev+Qpcr, Finitbar|Faf|Fsi);
- outb(dev+Qdlr, 0x01);
- outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
- data = (inb(dev+Qpsr)&0xf8)<<2;
- outb(dev+Qpcr, Finitbar|Faf|Fsi);
- data |= inb(dev+Qpsr)>>3;
- if(data&(OVERFLOW|CRC_ERROR)){
- if(data&OVERFLOW)
- ip->overflow++;
- if(data&CRC_ERROR)
- ip->crc++;
- }
- outb(dev+Qdlr, 0x03);
- outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
- outb(dev+Qpcr, Finitbar|Faf|Fsi|Fie);
-
- return data;
-}
-
-static void
-iwrcmd(int dev, int data) /* write command at interrupt level */
-{
- outb(dev+Qdlr, data);
- outb(dev+Qpcr, Finitbar|Faf|Fstrobe);
- outb(dev+Qpcr, Finitbar|Faf);
-}
-
-static int
-irdstatus(Incon *ip) /* read status at interrupt level */
-{
- int dev, data;
-
- dev = ip->dev;
-
- outb(dev+Qdlr, 0x01);
- outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
- data = (slowinb(dev+Qpsr)&0xf8)<<2;
- outb(dev+Qpcr, Finitbar|Faf|Fsi);
- data |= slowinb(dev+Qpsr)>>3;
- if(data&(OVERFLOW|CRC_ERROR)){
- if(data&OVERFLOW)
- ip->overflow++;
- if(data&CRC_ERROR)
- ip->crc++;
- }
-
- return data;
-}
-
-static int
-irddata(int dev) /* read data at interrupt level */
-{
- int data;
-
- outb(dev+Qdlr, 0x00);
- outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
- data = (slowinb(dev+Qpsr)&0xf8)<<2;
- outb(dev+Qpcr, Finitbar|Faf|Fsi);
- data |= slowinb(dev+Qpsr)>>3;
-
- return data;
-}
-
-static int
-irdnext(int dev) /* read next data at interrupt level */
-{
- int data;
-
- outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
- data = (inb(dev+Qpsr)&0xf8)<<2;
- outb(dev+Qpcr, Finitbar|Faf|Fsi);
- data |= inb(dev+Qpsr)>>3;
-
- return data;
-}
-
-static void
-irdnop(int dev, int pcr) /* read nop (mux reset) */
-{
- outb(dev+Qdlr, 0x03);
- outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
- outb(dev+Qpcr, pcr);
-}
-
-int Irdnext(int);
-#define irdnext Irdnext
-/**/
-
-/*
- * set the incon parameters
- */
-void
-inconset(Incon *ip, int cnt, int del)
-{
- int dev;
-
- if (cnt<1 || cnt>14 || del<1 || del>15)
- error(Ebadarg);
-
- dev = ip->dev;
- wrcmd(dev, sel_rcv_cnt | INCON_RUN);
- wrdata(dev, cnt);
- wrcmd(dev, sel_rcv_tim | INCON_RUN);
- wrdata(dev, del);
- wrcmd(dev, INCON_RUN | ENABLE_IRQ);
-}
-
-/*
- * parse a set request
- */
-void
-inconsetctl(Incon *ip, Block *bp)
-{
- char *field[3];
- int n;
- int del;
- int cnt;
-
- del = 15;
- n = getfields((char *)bp->rptr, field, 3, ' ');
- switch(n){
- default:
- freeb(bp);
- error(Ebadarg);
- case 2:
- del = strtol(field[1], 0, 0);
- if(del<0 || del>15){
- freeb(bp);
- error(Ebadarg);
- }
- /* fall through */
- case 1:
- cnt = strtol(field[0], 0, 0);
- if(cnt<0 || cnt>15){
- freeb(bp);
- error(Ebadarg);
- }
- }
- inconset(ip, cnt, del);
- freeb(bp);
-}
-
-/*
- * poll for a station number
- */
-void
-inconpoll(Incon *ip, int station)
-{
- ulong timer;
- int dev;
- char *p;
-
- dev = ip->dev;
-
- /*
- * get us to a known state
- */
- ip->state = Notliving;
- wrcmd(dev, INCON_STOP);
-
- /*
- * try a station number
- */
- wrcmd(dev, sel_station);
- wrdata(dev, station);
- wrcmd(dev, sel_poll0);
- wrdata(dev, HT_GNOT);
- wrcmd(dev, sel_rcv_cnt);
- wrdata(dev, 3);
- wrcmd(dev, sel_rcv_tim);
- wrdata(dev, 15);
- wrcmd(dev, sel_tx_cnt);
- wrdata(dev, 1);
- wrcmd(dev, sel_polln);
- wrdata(dev, 0x00);
- wrdata(dev, ST_UNIX);
- wrdata(dev, NCHAN);
- for(p = "gnot"; *p; p++)
- wrdata(dev, *p);
- wrctl(dev, 0);
-
- /*
- * poll and wait for ready (or 1/4 second)
- */
- ip->state = Selecting;
- wrcmd(dev, INCON_RUN | ENABLE_IRQ);
- timer = NOW + 250;
- while (NOW < timer) {
- nop();
- if(rdstatus(ip) & INCON_ALIVE){
- ip->station = station;
- ip->state = Selected;
- break;
- }
- }
-}
-
-/*
- * reset the chip and find a new station number
- */
-void
-inconrestart(Incon *ip)
-{
- int i;
-
- if(!canqlock(&ip->reslock))
- return;
-
- /*
- * poll for incon station numbers
- */
- DPRINT("inconrestart\n");
- for(i = Minstation; i <= Maxstation; i++){
- inconpoll(ip, i);
- if(ip->state == Selected)
- break;
- }
- switch(ip->state) {
- case Selecting:
- DPRINT("incon[%d] not polled\n", ip-incon);
- print("incon[%d] not polled\n", ip-incon);
- break;
- case Selected:
- DPRINT("incon[%d] station %d\n", ip-incon, ip->station);
- print("incon[%d] station %d\n", ip-incon, ip->station);
- inconset(ip, 3, 15);
- break;
- default:
- DPRINT("incon[%d] bollixed\n", ip-incon);
- print("incon[%d] bollixed\n", ip-incon);
- break;
- }
- qunlock(&ip->reslock);
-}
-
-/*
- * reset all incon chips.
- */
-
-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
- * i.e. we've already got a station number.
- * state is Selecting if this is a first-time open.
- */
-/* inconset(&incon[0], 3, 15); /**/
- for(i=0; i<Nincon; i++){
- incon[i].dev = lptinfo[incondev].base;
- incon[i].state = Notliving;
- reset(incon[i].dev);
- incon[i].ri = incon[i].wi = 0;
- }
- incon[0].state = Selecting;
- wrcmd(incon[0].dev, INCON_STOP);
-}
-
-void
-inconinit(void)
-{
- wrcmd(incon[0].dev, INCON_STOP);
-}
-
-/*
- * enable the device for interrupts, spec is the device number
- */
-Chan*
-inconattach(char *spec)
-{
- Incon *ip;
- int i;
- Chan *c;
-
- setvec(lptinfo[incondev].ivec, inconintr);
- i = strtoul(spec, 0, 0);
- if(i >= Nincon)
- error(Ebadarg);
- ip = &incon[i];
- rdstatus(ip);
- if(ip->state != Selected)
- inconrestart(ip);
-
- c = devattach('i', spec);
- c->dev = i;
- c->qid.path = CHDIR;
- c->qid.vers = 0;
- return c;
-}
-
-Chan*
-inconclone(Chan *c, Chan *nc)
-{
- return devclone(c, nc);
-}
-
-int
-inconwalk(Chan *c, char *name)
-{
- return devwalk(c, name, incondir, NINCON, streamgen);
-}
-
-void
-inconstat(Chan *c, char *dp)
-{
- devstat(c, dp, incondir, NINCON, streamgen);
-}
-
-Chan*
-inconopen(Chan *c, int omode)
-{
- if(c->qid.path != CHDIR && c->qid.path >= Slowqid)
- streamopen(c, &inconinfo);
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- return c;
-}
-
-void
-inconcreate(Chan *c, char *name, int omode, ulong perm)
-{
- USED(c, name, omode, perm);
- error(Eperm);
-}
-
-void
-inconclose(Chan *c)
-{
- if(c->qid.path != CHDIR && c->qid.path >= Slowqid)
- streamclose(c);
-}
-
-long
-inconread(Chan *c, void *buf, long n, ulong offset)
-{
- char b[256];
- Incon *ip;
-
- if(c->qid.path == CHDIR)
- return devdirread(c, buf, n, incondir, NINCON, streamgen);
- ip = &incon[c->dev];
- switch(c->qid.path){
- default:
- return streamread(c, buf, n);
- case Qdlr:
- case Qpsr:
- case Qpcr:
- sprint(b, "0x%2.2ux\n", inb(ip->dev + c->qid.path));
- break;
- case Qstats:
- sprint(b, "state: %d\nstation: %d\nin: %d\nout: %d\noverflow: %d\ncrc: %d\nwait: %d\n",
- ip->state, ip->station, ip->in, ip->out, ip->overflow, ip->crc, ip->wait);
- break;
- case Qdebug:
- sprint(b, "%d\n", incondebug);
- break;
- }
- return readstr(offset, buf, n, b);
-}
-
-long
-inconwrite(Chan *c, void *buf, long n, ulong offset)
-{
- char b[8];
- Incon *ip;
- int data;
-
- USED(offset);
- switch(c->qid.path){
- default:
- return streamwrite(c, buf, n, 0);
- case Qdlr:
- case Qpcr:
- case Qdebug:
- break;
- }
- if(n > sizeof b-1)
- n = sizeof b-1;
- memmove(b, buf, n);
- b[n] = 0;
- data = strtoul(b, 0, 0);
- switch(c->qid.path){
- default:
- ip = &incon[c->dev];
- outb(ip->dev + c->qid.path, data);
- break;
- case Qdebug:
- incondebug = data;
- break;
- }
- return n;
-}
-
-void
-inconremove(Chan *c)
-{
- USED(c);
- error(Eperm);
-}
-
-void
-inconwstat(Chan *c, char *dp)
-{
- USED(c, dp);
- error(Eperm);
-}
-
-/*
- * the stream routines
- */
-
-/*
- * kill off the kernel process
- */
-static int
-kNotliving(void *arg)
-{
- Incon *ip;
-
- ip = (Incon *)arg;
- return ip->kstarted == 0;
-}
-
-static void
-inconstclose(Queue * q)
-{
- Incon *ip;
-
- ip = (Incon *)q->ptr;
- qlock(ip);
- ip->rq = 0;
- qunlock(ip);
- wakeup(&ip->kr);
- sleep(&ip->r, kNotliving, ip);
-}
-
-/*
- * create the kernel process for input
- * first wait for any old ones to die
- */
-static void
-inconstopen(Queue *q, Stream *s)
-{
- Incon *ip;
- char name[32];
-
- ip = &incon[s->dev];
- sprint(name, "incon%d", s->dev);
- q->ptr = q->other->ptr = ip;
- wakeup(&ip->kr);
- sleep(&ip->r, kNotliving, ip);
- ip->rq = q;
- kproc(name, inconkproc, ip);
-}
-
-/*
- * free all blocks of a message in `q', `bp' is the first block
- * of the message
- */
-static void
-freemsg(Queue *q, Block *bp)
-{
- for(; bp; bp = getq(q)){
- if(bp->flags & S_DELIM){
- freeb(bp);
- return;
- }
- freeb(bp);
- }
-}
-
-static void
-showpkt(char *str, int chan, int ctl, Block *bp, int i)
-{
- int n;
-
- n = bp->wptr - bp->rptr;
- kprint("%s(%d)%uo %d", str, chan, ctl, n);
- if(n > 8)
- n = 8;
- for(; i<n; i++)
- kprint(" %2.2ux", bp->rptr[i]);
- kprint("\n");
-}
-
-/*
- * output a block
- *
- * the first 2 bytes of every message are the channel number,
- * low order byte first. the third is a possible trailing control
- * character.
- */
-void
-inconoput(Queue *q, Block *bp)
-{
- int dev;
- Incon *ip;
- ulong end;
- int status, chan, ctl;
- int n, size;
-
- ip = (Incon *)q->ptr;
-
- if(bp->type != M_DATA){
- if(streamparse("inconset", bp))
- inconsetctl(ip, bp);
- else
- freeb(bp);
- return;
- }
- if(BLEN(bp) < 3){
- bp = pullup(bp, 3);
- if(bp == 0){
- print("inconoput pullup failed\n");
- return;
- }
- }
-
- /*
- * get a whole message before handing bytes to the device
- */
- if(!putq(q, bp))
- return;
-
- /*
- * one transmitter at a time
- */
- qlock(&ip->xmit);
- dev = ip->dev;
-
- /*
- * parse message
- */
- bp = getq(q);
- chan = bp->rptr[0] | (bp->rptr[1]<<8);
- ctl = bp->rptr[2];
- bp->rptr += 3;
- if(chan<=0)
- print("bad channel %d\n", chan);
-
- if(incondebug){
- kprint("0x%.2ux ", rdstatus(ip));
- showpkt("->", chan, ctl, bp, 0);
- }
-
- /*
- * make sure there's an incon out there
- */
- if(!(rdstatus(ip)&INCON_ALIVE) || ip->state==Notliving){
- DPRINT("inconoput: not ready");
- inconrestart(ip);
- freemsg(q, bp);
- qunlock(&ip->xmit);
- return;
- }
-
- /*
- * send the 8 bit data
- */
- for(;;){
- /*
- * spin till there is room
- */
- for(n=0, end = NOW+1000; (status=rdstatus(ip)) & TX_FULL; n++){
- nop(); /* make sure we don't optimize too much */
- if(NOW > end){
- print("incon output stuck 0 %.2ux\n", status);
- freemsg(q, bp);
- qunlock(&ip->xmit);
- return;
- }
- }
- ip->wait = (n + ip->wait)>>1;
-
- /*
- * put in next packet
- */
- n = bp->wptr - bp->rptr;
- if(n > 16)
- n = 16;
- size = n;
- wrctl(dev, chan);
- ip->out += n;
- while(n--){
- wrdata(dev, *bp->rptr++);
- }
-
- /*
- * get next block
- */
- if(bp->rptr >= bp->wptr){
- if(bp->flags & S_DELIM){
- freeb(bp);
- break;
- }
- freeb(bp);
- bp = getq(q);
- if(bp==0)
- break;
- }
-
- /*
- * end packet
- */
- wrctl(dev, 0);
- }
-
- /*
- * send the control byte if there is one
- */
- if(ctl){
- if(size >= 16){
- wrctl(dev, 0);
- for(end = NOW+1000; rdstatus(ip) & TX_FULL;){
- nop(); /* make sure we don't optimize too much */
- if(NOW > end){
- print("incon output stuck 1\n");
- freemsg(q, bp);
- qunlock(&ip->xmit);
- return;
- }
- }
- wrctl(dev, chan);
- }
- if(rdstatus(ip) & TX_FULL)
- print("inconfull\n");
- ip->out += 1;
- wrctl(dev, ctl);
- }
- wrctl(dev, 0);
-
- qunlock(&ip->xmit);
- return;
-}
-
-/*
- * return true if the raw fifo is non-empty
- */
-static int
-notempty(void *arg)
-{
- Incon *ip;
-
- ip = (Incon *)arg;
- return ip->ri!=ip->wi;
-}
-
-/*
- * Read bytes from the raw input circular buffer.
- */
-static void
-inconkproc(void *arg)
-{
- Incon *ip;
- Block *bp;
- int i;
- int locked;
-
- ip = (Incon *)arg;
- ip->kstarted = 1;
-
- /*
- * create a number of blocks for input
- */
- for(i = 0; i < Nin; i++){
- bp = ip->inb[i] = allocb(Bsize);
- bp->wptr += 3;
- }
-
- locked = 0;
- if(waserror()){
- if(locked)
- qunlock(ip);
- ip->kstarted = 0;
- wakeup(&ip->r);
- return;
- }
-
- for(;;){
- /*
- * sleep if input fifo empty
- */
- sleep(&ip->kr, notempty, ip);
-
- /*
- * die if the device is closed
- */
- USED(locked);
- qlock(ip);
- locked = 1;
- if(ip->rq == 0){
- qunlock(ip);
- ip->kstarted = 0;
- wakeup(&ip->r);
- poperror();
- return;
- }
-
- /*
- * send blocks upstream and stage new blocks.
- */
- while(ip->ri != ip->wi){
- bp = ip->inb[ip->ri];
- bp->flags |= S_DELIM;
- ip->in += BLEN(bp);
- PUTNEXT(ip->rq, bp);
- bp = ip->inb[ip->ri] = allocb(Bsize);
- bp->wptr += 3;
- ip->ri = (ip->ri+1)%Nin;
- }
- USED(locked);
- qunlock(ip);
- locked = 0;
- }
-}
-
-/*
- * drop a single packet
- */
-static void
-droppacket(int dev)
-{
- if(irddata(dev) == 0)
- return;
- while(irdnext(dev))
- ;
-}
-
-/*
- * flush the input fifo
- */
-static void
-flushfifo(Incon *ip)
-{
- while(!(irdstatus(ip) & RCV_EMPTY))
- droppacket(ip->dev);
-}
-
-/*
- * advance the queue. if we've run out of staged input blocks,
- * drop the packet and return 0. otherwise return the next input
- * block to fill.
- */
-static Block *
-nextin(Incon *ip, unsigned int c)
-{
- Block *bp;
- int next;
-
- bp = ip->inb[ip->wi];
- bp->rptr[0] = ip->chan;
- bp->rptr[1] = ip->chan>>8;
- bp->rptr[2] = c;
- if(incondebug)
- showpkt("<-", ip->chan, c, bp, 3);
-
- next = (ip->wi+1)%Nin;
- if(next == ip->ri){
- bp->wptr = bp->rptr+3;
- return bp;
- }
- ip->wi = next;
-
- return ip->inb[ip->wi];
-}
-
-/*
- * read the packets from the device into the staged input blocks.
- * we have to do this at interrupt tevel to turn off the interrupts.
- */
-static void
-rdpackets(Incon *ip)
-{
- Block *bp;
- unsigned int c;
- int dev;
- uchar *p;
- int first = ip->wi;
-
- dev = ip->dev;
- bp = ip->inb[ip->wi];
- if(bp==0){
- flushfifo(ip);
- return;
- }
- p = bp->wptr;
- while(!(irdstatus(ip) & RCV_EMPTY)){
- /*
- * get channel number
- */
- c = irddata(dev);
- if(c == 0){
- droppacket(dev);
- continue;
- }
- if(ip->chan != c){
- if(p - bp->rptr > 3){
- bp->wptr = p;
- bp = nextin(ip, 0);
- p = bp->wptr;
- }
- ip->chan = c;
- }
-
- /*
- * null byte marks end of packet
- */
- while(c = irdnext(dev)){ /* assign = */
- if((c & 0x100) == 0){
- /*
- * control byte ends block
- */
- bp->wptr = p;
- bp = nextin(ip, c);
- p = bp->wptr;
- }else{
- /*
- * data byte, put in local buffer
- */
- *p++ = c;
- }
- }
-
- /*
- * pass a block on if it doesn't have room for one more
- * packet. this way we don't have to check per byte.
- */
- if(p + 16 > bp->lim){
- bp->wptr = p;
- bp = nextin(ip, 0);
- p = bp->wptr;
- }
- }
- bp->wptr = p;
- if(bp->wptr != bp->rptr+3)
- nextin(ip, 0);
-
- if(first != ip->wi)/**/
- wakeup(&ip->kr);
-}
-
-/*
- * Receive an incon interrupt. One entry point
- * for all types of interrupt. Until we figure out
- * how to use more than one incon, this routine only
- * is for incon[0].
- */
-static void
-inconintr(Ureg *ur)
-{
- uchar status;
- int pcr;
- Incon *ip;
-
- 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);
- if(pcr & Fstrobe)
- kprint("YIKES!!\n");
- }
- if(!(status & RCV_EMPTY))
- rdpackets(ip);
-
- /* see if it died underneath us */
- if(!(status&INCON_ALIVE)){
- switch(ip->state){
- case Selected:
- iwrcmd(ip->dev, INCON_STOP);
- DPRINT("Incon died\n");
- print("Incon died\n");
- break;
- case Selecting:
- DPRINT("rejected\n");
- print("rejected\n");
- break;
- default:
- iwrcmd(ip->dev, INCON_STOP);
- DPRINT("state was %d\n", ip->state);
- break;
- }
- ip->state = Notliving;
- }
- irdnop(ip->dev, pcr);
-}
D pc/ether.h => pc/ether.h +0 -169
@@ 1,169 0,0 @@
-/*
- * All the goo for PC ethernet cards.
- */
-typedef struct Card Card;
-typedef struct RingBuf RingBuf;
-typedef struct Type Type;
-typedef struct Ctlr Ctlr;
-
-/*
- * Hardware interface.
- */
-struct Card {
- ISAConf;
-
- int (*reset)(Ctlr*);
- void (*init)(Ctlr*);
- void (*attach)(Ctlr*);
- void (*mode)(Ctlr*, int);
-
- void *(*read)(Ctlr*, void*, ulong, ulong);
- void *(*write)(Ctlr*, ulong, void*, ulong);
-
- void (*receive)(Ctlr*);
- void (*transmit)(Ctlr*);
- void (*intr)(Ctlr*);
- void (*watch)(Ctlr*);
- void (*overflow)(Ctlr*);
-
- uchar bit16; /* true if a 16 bit interface */
- uchar ram; /* true if card has shared memory */
-
- ulong dp8390; /* I/O address of 8390 (if any) */
- ulong data; /* I/O data port if no shared memory */
- uchar nxtpkt; /* software bndry */
- uchar tstart; /* 8390 ring addresses */
- uchar pstart;
- uchar pstop;
-};
-
-/*
- * Software ring buffer.
- */
-struct RingBuf {
- uchar owner;
- uchar busy; /* unused */
- ushort len;
- uchar pkt[sizeof(Etherpkt)];
-};
-
-enum {
- Host = 0, /* buffer owned by host */
- Interface = 1, /* buffer owned by card */
-
- Nrb = 16, /* default number of receive buffers */
- Ntb = 4, /* default number of transmit buffers */
-};
-
-/*
- * One per ethernet packet type.
- */
-struct Type {
- QLock;
- Netprot; /* stat info */
- int type; /* ethernet type */
- int prom; /* promiscuous mode */
- Queue *q;
- int inuse;
- Ctlr *ctlr;
-
- Rendez cr; /* rendezvous for close */
- Type *clist; /* close list */
-};
-
-enum {
- NType = 9, /* types/card */
-};
-
-/*
- * Software controller.
- */
-struct Ctlr {
- QLock;
- int ctlrno;
- Ctlr *next;
-
- Card card; /* hardware info */
- int present;
- int debug;
-
- ushort nrb; /* number of software receive buffers */
- ushort ntb; /* number of software transmit buffers */
- RingBuf *rb; /* software receive buffers */
- RingBuf *tb; /* software transmit buffers */
-
- uchar ea[6]; /* ethernet address */
- uchar ba[6]; /* broadcast address */
-
- Rendez rr; /* rendezvous for a receive buffer */
- ushort rh; /* first receive buffer belonging to host */
- ushort ri; /* first receive buffer belonging to card */
-
- Rendez tr; /* rendezvous for a transmit buffer */
- QLock tlock; /* semaphore on th */
- ushort th; /* first transmit buffer belonging to host */
- ushort ti; /* first transmit buffer belonging to card */
- int tbusy; /* transmitter is busy */
-
- Type type[NType];
- int all; /* number of channels listening to all packets */
- Type *clist; /* channels waiting to close */
- Lock clock; /* lock for clist */
- int prom; /* number of promiscuous channels */
- int kproc; /* true if kproc started */
- char name[NAMELEN]; /* name of kproc */
- Network net;
-
- Queue lbq; /* software loopback packet queue */
-
- int inpackets;
- int outpackets;
- int crcs; /* input crc errors */
- int oerrs; /* output errors */
- int frames; /* framing errors */
- int overflows; /* packet overflows */
- int buffs; /* buffering errors */
-};
-
-#define NEXT(x, l) (((x)+1)%(l))
-#define HOWMANY(x, y) (((x)+((y)-1))/(y))
-#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
-
-/*
- * The Western Digital 8003 and 8013 series, the NE2000
- * and the 3Com 503 all use the DP8390 Network Interface
- * Chip.
- */
-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);
-extern void dp8390receive(Ctlr*);
-extern void dp8390transmit(Ctlr*);
-extern void dp8390intr(Ctlr*);
-extern void dp8390watch(Ctlr*);
-extern void dp8390overflow(Ctlr*);
-
-extern void dp8390debug(Ctlr*);
-
-/*
- * The DP8390 needs some time between successive
- * chip selects, so we need special I/O routines.
- * See l.s.
- * These routines only need to be used for accessing
- * the chip registers. Data I/O, either through
- * remote DMA or shared memory, can use the normal
- * routines.
- */
-extern int dp8390inb(ulong);
-extern void dp8390outb(ulong, uchar);
-
-enum {
- Dp8390BufSz = 256, /* hardware ring buffer size */
-};
-
-
-extern void addethercard(char*, int (*)(Ctlr*));
D pc/ether503.c => pc/ether503.c +0 -346
@@ 1,346 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "io.h"
-#include "devtab.h"
-
-#include "ether.h"
-
-/*
- * 3Com 503 (EtherLink II).
- * This driver doesn't work under load, the card gets blasted by
- * overwrite-warning interrupts and eventually just hangs. Always clearing
- * the Ovw bit in the DP8390 Isr along with the Rxe and Prx bits stops
- * the overwrite-warning interrupts, but the card eventually hangs anyway.
- * I really don't understand why this card doesn't work,
- * there is plenty of evidence that other systems manage to use it.
- * The only good thing about this driver is that both shared
- * memory and polled I/O work (given the above restraints), although
- * the polled I/O should be tuned.
- */
-enum { /* Gate Array Registers */
- Pstr = 0x400, /* Page Start Register */
- Pspr = 0x401, /* Page Stop Register */
- Dqtr = 0x402, /* Drq Timer Register */
- Bcfr = 0x403, /* Base Configuration Register */
- Pcfr = 0x404, /* EPROM Configuration Register */
- Gacfr = 0x405, /* GA Configuration Register */
- Ctrl = 0x406, /* Control Register */
- Streg = 0x407, /* Status Register */
- Idcfr = 0x408, /* Interrupt/DMA Configuration Register */
- Damsb = 0x409, /* DMA Address Register MSB */
- Dalsb = 0x40A, /* DMA Address Register LSB */
- Vptr2 = 0x40B, /* Vector Pointer Register 2 */
- Vptr1 = 0x40C, /* Vector Pointer Register 1 */
- Vptr0 = 0x40D, /* Vector Pointer Register 0 */
- Rfmsb = 0x40E, /* Register File Access MSB */
- Rflsb = 0x40F, /* Register File Access LSB */
-};
-
-enum { /* Pcfr */
- C8xxx = 0x10, /* memory address 0xC8000 */
- CCxxx = 0x20, /* memory address 0xCC000 */
- D8xxx = 0x40, /* memory address 0xD8000 */
- DCxxx = 0x80, /* memory address 0xDC000 */
-};
-
-enum { /* Gacfr */
- Mbs0 = 0x01, /* memory bank select 0 */
- Mbs1 = 0x02, /* memory bank select 1 */
- Mbs2 = 0x04, /* memory bank select 2 */
- Rsel = 0x08, /* RAM select */
- Test = 0x10, /* test */
- Ows = 0x20, /* 0 wait state */
- Tcm = 0x40, /* terminal count mask */
- Nim = 0x80, /* MIC interrupt mask */
-};
-
-enum { /* Ctrl */
- Rst = 0x01, /* software reset */
- Xsel = 0x02, /* transceiver select (BNC = 1, AUI = 0) */
- Ealo = 0x04, /* ethernet address low */
- Eahi = 0x08, /* ethernet address high */
- Share = 0x10, /* interrupt share */
- Dbsel = 0x20, /* double buffer select */
- Ddir = 0x40, /* DMA direction */
- Start = 0x80, /* DMA start */
-};
-
-enum { /* Streg */
- Rev0 = 0x01, /* gate array revision bit 0 */
- Rev1 = 0x02, /* gate array revision bit 1 */
- Rev2 = 0x04, /* gate array revision bit 2 */
- Dip = 0x08, /* DMA in progress */
- Dtc = 0x10, /* DMA terminal count */
- Oflw = 0x20, /* overflow */
- Uflw = 0x40, /* underflow */
- Dprdy = 0x80, /* data port ready */
-};
-
-enum { /* Idcfr */
- Drq1 = 0x01, /* DMA request 1 */
- Drq2 = 0x02, /* DMA request 2 */
- Drq3 = 0x04, /* DMA request 3 */
- Irq2 = 0x10, /* interrupt request 2 */
- Irq3 = 0x20, /* interrupt request 3 */
- Irq4 = 0x40, /* interrupt request 4 */
- Irq5 = 0x80, /* interrupt request 5 */
-};
-
-enum {
- RamOffset = 0x2000, /* where the card sees the shared memory */
-};
-
-typedef struct {
- ulong io; /* I/O base address */
- uchar irq; /* interrupt level */
- uchar bnc; /* use BNC connector */
-} Table;
-
-/*
- * The only configuration info we can get from the card is the
- * I/O base address and the shared-memory address. So let's make
- * a little hard-wired configuration table.
- */
-static Table table[] = {
- { 0x300, Irq2, 0, }, /* external transceiver */
- { 0x310, Irq3, 0, },
- { 0x330, Irq4, 0, },
- { 0x350, Irq5, 0, },
-
- { 0x250, Irq2, Xsel, }, /* BNC */
- { 0x280, Irq3, Xsel, },
- { 0x2A0, Irq4, Xsel, },
- { 0x2E0, Irq5, Xsel, },
-
- { 0 },
-};
-
-
-static int
-reset(Ctlr *ctlr)
-{
- Table *tp;
- int i;
- uchar cfr;
-
- /*
- * The Gate Array Ctrl register bits <3,2> determine what is
- * mapped at the I/O base address. The options are the DP8390,
- * PROM bytes 0-15 or PROM bytes 16-31.
- * At power-on, the I/O base address contains PROM bytes 16-31.
- */
- for(tp = table; ctlr->card.io = tp->io; tp++){
- /*
- * Toggle the software reset bit, this should initialise the
- * Ctrl register to 0x0A (Eahi|Xsel).
- * Hopefully there is no other card at the gate-array address.
- */
- outb(ctlr->card.io+Ctrl, Rst);
- delay(1);
- outb(ctlr->card.io+Ctrl, 0);
- if(inb(ctlr->card.io+Ctrl) == (Eahi|Xsel))
- break;
- }
- if(ctlr->card.io == 0)
- return -1;
-
- /*
- * Map PROM bytes 0-15 to the I/O base address
- * and read the ethernet address.
- * When done, map the DP8390 at the I/O base address
- * and set the transceiver type and irq.
- */
- outb(ctlr->card.io+Ctrl, Ealo|Xsel);
- for(i = 0; i < sizeof(ctlr->ea); i++)
- ctlr->ea[i] = inb(ctlr->card.io+i);
-
- outb(ctlr->card.io+Gacfr, Nim|Tcm);
-
- outb(ctlr->card.io+Ctrl, 0|tp->bnc);
- outb(ctlr->card.io+Idcfr, tp->irq);
-
- if(tp->irq == Irq2)
- ctlr->card.irq = 2;
- else if(tp->irq == Irq3)
- ctlr->card.irq = 3;
- else if(tp->irq == Irq4)
- ctlr->card.irq = 4;
- else if(tp->irq == Irq5)
- ctlr->card.irq = 5;
- else
- return -1;
-
- /*
- * Try to configure the shared memory.
- * Assume this is an 8K card.
- */
- ctlr->card.ram = 1;
- cfr = inb(ctlr->card.io+Pcfr);
- if(cfr & C8xxx)
- ctlr->card.ramstart = KZERO|0xC8000;
- else if(cfr & CCxxx)
- ctlr->card.ramstart = KZERO|0xCC000;
- else if(cfr & D8xxx)
- ctlr->card.ramstart = KZERO|0xD8000;
- else if(cfr & DCxxx)
- ctlr->card.ramstart = KZERO|0xDC000;
- else
- ctlr->card.ram = 0;
-
- ctlr->card.ramstop = ctlr->card.ramstart + 8*1024;
-
- /*
- * Finish initialising the gate-array.
- * The Pstr and Pspr registers must be the same as those
- * given to the DP8390.
- * Gacfr is set to enable shared memory and block DMA
- * interrupts.
- */
- outb(ctlr->card.io+Pstr, ctlr->card.pstart);
- outb(ctlr->card.io+Pspr, ctlr->card.pstop);
-
- outb(ctlr->card.io+Dqtr, 8);
- outb(ctlr->card.io+Damsb, ctlr->card.tstart);
- outb(ctlr->card.io+Dalsb, 0);
-
- outb(ctlr->card.io+Vptr2, 0xFF);
- outb(ctlr->card.io+Vptr1, 0xFF);
- outb(ctlr->card.io+Vptr0, 0x00);
-
- /*
- * Finally, init the 8390, set the ethernet address
- * and turn on the shared memory if any.
- */
- ctlr->card.dp8390 = ctlr->card.io;
- dp8390reset(ctlr);
- dp8390setea(ctlr);
-
- if(ctlr->card.ram)
- outb(ctlr->card.io+Gacfr, Tcm|Rsel|Mbs0);
- else
- outb(ctlr->card.io+Gacfr, Tcm);
-
- return 0;
-}
-
-static void*
-read(Ctlr *ctlr, void *to, ulong from, ulong len)
-{
- uchar *addr, ctrl;
-
- /*
- * If the interface has shared memory, just do a memmove.
- * In this case, 'from' is an index into the shared memory.
- * Due to 'hardware considerations', the memory is seen by
- * the adapter at RamOffset, so we have to adjust.
- */
- if(ctlr->card.ram)
- return memmove(to, (void*)(ctlr->card.ramstart+from-RamOffset), len);
-
- /*
- * Polled I/O. This should be tuned.
- * Set up the dma registers and pump the fifo.
- */
- outb(ctlr->card.io+Dalsb, from & 0xFF);
- outb(ctlr->card.io+Damsb, (from>>8) & 0xFF);
- ctrl = inb(ctlr->card.io+Ctrl);
- outb(ctlr->card.io+Ctrl, Start|ctrl);
- addr = to;
- while(len){
- /*
- * The fifo is 8 bytes deep, we have to wait
- * until it's ready before stuffing it.
- * The fifo is in its default configuration,
- * so we can do word accesses.
- */
- while((inb(ctlr->card.io+Streg) & Dprdy) == 0)
- ;
- if(len >= 8){
- inss(ctlr->card.io+Rfmsb, addr, 4);
- addr += 8;
- len -= 8;
- }
- else{
- insb(ctlr->card.io+Rfmsb, addr, len);
- break;
- }
- }
- outb(ctlr->card.io+Ctrl, ctrl);
- return to;
-}
-
-static void*
-write(Ctlr *ctlr, ulong to, void *from, ulong len)
-{
- uchar *addr, ctrl;
-
- /*
- * See the comments in 'read()' above.
- */
- if(ctlr->card.ram)
- return memmove((void*)(ctlr->card.ramstart+to-RamOffset), from, len);
-
- outb(ctlr->card.io+Dalsb, to & 0xFF);
- outb(ctlr->card.io+Damsb, (to>>8) & 0xFF);
- ctrl = inb(ctlr->card.io+Ctrl);
- outb(ctlr->card.io+Ctrl, Start|Ddir|ctrl);
- addr = from;
- while(len){
- while((inb(ctlr->card.io+Streg) & Dprdy) == 0)
- ;
- if(len >= 8){
- outss(ctlr->card.io+Rfmsb, addr, 4);
- addr += 8;
- len -= 8;
- }
- else{
- outsb(ctlr->card.io+Rfmsb, addr, len);
- break;
- }
- }
- outb(ctlr->card.io+Ctrl, ctrl);
- return (void*)to;
-}
-
-Card ether503 = {
- "3Com503", /* ident */
-
- reset, /* reset */
- 0, /* init */
- dp8390attach, /* attach */
- dp8390mode, /* mode */
-
- read, /* read */
- write, /* write */
-
- dp8390receive, /* receive */
- dp8390transmit, /* transmit */
- dp8390intr, /* interrupt */
- dp8390watch, /* watch */
- dp8390overflow, /* overflow */
-
- 0, /* io */
- 0, /* irq */
- 0, /* bit16 */
-
- 0, /* ram */
- 0, /* ramstart */
- 0, /* ramstop */
-
- 0, /* dp8390 */
- 0, /* data */
- 0, /* software bndry */
- RamOffset/Dp8390BufSz, /* tstart */
- (RamOffset+0x600)/Dp8390BufSz, /* pstart */
- (RamOffset+8*1024)/Dp8390BufSz, /* pstop */
-};
-
-void
-ether503link(void)
-{
- addethercard("3C503", ccc503reset);
-}
M pc/ether509.c => pc/ether509.c +112 -96
@@ 3,11 3,11 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
-#include "../port/error.h"
#include "io.h"
-#include "devtab.h"
+#include "../port/error.h"
+#include "../port/netif.h"
-#include "ether.h"
+#include "etherif.h"
enum {
IDport = 0x0100, /* anywhere between 0x0100 and 0x01F0 */
@@ 87,11 87,11 @@ enum {
#define COMMAND(port, cmd, a) outs(port+Command, ((cmd)<<11)|(a))
static void
-attach(Ctlr *ctlr)
+attach(Ether *ether)
{
ulong port;
- port = ctlr->card.port;
+ port = ether->port;
/*
* Set the receiver packet filter for our own and
* and broadcast addresses, set the interrupt masks
@@ 108,11 108,11 @@ attach(Ctlr *ctlr)
}
static void
-mode(Ctlr *ctlr, int on)
+promiscuous(void *arg, int on)
{
ulong port;
- port = ctlr->card.port;
+ port = ((Ether*)arg)->port;
if(on)
COMMAND(port, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr);
else
@@ 120,14 120,14 @@ mode(Ctlr *ctlr, int on)
}
static void
-receive(Ctlr *ctlr)
+receive(Ether *ether)
{
- ushort status;
- RingBuf *rb;
+ ushort status, type;
int len;
ulong port;
+ Netfile *f, **fp, **ep;
- port = ctlr->card.port;
+ port = ether->port;
while(((status = ins(port+RxStatus)) & RxEmpty) == 0){
/*
* If we had an error, log it and continue
@@ 137,47 137,44 @@ receive(Ctlr *ctlr)
switch(status & RxErrMask){
case RxErrOverrun: /* Overrrun */
- ctlr->overflows++;
+ ether->overflows++;
break;
case RxErrOversize: /* Oversize Packet (>1514) */
case RxErrRunt: /* Runt Packet */
- ctlr->buffs++;
+ ether->buffs++;
break;
case RxErrFraming: /* Alignment (Framing) */
- ctlr->frames++;
+ ether->frames++;
break;
case RxErrCRC: /* CRC */
- ctlr->crcs++;
+ ether->crcs++;
break;
}
}
else {
/*
- * We have a packet. Read it into the next
- * free ring buffer, if any.
- * The CRC is already stripped off.
+ * We have a packet. Read it into the
+ * buffer. The CRC is already stripped off.
+ * Must read len bytes padded to a
+ * doubleword. We can pick them out 16-bits
+ * at a time (can try 32-bits at a time
+ * later).
+ insl(port+Fifo, ether->rpkt, HOWMANY(len, 4));
+ */
+ len = (status & RxByteMask);
+ inss(port+Fifo, ðer->rpkt, HOWMANY(len, 2));
+
+ /*
+ * Copy the packet to whoever wants it.
*/
- rb = &ctlr->rb[ctlr->ri];
- if(rb->owner == Interface){
- len = (status & RxByteMask);
- rb->len = len;
-
- /*
- * Must read len bytes padded to a
- * doubleword. We can pick them out 16-bits
- * at a time (can try 32-bits at a time
- * later).
- insl(port+Fifo, rb->pkt, HOWMANY(len, 4));
- */
- inss(port+Fifo, rb->pkt, HOWMANY(len, 2));
-
- /*
- * Update the ring.
- */
- rb->owner = Host;
- ctlr->ri = NEXT(ctlr->ri, ctlr->nrb);
+ type = (ether->rpkt.type[0]<<8)|ether->rpkt.type[1];
+ ep = ðer->f[Ntypes];
+ for(fp = ether->f; fp < ep; fp++) {
+ f = *fp;
+ if(f && (f->type == type || f->type < 0))
+ qproduce(f->in, ðer->rpkt, len);
}
}
@@ 191,46 188,69 @@ receive(Ctlr *ctlr)
}
}
-static void
-transmit(Ctlr *ctlr)
+static int
+istxfifo(void *arg)
{
- RingBuf *tb;
+ Ether *ether;
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,
- * set up an interrupt for when space becomes available.
- * Output packet must be a multiple of 4 in length and
- * we need 4 bytes for the preamble.
- */
- len = ROUNDUP(tb->len, 4);
- if(len+4 > ins(port+TxFreeBytes)){
- COMMAND(port, SetTxAvailable, len);
- break;
- }
+ ether = arg;
+ port = ether->port;
+ /*
+ * If there's no room in the FIFO for this packet,
+ * set up an interrupt for when space becomes available.
+ * Output packet must be a multiple of 4 in length and
+ * we need 4 bytes for the preamble.
+ * Assume here that when we are called (via tsleep) that
+ * we are safe from interrupts.
+ */
+ len = ROUNDUP(ether->tlen, 4);
+ if(len+4 > ins(port+TxFreeBytes)){
+ COMMAND(port, SetTxAvailable, len);
+ return 0;
+ }
+ return 1;
+}
- /*
- * There's room, copy the packet to the FIFO and free
- * the buffer back to the host.
- */
- 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);
+static long
+write(Ether *ether, void *buf, long n)
+{
+ ushort len;
+ ulong port;
+
+print("W|");
+ port = ether->port;
+ ether->tlen = n;
+ len = ROUNDUP(ether->tlen, 4);
+ tsleep(ðer->tr, istxfifo, ether, 10000);
+ if(len+4 > ins(port+TxFreeBytes)){
+ print("ether509: transmitter jammed\n");
+ return 0;
}
+ /*
+ * We know there's room, copy the packet to the FIFO.
+ * To save copying the packet into a local buffer just
+ * so we can set the source address, stuff the packet
+ * into the FIFO in 3 pieces.
+ * Transmission won't start until the entire packet is
+ * in the FIFO, so it's OK to fault here.
+ */
+ outs(port+Fifo, ether->tlen);
+ outs(port+Fifo, 0);
+ outss(port+Fifo, buf, Eaddrlen/2);
+ outss(port+Fifo, ether->ea, Eaddrlen/2);
+ outss(port+Fifo, (uchar*)buf+2*Eaddrlen, (len-2*Eaddrlen)/2);
+ return n;
}
static ushort
-getdiag(Ctlr *ctlr)
+getdiag(Ether *ether)
{
ushort bytes;
ulong port;
- port = ctlr->card.port;
+ port = ether->port;
COMMAND(port, SelectWindow, 4);
bytes = ins(port+FIFOdiag);
COMMAND(port, SelectWindow, 1);
@@ 238,15 258,16 @@ getdiag(Ctlr *ctlr)
}
static void
-interrupt(Ctlr *ctlr)
+interrupt(Ether *ether)
{
ushort status, diag;
uchar txstatus, x;
ulong port;
- port = ctlr->card.port;
+ port = ether->port;
status = ins(port+Status);
+print("I%2.2ux|", status);
if(status & Failure){
/*
* Adapter failure, try to find out why.
@@ 255,28 276,25 @@ interrupt(Ctlr *ctlr)
* need to retransmit?
* This probably isn't right.
*/
- diag = getdiag(ctlr);
+ diag = getdiag(ether);
print("ether509: status #%ux, diag #%ux\n", status, diag);
if(diag & TxOverrun){
COMMAND(port, TxReset, 0);
COMMAND(port, TxEnable, 0);
+ wakeup(ðer->tr);
}
if(diag & RxUnderrun){
COMMAND(port, RxReset, 0);
- attach(ctlr);
+ attach(ether);
}
- if(diag & TxOverrun)
- transmit(ctlr);
-
return;
}
if(status & RxComplete){
- receive(ctlr);
- wakeup(&ctlr->rr);
+ receive(ether);
status &= ~RxComplete;
}
@@ 297,17 315,17 @@ interrupt(Ctlr *ctlr)
if(txstatus & (TxJabber|TxUnderrun))
COMMAND(port, TxReset, 0);
COMMAND(port, TxEnable, 0);
- ctlr->oerrs++;
+ ether->oerrs++;
}
if(status & (TxAvailable|TxComplete)){
/*
* Reset the Tx FIFO threshold.
*/
- if(status & TxAvailable)
+ if(status & TxAvailable){
COMMAND(port, AckIntr, TxAvailable);
- transmit(ctlr);
- wakeup(&ctlr->tr);
+ wakeup(ðer->tr);
+ }
status &= ~(TxAvailable|TxComplete);
}
@@ 317,7 335,7 @@ interrupt(Ctlr *ctlr)
* Otherwise, acknowledge the interrupt.
*/
if(status & AllIntr)
- panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(ctlr));
+ panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(ether));
COMMAND(port, AckIntr, Latch);
}
@@ 349,17 367,15 @@ idseq(void)
/*
* Get configuration parameters.
*/
-int
-ccc509reset(Ctlr *ctlr)
+static int
+reset(Ether *ether)
{
int i, ea;
ushort x, acr;
ulong port;
/*
- * 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.
+ * Do the little configuration dance:
*
* 2. get to command state, reset, then return to command state
*/
@@ 408,8 424,8 @@ ccc509reset(Ctlr *ctlr)
*
* Enable the adapter.
*/
- ctlr->card.port = (acr & 0x1F)*0x10 + 0x200;
- port = ctlr->card.port;
+ ether->port = (acr & 0x1F)*0x10 + 0x200;
+ port = ether->port;
outb(port+ConfigControl, 0x01);
/*
@@ 418,7 434,7 @@ ccc509reset(Ctlr *ctlr)
* The EEPROM command is 8bits, the lower 6 bits being
* the address offset.
*/
- ctlr->card.irq = (ins(port+ResourceConfig)>>12) & 0x0F;
+ ether->irq = (ins(port+ResourceConfig)>>12) & 0x0F;
for(ea = 0, i = 0; i < 3; i++, ea += 2){
while(ins(port+EEPROMcmd) & 0x8000)
;
@@ 426,8 442,8 @@ ccc509reset(Ctlr *ctlr)
while(ins(port+EEPROMcmd) & 0x8000)
;
x = ins(port+EEPROMdata);
- ctlr->ea[ea] = (x>>8) & 0xFF;
- ctlr->ea[ea+1] = x & 0xFF;
+ ether->ea[ea] = (x>>8) & 0xFF;
+ ether->ea[ea+1] = x & 0xFF;
}
/*
@@ 438,7 454,7 @@ ccc509reset(Ctlr *ctlr)
*/
COMMAND(port, SelectWindow, 2);
for(i = 0; i < 6; i++)
- outb(port+i, ctlr->ea[i]);
+ outb(port+i, ether->ea[i]);
/*
* Finished with window 2.
@@ 458,12 474,12 @@ ccc509reset(Ctlr *ctlr)
/*
* 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;
+ ether->attach = attach;
+ ether->write = write;
+ ether->interrupt = interrupt;
+
+ ether->promiscuous = promiscuous;
+ ether->arg = ether;
return 0;
}
@@ 471,5 487,5 @@ ccc509reset(Ctlr *ctlr)
void
ether509link(void)
{
- addethercard("3C509", ccc509reset);
+ addethercard("3C509", reset);
}
A pc/etherif.h => pc/etherif.h +29 -0
@@ 0,0 1,29 @@
+enum {
+ MaxEther = 4,
+ Ntypes = 8,
+};
+
+typedef struct Ether Ether;
+struct Ether {
+ ISAConf; /* hardware info */
+
+ void (*attach)(Ether*); /* filled in by reset routine */
+ long (*write)(Ether*, void*, long);
+ void (*interrupt)(Ether*);
+ void *private;
+
+ Etherpkt tpkt; /* transmit buffer */
+ Etherpkt rpkt; /* receive buffer */
+
+ QLock tlock; /* lock for grabbing transmitter queue */
+ Rendez tr; /* wait here for free xmit buffer */
+ long tlen; /* length of data in tb for txfifo management */
+
+ Netif;
+};
+
+#define NEXT(x, l) (((x)+1)%(l))
+#define HOWMANY(x, y) (((x)+((y)-1))/(y))
+#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
+
+extern void addethercard(char*, int(*)(Ether*));
M pc/fault386.c => pc/fault386.c +2 -1
@@ 24,7 24,7 @@ fault386(Ureg *ur)
read = !(ur->ecode & 2);
user = (ur->cs&0xffff) == UESEL;
spllo();
-/* print("F%d:A#%lux:U%d:R%d|", up->pid, addr, user, read);/**/
+/*print("F%d:A#%lux:U%d:R%d|", up->pid, addr, user, read);/**/
n = fault(addr, read);
if(n < 0){
if(user){
@@ 33,6 33,7 @@ fault386(Ureg *ur)
postnote(up, 1, buf, NDebug);
return;
}
+print("fault: 0x%lux", addr);
dumpregs(ur);
panic("fault: 0x%lux", addr);
}
M pc/fns.h => pc/fns.h +3 -0
@@ 63,6 63,7 @@ long pcmread(int, int, void*, long, ulong);
int pcmspecial(int);
void pcmspecialclose(int);
long pcmwrite(int, int, void*, long, ulong);
+void prflush(void);
void prhex(ulong);
void procrestore(Proc*);
void procsave(Proc*);
@@ 91,3 92,5 @@ void vgainit(void);
#define getcallerpc(x) (*(ulong*)(x))
#define KADDR(a) ((void*)((ulong)(a)|KZERO))
#define PADDR(a) ((ulong)(a)&~KZERO)
+
+void NS16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
M pc/kbd.c => pc/kbd.c +16 -16
@@ 115,11 115,6 @@ uchar kbtabesc1[] =
[0x58] No, No, No, No, No, No, No, No,
};
-/*
- * keyboard input q
- */
-KIOQ kbdq;
-
static int keybuttons;
static uchar ccc;
static int shift;
@@ 138,7 133,8 @@ enum
static void kbdintr(Ureg*);
static void ctps2intr(Ureg*);
-static int ps2mouseputc(IOQ*, int);
+
+extern int m3mouseputc(IOQ*, int);
/*
* wait for output no longer busy
@@ 246,6 242,8 @@ kbdinit(void)
{
int c;
+ kbdq = qopen(4*1024, 0, 0, 0);
+
setvec(Kbdvec, kbdintr);
bigcursor();
@@ 287,9 285,12 @@ serialmouse(int port, char *type, int setspeed)
error(Ebadarg);
/* set up /dev/eia0 as the mouse */
- uartspecial(port, 0, &mouseq, setspeed ? 1200 : 0);
+ if(setspeed)
+ setspeed = 1200;
if(type && *type == 'M')
- mouseq.putc = m3mouseputc;
+ NS16552special(port, setspeed, 0, 0, m3mouseputc);
+ else
+ NS16552special(port, setspeed, 0, 0, 0);
mousetype = Mouseserial;
}
@@ 390,14 391,13 @@ ps2mouse(void)
* shift & left button is the same as middle button
*/
static int
-ps2mouseputc(IOQ *q, int c)
+ps2mouseputc(int c)
{
static short msg[3];
static int nb;
static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 };
int buttons, dx, dy;
- USED(q); /* not */
/*
* check byte 0 for consistency
*/
@@ 508,7 508,7 @@ kbdintr0(void)
* if it's the mouse...
*/
if(s & Minready){
- ps2mouseputc(&mouseq, c);
+ ps2mouseputc(c);
return 0;
}
@@ 579,9 579,9 @@ kbdintr0(void)
putit:
lstate = 0;
if(c != -1)
- kbdputc(&kbdq, c);
+ kbdputc(kbdq, c);
else for(i=0; i<nk; i++)
- kbdputc(&kbdq, kc[i]);
+ kbdputc(kbdq, kc[i]);
break;
case 3:
case 4:
@@ 595,7 595,7 @@ kbdintr0(void)
nk = 5;
goto putit;
default:
- kbdputc(&kbdq, c);
+ kbdputc(kbdq, c);
break;
}
return 0;
@@ 618,7 618,7 @@ kbdintr0(void)
return 0;
}
}
- kbdputc(&kbdq, c);
+ kbdputc(kbdq, c);
return 0;
}
@@ 641,5 641,5 @@ ctps2intr(Ureg *ur)
if((c & Rready) == 0)
return;
c = inb(ctport + CTdata);
- ps2mouseputc(&mouseq, c);
+ ps2mouseputc(c);
}
M pc/l.s => pc/l.s +14 -0
@@ 498,6 498,18 @@ intrcommon:
ADDL $8,SP /* error code and trap type */
IRETL
+TEXT forkret(SB), $0
+ POPL AX
+ POPAL
+ NOP
+ POPL GS
+ POPL FS
+ POPL ES
+ POPL DS
+ NOP
+ ADDL $8,SP /* error code and trap type */
+ IRETL
+
intrscommon:
PUSHL DS
PUSHL ES
@@ 596,6 608,7 @@ TEXT config(SB),$0
OUTB
RET
+#ifdef notdef
/*
* copy bitmap changes to screen memory for ldepth 0 screen.
* reverse the bits since the screen is big-endian
@@ 706,6 719,7 @@ l20:
MOVB BX,-1(DI)(CX*1)
LOOP l20
RET
+#endif /* notdef */
/*
* The DP8390 ethernet chip needs some time between
M pc/main.c => pc/main.c +2 -4
@@ 92,8 92,6 @@ machinit(void)
m->mmask = 1<<m->machno;
}
-ulong garbage;
-
void
ksetterm(char *f)
{
@@ 292,7 290,7 @@ confinit(void)
pcnt = 0;
/*
- * parse configuration args from dos file p9rc
+ * parse configuration args from dos file plan9.ini
*/
cp = BOOTARGS; /* where b.com leaves its config */
cp[BOOTARGSLEN-1] = 0;
@@ 542,7 540,7 @@ exit(int ispanic)
up = 0;
print("exiting\n");
if(ispanic){
- if(cpuflag)
+ if(cpuserver)
delay(10000);
else
for(;;);
M pc/mmu.c => pc/mmu.c +31 -4
@@ 104,10 104,10 @@ struct
static void
taskswitch(ulong pagetbl, ulong stack)
{
- putcr3(pagetbl);
tss.ss0 = KDSEL;
tss.sp0 = stack;
tss.cr3 = pagetbl;
+ putcr3(pagetbl);
}
/*
@@ 166,11 166,11 @@ mmuinit(void)
*/
memset(&tss, 0, sizeof(tss));
taskswitch(ktoppg.pa, BY2PG + (ulong)m);
- puttr(TSSSEL);
+ puttr(TSSSEL);/**/
}
/*
- * Mark the mmu and tlb as inconsistent and call mapstack to fix it up.
+ * Mark the mmu and tlb as inconsistent and call mmuswitch to fix it up.
*/
void
flushmmu(void)
@@ 223,6 223,32 @@ mmuswitch(Proc *p)
taskswitch(ktoppg.pa, (ulong)(p->kstack+KSTACK));
}
+void
+simpleputpage(Page *pg)
+{
+ Rendez *r;
+
+ if(pg->ref != 1)
+ panic("simpleputpage");
+
+ pg->ref = 0;
+ if(palloc.head){
+ pg->next = palloc.head;
+ palloc.head->prev = pg;
+ }
+ else {
+ palloc.tail = pg;
+ pg->next = 0;
+ }
+ palloc.head = pg;
+ pg->prev = 0;
+
+ palloc.freecol[pg->color]++;
+ r = &palloc.r[pg->color];
+ if(r->p != 0)
+ wakeup(r);
+}
+
/*
* give all page table pages back to the free pool. This is called in sched()
* with palloc locked.
@@ 305,7 331,8 @@ putmmu(ulong va, ulong pa, Page *pg)
pt[BTMOFF(va)] = pa | PTEUSER;
/* flush cached mmu entries */
- taskswitch(up->mmutop->pa, (ulong)up->kstack);
+ /*taskswitch(up->mmutop->pa, (ulong)(up->kstack+KSTACK));/**/
+ putcr3(up->mmutop->pa);/**/
splx(s);
}
A pc/screen.c => pc/screen.c +309 -0
@@ 0,0 1,309 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#include <libg.h>
+#include <gnot.h>
+#include "screen.h"
+#include "vga.h"
+
+/*
+ * CGA-only hack.
+ */
+/* imported */
+extern GSubfont defont0;
+extern Cursor arrow;
+extern GBitmap cursorback;
+
+/* exported */
+GSubfont *defont;
+int islittle = 1; /* little endian bit ordering in bytes */
+GBitmap gscreen;
+
+/* local */
+static Lock vgalock;
+static ulong colormap[256][3];
+static Rectangle mbb;
+
+/*
+ * reverse pixels into little endian order
+ */
+uchar revtab0[] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+uchar revtab1[] = {
+ 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0,
+ 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0,
+ 0x04, 0x44, 0x84, 0xc4, 0x14, 0x54, 0x94, 0xd4,
+ 0x24, 0x64, 0xa4, 0xe4, 0x34, 0x74, 0xb4, 0xf4,
+ 0x08, 0x48, 0x88, 0xc8, 0x18, 0x58, 0x98, 0xd8,
+ 0x28, 0x68, 0xa8, 0xe8, 0x38, 0x78, 0xb8, 0xf8,
+ 0x0c, 0x4c, 0x8c, 0xcc, 0x1c, 0x5c, 0x9c, 0xdc,
+ 0x2c, 0x6c, 0xac, 0xec, 0x3c, 0x7c, 0xbc, 0xfc,
+ 0x01, 0x41, 0x81, 0xc1, 0x11, 0x51, 0x91, 0xd1,
+ 0x21, 0x61, 0xa1, 0xe1, 0x31, 0x71, 0xb1, 0xf1,
+ 0x05, 0x45, 0x85, 0xc5, 0x15, 0x55, 0x95, 0xd5,
+ 0x25, 0x65, 0xa5, 0xe5, 0x35, 0x75, 0xb5, 0xf5,
+ 0x09, 0x49, 0x89, 0xc9, 0x19, 0x59, 0x99, 0xd9,
+ 0x29, 0x69, 0xa9, 0xe9, 0x39, 0x79, 0xb9, 0xf9,
+ 0x0d, 0x4d, 0x8d, 0xcd, 0x1d, 0x5d, 0x9d, 0xdd,
+ 0x2d, 0x6d, 0xad, 0xed, 0x3d, 0x7d, 0xbd, 0xfd,
+ 0x02, 0x42, 0x82, 0xc2, 0x12, 0x52, 0x92, 0xd2,
+ 0x22, 0x62, 0xa2, 0xe2, 0x32, 0x72, 0xb2, 0xf2,
+ 0x06, 0x46, 0x86, 0xc6, 0x16, 0x56, 0x96, 0xd6,
+ 0x26, 0x66, 0xa6, 0xe6, 0x36, 0x76, 0xb6, 0xf6,
+ 0x0a, 0x4a, 0x8a, 0xca, 0x1a, 0x5a, 0x9a, 0xda,
+ 0x2a, 0x6a, 0xaa, 0xea, 0x3a, 0x7a, 0xba, 0xfa,
+ 0x0e, 0x4e, 0x8e, 0xce, 0x1e, 0x5e, 0x9e, 0xde,
+ 0x2e, 0x6e, 0xae, 0xee, 0x3e, 0x7e, 0xbe, 0xfe,
+ 0x03, 0x43, 0x83, 0xc3, 0x13, 0x53, 0x93, 0xd3,
+ 0x23, 0x63, 0xa3, 0xe3, 0x33, 0x73, 0xb3, 0xf3,
+ 0x07, 0x47, 0x87, 0xc7, 0x17, 0x57, 0x97, 0xd7,
+ 0x27, 0x67, 0xa7, 0xe7, 0x37, 0x77, 0xb7, 0xf7,
+ 0x0b, 0x4b, 0x8b, 0xcb, 0x1b, 0x5b, 0x9b, 0xdb,
+ 0x2b, 0x6b, 0xab, 0xeb, 0x3b, 0x7b, 0xbb, 0xfb,
+ 0x0f, 0x4f, 0x8f, 0xcf, 0x1f, 0x5f, 0x9f, 0xdf,
+ 0x2f, 0x6f, 0xaf, 0xef, 0x3f, 0x7f, 0xbf, 0xff,
+};
+uchar revtab2[] = {
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
+ 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
+ 0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1, 0xf1,
+ 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
+ 0x82, 0x92, 0xa2, 0xb2, 0xc2, 0xd2, 0xe2, 0xf2,
+ 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
+ 0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3, 0xe3, 0xf3,
+ 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
+ 0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4,
+ 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
+ 0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5,
+ 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
+ 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6,
+ 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
+ 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7,
+ 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
+ 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8,
+ 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
+ 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9,
+ 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a,
+ 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa,
+ 0x0b, 0x1b, 0x2b, 0x3b, 0x4b, 0x5b, 0x6b, 0x7b,
+ 0x8b, 0x9b, 0xab, 0xbb, 0xcb, 0xdb, 0xeb, 0xfb,
+ 0x0c, 0x1c, 0x2c, 0x3c, 0x4c, 0x5c, 0x6c, 0x7c,
+ 0x8c, 0x9c, 0xac, 0xbc, 0xcc, 0xdc, 0xec, 0xfc,
+ 0x0d, 0x1d, 0x2d, 0x3d, 0x4d, 0x5d, 0x6d, 0x7d,
+ 0x8d, 0x9d, 0xad, 0xbd, 0xcd, 0xdd, 0xed, 0xfd,
+ 0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e,
+ 0x8e, 0x9e, 0xae, 0xbe, 0xce, 0xde, 0xee, 0xfe,
+ 0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f,
+ 0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
+};
+
+void
+pixreverse(uchar *p, int len, int ldepth)
+{
+ uchar *e;
+ uchar *tab;
+
+ switch(ldepth){
+ case 0:
+ tab = revtab0;
+ break;
+ case 1:
+ tab = revtab1;
+ break;
+ case 2:
+ tab = revtab2;
+ break;
+ default:
+ return;
+ }
+
+ for(e = p + len; p < e; p++)
+ *p = tab[*p];
+}
+
+static void
+crout(int reg, int val)
+{
+ outb(CRX, reg);
+ outb(CR, val);
+}
+
+void
+screeninit(void)
+{
+ int i;
+ ulong *l;
+
+ /*
+ * arrow is defined as a big endian
+ */
+ pixreverse(arrow.set, 2*16, 0);
+ pixreverse(arrow.clr, 2*16, 0);
+
+ /*
+ * swizzle the font longs. we do both byte and bit swizzling
+ * since the font is initialized with big endian longs.
+ */
+ defont = &defont0;
+ l = defont->bits->base;
+ for(i = defont->bits->width*Dy(defont->bits->r); i > 0; i--, l++)
+ *l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24);
+ pixreverse((uchar*)defont->bits->base,
+ defont->bits->width*BY2WD*Dy(defont->bits->r), 0);
+
+ crout(0x0a, 0xff); /* turn off cursor */
+ memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT);
+}
+
+static void
+cgascreenputc(int c)
+{
+ int i;
+ static int color;
+ static int pos;
+
+ if(c == '\n'){
+ pos = pos/CGAWIDTH;
+ pos = (pos+1)*CGAWIDTH;
+ } else if(c == '\t'){
+ i = 8 - ((pos/2)&7);
+ while(i-->0)
+ cgascreenputc(' ');
+ } else if(c == '\b'){
+ if(pos >= 2)
+ pos -= 2;
+ cgascreenputc(' ');
+ pos -= 2;
+ } else {
+ CGASCREEN[pos++] = c;
+ CGASCREEN[pos++] = 2; /* green on black */
+ }
+ if(pos >= CGAWIDTH*CGAHEIGHT){
+ memmove(CGASCREEN, &CGASCREEN[CGAWIDTH], CGAWIDTH*(CGAHEIGHT-1));
+ memset(&CGASCREEN[CGAWIDTH*(CGAHEIGHT-1)], 0, CGAWIDTH);
+ pos = CGAWIDTH*(CGAHEIGHT-1);
+ }
+}
+
+void
+screenputs(char *s, int n)
+{
+ while(n-- > 0)
+ cgascreenputc(*s++);
+}
+
+/*
+ * collect changes to the 'soft' screen
+ */
+void
+mbbrect(Rectangle r)
+{
+ if (r.min.x < mbb.min.x)
+ mbb.min.x = r.min.x;
+ if (r.min.y < mbb.min.y)
+ mbb.min.y = r.min.y;
+ if (r.max.x > mbb.max.x)
+ mbb.max.x = r.max.x;
+ if (r.max.y > mbb.max.y)
+ mbb.max.y = r.max.y;
+ mousescreenupdate();
+}
+
+void
+hwcursset(ulong *s, ulong *c, int ox, int oy)
+{
+ USED(s, c, ox, oy);
+}
+
+void
+hwcursmove(int x, int y)
+{
+ USED(x, y);
+}
+
+void
+screenload(Rectangle r, uchar *data, int tl, int l)
+{
+ USED(r, data, tl, l);
+}
+
+void
+getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
+{
+ p &= (1<<(1<<gscreen.ldepth))-1;
+ lock(&vgalock);
+ *pr = colormap[p][0];
+ *pg = colormap[p][1];
+ *pb = colormap[p][2];
+ unlock(&vgalock);
+}
+
+void
+mousescreenupdate(void)
+{
+}
+
+/*
+ * a fatter than usual cursor for the safari
+ */
+Cursor fatarrow = {
+ { -1, -1 },
+ {
+ 0xff, 0xff, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0c,
+ 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
+ 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8c, 0x04,
+ 0x92, 0x08, 0x91, 0x10, 0xa0, 0xa0, 0xc0, 0x40,
+ },
+ {
+ 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf0,
+ 0x7f, 0xe0, 0x7f, 0xe0, 0x7f, 0xf0, 0x7f, 0xf8,
+ 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfc, 0x73, 0xf8,
+ 0x61, 0xf0, 0x60, 0xe0, 0x40, 0x40, 0x00, 0x00,
+ },
+};
+
+void
+bigcursor(void)
+{
+ memmove(&arrow, &fatarrow, sizeof(fatarrow));
+ pixreverse(arrow.set, 2*16, 0);
+ pixreverse(arrow.clr, 2*16, 0);
+}
M pc/trap.c => pc/trap.c +93 -33
@@ 219,6 219,7 @@ char *excname[] =
};
Ureg lasttrap, *lastur;
+Proc *lastup;
/*
@@ 234,10 235,17 @@ trap(Ureg *ur)
v = ur->trap;
- user = ((ur->cs)&0xffff)!=KESEL && v!=Syscallvec;
+ user = (ur->cs&0xffff) == UESEL;
if(user)
up->dbgreg = ur;
+ur->cs &= 0xffff;
+ur->ds &= 0xffff;
+ur->es &= 0xffff;
+ur->fs &= 0xffff;
+ur->gs &= 0xffff;
+if(user) ur->ss &= 0xffff;
+
/*
* tell the 8259 that we're done with the
* highest level interrupt (interrupts are still
@@ 253,6 261,7 @@ trap(Ureg *ur)
if(v>=256 || (h = halloc.ivec[v]) == 0){
lasttrap = *ur;
lastur = ur;
+lastup = up;
/* an old 386 generates these fairly often, no idea why */
if(v == 13)
return;
@@ 292,6 301,8 @@ lastur = ur;
splhi();
if(user && (up->procctl || up->nnote))
notify(ur);
+
+lastup = up;
lasttrap = *ur;
lastur = ur;
}
@@ 307,24 318,31 @@ dumpregs2(Ureg *ur)
else
print("registers for kernel\n");
print("FLAGS=%lux TRAP=%lux ECODE=%lux CS=%lux PC=%lux", ur->flags, ur->trap,
- ur->ecode, ur->cs&0xff, ur->pc);
- print(" SS=%lux USP=%lux\n", ur->ss&0xff, ur->usp);
+ ur->ecode, ur->cs, ur->pc);
+ print(" SS=%lux USP=%lux\n", ur->ss, ur->usp);
print(" AX %8.8lux BX %8.8lux CX %8.8lux DX %8.8lux\n",
ur->ax, ur->bx, ur->cx, ur->dx);
print(" SI %8.8lux DI %8.8lux BP %8.8lux\n",
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);
+ print(" DS %4.4lux ES %4.4lux FS %4.4lux GS %4.4lux\n",
+ ur->ds, ur->es, ur->fs, ur->gs);
}
void
dumpregs(Ureg *ur)
{
+ ulong *x;
+
+ x = (ulong*)(ur+1);
dumpregs2(ur);
- print(" ur %lux\n", ur);
+ print(" magic %lux %lux %lux\n", x[0], x[1], x[2]);
+ print(" ur %lux up %lux\n", ur, up);
dumpregs2(&lasttrap);
- print(" lastur %lux\n", lastur);
+ print(" lastur %lux lastup %lux\n", lastur);
+splhi();
+dumpstack();
+for(;;);
}
void
@@ 332,49 350,28 @@ dumpstack(void)
{
ulong l, v, i;
extern ulong etext;
+ int lim;
if(up == 0)
return;
i = 0;
- for(l=(ulong)&l; l<(ulong)(up->kstack+BY2PG); l+=4){
+ lim = 3;
+ for(l=(ulong)&l; l<(ulong)(up->kstack+BY2PG) && lim; l+=4){
v = *(ulong*)l;
if(KTZERO < v && v < (ulong)&etext){
print("%lux ", v);
i++;
}
- if(i == 4){
+ if(i == 8){
i = 0;
print("\n");
+ lim--;
}
}
}
-long
-execregs(ulong entry, ulong ssize, ulong nargs)
-{
- ulong *sp;
- Ureg *ur;
-
- sp = (ulong*)(USTKTOP - ssize);
- *--sp = nargs;
-
- ur = up->dbgreg;
- ur->usp = (ulong)sp;
- ur->pc = entry;
- return USTKTOP-BY2WD; /* address of user-level clock */
-}
-
-ulong
-userpc(void)
-{
- Ureg *ur;
-
- ur = (Ureg*)up->dbgreg;
- return ur->pc;
-}
-
/*
* system calls
*/
@@ 573,6 570,30 @@ noted(Ureg *ur, ulong arg0)
}
}
+long
+execregs(ulong entry, ulong ssize, ulong nargs)
+{
+ ulong *sp;
+ Ureg *ur;
+
+ sp = (ulong*)(USTKTOP - ssize);
+ *--sp = nargs;
+
+ ur = up->dbgreg;
+ ur->usp = (ulong)sp;
+ ur->pc = entry;
+ return USTKTOP-BY2WD; /* address of user-level clock */
+}
+
+ulong
+userpc(void)
+{
+ Ureg *ur;
+
+ ur = (Ureg*)up->dbgreg;
+ return ur->pc;
+}
+
/* This routine must save the values of registers the user is not permitted to write
* from devproc and the restore the saved values before returning
*/
@@ 592,6 613,45 @@ setregisters(Ureg *xp, char *pureg, char *uva, int n)
xp->ss = ss;
}
+static void
+linkproc(void)
+{
+ spllo();
+ (*up->kpfun)(up->kparg);
+}
+
+void
+kprocchild(Proc *p, void (*func)(void*), void *arg)
+{
+ p->sched.pc = (ulong)linkproc;
+ p->sched.sp = (ulong)p->kstack+KSTACK;
+
+ p->kpfun = func;
+ p->kparg = arg;
+}
+
+void
+forkchild(Proc *p, Ureg *ur)
+{
+ Ureg *cur;
+
+ /*
+ * We add 2*BY2Wd to the stack because we have to account for
+ * - the return PC
+ * - trap's argument (ur)
+ */
+ p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
+ p->sched.pc = (ulong)forkret;
+
+ cur = (Ureg*)(p->sched.sp+2*BY2WD);
+ memmove(cur, ur, sizeof(Ureg));
+ cur->ax = 0; /* return value of syscall in child */
+
+ /* Things from bottom of syscall we never got to execute */
+ p->psstate = 0;
+ p->insyscall = 0;
+}
+
/* Give enough context in the ureg to produce a kernel stack for
* a sleeping process
*/
D pc/ultrastor.c => pc/ultrastor.c +0 -484
@@ 1,484 0,0 @@
-/*
- * 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; i<m->cmdlen; 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; i<m->nscatter; 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; i<Nmbox; i++){
- m = &ctlr->mbox[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;
-}