diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/vga/vga.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/vga.c')
-rwxr-xr-x | sys/src/cmd/aux/vga/vga.c | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/vga.c b/sys/src/cmd/aux/vga/vga.c new file mode 100755 index 000000000..7fb79c2a7 --- /dev/null +++ b/sys/src/cmd/aux/vga/vga.c @@ -0,0 +1,486 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "pci.h" +#include "vga.h" + +enum { + NSeqx = 0x05, + NCrtx = 0x19, + NGrx = 0x09, + NAttrx = 0x15, +}; + +uchar +vgai(long port) +{ + uchar data; + + switch(port){ + + case MiscR: + case Status0: + case Status1: + case FeatureR: + case PaddrW: + case Pdata: + case Pixmask: + case Pstatus: + data = inportb(port); + break; + + default: + error("vgai(0x%4.4lX): unknown port\n", port); + /*NOTREACHED*/ + data = 0xFF; + break; + } + return data; +} + +uchar +vgaxi(long port, uchar index) +{ + uchar data; + + switch(port){ + + case Seqx: + case Crtx: + case Grx: + outportb(port, index); + data = inportb(port+1); + break; + + case Attrx: + /* + * Allow processor access to the colour + * palette registers. Writes to Attrx must + * be preceded by a read from Status1 to + * initialise the register to point to the + * index register and not the data register. + * Processor access is allowed by turning + * off bit 0x20. + */ + inportb(Status1); + if(index < 0x10){ + outportb(Attrx, index); + data = inportb(Attrx+1); + inportb(Status1); + outportb(Attrx, 0x20|index); + } + else{ + outportb(Attrx, 0x20|index); + data = inportb(Attrx+1); + } + break; + + default: + error("vgaxi(0x%4.4lx, 0x%2.2uX): unknown port\n", port, index); + /*NOTREACHED*/ + data = 0xFF; + break; + } + return data; +} + +void +vgao(long port, uchar data) +{ + switch(port){ + + case MiscW: + case FeatureW: + case PaddrW: + case Pdata: + case Pixmask: + case PaddrR: + outportb(port, data); + break; + + default: + error("vgao(0x%4.4lX, 0x%2.2uX): unknown port\n", port, data); + /*NOTREACHED*/ + break; + } +} + +void +vgaxo(long port, uchar index, uchar data) +{ + switch(port){ + + case Seqx: + case Crtx: + case Grx: + /* + * We could use an outport here, but some chips + * (e.g. 86C928) have trouble with that for some + * registers. + */ + outportb(port, index); + outportb(port+1, data); + break; + + case Attrx: + inportb(Status1); + if(index < 0x10){ + outportb(Attrx, index); + outportb(Attrx, data); + inportb(Status1); + outportb(Attrx, 0x20|index); + } + else{ + outportb(Attrx, 0x20|index); + outportb(Attrx, data); + } + break; + + default: + error("vgaxo(0x%4.4lX, 0x%2.2uX, 0x%2.2uX): unknown port\n", + port, index, data); + break; + } +} + +static void +snarf(Vga* vga, Ctlr* ctlr) +{ + int i; + + /* + * Generic VGA registers: + * misc, feature; + * sequencer; + * crt; + * graphics; + * attribute; + * palette. + */ + vga->misc = vgai(MiscR); + vga->feature = vgai(FeatureR); + + for(i = 0; i < NSeqx; i++) + vga->sequencer[i] = vgaxi(Seqx, i); + + for(i = 0; i < NCrtx; i++) + vga->crt[i] = vgaxi(Crtx, i); + + for(i = 0; i < NGrx; i++) + vga->graphics[i] = vgaxi(Grx, i); + + for(i = 0; i < NAttrx; i++) + vga->attribute[i] = vgaxi(Attrx, i); + + if(dflag) + palette.snarf(vga, ctlr); + + ctlr->flag |= Fsnarf; +} + +static void +init(Vga* vga, Ctlr* ctlr) +{ + Mode *mode; + int vt, vde, vrs, vre; + ulong tmp; + + mode = vga->mode; + + memset(vga->sequencer, 0, NSeqx*sizeof(vga->sequencer[0])); + memset(vga->crt, 0, NCrtx*sizeof(vga->crt[0])); + memset(vga->graphics, 0, NGrx*sizeof(vga->graphics[0])); + memset(vga->attribute, 0, NAttrx*sizeof(vga->attribute[0])); + if(dflag) + memset(vga->palette, 0, sizeof(vga->palette)); + + /* + * Misc. If both the horizontal and vertical sync polarity + * options are set, use them. Otherwise use the defaults for + * the given vertical size. + */ + vga->misc = 0x23; + if(mode->frequency == VgaFreq1) + vga->misc |= 0x04; + if(mode->hsync && mode->vsync){ + if(mode->hsync == '-') + vga->misc |= 0x40; + if(mode->vsync == '-') + vga->misc |= 0x80; + } + else{ + if(mode->y < 480) + vga->misc |= 0x40; + else if(mode->y < 400) + vga->misc |= 0x80; + else if(mode->y < 768) + vga->misc |= 0xC0; + } + + /* + * Sequencer + */ + vga->sequencer[0x00] = 0x03; + vga->sequencer[0x01] = 0x01; + vga->sequencer[0x02] = 0x0F; + vga->sequencer[0x03] = 0x00; + if(mode->z >= 8) + vga->sequencer[0x04] = 0x0A; + else + vga->sequencer[0x04] = 0x06; + + /* + * Crt. Most of the work here is in dealing + * with field overflow. + */ + memset(vga->crt, 0, NCrtx); + + vga->crt[0x00] = (mode->ht>>3)-5; + vga->crt[0x01] = (mode->x>>3)-1; + vga->crt[0x02] = (mode->shb>>3)-1; + + /* + * End Horizontal Blank is a 6-bit field, 5-bits + * in Crt3, high bit in Crt5. + */ + tmp = mode->ehb>>3; + vga->crt[0x03] = 0x80|(tmp & 0x1F); + if(tmp & 0x20) + vga->crt[0x05] |= 0x80; + + if(mode->shs == 0) + mode->shs = mode->shb; + vga->crt[0x04] = mode->shs>>3; + if(mode->ehs == 0) + mode->ehs = mode->ehb; + vga->crt[0x05] |= ((mode->ehs>>3) & 0x1F); + + /* + * Vertical Total is 10-bits, 8 in Crt6, the high + * two bits in Crt7. What if vt is >= 1024? We hope + * the specific controller has some more overflow + * bits. + * + * Interlace: if 'v', divide the vertical timing + * values by 2. + */ + vt = mode->vt; + vde = mode->y; + vrs = mode->vrs; + vre = mode->vre; + + if(mode->interlace == 'v'){ + vt /= 2; + vde /= 2; + vrs /= 2; + vre /= 2; + } + + tmp = vt-2; + vga->crt[0x06] = tmp; + if(tmp & 0x100) + vga->crt[0x07] |= 0x01; + if(tmp & 0x200) + vga->crt[0x07] |= 0x20; + + tmp = vrs; + vga->crt[0x10] = tmp; + if(tmp & 0x100) + vga->crt[0x07] |= 0x04; + if(tmp & 0x200) + vga->crt[0x07] |= 0x80; + + vga->crt[0x11] = 0x20|(vre & 0x0F); + + tmp = vde-1; + vga->crt[0x12] = tmp; + if(tmp & 0x100) + vga->crt[0x07] |= 0x02; + if(tmp & 0x200) + vga->crt[0x07] |= 0x40; + + vga->crt[0x15] = vrs; + if(vrs & 0x100) + vga->crt[0x07] |= 0x08; + if(vrs & 0x200) + vga->crt[0x09] |= 0x20; + + vga->crt[0x16] = (vrs+1); + + vga->crt[0x17] = 0x83; + tmp = ((vga->virtx*mode->z)/8); + if(tmp >= 512){ + vga->crt[0x14] |= 0x60; + tmp /= 8; + } + else if(tmp >= 256){ + vga->crt[0x17] |= 0x08; + tmp /= 4; + } + else{ + vga->crt[0x17] |= 0x40; + tmp /= 2; + } + vga->crt[0x13] = tmp; + + if(mode->x*mode->y*mode->z/8 > 64*1024) + vga->crt[0x17] |= 0x20; + + vga->crt[0x18] = 0x7FF; + if(vga->crt[0x18] & 0x100) + vga->crt[0x07] |= 0x10; + if(vga->crt[0x18] & 0x200) + vga->crt[0x09] |= 0x40; + + /* + * Graphics + */ + memset(vga->graphics, 0, NGrx); + if((vga->sequencer[0x04] & 0x04) == 0) + vga->graphics[0x05] |= 0x10; + if(mode->z >= 8) + vga->graphics[0x05] |= 0x40; + vga->graphics[0x06] = 0x05; + vga->graphics[0x07] = 0x0F; + vga->graphics[0x08] = 0xFF; + + /* + * Attribute + */ + memset(vga->attribute, 0, NAttrx); + for(tmp = 0; tmp < 0x10; tmp++) + vga->attribute[tmp] = tmp; + vga->attribute[0x10] = 0x01; + if(mode->z >= 8) + vga->attribute[0x10] |= 0x40; + vga->attribute[0x11] = 0xFF; + vga->attribute[0x12] = 0x0F; + + /* + * Palette + */ + if(dflag) + palette.init(vga, ctlr); + + ctlr->flag |= Finit; +} + +static void +load(Vga* vga, Ctlr* ctlr) +{ + int i; + + /* + * Reset the sequencer and leave it off. + * Load the generic VGA registers: + * misc; + * sequencer (but not seq01, display enable); + * take the sequencer out of reset; + * take off write-protect on crt[0x00-0x07]; + * crt; + * graphics; + * attribute; + * palette. + vgaxo(Seqx, 0x00, 0x00); + */ + + vgao(MiscW, vga->misc); + + for(i = 2; i < NSeqx; i++) + vgaxo(Seqx, i, vga->sequencer[i]); + /*vgaxo(Seqx, 0x00, 0x03);*/ + + vgaxo(Crtx, 0x11, vga->crt[0x11] & ~0x80); + for(i = 0; i < NCrtx; i++) + vgaxo(Crtx, i, vga->crt[i]); + + for(i = 0; i < NGrx; i++) + vgaxo(Grx, i, vga->graphics[i]); + + for(i = 0; i < NAttrx; i++) + vgaxo(Attrx, i, vga->attribute[i]); + + if(dflag) + palette.load(vga, ctlr); + + ctlr->flag |= Fload; +} + +static void +dump(Vga* vga, Ctlr* ctlr) +{ + int i; + + printitem(ctlr->name, "misc"); + printreg(vga->misc); + printitem(ctlr->name, "feature"); + printreg(vga->feature); + + printitem(ctlr->name, "sequencer"); + for(i = 0; i < NSeqx; i++) + printreg(vga->sequencer[i]); + + printitem(ctlr->name, "crt"); + for(i = 0; i < NCrtx; i++) + printreg(vga->crt[i]); + + printitem(ctlr->name, "graphics"); + for(i = 0; i < NGrx; i++) + printreg(vga->graphics[i]); + + printitem(ctlr->name, "attribute"); + for(i = 0; i < NAttrx; i++) + printreg(vga->attribute[i]); + + if(dflag) + palette.dump(vga, ctlr); + + printitem(ctlr->name, "virtual"); + Bprint(&stdout, "%ld %ld\n", vga->virtx, vga->virty); + printitem(ctlr->name, "panning"); + Bprint(&stdout, "%s\n", vga->panning ? "on" : "off"); + if(vga->f[0]){ + printitem(ctlr->name, "clock[0] f"); + Bprint(&stdout, "%9ld\n", vga->f[0]); + printitem(ctlr->name, "clock[0] d i m"); + Bprint(&stdout, "%9ld %8ld - %8ld\n", + vga->d[0], vga->i[0], vga->m[0]); + printitem(ctlr->name, "clock[0] n p q r"); + Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n", + vga->n[0], vga->p[0], vga->q[0], vga->r[0]); + } + if(vga->f[1]){ + printitem(ctlr->name, "clock[1] f"); + Bprint(&stdout, "%9ld\n", vga->f[1]); + printitem(ctlr->name, "clock[1] d i m"); + Bprint(&stdout, "%9ld %8ld - %8ld\n", + vga->d[1], vga->i[1], vga->m[1]); + printitem(ctlr->name, "clock[1] n p q r"); + Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n", + vga->n[1], vga->p[1], vga->q[1], vga->r[1]); + } + + if(vga->vma || vga->vmb){ + printitem(ctlr->name, "vm a b"); + Bprint(&stdout, "%9lud %8lud\n", vga->vma, vga->vmb); + } + if(vga->vmz){ + printitem(ctlr->name, "vmz"); + Bprint(&stdout, "%9lud\n", vga->vmz); + } + printitem(ctlr->name, "apz"); + Bprint(&stdout, "%9lud\n", vga->apz); + + printitem(ctlr->name, "linear"); + Bprint(&stdout, "%9d\n", vga->linear); +} + +Ctlr generic = { + "vga", /* name */ + snarf, /* snarf */ + 0, /* options */ + init, /* init */ + load, /* load */ + dump, /* dump */ +}; |