/* * ______ ____ ______ _____ ______ * | ____| | _ \| ____| / / _ \| ____| * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __| * | | | | | __/ __/ |_) | |____ / / | | | | | * |_| |_| \___|\___|____/|______/_/ |_| |_|_| * * * Assorted helper routines for use by the /AF drivers. * * The code in this file makes heavy use of DPMI and VESA functions, * so any drivers that use these helpers will not be portable to * Linux. For maximum portability, a driver should use direct hardware * access for all features, and not touch any of these routines. * * See freebe.txt for copyright information. */ #include #include #include "vbeaf.h" /* trace_putc: * Debugging trace function */ void trace_putc(char c) { asm ( " int $0x21 " : : "a" (0x200), "d" (c) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" ); } /* trace_printf: * Debugging trace function: supports %c, %s, %d, and %x */ void trace_printf(char *msg, ...) { static char hex_digit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; unsigned long l; char *s; int c, i; va_list ap; va_start(ap, msg); while (*msg) { if (*msg == '%') { /* handle escape token */ msg++; switch (*msg) { case '%': trace_putc('%'); break; case 'c': c = va_arg(ap, char); trace_putc(c); break; case 's': s = va_arg(ap, char *); while (*s) { if (*s == '\n') trace_putc('\r'); trace_putc(*s); s++; } break; case 'd': c = va_arg(ap, int); if (c < 0) { trace_putc('-'); c = -c; } i = 1; while (i*10 <= c) i *= 10; while (i) { trace_putc('0'+c/i); c %= i; i /= 10; } break; case 'x': l = va_arg(ap, unsigned long); for (i=7; i>=0; i--) trace_putc(hex_digit[(l>>(i*4))&0xF]); break; } if (*msg) msg++; } else { /* output normal character */ if (*msg == '\n') trace_putc('\r'); trace_putc(*msg); msg++; } } va_end(ap); } /* rm_int: * Calls a real mode interrupt: basically the same thing as __dpmi_int(). */ void rm_int(int num, RM_REGS *regs) { regs->x.flags = 0; regs->x.sp = 0; regs->x.ss = 0; asm ( " int $0x31 " : : "a" (0x300), "b" (num), "c" (0), "D" (regs) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" ); } /* allocate_dos_memory: * Allocates a block of conventional memory, returning a real mode segment * address, and filling in the protected mode selector for accessing it. * Returns -1 on error. */ int allocate_dos_memory(int size, int *sel) { int rm_seg; int pm_sel; int ok; asm ( " int $0x31 ; " " jc 0f ; " " movl $1, %2 ; " " jmp 1f ; " " 0: " " movl $0, %2 ; " " 1: " : "=a" (rm_seg), "=d" (pm_sel), "=m" (ok) : "a" (0x100), "b" ((size+15)/16) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" ); if (!ok) return -1; *sel = pm_sel; return rm_seg; } /* free_dos_memory: * Frees a block of conventional memory, given a selector previously * returned by a call allocate_dos_memory(). */ void free_dos_memory(int sel) { asm ( " int $0x31 " : : "a" (0x101), "d" (sel) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" ); } /* allocate_selector: * Creates a selector for accessing the specified linear memory region, * returning a selector value or -1 on error. */ int allocate_selector(int addr, int size) { int sel; int ok; asm ( " int $0x31 ; " " jc 0f ; " " movl %%eax, %%ebx ; " " movl $7, %%eax ; " " movl %4, %%ecx ; " " movl %5, %%edx ; " " int $0x31 ; " " jc 0f ; " " movl $8, %%eax ; " " movl %6, %%ecx ; " " movl %7, %%edx ; " " int $0x31 ; " " jc 0f ; " " movl $1, %1 ; " " jmp 1f ; " " 0: " " movl $1, %1 ; " " 1: " : "=b" (sel), "=D" (ok) : "a" (0), "c" (1), "m" (addr>>16), "m" (addr&0xFFFF), "m" ((size-1)>>16), "m" ((size-1)&0xFFFF) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" ); if (!ok) return -1; return sel; } /* free_selector: * Destroys a selector that was previously created with the * allocate_selector() function. */ void free_selector(int sel) { asm ( " int $0x31 " : : "a" (1), "b" (sel) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" ); } /* Helper routines for accessing the underlying VESA interface. */ #define MASK_LINEAR(addr) (addr & 0x000FFFFF) #define RM_TO_LINEAR(addr) (((addr & 0xFFFF0000) >> 12) + (addr & 0xFFFF)) #define RM_OFFSET(addr) (addr & 0xF) #define RM_SEGMENT(addr) ((addr >> 4) & 0xFFFF) typedef struct VESA_INFO /* VESA information block structure */ { unsigned char VESASignature[4] __attribute__ ((packed)); unsigned short VESAVersion __attribute__ ((packed)); unsigned long OEMStringPtr __attribute__ ((packed)); unsigned char Capabilities[4] __attribute__ ((packed)); unsigned long VideoModePtr __attribute__ ((packed)); unsigned short TotalMemory __attribute__ ((packed)); unsigned short OemSoftwareRev __attribute__ ((packed)); unsigned long OemVendorNamePtr __attribute__ ((packed)); unsigned long OemProductNamePtr __attribute__ ((packed)); unsigned long OemProductRevPtr __attribute__ ((packed)); unsigned char Reserved[222] __attribute__ ((packed)); unsigned char OemData[256] __attribute__ ((packed)); } VESA_INFO; typedef struct VESA_MODE_INFO /* VESA information for a specific mode */ { unsigned short ModeAttributes __attribute__ ((packed)); unsigned char WinAAttributes __attribute__ ((packed)); unsigned char WinBAttributes __attribute__ ((packed)); unsigned short WinGranularity __attribute__ ((packed)); unsigned short WinSize __attribute__ ((packed)); unsigned short WinASegment __attribute__ ((packed)); unsigned short WinBSegment __attribute__ ((packed)); unsigned long WinFuncPtr __attribute__ ((packed)); unsigned short BytesPerScanLine __attribute__ ((packed)); unsigned short XResolution __attribute__ ((packed)); unsigned short YResolution __attribute__ ((packed)); unsigned char XCharSize __attribute__ ((packed)); unsigned char YCharSize __attribute__ ((packed)); unsigned char NumberOfPlanes __attribute__ ((packed)); unsigned char BitsPerPixel __attribute__ ((packed)); unsigned char NumberOfBanks __attribute__ ((packed)); unsigned char MemoryModel __attribute__ ((packed)); unsigned char BankSize __attribute__ ((packed)); unsigned char NumberOfImagePages __attribute__ ((packed)); unsigned char Reserved_page __attribute__ ((packed)); unsigned char RedMaskSize __attribute__ ((packed)); unsigned char RedMaskPos __attribute__ ((packed)); unsigned char GreenMaskSize __attribute__ ((packed)); unsigned char GreenMaskPos __attribute__ ((packed)); unsigned char BlueMaskSize __attribute__ ((packed)); unsigned char BlueMaskPos __attribute__ ((packed)); unsigned char ReservedMaskSize __attribute__ ((packed)); unsigned char ReservedMaskPos __attribute__ ((packed)); unsigned char DirectColorModeInfo __attribute__ ((packed)); /* VBE 2.0 extensions */ unsigned long PhysBasePtr __attribute__ ((packed)); unsigned long OffScreenMemOffset __attribute__ ((packed)); unsigned short OffScreenMemSize __attribute__ ((packed)); /* VBE 3.0 extensions */ unsigned short LinBytesPerScanLine __attribute__ ((packed)); unsigned char BnkNumberOfPages __attribute__ ((packed)); unsigned char LinNumberOfPages __attribute__ ((packed)); unsigned char LinRedMaskSize __attribute__ ((packed)); unsigned char LinRedFieldPos __attribute__ ((packed)); unsigned char LinGreenMaskSize __attribute__ ((packed)); unsigned char LinGreenFieldPos __attribute__ ((packed)); unsigned char LinBlueMaskSize __attribute__ ((packed)); unsigned char LinBlueFieldPos __attribute__ ((packed)); unsigned char LinRsvdMaskSize __attribute__ ((packed)); unsigned char LinRsvdFieldPos __attribute__ ((packed)); unsigned long MaxPixelClock __attribute__ ((packed)); unsigned char Reserved[190] __attribute__ ((packed)); } VESA_MODE_INFO; #define MAX_VESA_MODES 256 #define SAFETY_BUFFER 4096 /* get_vesa_info: * Retrieves data from the VESA info block structure and mode list, * returning 0 for success. */ int get_vesa_info(int *vram_size, unsigned long *linear_addr, void (*callback)(int vesa_num, int linear, int w, int h, int bpp, int bytes_per_scanline, int redsize, int redpos, int greensize, int greenpos, int bluesize, int bluepos, int rsvdsize, int rsvdpos)) { VESA_INFO vesa_info; VESA_MODE_INFO mode_info; RM_REGS r; int mode_list[MAX_VESA_MODES]; long mode_ptr; int num_modes; int seg, sel; int c, i; /* fetch the VESA info block */ seg = allocate_dos_memory(sizeof(VESA_INFO)+SAFETY_BUFFER, &sel); if (seg < 0) return -1; for (c=0; c<(int)sizeof(VESA_INFO); c++) _farpokeb(sel, c, 0); _farpokeb(sel, 0, 'V'); _farpokeb(sel, 1, 'B'); _farpokeb(sel, 2, 'E'); _farpokeb(sel, 3, '2'); r.x.ax = 0x4F00; r.x.di = 0; r.x.es = seg; rm_int(0x10, &r); if (r.h.ah) { free_dos_memory(sel); return -1; } for (c=0; c<(int)sizeof(VESA_INFO); c++) ((char *)&vesa_info)[c] = _farpeekb(sel, c); free_dos_memory(sel); if ((vesa_info.VESASignature[0] != 'V') || (vesa_info.VESASignature[1] != 'E') || (vesa_info.VESASignature[2] != 'S') || (vesa_info.VESASignature[3] != 'A')) return -1; *vram_size = vesa_info.TotalMemory << 16; if (linear_addr) *linear_addr = 0; sel = allocate_selector(0, 1024*1024); if (sel < 0) return -1; /* read the mode list */ mode_ptr = RM_TO_LINEAR(vesa_info.VideoModePtr); num_modes = 0; while ((mode_list[num_modes] = _farpeekw(sel, mode_ptr)) != 0xFFFF) { num_modes++; mode_ptr += 2; if (num_modes >= MAX_VESA_MODES) break; } free_selector(sel); seg = allocate_dos_memory(sizeof(VESA_MODE_INFO)+SAFETY_BUFFER, &sel); if (seg < 0) return -1; /* fetch info about each supported mode */ for (c=0; c= 0x300) { if (callback) { callback(mode_list[c], TRUE, mode_info.XResolution, mode_info.YResolution, mode_info.BitsPerPixel, mode_info.LinBytesPerScanLine, mode_info.LinRedMaskSize, mode_info.LinRedFieldPos, mode_info.LinGreenMaskSize, mode_info.LinGreenFieldPos, mode_info.LinBlueMaskSize, mode_info.LinBlueFieldPos, mode_info.LinRsvdMaskSize, mode_info.LinRsvdFieldPos); } } else { if (callback) { callback(mode_list[c], TRUE, mode_info.XResolution, mode_info.YResolution, mode_info.BitsPerPixel, mode_info.BytesPerScanLine, mode_info.RedMaskSize, mode_info.RedMaskPos, mode_info.GreenMaskSize, mode_info.GreenMaskPos, mode_info.BlueMaskSize, mode_info.BlueMaskPos, mode_info.ReservedMaskSize, mode_info.ReservedMaskPos); } } } else { /* banked mode */ if (callback) { callback(mode_list[c], FALSE, mode_info.XResolution, mode_info.YResolution, mode_info.BitsPerPixel, mode_info.BytesPerScanLine, mode_info.RedMaskSize, mode_info.RedMaskPos, mode_info.GreenMaskSize, mode_info.GreenMaskPos, mode_info.BlueMaskSize, mode_info.BlueMaskPos, mode_info.ReservedMaskSize, mode_info.ReservedMaskPos); } } } } } free_dos_memory(sel); return 0; } /* FindPCIDevice: * Replacement for the INT 1A - PCI BIOS v2.0c+ - FIND PCI DEVICE, AX = B102h * * Note: deviceIndex is because a card can hold more than one PCI chip. * * Searches the board of the vendor supplied in vendorID with * identification number deviceID and index deviceIndex (normally 0). * The value returned in handle can be used to access the PCI registers * of this board. * * Return: 1 if found 0 if not found. */ int FindPCIDevice(int deviceID, int vendorID, int deviceIndex, int *handle) { int model, vendor, card, device; unsigned value, full_id, bus, busMax; deviceIndex <<= 8; /* for each PCI bus */ for (bus=0, busMax=0x10000; bus> 16; if (vendor != 0xFFFF) { /* is this the one we want? */ if ((deviceID == model) && (vendorID == vendor)) { *handle = value; return 1; } /* is it a bridge to a secondary bus? */ outportl(PCIConfigurationAddress, value | 8); if (((inportl(PCIConfigurationData) >> 16) == 0x0600) || (full_id==0x00011011)) busMax += 0x10000; } } } return 0; } /* fixup_feature_list: * Helper for the FAF_CFG_FEATURES extension, for blanking out any * accelerated drawing routines that the install program has disabled. */ void fixup_feature_list(AF_DRIVER *af, unsigned long flags) { if (!(flags & fafHWCursor)) { af->Attributes &= ~afHaveHWCursor; af->SetCursor = NULL; af->SetCursorPos = NULL; af->SetCursorColor = NULL; af->ShowCursor = NULL; } if (!(flags & fafDrawScan)) af->DrawScan = NULL; if (!(flags & fafDrawPattScan)) af->DrawPattScan = NULL; if (!(flags & fafDrawColorPattScan)) af->DrawColorPattScan = NULL; if (!(flags & fafDrawScanList)) af->DrawScanList = NULL; if (!(flags & fafDrawPattScanList)) af->DrawPattScanList = NULL; if (!(flags & fafDrawColorPattScanList)) af->DrawColorPattScanList = NULL; if (!(flags & fafDrawRect)) af->DrawRect = NULL; if (!(flags & fafDrawPattRect)) af->DrawPattRect = NULL; if (!(flags & fafDrawColorPattRect)) af->DrawColorPattRect = NULL; if (!(flags & fafDrawLine)) af->DrawLine = NULL; if (!(flags & fafDrawStippleLine)) af->DrawStippleLine = NULL; if (!(flags & fafDrawTrap)) af->DrawTrap = NULL; if (!(flags & fafDrawTri)) af->DrawTri = NULL; if (!(flags & fafDrawQuad)) af->DrawQuad = NULL; if (!(flags & fafPutMonoImage)) af->PutMonoImage = NULL; if (!(flags & fafPutMonoImageLin)) af->PutMonoImageLin = NULL; if (!(flags & fafPutMonoImageBM)) af->PutMonoImageBM = NULL; if (!(flags & fafBitBlt)) af->BitBlt = NULL; if (!(flags & fafBitBltSys)) af->BitBltSys = NULL; if (!(flags & fafBitBltLin)) af->BitBltLin = NULL; if (!(flags & fafBitBltBM)) af->BitBltBM = NULL; if (!(flags & fafSrcTransBlt)) af->SrcTransBlt = NULL; if (!(flags & fafSrcTransBltSys)) af->SrcTransBltSys = NULL; if (!(flags & fafSrcTransBltLin)) af->SrcTransBltLin = NULL; if (!(flags & fafSrcTransBltBM)) af->SrcTransBltBM = NULL; }