diff options
Diffstat (limited to 'os/pc/vgaclgd546x.c')
| -rw-r--r-- | os/pc/vgaclgd546x.c | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/os/pc/vgaclgd546x.c b/os/pc/vgaclgd546x.c new file mode 100644 index 00000000..62bcd82a --- /dev/null +++ b/os/pc/vgaclgd546x.c @@ -0,0 +1,277 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#define Image IMAGE +#include <draw.h> +#include <memdraw.h> +#include <cursor.h> +#include "screen.h" + +typedef struct Cursor546x Cursor546x; +struct Cursor546x { + ushort x; + ushort y; + ushort preset; + ushort enable; + ushort addr; +}; + +enum { + PaletteState = 0xB0, + CursorMMIO = 0xE0, +}; + +static ulong +clgd546xlinear(VGAscr* scr, int* size, int* align) +{ + ulong aperture, oaperture; + int oapsize, wasupamem; + Pcidev *p; + + oaperture = scr->aperture; + oapsize = scr->apsize; + wasupamem = scr->isupamem; + + aperture = 0; + if(p = pcimatch(nil, 0x1013, 0)){ + switch(p->did){ + case 0xD0: + case 0xD4: + case 0xD6: + aperture = p->mem[0].bar & ~0x0F; + *size = p->mem[0].size; + break; + default: + break; + } + } + + if(wasupamem){ + if(oaperture == aperture) + return oaperture; + upafree(oaperture, oapsize); + } + scr->isupamem = 0; + + aperture = upamalloc(aperture, *size, *align); + if(aperture == 0){ + if(wasupamem && upamalloc(oaperture, oapsize, 0)){ + aperture = oaperture; + scr->isupamem = 1; + } + else + scr->isupamem = 0; + } + else + scr->isupamem = 1; + + return aperture; +} +static void +clgd546xenable(VGAscr* scr) +{ + Pcidev *p; + int size, align; + ulong aperture; + + /* + * Only once, can't be disabled for now. + * scr->io holds the virtual address of + * the MMIO registers. + */ + if(scr->io) + return; + if(p = pcimatch(nil, 0x1013, 0)){ + switch(p->did){ + case 0xD0: + case 0xD4: + case 0xD6: + break; + default: + return; + } + } + else + return; + scr->io = upamalloc(p->mem[1].bar & ~0x0F, p->mem[1].size, 0); + if(scr->io == 0) + return; + addvgaseg("clgd546xmmio", scr->io, p->mem[1].size); + + scr->io = (ulong)KADDR(scr->io); + + size = p->mem[0].size; + align = 0; + aperture = clgd546xlinear(scr, &size, &align); + if(aperture) { + scr->aperture = aperture; + scr->apsize = size; + addvgaseg("clgd546xscreen", aperture, size); + } +} + +static void +clgd546xcurdisable(VGAscr* scr) +{ + Cursor546x *cursor546x; + + if(scr->io == 0) + return; + cursor546x = (Cursor546x*)(scr->io+CursorMMIO); + cursor546x->enable = 0; +} + +static void +clgd546xcurload(VGAscr* scr, Cursor* curs) +{ + int c, i, m, y; + uchar *p; + Cursor546x *cursor546x; + + if(scr->io == 0) + return; + cursor546x = (Cursor546x*)(scr->io+CursorMMIO); + + /* + * Disable the cursor then change only the bits + * that need it. + */ + cursor546x->enable = 0; + p = (uchar*)(scr->aperture + scr->storage); + for(y = 0; y < 16; y++){ + c = curs->set[2*y]; + m = 0; + for(i = 0; i < 8; i++){ + if(c & (1<<(7-i))) + m |= 1<<i; + } + *p++ = m; + c = curs->set[2*y + 1]; + m = 0; + for(i = 0; i < 8; i++){ + if(c & (1<<(7-i))) + m |= 1<<i; + } + *p++ = m; + p += 6; + c = curs->set[2*y]|curs->clr[2*y]; + m = 0; + for(i = 0; i < 8; i++){ + if(c & (1<<(7-i))) + m |= 1<<i; + } + *p++ = m; + c = curs->set[2*y + 1]|curs->clr[2*y + 1]; + m = 0; + for(i = 0; i < 8; i++){ + if(c & (1<<(7-i))) + m |= 1<<i; + } + *p++ = m; + p += 6; + } + + /* + * Save the cursor hotpoint and enable the cursor. + */ + scr->offset = curs->offset; + cursor546x->enable = 1; +} + +static int +clgd546xcurmove(VGAscr* scr, Point p) +{ + int x, xo, y, yo; + Cursor546x *cursor546x; + + if(scr->io == 0) + return 1; + cursor546x = (Cursor546x*)(scr->io+CursorMMIO); + + if((x = p.x+scr->offset.x) < 0){ + xo = -x; + x = 0; + } + else + xo = 0; + if((y = p.y+scr->offset.y) < 0){ + yo = -y; + y = 0; + } + else + yo = 0; + + cursor546x->preset = (xo<<8)|yo; + cursor546x->x = x; + cursor546x->y = y; + + return 0; +} + +static void +clgd546xcurenable(VGAscr* scr) +{ + uchar *p; + Cursor546x *cursor546x; + + clgd546xenable(scr); + if(scr->io == 0) + return; + cursor546x = (Cursor546x*)(scr->io+CursorMMIO); + + /* + * Cursor colours. + * Can't call setcolor here as cursor is already locked. + */ + p = (uchar*)(scr->io+PaletteState); + *p |= 0x08; + vgao(PaddrW, 0x00); + vgao(Pdata, Pwhite); + vgao(Pdata, Pwhite); + vgao(Pdata, Pwhite); + vgao(PaddrW, 0x0F); + vgao(Pdata, Pblack); + vgao(Pdata, Pblack); + vgao(Pdata, Pblack); + *p &= ~0x08; + + /* + * Find a place for the cursor data in display memory. + * 2 cursor images might be needed, 1KB each so use the last + * 2KB of the framebuffer and initialise them to be + * transparent. + */ + scr->storage = ((vgaxi(Seqx, 0x14) & 0x07)+1)*1024*1022; + cursor546x->addr = (scr->storage>>10)<<2; + memset((uchar*)(scr->aperture + scr->storage), 0, 2*64*16); + + /* + * Load, locate and enable the 64x64 cursor. + */ + clgd546xcurload(scr, &arrow); + clgd546xcurmove(scr, ZP); + cursor546x->enable = 1; +} + +VGAdev vgaclgd546xdev = { + "clgd546x", + + clgd546xenable, + nil, + nil, + clgd546xlinear, +}; + +VGAcur vgaclgd546xcur = { + "clgd546xhwgc", + + clgd546xcurenable, + clgd546xcurdisable, + clgd546xcurload, + clgd546xcurmove, +}; |
