1b9878ffcf
The address written to 0xcf8 contains the PCI slot address to send the config cycle to. However, we would ignore that and always send the cycle to the device whose BIOS we were running. This breaks some integrated graphics platforms that have explicit knowledge about the system's host bridge, for example.
741 lines
18 KiB
C
741 lines
18 KiB
C
/*
|
|
* XFree86 int10 module
|
|
* execute BIOS int 10h calls in x86 real mode environment
|
|
* Copyright 1999 Egbert Eich
|
|
*
|
|
* Part of this code was inspired by the VBIOS POSTing code in DOSEMU
|
|
* developed by the "DOSEMU-Development-Team"
|
|
*/
|
|
|
|
/*
|
|
* To debug port accesses define PRINT_PORT to 1.
|
|
* Note! You also have to comment out ioperm()
|
|
* in xf86EnableIO(). Otherwise we won't trap
|
|
* on PIO.
|
|
*/
|
|
|
|
#ifdef HAVE_XORG_CONFIG_H
|
|
#include <xorg-config.h>
|
|
#endif
|
|
|
|
#define PRINT_PORT 0
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <X11/Xos.h>
|
|
#include "xf86.h"
|
|
#include "xf86_OSproc.h"
|
|
#include "compiler.h"
|
|
#define _INT10_PRIVATE
|
|
#include "int10Defines.h"
|
|
#include "xf86int10.h"
|
|
#include "Pci.h"
|
|
#ifdef _X86EMU
|
|
#include "x86emu/x86emui.h"
|
|
#endif
|
|
#include <pciaccess.h>
|
|
|
|
static int pciCfg1in(CARD16 addr, CARD32 *val);
|
|
static int pciCfg1out(CARD16 addr, CARD32 val);
|
|
static int pciCfg1inw(CARD16 addr, CARD16 *val);
|
|
static int pciCfg1outw(CARD16 addr, CARD16 val);
|
|
static int pciCfg1inb(CARD16 addr, CARD8 *val);
|
|
static int pciCfg1outb(CARD16 addr, CARD8 val);
|
|
#if defined (_PC)
|
|
static void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set);
|
|
#endif
|
|
|
|
#define REG pInt
|
|
|
|
int
|
|
setup_int(xf86Int10InfoPtr pInt)
|
|
{
|
|
if (pInt != Int10Current) {
|
|
if (!MapCurrentInt10(pInt))
|
|
return -1;
|
|
Int10Current = pInt;
|
|
}
|
|
X86_EAX = (CARD32) pInt->ax;
|
|
X86_EBX = (CARD32) pInt->bx;
|
|
X86_ECX = (CARD32) pInt->cx;
|
|
X86_EDX = (CARD32) pInt->dx;
|
|
X86_ESI = (CARD32) pInt->si;
|
|
X86_EDI = (CARD32) pInt->di;
|
|
X86_EBP = (CARD32) pInt->bp;
|
|
X86_ESP = 0x1000; X86_SS = pInt->stackseg >> 4;
|
|
X86_EIP = 0x0600; X86_CS = 0x0; /* address of 'hlt' */
|
|
X86_DS = 0x40; /* standard pc ds */
|
|
X86_ES = pInt->es;
|
|
X86_FS = 0;
|
|
X86_GS = 0;
|
|
X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK;
|
|
#if defined (_PC)
|
|
if (pInt->Flags & SET_BIOS_SCRATCH)
|
|
SetResetBIOSVars(pInt, TRUE);
|
|
#endif
|
|
return xf86BlockSIGIO();
|
|
}
|
|
|
|
void
|
|
finish_int(xf86Int10InfoPtr pInt, int sig)
|
|
{
|
|
xf86UnblockSIGIO(sig);
|
|
pInt->ax = (CARD32) X86_EAX;
|
|
pInt->bx = (CARD32) X86_EBX;
|
|
pInt->cx = (CARD32) X86_ECX;
|
|
pInt->dx = (CARD32) X86_EDX;
|
|
pInt->si = (CARD32) X86_ESI;
|
|
pInt->di = (CARD32) X86_EDI;
|
|
pInt->es = (CARD16) X86_ES;
|
|
pInt->bp = (CARD32) X86_EBP;
|
|
pInt->flags = (CARD32) X86_FLAGS;
|
|
#if defined (_PC)
|
|
if (pInt->Flags & RESTORE_BIOS_SCRATCH)
|
|
SetResetBIOSVars(pInt, FALSE);
|
|
#endif
|
|
}
|
|
|
|
/* general software interrupt handler */
|
|
CARD32
|
|
getIntVect(xf86Int10InfoPtr pInt,int num)
|
|
{
|
|
return MEM_RW(pInt, num << 2) + (MEM_RW(pInt, (num << 2) + 2) << 4);
|
|
}
|
|
|
|
void
|
|
pushw(xf86Int10InfoPtr pInt, CARD16 val)
|
|
{
|
|
X86_ESP -= 2;
|
|
MEM_WW(pInt, ((CARD32) X86_SS << 4) + X86_SP, val);
|
|
}
|
|
|
|
int
|
|
run_bios_int(int num, xf86Int10InfoPtr pInt)
|
|
{
|
|
CARD32 eflags;
|
|
#ifndef _PC
|
|
/* check if bios vector is initialized */
|
|
if (MEM_RW(pInt, (num << 2) + 2) == (SYS_BIOS >> 4)) { /* SYS_BIOS_SEG ?*/
|
|
|
|
if (num == 21 && X86_AH == 0x4e) {
|
|
xf86DrvMsg(pInt->scrnIndex, X_NOTICE,
|
|
"Failing Find-Matching-File on non-PC"
|
|
" (int 21, func 4e)\n");
|
|
X86_AX = 2;
|
|
SET_FLAG(F_CF);
|
|
return 1;
|
|
} else {
|
|
xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
|
|
"Ignoring int 0x%02x call\n", num);
|
|
if (xf86GetVerbosity() > 3) {
|
|
dump_registers(pInt);
|
|
stack_trace(pInt);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef PRINT_INT
|
|
ErrorF("calling card BIOS at: ");
|
|
#endif
|
|
eflags = X86_EFLAGS;
|
|
#if 0
|
|
eflags = eflags | IF_MASK;
|
|
X86_EFLAGS = X86_EFLAGS & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK);
|
|
#endif
|
|
pushw(pInt, eflags);
|
|
pushw(pInt, X86_CS);
|
|
pushw(pInt, X86_IP);
|
|
X86_CS = MEM_RW(pInt, (num << 2) + 2);
|
|
X86_IP = MEM_RW(pInt, num << 2);
|
|
#ifdef PRINT_INT
|
|
ErrorF("0x%x:%lx\n", X86_CS, X86_EIP);
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
/* Debugging stuff */
|
|
void
|
|
dump_code(xf86Int10InfoPtr pInt)
|
|
{
|
|
int i;
|
|
unsigned long lina = SEG_ADR((CARD32), X86_CS, IP);
|
|
|
|
xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, "code at 0x%8.8lx:\n", lina);
|
|
for (i=0; i<0x10; i++)
|
|
xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i));
|
|
xf86ErrorFVerb(3, "\n");
|
|
for (; i<0x20; i++)
|
|
xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i));
|
|
xf86ErrorFVerb(3, "\n");
|
|
}
|
|
|
|
void
|
|
dump_registers(xf86Int10InfoPtr pInt)
|
|
{
|
|
xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3,
|
|
"EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n",
|
|
(unsigned long)X86_EAX, (unsigned long)X86_EBX,
|
|
(unsigned long)X86_ECX, (unsigned long)X86_EDX);
|
|
xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3,
|
|
"ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n",
|
|
(unsigned long)X86_ESP, (unsigned long)X86_EBP,
|
|
(unsigned long)X86_ESI, (unsigned long)X86_EDI);
|
|
xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3,
|
|
"CS=0x%4.4x, SS=0x%4.4x,"
|
|
" DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n",
|
|
X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS);
|
|
xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3,
|
|
"EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n",
|
|
(unsigned long)X86_EIP, (unsigned long)X86_EFLAGS);
|
|
}
|
|
|
|
void
|
|
stack_trace(xf86Int10InfoPtr pInt)
|
|
{
|
|
int i = 0;
|
|
unsigned long stack = SEG_ADR((CARD32), X86_SS, SP);
|
|
unsigned long tail = (CARD32)((X86_SS << 4) + 0x1000);
|
|
|
|
if (stack >= tail) return;
|
|
|
|
xf86MsgVerb(X_INFO, 3, "stack at 0x%8.8lx:\n", stack);
|
|
for (; stack < tail; stack++) {
|
|
xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, stack));
|
|
i = (i + 1) % 0x10;
|
|
if (!i)
|
|
xf86ErrorFVerb(3, "\n");
|
|
}
|
|
if (i)
|
|
xf86ErrorFVerb(3, "\n");
|
|
}
|
|
|
|
int
|
|
port_rep_inb(xf86Int10InfoPtr pInt,
|
|
CARD16 port, CARD32 base, int d_f, CARD32 count)
|
|
{
|
|
register int inc = d_f ? -1 : 1;
|
|
CARD32 dst = base;
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" rep_insb(%#x) %d bytes at %8.8x %s\n",
|
|
port, count, base, d_f ? "up" : "down");
|
|
while (count--) {
|
|
MEM_WB(pInt, dst, x_inb(port));
|
|
dst += inc;
|
|
}
|
|
return dst - base;
|
|
}
|
|
|
|
int
|
|
port_rep_inw(xf86Int10InfoPtr pInt,
|
|
CARD16 port, CARD32 base, int d_f, CARD32 count)
|
|
{
|
|
register int inc = d_f ? -2 : 2;
|
|
CARD32 dst = base;
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" rep_insw(%#x) %d bytes at %8.8x %s\n",
|
|
port, count, base, d_f ? "up" : "down");
|
|
while (count--) {
|
|
MEM_WW(pInt, dst, x_inw(port));
|
|
dst += inc;
|
|
}
|
|
return dst - base;
|
|
}
|
|
|
|
int
|
|
port_rep_inl(xf86Int10InfoPtr pInt,
|
|
CARD16 port, CARD32 base, int d_f, CARD32 count)
|
|
{
|
|
register int inc = d_f ? -4 : 4;
|
|
CARD32 dst = base;
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" rep_insl(%#x) %d bytes at %8.8x %s\n",
|
|
port, count, base, d_f ? "up" : "down");
|
|
while (count--) {
|
|
MEM_WL(pInt, dst, x_inl(port));
|
|
dst += inc;
|
|
}
|
|
return dst - base;
|
|
}
|
|
|
|
int
|
|
port_rep_outb(xf86Int10InfoPtr pInt,
|
|
CARD16 port, CARD32 base, int d_f, CARD32 count)
|
|
{
|
|
register int inc = d_f ? -1 : 1;
|
|
CARD32 dst = base;
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" rep_outb(%#x) %d bytes at %8.8x %s\n",
|
|
port, count, base, d_f ? "up" : "down");
|
|
while (count--) {
|
|
x_outb(port, MEM_RB(pInt, dst));
|
|
dst += inc;
|
|
}
|
|
return dst - base;
|
|
}
|
|
|
|
int
|
|
port_rep_outw(xf86Int10InfoPtr pInt,
|
|
CARD16 port, CARD32 base, int d_f, CARD32 count)
|
|
{
|
|
register int inc = d_f ? -2 : 2;
|
|
CARD32 dst = base;
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" rep_outw(%#x) %d bytes at %8.8x %s\n",
|
|
port, count, base, d_f ? "up" : "down");
|
|
while (count--) {
|
|
x_outw(port, MEM_RW(pInt, dst));
|
|
dst += inc;
|
|
}
|
|
return dst - base;
|
|
}
|
|
|
|
int
|
|
port_rep_outl(xf86Int10InfoPtr pInt,
|
|
CARD16 port, CARD32 base, int d_f, CARD32 count)
|
|
{
|
|
register int inc = d_f ? -4 : 4;
|
|
CARD32 dst = base;
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" rep_outl(%#x) %d bytes at %8.8x %s\n",
|
|
port, count, base, d_f ? "up" : "down");
|
|
while (count--) {
|
|
x_outl(port, MEM_RL(pInt, dst));
|
|
dst += inc;
|
|
}
|
|
return dst - base;
|
|
}
|
|
|
|
CARD8
|
|
x_inb(CARD16 port)
|
|
{
|
|
CARD8 val;
|
|
|
|
if (port == 0x40) {
|
|
Int10Current->inb40time++;
|
|
val = (CARD8)(Int10Current->inb40time >>
|
|
((Int10Current->inb40time & 1) << 3));
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" inb(%#x) = %2.2x\n", port, val);
|
|
#ifdef __NOT_YET__
|
|
} else if (port < 0x0100) { /* Don't interfere with mainboard */
|
|
val = 0;
|
|
xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2,
|
|
"inb 0x%4.4x\n", port);
|
|
if (xf86GetVerbosity() > 3) {
|
|
dump_registers(Int10Current);
|
|
stack_trace(Int10Current);
|
|
}
|
|
#endif /* __NOT_YET__ */
|
|
} else if (!pciCfg1inb(port, &val)) {
|
|
val = inb(Int10Current->ioBase + port);
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" inb(%#x) = %2.2x\n", port, val);
|
|
}
|
|
return val;
|
|
}
|
|
|
|
CARD16
|
|
x_inw(CARD16 port)
|
|
{
|
|
CARD16 val;
|
|
|
|
if (port == 0x5c) {
|
|
struct timeval tv;
|
|
|
|
/*
|
|
* Emulate a PC98's timer. Typical resolution is 3.26 usec.
|
|
* Approximate this by dividing by 3.
|
|
*/
|
|
X_GETTIMEOFDAY(&tv);
|
|
val = (CARD16)(tv.tv_usec / 3);
|
|
} else if (!pciCfg1inw(port, &val)) {
|
|
val = inw(Int10Current->ioBase + port);
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" inw(%#x) = %4.4x\n", port, val);
|
|
}
|
|
return val;
|
|
}
|
|
|
|
void
|
|
x_outb(CARD16 port, CARD8 val)
|
|
{
|
|
if ((port == 0x43) && (val == 0)) {
|
|
struct timeval tv;
|
|
/*
|
|
* Emulate a PC's timer 0. Such timers typically have a resolution of
|
|
* some .838 usec per tick, but this can only provide 1 usec per tick.
|
|
* (Not that this matters much, given inherent emulation delays.) Use
|
|
* the bottom bit as a byte select. See inb(0x40) above.
|
|
*/
|
|
X_GETTIMEOFDAY(&tv);
|
|
Int10Current->inb40time = (CARD16)(tv.tv_usec | 1);
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" outb(%#x, %2.2x)\n", port, val);
|
|
#ifdef __NOT_YET__
|
|
} else if (port < 0x0100) { /* Don't interfere with mainboard */
|
|
xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2,
|
|
"outb 0x%4.4x,0x%2.2x\n", port, val);
|
|
if (xf86GetVerbosity() > 3) {
|
|
dump_registers(Int10Current);
|
|
stack_trace(Int10Current);
|
|
}
|
|
#endif /* __NOT_YET__ */
|
|
} else if (!pciCfg1outb(port, val)) {
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" outb(%#x, %2.2x)\n", port, val);
|
|
outb(Int10Current->ioBase + port, val);
|
|
}
|
|
}
|
|
|
|
void
|
|
x_outw(CARD16 port, CARD16 val)
|
|
{
|
|
|
|
if (!pciCfg1outw(port, val)) {
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" outw(%#x, %4.4x)\n", port, val);
|
|
outw(Int10Current->ioBase + port, val);
|
|
}
|
|
}
|
|
|
|
CARD32
|
|
x_inl(CARD16 port)
|
|
{
|
|
CARD32 val;
|
|
|
|
if (!pciCfg1in(port, &val)) {
|
|
val = inl(Int10Current->ioBase + port);
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" inl(%#x) = %8.8x\n", port, val);
|
|
}
|
|
return val;
|
|
}
|
|
|
|
void
|
|
x_outl(CARD16 port, CARD32 val)
|
|
{
|
|
if (!pciCfg1out(port, val)) {
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" outl(%#x, %8.8x)\n", port, val);
|
|
outl(Int10Current->ioBase + port, val);
|
|
}
|
|
}
|
|
|
|
CARD8
|
|
Mem_rb(CARD32 addr)
|
|
{
|
|
return (*Int10Current->mem->rb)(Int10Current, addr);
|
|
}
|
|
|
|
CARD16
|
|
Mem_rw(CARD32 addr)
|
|
{
|
|
return (*Int10Current->mem->rw)(Int10Current, addr);
|
|
}
|
|
|
|
CARD32
|
|
Mem_rl(CARD32 addr)
|
|
{
|
|
return (*Int10Current->mem->rl)(Int10Current, addr);
|
|
}
|
|
|
|
void
|
|
Mem_wb(CARD32 addr, CARD8 val)
|
|
{
|
|
(*Int10Current->mem->wb)(Int10Current, addr, val);
|
|
}
|
|
|
|
void
|
|
Mem_ww(CARD32 addr, CARD16 val)
|
|
{
|
|
(*Int10Current->mem->ww)(Int10Current, addr, val);
|
|
}
|
|
|
|
void
|
|
Mem_wl(CARD32 addr, CARD32 val)
|
|
{
|
|
(*Int10Current->mem->wl)(Int10Current, addr, val);
|
|
}
|
|
|
|
static CARD32 PciCfg1Addr = 0;
|
|
|
|
#define PCI_OFFSET(x) ((x) & 0x000000ff)
|
|
#define PCI_TAG(x) ((x) & 0xffffff00)
|
|
|
|
static struct pci_device*
|
|
pci_device_for_cfg_address (CARD32 addr)
|
|
{
|
|
struct pci_device *dev = NULL;
|
|
PCITAG tag = PCI_TAG(addr);
|
|
struct pci_slot_match slot_match = {
|
|
.domain = PCI_DOM_FROM_TAG(tag),
|
|
.bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)),
|
|
.dev = PCI_DEV_FROM_TAG(tag),
|
|
.func = PCI_FUNC_FROM_TAG(tag),
|
|
.match_data = 0
|
|
};
|
|
|
|
struct pci_device_iterator *iter =
|
|
pci_slot_match_iterator_create (&slot_match);
|
|
if (iter)
|
|
dev = pci_device_next(iter);
|
|
if (!dev) {
|
|
char buf[128]; /* enough to store "%u@%u" */
|
|
xf86FormatPciBusNumber(tag >> 16, buf);
|
|
ErrorF("Failed to find device matching %s:%u:%u\n",
|
|
buf, slot_match.dev, slot_match.func);
|
|
return NULL;
|
|
}
|
|
|
|
if (pci_device_next(iter)) {
|
|
char buf[128]; /* enough to store "%u@%u" */
|
|
xf86FormatPciBusNumber(tag >> 16, buf);
|
|
ErrorF("Multiple devices matching %s:%u:%u\n",
|
|
buf, slot_match.dev, slot_match.func);
|
|
}
|
|
|
|
return dev;
|
|
}
|
|
|
|
static int
|
|
pciCfg1in(CARD16 addr, CARD32 *val)
|
|
{
|
|
if (addr == 0xCF8) {
|
|
*val = PciCfg1Addr;
|
|
return 1;
|
|
}
|
|
if (addr == 0xCFC) {
|
|
pci_device_cfg_read_u32(pci_device_for_cfg_address(PciCfg1Addr),
|
|
val, PCI_OFFSET(PciCfg1Addr));
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" cfg_inl(%#x) = %8.8x\n", PciCfg1Addr, *val);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
pciCfg1out(CARD16 addr, CARD32 val)
|
|
{
|
|
if (addr == 0xCF8) {
|
|
PciCfg1Addr = val;
|
|
return 1;
|
|
}
|
|
if (addr == 0xCFC) {
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" cfg_outl(%#x, %8.8x)\n", PciCfg1Addr, val);
|
|
pci_device_cfg_write_u32(pci_device_for_cfg_address(PciCfg1Addr),
|
|
val, PCI_OFFSET(PciCfg1Addr));
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
pciCfg1inw(CARD16 addr, CARD16 *val)
|
|
{
|
|
int shift;
|
|
|
|
if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
|
|
shift = (addr - 0xCF8) * 8;
|
|
*val = (PciCfg1Addr >> shift) & 0xffff;
|
|
return 1;
|
|
}
|
|
if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
|
|
const unsigned offset = addr - 0xCFC;
|
|
|
|
pci_device_cfg_read_u16(pci_device_for_cfg_address(PciCfg1Addr),
|
|
val, PCI_OFFSET(PciCfg1Addr) + offset);
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" cfg_inw(%#x) = %4.4x\n", PciCfg1Addr + offset, *val);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
pciCfg1outw(CARD16 addr, CARD16 val)
|
|
{
|
|
int shift;
|
|
|
|
if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
|
|
shift = (addr - 0xCF8) * 8;
|
|
PciCfg1Addr &= ~(0xffff << shift);
|
|
PciCfg1Addr |= ((CARD32) val) << shift;
|
|
return 1;
|
|
}
|
|
if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
|
|
const unsigned offset = addr - 0xCFC;
|
|
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" cfg_outw(%#x, %4.4x)\n", PciCfg1Addr + offset, val);
|
|
pci_device_cfg_write_u16(pci_device_for_cfg_address(PciCfg1Addr),
|
|
val, PCI_OFFSET(PciCfg1Addr) + offset);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
pciCfg1inb(CARD16 addr, CARD8 *val)
|
|
{
|
|
int shift;
|
|
|
|
if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
|
|
shift = (addr - 0xCF8) * 8;
|
|
*val = (PciCfg1Addr >> shift) & 0xff;
|
|
return 1;
|
|
}
|
|
if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
|
|
const unsigned offset = addr - 0xCFC;
|
|
|
|
pci_device_cfg_read_u8(pci_device_for_cfg_address(PciCfg1Addr),
|
|
val, PCI_OFFSET(PciCfg1Addr) + offset);
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" cfg_inb(%#x) = %2.2x\n", PciCfg1Addr + offset, *val);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
pciCfg1outb(CARD16 addr, CARD8 val)
|
|
{
|
|
int shift;
|
|
|
|
if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
|
|
shift = (addr - 0xCF8) * 8;
|
|
PciCfg1Addr &= ~(0xff << shift);
|
|
PciCfg1Addr |= ((CARD32) val) << shift;
|
|
return 1;
|
|
}
|
|
if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
|
|
const unsigned offset = addr - 0xCFC;
|
|
|
|
if (PRINT_PORT && DEBUG_IO_TRACE())
|
|
ErrorF(" cfg_outb(%#x, %2.2x)\n", PciCfg1Addr + offset, val);
|
|
pci_device_cfg_write_u8(pci_device_for_cfg_address(PciCfg1Addr),
|
|
val, PCI_OFFSET(PciCfg1Addr) + offset);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
CARD8
|
|
bios_checksum(const CARD8 *start, int size)
|
|
{
|
|
CARD8 sum = 0;
|
|
|
|
while (size-- > 0)
|
|
sum += *start++;
|
|
return sum;
|
|
}
|
|
|
|
/*
|
|
* Lock/Unlock legacy VGA. Some Bioses try to be very clever and make
|
|
* an attempt to detect a legacy ISA card. If they find one they might
|
|
* act very strange: for example they might configure the card as a
|
|
* monochrome card. This might cause some drivers to choke.
|
|
* To avoid this we attempt legacy VGA by writing to all know VGA
|
|
* disable registers before we call the BIOS initialization and
|
|
* restore the original values afterwards. In beween we hold our
|
|
* breath. To get to a (possibly exising) ISA card need to disable
|
|
* our current PCI card.
|
|
*/
|
|
/*
|
|
* This is just for booting: we just want to catch pure
|
|
* legacy vga therefore we don't worry about mmio etc.
|
|
* This stuff should really go into vgaHW.c. However then
|
|
* the driver would have to load the vga-module prior to
|
|
* doing int10.
|
|
*/
|
|
void
|
|
LockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga)
|
|
{
|
|
xf86SetCurrentAccess(FALSE, xf86Screens[pInt->scrnIndex]);
|
|
vga->save_msr = inb(pInt->ioBase + 0x03CC);
|
|
vga->save_vse = inb(pInt->ioBase + 0x03C3);
|
|
#ifndef __ia64__
|
|
vga->save_46e8 = inb(pInt->ioBase + 0x46E8);
|
|
#endif
|
|
vga->save_pos102 = inb(pInt->ioBase + 0x0102);
|
|
outb(pInt->ioBase + 0x03C2, ~(CARD8)0x03 & vga->save_msr);
|
|
outb(pInt->ioBase + 0x03C3, ~(CARD8)0x01 & vga->save_vse);
|
|
#ifndef __ia64__
|
|
outb(pInt->ioBase + 0x46E8, ~(CARD8)0x08 & vga->save_46e8);
|
|
#endif
|
|
outb(pInt->ioBase + 0x0102, ~(CARD8)0x01 & vga->save_pos102);
|
|
xf86SetCurrentAccess(TRUE, xf86Screens[pInt->scrnIndex]);
|
|
}
|
|
|
|
void
|
|
UnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga)
|
|
{
|
|
xf86SetCurrentAccess(FALSE, xf86Screens[pInt->scrnIndex]);
|
|
outb(pInt->ioBase + 0x0102, vga->save_pos102);
|
|
#ifndef __ia64__
|
|
outb(pInt->ioBase + 0x46E8, vga->save_46e8);
|
|
#endif
|
|
outb(pInt->ioBase + 0x03C3, vga->save_vse);
|
|
outb(pInt->ioBase + 0x03C2, vga->save_msr);
|
|
xf86SetCurrentAccess(TRUE, xf86Screens[pInt->scrnIndex]);
|
|
}
|
|
|
|
#if defined (_PC)
|
|
static void
|
|
SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set)
|
|
{
|
|
int pagesize = getpagesize();
|
|
unsigned char* base = xf86MapVidMem(pInt->scrnIndex,
|
|
VIDMEM_MMIO, 0, pagesize);
|
|
int i;
|
|
|
|
if (set) {
|
|
for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++)
|
|
MEM_WW(pInt, i, *(base + i));
|
|
} else {
|
|
for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++)
|
|
*(base + i) = MEM_RW(pInt, i);
|
|
}
|
|
|
|
xf86UnMapVidMem(pInt->scrnIndex,base,pagesize);
|
|
}
|
|
|
|
void
|
|
xf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save)
|
|
{
|
|
int pagesize = getpagesize();
|
|
unsigned char* base;
|
|
int i;
|
|
|
|
if (!xf86IsEntityPrimary(pInt->entityIndex)
|
|
|| (!save && !pInt->BIOSScratch))
|
|
return;
|
|
|
|
base = xf86MapVidMem(pInt->scrnIndex, VIDMEM_MMIO, 0, pagesize);
|
|
base += BIOS_SCRATCH_OFF;
|
|
if (save) {
|
|
if ((pInt->BIOSScratch
|
|
= xnfalloc(BIOS_SCRATCH_LEN)))
|
|
for (i = 0; i < BIOS_SCRATCH_LEN; i++)
|
|
*(((char*)pInt->BIOSScratch + i)) = *(base + i);
|
|
} else {
|
|
if (pInt->BIOSScratch) {
|
|
for (i = 0; i < BIOS_SCRATCH_LEN; i++)
|
|
*(base + i) = *(pInt->BIOSScratch + i);
|
|
xfree(pInt->BIOSScratch);
|
|
pInt->BIOSScratch = NULL;
|
|
}
|
|
}
|
|
|
|
xf86UnMapVidMem(pInt->scrnIndex,base - BIOS_SCRATCH_OFF ,pagesize);
|
|
}
|
|
#endif
|
|
|
|
xf86Int10InfoPtr
|
|
xf86InitInt10(int entityIndex)
|
|
{
|
|
return xf86ExtendedInitInt10(entityIndex, 0);
|
|
}
|