105b261ecSmrg/* 205b261ecSmrg * XFree86 int10 module 305b261ecSmrg * execute BIOS int 10h calls in x86 real mode environment 405b261ecSmrg * Copyright 1999 Egbert Eich 505b261ecSmrg * 605b261ecSmrg * Part of this code was inspired by the VBIOS POSTing code in DOSEMU 705b261ecSmrg * developed by the "DOSEMU-Development-Team" 805b261ecSmrg */ 905b261ecSmrg 1005b261ecSmrg/* 1105b261ecSmrg * To debug port accesses define PRINT_PORT to 1. 1205b261ecSmrg * Note! You also have to comment out ioperm() 1305b261ecSmrg * in xf86EnableIO(). Otherwise we won't trap 1405b261ecSmrg * on PIO. 1505b261ecSmrg */ 1605b261ecSmrg 1705b261ecSmrg#ifdef HAVE_XORG_CONFIG_H 1805b261ecSmrg#include <xorg-config.h> 1905b261ecSmrg#endif 2005b261ecSmrg 2105b261ecSmrg#define PRINT_PORT 0 2205b261ecSmrg 2305b261ecSmrg#include <unistd.h> 2405b261ecSmrg 2505b261ecSmrg#include <X11/Xos.h> 2605b261ecSmrg#include "xf86.h" 2705b261ecSmrg#include "xf86_OSproc.h" 2805b261ecSmrg#include "compiler.h" 2905b261ecSmrg#define _INT10_PRIVATE 3005b261ecSmrg#include "int10Defines.h" 3105b261ecSmrg#include "xf86int10.h" 324642e01fSmrg#include "Pci.h" 3305b261ecSmrg#ifdef _X86EMU 3405b261ecSmrg#include "x86emu/x86emui.h" 354642e01fSmrg#else 364642e01fSmrg#define DEBUG_IO_TRACE() 0 3705b261ecSmrg#endif 384642e01fSmrg#include <pciaccess.h> 3905b261ecSmrg 40f7df2e56Smrgstatic int pciCfg1in(uint16_t addr, uint32_t *val); 41f7df2e56Smrgstatic int pciCfg1out(uint16_t addr, uint32_t val); 42f7df2e56Smrgstatic int pciCfg1inw(uint16_t addr, uint16_t *val); 43f7df2e56Smrgstatic int pciCfg1outw(uint16_t addr, uint16_t val); 44f7df2e56Smrgstatic int pciCfg1inb(uint16_t addr, uint8_t *val); 45f7df2e56Smrgstatic int pciCfg1outb(uint16_t addr, uint8_t val); 46f7df2e56Smrg 4705b261ecSmrg#if defined (_PC) 4805b261ecSmrgstatic void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set); 4905b261ecSmrg#endif 5005b261ecSmrg 5105b261ecSmrg#define REG pInt 5205b261ecSmrg 5305b261ecSmrgint 5405b261ecSmrgsetup_int(xf86Int10InfoPtr pInt) 5505b261ecSmrg{ 5605b261ecSmrg if (pInt != Int10Current) { 57f7df2e56Smrg if (!MapCurrentInt10(pInt)) 58f7df2e56Smrg return -1; 59f7df2e56Smrg Int10Current = pInt; 60f7df2e56Smrg } 61f7df2e56Smrg X86_EAX = (uint32_t) pInt->ax; 62f7df2e56Smrg X86_EBX = (uint32_t) pInt->bx; 63f7df2e56Smrg X86_ECX = (uint32_t) pInt->cx; 64f7df2e56Smrg X86_EDX = (uint32_t) pInt->dx; 65f7df2e56Smrg X86_ESI = (uint32_t) pInt->si; 66f7df2e56Smrg X86_EDI = (uint32_t) pInt->di; 67f7df2e56Smrg X86_EBP = (uint32_t) pInt->bp; 68f7df2e56Smrg X86_ESP = 0x1000; 69f7df2e56Smrg X86_SS = pInt->stackseg >> 4; 70f7df2e56Smrg X86_EIP = 0x0600; 71f7df2e56Smrg X86_CS = 0x0; /* address of 'hlt' */ 72f7df2e56Smrg X86_DS = 0x40; /* standard pc ds */ 7305b261ecSmrg X86_ES = pInt->es; 7405b261ecSmrg X86_FS = 0; 7505b261ecSmrg X86_GS = 0; 7605b261ecSmrg X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK; 7705b261ecSmrg#if defined (_PC) 7805b261ecSmrg if (pInt->Flags & SET_BIOS_SCRATCH) 79f7df2e56Smrg SetResetBIOSVars(pInt, TRUE); 8005b261ecSmrg#endif 8165b04b38Smrg OsBlockSignals(); 8265b04b38Smrg return 0; 8305b261ecSmrg} 8405b261ecSmrg 8505b261ecSmrgvoid 8605b261ecSmrgfinish_int(xf86Int10InfoPtr pInt, int sig) 8705b261ecSmrg{ 8865b04b38Smrg OsReleaseSignals(); 89f7df2e56Smrg pInt->ax = (uint32_t) X86_EAX; 90f7df2e56Smrg pInt->bx = (uint32_t) X86_EBX; 91f7df2e56Smrg pInt->cx = (uint32_t) X86_ECX; 92f7df2e56Smrg pInt->dx = (uint32_t) X86_EDX; 93f7df2e56Smrg pInt->si = (uint32_t) X86_ESI; 94f7df2e56Smrg pInt->di = (uint32_t) X86_EDI; 95f7df2e56Smrg pInt->es = (uint16_t) X86_ES; 96f7df2e56Smrg pInt->bp = (uint32_t) X86_EBP; 97f7df2e56Smrg pInt->flags = (uint32_t) X86_FLAGS; 9805b261ecSmrg#if defined (_PC) 9905b261ecSmrg if (pInt->Flags & RESTORE_BIOS_SCRATCH) 100f7df2e56Smrg SetResetBIOSVars(pInt, FALSE); 10105b261ecSmrg#endif 10205b261ecSmrg} 10305b261ecSmrg 10405b261ecSmrg/* general software interrupt handler */ 105f7df2e56Smrguint32_t 106f7df2e56SmrggetIntVect(xf86Int10InfoPtr pInt, int num) 10705b261ecSmrg{ 10805b261ecSmrg return MEM_RW(pInt, num << 2) + (MEM_RW(pInt, (num << 2) + 2) << 4); 10905b261ecSmrg} 11005b261ecSmrg 11105b261ecSmrgvoid 112f7df2e56Smrgpushw(xf86Int10InfoPtr pInt, uint16_t val) 11305b261ecSmrg{ 11405b261ecSmrg X86_ESP -= 2; 115f7df2e56Smrg MEM_WW(pInt, ((uint32_t) X86_SS << 4) + X86_SP, val); 11605b261ecSmrg} 11705b261ecSmrg 11805b261ecSmrgint 11905b261ecSmrgrun_bios_int(int num, xf86Int10InfoPtr pInt) 12005b261ecSmrg{ 121f7df2e56Smrg uint32_t eflags; 122f7df2e56Smrg 12305b261ecSmrg#ifndef _PC 12405b261ecSmrg /* check if bios vector is initialized */ 125f7df2e56Smrg if (MEM_RW(pInt, (num << 2) + 2) == (SYS_BIOS >> 4)) { /* SYS_BIOS_SEG ? */ 126f7df2e56Smrg 127f7df2e56Smrg if (num == 21 && X86_AH == 0x4e) { 128f7df2e56Smrg xf86DrvMsg(pInt->pScrn->scrnIndex, X_NOTICE, 129f7df2e56Smrg "Failing Find-Matching-File on non-PC" 130f7df2e56Smrg " (int 21, func 4e)\n"); 131f7df2e56Smrg X86_AX = 2; 132f7df2e56Smrg SET_FLAG(F_CF); 133f7df2e56Smrg return 1; 134f7df2e56Smrg } 135f7df2e56Smrg else { 136f7df2e56Smrg xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2, 137f7df2e56Smrg "Ignoring int 0x%02x call\n", num); 138f7df2e56Smrg if (xf86GetVerbosity() > 3) { 139f7df2e56Smrg dump_registers(pInt); 140f7df2e56Smrg stack_trace(pInt); 141f7df2e56Smrg } 142f7df2e56Smrg return 1; 143f7df2e56Smrg } 14405b261ecSmrg } 14505b261ecSmrg#endif 14605b261ecSmrg#ifdef PRINT_INT 14705b261ecSmrg ErrorF("calling card BIOS at: "); 14805b261ecSmrg#endif 14905b261ecSmrg eflags = X86_EFLAGS; 15005b261ecSmrg#if 0 15105b261ecSmrg eflags = eflags | IF_MASK; 152f7df2e56Smrg X86_EFLAGS = X86_EFLAGS & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK); 15305b261ecSmrg#endif 15405b261ecSmrg pushw(pInt, eflags); 15505b261ecSmrg pushw(pInt, X86_CS); 15605b261ecSmrg pushw(pInt, X86_IP); 15705b261ecSmrg X86_CS = MEM_RW(pInt, (num << 2) + 2); 158f7df2e56Smrg X86_IP = MEM_RW(pInt, num << 2); 15905b261ecSmrg#ifdef PRINT_INT 16005b261ecSmrg ErrorF("0x%x:%lx\n", X86_CS, X86_EIP); 16105b261ecSmrg#endif 16205b261ecSmrg return 1; 16305b261ecSmrg} 16405b261ecSmrg 16505b261ecSmrg/* Debugging stuff */ 16605b261ecSmrgvoid 16705b261ecSmrgdump_code(xf86Int10InfoPtr pInt) 16805b261ecSmrg{ 16905b261ecSmrg int i; 170f7df2e56Smrg uint32_t lina = SEG_ADR((uint32_t), X86_CS, IP); 17105b261ecSmrg 172f7df2e56Smrg xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, "code at 0x%8.8" PRIx32 ":\n", 173f7df2e56Smrg (unsigned) lina); 174f7df2e56Smrg for (i = 0; i < 0x10; i++) 175f7df2e56Smrg xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); 17605b261ecSmrg xf86ErrorFVerb(3, "\n"); 177f7df2e56Smrg for (; i < 0x20; i++) 178f7df2e56Smrg xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); 17905b261ecSmrg xf86ErrorFVerb(3, "\n"); 18005b261ecSmrg} 18105b261ecSmrg 18205b261ecSmrgvoid 18305b261ecSmrgdump_registers(xf86Int10InfoPtr pInt) 18405b261ecSmrg{ 185f7df2e56Smrg xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, 186f7df2e56Smrg "EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n", 187f7df2e56Smrg (unsigned long) X86_EAX, (unsigned long) X86_EBX, 188f7df2e56Smrg (unsigned long) X86_ECX, (unsigned long) X86_EDX); 189f7df2e56Smrg xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, 190f7df2e56Smrg "ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n", 191f7df2e56Smrg (unsigned long) X86_ESP, (unsigned long) X86_EBP, 192f7df2e56Smrg (unsigned long) X86_ESI, (unsigned long) X86_EDI); 193f7df2e56Smrg xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, 194f7df2e56Smrg "CS=0x%4.4x, SS=0x%4.4x," 195f7df2e56Smrg " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n", 196f7df2e56Smrg X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS); 197f7df2e56Smrg xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, 198f7df2e56Smrg "EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n", 199f7df2e56Smrg (unsigned long) X86_EIP, (unsigned long) X86_EFLAGS); 20005b261ecSmrg} 20105b261ecSmrg 20205b261ecSmrgvoid 20305b261ecSmrgstack_trace(xf86Int10InfoPtr pInt) 20405b261ecSmrg{ 20505b261ecSmrg int i = 0; 206f7df2e56Smrg unsigned long stack = SEG_ADR((uint32_t), X86_SS, SP); 207f7df2e56Smrg unsigned long tail = (uint32_t) ((X86_SS << 4) + 0x1000); 20805b261ecSmrg 209f7df2e56Smrg if (stack >= tail) 210f7df2e56Smrg return; 21105b261ecSmrg 21205b261ecSmrg xf86MsgVerb(X_INFO, 3, "stack at 0x%8.8lx:\n", stack); 21305b261ecSmrg for (; stack < tail; stack++) { 214f7df2e56Smrg xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, stack)); 215f7df2e56Smrg i = (i + 1) % 0x10; 216f7df2e56Smrg if (!i) 217f7df2e56Smrg xf86ErrorFVerb(3, "\n"); 21805b261ecSmrg } 21905b261ecSmrg if (i) 220f7df2e56Smrg xf86ErrorFVerb(3, "\n"); 22105b261ecSmrg} 22205b261ecSmrg 22305b261ecSmrgint 22405b261ecSmrgport_rep_inb(xf86Int10InfoPtr pInt, 225f7df2e56Smrg uint16_t port, uint32_t base, int d_f, uint32_t count) 22605b261ecSmrg{ 22705b261ecSmrg register int inc = d_f ? -1 : 1; 228f7df2e56Smrg uint32_t dst = base; 229f7df2e56Smrg 23005b261ecSmrg if (PRINT_PORT && DEBUG_IO_TRACE()) 231f7df2e56Smrg ErrorF(" rep_insb(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", 232f7df2e56Smrg port, (unsigned) count, (unsigned) base, d_f ? "up" : "down"); 23305b261ecSmrg while (count--) { 234f7df2e56Smrg MEM_WB(pInt, dst, x_inb(port)); 235f7df2e56Smrg dst += inc; 23605b261ecSmrg } 23705b261ecSmrg return dst - base; 23805b261ecSmrg} 23905b261ecSmrg 24005b261ecSmrgint 24105b261ecSmrgport_rep_inw(xf86Int10InfoPtr pInt, 242f7df2e56Smrg uint16_t port, uint32_t base, int d_f, uint32_t count) 24305b261ecSmrg{ 24405b261ecSmrg register int inc = d_f ? -2 : 2; 245f7df2e56Smrg uint32_t dst = base; 246f7df2e56Smrg 24705b261ecSmrg if (PRINT_PORT && DEBUG_IO_TRACE()) 248f7df2e56Smrg ErrorF(" rep_insw(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", 249f7df2e56Smrg port, (unsigned) count, (unsigned) base, d_f ? "up" : "down"); 25005b261ecSmrg while (count--) { 251f7df2e56Smrg MEM_WW(pInt, dst, x_inw(port)); 252f7df2e56Smrg dst += inc; 25305b261ecSmrg } 25405b261ecSmrg return dst - base; 25505b261ecSmrg} 25605b261ecSmrg 25705b261ecSmrgint 25805b261ecSmrgport_rep_inl(xf86Int10InfoPtr pInt, 259f7df2e56Smrg uint16_t port, uint32_t base, int d_f, uint32_t count) 26005b261ecSmrg{ 26105b261ecSmrg register int inc = d_f ? -4 : 4; 262f7df2e56Smrg uint32_t dst = base; 263f7df2e56Smrg 26405b261ecSmrg if (PRINT_PORT && DEBUG_IO_TRACE()) 265f7df2e56Smrg ErrorF(" rep_insl(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", 266f7df2e56Smrg port, (unsigned) count, (unsigned) base, d_f ? "up" : "down"); 26705b261ecSmrg while (count--) { 268f7df2e56Smrg MEM_WL(pInt, dst, x_inl(port)); 269f7df2e56Smrg dst += inc; 27005b261ecSmrg } 27105b261ecSmrg return dst - base; 27205b261ecSmrg} 27305b261ecSmrg 27405b261ecSmrgint 27505b261ecSmrgport_rep_outb(xf86Int10InfoPtr pInt, 276f7df2e56Smrg uint16_t port, uint32_t base, int d_f, uint32_t count) 27705b261ecSmrg{ 27805b261ecSmrg register int inc = d_f ? -1 : 1; 279f7df2e56Smrg uint32_t dst = base; 280f7df2e56Smrg 28105b261ecSmrg if (PRINT_PORT && DEBUG_IO_TRACE()) 282f7df2e56Smrg ErrorF(" rep_outb(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", 283f7df2e56Smrg port, (unsigned) count, (unsigned) base, d_f ? "up" : "down"); 28405b261ecSmrg while (count--) { 285f7df2e56Smrg x_outb(port, MEM_RB(pInt, dst)); 286f7df2e56Smrg dst += inc; 28705b261ecSmrg } 28805b261ecSmrg return dst - base; 28905b261ecSmrg} 29005b261ecSmrg 29105b261ecSmrgint 29205b261ecSmrgport_rep_outw(xf86Int10InfoPtr pInt, 293f7df2e56Smrg uint16_t port, uint32_t base, int d_f, uint32_t count) 29405b261ecSmrg{ 29505b261ecSmrg register int inc = d_f ? -2 : 2; 296f7df2e56Smrg uint32_t dst = base; 297f7df2e56Smrg 29805b261ecSmrg if (PRINT_PORT && DEBUG_IO_TRACE()) 299f7df2e56Smrg ErrorF(" rep_outw(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", 300f7df2e56Smrg port, (unsigned) count, (unsigned) base, d_f ? "up" : "down"); 30105b261ecSmrg while (count--) { 302f7df2e56Smrg x_outw(port, MEM_RW(pInt, dst)); 303f7df2e56Smrg dst += inc; 30405b261ecSmrg } 30505b261ecSmrg return dst - base; 30605b261ecSmrg} 30705b261ecSmrg 30805b261ecSmrgint 30905b261ecSmrgport_rep_outl(xf86Int10InfoPtr pInt, 310f7df2e56Smrg uint16_t port, uint32_t base, int d_f, uint32_t count) 31105b261ecSmrg{ 31205b261ecSmrg register int inc = d_f ? -4 : 4; 313f7df2e56Smrg uint32_t dst = base; 314f7df2e56Smrg 31505b261ecSmrg if (PRINT_PORT && DEBUG_IO_TRACE()) 316f7df2e56Smrg ErrorF(" rep_outl(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", 317f7df2e56Smrg port, (unsigned) count, (unsigned) base, d_f ? "up" : "down"); 31805b261ecSmrg while (count--) { 319f7df2e56Smrg x_outl(port, MEM_RL(pInt, dst)); 320f7df2e56Smrg dst += inc; 32105b261ecSmrg } 32205b261ecSmrg return dst - base; 32305b261ecSmrg} 32405b261ecSmrg 325f7df2e56Smrguint8_t 326f7df2e56Smrgx_inb(uint16_t port) 32705b261ecSmrg{ 328f7df2e56Smrg uint8_t val; 32905b261ecSmrg 33005b261ecSmrg if (port == 0x40) { 331f7df2e56Smrg Int10Current->inb40time++; 332f7df2e56Smrg val = (uint8_t) (Int10Current->inb40time >> 333f7df2e56Smrg ((Int10Current->inb40time & 1) << 3)); 334f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 335f7df2e56Smrg ErrorF(" inb(%#x) = %2.2x\n", port, val); 33605b261ecSmrg#ifdef __NOT_YET__ 337f7df2e56Smrg } 338f7df2e56Smrg else if (port < 0x0100) { /* Don't interfere with mainboard */ 339f7df2e56Smrg val = 0; 340f7df2e56Smrg xf86DrvMsgVerb(Int10Current->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2, 341f7df2e56Smrg "inb 0x%4.4x\n", port); 342f7df2e56Smrg if (xf86GetVerbosity() > 3) { 343f7df2e56Smrg dump_registers(Int10Current); 344f7df2e56Smrg stack_trace(Int10Current); 345f7df2e56Smrg } 346f7df2e56Smrg#endif /* __NOT_YET__ */ 347f7df2e56Smrg } 348f7df2e56Smrg else if (!pciCfg1inb(port, &val)) { 349f7df2e56Smrg val = pci_io_read8(Int10Current->io, port); 350f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 351f7df2e56Smrg ErrorF(" inb(%#x) = %2.2x\n", port, val); 35205b261ecSmrg } 35305b261ecSmrg return val; 35405b261ecSmrg} 35505b261ecSmrg 356f7df2e56Smrguint16_t 357f7df2e56Smrgx_inw(uint16_t port) 35805b261ecSmrg{ 359f7df2e56Smrg uint16_t val; 36005b261ecSmrg 36105b261ecSmrg if (port == 0x5c) { 362f7df2e56Smrg struct timeval tv; 363f7df2e56Smrg 364f7df2e56Smrg /* 365f7df2e56Smrg * Emulate a PC's timer. Typical resolution is 3.26 usec. 366f7df2e56Smrg * Approximate this by dividing by 3. 367f7df2e56Smrg */ 368f7df2e56Smrg X_GETTIMEOFDAY(&tv); 369f7df2e56Smrg val = (uint16_t) (tv.tv_usec / 3); 370f7df2e56Smrg } 371f7df2e56Smrg else if (!pciCfg1inw(port, &val)) { 372f7df2e56Smrg val = pci_io_read16(Int10Current->io, port); 373f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 374f7df2e56Smrg ErrorF(" inw(%#x) = %4.4x\n", port, val); 37505b261ecSmrg } 37605b261ecSmrg return val; 37705b261ecSmrg} 37805b261ecSmrg 37905b261ecSmrgvoid 380f7df2e56Smrgx_outb(uint16_t port, uint8_t val) 38105b261ecSmrg{ 38205b261ecSmrg if ((port == 0x43) && (val == 0)) { 383f7df2e56Smrg struct timeval tv; 384f7df2e56Smrg 385f7df2e56Smrg /* 386f7df2e56Smrg * Emulate a PC's timer 0. Such timers typically have a resolution of 387f7df2e56Smrg * some .838 usec per tick, but this can only provide 1 usec per tick. 388f7df2e56Smrg * (Not that this matters much, given inherent emulation delays.) Use 389f7df2e56Smrg * the bottom bit as a byte select. See inb(0x40) above. 390f7df2e56Smrg */ 391f7df2e56Smrg X_GETTIMEOFDAY(&tv); 392f7df2e56Smrg Int10Current->inb40time = (uint16_t) (tv.tv_usec | 1); 393f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 394f7df2e56Smrg ErrorF(" outb(%#x, %2.2x)\n", port, val); 39505b261ecSmrg#ifdef __NOT_YET__ 396f7df2e56Smrg } 397f7df2e56Smrg else if (port < 0x0100) { /* Don't interfere with mainboard */ 398f7df2e56Smrg xf86DrvMsgVerb(Int10Current->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2, 399f7df2e56Smrg "outb 0x%4.4x,0x%2.2x\n", port, val); 400f7df2e56Smrg if (xf86GetVerbosity() > 3) { 401f7df2e56Smrg dump_registers(Int10Current); 402f7df2e56Smrg stack_trace(Int10Current); 403f7df2e56Smrg } 404f7df2e56Smrg#endif /* __NOT_YET__ */ 405f7df2e56Smrg } 406f7df2e56Smrg else if (!pciCfg1outb(port, val)) { 407f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 408f7df2e56Smrg ErrorF(" outb(%#x, %2.2x)\n", port, val); 409f7df2e56Smrg pci_io_write8(Int10Current->io, port, val); 41005b261ecSmrg } 41105b261ecSmrg} 41205b261ecSmrg 41305b261ecSmrgvoid 414f7df2e56Smrgx_outw(uint16_t port, uint16_t val) 41505b261ecSmrg{ 41605b261ecSmrg 41705b261ecSmrg if (!pciCfg1outw(port, val)) { 418f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 419f7df2e56Smrg ErrorF(" outw(%#x, %4.4x)\n", port, val); 420f7df2e56Smrg pci_io_write16(Int10Current->io, port, val); 42105b261ecSmrg } 42205b261ecSmrg} 42305b261ecSmrg 424f7df2e56Smrguint32_t 425f7df2e56Smrgx_inl(uint16_t port) 42605b261ecSmrg{ 427f7df2e56Smrg uint32_t val; 42805b261ecSmrg 42905b261ecSmrg if (!pciCfg1in(port, &val)) { 430f7df2e56Smrg val = pci_io_read32(Int10Current->io, port); 431f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 432f7df2e56Smrg ErrorF(" inl(%#x) = %8.8" PRIx32 "\n", port, (unsigned) val); 43305b261ecSmrg } 43405b261ecSmrg return val; 43505b261ecSmrg} 43605b261ecSmrg 43705b261ecSmrgvoid 438f7df2e56Smrgx_outl(uint16_t port, uint32_t val) 43905b261ecSmrg{ 44005b261ecSmrg if (!pciCfg1out(port, val)) { 441f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 442f7df2e56Smrg ErrorF(" outl(%#x, %8.8" PRIx32 ")\n", port, (unsigned) val); 443f7df2e56Smrg pci_io_write32(Int10Current->io, port, val); 44405b261ecSmrg } 44505b261ecSmrg} 44605b261ecSmrg 447f7df2e56Smrguint8_t 448f7df2e56SmrgMem_rb(uint32_t addr) 44905b261ecSmrg{ 450f7df2e56Smrg return (*Int10Current->mem->rb) (Int10Current, addr); 45105b261ecSmrg} 45205b261ecSmrg 453f7df2e56Smrguint16_t 454f7df2e56SmrgMem_rw(uint32_t addr) 45505b261ecSmrg{ 456f7df2e56Smrg return (*Int10Current->mem->rw) (Int10Current, addr); 45705b261ecSmrg} 45805b261ecSmrg 459f7df2e56Smrguint32_t 460f7df2e56SmrgMem_rl(uint32_t addr) 46105b261ecSmrg{ 462f7df2e56Smrg return (*Int10Current->mem->rl) (Int10Current, addr); 46305b261ecSmrg} 46405b261ecSmrg 46505b261ecSmrgvoid 466f7df2e56SmrgMem_wb(uint32_t addr, uint8_t val) 46705b261ecSmrg{ 468f7df2e56Smrg (*Int10Current->mem->wb) (Int10Current, addr, val); 46905b261ecSmrg} 47005b261ecSmrg 47105b261ecSmrgvoid 472f7df2e56SmrgMem_ww(uint32_t addr, uint16_t val) 47305b261ecSmrg{ 474f7df2e56Smrg (*Int10Current->mem->ww) (Int10Current, addr, val); 47505b261ecSmrg} 47605b261ecSmrg 47705b261ecSmrgvoid 478f7df2e56SmrgMem_wl(uint32_t addr, uint32_t val) 47905b261ecSmrg{ 480f7df2e56Smrg (*Int10Current->mem->wl) (Int10Current, addr, val); 48105b261ecSmrg} 48205b261ecSmrg 483f7df2e56Smrgstatic uint32_t PciCfg1Addr = 0; 48405b261ecSmrg 48565b04b38Smrg#define PCI_DOM_FROM_TAG(tag) (((tag) >> 24) & (PCI_DOM_MASK)) 48665b04b38Smrg#define PCI_BUS_FROM_TAG(tag) (((tag) >> 16) & (PCI_DOMBUS_MASK)) 48765b04b38Smrg#define PCI_DEV_FROM_TAG(tag) (((tag) & 0x0000f800u) >> 11) 48865b04b38Smrg#define PCI_FUNC_FROM_TAG(tag) (((tag) & 0x00000700u) >> 8) 48965b04b38Smrg 4904642e01fSmrg#define PCI_OFFSET(x) ((x) & 0x000000ff) 4914642e01fSmrg#define PCI_TAG(x) ((x) & 0x7fffff00) 4924642e01fSmrg 493f7df2e56Smrgstatic struct pci_device * 494f7df2e56Smrgpci_device_for_cfg_address(uint32_t addr) 4954642e01fSmrg{ 496f7df2e56Smrg struct pci_device *dev = NULL; 497f7df2e56Smrg uint32_t tag = PCI_TAG(addr); 4984642e01fSmrg 499f7df2e56Smrg struct pci_slot_match slot_match = { 500f7df2e56Smrg .domain = PCI_DOM_FROM_TAG(tag), 501f7df2e56Smrg .bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)), 502f7df2e56Smrg .dev = PCI_DEV_FROM_TAG(tag), 503f7df2e56Smrg .func = PCI_FUNC_FROM_TAG(tag), 504f7df2e56Smrg .match_data = 0 505f7df2e56Smrg }; 5064642e01fSmrg 507f7df2e56Smrg struct pci_device_iterator *iter = 508f7df2e56Smrg pci_slot_match_iterator_create(&slot_match); 5094642e01fSmrg 510f7df2e56Smrg if (iter) 511f7df2e56Smrg dev = pci_device_next(iter); 5124642e01fSmrg 513f7df2e56Smrg pci_iterator_destroy(iter); 514f7df2e56Smrg 515f7df2e56Smrg return dev; 5164642e01fSmrg} 51705b261ecSmrg 51805b261ecSmrgstatic int 519f7df2e56SmrgpciCfg1in(uint16_t addr, uint32_t *val) 52005b261ecSmrg{ 52105b261ecSmrg if (addr == 0xCF8) { 522f7df2e56Smrg *val = PciCfg1Addr; 523f7df2e56Smrg return 1; 52405b261ecSmrg } 52505b261ecSmrg if (addr == 0xCFC) { 526f7df2e56Smrg pci_device_cfg_read_u32(pci_device_for_cfg_address(PciCfg1Addr), 527f7df2e56Smrg /* 528f7df2e56Smrg * XXXMRG 529f7df2e56Smrg * this one is OK - CARD32 is "long" for 32 bit 530f7df2e56Smrg * and "int" for 64 bit 531f7df2e56Smrg */ 532f7df2e56Smrg (uint32_t *) val, PCI_OFFSET(PciCfg1Addr)); 533f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 534f7df2e56Smrg ErrorF(" cfg_inl(%#" PRIx32 ") = %8.8" PRIx32 "\n", (unsigned) PciCfg1Addr, 535f7df2e56Smrg (unsigned) *val); 536f7df2e56Smrg return 1; 53705b261ecSmrg } 53805b261ecSmrg return 0; 53905b261ecSmrg} 54005b261ecSmrg 54105b261ecSmrgstatic int 542f7df2e56SmrgpciCfg1out(uint16_t addr, uint32_t val) 54305b261ecSmrg{ 54405b261ecSmrg if (addr == 0xCF8) { 545f7df2e56Smrg PciCfg1Addr = val; 546f7df2e56Smrg return 1; 54705b261ecSmrg } 54805b261ecSmrg if (addr == 0xCFC) { 549f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 550f7df2e56Smrg ErrorF(" cfg_outl(%#" PRIx32 ", %8.8" PRIx32 ")\n", (unsigned) PciCfg1Addr, 551f7df2e56Smrg (unsigned) val); 552f7df2e56Smrg pci_device_cfg_write_u32(pci_device_for_cfg_address(PciCfg1Addr), val, 553f7df2e56Smrg PCI_OFFSET(PciCfg1Addr)); 554f7df2e56Smrg return 1; 55505b261ecSmrg } 55605b261ecSmrg return 0; 55705b261ecSmrg} 55805b261ecSmrg 55905b261ecSmrgstatic int 560f7df2e56SmrgpciCfg1inw(uint16_t addr, uint16_t *val) 56105b261ecSmrg{ 5624642e01fSmrg int shift; 56305b261ecSmrg 56405b261ecSmrg if ((addr >= 0xCF8) && (addr <= 0xCFB)) { 565f7df2e56Smrg shift = (addr - 0xCF8) * 8; 566f7df2e56Smrg *val = (PciCfg1Addr >> shift) & 0xffff; 567f7df2e56Smrg return 1; 56805b261ecSmrg } 56905b261ecSmrg if ((addr >= 0xCFC) && (addr <= 0xCFF)) { 570f7df2e56Smrg const unsigned offset = addr - 0xCFC; 571f7df2e56Smrg 572f7df2e56Smrg pci_device_cfg_read_u16(pci_device_for_cfg_address(PciCfg1Addr), 573f7df2e56Smrg val, PCI_OFFSET(PciCfg1Addr) + offset); 574f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 575f7df2e56Smrg ErrorF(" cfg_inw(%#" PRIx32 ") = %4.4x\n", (unsigned) (PciCfg1Addr + offset), 576f7df2e56Smrg (unsigned) *val); 577f7df2e56Smrg return 1; 57805b261ecSmrg } 57905b261ecSmrg return 0; 58005b261ecSmrg} 58105b261ecSmrg 58205b261ecSmrgstatic int 583f7df2e56SmrgpciCfg1outw(uint16_t addr, uint16_t val) 58405b261ecSmrg{ 5854642e01fSmrg int shift; 58605b261ecSmrg 58705b261ecSmrg if ((addr >= 0xCF8) && (addr <= 0xCFB)) { 588f7df2e56Smrg shift = (addr - 0xCF8) * 8; 589f7df2e56Smrg PciCfg1Addr &= ~(0xffff << shift); 590f7df2e56Smrg PciCfg1Addr |= ((uint32_t) val) << shift; 591f7df2e56Smrg return 1; 59205b261ecSmrg } 59305b261ecSmrg if ((addr >= 0xCFC) && (addr <= 0xCFF)) { 594f7df2e56Smrg const unsigned offset = addr - 0xCFC; 595f7df2e56Smrg 596f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 597f7df2e56Smrg ErrorF(" cfg_outw(%#" PRIx32 ", %4.4x)\n", (unsigned) (PciCfg1Addr + offset), 598f7df2e56Smrg (unsigned) val); 599f7df2e56Smrg pci_device_cfg_write_u16(pci_device_for_cfg_address(PciCfg1Addr), val, 600f7df2e56Smrg PCI_OFFSET(PciCfg1Addr) + offset); 601f7df2e56Smrg return 1; 60205b261ecSmrg } 60305b261ecSmrg return 0; 60405b261ecSmrg} 60505b261ecSmrg 60605b261ecSmrgstatic int 607f7df2e56SmrgpciCfg1inb(uint16_t addr, uint8_t *val) 60805b261ecSmrg{ 6094642e01fSmrg int shift; 61005b261ecSmrg 61105b261ecSmrg if ((addr >= 0xCF8) && (addr <= 0xCFB)) { 612f7df2e56Smrg shift = (addr - 0xCF8) * 8; 613f7df2e56Smrg *val = (PciCfg1Addr >> shift) & 0xff; 614f7df2e56Smrg return 1; 61505b261ecSmrg } 61605b261ecSmrg if ((addr >= 0xCFC) && (addr <= 0xCFF)) { 617f7df2e56Smrg const unsigned offset = addr - 0xCFC; 618f7df2e56Smrg 619f7df2e56Smrg pci_device_cfg_read_u8(pci_device_for_cfg_address(PciCfg1Addr), 620f7df2e56Smrg val, PCI_OFFSET(PciCfg1Addr) + offset); 621f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 622f7df2e56Smrg ErrorF(" cfg_inb(%#" PRIx32 ") = %2.2x\n", (unsigned) (PciCfg1Addr + offset), 623f7df2e56Smrg (unsigned) *val); 624f7df2e56Smrg return 1; 62505b261ecSmrg } 62605b261ecSmrg return 0; 62705b261ecSmrg} 62805b261ecSmrg 62905b261ecSmrgstatic int 630f7df2e56SmrgpciCfg1outb(uint16_t addr, uint8_t val) 63105b261ecSmrg{ 6324642e01fSmrg int shift; 63305b261ecSmrg 63405b261ecSmrg if ((addr >= 0xCF8) && (addr <= 0xCFB)) { 635f7df2e56Smrg shift = (addr - 0xCF8) * 8; 636f7df2e56Smrg PciCfg1Addr &= ~(0xff << shift); 637f7df2e56Smrg PciCfg1Addr |= ((uint32_t) val) << shift; 638f7df2e56Smrg return 1; 63905b261ecSmrg } 64005b261ecSmrg if ((addr >= 0xCFC) && (addr <= 0xCFF)) { 641f7df2e56Smrg const unsigned offset = addr - 0xCFC; 642f7df2e56Smrg 643f7df2e56Smrg if (PRINT_PORT && DEBUG_IO_TRACE()) 644f7df2e56Smrg ErrorF(" cfg_outb(%#" PRIx32 ", %2.2x)\n", (unsigned) (PciCfg1Addr + offset), 645f7df2e56Smrg (unsigned) val); 646f7df2e56Smrg pci_device_cfg_write_u8(pci_device_for_cfg_address(PciCfg1Addr), val, 647f7df2e56Smrg PCI_OFFSET(PciCfg1Addr) + offset); 648f7df2e56Smrg return 1; 64905b261ecSmrg } 65005b261ecSmrg return 0; 65105b261ecSmrg} 65205b261ecSmrg 653f7df2e56Smrguint8_t 654f7df2e56Smrgbios_checksum(const uint8_t *start, int size) 65505b261ecSmrg{ 656f7df2e56Smrg uint8_t sum = 0; 65705b261ecSmrg 65805b261ecSmrg while (size-- > 0) 659f7df2e56Smrg sum += *start++; 66005b261ecSmrg return sum; 66105b261ecSmrg} 66205b261ecSmrg 66305b261ecSmrg/* 66405b261ecSmrg * Lock/Unlock legacy VGA. Some Bioses try to be very clever and make 66505b261ecSmrg * an attempt to detect a legacy ISA card. If they find one they might 66605b261ecSmrg * act very strange: for example they might configure the card as a 66705b261ecSmrg * monochrome card. This might cause some drivers to choke. 6685a112b11Smrg * To avoid this we attempt legacy VGA by writing to all known VGA 66905b261ecSmrg * disable registers before we call the BIOS initialization and 6705a112b11Smrg * restore the original values afterwards. In between we hold our 6715a112b11Smrg * breath. To get to a (possibly existing) ISA card need to disable 67205b261ecSmrg * our current PCI card. 67305b261ecSmrg */ 67405b261ecSmrg/* 67505b261ecSmrg * This is just for booting: we just want to catch pure 67605b261ecSmrg * legacy vga therefore we don't worry about mmio etc. 67705b261ecSmrg * This stuff should really go into vgaHW.c. However then 67805b261ecSmrg * the driver would have to load the vga-module prior to 67905b261ecSmrg * doing int10. 68005b261ecSmrg */ 68105b261ecSmrgvoid 68205b261ecSmrgLockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) 68305b261ecSmrg{ 684af31da9aSmacallan#ifndef NO_LEGACY_VGA 685f7df2e56Smrg vga->save_msr = pci_io_read8(pInt->io, 0x03CC); 686f7df2e56Smrg vga->save_vse = pci_io_read8(pInt->io, 0x03C3); 68705b261ecSmrg#ifndef __ia64__ 688f7df2e56Smrg vga->save_46e8 = pci_io_read8(pInt->io, 0x46E8); 68905b261ecSmrg#endif 690f7df2e56Smrg vga->save_pos102 = pci_io_read8(pInt->io, 0x0102); 691f7df2e56Smrg pci_io_write8(pInt->io, 0x03C2, ~(uint8_t) 0x03 & vga->save_msr); 692f7df2e56Smrg pci_io_write8(pInt->io, 0x03C3, ~(uint8_t) 0x01 & vga->save_vse); 69305b261ecSmrg#ifndef __ia64__ 694f7df2e56Smrg pci_io_write8(pInt->io, 0x46E8, ~(uint8_t) 0x08 & vga->save_46e8); 69505b261ecSmrg#endif 696f7df2e56Smrg pci_io_write8(pInt->io, 0x0102, ~(uint8_t) 0x01 & vga->save_pos102); 697af31da9aSmacallan#endif 69805b261ecSmrg} 69905b261ecSmrg 70005b261ecSmrgvoid 70105b261ecSmrgUnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) 70205b261ecSmrg{ 703af31da9aSmacallan#ifndef NO_LEGACY_VGA 704f7df2e56Smrg pci_io_write8(pInt->io, 0x0102, vga->save_pos102); 70505b261ecSmrg#ifndef __ia64__ 706f7df2e56Smrg pci_io_write8(pInt->io, 0x46E8, vga->save_46e8); 70705b261ecSmrg#endif 708f7df2e56Smrg pci_io_write8(pInt->io, 0x03C3, vga->save_vse); 709f7df2e56Smrg pci_io_write8(pInt->io, 0x03C2, vga->save_msr); 710af31da9aSmacallan#endif 71105b261ecSmrg} 71205b261ecSmrg 71305b261ecSmrg#if defined (_PC) 71405b261ecSmrgstatic void 71505b261ecSmrgSetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set) 71605b261ecSmrg{ 71705b261ecSmrg int pagesize = getpagesize(); 718f7df2e56Smrg unsigned char *base; 71905b261ecSmrg int i; 72005b261ecSmrg 721f7df2e56Smrg if (pci_device_map_legacy 722f7df2e56Smrg (pInt->dev, 0, pagesize, PCI_DEV_MAP_FLAG_WRITABLE, (void **) &base)) 723f7df2e56Smrg return; /* eek */ 724f7df2e56Smrg 72505b261ecSmrg if (set) { 726f7df2e56Smrg for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) 727f7df2e56Smrg MEM_WW(pInt, i, *(base + i)); 728f7df2e56Smrg } 729f7df2e56Smrg else { 730f7df2e56Smrg for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) 731f7df2e56Smrg *(base + i) = MEM_RW(pInt, i); 73205b261ecSmrg } 733f7df2e56Smrg 734f7df2e56Smrg pci_device_unmap_legacy(pInt->dev, base, pagesize); 73505b261ecSmrg} 73605b261ecSmrg 73705b261ecSmrgvoid 73805b261ecSmrgxf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save) 73905b261ecSmrg{ 74005b261ecSmrg int pagesize = getpagesize(); 741f7df2e56Smrg unsigned char *base; 74205b261ecSmrg int i; 74305b261ecSmrg 74405b261ecSmrg if (!xf86IsEntityPrimary(pInt->entityIndex) 745f7df2e56Smrg || (!save && !pInt->BIOSScratch)) 746f7df2e56Smrg return; 747f7df2e56Smrg 748f7df2e56Smrg if (pci_device_map_legacy 749f7df2e56Smrg (pInt->dev, 0, pagesize, PCI_DEV_MAP_FLAG_WRITABLE, (void **) &base)) 750f7df2e56Smrg return; /* eek */ 751f7df2e56Smrg 75205b261ecSmrg base += BIOS_SCRATCH_OFF; 75305b261ecSmrg if (save) { 754f7df2e56Smrg if ((pInt->BIOSScratch = xnfalloc(BIOS_SCRATCH_LEN))) 755f7df2e56Smrg for (i = 0; i < BIOS_SCRATCH_LEN; i++) 756f7df2e56Smrg *(((char *) pInt->BIOSScratch + i)) = *(base + i); 757f7df2e56Smrg } 758f7df2e56Smrg else { 759f7df2e56Smrg if (pInt->BIOSScratch) { 760f7df2e56Smrg for (i = 0; i < BIOS_SCRATCH_LEN; i++) 761f7df2e56Smrg *(base + i) = *(pInt->BIOSScratch + i); 762f7df2e56Smrg free(pInt->BIOSScratch); 763f7df2e56Smrg pInt->BIOSScratch = NULL; 764f7df2e56Smrg } 765f7df2e56Smrg } 766f7df2e56Smrg 767f7df2e56Smrg pci_device_unmap_legacy(pInt->dev, base - BIOS_SCRATCH_OFF, pagesize); 76805b261ecSmrg} 76905b261ecSmrg#endif 77005b261ecSmrg 77105b261ecSmrgxf86Int10InfoPtr 77205b261ecSmrgxf86InitInt10(int entityIndex) 77305b261ecSmrg{ 77405b261ecSmrg return xf86ExtendedInitInt10(entityIndex, 0); 77505b261ecSmrg} 776