M carrera/kbd.c => carrera/kbd.c +5 -5
@@ 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;
M carrera/main.c => carrera/main.c +6 -3
@@ 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;
M carrera/mem.h => carrera/mem.h +1 -1
@@ 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 */
M carrera/screen.c => carrera/screen.c +63 -126
@@ 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; y<gscreen.r.max.y; y++)
- memset(byteaddr(&gscreen, Pt(gscreen.r.min.x, y)), 0xba, Dx(gscreen.r));
+ memset((void*)Screenvirt, 0, 3*1024*1024);
+ memfillcolor(gscreen, 0x444488FF);
w = memdefont->info[' '].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<<gscreen.ldepth;
+ return gscreen->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; y<r.max.y; y++){
memmove(q, data, tl);
- q += gscreen.width*sizeof(ulong);
+ q += gscreen->width*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; y<r.max.y; y++){
memmove(data, q, tl);
- q += gscreen.width*sizeof(ulong);
+ q += gscreen->width*sizeof(ulong);
data += l;
}
unlock(&screenlock);
M ip/ip.c => ip/ip.c +3 -13
@@ 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;
M pc/cga.c => pc/cga.c +27 -6
@@ 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<Width/2; i++){
+ *p++ = ' ';
+ *p++ = Attr;
+ }
cgapos = Width*(Height-1);
}
movecursor();
@@ 85,7 106,7 @@ screeninit(void)
static void
cgascreenputs(char* s, int n)
{
- if(!islo()) {
+ if(!islo()){
/*
* Don't deadlock trying to
* print in an interrupt.
M pc/devlml.c => pc/devlml.c +0 -8
@@ 7,14 7,6 @@
#include "io.h"
#include "devlml.h"
-#include "index.h"
-#include "avctl.h"
-#include "misc.h"
-
-Medium *m;
-
-AVctl *ctl = &ctlinit;
-
static void * pciPhysBaseAddr;
static ulong pciBaseAddr;
A pc/devusb.c => pc/devusb.c +1934 -0
@@ 0,0 1,1934 @@
+/*
+ * UHCI USB driver
+ * (c) 1998, 1999 C H Forsyth, forsyth@caldo.demon.co.uk
+ * to do:
+ * endpoint open/close
+ * build Endpt on open from attributes stored in Udev?
+ * build data0/data1 rings for bulk and interrupt endpoints
+ * endpoint TD rings (can there be prefetch?)
+ * hubs?
+ * special handling of isochronous traffic?
+ * is use of Queues justified? (could have client clean TD rings on wakeup)
+ * bandwidth check
+ */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+/*
+#ifndef Inferno
+#include "devtab.h"
+#include "brazilia.h"
+#endif
+*/
+
+#define Pprint
+#define Chatty 1
+#define DPRINT if(Chatty)print
+#define XPRINT if(0)print
+
+/*
+ * USB packet definitions
+ */
+enum {
+ TokIN = 0x69,
+ TokOUT = 0xE1,
+ TokSETUP = 0x2D,
+
+ /* request type */
+ RH2D = 0<<7,
+ RD2H = 1<<7,
+ Rstandard = 0<<5,
+ Rclass = 1<<5,
+ Rvendor = 2<<5,
+ Rdevice = 0,
+ Rinterface = 1,
+ Rendpt = 2,
+ Rother = 3,
+};
+
+typedef uchar byte;
+
+typedef struct Ctlr Ctlr;
+typedef struct Endpt Endpt;
+typedef struct QTree QTree;
+typedef struct Udev Udev;
+
+/*
+ * UHCI hardware structures, aligned on 16-byte boundary
+ */
+typedef struct QH QH;
+typedef struct TD TD;
+
+struct TD {
+ ulong link;
+ ulong status; /* controller r/w */
+ ulong dev;
+ ulong buffer;
+
+ /* software */
+ ulong flags;
+ Block* bp;
+ Endpt* ep;
+ TD* next;
+};
+#define TFOL(p) ((TD*)KADDR((ulong)(p) & ~0xF))
+
+struct QH {
+ ulong head;
+ ulong entries; /* address of next TD or QH to process (updated by controller) */
+
+ /* software */
+ union {
+ TD* first;
+ QH* next; /* free list */
+ };
+ TD* last;
+};
+#define QFOL(p) ((QH*)KADDR((ulong)(p) & ~0xF))
+
+/*
+ * UHCI interface registers and bits
+ */
+enum {
+ /* i/o space */
+ Cmd = 0,
+ Status = 2,
+ Usbintr = 4,
+ Frnum = 6,
+ Flbaseadd = 8,
+ SOFMod = 0xC,
+ Portsc0 = 0x10,
+ Portsc1 = 0x12,
+
+ /* port status */
+ Suspend = 1<<12,
+ PortReset = 1<<9,
+ SlowDevice = 1<<8,
+ ResumeDetect = 1<<6,
+ PortChange = 1<<3, /* write 1 to clear */
+ PortEnable = 1<<2,
+ StatusChange = 1<<1, /* write 1 to clear */
+ DevicePresent = 1<<0,
+
+ FRAMESIZE= 4096, /* fixed by hardware; aligned to same */
+ NFRAME = FRAMESIZE/4,
+
+ Vf = 1<<2, /* TD only */
+ IsQH = 1<<1,
+ Terminate = 1<<0,
+
+ /* TD.status */
+ SPD = 1<<29,
+ ErrLimit0 = 0<<27,
+ ErrLimit1 = 1<<27,
+ ErrLimit2 = 2<<27,
+ ErrLimit3 = 3<<27,
+ LowSpeed = 1<<26,
+ IsoSelect = 1<<25,
+ IOC = 1<<24,
+ Active = 1<<23,
+ Stalled = 1<<22,
+ DataBufferErr = 1<<21,
+ Babbling = 1<<20,
+ NAKed = 1<<19,
+ CRCorTimeout = 1<<18,
+ BitstuffErr = 1<<17,
+ AnyError = (Stalled | DataBufferErr | Babbling | NAKed | CRCorTimeout | BitstuffErr),
+
+ /* TD.dev */
+ IsDATA1 = 1<<19,
+
+ /* TD.flags (software) */
+ CancelTD= 1<<0,
+};
+
+/*
+ * software structures
+ */
+struct QTree {
+ QLock;
+ int nel;
+ int depth;
+ QH* root;
+ ulong* bw;
+};
+
+#define GET2(p) ((((p)[1]&0xFF)<<8)|((p)[0]&0xFF))
+#define PUT2(p,v) (((p)[0] = (v)), ((p)[1] = (v)>>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; i<n; i++)
+ XPRINT(" %2.2ux", b->rp[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; i<nbuf; i++){
+ t = alloctd(&ubus);
+ t->ep = 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<<i)<n; i++)
+ ;
+ return i;
+}
+
+/*
+ * build the periodic scheduling tree:
+ * framesize must be a multiple of the tree size
+ */
+static QTree *
+mkqhtree(ulong *frame, int framesize, int maxms)
+{
+ int i, n, d, o, leaf0, depth;
+ QH *tree, *qh;
+ QTree *qt;
+
+ depth = flog2(maxms);
+ n = (1<<(depth+1))-1;
+ qt = mallocz(sizeof(*qt), 1);
+ if(qt == nil)
+ return nil;
+ qt->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; i<n; i++){
+ qh = &tree[i];
+ qh->head = PADDR(&tree[(i-1)/2]) | IsQH;
+ qh->entries = Terminate;
+ }
+ /* distribute leaves evenly round the frame list */
+ leaf0 = n/2;
+ for(i=0; i<framesize; i++){
+ o = 0;
+ for(d=0; d<depth; d++){
+ o <<= 1;
+ if(i & (1<<d))
+ o |= 1;
+ }
+ if(leaf0+o >= 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; i<t; i++){
+ pprint("F%.2d %8.8lux %8.8lux\n", i, frame[i], QFOL(frame[i])->head);
+ 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<<d)-1; i<ub; i++){
+ total = qt->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; i<nelem(d->ep); 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)-1)
+
+#define QID(q) ((q).path&QMASK)
+#define DEVPATH(q) (((q)&~CHDIR)>>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; i<nelem(usbdev); i++)
+ if(usbdev[i] == nil){
+ ubus.idgen++;
+ d = mallocz(sizeof(*d), 1);
+ d->ref = 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)<<QSHIFT)|Q3rd, d->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)<<QSHIFT);
+ c->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; i<nelem(d->ep); 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,
+};
M pc/devvga.c => pc/devvga.c +84 -80
@@ 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<<scr->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;
M pc/kbd.c => pc/kbd.c +9 -9
@@ 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);
M pc/screen.c => pc/screen.c +267 -64
@@ 13,26 13,14 @@
#include <cursor.h>
#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<<z))/BI2WD;
+ int width = (x*z)/BI2WD;
- gscreendata.data = xalloc(width*BY2WD*y);
- if(gscreendata.data == 0)
+ gscreendata.bdata = xalloc(width*BY2WD*y);
+ if(gscreendata.bdata == 0)
error("screensize: vga soft memory");
- memset(gscreendata.data, Backgnd, width*BY2WD*y);
+/* memset(gscreendata.bdata, 0x72, width*BY2WD*y); /* not really black */
scr->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<<gscreen.ldepth)+31)/32;
- gscreen.r.min = ZP;
- gscreen.r.max = Pt(x, y);
- gscreen.clipr = gscreen.r;
- gscreen.repl = 0;
+ if(gscreen)
+ freememimage(gscreen);
- scr->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;
}
@@ 244,37 239,58 @@ getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
}
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<<bpp)-1;
+ break;
+ case 8:
+ val = p[0];
+ break;
+ case 16:
+ val = p[0]|(p[1]<<8);
+ break;
+ case 24:
+ val = p[0]|(p[1]<<8)|(p[2]<<16);
+ break;
+ case 32:
+ val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+ break;
+ }
+ while(bpp<32){
+ val |= val<<bpp;
+ bpp *= 2;
+ }
+ return val;
+}
+
+
+static ulong
+imgtorgba(Memimage *img, ulong val)
+{
+ uchar r, g, b, a;
+ int nb, ov, v;
+ ulong chan;
+ uchar *p;
+
+ a = 0xFF;
+ r = g = b = 0xAA; /* garbage */
+ for(chan=img->chan; chan; chan>>=8){
+ nb = NBITS(chan);
+ ov = v = val&((1<<nb)-1);
+ val >>= nb;
+
+ while(nb < 8){
+ v |= v<<nb;
+ nb *= 2;
+ }
+ 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))<<d;
+ break;
+ case CGreen:
+ v |= (g>>(8-nb))<<d;
+ break;
+ case CBlue:
+ v |= (b>>(8-nb))<<d;
+ break;
+ case CAlpha:
+ v |= (a>>(8-nb))<<d;
+ break;
+ case CMap:
+ p = img->cmap->rgb2cmap;
+ m = p[(r>>4)*256+(g>>4)*16+(b>>4)];
+ v |= m<<d;
+ break;
+ case CGrey:
+ m = RGB2K(r,g,b);
+ v |= m<<d;
+ break;
+ }
+ d += nb;
+ }
+// print("rgba2img %.8lux = %.*lux\n", rgba, 2*d/8, v);
+ return v;
+}
+
+Memimage *lastbadi;
+Memdata *lastbad;
+Memimage *lastbadsrc, *lastbaddst;
+
+#ifndef SDFSDF
+int
+hwdraw(Memdrawparam *par)
+{
+ VGAscr *scr;
+ Memimage *dst, *src;
+
+ dst = par->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
M pc/screen.h => pc/screen.h +20 -2
@@ 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);
M pc/vga.c => pc/vga.c +34 -36
@@ 11,42 11,37 @@
#include <cursor.h>
#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;
}
+
M pc/vgaark2000pv.c => pc/vgaark2000pv.c +6 -6
@@ 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
M pc/vgacyber938x.c => pc/vgacyber938x.c +2 -2
@@ 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.
M pc/vgamach64xx.c => pc/vgamach64xx.c +397 -6
@@ 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);
}
@@ 208,9 317,75 @@ mach64xxcurload(VGAscr* scr, Cursor* curs)
}
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 */
};
M pc/vgas3.c => pc/vgas3.c +196 -26
@@ 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 = {
M port/devaudio.c => port/devaudio.c +48 -6
@@ 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; i<Nbuf; i++)
putbuf(&audio.empty, &audio.buf[i]);
+ audio.totcount = 0;
+ audio.tottime = 0LL;
iunlock(&blaster);
}
@@ 707,7 719,8 @@ static void
audioinit(void)
{
ISAConf sbconf;
- int i;
+ int i, x;
+ static int irq[] = {2,5,7,10};
sbconf.port = 0x220;
sbconf.dma = Dma;
@@ 752,9 765,6 @@ audioinit(void)
blaster.startdma = sb16startdma;
blaster.intr = sb16intr;
- seteisadma(blaster.dma, audiodmaintr);
- setvec(Int0vec+sbconf.irq, pcaudiosbintr, 0);
-
audio.amode = Aclosed;
resetlevel();
@@ 789,7 799,13 @@ audioinit(void)
mxvolume();
/*
- * set up irq/dma chans
+ * Attempt to set IRQ/DMA channels.
+ * On old ISA boards, these registers are writable.
+ * On Plug-n-Play boards, these are read-only.
+ *
+ * To accomodate both, we write to the registers,
+ * but then use the contents in case the write is
+ * disallowed.
*/
mxcmd(0x80, /* irq */
(sbconf.irq==2)? 1:
@@ 798,6 814,23 @@ audioinit(void)
(sbconf.irq==10)? 8:
0);
mxcmd(0x81, 1<<blaster.dma); /* dma */
+
+ x = mxread(0x81);
+ for(i=5; i<=7; i++)
+ if(x & (1<<i)){
+ blaster.dma = i;
+ break;
+ }
+
+ x = mxread(0x80);
+ for(i=0; i<=3; i++)
+ if(x & (1<<i)){
+ sbconf.irq = irq[i];
+ break;
+ }
+
+ seteisadma(blaster.dma, audiodmaintr);
+ setvec(Int0vec+sbconf.irq, pcaudiosbintr, 0);
}
static Chan*
@@ 831,6 864,9 @@ audioopen(Chan *c, int omode)
error(Eperm);
break;
+ case Qstatus:
+ if((omode&7) != OREAD)
+ error(Eperm);
case Qvolume:
case Qdir:
break;
@@ 875,6 911,7 @@ audioclose(Chan *c)
case Qdir:
case Qvolume:
+ case Qstatus:
break;
case Qaudio:
@@ 965,6 1002,12 @@ audioread(Chan *c, void *v, long n, vlong off)
qunlock(&audio);
break;
+ case Qstatus:
+ buf[0] = 0;
+ snprint(buf, sizeof(buf), "bytes %lud\ntime %lld\n",
+ audio.totcount, audio.tottime);
+ return readstr(offset, a, n, buf);
+
case Qvolume:
j = 0;
buf[0] = 0;
@@ 1004,7 1047,6 @@ audioread(Chan *c, void *v, long n, vlong off)
}
j += snprint(buf+j, sizeof(buf)-j, "\n");
}
-
return readstr(offset, a, n, buf);
}
return n0-n;
M port/devcons.c => port/devcons.c +13 -5
@@ 5,7 5,7 @@
#include "fns.h"
#include "../port/error.h"
-void (*consdebug)(void);
+void (*consdebug)(void) = rdb;
Queue* kbdq; /* unprocessed console input */
Queue* lineq; /* processed console input */
@@ 141,6 141,8 @@ sprint(char *s, char *fmt, ...)
return n;
}
+int noprint;
+
int
print(char *fmt, ...)
{
@@ 148,6 150,9 @@ print(char *fmt, ...)
va_list arg;
char buf[PRINTSIZE];
+ if(noprint)
+ return -1;
+
va_start(arg, fmt);
n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;
va_end(arg);
@@ 168,6 173,7 @@ iprint(char *fmt, ...)
n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;
va_end(arg);
serialputs(buf, n);
+// screenputs(buf, n);
splx(s);
return n;
@@ 180,11 186,14 @@ panic(char *fmt, ...)
va_list arg;
char buf[PRINTSIZE];
+ splhi();
strcpy(buf, "panic: ");
va_start(arg, fmt);
n = doprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
va_end(arg);
buf[n] = '\n';
+ serialputs(buf, n+1);
+ rdb();
putstrn(buf, n+1);
spllo();
prflush();
@@ 207,7 216,7 @@ pprint(char *fmt, ...)
va_list arg;
char buf[2*PRINTSIZE];
- if(up->fgrp == 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,
M port/devdraw.c => port/devdraw.c +197 -60
@@ 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 <pool.h>
#define Image IMAGE
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
+#include <cursor.h>
+#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<<BGLONG(a+5)))
+ error("inconsistent depth");
if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
error(Edrawmem);
continue;
/* top or bottom windows: 't' top[1] nw[2] n*id[4] */
case 't':
+ printmesg(fmt="bsL", a, 0);
m = 1+1+2;
if(n < m)
error(Eshortdraw);
@@ 1723,7 1853,7 @@ drawmesg(Client *client, void *av, int n)
memltofrontn(lp, nw);
else
memltorearn(lp, nw);
- if(lp[0]->layer->screen->image->data == screenimage.data)
+ if(lp[0]->layer->screen->image->data == screenimage->data)
for(j=0; j<nw; j++)
addflush(lp[j]->layer->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<<screenimage.ldepth);
+ nc = screenimage->depth > 8 ? 256 : 1<<screenimage->depth;
+
if(blank == 0) /* turn screen on */
for(i=0; i<nc; i++, p+=3)
setcolor(i, p[0], p[1], p[2]);
M port/devmouse.c => port/devmouse.c +13 -10
@@ 58,7 58,7 @@ static uchar buttonmap[8] = {
};
static int mouseswap;
-extern Memimage gscreen;
+extern Memimage* gscreen;
static void
mousereset(void)
@@ 323,7 323,7 @@ mousewrite(Chan *c, void *va, long n, vlong)
error(Eshort);
pt.y = strtoul(p, 0, 0);
qlock(&mouse);
- if(ptinrect(pt, gscreen.r)){
+ if(ptinrect(pt, gscreen->r)){
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;
M port/portfns.h => port/portfns.h +2 -1
@@ 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*);