Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ndb.h>

#include "pci.h"
#include "vga.h"

static Ndb*
dbopen(char* dbname)
{
        Ndb *db;

        if((db = ndbopen(dbname)) == 0)
                error("dbopen: %s: %r\n", dbname);
        return db;
}

static void
addattr(Attr** app, Ndbtuple* t)
{
        Attr *attr, *l;

        attr = alloc(sizeof(Attr));
        attr->attr = alloc(strlen(t->attr)+1);
        strcpy(attr->attr, t->attr);
        attr->val = alloc(strlen(t->val)+1);
        strcpy(attr->val, t->val);

        for(l = *app; l; l = l->next)
                app = &l->next;
        *app = attr;
}

char*
dbattr(Attr* ap, char* attr)
{
        while(ap){
                if(strcmp(ap->attr, attr) == 0)
                        return ap->val;
                ap = ap->next;
        }

        return 0;
}

static Ctlr*
addctlr(Vga* vga, char* val)
{
        Ctlr **ctlr;
        char name[Namelen+1], *p;
        int i;

        /*
         * A controller name may have an extension on the end
         * following a '-' which can be used as a speed grade or
         * subtype.  Do the match without the extension.
         * The linked copy of the controller struct gets the
         * full name with extension.
         */
        strncpy(name, val, Namelen);
        name[Namelen] = 0;
        if(p = strchr(name, '-'))
                *p = 0;

        for(i = 0; ctlrs[i]; i++){
                if(strcmp(ctlrs[i]->name, name))
                        continue;
                for(ctlr = &vga->link; *ctlr; ctlr = &((*ctlr)->link))
                        ;
                *ctlr = alloc(sizeof(Ctlr));
                **ctlr = *ctlrs[i];
                strncpy((*ctlr)->name, val, Namelen);
                return *ctlr;   
        }

        fprint(2, "dbctlr: unknown controller \"%s\" ctlr\n", val);
        return 0;
}

int
dbbios(Vga *vga, Ndbtuple *tuple)
{
        char *bios, *p, *string;
        int len;
        long offset, offset1;
        Ndbtuple *t;

        for(t = tuple->entry; t; t = t->entry){
                if((offset = strtol(t->attr, 0, 0)) == 0)
                        continue;

                string = t->val;
                len = strlen(string);

                if(p = strchr(t->attr, '-')) {
                        if((offset1 = strtol(p+1, 0, 0)) < offset+len)
                                continue;
                } else
                        offset1 = offset+len;

                if(vga->offset) {
                        if(offset > vga->offset || vga->offset+len > offset1)
                                continue;
                        offset = vga->offset;
                        offset1 = offset+len;
                }

                for(; offset+len<=offset1; offset++) {
                        if(vga->bios)
                                bios = vga->bios;
                        else
                                bios = readbios(len, offset);
                        if(strncmp(bios, string, len) == 0){
                                if(vga->bios == 0){
                                        vga->bios = alloc(len+1);
                                        strncpy(vga->bios, bios, len);
                                }
                                addattr(&vga->attr, t);
                                return 1;
                        }
                }
        }
        return 0;
}

int
dbpci(Vga *vga, Ndbtuple *tuple)
{
        int did, vid;
        Ndbtuple *t, *td;
        Pcidev *pci;

        for(t = tuple->entry; t; t = t->entry){
                if(strcmp(t->attr, "vid") != 0 || (vid=atoi(t->val)) == 0)
                        continue;
                for(td = t->line; td != t; td = td->line){
                        if(strcmp(td->attr, "did") != 0)
                                continue;
                        if(strcmp(td->val, "*") == 0)
                                did = 0;
                        else if((did=atoi(td->val)) == 0)
                                continue;
                        for(pci=nil; pci=pcimatch(pci, vid, did);)
                                if((pci->ccru>>8) == 3)
                                        break;
                        if(pci == nil)
                                continue;
                        vga->pci = pci;
                        addattr(&vga->attr, t);
                        addattr(&vga->attr, td);
                        return 1;
                }
        }
        return 0;
}

