From de239c022b3f82273d466a6bac40147188e92793 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 5 Oct 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-10-05 --- carrera/kbd.c | 10 +- carrera/main.c | 9 +- carrera/mem.h | 2 +- carrera/screen.c | 189 ++--- ip/ip.c | 16 +- pc/cga.c | 33 +- pc/devlml.c | 8 - pc/devusb.c | 1934 +++++++++++++++++++++++++++++++++++++++++++++ pc/devvga.c | 164 ++-- pc/kbd.c | 18 +- pc/screen.c | 331 ++++++-- pc/screen.h | 22 +- pc/vga.c | 70 +- pc/vgaark2000pv.c | 12 +- pc/vgacyber938x.c | 4 +- pc/vgamach64xx.c | 403 +++++++++- pc/vgas3.c | 222 +++++- port/devaudio.c | 54 +- port/devcons.c | 18 +- port/devdraw.c | 257 ++++-- port/devmouse.c | 23 +- port/portfns.h | 3 +- 22 files changed, 3327 insertions(+), 475 deletions(-) create mode 100644 pc/devusb.c diff --git a/carrera/kbd.c b/carrera/kbd.c index 5b6de0037b324c750649de15812e5204f559cad4..dd49082f50794a7b16d77a6fd14b0754395746ce 100644 --- a/carrera/kbd.c +++ b/carrera/kbd.c @@ -47,7 +47,7 @@ enum PF= Spec|0x20, /* num pad function key */ View= Spec|0x00, /* view (shift window up) */ - KF= Spec|0x40, /* function key */ + KF= 0xF000, /* function key (begin Unicode private space) */ Shift= Spec|0x60, Break= Spec|0x61, Ctrl= Spec|0x62, @@ -76,7 +76,7 @@ enum #define INWAIT while(!(KBDCTL & Sobf)); kdbdly(1) #define ACKWAIT INWAIT ; if(KBDDAT != Rack) print("bad response\n"); kdbdly(1) -uchar kbtab[] = +Rune kbtab[] = { [0x00] No, 0x1b, '1', '2', '3', '4', '5', '6', [0x08] '7', '8', '9', '0', '-', '=', '\b', '\t', @@ -92,7 +92,7 @@ uchar kbtab[] = [0x58] KF|12, No, No, No, No, No, No, No, }; -uchar kbtabshift[] = +Rune kbtabshift[] = { [0x00] No, 0x1b, '!', '@', '#', '$', '%', '^', [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t', @@ -108,7 +108,7 @@ uchar kbtabshift[] = [0x58] KF|12, No, No, No, No, No, No, No, }; -uchar kbtabesc1[] = +Rune kbtabesc1[] = { [0x00] No, No, No, No, No, No, No, No, [0x08] No, No, No, No, No, No, No, No, @@ -199,7 +199,7 @@ kbdintr(void) static int ctl; static int num; static int collecting, nk; - static uchar kc[5]; + static Rune kc[5]; static int shift; int keyup; diff --git a/carrera/main.c b/carrera/main.c index 5500ada71f266d437c84609ad897ab05484f2853..7caccc03941c159842eddcdfabb896d4cfaabdd6 100644 --- a/carrera/main.c +++ b/carrera/main.c @@ -38,10 +38,12 @@ int int1mask = 0xff; /* interrupts enabled for second 8259 */ extern uchar rdbgcode[]; extern ulong rdbglen; +extern int noprint; void main(void) { + noprint = 1; tlbinit(); ioinit(1); /* Very early to establish IO mappings */ rdbginit(); @@ -54,10 +56,10 @@ main(void) iomapinit(); printinit(); serialinit(); + iprint("Brazil\n"); /**/ vecinit(); screeninit(); -/* iprint("\n\nBrazil\n"); /**/ - print("Brazil config reg %#ux\n", configreg); +// print("Brazil config reg %#ux\n", configreg); pageinit(); procinit0(); initseg(); @@ -65,6 +67,7 @@ main(void) chandevreset(); swapinit(); userinit(); + noprint = 0; schedinit(); } @@ -430,7 +433,7 @@ exit(int type) splhi(); if(type == 1) - for(;;); + rdb(); /* Turn off the NMI hander for the debugger */ vec = (uchar*)0xA0000420; diff --git a/carrera/mem.h b/carrera/mem.h index db8b3a9cf3a497128c0803429cfa1e12b28ed0b1..ca9da356fcea5115e58dca3adb2885d77664c9a8 100644 --- a/carrera/mem.h +++ b/carrera/mem.h @@ -23,7 +23,7 @@ /* * Time */ -#define HZ 1000 /* clock frequency */ +#define HZ 100 /* clock frequency */ #define MS2HZ (1000/HZ) /* millisec per clock tick */ #define TK2SEC(t) ((t)/HZ) /* ticks to seconds */ #define TK2MS(t) ((t)*MS2HZ) /* ticks to milliseconds */ diff --git a/carrera/screen.c b/carrera/screen.c index 58f8f5292604125fa5531ba90f5635de2f62297b..32d1a97f662269c3ff0f4403f7abbdea07b48930 100644 --- a/carrera/screen.c +++ b/carrera/screen.c @@ -30,7 +30,7 @@ struct Dac }; char s1[] = { 0x00, 0x00, 0xC0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -#define Backgnd 0x00 +#define Backgnd 0xFF /* white */ Memsubfont *memdefont; static ulong rep(ulong, int); @@ -44,8 +44,6 @@ Lock screenlock; Point ZP = {0, 0}; -static Memdata hwcursordata; - static Memdata gscreendata = { nil, @@ -53,96 +51,25 @@ static Memdata gscreendata = 1, }; -Memimage gscreen = +static Memimage xgscreen = { { 0, 0, 1597, 1234 }, /* r */ { 0, 0, 1597, 1234 }, /* clipr */ - 3, /* ldepth */ - 0, /* repl */ + 8, /* depth */ + 1, /* nchan */ + CMAP8, /* chan */ + nil, /* cmap */ &gscreendata, /* data */ 0, /* zero */ 512, /* width */ 0, /* layer */ + Frepl, /* flags */ }; -static Memimage hwcursor= -{ - {0, 0, 64, 64}, - {0, 0, 64, 64}, - 1, - 0, - &hwcursordata, /* base filled in by malloc when needed */ - 0, - 4, - 0, -}; - -ulong consbits = ~0; -Memdata consdata = { - nil, - &consbits -}; -Memimage conscol = -{ - { 0, 0, 1, 1 }, - { -100000, -100000, 100000, 100000 }, - 3, - 1, - &consdata, - 0, - 1 -}; - -ulong onesbits = ~0; -Memdata onesdata = { - nil, - &onesbits, -}; -Memimage xones = -{ - { 0, 0, 1, 1 }, - { -100000, -100000, 100000, 100000 }, - 3, - 1, - &onesdata, - 0, - 1 -}; -Memimage *memones = &xones; - -ulong zerosbits = 0; -Memdata zerosdata = { - nil, - &zerosbits, -}; -Memimage xzeros = -{ - { 0, 0, 1, 1 }, - { -100000, -100000, 100000, 100000 }, - 3, - 1, - &zerosdata, - 0, - 1 -}; -Memimage *memzeros = &xzeros; - -ulong backbits = (Backgnd<<24)|(Backgnd<<16)|(Backgnd<<8)|Backgnd; -Memdata backdata = { - nil, - &backbits -}; -Memimage xback = -{ - { 0, 0, 1, 1 }, - { -100000, -100000, 100000, 100000 }, - 3, - 1, - &backdata, - 0, - 1 -}; -Memimage *back = &xback; +Memimage *gscreen; +Memimage *conscol; +Memimage *back; +Memimage *hwcursor; Cursor arrow = { { -1, -1 }, @@ -161,19 +88,27 @@ Cursor arrow = { static Rectangle window; static Point curpos; static int h, w; +int drawdebug; void screenwin(void) { Dac *d; Point p, q; - int y; Cursor zero; char *greet; + Memimage *grey; + + gscreen = &xgscreen; + memsetchan(gscreen, CMAP8); + hwcursor = allocmemimage(Rect(0,0,64,64), GREY2); + memsetchan(hwcursor, GREY2); + + back = memwhite; + conscol = memblack; - memset((void*)Screenvirt, 0xff, 3*1024*1024); - for(y=gscreen.r.min.y; yinfo[' '].width; h = memdefont->height; @@ -181,20 +116,24 @@ screenwin(void) window.min = Pt(100, 100); window.max = addpt(window.min, Pt(10+w*120, 10+h*60)); - memimagedraw(&gscreen, window, memones, ZP, memones, ZP); + memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP); window = insetrect(window, 4); - memimagedraw(&gscreen, window, back, ZP, memones, ZP); - /* hack to get a grey color */ - memzeros->data->data[0] = 0x33333333; - memimagedraw(&gscreen, Rect(window.min.x, window.min.y, - window.max.x, window.min.y+h+5+6), memzeros, ZP, memones, ZP); - memzeros->data->data[0] = 0; + memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP); + + /* a lot of work to get a grey color */ + grey = allocmemimage(Rect(0,0,1,1), CMAP8); + grey->flags |= Frepl; + grey->clipr = gscreen->r; + grey->data->bdata[0] = 0xAA; + memimagedraw(gscreen, Rect(window.min.x, window.min.y, + window.max.x, window.min.y+h+5+6), grey, ZP, nil, ZP); + freememimage(grey); window = insetrect(window, 5); - greet = " Brazil Console: Draw version "; + greet = " Brazil Console: New Draw version "; p = addpt(window.min, Pt(10, 0)); q = memsubfontwidth(memdefont, greet); - memimagestring(&gscreen, p, &conscol, memdefont, greet); + memimagestring(gscreen, p, conscol, memdefont, greet); window.min.y += h+6; curpos = window.min; window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h; @@ -254,7 +193,7 @@ dacinit(void) for(i = 0; i < 0x400; i++) d->cr2 = 0xff; - drawcmap(0); + drawcmap(1); /* Overlay Palette Ram */ d->cr0 = 0x00; @@ -280,6 +219,7 @@ screeninit(void) { dacinit(); + memimageinit(); memdefont = getmemdefont(); out.pos.x = MINX; @@ -299,9 +239,9 @@ scroll(void) o = 8*h; r = Rpt(window.min, Pt(window.max.x, window.max.y-o)); p = Pt(window.min.x, window.min.y+o); - memimagedraw(&gscreen, r, &gscreen, p, memones, p); + memimagedraw(gscreen, r, gscreen, p, nil, p); r = Rpt(Pt(window.min.x, window.max.y-o), window.max); - memimagedraw(&gscreen, r, back, ZP, memones, ZP); + memimagedraw(gscreen, r, back, ZP, nil, ZP); curpos.y -= o; } @@ -309,15 +249,16 @@ scroll(void) /* * export screen to devdraw */ -ulong* -attachscreen(Rectangle *r, int *ld, int *width, int *softscreen) +uchar* +attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen) { - *r = gscreen.r; - *ld = gscreen.ldepth; - *width = gscreen.width; + *r = gscreen->r; + *d = gscreen->depth; + *chan = gscreen->chan; + *width = gscreen->width; *softscreen = 0; - return gscreendata.data; + return gscreendata.bdata; } /* @@ -335,10 +276,10 @@ flushmemscreen(Rectangle r) if(Dx(r)<=0 || Dy(r)<=0) return; x = allocmemimage(r, 3); - memimagedraw(x, r, &gscreen, r.min, memones, r.min); - memimagedraw(&gscreen, r, memones, r.min, memones, r.min); + memimagedraw(x, r, &gscreen, r.min, memopaque, r.min); + memimagedraw(&gscreen, r, memblack, r.min, memopaque, r.min); for(i=1000000; --i>0; ); - memimagedraw(&gscreen, r, x, r.min, memones, r.min); + memimagedraw(&gscreen, r, x, r.min, memopaque, r.min); freememimage(x); */ } @@ -373,7 +314,7 @@ screenputc(char *buf) pos = (curpos.x-window.min.x)/w; pos = 8-(pos%8); r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h); - memimagedraw(&gscreen, r, back, back->r.min, memones, back->r.min); + memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min); curpos.x += pos*w; break; case '\b': @@ -381,7 +322,7 @@ screenputc(char *buf) break; xp--; r = Rect(*xp, curpos.y, curpos.x, curpos.y + h); - memimagedraw(&gscreen, r, back, back->r.min, memones, back->r.min); + memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min); curpos.x = *xp; break; default: @@ -393,8 +334,8 @@ screenputc(char *buf) *xp++ = curpos.x; r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h); - memimagedraw(&gscreen, r, back, back->r.min, memones, back->r.min); - memimagestring(&gscreen, curpos, &conscol, memdefont, buf); + memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min); + memimagestring(gscreen, curpos, conscol, memdefont, buf); curpos.x += w; } } @@ -542,9 +483,7 @@ setcursor(Cursor *curs) *p = curs->clr[2*i]; *(p+1) = curs->clr[2*i+1]; } - hwcursor.data->data = (ulong *)malloc(1024); - if(hwcursor.data->data == 0) - error(Enomem); + memset(hwcursor->data->bdata, 0, sizeof(long)*hwcursor->width*Dy(hwcursor->r)); /* hw cursor is 64x64 with hot point at (32,32) */ org = addpt(Pt(32,32), curs->offset); for(y = 0; y < 16; y++) @@ -553,7 +492,7 @@ setcursor(Cursor *curs) cpix = (c[y]>>(15-x))&1; dpix = (spix<<1) | cpix; /* point(&hwcursor, addpt(Pt(x,y), org), dpix, S), by hand */ - *byteaddr(&hwcursor, Pt(x+org.x, y+org.y)) |= dpix<<(6-(2*((x+org.x)&3))); + *byteaddr(hwcursor, Pt(x+org.x, y+org.y)) |= (dpix<<(6-(2*((x+org.x)&3)))); } d = DAC; @@ -571,14 +510,12 @@ setcursor(Cursor *curs) d->cr1 = 0x04; d->cr0 = 0x00; for(x = 0; x < 1024; x++) - d->cr2 = ((uchar *)hwcursor.data->data)[x]; + d->cr2 = hwcursor->data->bdata[x]; /* set y back */ d->cr1 = 0x03; d->cr0 = 0x03; d->cr2 = ylow; d->cr2 = yhigh; - - free(hwcursor.data->data); } int @@ -611,7 +548,7 @@ cursoron(int dolock) int screenbits(void) { - return 1<depth; } extern cursorlock(Rectangle); @@ -632,14 +569,14 @@ screenload(Rectangle r, uchar *data, int tl, int l, int dolock) USED(dolock); - if(!rectclip(&r, gscreen.r) || tl<=0) + if(!rectclip(&r, gscreen->r) || tl<=0) return; lock(&screenlock); - q = byteaddr(&gscreen, r.min); + q = byteaddr(gscreen, r.min); for(y=r.min.y; ywidth*sizeof(ulong); data += l; } unlock(&screenlock); @@ -663,10 +600,10 @@ screenunload(Rectangle r, uchar *data, int tl, int l, int dolock) USED(dolock); lock(&screenlock); - q = byteaddr(&gscreen, r.min); + q = byteaddr(gscreen, r.min); for(y=r.min.y; ywidth*sizeof(ulong); data += l; } unlock(&screenlock); diff --git a/ip/ip.c b/ip/ip.c index 97a49d72aa9ffc38c526ed1abccfc4a6730f762e..72c2c4daccb4d9281747cca6f8af289cf6e5ab2c 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -180,20 +180,10 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos) else gate = r->v4.gate; - if(gating){ - switch(eh->ttl){ - case 0: - case 1: - goto free; - default: - eh->ttl--; - break; - } - } else { + if(!gating) eh->vihl = IP_VER|IP_HLEN; - eh->ttl = ttl; - eh->tos = tos; - } + eh->ttl = ttl; + eh->tos = tos; if(!canrlock(ifc)) goto free; diff --git a/pc/cga.c b/pc/cga.c index f844a5d3c10aacf6b59d7e2634a2c868aa8f93f9..e205449e3e51b2a663ddfa8cda50e14ccde0cf46 100644 --- a/pc/cga.c +++ b/pc/cga.c @@ -5,12 +5,28 @@ #include "fns.h" #include "../port/error.h" -enum -{ - Width = 160, +enum { + Black, + Blue, + Green, + Cyan, + Red, + Magenta, + Brown, + Grey, + + Bright = 0x08, + Blinking = 0x80, + + Yellow = Bright|Brown, + White = Bright|Grey, +}; + +enum { + Width = 80*2, Height = 25, - Attr = 7, /* white on black */ + Attr = (Black<<4)|White, /* high nibble background, low foreground */ }; #define CGASCREENBASE ((uchar*)KADDR(0xB8000)) @@ -45,6 +61,7 @@ static void cgascreenputc(int c) { int i; + uchar *p; if(c == '\n'){ cgapos = cgapos/Width; @@ -67,7 +84,11 @@ cgascreenputc(int c) } if(cgapos >= Width*Height){ memmove(CGASCREENBASE, &CGASCREENBASE[Width], Width*(Height-1)); - memset(&CGASCREENBASE[Width*(Height-1)], 0, Width); + p = &CGASCREENBASE[Width*(Height-1)]; + for(i=0; i>8)) + +/* + * active USB device + */ +struct Udev { + Ref; + Lock; + int x; /* index in usbdev[] */ + int busy; + int state; + int id; + byte port; /* port number on connecting hub */ + byte class; + byte subclass; + byte proto; + int ls; + int npt; + Endpt* ep[16]; /* active end points */ + Udev* ports; /* active ports, if hub */ + Udev* next; /* next device on this hub */ +}; + +/* device parameters */ +enum { + /* Udev.state */ + Disabled = 0, + Attached, + Enabled, + Assigned, + Configured, + + /* Udev.class */ + Noclass = 0, + Hubclass = 9, +}; + +static char *devstates[] = { + [Disabled] "Disabled", + [Attached] "Attached", + [Enabled] "Enabled", + [Assigned] "Assigned", + [Configured] "Configured", +}; + +/* + * device endpoint + */ +struct Endpt { + Ref; + Lock; + int x; /* index in Udev.ep */ + int id; /* hardware endpoint address */ + int maxpkt; /* maximum packet size (from endpoint descriptor) */ + int data01; /* 0=DATA0, 1=DATA1 */ + byte eof; + byte class; + byte subclass; + byte proto; + byte mode; /* OREAD, OWRITE, ORDWR */ + byte nbuf; /* number of buffers allowed */ + byte periodic; + byte iso; + byte debug; + byte active; /* listed for examination by interrupts */ + int sched; /* schedule index; -1 if undefined or aperiodic */ + int setin; + ulong bw; /* bandwidth requirement */ + int pollms; /* polling interval in msec */ + QH* epq; /* queue of TDs for this endpoint */ + + QLock rlock; + Rendez rr; + Queue* rq; + QLock wlock; + Rendez wr; + Queue* wq; + + int ntd; + char* err; + + Udev* dev; /* owning device */ + + Endpt* activef; /* active endpoint list */ + + ulong nbytes; + ulong nblocks; +}; + +struct Ctlr { + Lock; /* protects state shared with interrupt (eg, free list) */ + int io; + ulong* frames; /* frame list */ + int idgen; /* version number to distinguish new connections */ + QLock resetl; /* lock controller during USB reset */ + + TD* tdpool; + TD* freetd; + QH* qhpool; + QH* freeqh; + + QTree* tree; /* tree for periodic Endpt i/o */ + QH* ctlq; /* queue for control i/o */ + QH* bwsop; /* empty bandwidth sop (to PIIX4 errata specifications) */ + QH* bulkq; /* queue for bulk i/o (points back to bandwidth sop) */ + + Udev* ports[2]; +}; +#define IN(x) ins(ub->io+(x)) +#define OUT(x, v) outs(ub->io+(x), (v)) + +static Ctlr ubus; +static char Estalled[] = "usb endpoint stalled"; + +static QLock usbstate; /* protects name space state */ +static Udev* usbdev[32]; +static struct { + Lock; + Endpt* f; +} activends; + +static long readusb(Endpt*, void*, long); +static long writeusb(Endpt*, void*, long, int); + +static TD * +alloctd(Ctlr *ub) +{ + TD *t; + + ilock(ub); + t = ub->freetd; + if(t == nil) + panic("alloctd"); /* TO DO */ + ub->freetd = t->next; + t->next = nil; + iunlock(ub); + t->ep = nil; + t->bp = nil; + t->status = 0; + t->link = Terminate; + t->buffer = 0; + t->flags = 0; + return t; +} + +static void +freetd(TD *t) +{ + Ctlr *ub; + + ub = &ubus; + t->ep = nil; + if(t->bp) + freeb(t->bp); + t->bp = nil; + ilock(ub); + t->buffer = 0xdeadbeef; + t->next = ub->freetd; + ub->freetd = t; + iunlock(ub); +} + +static void +dumpdata(Block *b, int n) +{ + int i; + + XPRINT("\tb %8.8lux[%d]: ", (ulong)b->rp, n); + if(n > 16) + n = 16; + for(i=0; irp[i]); + XPRINT("\n"); +} + +static void +dumptd(TD *t, int follow) +{ + int i, n; + char buf[20], *s; + TD *t0; + + t0 = t; + while(t){ + i = t->dev & 0xFF; + if(i == TokOUT || i == TokSETUP) + n = ((t->dev>>21) + 1) & 0x7FF; + else if((t->status & Active) == 0) + n = (t->status + 1) & 0x7FF; + else + n = 0; + s = buf; + if(t->status & Active) + *s++ = 'A'; + if(t->status & Stalled) + *s++ = 'S'; + if(t->status & DataBufferErr) + *s++ = 'D'; + if(t->status & Babbling) + *s++ = 'B'; + if(t->status & NAKed) + *s++ = 'N'; + if(t->status & CRCorTimeout) + *s++ = 'T'; + if(t->status & BitstuffErr) + *s++ = 'b'; + if(t->status & LowSpeed) + *s++ = 'L'; + *s = 0; + print("td %8.8lux: l=%8.8lux s=%8.8lux d=%8.8lux b=%8.8lux %8.8lux f=%8.8lux\n", + t, t->link, t->status, t->dev, t->buffer, t->bp?(ulong)t->bp->rp:0, t->flags); + print("\ts=%s,ep=%ld,d=%ld,D=%ld\n", buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1); + if(t->bp) + dumpdata(t->bp, n); + if(!follow || t->link & Terminate || t->link & IsQH) + break; + t = TFOL(t->link); + if(t == t0) + break; /* looped */ + } +} + +static TD * +alloctde(Endpt *e, int pid, int n) +{ + TD *t; + int tog, id; + + t = alloctd(&ubus); + id = (e->x<<7)|(e->dev->x&0x7F); + tog = 0; + if(e->data01 && pid != TokSETUP) + tog = IsDATA1; + t->ep = e; + t->status = ErrLimit3 | Active | IOC; /* or put IOC only on last? */ + if(e->dev->ls) + t->status |= LowSpeed; + t->dev = ((n-1)<<21) | ((id&0x7FF)<<8) | pid | tog; + return t; +} + +static TD * +alloctdring(int nbuf, Endpt *e, int pid, int maxn) +{ + TD *t, *lt, *ft; + int id, i; + ulong status, dev; + + if(!e->iso) + nbuf = (nbuf+1)&~1; + id = (e->x<<7)|(e->dev->x&0x7F); + dev = ((maxn-1)<<21) | ((id&0x7FF)<<8) | pid; + status = 0; + if(e->dev->ls) + status |= LowSpeed; + ft = lt = nil; + for(i=0; iep = e; + t->status = status; + t->dev = dev; + if(!e->iso) + dev ^= IsDATA1; + if(pid == TokIN){ + t->bp = allocb(maxn); + t->buffer = PADDR(t->bp->wp); + } + if(ft != nil){ + lt->next = t; + lt->link = PADDR(t); + }else + ft = t; + lt = t; + } + if(lt != nil) + lt->link = PADDR(ft); /* loop to form ring */ + return ft; +} + +static QH * +allocqh(Ctlr *ub) +{ + QH *qh; + + ilock(ub); + qh = ub->freeqh; + if(qh == nil) + panic("allocqh"); /* TO DO */ + ub->freeqh = qh->next; + qh->next = nil; + iunlock(ub); + qh->head = Terminate; + qh->entries = Terminate; + qh->first = nil; + qh->last = nil; + return qh; +} + +static void +freeqh(Ctlr *ub, QH *qh) +{ + ilock(ub); + qh->next = ub->freeqh; + ub->freeqh = qh; + iunlock(ub); +} + +static void +dumpqh(QH *q) +{ + int i; + QH *q0; + + q0 = q; + for(i = 0; q != nil && i < 10; i++){ + pprint("qh %8.8lux: %8.8lux %8.8lux\n", q, q->head, q->entries); + if((q->entries & Terminate) == 0) + dumptd(TFOL(q->entries), 1); + if(q->head & Terminate) + break; + if((q->head & IsQH) == 0){ + pprint("head:"); + dumptd(TFOL(q->head), 1); + break; + } + q = QFOL(q->head); + if(q == q0) + break; /* looped */ + } +} + +static void +queuetd(Ctlr *ub, QH *q, TD *t, int vf) +{ + TD *lt; + + for(lt = t; lt->next != nil; lt = lt->next) + lt->link = PADDR(lt->next) | vf; + lt->link = Terminate; + ilock(ub); + if(q->first != nil){ + q->last->link = PADDR(t) | vf; + q->last->next = t; + }else{ + q->first = t; + q->entries = PADDR(t); + } + q->last = lt; + iunlock(ub); +} + +static void +cleantd(TD *t, int discard) +{ + Block *b; + int n, err; + + XPRINT("cleanTD: %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); + if(t->ep != nil && t->ep->debug) + dumptd(t, 0); + if(t->status & Active) + panic("cleantd Active"); + err = t->status & (AnyError&~NAKed); + /* TO DO: on t->status&AnyError, q->entries will not have advanced */ + if (err) + print("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); + switch(t->dev&0xFF){ + case TokIN: + if(discard || (t->flags & CancelTD) || t->ep == nil || t->ep->x!=0&&err){ + if(t->ep != nil){ + if(err != 0) + t->ep->err = err==Stalled? Estalled: Eio; + wakeup(&t->ep->rr); /* in case anyone cares */ + } + break; + } + b = t->bp; + n = (t->status + 1) & 0x7FF; + if(n > b->lim - b->wp) + n = 0; + b->wp += n; + if(Chatty) + dumpdata(b, n); + t->bp = nil; + t->ep->nbytes += n; + t->ep->nblocks++; + qpass(t->ep->rq, b); /* TO DO: flow control */ + wakeup(&t->ep->rr); /* TO DO */ + break; + case TokSETUP: + XPRINT("cleanTD: TokSETUP %lux\n", &t->ep); + /* don't really need to wakeup: subsequent IN or OUT gives status */ + if(t->ep != nil) { + wakeup(&t->ep->wr); /* TO DO */ + XPRINT("cleanTD: wakeup %lux\n", &t->ep->wr); + } + break; + case TokOUT: + /* TO DO: mark it done somewhere */ + XPRINT("cleanTD: TokOut %lux\n", &t->ep); + if(t->ep != nil){ + if(t->bp){ + n = BLEN(t->bp); + t->ep->nbytes += n; + t->ep->nblocks++; + } + if(t->ep->x!=0 && err != 0) + t->ep->err = err==Stalled? Estalled: Eio; + if(--t->ep->ntd < 0) + panic("cleantd ntd"); + wakeup(&t->ep->wr); /* TO DO */ + XPRINT("cleanTD: wakeup %lux\n", &t->ep->wr); + } + break; + } + freetd(t); +} + +static void +cleanq(QH *q, int discard) +{ + TD *t; + Ctlr *ub; + + ub = &ubus; + ilock(ub); + for(t = q->first; t != nil;){ +// XPRINT("cleanq: %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); + if(t->status & Active){ + if(t->flags & CancelTD){ + XPRINT("cancelTD: %8.8lux\n", (ulong)t); + t->status = (t->status & ~Active) | IOC; /* ensure interrupt next frame */ + t = t->next; + continue; + } + break; + } + t->status &= ~IOC; + /* TO DO: need to deal with TDs as chain if necessary */ + q->first = t->next; + if(q->first != nil) + q->entries = PADDR(q->first); + else + q->entries = Terminate; + t->next = nil; + iunlock(ub); + cleantd(t, discard); + ilock(ub); + t = q->first; + } + iunlock(ub); +} + +static void +canceltds(Ctlr *ub, QH *q, Endpt *e) +{ + TD *t; + + if(q != nil){ + ilock(ub); + for(t = q->first; t != nil; t = t->next) + if(t->ep == e) + t->flags |= CancelTD; + iunlock(ub); + pprint("cancel:\n"); + dumpqh(q); + } +} + +static void +eptcancel(Endpt *e) +{ + Ctlr *ub; + + if(e == nil) + return; + ub = &ubus; + canceltds(ub, e->epq, e); + canceltds(ub, ub->ctlq, e); + canceltds(ub, ub->bulkq, e); +} + +static void +eptactivate(Endpt *e) +{ + ilock(&activends); + if(e->active == 0){ + e->active = 1; + e->activef = activends.f; + activends.f = e; + } + iunlock(&activends); +} + +static void +eptdeactivate(Endpt *e) +{ + Endpt **l; + + /* could be O(1) but not worth it yet */ + ilock(&activends); + if(e->active){ + e->active = 0; + for(l = &activends.f; *l != e; l = &(*l)->activef) + if(*l == nil){ + iunlock(&activends); + panic("usb eptdeactivate"); + } + *l = e->activef; + } + iunlock(&activends); +} + +static QH* +qxmit(Endpt *e, Block *b, int pid) +{ + TD *t; + int n, vf; + Ctlr *ub; + QH *qh; + + if(b != nil){ + n = BLEN(b); + t = alloctde(e, pid, n); + t->bp = b; + t->buffer = PADDR(b->rp); + }else + t = alloctde(e, pid, 0); + ub = &ubus; + ilock(ub); + e->ntd++; + iunlock(ub); +if(e->debug)pprint("QTD: %8.8lux n=%ld\n", t, b?BLEN(b): 0); + vf = 0; + if(e->x == 0){ + qh = ub->ctlq; + vf = 0; + }else if((qh = e->epq) == nil || e->mode != OWRITE){ + qh = ub->bulkq; + vf = Vf; + } + queuetd(ub, qh, t, vf); + return qh; +} + +static QH* +qrcv(Endpt *e) +{ + TD *t; + Block *b; + Ctlr *ub; + QH *qh; + int vf; + + t = alloctde(e, TokIN, e->maxpkt); + b = allocb(e->maxpkt); + t->bp = b; + t->buffer = PADDR(b->wp); + ub = &ubus; + vf = 0; + if(e->x == 0){ + qh = ub->ctlq; + vf = 0; + }else if((qh = e->epq) == nil || e->mode != OREAD){ + qh = ub->bulkq; + vf = Vf; + } + queuetd(ub, qh, t, vf); + return qh; +} + +static Block * +usbreq(int type, int req, int value, int offset, int count) +{ + Block *b; + + b = allocb(8); + b->wp[0] = type; + b->wp[1] = req; + PUT2(b->wp+2, value); + PUT2(b->wp+4, offset); + PUT2(b->wp+6, count); + b->wp += 8; + return b; +} + +/* + * return smallest power of 2 >= n + */ +static int +flog2(int n) +{ + int i; + + for(i=0; (1<nel = n; + qt->depth = depth; + qt->bw = mallocz(n*sizeof(qt->bw), 1); + if(qt->bw == nil){ + free(qt); + return nil; + } + tree = xspanalloc(n*sizeof(QH), 16, 0); + if(tree == nil){ + free(qt); + return nil; + } + qt->root = tree; + tree->head = Terminate; /* root */ + tree->entries = Terminate; + for(i=1; ihead = PADDR(&tree[(i-1)/2]) | IsQH; + qh->entries = Terminate; + } + /* distribute leaves evenly round the frame list */ + leaf0 = n/2; + for(i=0; i= n){ + pprint("leaf0=%d o=%d i=%d n=%d\n", leaf0, o, i, n); + break; + } + frame[i] = PADDR(&tree[leaf0+o]) | IsQH; + } + return qt; +} + +static void +dumpframe(int f, int t) +{ + QH *q, *tree; + ulong p, *frame; + int i, n; + + n = ubus.tree->nel; + tree = ubus.tree->root; + frame = ubus.frames; + if(f < 0) + f = 0; + if(t < 0) + t = 32; + for(i=f; ihead); + for(p=frame[i]; (p & IsQH) && (p &Terminate) == 0; p = q->head){ + q = QFOL(p); + if(!(q >= tree && q < &tree[n])){ + pprint("Q: p=%8.8lux out of range\n", p); + break; + } + pprint(" -> %8.8lux h=%8.8lux e=%8.8lux\n", p, q->head, q->entries); + } + } +} + +static int +pickschedq(QTree *qt, int pollms, ulong bw, ulong limit) +{ + int i, j, d, ub, q; + ulong best, worst, total; + + d = flog2(pollms); + if(d > qt->depth) + d = qt->depth; + q = -1; + worst = 0; + best = ~0; + ub = (1<<(d+1))-1; + for(i=(1<bw[0]; + for(j=i; j > 0; j=(j-1)/2) + total += qt->bw[j]; + if(total < best){ + best = total; + q = i; + } + if(total > worst) + worst = total; + } + if(worst+bw >= limit) + return -1; + return q; +} + +static int +schedendpt(Endpt *e) +{ + Ctlr *ub; + QH *qh; + int q; + + if(!e->periodic || e->sched >= 0) + return 0; + ub = &ubus; + if(e->epq == nil){ + e->epq = allocqh(ub); + if(e->epq == nil) + return -1; + } + qlock(ub->tree); + q = pickschedq(ub->tree, e->pollms, e->bw, ~0); /* TO DO: bus bandwidth limit */ + if(q < 0) + return -1; + ub->tree->bw[q] += e->bw; + qh = &ub->tree->root[q]; + e->sched = q; + e->epq->head = qh->entries; + e->epq->entries = Terminate; + qh->entries = PADDR(e->epq) | IsQH; + qunlock(ub->tree); + return 0; +} + +static void +unschedendpt(Endpt *e) +{ + Ctlr *ub; + ulong p; + QH *qh; + int q; + + ub = &ubus; + if(e->epq == nil || (q = e->sched) < 0) + return; + p = PADDR(e->epq) | IsQH; + qlock(ub->tree); + ub->tree->bw[q] -= e->bw; + qh = &ub->tree->root[q]; + for(; qh->entries != p; qh = QFOL(qh->entries)) + if(qh->entries & Terminate || (qh->entries & IsQH) == 0){ + qunlock(ub->tree); + panic("usb: unschedendpt"); + } + qh->entries = e->epq->head; + qunlock(ub->tree); + e->epq->head = Terminate; +} + +static Endpt * +devendpt(Udev *d, int id, int add) +{ + Endpt *e, **p; + + p = &d->ep[id&0xF]; + lock(d); + if((e = *p) != nil){ + incref(e); + unlock(d); + return e; + } + unlock(d); + if(!add) + return nil; + e = mallocz(sizeof(*e), 1); + e->ref = 1; + e->x = id&0xF; + e->id = id; + e->periodic = 0; + e->sched = -1; + e->maxpkt = 8; + e->pollms = 0; + e->bw = 0; + e->nbuf = 1; + e->dev = d; + e->active = 0; + lock(d); + if(*p != nil){ + incref(*p); + unlock(d); + free(e); + return *p; + } + *p = e; + unlock(d); + e->rq = qopen(8*1024, 0, nil, e); + e->wq = qopen(8*1024, 0, nil, e); + return e; +} + +static void +freept(Endpt *e) +{ + if(e != nil && decref(e) == 0){ + XPRINT("freept(%d,%d)\n", e->dev->x, e->x); + unschedendpt(e); + e->dev->ep[e->x] = nil; + eptdeactivate(e); + if(e->epq != nil) + freeqh(&ubus, e->epq); + free(e); + } +} + +static void +usbdevreset(Udev *d) +{ + d->state = Disabled; + if(d->class == Hubclass) + for(d = d->ports; d != nil; d = d->next) + usbdevreset(d); +} + +static void +freedev(Udev *d) +{ + int i; + + if(d != nil && decref(d) == 0){ + for(i=0; iep); i++) + freept(d->ep[i]); + if(d->x >= 0) + usbdev[d->x] = nil; + free(d); + } +} + +static void +hubportreset(Udev *h, int p) +{ + USED(h, p); + /* reset state of each attached device? */ +} + +static int ioports[] = {-1, Portsc0, Portsc1}; + +static void +portreset(int port) +{ + Ctlr *ub; + int i, p; + + /* should check that device not being configured on other port? */ + p = ioports[port]; + ub = &ubus; + qlock(&ub->resetl); + if(waserror()){ + qunlock(&ub->resetl); + nexterror(); + } + XPRINT("r: %x\n", IN(p)); + ilock(ub); + OUT(p, PortReset); + delay(12); /* BUG */ + XPRINT("r2: %x\n", IN(p)); + OUT(p, IN(p) & ~PortReset); + XPRINT("r3: %x\n", IN(p)); + OUT(p, IN(p) | PortEnable); + microdelay(64); + for(i=0; i<1000 && (IN(p) & PortEnable) == 0; i++) + ; + XPRINT("r': %x %d\n", IN(p), i); + OUT(p, (IN(p) & ~PortReset)|PortEnable); + iunlock(ub); + hubportreset(nil, port); + poperror(); + qunlock(&ub->resetl); +} + +static void +portenable(int port, int on) +{ + Ctlr *ub; + int w, p; + + /* should check that device not being configured on other port? */ + p = ioports[port]; + ub = &ubus; + qlock(&ub->resetl); + if(waserror()){ + qunlock(&ub->resetl); + nexterror(); + } + ilock(ub); + w = IN(p); + if(on) + w |= PortEnable; + else + w &= ~PortEnable; + OUT(p, w); + microdelay(64); + iunlock(ub); + XPRINT("e: %x\n", IN(p)); + if(!on) + hubportreset(nil, port); + poperror(); + qunlock(&ub->resetl); +} + +static int +portinfo(Ctlr *ub, int *p0, int *p1) +{ + int m, v; + + ilock(ub); + m = 0; + if((v = IN(Portsc0)) & PortChange){ + OUT(Portsc0, v); + m |= 1<<0; + } + *p0 = v; + if((v = IN(Portsc1)) & PortChange){ + OUT(Portsc1, v); + m |= 1<<1; + } + *p1 = v; + iunlock(ub); + return m; +} + +static void +interrupt(Ureg*, void *a) +{ + Ctlr *ub; + Endpt *e; + int s; + + ub = a; + s = IN(Status); + if (s & 0x1a) { + print("usbint: #%x f%d\n", s, IN(Frnum)); + print("cmd #%x sofmod #%x\n", IN(Cmd), inb(ub->io+SOFMod)); + print("sc0 #%x sc1 #%x\n", IN(Portsc0), IN(Portsc1)); + } + OUT(Status, s); + +// XPRINT("cleanq(ub->ctlq, 0)\n"); + cleanq(ub->ctlq, 0); +// XPRINT("cleanq(ub->bulkq, 0)\n"); + cleanq(ub->bulkq, 0); + ilock(&activends); + for(e = activends.f; e != nil; e = e->activef) + if(e->epq != nil) { +// XPRINT("cleanq(e->epq, 0)\n"); + cleanq(e->epq, 0); + } + iunlock(&activends); +} + +static void +resetusbctlr(void) +{ + Ctlr *ub; + Pcidev *cfg; + int i; + ulong port; + QTree *qt; + TD *t; + + ub = &ubus; + memset(&cfg, 0, sizeof(cfg)); + cfg = pcimatch(0, 0x8086, 0x7112); /* Intel chipset PIIX 4*/ + if(cfg == nil) { +// cfg = pcimatch(0, 0x8086, 0x7112); /* Intel chipset PIIX 3*/ +// if(cfg == nil) { + cfg = pcimatch(0, 0x1106, 0x0586); /* Via chipset */ + if(cfg == nil) { + DPRINT("No USB device found\n"); + return; + } +// } + } + port = cfg->mem[4].bar & ~0x0F; + if (port == 0) { + print("usb: failed to map registers\n"); + return; + } + + print("USB: %x/%x port 0x%lux size 0x%x irq %d\n", + cfg->vid, cfg->did, port, cfg->mem[4].size, cfg->intl); + + i = inb(port+SOFMod); + if(0){ + OUT(Cmd, 4); /* global reset */ + delay(15); + OUT(Cmd, 0); /* end reset */ + delay(4); + } + outb(port+SOFMod, i); + // Interrupt handler + intrenable(cfg->intl, interrupt, ub, cfg->tbdf, "usb"); + + ub->io = port; + ub->tdpool = xspanalloc(128*sizeof(TD), 16, 0); + for(i=128; --i>=0;){ + ub->tdpool[i].next = ub->freetd; + ub->freetd = &ub->tdpool[i]; + } + ub->qhpool = xspanalloc(32*sizeof(QH), 16, 0); + for(i=32; --i>=0;){ + ub->qhpool[i].next = ub->freeqh; + ub->freeqh = &ub->qhpool[i]; + } + + /* + * the root of the periodic (interrupt & isochronous) scheduling tree + * points to the control queue and the bandwidth sop for bulk traffic. + * this is looped following the instructions in PIIX4 errata 29773804.pdf: + * a QH links to a looped but inactive TD as its sole entry, + * with its head entry leading on to the bulk traffic, the last QH of which + * links back to the empty QH. + */ + ub->bulkq = allocqh(ub); + t = alloctd(ub); /* inactive TD, looped */ + t->link = PADDR(t); + ub->bwsop = allocqh(ub); + ub->bwsop->head = PADDR(ub->bulkq) | IsQH; + ub->bwsop->entries = PADDR(t); + ub->ctlq = allocqh(ub); + ub->ctlq->head = PADDR(ub->bwsop) | IsQH; +// ub->bulkq->head = PADDR(ub->bwsop) | IsQH; /* loop back */ + print("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", + IN(Cmd), IN(Status), IN(Usbintr), inb(port+Frnum)); + print("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", + IN(Flbaseadd), inb(port+SOFMod), IN(Portsc0), IN(Portsc1)); + OUT(Cmd, 0); /* stop */ + ub->frames = xspanalloc(FRAMESIZE, FRAMESIZE, 0); + qt = mkqhtree(ub->frames, NFRAME, 32); + if(qt == nil){ + print("usb: can't allocate scheduling tree\n"); + ub->io = 0; + return; + } + qt->root->head = PADDR(ub->ctlq) | IsQH; + ub->tree = qt; + print("usb tree: nel=%d depth=%d\n", qt->nel, qt->depth); + + outl(port+Flbaseadd, PADDR(ub->frames)); + OUT(Frnum, 0); + OUT(Usbintr, 0xF); /* enable all interrupts */ + print("cmd 0x%x sofmod 0x%x\n", IN(Cmd), inb(port+SOFMod)); + print("sc0 0x%x sc1 0x%x\n", IN(Portsc0), IN(Portsc1)); +} + +enum +{ + Qtopdir = 0, + Q2nd, + Qbusctl, + Qnew, + Qport, + Q3rd, + Qctl, + Qsetup, + Qdebug, + Qstatus, + Qep0, + /* other endpoint files */ +}; + +/* + * Qid path is: + * 8 bits of file type (qids above) + * 10 bits of slot number +1; 0 means not attached to device + */ +#define QSHIFT 8 /* location in qid of device # */ +#define QMASK ((1<>QSHIFT) + +static Dirtab usbdir2[] = { + "new", {Qnew}, 0, 0666, + "ctl", {Qbusctl}, 0, 0666, + "port", {Qport}, 0, 0444, +}; + +static Dirtab usbdir3[]={ + "ctl", {Qctl}, 0, 0666, + "setup", {Qsetup}, 0, 0666, + "status", {Qstatus}, 0, 0444, + "debug", {Qdebug}, 1, 0666, + /* epNdata names are generated on demand */ +}; + +static Udev * +usbdeviceofpath(ulong path) +{ + int s; + + s = DEVPATH(path); + if(s == 0) + return nil; + return usbdev[s-1]; +} + +static Udev * +usbdevice(Chan *c) +{ + Udev *d; + + d = usbdeviceofpath(c->qid.path); + if(d == nil || d->id != c->qid.vers || d->state == Disabled) + error(Ehungup); + return d; +} + +static Udev * +usbnewdevice(void) +{ + Udev *d; + Endpt *e; + int i; + + d = nil; + qlock(&usbstate); + if(waserror()){ + qunlock(&usbstate); + nexterror(); + } + for(i=0; iref = 1; + d->x = i; + d->id = (ubus.idgen << 8) | i; + d->state = Enabled; + e = devendpt(d, 0, 1); /* always provide control endpoint 0 */ + e->mode = ORDWR; + e->periodic = 0; + e->sched = -1; + usbdev[i] = d; + break; + } + poperror(); + qunlock(&usbstate); + return d; +} + +static void +usbreset(void) +{ + resetusbctlr(); +} + +void +usbinit(void) +{ + Udev *d; + + if(ubus.io != 0 && usbdev[0] == nil){ + d = usbnewdevice(); /* reserve device 0 for configuration */ + incref(d); + d->state = Attached; + } +} + +Chan * +usbattach(char *spec) +{ + Ctlr *ub; + + ub = &ubus; + if(ub->io == 0) + error(Enodev); + if((IN(Cmd)&1)==0 || *spec) + OUT(Cmd, 1); /* run */ +// pprint("at: c=%x s=%x c0=%x\n", IN(Cmd), IN(Status), IN(Portsc0)); + return devattach('U', spec); +} + +Chan * +usbclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +static int +usbgen(Chan *c, Dirtab*, int, int s, Dir *dp) +{ + int t; + Qid q; + ulong path; + Udev *d; + Dirtab *tab; + Endpt *e; + char buf[NAMELEN]; + + /* + * Top level directory contains the name of the device. + */ + if(c->qid.path == CHDIR){ + if(s == 0){ + devdir(c, (Qid){CHDIR|Q2nd, 0}, "usb", 0, eve, 0555, dp); + return 1; + } + return -1; + } + + /* + * Second level contains "new" plus all the clients. + */ + t = QID(c->qid); + if(t < Q3rd){ + if(s < nelem(usbdir2)){ + tab = &usbdir2[s]; + devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp); + return 1; + } + if((s -= nelem(usbdir2)) >= 0 && s < nelem(usbdev)){ + d = usbdev[s]; + if(d == nil) + return 0; + sprint(buf, "%d", s); + q = (Qid){CHDIR|((s+1)<id}; + devdir(c, q, buf, 0, eve, 0555, dp); + return 1; + } + return -1; + } + + /* + * Third level. + */ + path = c->qid.path&~(CHDIR|QMASK); /* slot component */ + q.vers = c->qid.vers; + if(s < nelem(usbdir3)){ + Dirtab *tab = &usbdir3[s]; + q.path = path | tab->qid.path; + devdir(c, q, tab->name, tab->length, eve, tab->perm, dp); + return 1; + } + + /* active endpoints */ + d = usbdeviceofpath(path); + if(d == nil) + return -1; + s -= nelem(usbdir3); + if(s < 0 || s >= nelem(d->ep)) + return -1; + if(s == 0 || (e = d->ep[s]) == nil) /* ep0data is called "setup" */ + return 0; + sprint(buf, "ep%ddata", s); + q.path = path | (Qep0+s); + devdir(c, q, buf, 0, eve, e->mode==OREAD? 0444: e->mode==OWRITE? 0222: 0666, dp); + return 1; +} + +int +usbwalk(Chan *c, char *name) +{ + if(strcmp(name, "..") == 0){ + switch(QID(c->qid)){ + case Qtopdir: + return 1; + case Q2nd: + c->qid = (Qid){CHDIR|Qtopdir, 0}; + break; + case Q3rd: + c->qid = (Qid){CHDIR|Q2nd, 0}; + break; + default: + panic("usbwalk %lux", c->qid.path); + } + return 1; + } + return devwalk(c, name, nil, 0, usbgen); +} + +void +usbstat(Chan *c, char *db) +{ + devstat(c, db, nil, 0, usbgen); +} + +Chan * +usbopen(Chan *c, int omode) +{ + Udev *d; + int f, s; + + if(c->qid.path & CHDIR) + return devopen(c, omode, nil, 0, usbgen); + + f = 0; + if(QID(c->qid) == Qnew){ + d = usbnewdevice(); + if(d == nil) + error(Enodev); + c->qid.path = Qctl|((d->x+1)<qid.vers = d->id; + f = 1; + } + + if(c->qid.path < Q3rd) + return devopen(c, omode, nil, 0, usbgen); + + qlock(&usbstate); + if(waserror()){ + qunlock(&usbstate); + nexterror(); + } + + switch(QID(c->qid)){ + case Qctl: + d = usbdevice(c); + if(0&&d->busy) + error(Einuse); + d->busy = 1; + if(!f) + incref(d); + break; + + default: + d = usbdevice(c); + s = QID(c->qid) - Qep0; + if(s >= 0 && s < nelem(d->ep)){ + Endpt *e; + if((e = d->ep[s]) == nil) + error(Enodev); + if(schedendpt(e) < 0) + error("can't schedule USB endpoint"); + eptactivate(e); + } + incref(d); + break; + } + poperror(); + qunlock(&usbstate); + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +usbcreate(Chan *c, char *name, int omode, ulong perm) +{ + USED(c, name, omode, perm); + error(Eperm); +} + +void +usbremove(Chan*) +{ + error(Eperm); +} + +void +usbwstat(Chan *c, char *dp) +{ + USED(c, dp); + error(Eperm); +} + +void +usbclose(Chan *c) +{ + Udev *d; + + if(c->qid.path & CHDIR || c->qid.path < Q3rd) + return; + qlock(&usbstate); + if(waserror()){ + qunlock(&usbstate); + nexterror(); + } + d = usbdevice(c); + if(QID(c->qid) == Qctl) + d->busy = 0; + if(c->flag & COPEN) + freedev(d); + poperror(); + qunlock(&usbstate); +} + +static int +eptinput(void *arg) +{ + Endpt *e; + + e = arg; + return e->eof || e->err || qcanread(e->rq); +} + +static long +readusb(Endpt *e, void *a, long n) +{ + Block *b; + uchar *p; + long l, i; + + qlock(&e->rlock); + if(waserror()){ + qunlock(&e->rlock); + eptcancel(e); + nexterror(); + } + p = a; + do { + if(e->eof) { + pprint("e->eof\n"); + break; + } + if(e->err) + error(e->err); + qrcv(e); + if(!e->iso) + e->data01 ^= 1; + sleep(&e->rr, eptinput, e); + if(e->err) + error(e->err); + b = qget(e->rq); /* TO DO */ + if(b == nil) { + pprint("b == nil\n"); + break; + } + if(waserror()){ + freeb(b); + nexterror(); + } + l = BLEN(b); + if((i = l) > n) + i = n; + if(i > 0){ + memmove(p, b->rp, i); + p += i; + } + poperror(); + freeb(b); + n -= i; + } while (l == e->maxpkt && n > 0); + poperror(); + qunlock(&e->rlock); + return p-(uchar*)a; +} + +long +usbread(Chan *c, void *a, long n, vlong offset) +{ + Endpt *e; + Udev *d; + char buf[48], *s; + int t, w0, w1, ps, l, i; + + if(c->qid.path & CHDIR) + return devdirread(c, a, n, nil, 0, usbgen); + + t = QID(c->qid); + switch(t){ + case Qbusctl: + snprint(buf, sizeof(buf), "%11d %11d ", 0, 0); + return readstr(offset, a, n, buf); + + case Qport: + ps = portinfo(&ubus, &w0, &w1); + snprint(buf, sizeof(buf), "0x%ux 0x%ux 0x%ux ", ps, w0, w1); + return readstr(offset, a, n, buf); + + case Qctl: + d = usbdevice(c); + sprint(buf, "%11d %11d ", d->x, d->id); + return readstr(offset, a, n, buf); + + case Qsetup: /* endpoint 0 */ + d = usbdevice(c); + if((e = d->ep[0]) == nil) + error(Eio); /* can't happen */ + e->data01 = 1; + n = readusb(e, a, n); + if(e->setin){ + e->setin = 0; + e->data01 = 1; + writeusb(e, "", 0, TokOUT); + } + break; + + case Qdebug: + n=0; + break; + + case Qstatus: + d = usbdevice(c); + s = smalloc(READSTR); + if(waserror()){ + free(s); + nexterror(); + } + l = snprint(s, READSTR, "%s %d %d %d\n", devstates[d->state], d->class, d->subclass, d->proto); + for(i=0; iep); i++) + if((e = d->ep[i]) != nil) /* TO DO: freeze e */ + l += snprint(s+l, READSTR-l, "%d bytes %lud blocks %lud\n", i, e->nbytes, e->nblocks); + n = readstr(offset, a, n, s); + poperror(); + free(s); + break; + + default: + d = usbdevice(c); + if((t -= Qep0) < 0 || t >= nelem(d->ep)) + error(Eio); + if((e = d->ep[t]) == nil || e->mode == OWRITE) + error(Eio); /* can't happen */ + n=readusb(e, a, n); + break; + } + return n; +} + +static int +qisempty(void *arg) +{ + return ((QH*)arg)->entries & Terminate; +} + +static long +writeusb(Endpt *e, void *a, long n, int tok) +{ + long i; + Block *b; + uchar *p; + QH *qh; + + p = a; + qlock(&e->wlock); + if(waserror()){ + qunlock(&e->wlock); + eptcancel(e); + nexterror(); + } + do { + int j; + + if(e->err) + error(e->err); + if((i = n) >= e->maxpkt) + i = e->maxpkt; + b = allocb(i); + if(waserror()){ + freeb(b); + nexterror(); + } + XPRINT("out [%ld]", i); + for (j = 0; j < i; j++) XPRINT(" %.2x", p[j]); + XPRINT("\n"); + memmove(b->wp, p, i); + b->wp += i; + p += i; + n -= i; + poperror(); + qh = qxmit(e, b, tok); + tok = TokOUT; + if(!e->iso) + e->data01 ^= 1; + if(e->ntd >= e->nbuf) { + XPRINT("writeusb: sleep %lux\n", &e->wr); + sleep(&e->wr, qisempty, qh); + XPRINT("writeusb: awake\n"); + } + } while(n > 0); + poperror(); + qunlock(&e->wlock); + return p-(uchar*)a; +} + +int +getfields(char *ss, char **sp, int nptrs) +{ + uchar *s = (uchar*)ss; + uchar **p = (uchar**)sp; + uint c; + + c = 0; + for(;;){ + if(--nptrs < 0) + break; + *p++ = s; + do { + c = *s++; + if (c == ' ') break; + if (c == '\t') break; + if (c == '\n') break; + } while(c); + if(c == 0) + break; + s[-1] = 0; + } + if(nptrs > 0) + *p = 0; + else + if(--s >= (uchar*)ss) + *s = c; + return p - (uchar**)sp; +} + +long +usbwrite(Chan *c, void *a, long n, vlong) +{ + Udev *d; + Endpt *e; + int id, nw, nf, t, i; + char cmd[50], *fields[10]; + + if(c->qid.path & CHDIR) + error(Egreg); + t = QID(c->qid); + if(t == Qbusctl){ + if(n >= sizeof(cmd)-1) + n = sizeof(cmd)-1; + memmove(cmd, a, n); + cmd[n] = 0; + nf = getfields(cmd, fields, nelem(fields)); + if(nf==1 && strcmp(fields[0], "dump")==0){ + dumpframe(-1, -1); + return n; + } + if(nf < 2) + error(Ebadarg); + id = strtol(fields[1], nil, 0); + if(id != 1 && id != 2) + error(Ebadarg); /* there are two ports on the root hub */ + if(strcmp(fields[0], "reset") == 0) + portreset(id); + else if(strcmp(fields[0], "enable") == 0) + portenable(id, 1); + else if(strcmp(fields[0], "disable") == 0) + portenable(id, 0); + else + error(Ebadarg); + return n; + } + d = usbdevice(c); + t = QID(c->qid); + switch(t){ + case Qctl: + if(n >= sizeof(cmd)-1) + n = sizeof(cmd)-1; + memmove(cmd, a, n); + cmd[n] = 0; + nf = getfields(cmd, fields, nelem(fields)); + if(nf > 1 && strcmp(fields[0], "speed") == 0){ + d->ls = strtoul(fields[1], nil, 0) == 0; + } else if(nf > 4 && strcmp(fields[0], "class") == 0){ + /* class class subclass proto */ + d->class = strtoul(fields[4], nil, 0); + d->subclass = strtoul(fields[5], nil, 0); + d->proto = strtoul(fields[6], nil, 0); + }else if(nf > 2 && strcmp(fields[0], "data") == 0){ + i = strtoul(fields[1], nil, 0); + if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) + error(Ebadarg); + e = d->ep[i]; + e->data01 = strtoul(fields[2], nil, 0) != 0; + }else if(nf > 2 && strcmp(fields[0], "maxpkt") == 0){ + i = strtoul(fields[1], nil, 0); + if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) + error(Ebadarg); + e = d->ep[i]; + e->maxpkt = strtoul(fields[2], nil, 0); + if(e->maxpkt > 1500) + e->maxpkt = 1500; + }else if(nf > 2 && strcmp(fields[0], "debug") == 0){ + i = strtoul(fields[1], nil, 0); + if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) + error(Ebadarg); + e = d->ep[i]; + e->debug = strtoul(fields[2], nil, 0); + }else if(nf > 1 && strcmp(fields[0], "unstall") == 0){ + i = strtoul(fields[1], nil, 0); + if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil) + error(Ebadarg); + e = d->ep[i]; + e->err = nil; + }else if(nf == 6 && strcmp(fields[0], "ep") == 0){ + /* ep n maxpkt mode poll nbuf */ + i = strtoul(fields[1], nil, 0); + if(i < 0 || i >= nelem(d->ep)) + error(Ebadarg); + if(d->ep[i] != nil) + error(Einuse); + e = devendpt(d, i, 1); + if(waserror()){ + freept(e); + nexterror(); + } + i = strtoul(fields[2], nil, 0); + if(i < 8 || i > 1023) + i = 8; + e->maxpkt = i; + e->mode = strcmp(fields[3],"r")==0? OREAD: strcmp(fields[3],"w") == 0? OWRITE: ORDWR; + e->periodic = 0; + e->sched = -1; + if(strcmp(fields[4], "bulk") != 0){ + e->periodic = 1; + i = strtoul(fields[4], nil, 0); + if(i > 0 && i <= 1000) + e->pollms = i; + else + error(Ebadarg); + } + i = strtoul(fields[5], nil, 0); + if(i >= 1 && i <= 32) + e->nbuf = i; + poperror(); + }else + error(Ebadarg); + return n; + + case Qsetup: /* SETUP endpoint 0 */ + /* should canqlock etc */ + if((e = d->ep[0]) == nil) + error(Eio); /* can't happen */ + if(n < 8 || n > 1023) + error(Eio); + nw = *(uchar*)a & RD2H; + e->data01 = 0; + n = writeusb(e, a, n, TokSETUP); + if(nw == 0){ /* host to device: use IN[DATA1] to ack */ + e->data01 = 1; + nw = readusb(e, cmd, 8); + if(nw != 0) + error(Eio); /* could provide more status */ + }else + e->setin = 1; /* two-phase */ + break; + + default: /* sends DATA[01] */ + if((t -= Qep0) < 0 || t >= nelem(d->ep)) + error(Eio); + if((e = d->ep[t]) == nil || e->mode == OREAD) + error(Eio); /* can't happen */ + n = writeusb(e, a, n, TokOUT); + break; + } + return n; +} + +Dev usbdevtab = { + 'U', + "usb", + + usbreset, + usbinit, + usbattach, + usbclone, + usbwalk, + usbstat, + usbopen, + devcreate, + usbclose, + usbread, + devbread, + usbwrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/pc/devvga.c b/pc/devvga.c index 96230a2893583ada1ee22e6aabd5e86b5db2fc46..0e33eedb15685176f261fbbe2dccd159828a86e9 100644 --- a/pc/devvga.c +++ b/pc/devvga.c @@ -15,16 +15,10 @@ enum { Qdir, - Qvgaiob, - Qvgaiow, - Qvgaiol, Qvgactl, }; static Dirtab vgadir[] = { - "vgaiob", { Qvgaiob, 0 }, 0, 0660, - "vgaiow", { Qvgaiow, 0 }, 0, 0660, - "vgaiol", { Qvgaiol, 0 }, 0, 0660, "vgactl", { Qvgactl, 0 }, 0, 0660, }; @@ -87,10 +81,8 @@ checkport(int start, int end) static long vgaread(Chan* c, void* a, long n, vlong off) { - int len, port; + int len; char *p, *s; - ushort *sp; - ulong *lp; VGAscr *scr; ulong offset = off; @@ -115,7 +107,7 @@ vgaread(Chan* c, void* a, long n, vlong off) if(scr->gscreen) len += snprint(p+len, READSTR-len, "size: %dx%dx%d\n", scr->gscreen->r.max.x, scr->gscreen->r.max.y, - 1<gscreen->ldepth); + scr->gscreen->depth); if(scr->cur) s = scr->cur->name; else @@ -129,33 +121,6 @@ vgaread(Chan* c, void* a, long n, vlong off) return n; - case Qvgaiob: - port = offset; - checkport(offset, offset+n); - for(p = a; port < offset+n; port++) - *p++ = inb(port); - return n; - - case Qvgaiow: - if((n & 0x01) || (offset & 0x01)) - error(Ebadarg); - checkport(offset, offset+n+1); - n /= 2; - sp = a; - for(port = offset; port < offset+n; port += 2) - *sp++ = ins(port); - return n*2; - - case Qvgaiol: - if((n & 0x03) || (offset & 0x03)) - error(Ebadarg); - checkport(offset, offset+n+3); - n /= 4; - lp = a; - for(port = offset; port < offset+n; port += 4) - *lp++ = inl(port); - return n*4; - default: error(Egreg); break; @@ -168,19 +133,26 @@ static void vgactl(char* a) { int align, i, n, size, x, y, z; - char *field[4], *p; + char *chanstr, *field[6], *p; + ulong chan; VGAscr *scr; extern VGAdev *vgadev[]; extern VGAcur *vgacur[]; + Rectangle r; - n = parsefields(a, field, 4, " "); - if(n < 2) + n = parsefields(a, field, nelem(field), " "); + if(n < 1) error(Ebadarg); scr = &vgascreen[0]; if(strcmp(field[0], "hwgc") == 0){ if(n < 2) error(Ebadarg); + + /* BUG: drawinit should become a different message rather than piggybacking */ + if(scr && scr->dev && scr->dev->drawinit) + scr->dev->drawinit(scr); + if(strcmp(field[1], "off") == 0){ lock(&cursor); if(scr->cur){ @@ -221,7 +193,7 @@ vgactl(char* a) } } else if(strcmp(field[0], "size") == 0){ - if(n < 2) + if(n < 3) error(Ebadarg); x = strtoul(field[1], &p, 0); if(x == 0 || x > 2048) @@ -235,23 +207,67 @@ vgactl(char* a) if(*p) p++; - switch(strtoul(p, &p, 0)){ - case 8: - z = 3; - break; + z = strtoul(p, &p, 0); - default: - z = 0; - error(Ebadarg); - } + chanstr = field[2]; + if((chan = strtochan(chanstr)) == 0) + error("bad channel"); + + if(chantodepth(chan) != z) + error("depth, channel do not match"); cursoroff(1); - if(screensize(x, y, z)) + deletescreenimage(); + if(screensize(x, y, z, chan)) error(Egreg); vgascreenwin(scr); cursoron(1); return; } + else if(strcmp(field[0], "actualsize") == 0){ + if(scr->gscreen == nil) + error("set the screen size first"); + + if(n < 2) + error(Ebadarg); + x = strtoul(field[1], &p, 0); + if(x == 0 || x > 2048) + error(Ebadarg); + if(*p) + p++; + + y = strtoul(p, nil, 0); + if(y == 0 || y > 2048) + error(Ebadarg); + + if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y) + error("physical screen bigger than virtual"); + + r = Rect(0,0,x,y); + if(!eqrect(r, scr->gscreen->r)){ + if(scr->cur == nil || scr->cur->doespanning == 0) + error("virtual screen not supported"); + } + + physgscreenr = r; + return; + } + else if(strcmp(field[0], "palettedepth") == 0){ + if(n < 2) + error(Ebadarg); + + x = strtoul(field[1], &p, 0); + if(x != 8 && x != 6) + error(Ebadarg); + + scr->palettedepth = x; + return; + } + else if(strcmp(field[0], "drawinit") == 0){ + if(scr && scr->dev && scr->dev->drawinit) + scr->dev->drawinit(scr); + return; + } else if(strcmp(field[0], "linear") == 0){ if(n < 2) error(Ebadarg); @@ -265,6 +281,24 @@ vgactl(char* a) error("not enough free address space"); return; } +/* else if(strcmp(field[0], "memset") == 0){ + if(n < 4) + error(Ebadarg); + memset((void*)strtoul(field[1], 0, 0), atoi(field[2]), atoi(field[3])); + return; + } +*/ + else if(strcmp(field[0], "blank") == 0){ + if(n < 2) + error(Ebadarg); + drawblankscreen(atoi(field[1])); + return; + } + else if(strcmp(field[0], "hwacceloff") == 0){ + scr->fill = nil; + scr->scroll = nil; + return; + } error(Ebadarg); } @@ -272,10 +306,7 @@ vgactl(char* a) static long vgawrite(Chan* c, void* a, long n, vlong off) { - int port; char *p; - ushort *sp; - ulong *lp; ulong offset = off; switch(c->qid.path & ~CHDIR){ @@ -298,33 +329,6 @@ vgawrite(Chan* c, void* a, long n, vlong off) free(p); return n; - case Qvgaiob: - p = a; - checkport(offset, offset+n); - for(port = offset; port < offset+n; port++) - outb(port, *p++); - return n; - - case Qvgaiow: - if((n & 01) || (offset & 01)) - error(Ebadarg); - checkport(offset, offset+n+1); - n /= 2; - sp = a; - for(port = offset; port < offset+n; port += 2) - outs(port, *sp++); - return n*2; - - case Qvgaiol: - if((n & 0x03) || (offset & 0x03)) - error(Ebadarg); - checkport(offset, offset+n+3); - n /= 4; - lp = a; - for(port = offset; port < offset+n; port += 4) - outl(port, *lp++); - return n*4; - default: error(Egreg); break; diff --git a/pc/kbd.c b/pc/kbd.c index 27f70a4a6e1608f130dad6523b54405328317615..36898d0844842eac7176a10d608951e4acc7f42c 100644 --- a/pc/kbd.c +++ b/pc/kbd.c @@ -25,7 +25,7 @@ enum { PF= Spec|0x20, /* num pad function key */ View= Spec|0x00, /* view (shift window up) */ - KF= Spec|0x40, /* function key */ + KF= 0xF000, /* function key (begin Unicode private space) */ Shift= Spec|0x60, Break= Spec|0x61, Ctrl= Spec|0x62, @@ -39,16 +39,16 @@ enum { Up= KF|14, Pgup= KF|15, Print= KF|16, - Left= View, - Right= View, + Left= KF|17, + Right= KF|18, End= '\r', Down= View, - Pgdown= View, + Pgdown= KF|19, Ins= KF|20, Del= 0x7F, }; -uchar kbtab[] = +Rune kbtab[] = { [0x00] No, 0x1b, '1', '2', '3', '4', '5', '6', [0x08] '7', '8', '9', '0', '-', '=', '\b', '\t', @@ -68,7 +68,7 @@ uchar kbtab[] = [0x78] No, View, No, KF|14, No, No, No, No, }; -uchar kbtabshift[] = +Rune kbtabshift[] = { [0x00] No, 0x1b, '!', '@', '#', '$', '%', '^', [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t', @@ -88,7 +88,7 @@ uchar kbtabshift[] = [0x78] No, KF|14, No, KF|14, No, No, No, No, }; -uchar kbtabesc1[] = +Rune kbtabesc1[] = { [0x00] No, No, No, No, No, No, No, No, [0x08] No, No, No, No, No, No, No, No, @@ -231,7 +231,7 @@ i8042intr(Ureg*, void*) static int esc1, esc2; static int alt, caps, ctl, num, shift; static int collecting, nk; - static uchar kc[5]; + static Rune kc[5]; int keyup; /* @@ -314,7 +314,7 @@ i8042intr(Ureg*, void*) /* * normal character */ - if(!(c & Spec)){ + if(!(c & (Spec|KF))){ if(ctl){ if(alt && c == Del) exit(0); diff --git a/pc/screen.c b/pc/screen.c index d8da276b246cbb07740e09d49679e8c38f9c2f9f..2ef2f428861d80429c5da8d2f72f9316f80f7429 100644 --- a/pc/screen.c +++ b/pc/screen.c @@ -13,26 +13,14 @@ #include #include "screen.h" -static ulong onesbits = ~0; -static Memdata onesdata = { - nil, - &onesbits, -}; -static Memimage xones = { - { 0, 0, 1, 1 }, - { -100000, -100000, 100000, 100000 }, - 3, - 1, - &onesdata, - 0, - 1 -}; -Memimage *memones = &xones; +#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) Point ZP = {0, 0}; +Rectangle physgscreenr; + Memdata gscreendata; -Memimage gscreen; +Memimage *gscreen; VGAscr vgascreen[1]; @@ -51,10 +39,11 @@ Cursor arrow = { }; int -screensize(int x, int y, int z) +screensize(int x, int y, int z, ulong chan) { VGAscr *scr; + memimageinit(); scr = &vgascreen[0]; /* @@ -62,36 +51,38 @@ screensize(int x, int y, int z) * be given back if aperture is set. */ if(scr->aperture == 0){ - int width = (x*(1<useflush = 1; - scr->aperture = 0xA0000; scr->apsize = 1<<16; } else - gscreendata.data = KADDR(scr->aperture); + gscreendata.bdata = KADDR(scr->aperture); - gscreen.data = &gscreendata; - gscreen.ldepth = z; - gscreen.width = (x*(1<gscreendata = gscreen.data; - scr->memdefont = getmemdefont(); - scr->gscreen = &gscreen; + gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata); + vgaimageinit(chan); + if(gscreen == nil) + return -1; -// memset(gscreen.data->data, Backgnd, scr->apsize); +/* memset(gscreen->data->bdata, 0x15, (x*y*z+7)/8); /* RSC BUG */ + memfillcolor(gscreen, DRed); - drawcmap(0); + scr->palettedepth = 6; /* default */ + scr->gscreendata = &gscreendata; + scr->memdefont = getmemdefont(); + scr->gscreen = gscreen; + physgscreenr = gscreen->r; + + drawcmap(1); return 0; } @@ -114,8 +105,7 @@ screenaperture(int size, int align) aperture = scr->dev->linear(scr, &size, &align); if(aperture == 0) return 1; - } - else{ + }else{ aperture = upamalloc(0, size, align); if(aperture == 0) return 1; @@ -131,8 +121,8 @@ screenaperture(int size, int align) return 0; } -ulong* -attachscreen(Rectangle* r, int* ld, int* width, int *softscreen) +uchar* +attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen) { VGAscr *scr; @@ -141,13 +131,17 @@ attachscreen(Rectangle* r, int* ld, int* width, int *softscreen) return nil; *r = scr->gscreen->r; - *ld = scr->gscreen->ldepth; + *chan = scr->gscreen->chan; + *d = scr->gscreen->depth; *width = scr->gscreen->width; *softscreen = scr->useflush; - return scr->gscreendata->data; + return scr->gscreendata->bdata; } +/* + * It would be fair to say that this doesn't work for >8-bit screens. + */ void flushmemscreen(Rectangle r) { @@ -166,27 +160,28 @@ flushmemscreen(Rectangle r) incs = scr->gscreen->width * BY2WD; - switch(scr->gscreen->ldepth){ + switch(scr->gscreen->depth){ default: len = 0; - panic("flushmemscreen: ldepth\n"); + panic("flushmemscreen: depth\n"); break; - case 3: + case 8: len = Dx(r); break; } if(len < 1) return; - off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x>>(3-scr->gscreen->ldepth)); + off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8; page = off/scr->apsize; off %= scr->apsize; disp = KADDR(scr->aperture); sdisp = disp+off; edisp = disp+scr->apsize; - off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x>>(3-scr->gscreen->ldepth)); - sp = ((uchar*)scr->gscreendata->data) + off; + off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8; + + sp = scr->gscreendata->bdata + off; scr->dev->page(scr, page); for(y = r.min.y; y < r.max.y; y++) { @@ -225,11 +220,11 @@ getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb) if(scr->gscreen == nil) return; - switch(scr->gscreen->ldepth){ + switch(scr->gscreen->depth){ default: x = 0x0F; break; - case 3: + case 8: x = 0xFF; break; } @@ -243,38 +238,59 @@ getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb) unlock(&cursor); } +int +setpalette(ulong p, ulong r, ulong g, ulong b) +{ + VGAscr *scr; + int d; + + scr = &vgascreen[0]; + d = scr->palettedepth; + + lock(&cursor); + scr->colormap[p][0] = r; + scr->colormap[p][1] = g; + scr->colormap[p][2] = b; + vgao(PaddrW, p); + vgao(Pdata, r>>(32-d)); + vgao(Pdata, g>>(32-d)); + vgao(Pdata, b>>(32-d)); + unlock(&cursor); + + return ~0; +} + +/* + * On some video cards (e.g. Mach64), the palette is used as the + * DAC registers for >8-bit modes. We don't want to set them when the user + * is trying to set a colormap and the card is in one of these modes. + */ int setcolor(ulong p, ulong r, ulong g, ulong b) { VGAscr *scr; - ulong x; + int x; scr = &vgascreen[0]; if(scr->gscreen == nil) return 0; - switch(scr->gscreen->ldepth){ - default: + switch(scr->gscreen->depth){ + case 1: + case 2: + case 4: x = 0x0F; break; - case 3: + case 8: x = 0xFF; break; + default: + return 0; } p &= x; p ^= x; - lock(&cursor); - scr->colormap[p][0] = r; - scr->colormap[p][1] = g; - scr->colormap[p][2] = b; - vgao(PaddrW, p); - vgao(Pdata, r>>(32-6)); - vgao(Pdata, g>>(32-6)); - vgao(Pdata, b>>(32-6)); - unlock(&cursor); - - return ~0; + return setpalette(p, r, g, b); } int @@ -312,3 +328,190 @@ setcursor(Cursor* curs) scr->cur->load(scr, curs); } + +static ulong +pixelbits(Memimage *i, Point pt) +{ + uchar *p; + ulong val; + int off, bpp, npack; + + val = 0; + p = byteaddr(i, pt); + switch(bpp=i->depth){ + case 1: + case 2: + case 4: + npack = 8/bpp; + off = pt.x%npack; + val = p[0] >> bpp*(npack-1-off); + val &= (1<chan; chan; chan>>=8){ + nb = NBITS(chan); + ov = v = val&((1<>= nb; + + while(nb < 8){ + v |= v<>= (nb-8); + + switch(TYPE(chan)){ + case CRed: + r = v; + break; + case CGreen: + g = v; + break; + case CBlue: + b = v; + break; + case CAlpha: + a = v; + break; + case CGrey: + r = g = b = v; + break; + case CMap: + p = img->cmap->cmap2rgb+3*ov; + r = *p++; + g = *p++; + b = *p; + break; + } + } + return (r<<24)|(g<<16)|(b<<8)|a; +} + +static ulong +rgbatoimg(Memimage *img, ulong rgba) +{ + ulong chan; + int d, nb; + ulong v; + uchar *p, r, g, b, a, m; + + v = 0; + r = rgba>>24; + g = rgba>>16; + b = rgba>>8; + a = rgba; + d = 0; + for(chan=img->chan; chan; chan>>=8){ + nb = NBITS(chan); + switch(TYPE(chan)){ + case CRed: + v |= (r>>(8-nb))<>(8-nb))<>(8-nb))<>(8-nb))<cmap->rgb2cmap; + m = p[(r>>4)*256+(g>>4)*16+(b>>4)]; + v |= m<dst; + scr = &vgascreen[0]; + if(dst == nil || dst->data == nil) + return 0; + + if(dst->data->bdata != gscreendata.bdata) + return 0; + +// if(dst->data != &gscreendata){ +// lastbad = dst->data; +// lastbadi = dst; +// return 0; +// } + + if(scr->fill==nil && scr->scroll==nil) + return 0; + + /* + * If we have an opaque mask and source is one opaque pixel we can convert to the + * destination format and just replicate with memset. + */ + if(scr->fill && (par->state&(Simplemask|Simplesrc|Fullmask))==(Simplemask|Simplesrc|Fullmask)) + return scr->fill(scr, par->r, par->sdval); + + /* + * If no source alpha, an opaque mask, we can just copy the + * source onto the destination. If the channels are the same and + * the source is not replicated, memmove suffices. + */ + src = par->src; + if(scr->scroll && src->data->bdata==dst->data->bdata && !(src->flags&Falpha) + && (par->state&(Simplemask|Fullmask))==(Simplemask|Fullmask)){ + if(src->zero != dst->zero){ + lastbadsrc = src; + lastbaddst = dst; + iprint("#"); + } + return scr->scroll(scr, par->r, par->sr); + } + + return 0; +} +#endif diff --git a/pc/screen.h b/pc/screen.h index ac896752d94c2e630a80b69dca75e39bcbe6c344..b7516eae0538541d0936d0170c23fbaedad8292a 100644 --- a/pc/screen.h +++ b/pc/screen.h @@ -66,6 +66,9 @@ struct VGAdev { void (*disable)(VGAscr*); void (*page)(VGAscr*, int); ulong (*linear)(VGAscr*, int*, int*); + void (*drawinit)(VGAscr*); + int (*fill)(VGAscr*, Rectangle, ulong); + }; struct VGAcur { @@ -75,6 +78,8 @@ struct VGAcur { void (*disable)(VGAscr*); void (*load)(VGAscr*, Cursor*); int (*move)(VGAscr*, Point); + + int doespanning; }; /* @@ -96,15 +101,22 @@ struct VGAscr { ulong io; /* device specific registers */ ulong colormap[Pcolours][3]; + int palettedepth; + ulong *mmio; Memimage* gscreen; Memdata* gscreendata; Memsubfont* memdefont; + + int (*fill)(VGAscr*, Rectangle, ulong); + int (*scroll)(VGAscr*, Rectangle, Rectangle); + ulong id; /* internal identifier for driver use */ }; + extern VGAscr vgascreen[]; enum { - Backgnd = Pwhite, + Backgnd = 0, /* black */ }; /* mouse.c */ @@ -115,8 +127,14 @@ extern void flushmemscreen(Rectangle); extern int cursoron(int); extern void cursoroff(int); extern void setcursor(Cursor*); -extern int screensize(int, int, int); +extern int screensize(int, int, int, ulong); extern int screenaperture(int, int); +extern Rectangle physgscreenr; /* actual monitor size */ +extern void deletescreenimage(void); /* vga.c */ extern void vgascreenwin(VGAscr*); +extern void vgaimageinit(ulong); +extern ulong vgapcilinear(VGAscr*, int*, int*, int, int); + +extern void drawblankscreen(int); diff --git a/pc/vga.c b/pc/vga.c index 7ca41d658d1d7f0020fe4a16a9837216f4a5e342..7732e446227d88e9760b0e25a166585fe6cabdd2 100644 --- a/pc/vga.c +++ b/pc/vga.c @@ -11,42 +11,37 @@ #include #include "screen.h" -static ulong backbits = (Backgnd<<24)|(Backgnd<<16)|(Backgnd<<8)|Backgnd; -static Memdata backdata = { - nil, - &backbits -}; -static Memimage xback = { - { 0, 0, 1, 1 }, - { -100000, -100000, 100000, 100000 }, - 3, - 1, - &backdata, - 0, - 1 -}; -static Memimage* back = &xback; - -static ulong consbits = 0; -static Memdata consdata = { - nil, - &consbits -}; -static Memimage conscol = { - { 0, 0, 1, 1 }, - { -100000, -100000, 100000, 100000 }, - 3, - 1, - &consdata, - 0, - 1 -}; +static Memimage* back; +static Memimage *conscol; static Point curpos; static Rectangle window; static int *xp; static int xbuf[256]; static Lock vgascreenlock; +int drawdebug; + +void +vgaimageinit(ulong chan) +{ + if(back == nil){ + back = allocmemimage(Rect(0,0,1,1), chan); /* RSC BUG */ + if(back == nil) + panic("back alloc"); /* RSC BUG */ + back->flags |= Frepl; + back->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); + memfillcolor(back, DBlack); + } + + if(conscol == nil){ + conscol = allocmemimage(Rect(0,0,1,1), chan); /* RSC BUG */ + if(conscol == nil) + panic("conscol alloc"); /* RSC BUG */ + conscol->flags |= Frepl; + conscol->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); + memfillcolor(conscol, DWhite); + } +} static void vgascroll(VGAscr* scr) @@ -59,9 +54,9 @@ vgascroll(VGAscr* scr) o = 8*h; r = Rpt(window.min, Pt(window.max.x, window.max.y-o)); p = Pt(window.min.x, window.min.y+o); - memimagedraw(scr->gscreen, r, scr->gscreen, p, memones, p); + memimagedraw(scr->gscreen, r, scr->gscreen, p, nil, p); r = Rpt(Pt(window.min.x, window.max.y-o), window.max); - memimagedraw(scr->gscreen, r, back, ZP, memones, ZP); + memimagedraw(scr->gscreen, r, back, ZP, nil, ZP); curpos.y -= o; } @@ -73,6 +68,7 @@ vgascreenputc(VGAscr* scr, char* buf, Rectangle *flushr) int h, w, pos; Rectangle r; +// drawdebug = 1; if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)]) xp = xbuf; @@ -100,7 +96,7 @@ vgascreenputc(VGAscr* scr, char* buf, Rectangle *flushr) pos = (curpos.x-window.min.x)/w; pos = 4-(pos%4); r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y+h); - memimagedraw(scr->gscreen, r, back, back->r.min, memones, back->r.min); + memimagedraw(scr->gscreen, r, back, back->r.min, nil, ZP); bbox(flushr, r); curpos.x += pos*w; break; @@ -110,7 +106,7 @@ vgascreenputc(VGAscr* scr, char* buf, Rectangle *flushr) break; xp--; r = Rect(*xp, curpos.y, curpos.x, curpos.y+h); - memimagedraw(scr->gscreen, r, back, back->r.min, memones, back->r.min); + memimagedraw(scr->gscreen, r, back, back->r.min, nil, ZP); bbox(flushr, r); curpos.x = *xp; break; @@ -124,11 +120,12 @@ vgascreenputc(VGAscr* scr, char* buf, Rectangle *flushr) *xp++ = curpos.x; r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y+h); - memimagedraw(scr->gscreen, r, back, back->r.min, memones, back->r.min); - memimagestring(scr->gscreen, curpos, &conscol, scr->memdefont, buf); + memimagedraw(scr->gscreen, r, back, back->r.min, nil, back->r.min); + memimagestring(scr->gscreen, curpos, conscol, scr->memdefont, buf); bbox(flushr, r); curpos.x += w; } +// drawdebug = 0; } static void @@ -192,3 +189,4 @@ vgascreenwin(VGAscr* scr) screenputs = vgascreenputs; } + diff --git a/pc/vgaark2000pv.c b/pc/vgaark2000pv.c index 3dfb96e18cf3d0760144de200d348a01f7657bad..d42eccc3361f6fad7f4becfc8365d2e03bb49b20 100644 --- a/pc/vgaark2000pv.c +++ b/pc/vgaark2000pv.c @@ -55,12 +55,12 @@ ark2000pvenable(VGAscr* scr) vgaxo(Seqx, 0x20, seq20); seq20 |= 0x18; - vgaxo(Seqx, 0x26, Pwhite); - vgaxo(Seqx, 0x27, Pwhite); - vgaxo(Seqx, 0x28, Pwhite); - vgaxo(Seqx, 0x29, Pblack); - vgaxo(Seqx, 0x2A, Pblack); - vgaxo(Seqx, 0x2B, Pblack); + vgaxo(Seqx, 0x26, 0x00); + vgaxo(Seqx, 0x27, 0x00); + vgaxo(Seqx, 0x28, 0x00); + vgaxo(Seqx, 0x29, 0xFF); + vgaxo(Seqx, 0x2A, 0xFF); + vgaxo(Seqx, 0x2B, 0xFF); /* * Cursor storage is a 256 byte or 1Kb block located in the last diff --git a/pc/vgacyber938x.c b/pc/vgacyber938x.c index 5794394ca4ed3911232442d9c3aff5df9207bca2..00cd74faf7e06de9386a8cfb97124a3ea1fd01f8 100644 --- a/pc/vgacyber938x.c +++ b/pc/vgacyber938x.c @@ -167,9 +167,9 @@ cyber938xcurenable(VGAscr* scr) * Cursor colours. */ for(i = 0x48; i < 0x4C; i++) - vgaxo(Crtx, i, Pwhite); + vgaxo(Crtx, i, 0x00); for(i = 0x4C; i < 0x50; i++) - vgaxo(Crtx, i, Pblack); + vgaxo(Crtx, i, 0xFF); /* * Find a place for the cursor data in display memory. diff --git a/pc/vgamach64xx.c b/pc/vgamach64xx.c index 92ce7b44d43e74de4f5955ae8070de2b9f2d6e7c..33694d16da12ed97fc5e36920e81b9ac868b9672 100644 --- a/pc/vgamach64xx.c +++ b/pc/vgamach64xx.c @@ -13,7 +13,7 @@ #include "screen.h" /* - * ATI Mach64(CT|ET|G*|VT|VU). + * ATI Mach64(CT|ET|G*|VT|VU|LP). */ static ushort mach64xxdid[] = { ('C'<<8)|'T', @@ -25,13 +25,16 @@ static ushort mach64xxdid[] = { ('G'<<8)|'Q', ('G'<<8)|'T', ('G'<<8)|'U', - ('G'<<8)|'V', - ('G'<<8)|'Z', ('V'<<8)|'T', ('V'<<8)|'U', + ('L'<<8)|'P', 0, }; +static int hwfill(VGAscr*, Rectangle, ulong); +static int hwscroll(VGAscr*, Rectangle, Rectangle); +static void initengine(VGAscr*); + static Pcidev* mach64xxpci(void) { @@ -66,6 +69,7 @@ mach64xxenable(VGAscr* scr) * this will do for now. */ scr->io = p->mem[1].bar & ~0x03; + if(scr->io == 0 && p->did == ('C'<<8)|'T') scr->io = 0x2EC; } @@ -74,10 +78,12 @@ mach64xxenable(VGAscr* scr) static ulong mach64xxlinear(VGAscr* scr, int* size, int* align) { - ulong aperture, oaperture; + ulong aperture, osize, oaperture; int oapsize, wasupamem; Pcidev *p; + Physseg seg; + osize = *size; oaperture = scr->aperture; oapsize = scr->apsize; wasupamem = scr->isupamem; @@ -100,27 +106,126 @@ mach64xxlinear(VGAscr* scr, int* size, int* align) else scr->isupamem = 1; + scr->mmio = (ulong*)(aperture+osize-0x400); + if(oaperture) + print("warning (BUG): redefinition of aperture does not change mach64mmio segment\n"); + memset(&seg, 0, sizeof(seg)); + seg.attr = SG_PHYSICAL; + seg.name = smalloc(NAMELEN); + snprint(seg.name, NAMELEN, "mach64mmio"); + seg.pa = aperture+osize - BY2PG; + seg.size = BY2PG; + addphysseg(&seg); + + seg.name = smalloc(NAMELEN); + snprint(seg.name, NAMELEN, "mach64screen"); + seg.pa = aperture; + seg.size = osize; + addphysseg(&seg); + return aperture; } enum { + CrtcOffPitch = 0x05, + CrtcGenCtl = 0x07, CurClr0 = 0x0B, /* I/O Select */ CurClr1 = 0x0C, CurOffset = 0x0D, CurHVposn = 0x0E, CurHVoff = 0x0F, - + BusCntl = 0x13, GenTestCntl = 0x19, + + ContextMask = 0x100, /* not accessible via I/O */ + FifoStat, + GuiStat, + DpFrgdClr, + DpBkgdClr, + DpWriteMask, + DpMix, + DpPixWidth, + DpSrc, + ClrCmpCntl, + GuiTrajCntl, + ScLeftRight, + ScTopBottom, + DstOffPitch, + DstYX, + DstHeightWidth, + DstCntl, + DstHeight, + DstBresErr, + DstBresInc, + DstBresDec, + SrcCntl, + SrcHeight1Width1, + SrcHeight2Width2, + SrcYX, + SrcWidth1, + SrcYXstart, + HostCntl, + PatReg0, + PatReg1, + PatCntl, + ScBottom, + ScLeft, + ScRight, + ScTop, + ClrCmpClr, + ClrCmpMask, + DpChainMask, + SrcOffPitch, }; static uchar mmoffset[] = { + [CrtcOffPitch] 0x05, [CurClr0] 0x18, [CurClr1] 0x19, [CurOffset] 0x1A, [CurHVposn] 0x1B, [CurHVoff] 0x1C, - + [BusCntl] 0x28, [GenTestCntl] 0x34, + [DstOffPitch] 0x40, + [DstYX] 0x43, + [DstHeight] 0x45, + [DstHeightWidth] 0x46, + [DstBresErr] 0x49, + [DstBresInc] 0x4A, + [DstBresDec] 0x4B, + [DstCntl] 0x4C, + [SrcOffPitch] 0x60, + [SrcYX] 0x63, + [SrcWidth1] 0x64, + [SrcYXstart] 0x69, + [SrcHeight1Width1] 0x66, + [SrcHeight2Width2] 0x6C, + [SrcCntl] 0x6D, + [HostCntl] 0x90, + [PatReg0] 0xA0, + [PatReg1] 0xA1, + [PatCntl] 0xA2, + [ScLeft] 0xA8, + [ScRight] 0xA9, + [ScLeftRight] 0xAA, + [ScTop] 0xAB, + [ScBottom] 0xAC, + [ScTopBottom] 0xAD, + [DpBkgdClr] 0xB0, + [DpFrgdClr] 0xB1, + [DpWriteMask] 0xB2, + [DpChainMask] 0xB3, + [DpPixWidth] 0xB4, + [DpMix] 0xB5, + [DpSrc] 0xB6, + [ClrCmpClr] 0xC0, + [ClrCmpMask] 0xC1, + [ClrCmpCntl] 0xC2, + [FifoStat] 0xC4, + [ContextMask] 0xC8, + [GuiTrajCntl] 0xCC, + [GuiStat] 0xCE, }; static ulong @@ -128,6 +233,8 @@ ior32(VGAscr* scr, int r) { if(scr->io == 0x2EC || scr->io == 0x1C8) return inl((r<<10)+scr->io); + if(r >= 0x100 && scr->mmio != nil) + return scr->mmio[mmoffset[r]]; return inl((mmoffset[r]<<2)+scr->io); } @@ -136,6 +243,8 @@ iow32(VGAscr* scr, int r, ulong l) { if(scr->io == 0x2EC || scr->io == 0x1C8) outl(((r)<<10)+scr->io, l); + else if(r >= 0x100 && scr->mmio != nil) + scr->mmio[mmoffset[r]] = l; else outl((mmoffset[r]<<2)+scr->io, l); } @@ -207,10 +316,76 @@ mach64xxcurload(VGAscr* scr, Cursor* curs) iow32(scr, GenTestCntl, 0x80|r); } +static int +ptalmostinrect(Point p, Rectangle r) +{ + return p.x>=r.min.x && p.x<=r.max.x && + p.y>=r.min.y && p.y<=r.max.y; +} + +/* + * If necessary, translate the rectangle physr + * some multiple of [dx dy] so that it includes p. + * Return 1 if the rectangle changed. + */ +static int +screenpan(Point p, Rectangle *physr, int dx, int dy) +{ + int d; + + if(ptalmostinrect(p, *physr)) + return 0; + + if(p.y < physr->min.y){ + d = physr->min.y - (p.y&~(dy-1)); + physr->min.y -= d; + physr->max.y -= d; + } + if(p.y > physr->max.y){ + d = ((p.y+dy-1)&~(dy-1)) - physr->max.y; + physr->min.y += d; + physr->max.y += d; + } + + if(p.x < physr->min.x){ + d = physr->min.x - (p.x&~(dx-1)); + physr->min.x -= d; + physr->max.x -= d; + } + if(p.x > physr->max.x){ + d = ((p.x+dx-1)&~(dx-1)) - physr->max.x; + physr->min.x += d; + physr->max.x += d; + } + return 1; +} + static int mach64xxcurmove(VGAscr* scr, Point p) { int x, xo, y, yo; + int dx; + ulong off, pitch; + + /* + * If the point we want to display is outside the current + * screen rectangle, pan the screen to display it. + * + * We have to move in 64-bit chunks. + */ + if(scr->gscreen->depth == 24) + dx = (64*3)/24; + else + dx = 64 / scr->gscreen->depth; + + if(screenpan(p, &physgscreenr, dx, 1)){ + off = (physgscreenr.min.y*Dx(scr->gscreen->r)+physgscreenr.min.x)/dx; + pitch = Dx(scr->gscreen->r)/8; + iow32(scr, CrtcOffPitch, (pitch<<22)|off); + } + + p.x -= physgscreenr.min.x; + p.y -= physgscreenr.min.y; /* * Mustn't position the cursor offscreen even partially, @@ -276,6 +451,219 @@ mach64xxcurenable(VGAscr* scr) iow32(scr, GenTestCntl, 0x80|r); } +static void +waitforfifo(VGAscr *scr, int entries) +{ + int x; + x = 0; + while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000) + ; + if(x >= 1000000) + iprint("fifo %d stat %.8lux %.8lux scrio %.8lux mmio %p scr %p pc %luX\n", entries, ior32(scr, FifoStat), scr->mmio[mmoffset[FifoStat]], scr->io, scr->mmio, scr, getcallerpc(&scr)); +} + +static void +waitforidle(VGAscr *scr) +{ + int x; + waitforfifo(scr, 16); + x = 0; + while((ior32(scr, GuiStat)&1) && x++ < 1000000) + ; + if(x >= 1000000) + iprint("idle stat %.8lux %.8lux scrio %.8lux mmio %p scr %p pc %luX\n", ior32(scr, GuiStat), scr->mmio[mmoffset[GuiStat]], scr->io, scr->mmio, scr, getcallerpc(&scr)); +} + +static void +resetengine(VGAscr *scr) +{ + ulong x; + x = ior32(scr, GenTestCntl); + iow32(scr, GenTestCntl, x&~0x100); + iow32(scr, GenTestCntl, x|0x100); + iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000); +} + +static void +initengine(VGAscr *scr) +{ + ulong pitch; + + pitch = Dx(scr->gscreen->r)/8; + if(scr->gscreen->depth == 24) + pitch *= 3; + + resetengine(scr); + waitforfifo(scr, 14); + iow32(scr, ContextMask, ~0); + iow32(scr, DstOffPitch, pitch<<22); + iow32(scr, DstYX, 0); + iow32(scr, DstHeight, 0); + iow32(scr, DstBresErr, 0); + iow32(scr, DstBresInc, 0); + iow32(scr, DstBresDec, 0); + iow32(scr, DstCntl, 0x23); + iow32(scr, SrcOffPitch, pitch<<22); + iow32(scr, SrcYX, 0); + iow32(scr, SrcHeight1Width1, 1); + iow32(scr, SrcYXstart, 0); + iow32(scr, SrcHeight2Width2, 1); + iow32(scr, SrcCntl, 0x01); + + waitforfifo(scr, 13); + iow32(scr, HostCntl, 0); + iow32(scr, PatReg0, 0); + iow32(scr, PatReg1, 0); + iow32(scr, PatCntl, 0); + iow32(scr, ScLeft, 0); + iow32(scr, ScTop, 0); + iow32(scr, ScBottom, 0xFFFF); + iow32(scr, ScRight, 0xFFFF); + iow32(scr, DpBkgdClr, 0); + iow32(scr, DpFrgdClr, ~0); + iow32(scr, DpWriteMask, ~0); + iow32(scr, DpMix, 0x70003); + iow32(scr, DpSrc, 0x00010100); + + waitforfifo(scr, 3); + iow32(scr, ClrCmpClr, 0); + iow32(scr, ClrCmpMask, ~0); + iow32(scr, ClrCmpCntl, 0); + + waitforfifo(scr, 2); + switch(scr->gscreen->depth){ + case 8: + case 24: /* [sic] */ + iow32(scr, DpPixWidth, 0x00020202); + iow32(scr, DpChainMask, 0x8080); + break; + case 16: + iow32(scr, DpPixWidth, 0x00040404); + iow32(scr, DpChainMask, 0x8410); + break; + case 32: + iow32(scr, DpPixWidth, 0x00060606); + iow32(scr, DpChainMask, 0x8080); + break; + } + + waitforidle(scr); +} + +static int +mach64hwfill(VGAscr *scr, Rectangle r, ulong sval) +{ + ulong pitch; + ulong ctl; + +if(drawdebug) + iprint("hwfill %R val %lux...\n", r, sval); + + /* shouldn't happen */ + if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0) + return 0; + + pitch = Dx(scr->gscreen->r)/8; + ctl = 1|2; /* left-to-right, top-to-bottom */ + if(scr->gscreen->depth == 24){ + r.min.x *= 3; + r.max.x *= 3; + pitch *= 3; + ctl |= (1<<7)|(((r.min.x/4)%6)<<8); + } + + waitforfifo(scr, 11); + iow32(scr, DpFrgdClr, sval); + iow32(scr, DpWriteMask, 0xFFFFFFFF); + iow32(scr, DpMix, 0x00070003); + iow32(scr, DpSrc, 0x00000111); + iow32(scr, ClrCmpCntl, 0x00000000); + iow32(scr, ScLeftRight, 0x1FFF0000); + iow32(scr, ScTopBottom, 0x1FFF0000); + iow32(scr, DstOffPitch, pitch<<22); + iow32(scr, DstCntl, ctl); + iow32(scr, DstYX, (r.min.x<<16)|r.min.y); + iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r)); + + waitforidle(scr); + return 1; +} + +static int +mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr) +{ + ulong pitch; + Point dp, sp; + ulong ctl; + int dx, dy; + + dx = Dx(r); + dy = Dy(r); + pitch = Dx(scr->gscreen->r)/8; + if(scr->gscreen->depth == 24){ + dx *= 3; + pitch *= 3; + r.min.x *= 3; + sr.min.x *= 3; + } + + ctl = 0; + if(r.min.x <= sr.min.x){ + ctl |= 1; + dp.x = r.min.x; + sp.x = sr.min.x; + }else{ + dp.x = r.min.x+dx-1; + sp.x = sr.min.x+dx-1; + } + + if(r.min.y <= sr.min.y){ + ctl |= 2; + dp.y = r.min.y; + sp.y = sr.min.y; + }else{ + dp.y = r.min.y+dy-1; + sp.y = sr.min.y+dy-1; + } + + if(scr->gscreen->depth == 24) + ctl |= (1<<7)|(((dp.x/4)%6)<<8); + + waitforfifo(scr, 6); + iow32(scr, ScLeftRight, 0x1FFF0000); + iow32(scr, ScTopBottom, 0x1FFF0000); + iow32(scr, DpWriteMask, 0xFFFFFFFF); + iow32(scr, DpMix, 0x00070003); + iow32(scr, DpSrc, 0x00000300); + iow32(scr, ClrCmpCntl, 0x00000000); + + waitforfifo(scr, 8); + iow32(scr, SrcOffPitch, pitch<<22); + iow32(scr, SrcCntl, 0x00000000); + iow32(scr, SrcYX, (sp.x<<16)|sp.y); + iow32(scr, SrcWidth1, dx); + iow32(scr, DstOffPitch, pitch<<22); + iow32(scr, DstCntl, ctl); + + iow32(scr, DstYX, (dp.x<<16)|dp.y); + iow32(scr, DstHeightWidth, (dx<<16)|dy); + + waitforidle(scr); + + return 1; +} + +static void +mach64xxdrawinit(VGAscr *scr) +{ + if(scr->io > 0x2FF){ + initengine(scr); + scr->fill = mach64hwfill; + scr->scroll = mach64hwscroll; + } +} + + VGAdev vgamach64xxdev = { "mach64xx", @@ -283,6 +671,7 @@ VGAdev vgamach64xxdev = { 0, /* disable */ 0, /* page */ mach64xxlinear, /* linear */ + mach64xxdrawinit, /* drawinit */ }; VGAcur vgamach64xxcur = { @@ -292,4 +681,6 @@ VGAcur vgamach64xxcur = { mach64xxcurdisable, /* disable */ mach64xxcurload, /* load */ mach64xxcurmove, /* move */ + + 1 /* doespanning */ }; diff --git a/pc/vgas3.c b/pc/vgas3.c index c7acfb8503243e480aba5e525616ef4525ce7948..19add082de133bf0f72aa2af52e495fb58a2347a 100644 --- a/pc/vgas3.c +++ b/pc/vgas3.c @@ -19,7 +19,7 @@ s3pageset(VGAscr* scr, int page) int opage; crt35 = vgaxi(Crtx, 0x35); - if(scr->gscreen->ldepth == 3){ + if(scr->gscreen->depth >= 8){ /* * The S3 registers need to be unlocked for this. * Let's hope they are already: @@ -64,14 +64,14 @@ s3page(VGAscr* scr, int page) static ulong s3linear(VGAscr* scr, int* size, int* align) { - ulong aperture, oaperture, osize; - int oapsize, wasupamem; + ulong aperture, oaperture; + int osize, oapsize, wasupamem; Pcidev *p; Physseg seg; + osize = *size; oaperture = scr->aperture; oapsize = scr->apsize; - osize = *size; wasupamem = scr->isupamem; if(wasupamem) upafree(oaperture, oapsize); @@ -92,6 +92,8 @@ s3linear(VGAscr* scr, int* size, int* align) else scr->isupamem = 1; + if(oaperture) + print("warning (BUG): redefinition of aperture does not change s3screen segment\n"); memset(&seg, 0, sizeof(seg)); seg.attr = SG_PHYSICAL; seg.name = smalloc(NAMELEN); @@ -99,6 +101,7 @@ s3linear(VGAscr* scr, int* size, int* align) seg.pa = aperture; seg.size = osize; addphysseg(&seg); + return aperture; } @@ -130,7 +133,7 @@ s3disable(VGAscr*) static void s3enable(VGAscr* scr) { - int i, id; + int i; ulong storage; s3disable(scr); @@ -138,30 +141,16 @@ s3enable(VGAscr* scr) /* * Cursor colours. Set both the CR0[EF] and the colour * stack in case we are using a 16-bit RAMDAC. - * This stuff is just a mystery for the ViRGE/GX2. */ vgaxo(Crtx, 0x0E, Pwhite); vgaxo(Crtx, 0x0F, Pblack); vgaxi(Crtx, 0x45); - id = (vgaxi(Crtx, 0x30)<<8)|vgaxi(Crtx, 0x2E); - switch(id){ - - case 0xE110: /* ViRGE/GX2 */ - for(i = 0; i < 3; i++) - vgaxo(Crtx, 0x4A, Pblack); - vgaxi(Crtx, 0x45); - for(i = 0; i < 3; i++) - vgaxo(Crtx, 0x4B, Pwhite); - break; - default: - for(i = 0; i < 3; i++) - vgaxo(Crtx, 0x4A, Pwhite); - vgaxi(Crtx, 0x45); - for(i = 0; i < 3; i++) - vgaxo(Crtx, 0x4B, Pblack); - break; - } + for(i = 0; i < 3; i++) + vgaxo(Crtx, 0x4A, Pblack); + vgaxi(Crtx, 0x45); + for(i = 0; i < 3; i++) + vgaxo(Crtx, 0x4B, Pwhite); /* * Find a place for the cursor data in display memory. @@ -198,8 +187,10 @@ s3load(VGAscr* scr, Cursor* curs) id = (vgaxi(Crtx, 0x30)<<8)|vgaxi(Crtx, 0x2E); switch(id){ - case 0xE110: /* ViRGE/GX2 */ case 0xE131: /* ViRGE */ + case 0xE18A: /* ViRGE/[DG]X */ + case 0xE110: /* ViRGE/GX2 */ + case 0xE13D: /* ViRGE/VX */ p += scr->storage; break; @@ -242,8 +233,10 @@ s3load(VGAscr* scr, Cursor* curs) switch(id){ - case 0xE110: /* ViRGE/GX2 */ case 0xE131: /* ViRGE */ + case 0xE18A: /* ViRGE/[DG]X */ + case 0xE110: /* ViRGE/GX2 */ + case 0xE13D: /* ViRGE/VX */ break; default: @@ -297,6 +290,182 @@ s3move(VGAscr* scr, Point p) return 0; } +/* + * The manual gives byte offsets, but we want ulong offsets, hence /4. + */ +enum { + SrcBase = 0xA4D4/4, + DstBase = 0xA4D8/4, + Stride = 0xA4E4/4, + FgrdData = 0xA4F4/4, + WidthHeight = 0xA504/4, + SrcXY = 0xA508/4, + DestXY = 0xA50C/4, + Command = 0xA500/4, + SubStat = 0x8504/4, + FifoStat = 0x850C/4, +}; + +/* + * Wait for writes to VGA memory via linear aperture to flush. + */ +enum {Maxloop = 1<<24}; +struct { + ulong linear; + ulong fifo; + ulong idle; +} waitcount; + +static void +waitforlinearfifo(VGAscr *scr) +{ + ulong *mmio; + long x; + static ulong nwaitforlinearfifo; + ulong mask, val; + + switch(scr->id){ + default: + panic("unknown scr->id in s3 waitforlinearfifo"); + case 0xE131: /* ViRGE */ + case 0xE13D: /* ViRGE/VX */ + mask = 0x0F<<6; + val = 0x08<<6; + break; + case 0xE110: /* ViRGE/GX2 */ + mask = 0x1F<<6; + val = 0x10<<6; + break; + } + mmio = scr->mmio; + x = 0; + while((mmio[FifoStat]&mask) != val && x++ < Maxloop) + waitcount.linear++; +} + +static void +waitforfifo(VGAscr *scr, int entries) +{ + ulong *mmio; + long x; + static ulong nwaitforfifo; + + mmio = scr->mmio; + x = 0; + while((mmio[SubStat]&0x1F00) < ((entries+2)<<8) && x++ < Maxloop) + waitcount.fifo++; +} + +static void +waitforidle(VGAscr *scr) +{ + ulong *mmio; + long x; + + mmio = scr->mmio; + x = 0; + while((mmio[SubStat]&0x3F00) != 0x3000 && x++ < Maxloop) + waitcount.idle++; +} + +static int +hwscroll(VGAscr *scr, Rectangle r, Rectangle sr) +{ + enum { Bitbltop = 0xCC }; /* copy source */ + ulong *mmio; + ulong cmd, stride; + Point dp, sp; + int did, d; + + d = scr->gscreen->depth; + did = (d-8)/8; + cmd = 0x00000020|(Bitbltop<<17)|(did<<2); + stride = Dx(scr->gscreen->r)*d/8; + + if(r.min.x <= sr.min.x){ + cmd |= 1<<25; + dp.x = r.min.x; + sp.x = sr.min.x; + }else{ + dp.x = r.max.x-1; + sp.x = sr.max.x-1; + } + + if(r.min.y <= sr.min.y){ + cmd |= 1<<26; + dp.y = r.min.y; + sp.y = sr.min.y; + }else{ + dp.y = r.max.y-1; + sp.y = sr.max.y-1; + } + + mmio = scr->mmio; + waitforlinearfifo(scr); + waitforfifo(scr, 7); + mmio[SrcBase] = scr->aperture; + mmio[DstBase] = scr->aperture; + mmio[Stride] = (stride<<16)|stride; + mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r); + mmio[SrcXY] = (sp.x<<16)|sp.y; + mmio[DestXY] = (dp.x<<16)|dp.y; + mmio[Command] = cmd; + waitforidle(scr); + return 1; +} + +static int +hwfill(VGAscr *scr, Rectangle r, ulong sval) +{ + enum { Bitbltop = 0xCC }; /* copy source */ + ulong *mmio; + ulong cmd, stride; + int did, d; + + d = scr->gscreen->depth; + did = (d-8)/8; + cmd = 0x16000120|(Bitbltop<<17)|(did<<2); + stride = Dx(scr->gscreen->r)*d/8; + mmio = scr->mmio; + waitforlinearfifo(scr); + waitforfifo(scr, 8); + mmio[SrcBase] = scr->aperture; + mmio[DstBase] = scr->aperture; + mmio[DstBase] = scr->aperture; + mmio[Stride] = (stride<<16)|stride; + mmio[FgrdData] = sval; + mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r); + mmio[DestXY] = (r.min.x<<16)|r.min.y; + mmio[Command] = cmd; + waitforidle(scr); + return 1; +} + +static void +s3drawinit(VGAscr *scr) +{ + ulong id; + + id = (vgaxi(Crtx, 0x30)<<8)|vgaxi(Crtx, 0x2E); + scr->id = id; + + /* + * It's highly likely that other ViRGEs will work without + * change to the driver, with the exception of the size of + * the linear aperture memory write FIFO. Since we don't + * know that size, I'm not turning them on. See waitforlinearfifo + * above. + */ + switch(id){ + case 0xE131: /* ViRGE */ + case 0xE13D: /* ViRGE/VX */ + case 0xE110: /* ViRGE/GX2 */ + scr->mmio = (ulong*)(scr->aperture+0x1000000); + scr->fill = hwfill; + scr->scroll = hwscroll; + } +} + VGAdev vgas3dev = { "s3", @@ -304,6 +473,7 @@ VGAdev vgas3dev = { 0, s3page, s3linear, + s3drawinit, }; VGAcur vgas3cur = { diff --git a/port/devaudio.c b/port/devaudio.c index acc0c34bea76508e70b3949223357ca99bdf9f62..6dfdeb9892ee4ee50ac10bc2fad95475519f912f 100644 --- a/port/devaudio.c +++ b/port/devaudio.c @@ -18,6 +18,7 @@ enum Qdir = 0, Qaudio, Qvolume, + Qstatus, Fmono = 1, Fin = 2, @@ -47,6 +48,7 @@ audiodir[] = { "audio", {Qaudio}, 0, 0666, "volume", {Qvolume}, 0, 0666, + "audiostat",{Qstatus}, 0, 0444, }; struct Buf @@ -76,6 +78,8 @@ static struct int lovol[Nvol]; int major; /* SB16 major version number (sb 4) */ int minor; /* SB16 minor version number */ + ulong totcount; /* how many bytes processed since open */ + vlong tottime; /* time at which totcount bytes were processed */ Buf buf[Nbuf]; /* buffers and queues */ AQueue empty; @@ -399,6 +403,7 @@ sb16startdma(void) sbcmd(count>>8); audio.active = 1; + audio.tottime = todget(nil); contindma(); iunlock(&blaster); } @@ -490,6 +495,7 @@ ess1688startdma(void) ess1688w(0xB8, x|0x05); audio.active = 1; + audio.tottime = todget(nil); contindma(); iunlock(&blaster); } @@ -516,6 +522,8 @@ sb16intr(void) if(stat & 2) { ilock(&blaster); dummy = inb(blaster.clri16); + audio.totcount += Bufsize; + audio.tottime = todget(nil); contindma(); iunlock(&blaster); audio.intr = 1; @@ -538,6 +546,8 @@ ess1688intr(void) if(audio.active){ ilock(&blaster); + audio.totcount += Bufsize; + audio.tottime = todget(nil); contindma(); dummy = inb(blaster.clri8); iunlock(&blaster); @@ -625,6 +635,8 @@ setempty(void) audio.filling = 0; for(i=0; ifgrp == 0) + if(up == nil || up->fgrp == nil) return 0; c = up->fgrp->fd[2]; @@ -267,9 +276,6 @@ echo(Rune r, char *buf, int n) if(consdebug != nil) consdebug(); return; - case 'D': - consdebug = rdb; - return; case 'p': x = spllo(); procdump(); @@ -378,6 +384,7 @@ enum{ Qkey, Qhostdomain, Qhostowner, + Qnewkernel, Qnull, Qpgrpid, Qpid, @@ -409,6 +416,7 @@ static Dirtab consdir[]={ "hostdomain", {Qhostdomain}, DOMLEN, 0664, "hostowner", {Qhostowner}, NAMELEN, 0664, "key", {Qkey}, DESKEYLEN, 0622, + "newkernel", {Qnewkernel}, 0, 0000, /* stupid hack -rsc */ "null", {Qnull}, 0, 0666, "pgrpid", {Qpgrpid}, NUMSIZE, 0444, "pid", {Qpid}, NUMSIZE, 0444, diff --git a/port/devdraw.c b/port/devdraw.c index 039ff0e1784da4dd74c66da5550742aea0b0cc5f..5da8145ddc745297ee1f1d27abc9854bad838fb5 100644 --- a/port/devdraw.c +++ b/port/devdraw.c @@ -1,21 +1,24 @@ #include "u.h" -#include "lib.h" +#include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" -#include "error.h" +#include "../port/error.h" +#include #define Image IMAGE #include #include #include +#include +#include "screen.h" enum { Qtopdir = 0, - Q2nd, Qnew, Q3rd, + Q2nd, Qcolormap, Qctl, Qdata, @@ -150,7 +153,7 @@ struct DScreen }; static Draw sdraw; -static Memimage screenimage; +static Memimage *screenimage; static Memdata screendata; static Rectangle flushrect; static int waste; @@ -172,7 +175,7 @@ static char Ewriteoutside[] = "writeimage outside image"; static char Enotfont[] = "image not a font"; static char Eindex[] = "character index out of range"; static char Enoclient[] = "no such draw client"; -static char Eldepth[] = "image has bad ldepth"; +static char Edepth[] = "image has bad depth"; static char Enameused[] = "image name in use"; static char Enoname[] = "no image with that name"; static char Eoldname[] = "named image no longer valid"; @@ -302,7 +305,7 @@ addflush(Rectangle r) int abb, ar, anbb; Rectangle nbb; - if(sdraw.softscreen==0 || !rectclip(&r, screenimage.r)) + if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r)) return; if(flushrect.min.x >= flushrect.max.x){ @@ -353,7 +356,7 @@ dstflush(int dstid, Memimage *dst, Rectangle r) if(l == nil) return; do{ - if(l->screen->image->data != screenimage.data) + if(l->screen->image->data != screenimage->data) return; r = rectaddpt(r, l->delta); l = l->screen->image->layer; @@ -414,15 +417,18 @@ drawlookup(Client *client, int id, int checkname) { DImage *d; +// print("drawlookup %d", id); d = client->dimage[id&HASHMASK]; while(d){ if(d->id == id){ if(checkname && !drawgoodname(d)) error(Eoldname); +// print(" %p...", d); return d; } d = d->next; } +// print(" nil..."); return 0; } @@ -475,6 +481,7 @@ drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen) d->dscreen = dscreen; d->next = client->dimage[id&HASHMASK]; client->dimage[id&HASHMASK] = d; +// print("install %d %p...", id, d); return i; } @@ -485,6 +492,9 @@ drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *df CScreen *c; c = malloc(sizeof(CScreen)); + if(dimage && dimage->image && dimage->image->chan == 0) + panic("bad image %p in drawinstallscreen", dimage->image); + if(c == 0) return 0; if(d == 0){ @@ -590,12 +600,12 @@ drawfreedimage(DImage *dimage) i++; if(dimage->vers != 0) /* acquired by name; owned by someone else*/ goto Return; - if(dimage->image == &screenimage) /* don't free the display */ + if(dimage->image == screenimage) /* don't free the display */ goto Return; ds = dimage->dscreen; if(ds){ l = dimage->image; - if(l->data == screenimage.data) + if(l->data == screenimage->data) addflush(l->layer->screenr); if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */ free(l->layer->refreshptr); @@ -790,25 +800,41 @@ drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int ind static int initscreenimage(void) { - int width; + int width, depth; + ulong chan; + Rectangle r; - if(screendata.data != nil) + if(screenimage != nil) return 1; screendata.base = nil; - screendata.data = attachscreen(&screenimage.r, &screenimage.ldepth, &width, &sdraw.softscreen); - - if(screendata.data == nil) + screendata.bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen); + if(screendata.bdata == nil) return 0; - screendata.ref = 1; - screenimage.data = &screendata; - screenimage.width = width; - screenimage.clipr = screenimage.r; + screenimage = allocmemimaged(r, chan, &screendata); + if(screenimage == nil){ + /* RSC: BUG: detach screen */ + return 0; + } + + screenimage->width = width; + screenimage->clipr = screenimage->r; return 1; } +void +deletescreenimage(void) +{ + qlock(&sdraw); + /* RSC: BUG: detach screen */ + if(screenimage) + freememimage(screenimage); + screenimage = nil; + qunlock(&sdraw); +} + Chan* drawattach(char *spec) { @@ -824,7 +850,7 @@ drawattach(char *spec) int drawwalk(Chan *c, char *name) { - if(screendata.data == nil) + if(screendata.bdata == nil) error("no frame buffer"); if(strcmp(name, "..") == 0){ switch(QID(c->qid)){ @@ -885,7 +911,7 @@ drawopen(Chan *c, int omode) error(Einuse); cl->busy = 1; flushrect = Rect(10000, 10000, -10000, -10000); - drawinstall(cl, 0, &screenimage, 0); + drawinstall(cl, 0, screenimage, 0); incref(&cl->r); break; case Qcolormap: @@ -963,6 +989,7 @@ drawread(Chan *c, void *a, long n, vlong off) DImage *di; Memimage *i; ulong offset = off; + char buf[16]; USED(offset); if(c->qid.path & CHDIR) @@ -979,16 +1006,18 @@ drawread(Chan *c, void *a, long n, vlong off) error(Eshortread); if(cl->infoid < 0) error(Enodrawimage); - if(cl->infoid == 0) - i = &screenimage; - else{ + if(cl->infoid == 0){ + i = screenimage; + if(i == nil) + error(Enodrawimage); + }else{ di = drawlookup(cl, cl->infoid, 1); if(di == nil) error(Enodrawimage); i = di->image; } - n = sprint(a, "%11d %11d %11d %11d %11d %11d %11d %11d %11d %11d %11d %11d ", - cl->clientid, cl->infoid, i->ldepth, i->repl, + n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ", + cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl, i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y, i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y); cl->infoid = -1; @@ -1110,15 +1139,15 @@ drawwrite(Chan *c, void *a, long n, vlong off) m -= i; *q = 0; if(parsefields(buf, fields, nelem(fields), " ") != 4) - error(Ebadarg); + error("eb1"); //error(Ebadarg); i = strtoul(fields[0], 0, 0); red = strtoul(fields[1], 0, 0); green = strtoul(fields[2], 0, 0); blue = strtoul(fields[3], &q, 0); if(fields[3] == q) - error(Ebadarg); + error("eb2"); //error(Ebadarg); if(red>255 || green>255 || blue>255 || i<0 || i>255) - error(Ebadarg); + error("eb3"); //error(Ebadarg); red |= red<<8; red |= red<<16; green |= green<<8; @@ -1167,11 +1196,63 @@ drawcoord(uchar *p, uchar *maxp, int oldx, int *newx) return p; } +static void +printmesg(char *fmt, uchar *a, int itwouldmakemehappyifyouprintthis) +{ + char buf[256]; + char *p, *q; + int s; + + if(1|| itwouldmakemehappyifyouprintthis==0){ + SET(s,q,p); + USED(fmt, a, buf, p, q, s); + return; + } + q = buf; + *q++ = *a++; + for(p=fmt; *p; p++){ + switch(*p){ + case 'l': + q += sprint(q, " %ld", (long)BGLONG(a)); + a += 4; + break; + case 'L': + q += sprint(q, " %.8lux", (ulong)BGLONG(a)); + a += 4; + break; + case 'R': + q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12)); + a += 16; + break; + case 'P': + q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4)); + a += 8; + break; + case 'b': + q += sprint(q, " %d", *a++); + break; + case 's': + q += sprint(q, " %d", BGSHORT(a)); + a += 2; + break; + case 'S': + q += sprint(q, " %.4ux", BGSHORT(a)); + a += 2; + break; + } + } + *q++ = '\n'; + *q = 0; + iprint("%.*s", (int)(q-buf), buf); +} + void drawmesg(Client *client, void *av, int n) { - int c, ldepth, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, ox, oy, esize, doflush; - uchar *u, *a; + int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, ox, oy, esize, doflush; + uchar *u, *a, refresh; + char *fmt; + ulong value, chan; Rectangle r, clipr; Point p, q, *pp, sp; Memimage *i, *dst, *src, *mask; @@ -1187,30 +1268,41 @@ drawmesg(Client *client, void *av, int n) a = av; m = 0; + fmt = nil; + if(waserror()){ + if(fmt) printmesg(fmt, a, 1); + // iprint("error: %s\n", up->error); + nexterror(); + } while((n-=m) > 0){ + USED(fmt); a += m; switch(*a){ default: error("bad draw command"); - /* allocate: 'a' id[4] screenid[4] refresh[1] ldepth[2] repl[1] R[4*4] clipR[4*4] value[1] */ - case 'a': - m = 1+4+4+1+2+1+4*4+4*4+1; + /* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbαα[4] */ + case 'b': + printmesg(fmt="LLbLbRRL", a, 0); + m = 1+4+4+1+4+1+4*4+4*4+4; if(n < m) error(Eshortdraw); dstid = BGLONG(a+1); + scrnid = BGSHORT(a+5); + refresh = a[9]; + chan = BGLONG(a+10); + repl = a[14]; + drawrectangle(&r, a+15); + drawrectangle(&clipr, a+31); + value = BGLONG(a+47); if(drawlookup(client, dstid, 0)) error(Eimageexists); - ldepth = BGSHORT(a+10); - repl = a[12]; - drawrectangle(&r, a+13); - scrnid = BGSHORT(a+5); if(scrnid){ dscrn = drawlookupscreen(client, scrnid, &cs); scrn = dscrn->screen; - if(repl || ldepth!=scrn->image->ldepth) + if(repl || chan!=scrn->image->chan) error("image parameters incompatible with screen"); reffn = nil; - switch(a[9]){ + switch(refresh){ case Refbackup: break; case Refnone: @@ -1222,11 +1314,11 @@ drawmesg(Client *client, void *av, int n) default: error("unknown refresh method"); } - l = memlalloc(scrn, r, reffn, 0, a[45]); + l = memlalloc(scrn, r, reffn, 0, value); if(l == 0) error(Edrawmem); addflush(l->layer->screenr); - drawrectangle(&l->clipr, a+29); + l->clipr = clipr; rectclip(&l->clipr, r); if(drawinstall(client, dstid, l, dscrn) == 0){ memldelete(l); @@ -1248,22 +1340,26 @@ drawmesg(Client *client, void *av, int n) } continue; } - i = allocmemimage(r, ldepth); - if(i == 0) + i = allocmemimage(r, chan); + if(i == 0){ + iprint("chan %lux\n", chan); error(Edrawmem); - i->repl = repl; - drawrectangle(&i->clipr, a+29); + } + if(repl) + i->flags |= Frepl; + i->clipr = clipr; if(!repl) rectclip(&i->clipr, r); if(drawinstall(client, dstid, i, 0) == 0){ freememimage(i); error(Edrawmem); } - memfillcolor(i, a[45]); + memfillcolor(i, value); continue; /* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */ case 'A': + printmesg(fmt="LLLb", a, 1); m = 1+4+4+4+1; if(n < m) error(Eshortdraw); @@ -1282,6 +1378,7 @@ drawmesg(Client *client, void *av, int n) /* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */ case 'c': + printmesg(fmt="LbR", a, 0); m = 1+4+1+4*4; if(n < m) error(Eshortdraw); @@ -1291,12 +1388,14 @@ drawmesg(Client *client, void *av, int n) if(ddst->name) error("can't change repl/clipr of shared image"); dst = ddst->image; - dst->repl = a[5]; + if(a[5]) + dst->flags |= Frepl; drawrectangle(&dst->clipr, a+6); continue; /* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */ case 'd': + printmesg(fmt="LLLRPP", a, 0); m = 1+4+4+4+4*4+2*4+2*4; if(n < m) error(Eshortdraw); @@ -1311,9 +1410,19 @@ drawmesg(Client *client, void *av, int n) dstflush(dstid, dst, r); continue; + /* toggle debugging: 'D' val[1] */ + case 'D': + printmesg(fmt="b", a, 0); + m = 1+1; + if(n < m) + error(Eshortdraw); + drawdebug = a[1]; + continue; + /* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/ case 'e': case 'E': + printmesg(fmt="LLPlllPll", a, 0); m = 1+4+4+2*4+4+4+4+2*4+2*4; if(n < m) error(Eshortdraw); @@ -1346,6 +1455,7 @@ drawmesg(Client *client, void *av, int n) /* free: 'f' id[4] */ case 'f': + printmesg(fmt="L", a, 1); m = 1+4; if(n < m) error(Eshortdraw); @@ -1357,6 +1467,7 @@ drawmesg(Client *client, void *av, int n) /* free screen: 'F' id[4] */ case 'F': + printmesg(fmt="L", a, 1); m = 1+4; if(n < m) error(Eshortdraw); @@ -1366,6 +1477,7 @@ drawmesg(Client *client, void *av, int n) /* initialize font: 'i' fontid[4] nchars[4] ascent[1] */ case 'i': + printmesg(fmt="Llb", a, 1); m = 1+4+4+1; if(n < m) error(Eshortdraw); @@ -1389,6 +1501,7 @@ drawmesg(Client *client, void *av, int n) /* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */ case 'l': + printmesg(fmt="LLSRPbb", a, 0); m = 1+4+4+2+4*4+2*4+1+1; if(n < m) error(Eshortdraw); @@ -1403,7 +1516,7 @@ drawmesg(Client *client, void *av, int n) error(Eindex); drawrectangle(&r, a+11); drawpoint(&p, a+27); - memdraw(font->image, r, src, p, memones, p); + memdraw(font->image, r, src, p, memopaque, p); fc = &font->fchar[ci]; fc->minx = r.min.x; fc->maxx = r.max.x; @@ -1415,6 +1528,7 @@ drawmesg(Client *client, void *av, int n) /* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */ case 'L': + printmesg(fmt="LPPlllLP", a, 0); m = 1+4+2*4+2*4+4+4+4+4+2*4; if(n < m) error(Eshortdraw); @@ -1438,8 +1552,17 @@ drawmesg(Client *client, void *av, int n) } continue; + /* create image mask: 'm' newid[4] id[4] */ + case 'm': + printmesg("LL", a, 0); + m = 4+4; + if(n < m) + error(Eshortdraw); + break; + /* attach to a named image: 'n' dstid[4] j[1] name[j] */ case 'n': + printmesg(fmt="Lz", a, 0); m = 1+4+1; if(n < m) error(Eshortdraw); @@ -1469,6 +1592,7 @@ drawmesg(Client *client, void *av, int n) /* name an image: 'N' dstid[4] in[1] j[1] name[j] */ case 'N': + printmesg(fmt="Lbz", a, 0); m = 1+4+1+1; if(n < m) error(Eshortdraw); @@ -1498,6 +1622,7 @@ drawmesg(Client *client, void *av, int n) /* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */ case 'o': + printmesg(fmt="LPP", a, 0); m = 1+4+2*4+2*4; if(n < m) error(Eshortdraw); @@ -1523,6 +1648,7 @@ drawmesg(Client *client, void *av, int n) /* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */ case 'p': case 'P': + printmesg(fmt="LslllLPP", a, 0); m = 1+4+2+4+4+4+4+2*4; if(n < m) error(Eshortdraw); @@ -1547,7 +1673,7 @@ drawmesg(Client *client, void *av, int n) if(pp == nil) error(Enomem); doflush = 0; - if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage.data)) + if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data)) doflush = 1; /* simplify test in loop */ ox = oy = 0; u = a+m; @@ -1588,6 +1714,7 @@ drawmesg(Client *client, void *av, int n) /* read: 'r' id[4] R[4*4] */ case 'r': + printmesg(fmt="LR", a, 0); m = 1+4+4*4; if(n < m) error(Eshortdraw); @@ -1597,7 +1724,7 @@ drawmesg(Client *client, void *av, int n) drawrectangle(&r, a+5); if(!rectinrect(r, i->r)) error(Ereadoutside); - c = bytesperline(r, i->ldepth); + c = bytesperline(r, i->depth); c *= Dy(r); free(client->readdata); client->readdata = mallocz(c, 0); @@ -1615,6 +1742,7 @@ drawmesg(Client *client, void *av, int n) /* stringbg: 'x' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] bgid[4] bgpt[2*4] ni*(index[2]) */ case 's': case 'x': + printmesg(fmt="LLLPRPs", a, 0); m = 1+4+4+4+2*4+4*4+2*4+2; if(*a == 'x') m += 4+2*4; @@ -1657,7 +1785,7 @@ drawmesg(Client *client, void *av, int n) r.max.x += font->fchar[ci].width; u += 2; } - memdraw(dst, r, l, q, memones, ZP); + memdraw(dst, r, l, q, memopaque, ZP); u -= 2*ni; } q = p; @@ -1677,6 +1805,7 @@ drawmesg(Client *client, void *av, int n) /* use public screen: 'S' id[4] ldepth[4] */ case 'S': + printmesg(fmt="Ll", a, 0); m = 1+4+4; if(n < m) error(Eshortdraw); @@ -1686,14 +1815,15 @@ drawmesg(Client *client, void *av, int n) dscrn = drawlookupdscreen(dstid); if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client)) error(Enodrawscreen); - if(dscrn->screen->image->ldepth != BGLONG(a+5)) - error("inconsistent ldepth"); + if(dscrn->screen->image->depth != (1<layer->screen->image->data == screenimage.data) + if(lp[0]->layer->screen->image->data == screenimage->data) for(j=0; jlayer->screenr); ll = drawlookup(client, BGLONG(a+1+1+2), 1); @@ -1735,14 +1865,19 @@ drawmesg(Client *client, void *av, int n) /* visible: 'v' */ case 'v': + printmesg(fmt="", a, 0); m = 1; drawflush(); continue; - /* write: 'w' id[4] R[4*4] data[x*1] */ - /* write from compressed data: 'W' id[4] R[4*4] data[x*1] */ - case 'w': - case 'W': + /* old write: 'w' id[4] R[4*4] data[x*1] */ + /* old write from compressed data: 'W' id[4] R[4*4] data[x*1] */ + /* new write: 'y' id[4] R[4*4] data[x*1] */ + /* new write from compressed data: 'Y' id[4] R[4*4] data[x*1] */ + case 'y': + case 'Y': + printmesg(fmt="LR", a, 0); + // iprint("load %c\n", *a); m = 1+4+4*4; if(n < m) error(Eshortdraw); @@ -1751,7 +1886,7 @@ drawmesg(Client *client, void *av, int n) drawrectangle(&r, a+5); if(!rectinrect(r, dst->r)) error(Ewriteoutside); - y = memload(dst, r, a+m, n-m, *a=='W'); + y = memload(dst, r, a+m, n-m, *a=='Y'); if(y < 0) error("bad writeimage call"); dstflush(dstid, dst, r); @@ -1759,6 +1894,7 @@ drawmesg(Client *client, void *av, int n) continue; } } + poperror(); } Dev drawdevtab = { @@ -1829,7 +1965,8 @@ drawblankscreen(int blank) return; } p = sdraw.savemap; - nc = 1<<(1<depth > 8 ? 256 : 1<depth; + if(blank == 0) /* turn screen on */ for(i=0; ir)){ mouse.xy = pt; mouse.redraw = 1; mouse.track = 1; @@ -426,20 +426,23 @@ mousetrack(int b, int dx, int dy) { int x, y; + if(gscreen==nil) + return; + if(mouse.acceleration){ dx = scale(dx); dy = scale(dy); } x = mouse.xy.x + dx; - if(x < gscreen.r.min.x) - x = gscreen.r.min.x; - if(x >= gscreen.r.max.x) - x = gscreen.r.max.x; + if(x < gscreen->r.min.x) + x = gscreen->r.min.x; + if(x >= gscreen->r.max.x) + x = gscreen->r.max.x; y = mouse.xy.y + dy; - if(y < gscreen.r.min.y) - y = gscreen.r.min.y; - if(y >= gscreen.r.max.y) - y = gscreen.r.max.y; + if(y < gscreen->r.min.y) + y = gscreen->r.min.y; + if(y >= gscreen->r.max.y) + y = gscreen->r.max.y; mouse.counter++; mouse.xy = Pt(x, y); mouse.buttons = b; diff --git a/port/portfns.h b/port/portfns.h index 21e88bda44a9d607da2f5e0c2a987d0b5f404139..7fd92de10a7a66504ef14aeb2add76c3b1b8582f 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -8,6 +8,7 @@ Block* allocb(int); int anyhigher(void); int anyready(void); #define assert(x) if(x);else panic("assert(x) failed"); +void _assert(char*); Image* attachimage(int, Chan*, ulong, ulong); long authcheck(Chan*, char*, int); long authcheckread(Chan*, char*, int n); @@ -146,7 +147,7 @@ void kproc(char*, void(*)(void*), void*); void kprocchild(Proc*, void (*)(void*), void*); void (*kproftimer)(ulong); void ksetenv(char*, char*); -long latin1(uchar*, int); +long latin1(Rune*, int); void lock(Lock*); void lockinit(void); void logopen(Log*);