M pc/devfloppy.c => pc/devfloppy.c +7 -0
@@ 367,6 367,7 @@ static void
floppykproc(void *a)
{
Drive *dp;
+ int disp = 0;
waserror();
for(;;){
@@ 378,7 379,13 @@ floppykproc(void *a)
qunlock(dp);
}
}
+ disp++;
+ if(owl(disp&1) < 0)
+ print("owl failed\n");
+ if(mail((disp>>1)&1) < 0)
+ print("mail failed\n");
tsleep(&floppy.kr, return0, 0, 5*1000);
+
}
}
M pc/devhard.c => pc/devhard.c +25 -2
@@ 116,6 116,10 @@ Dirtab harddir[]={
};
#define NHDIR (sizeof(harddir)/sizeof(Dirtab))
+static void hardintr(Ureg*);
+static long hardxfer(Drive*, int, void*, long, long);
+static long hardident(Drive*);
+
void
hardreset(void)
{
@@ 213,6 217,8 @@ hardread(Chan *c, void *a, long n)
break;
case Qstruct:
hardident(dp);
+ dp->cap = 512 * dp->id->lcyls * dp->id->lheads *dp->id->ls2t;
+ dp->bytes = 512;
if (n < 2*sizeof(ulong))
error(Ebadarg);
if (c->offset >= 2*sizeof(ulong))
@@ 257,7 263,7 @@ hardwrite(Chan *c, void *a, long n)
* did an interrupt happen?
*/
static int
-interrupted(Drive *dp)
+interrupted(void *a)
{
return hard.intr;
}
@@ 265,16 271,33 @@ interrupted(Drive *dp)
/*
* get parameters from the drive
*/
+static long
hardident(Drive *dp)
{
+ qlock(&hard);
hard.intr = 0;
outb(Pdh, dp->dev<<4);
outb(Pcmd, Cident);
+ sleep(&hard.r, interrupted, 0);
+ insw(Pdata, &hard.id, 512);
+ qunlock(&hard);
}
-long
+static long
hardxfer(Drive *dp, int cmd, void *va, long off, long len)
{
errors("not implemented");
}
+/*
+ * take/clear a disk interrupt
+ */
+static void
+hardintr(Ureg *ur)
+{
+ hard.status = inb(Pstatus);
+ hard.intr = 1;
+ print("hardintr\n");
+ wakeup(&hard.r);
+}
+
M pc/devuart.c => pc/devuart.c +15 -7
@@ 37,7 37,7 @@ enum
Loop= (1<<4), /* loop bask */
Lstat= 5, /* line status */
Inready=(1<<0), /* receive buffer full */
- Outbusy=(1<<5), /* output buffer full */
+ Outready=(1<<5), /* output buffer full */
Mstat= 6, /* modem status */
Scratch=7, /* scratchpad */
Dlsb= 0, /* divisor lsb */
@@ 88,7 88,7 @@ uartsetbaud(Uart *up, int rate)
{
ulong brconst;
- brconst = (UartFREQ+8*rate-1)/16*rate;
+ brconst = (UartFREQ+8*rate-1)/(16*rate);
uartwrreg(up, Format, Dra);
uartwrreg(up, Dmsb, (brconst>>8) & 0xff);
@@ 178,6 178,7 @@ uartputs(IOQ *cq, char *s, int n)
{
Uart *up = cq->ptr;
int st, ch, x;
+ int tries;
x = splhi();
lock(cq);
@@ 187,7 188,8 @@ uartputs(IOQ *cq, char *s, int n)
print("<start %2.2ux>", ch);/**/
if(ch >= 0){
up->printing = 1;
- while(uartrdreg(up, Lstat) & Outbusy)
+ for(tries = 0; tries<10000 && !(uartrdreg(up, Lstat)&Outready);
+ tries++)
;
outb(up->port + Data, ch);
}
@@ 202,11 204,13 @@ print("<start %2.2ux>", ch);/**/
void
uartintr(Uart *up)
{
- int s;
int ch;
IOQ *cq;
+ int s;
- switch(uartrdreg(up, Istat)){
+ s = uartrdreg(up, Istat);
+print("uartintr %lux\n", s);
+ switch(s){
case 3:
/*
* get any input characters
@@ 227,10 231,11 @@ uartintr(Uart *up)
/*
* send next output character
*/
- if((s & Outbusy)==0){
+ if(uartrdreg(up, Lstat)&Outready){
cq = up->oq;
lock(cq);
ch = getc(cq);
+print("<cont %2.2ux>", ch);/**/
if(ch < 0){
up->printing = 0;
wakeup(&cq->r);
@@ 270,6 275,7 @@ uartenable(Uart *up)
up->iq->ptr = up;
up->sticky[Iena] |= Ircv;
}
+ up->sticky[Iena] |= (1<<2) | (1<<3);
/*
* turn on interrupts
@@ 465,7 471,6 @@ uartkproc(void *a)
loop:
while ((n = cangetc(cq)) == 0){
-print("uart0 sleeping/n");
sleep(&cq->r, cangetc, cq);
}
qlock(up);
@@ 506,6 511,9 @@ uartreset(void)
{
Uart *up;
+ if(serial(0) < 0)
+ print("can't turn on power\n");
+
uartsetup();
for(up = uart; up < &uart[2]; up++){
if(up->nostream)
A pc/dma.c => pc/dma.c +173 -0
@@ 0,0 1,173 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+/*
+ * headland chip set for the safari.
+ */
+typedef struct DMAport DMAport;
+typedef struct DMA DMA;
+typedef struct DMAxfer DMAxfer;
+
+enum
+{
+ /*
+ * the byte registers for DMA0 are all one byte apart
+ */
+ Dma0= 0x00,
+ Dma0status= Dma0+0x8, /* status port */
+ Dma0reset= Dma0+0xD, /* reset port */
+
+ /*
+ * the byte registers for DMA1 are all two bytes apart (why?)
+ */
+ Dma1= 0xC0,
+ Dma1status= Dma1+2*0x8, /* status port */
+ Dma1reset= Dma1+2*0xD, /* reset port */
+};
+
+/*
+ * state of a dma transfer
+ */
+struct DMAxfer
+{
+ Page *pg; /* page used by dma */
+ void *va; /* virtual address destination/src */
+ long len; /* bytes to be transferred */
+ int isread;
+};
+
+/*
+ * the dma controllers. the first half of this structure specifies
+ * the I/O ports used by the DMA controllers.
+ */
+struct DMAport
+{
+ uchar addr[4]; /* current address (4 channels) */
+ uchar count[4]; /* current count (4 channels) */
+ uchar page[4]; /* page registers (4 channels) */
+ uchar cmd; /* command status register */
+ uchar req; /* request registers */
+ uchar sbm; /* single bit mask register */
+ uchar mode; /* mode register */
+ uchar cbp; /* clear byte pointer */
+ uchar mc; /* master clear */
+ uchar cmask; /* clear mask register */
+ uchar wam; /* write all mask register bit */
+
+ Lock;
+};
+
+struct DMA
+{
+ DMAport;
+ Lock;
+ DMAxfer x[4];
+};
+
+DMA dma[2] = {
+ { 0x00, 0x02, 0x04, 0x06,
+ 0x01, 0x03, 0x05, 0x07,
+ 0x87, 0x83, 0x81, 0x82,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+ { 0xc0, 0xc6, 0xca, 0xce,
+ 0xc4, 0xc8, 0xcc, 0xcf,
+ 0x80, 0x8b, 0x89, 0x8a,
+ 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde },
+};
+
+/*
+ * setup a dma transfer. if the destination is not in kernel
+ * memory, allocate a page for the transfer.
+ *
+ * we assume BIOS has set up the command register before we
+ * are booted.
+ *
+ * return the updated transfer length (we can't transfer across 64k
+ * boundaries)
+ */
+long
+dmasetup(int chan, void *va, long len, int isread)
+{
+ DMA *dp;
+ DMAxfer *xp;
+ ulong pa;
+ uchar mode;
+
+ dp = &dma[(chan>>2)&1];
+ chan = chan & 3;
+ xp = &dp->x[chan];
+
+ /*
+ * if this isn't kernel memory (or crossing 64k boundary),
+ * allocate a page for the DMA.
+ */
+ pa = ((ulong)va) & ~KZERO;
+ if(!isphys(va) || (pa&0xFFFF0000)!=((pa+len)&0xFFFF0000)){
+ xp->pg = newpage(1, 0, 0);
+ if(len > BY2PG)
+ len = BY2PG;
+ if(!isread)
+ memmove((void*)(KZERO|xp->pg->pa), va, len);
+ xp->va = va;
+ xp->len = len;
+ xp->isread = isread;
+ pa = xp->pg->pa;
+ }
+
+ /*
+ * this setup must be atomic
+ */
+ lock(dp);
+ outb(dp->cbp, 0); /* set count & address to their first byte */
+ mode = (isread ? 0x44 : 0x48) | chan;
+ outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */
+ outb(dp->addr[chan], pa); /* set address */
+ outb(dp->addr[chan], pa>>8);
+ outb(dp->page[chan], pa>>16);
+ outb(dp->count[chan], len-1); /* set count */
+ outb(dp->count[chan], (len-1)>>8);
+ outb(dp->sbm, chan); /* enable the channel */
+ unlock(dp);
+
+ return len;
+}
+
+/*
+ * this must be called after a dma has been completed.
+ *
+ * if a page has been allocated for the dma,
+ * copy the data into the actual destination
+ * and free the page.
+ */
+void
+dmaend(int chan)
+{
+ DMA *dp;
+ DMAxfer *xp;
+ ulong addr;
+ uchar mode;
+
+ dp = &dma[(chan>>2)&1];
+ chan = chan & 3;
+
+ /*
+ * disable the channel
+ */
+ lock(dp);
+ outb(dp->sbm, 4|chan);
+ unlock(dp);
+
+ xp = &dp->x[chan];
+ if(xp->pg == 0)
+ return;
+
+ /*
+ * copy out of temporary page
+ */
+ memmove(xp->va, (void*)(KZERO|xp->pg->pa), xp->len);
+ putpage(xp->pg);
+ xp->pg = 0;
+}
M pc/fns.h => pc/fns.h +3 -0
@@ 16,6 16,8 @@ void fprestore(FPsave*);
ulong getcr2(void);
void idle(void);
int inb(int);
+int inss(int, void*, int);
+int outss(int, void*, int);
void kbdinit(void);
void kbdintr(Ureg*);
void mmuinit(void);
@@ 31,6 33,7 @@ void puttr(ulong);
void screeninit(void);
void screenputc(int);
void screenputs(char*, int);
+int serial(int);
void setvec(int, void (*)(Ureg*));
void systrap(void);
void touser(void);
M pc/kbd.c => pc/kbd.c +52 -25
@@ 240,35 240,64 @@ latin1(int k1, int k2)
return 0;
}
-static void
-mousecmd(int cmd, int arg)
+/*
+ * wait for output no longer busy
+ */
+static int
+outready(void)
+{
+ int tries;
+
+ for(tries = 0; (inb(Status) & Outbusy); tries++)
+ if(tries > 1000)
+ return -1;
+ return 0;
+}
+
+/*
+ * wait for input
+ */
+static int
+inready(void)
+{
+ int tries;
+
+ for(tries = 0; !(inb(Status) & Inready); tries++)
+ if(tries > 1000)
+ return -1;
+ return 0;
+}
+
+/*
+ * send a command to the mouse
+ */
+static int
+mousecmd(int cmd)
{
unsigned int c;
+ int tries;
- do {
- while(inb(Status) & Outbusy)
- ;
+ for(tries=0; tries < 10; tries++){
+ if(outready() < 0)
+ return -1;
outb(Cmd, 0xD4);
- while(inb(Status) & Outbusy)
- ;
+ if(outready() < 0)
+ return -1;
outb(Data, cmd);
- if(arg >= 0){
- while(inb(Status) & Outbusy)
- ;
- outb(Data, arg);
- }
- while(!(inb(Status) & Inready))
- ;
+ if(inready() < 0)
+ return -1;
c = inb(Data);
} while(c == 0xFE);
if(c != 0xFA)
- print("mouse command returns bad status %lux", c);
+ return -1;
+ return 0;
}
void
kbdinit(void)
{
int c, s;
+ int tries;
initq(&kbdq);
setvec(Kbdvec, kbdintr);
@@ 282,19 311,17 @@ kbdinit(void)
/* enable kbd/mouse xfers and interrupts */
outb(Cmd, 0x60);
- while(inb(Status) & Outbusy)
- ;
+ if(outready() < 0)
+ print("kbd init failed\n");
outb(Data, 0x47);
- while(inb(Status) & Outbusy)
- ;
+ if(outready() < 0)
+ print("kbd init failed\n");
outb(Cmd, 0xA8);
- /* make mouse streaming (and enabled) */
- mousecmd(0xEA, -1);
- mousecmd(0xF4, -1);
-
- /* resolution */
-/* mousecmd(0xE8, 0x03); /**/
+ /* make mouse streaming, enabled */
+ if(mousecmd(0xEA) < 0
+ || mousecmd(0xF4) < 0)
+ print("can't initialize mouse\n");
}
/*
M pc/main.c => pc/main.c +117 -0
@@ 265,3 265,120 @@ void
lights(int val)
{
}
+
+
+/*
+ * special stuff for 80c51 power management and headland system controller
+ */
+enum
+{
+ /*
+ * system control port
+ */
+ Head= 0x92, /* control port */
+ Reset= (1<<0), /* reset the 386 */
+ A20ena= (1<<1), /* enable address line 20 */
+
+ /*
+ * power management unit ports
+ */
+ Pmudata= 0x198,
+
+ Pmucsr= 0x199,
+ Busy= 0x1,
+};
+
+/*
+ * enable address bit 20
+ */
+void
+a20enable(void)
+{
+ outb(Head, A20ena);
+}
+
+/*
+ * reset the chip
+ */
+void
+exit(void)
+{
+ int i;
+
+ u = 0;
+ print("exiting\n");
+ outb(Head, Reset);
+}
+
+/*
+ * return when pmu ready
+ */
+static int
+pmuready(void)
+{
+ int tries;
+
+ for(tries = 0; (inb(Pmucsr) & Busy); tries++)
+ if(tries > 1000)
+ return -1;
+ return 0;
+}
+
+/*
+ * return when pmu busy
+ */
+static int
+pmubusy(void)
+{
+ int tries;
+
+ for(tries = 0; !(inb(Pmucsr) & Busy); tries++)
+ if(tries > 1000)
+ return -1;
+ return 0;
+}
+
+/*
+ * set a bit in the PMU
+ */
+int
+pmuwrbit(int index, int bit, int pos)
+{
+ outb(Pmucsr, 0x02); /* next is command request */
+ if(pmuready() < 0)
+ return -1;
+ outb(Pmudata, (2<<4) | index); /* send write bit command */
+ outb(Pmucsr, 0x01); /* send available */
+ if(pmubusy() < 0)
+ return -1;
+ outb(Pmucsr, 0x01); /* next is data */
+ if(pmuready() < 0)
+ return -1;
+ outb(Pmudata, (bit<<3) | pos); /* send bit to write */
+ outb(Pmucsr, 0x01); /* send available */
+ if(pmubusy() < 0)
+ return -1;
+}
+
+/*
+ * control power to the serial line
+ * onoff == 0 means turn power on
+ * onoff == 1 means off
+ */
+int
+serial(int onoff)
+{
+ return pmuwrbit(1, onoff, 6);
+}
+
+int
+owl(int onoff)
+{
+ return pmuwrbit(0, onoff, 4);
+}
+
+int
+mail(int onoff)
+{
+ return pmuwrbit(0, onoff, 1);
+}
M pc/trap.c => pc/trap.c +1 -1
@@ 35,7 35,7 @@ enum
};
int int0mask = 0xff; /* interrupts enabled for first 8259 */
-int int1mask = 0xff; /* interrupts enabled for second 8259 */
+int int1mask = 0xff; /* interrupts enabled for second 8259 */
/*
* trap/interrupt gates
M port/segment.c => port/segment.c +2 -1
@@ 438,7 438,8 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
ns = u->p->seg[i];
if(ns == 0)
continue;
- if(newtop >= ns->base && newtop < ns->top)
+ if((newtop > ns->base && newtop <= ns->top) ||
+ (va >= ns->base && va < ns->top))
errors("segments overlap");
}
M power/conf.h => power/conf.h +1 -0
@@ 3,6 3,7 @@ Conftab conftab[] = {
{"nproc", &conf.nproc },
{"npgrp", &conf.npgrp },
{"npage0", &conf.npage0 },
+ {"npage1", &conf.npage1 },
{"npage", &conf.npage },
{"nseg", &conf.nseg },
{"nimage", &conf.nimage },
M power/dat.h => power/dat.h +1 -0
@@ 40,6 40,7 @@ struct Conf
ulong nproc; /* processes */
ulong npgrp; /* process groups */
ulong npage0; /* total physical pages of memory */
+ ulong npage1; /* total physical pages of memory */
ulong npage; /* total physical pages of memory */
ulong nseg; /* number of segments */
ulong nimage; /* number of page cache image headers */
M power/main.c => power/main.c +2 -0
@@ 539,6 539,8 @@ confinit(void)
conf.npage0 = i*1024/4;
conf.base0 = 0;
conf.npage = conf.npage0;
+ conf.npage1 = 0;
+ conf.base1 = 0;
conf.maxialloc = (128*1024*1024-256*1024-BY2PG);
/*