static void
save(Vga *vga, Ndbtuple *tuple)
{
        Ctlr *c;
        Ndbtuple *t;

        for(t = tuple->entry; t; t = t->entry){
                if(strcmp(t->attr, "ctlr") == 0){
                        vga->ctlr = addctlr(vga, t->val);
                        if(strcmp(t->val, "vesa") == 0)
                                vga->vesa = vga->ctlr;
                }else if(strcmp(t->attr, "ramdac") == 0)
                        vga->ramdac = addctlr(vga, t->val);
                else if(strcmp(t->attr, "clock") == 0)
                        vga->clock = addctlr(vga, t->val);
                else if(strcmp(t->attr, "hwgc") == 0)
                        vga->hwgc = addctlr(vga, t->val);
                else if(strcmp(t->attr, "link") == 0){
                        c = addctlr(vga, t->val);
                        if(strcmp(t->val, "vesa") == 0)
                                vga->vesa = c;
                }else if(strcmp(t->attr, "linear") == 0)
                        vga->linear = strtol(t->val, 0, 0);
                else if(strcmp(t->attr, "membw") == 0)
                        vga->membw = strtol(t->val, 0, 0)*1000000;
                else if(strcmp(t->attr, "vid")==0 || strcmp(t->attr, "did")==0)
                        {}
                else if(strtol(t->attr, 0, 0) == 0)
                        addattr(&vga->attr, t);
        }
}

int
dbctlr(char* name, Vga* vga)
{
        Ndb *db;
        Ndbs s;
        Ndbtuple *tuple;
        Ndbtuple *pcituple;

        db = dbopen(name);

        /*
         * Search vgadb for a matching BIOS string or PCI id.
         * If we have both, the BIOS string wins.
         */
        pcituple = nil;
        for(tuple = ndbsearch(db, &s, "ctlr", ""); tuple; tuple = ndbsnext(&s, "ctlr", "")){
                if(!pcituple && dbpci(vga, tuple))
                        pcituple = tuple;
                if(dbbios(vga, tuple)){
                        save(vga, tuple);
                        if(pcituple && pcituple != tuple)
                                ndbfree(pcituple);
                        ndbfree(tuple);
                        ndbclose(db);
                        return 1;
                }
                if(tuple != pcituple)
                        ndbfree(tuple);
        }

        if(pcituple){
                save(vga, pcituple);
                ndbfree(pcituple);
        }
        ndbclose(db);
        if(pcituple)
                return 1;
        return 0;
}

static int
dbmonitor(Ndb* db, Mode* mode, char* type, char* size)
{
        Ndbs s;
        Ndbtuple *t, *tuple;
        char *p, attr[Namelen+1], val[Namelen+1], buf[2*Namelen+1];
        int clock, x, i;

        /*
         * Clock rate hack.
         * If the size is 'XxYxZ@NMHz' then override the database entry's
         * 'clock=' with 'N*1000000'.
         */
        clock = 0;
        strcpy(buf, size);
        if(p = strchr(buf, '@')){
                *p++ = 0;
                if((clock = strtol(p, &p, 0)) && strcmp(p, "MHz") == 0)
                        clock *= 1000000;
        }

        memset(mode, 0, sizeof(Mode));

        if((p = strchr(buf, 'x')) && (p = strchr(p+1, 'x'))){
                *p++ = 0;
                mode->z = atoi(p);
        }

        strcpy(attr, type);
        strcpy(val, buf);

        if(p = ndbgetvalue(db, &s, attr, "", "videobw", nil)){
                mode->videobw = atol(p)*1000000UL;
                free(p);
        }

        if(mode->x == 0 && ((mode->x = strtol(val, &p, 0)) == 0 || *p++ != 'x'))
                return 0;
        if(mode->y == 0 && (mode->y = strtol(p, &p, 0)) == 0)
                return 0;
        i = 0;
buggery:
        if((tuple = ndbsearch(db, &s, attr, val)) == 0)
                return 0;

        for(t = tuple->entry; t; t = t->entry){
                if(strcmp(t->attr, "clock") == 0 && mode->frequency == 0)
                        mode->frequency = strtod(t->val, 0)*1000000;
                else if(strcmp(t->attr, "defaultclock") == 0 && mode->deffrequency == 0)
                        mode->deffrequency = strtod(t->val, 0)*1000000;
                else if(strcmp(t->attr, "ht") == 0 && mode->ht == 0)
                        mode->ht = strtol(t->val, 0, 0);
                else if(strcmp(t->attr, "shb") == 0 && mode->shb == 0)
                        mode->shb = strtol(t->val, 0, 0);
                else if(strcmp(t->attr, "ehb") == 0 && mode->ehb == 0)
                        mode->ehb = strtol(t->val, 0, 0);
                else if(strcmp(t->attr, "shs") == 0 && mode->shs == 0)
                        mode->shs = strtol(t->val, 0, 0);
                else if(strcmp(t->attr, "ehs") == 0 && mode->ehs == 0)
                        mode->ehs = strtol(t->val, 0, 0);
                else if(strcmp(t->attr, "vt") == 0 && mode->vt == 0)
                        mode->vt = strtol(t->val, 0, 0);
                else if(strcmp(t->attr, "vrs") == 0 && mode->vrs == 0)
                        mode->vrs = strtol(t->val, 0, 0);
                else if(strcmp(t->attr, "vre") == 0 && mode->vre == 0)
                        mode->vre = strtol(t->val, 0, 0);
                else if(strcmp(t->attr, "hsync") == 0)
                        mode->hsync = *t->val;
                else if(strcmp(t->attr, "vsync") == 0)
                        mode->vsync = *t->val;
                else if(strcmp(t->attr, "interlace") == 0)
                        mode->interlace = *t->val;
                else if(strcmp(t->attr, "include") == 0 /*&& strcmp(t->val, val) != 0*/){
                        strcpy(attr, t->attr);
                        strcpy(val, t->val);
                        ndbfree(tuple);
                        if(i++ > 5)
                                error("dbmonitor: implausible include depth at %s=%s\n", attr, val);
                        goto buggery;
                }
                else if(strcmp(t->attr, "include") == 0){
                        print("warning: bailed out of infinite loop in attr %s=%s\n", attr, val);
                }
                else
                        addattr(&mode->attr, t);
        }
        ndbfree(tuple);

        if((x = strtol(size, &p, 0)) == 0 || x != mode->x || *p++ != 'x')
                return 0;
        if((x = strtol(p, &p, 0)) == 0 || x != mode->y || *p++ != 'x')
                return 0;
        if((x = strtol(p, &p, 0)) == 0 || x != mode->z)
                return 0;

        if(clock)
                mode->frequency = clock;

        return 1;
}

