NetBSD/sys/arch/i386/bios/vesabios.c
drochner 46289e1fef Phase out the use of a string as first "attach args" member to control
which bustype should be attached with a specific call to config_found()
(from a "mainbus" or a bus bridge).
Do it for isa/eisa/mca and pci/agp for now. These buses all attach to
an mi interface attribute "isabus", "eisabus" etc., and the autoconf
framework now allows to specify an interface attribute on config_found()
and config_search(), which limits the search of matching config data
to these which attach to that specific attribute.
So we basically have to call config_found_ia(..., "foobus", ...) where
such a bus is attached.
As a consequence, where a "mainbus" or alike also attaches other
devices (eg CPUs) which do not attach to a specific attribute yet,
we need at least pass an attribute name (different from "foobus") so
that the foo bus is not found at these places. This made some minor
changes necessary which are not obviously related to the mentioned buses.
2004-08-30 15:05:15 +00:00

277 lines
5.9 KiB
C

/* $NetBSD: vesabios.c,v 1.11 2004/08/30 15:05:17 drochner Exp $ */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vesabios.c,v 1.11 2004/08/30 15:05:17 drochner Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/frame.h>
#include <machine/kvm86.h>
#include <arch/i386/bios/vesabios.h>
#include <arch/i386/bios/vesabiosreg.h>
#include "opt_vesabios.h"
struct vbeinfoblock
{
char VbeSignature[4];
u_int16_t VbeVersion;
u_int32_t OemStringPtr;
u_int32_t Capabilities;
u_int32_t VideoModePtr;
u_int16_t TotalMemory;
u_int16_t OemSoftwareRev;
u_int32_t OemVendorNamePtr, OemProductNamePtr, OemProductRevPtr;
/* data area, in total max 512 bytes for VBE 2.0 */
} __attribute__ ((packed));
#define FAR2FLATPTR(p) ((p & 0xffff) + ((p >> 12) & 0xffff0))
static int vesabios_match(struct device *, struct cfdata *, void *);
static void vesabios_attach(struct device *, struct device *, void *);
static int vesabios_print(void *, const char *);
static int vbegetinfo(struct vbeinfoblock **);
static void vbefreeinfo(struct vbeinfoblock *);
#ifdef VESABIOSVERBOSE
static const char *mm2txt(unsigned int);
#endif
CFATTACH_DECL(vesabios, sizeof(struct device),
vesabios_match, vesabios_attach, NULL, NULL);
static int
vesabios_match(parent, match, aux)
struct device *parent;
struct cfdata *match;
void *aux;
{
return (1);
}
static int
vbegetinfo(vip)
struct vbeinfoblock **vip;
{
unsigned char *buf;
struct trapframe tf;
int res, error;
buf = kvm86_bios_addpage(0x2000);
if (!buf) {
printf("vbegetinfo: kvm86_bios_addpage(0x2000) failed\n");
return (ENOMEM);
}
memcpy(buf, "VBE2", 4);
memset(&tf, 0, sizeof(struct trapframe));
tf.tf_eax = 0x4f00; /* function code */
tf.tf_vm86_es = 0;
tf.tf_edi = 0x2000; /* buf ptr */
res = kvm86_bioscall(0x10, &tf);
if (res || tf.tf_eax != 0x004f) {
printf("vbecall: res=%d, ax=%x\n", res, tf.tf_eax);
error = ENXIO;
goto out;
}
if (memcmp(((struct vbeinfoblock *)buf)->VbeSignature, "VESA", 4)) {
error = EIO;
goto out;
}
if (vip)
*vip = (struct vbeinfoblock *)buf;
return (0);
out:
kvm86_bios_delpage(0x2000, buf);
return (error);
}
static void
vbefreeinfo(vip)
struct vbeinfoblock *vip;
{
kvm86_bios_delpage(0x2000, vip);
}
int
vbeprobe()
{
struct vbeinfoblock *vi;
if (vbegetinfo(&vi))
return (0);
vbefreeinfo(vi);
return (1);
}
#ifdef VESABIOSVERBOSE
static const char *
mm2txt(mm)
unsigned int mm;
{
static char buf[30];
static const char *names[] = {
"Text mode",
"CGA graphics",
"Hercules graphics",
"Planar",
"Packed pixel",
"Non-chain 4, 256 color",
"Direct Color",
"YUV"
};
if (mm < sizeof(names)/sizeof(names[0]))
return (names[mm]);
snprintf(buf, sizeof(buf), "unknown memory model %d", mm);
return (buf);
}
#endif
static void
vesabios_attach(parent, dev, aux)
struct device * parent, *dev;
void *aux;
{
struct vbeinfoblock *vi;
unsigned char *buf;
struct trapframe tf;
int res;
char name[256];
#define MAXMODES 60
u_int16_t modes[MAXMODES];
int raster8modes[MAXMODES];
int textmodes[MAXMODES];
int nmodes, nraster8modes, ntextmodes, i;
u_int32_t modeptr;
struct modeinfoblock *mi;
struct vesabiosdev_attach_args vbaa;
if (vbegetinfo(&vi))
panic("vesabios_attach: disappeared");
printf(": version %d.%d", vi->VbeVersion >> 8, vi->VbeVersion & 0xff);
res = kvm86_bios_read(FAR2FLATPTR(vi->OemVendorNamePtr),
name, sizeof(name));
if (res > 0) {
name[res - 1] = 0;
printf(", %s", name);
res = kvm86_bios_read(FAR2FLATPTR(vi->OemProductNamePtr),
name, sizeof(name));
if (res > 0) {
name[res - 1] = 0;
printf(" %s", name);
}
}
printf("\n");
nmodes = 0;
modeptr = FAR2FLATPTR(vi->VideoModePtr);
while (nmodes < MAXMODES) {
res = kvm86_bios_read(modeptr, (char *)&modes[nmodes], 2);
if (res != 2 || modes[nmodes] == 0xffff)
break;
nmodes++;
modeptr += 2;
}
vbefreeinfo(vi);
if (nmodes == 0)
return;
nraster8modes = ntextmodes = 0;
buf = kvm86_bios_addpage(0x2000);
if (!buf) {
printf("vesabios_attach: kvm86_bios_addpage(0x2000) failed\n");
return;
}
for (i = 0; i < nmodes; i++) {
memset(&tf, 0, sizeof(struct trapframe));
tf.tf_eax = 0x4f01; /* function code */
tf.tf_ecx = modes[i];
tf.tf_vm86_es = 0;
tf.tf_edi = 0x2000; /* buf ptr */
res = kvm86_bioscall(0x10, &tf);
if (res || tf.tf_eax != 0x004f) {
printf("vbecall: res=%d, ax=%x\n", res, tf.tf_eax);
printf("error getting info for mode %04x\n", modes[i]);
continue;
}
mi = (struct modeinfoblock *)buf;
#ifdef VESABIOSVERBOSE
printf("VESA mode %04x: attributes %04x",
modes[i], mi->ModeAttributes);
#endif
if (!(mi->ModeAttributes & 1)) {
#ifdef VESABIOSVERBOSE
printf("\n");
#endif
continue;
}
if (mi->ModeAttributes & 0x10) {
/* graphics */
#ifdef VESABIOSVERBOSE
printf(", %dx%d %dbbp %s\n",
mi->XResolution, mi->YResolution,
mi->BitsPerPixel, mm2txt(mi->MemoryModel));
#endif
if ((mi->ModeAttributes & 0x80)
&& mi->BitsPerPixel == 8
&& mi->MemoryModel == 4) {
/* flat buffer, 8bpp packed pixel */
raster8modes[nraster8modes++] = modes[i];
}
} else {
/* text */
#ifdef VESABIOSVERBOSE
printf(", text %dx%d\n",
mi->XResolution, mi->YResolution);
#endif
if (!(mi->ModeAttributes & 0x20)) /* VGA compatible */
textmodes[ntextmodes++] = modes[i];
}
}
kvm86_bios_delpage(0x2000, buf);
if (nraster8modes) {
vbaa.vbaa_type = "raster8";
vbaa.vbaa_modes = raster8modes;
vbaa.vbaa_nmodes = nraster8modes;
config_found(dev, &vbaa, vesabios_print);
}
if (ntextmodes) {
vbaa.vbaa_type = "text";
vbaa.vbaa_modes = textmodes;
vbaa.vbaa_nmodes = ntextmodes;
config_found(dev, &vbaa, vesabios_print);
}
}
static int
vesabios_print(aux, pnp)
void *aux;
const char *pnp;
{
struct vesabiosdev_attach_args *vbaa = aux;
if (pnp)
aprint_normal("%s at %s", vbaa->vbaa_type, pnp);
return (UNCONF);
}