Mode*
dbmode(char* name, char* type, char* size)
{
        Ndb *db;
        Ndbs s;
        Ndbtuple *t, *tuple;
        Mode *mode;
        char attr[Namelen+1];
        ulong videobw;

        db = dbopen(name);
        mode = alloc(sizeof(Mode));
        strcpy(attr, type);

        videobw = 0;
        /*
         * Look for the attr=size entry.
         */
        if(dbmonitor(db, mode, attr, size)){
                strcpy(mode->type, type);
                strcpy(mode->size, size);
                ndbclose(db);
                return mode;
        }

        if(mode->videobw && videobw == 0)       /* we at least found that; save it away */
                videobw = mode->videobw;

        /*
         * Not found. Look for an attr="" entry and then
         * for an alias=attr within.
         */
buggery:
        for(tuple = ndbsearch(db, &s, attr, ""); tuple; tuple = ndbsnext(&s, attr, "")){
                for(t = tuple->entry; t; t = t->entry){
                        if(strcmp(t->attr, "alias"))
                                continue;
                        strcpy(attr, t->val);
                        if(dbmonitor(db, mode, attr, size)){
                                strcpy(mode->type, type);
                                strcpy(mode->size, size);
                                ndbfree(tuple);
                                ndbclose(db);
                                if(videobw)
                                        mode->videobw = videobw;
                                return mode;
                        }

                        /*
                         * Found an alias but no match for size,
                         * restart looking for attr="" with the
                         * new attr.
                         */
                        ndbfree(tuple);
                        goto buggery;
                }
                ndbfree(tuple);
        }

        free(mode);
        ndbclose(db);
        return 0;
}

void
dbdumpmode(Mode* mode)
{
        Attr *attr;

        Bprint(&stdout, "dbdumpmode\n");

        Bprint(&stdout, "type=%s, size=%s\n", mode->type, mode->size);
        Bprint(&stdout, "frequency=%d\n", mode->frequency);
        Bprint(&stdout, "x=%d (0x%X), y=%d (0x%X), z=%d (0x%X)\n",
                mode->x, mode->x, mode->y,  mode->y, mode->z, mode->z);
        Bprint(&stdout, "ht=%d (0x%X), shb=%d (0x%X), ehb=%d (0x%X)\n",
                mode->ht, mode->ht, mode->shb, mode->shb, mode->ehb, mode->ehb);
        Bprint(&stdout, "shs=%d (0x%X), ehs=%d (0x%X)\n",
                mode->shs, mode->shs, mode->ehs, mode->ehs);
        Bprint(&stdout, "vt=%d (0x%X), vrs=%d (0x%X), vre=%d (0x%X)\n",
                mode->vt, mode->vt, mode->vrs, mode->vrs, mode->vre, mode->vre);
        Bprint(&stdout, "hsync=%d, vsync=%d, interlace=%d\n",
                mode->hsync, mode->vsync, mode->interlace);

        for(attr = mode->attr; attr; attr = attr->next)
                Bprint(&stdout, "mode->attr: %s=%s\n", attr->attr, attr->val);
}