/* * PCIAGP.CC - Contains PCI BIOS functions. * Copyright (C) 1998, 1999 Prashant TR * * Special thanks to Ralf Brown. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * See the file COPYING.TR for more details. */ // ID for this file. #define _PCIAGP_CC_ #include "pciagp.h" #define DEVICES 93 typedef struct { long unsigned code; char name[80]; } DEVICE; DEVICE device[DEVICES] = { { 0x000000, "Reserved" }, { 0x00ff00, "None" }, { 0x010000, "SCSI Controller" }, { 0x010100, "IDE Controller" }, { 0x010200, "FDD Controller" }, { 0x010300, "IPI Controller" }, { 0x010400, "RAID Controller" }, { 0x018000, "Other Mass Storage Controller" }, { 0x01ff00, "None" }, { 0x020000, "Ethernet Controller" }, { 0x020100, "Token Ring Controller" }, { 0x020200, "FDDI Controller" }, { 0x020300, "ATM Controller" }, { 0x028000, "Other Network Interface Controller" }, { 0x02ff00, "None" }, { 0x030000, "VGA Controller" }, { 0x030001, "VESA SVGA Controller" }, { 0x030100, "XGA Controller" }, { 0x038000, "Other Display Controller" }, { 0x03ff00, "None" }, { 0x040000, "Multimedia Video Controller" }, { 0x040100, "Audio Controller" }, { 0x048000, "Other Multimedia Controller" }, { 0x04ff00, "None" }, { 0x050000, "RAM Controller" }, { 0x050100, "FLASH Memory Controller" }, { 0x058000, "Other Memory Controller" }, { 0x05ff00, "None" }, { 0x060000, "Host Processor Bridge" }, { 0x060100, "PCI-ISA Brigde" }, { 0x060200, "PCI-EISA Brigde" }, { 0x060300, "PCI-MCA Brigde" }, { 0x060400, "PCI-PCI Brigde" }, { 0x060500, "PCI-PCMCIA Brigde" }, { 0x060600, "NuBus Brigde" }, { 0x060700, "CardBus Brigde" }, { 0x068000, "Other Bridge Device" }, { 0x06ff00, "None" }, { 0x070000, "XT Compatible RS-232 Device" }, { 0x070001, "16450 Compatible RS-232 Device" }, { 0x070002, "16550 Compatible RS-232 Device" }, { 0x070100, "AT Compatible Parallel Port" }, { 0x070101, "Model-30 Bidirectional Port" }, { 0x070102, "ECP-1.0 Compliant Port" }, { 0x078000, "Other Communication Device" }, { 0x07ff00, "None" }, { 0x080000, "Generic 8259 PIC" }, { 0x080001, "ISA PIC" }, { 0x080003, "EISA PIC" }, { 0x080100, "Generic DMA Controller" }, { 0x080101, "ISA DMA Controller" }, { 0x080102, "EISA DMA Controller" }, { 0x080200, "Generic System Timer" }, { 0x080201, "ISA System Timer" }, { 0x080202, "EISA System Timer" }, { 0x080300, "Generic Real Time Clock" }, { 0x080301, "ISA Real Time Clock" }, { 0x088000, "Other System Peripheral" }, { 0x08ff00, "None" }, { 0x090000, "Keyboard Controller" }, { 0x090001, "Keyboard Controller" }, { 0x090100, "Digitizer (Pen)" }, { 0x090101, "Digitizer (Pen)" }, { 0x090200, "Mouse Controller" }, { 0x090201, "Mouse Controller" }, { 0x098000, "Other Input Controller" }, { 0x09ff00, "None" }, { 0x0a0000, "Generic Docking Station" }, { 0x0a0001, "Generic Docking Station" }, { 0x0a8000, "Other Docking Station" }, { 0x0aff00, "None" }, { 0x0b0000, "386 based Processor" }, { 0x0b0001, "386 based Processor" }, { 0x0b0100, "486 based Processor" }, { 0x0b0101, "486 based Processor" }, { 0x0b0200, "Pentium based Processor" }, { 0x0b0201, "Pentium based Processor" }, { 0x0b0300, "P6 based Processor" }, { 0x0b0301, "P6 based Processor" }, { 0x0b1000, "Alpha based Processor" }, { 0x0b1001, "Alpha based Processor" }, { 0x0b4000, "Coprocessor" }, { 0x0b4001, "Coprocessor" }, { 0x0b8000, "Other Processor" }, { 0x0bff00, "None" }, { 0x0c0000, "Firewire Bus Controller" }, { 0x0c0000, "ACCESS.bus Controller" }, { 0x0c0200, "SSA Controller" }, { 0x0c0300, "USB Controller" }, { 0x0c0400, "Fibre Channel Device" }, { 0x0c0500, "SMBus Controller" }, // To be checked. { 0x0c8000, "Other Bus Controller" }, { 0x0cff00, "None" }, }; int errflag = 0; FILE *fp; char cmdline[20]; // Write any string to the file and check for successfulness. void writestring(const char *string) { if (fprintf(fp, "%s", string) == EOF) { errflag = 2; checkerrors(); } } int sysinfo() { char output[256], buffer[256], namebuf[20], pciname[256]; unsigned long pinsize; int i, j, k, l, buses, ndevices, major, minor; int found, foundname, foundvendor; long unsigned classcode; __dpmi_regs regs; void *pinbuffer; char *ptr; int position = 0; PCICFG *cfg; // Create output file. if ((fp = fopen("pciagp.txt", "w")) == NULL) { errflag = 1; checkerrors(); } writestring("\nPCI/AGP INFORMATION :\n\n"); // Load PIN file. pinbuffer = pinload("sysinfo.pin"); // Check for PCI/AGP bus. regs.x.ax = 0xb101; __dpmi_int(0x1a, ®s); if ((regs.x.flags & 1) || (regs.d.edx != 0x20494350) || (regs.h.ah)) { writestring("\tPCI bus not installed.\n"); fclose(fp); return 0; } // Write number of buses present. sprintf(output, "\tNumber of PCI/AGP buses : %d\n", regs.h.cl + 1); writestring(output); sprintf(output, "\tPCI/AGP bus interface version : %X.%02X\n", regs.h.bh, regs.h.bl); writestring(output); // sprintf(output, "\tProtected Mode Entry Point : %lXh\n", // regs.d.edi); // writestring(output); // Write access mechanisms. sprintf(output, "\tAccess Mechanism 1 supported : %s\n", (regs.h.al & 1) ? "Yes" : "No"); writestring(output); sprintf(output, "\tAccess Mechanism 2 supported : %s\n", (regs.h.al & 2) ? "Yes" : "No"); writestring(output); sprintf(output, "\tSpecial Cycle Generation 1 supported : %s\n", (regs.h.al & 16) ? "Yes" : "No"); writestring(output); sprintf(output, "\tSpecial Cycle Generation 2 supported : %s\n", (regs.h.al & 32) ? "Yes" : "No"); writestring(output); major = regs.h.bh; minor = regs.h.bl; buses = regs.h.cl; ndevices = 0; // PCI/AGP Information. for(i = 0; i <= 0x1f; i++) // Devices. for(j = 0; j <= 7; j++) // Functions. for(k = 0; k <= buses; k++) // Buses. { regs.x.ax = 0xb10a; regs.x.di = 0; if ((major < 2) || (minor < 1)) { regs.h.bl = k; regs.h.bh = (i << 3) | j; } else { regs.h.bh = k; regs.h.bl = (i << 3) | j; } regs.x.dx = 1; __dpmi_int(0x1a, ®s); if (regs.d.ecx != 0xffffffff) ndevices++; } sprintf(output, "\tNumber of PCI/AGP devices attached : %d\n", ndevices); writestring(output); // PCI/AGP Information. for(i = 0; i <= 0x1f; i++) // Devices. for(j = 0; j <= 7; j++) // Functions. for(k = 0; k <= buses; k++) // Buses. { for(l = 0; l <= 72; l += 4) // Registers. l < 256 crashes for some devices. { regs.x.ax = 0xb10a; regs.x.di = l; if ((major < 2) || (minor < 1)) { regs.h.bl = k; regs.h.bh = (i << 3) | j; } else { regs.h.bh = k; regs.h.bl = (i << 3) | j; } regs.x.dx = 1; __dpmi_int(0x1a, ®s); if ((!l) && (regs.d.ecx == 0xffffffff)) break; // Save device information. *(unsigned long *)&buffer[l] = regs.d.ecx; } if ((!l) && (regs.d.ecx == 0xffffffff)) continue; // Write out device configuration. cfg = (PCICFG *)buffer; // Write configuration information. writestring("\nPCI/AGP DEVICES INFORMATION :\n\n"); sprintf(output, "\tDevice Number : %Xh\n", i); writestring(output); sprintf(output, "\tFunction Number : %Xh\n", j); writestring(output); sprintf(output, "\tBus Number : %Xh\n", k); writestring(output); sprintf(output, "\tVendor ID : %04Xh\n", cfg -> vendorID); writestring(output); sprintf(output, "\tDevice ID : %04Xh\n", cfg -> deviceID); writestring(output); sprintf(output, "\tOEM Device ID : " "VEN_%04X DEV_%04X FUN_%X\n", cfg -> vendorID, cfg -> deviceID, j); writestring(output); classcode = ((*(unsigned short *)&buffer[10]) << 8) + (unsigned char)buffer[9]; sprintf(output, "\tDevice Class Code : %06lXh\n", classcode); writestring(output); // Write device type. found = 0; for(l = 0; ((l < DEVICES) && (!found)); l++) if (classcode == device[l].code) { found++; break; } if (!found) for(l = 0; ((l < DEVICES) && (!found)); l++) if ((classcode & 0xffffff00) == device[l].code) { found++; break; } sprintf(output, "\tDevice Type : %s\n", (i < DEVICES) ? device[l].name : "(Unknown)"); writestring(output); // Seek to PCILIST.TXT and load vendor names from PIN file. ptr = (char *)pinseek(pinbuffer, "pcilist.txt", PINFILES); ptr = (char *)((unsigned long)ptr + 100); pinsize = *(unsigned long *)ptr; ptr = (char *)((unsigned long)ptr + 4); foundname = foundvendor = 0; // Search for entry in PCI list. sprintf(namebuf, "%04Xh%04Xh", *(unsigned short *)&buffer[0], *(unsigned short *)&buffer[2]); strcpy(pciname, "(Unknown)"); do { if ((ptr[5] == '=') && (!strncmp(namebuf, ptr, 5))) { position = 0; // We have got the vendor name (1st entry in PCI list). ptr = (char *)((unsigned long)ptr + 6); pinsize -= 6; // Scan through buffer until newline and add NULL if required. while ((*ptr != '\r') && (*ptr != '\n')) { pciname[position++] = *ptr++; pinsize--; } while ((*ptr == '\r') || (*ptr == '\n')) { *ptr++; pinsize--; } // Add null after one space. pciname[position++] = ' '; pciname[position] = 0; foundvendor++; } else if ((ptr[10] == '=') && (!strncmp(namebuf, ptr, 10))) { // We have got the device name. ptr = (char *)((unsigned long)ptr + 11); pinsize -= 11; // Scan through buffer until newline and add NULL if required. while ((*ptr != '\r') && (*ptr != '\n')) { pciname[position++] = *ptr++; pinsize--; } while ((*ptr == '\r') || (*ptr == '\n')) { *ptr++; pinsize--; } // Add null after one space. pciname[position++] = ' '; pciname[position++] = 0; foundname++; } else { if ((foundvendor) && (strncmp(namebuf, ptr, 5))) break; // Simply go to next line. while ((*ptr != '\r') && (*ptr != '\n')) { pinsize--; *ptr++; } while ((*ptr == '\r') || (*ptr == '\n')) *ptr++; } } while ((pinsize) && (!foundname)); // Write out device name. if ((foundvendor) && (!foundname)) strcat(pciname, "(Unknown)"); sprintf(output, "\tTrue Device Name : %s\n", pciname); writestring(output); sprintf(output, "\tHardware Revision : %Xh\n", cfg -> revisionID); writestring(output); if (cfg -> latency) { sprintf(output, "\tLatency Timer : %d Clocks\n", cfg -> latency); writestring(output); } else writestring("\tLatency Timer : N/A\n"); if ((cfg -> nonbridge.interrupt_line) && (cfg -> nonbridge.interrupt_line <= 15)) { sprintf(output, "\tInterrupt Line : IRQ%d\n", cfg -> nonbridge.interrupt_line); writestring(output); } else writestring("\tInterrupt Line : N/A\n"); if ((cfg -> nonbridge.interrupt_pin) && (cfg -> nonbridge.interrupt_pin <= 4)) { sprintf(output, "\tInterrupt Pin : INT%c#\n", cfg -> nonbridge.interrupt_pin + 'A' - 1); writestring(output); } else writestring("\tInterrupt Pin : N/A\n"); // Write flags. // Write command bits. sprintf(output, "\tI/O Access : %s\n", (cfg -> command_reg & 1) ? "Yes" : "No"); writestring(output); sprintf(output, "\tMemory Access : %s\n", (cfg -> command_reg & 2) ? "Yes" : "No"); writestring(output); sprintf(output, "\tBus Master Capable : %s\n", (cfg -> command_reg & 4) ? "Yes" : "No"); writestring(output); sprintf(output, "\tSpecial Cycle Recognition : %s\n", (cfg -> command_reg & 8) ? "Yes" : "No"); writestring(output); sprintf(output, "\tMemory Write and Invalidate : %s\n", (cfg -> command_reg & 0x10) ? "Yes" : "No"); writestring(output); sprintf(output, "\tVGA Palette snoop : %s\n", (cfg -> command_reg & 0x20) ? "Yes" : "No"); writestring(output); sprintf(output, "\tParity Error Response : %s\n", (cfg -> command_reg & 0x40) ? "Yes" : "No"); writestring(output); // Address/Data Stepping ?. sprintf(output, "\tWait Cycles : %s\n", (cfg -> command_reg & 0x80) ? "Yes" : "No"); writestring(output); sprintf(output, "\tSystem Error Line : %s\n", (cfg -> command_reg & 0x100) ? "Yes" : "No"); writestring(output); sprintf(output, "\tFast Back to Back Transactions : %s\n", (cfg -> command_reg & 0x200) ? "Yes" : "No"); writestring(output); // Write status bits. sprintf(output, "\tCapability List : %s\n", (cfg -> status_reg & 0x10) ? "Yes" : "No"); writestring(output); sprintf(output, "\t66MHz PCI bus support : %s\n", (cfg -> status_reg & 0x20) ? "Yes" : "No"); writestring(output); sprintf(output, "\tUser Defined Format : %s\n", (cfg -> status_reg & 0x40) ? "Yes" : "No"); writestring(output); sprintf(output, "\tSupports Fast Transactions : %s\n", (cfg -> status_reg & 0x80) ? "Yes" : "No"); writestring(output); sprintf(output, "\tSupports Parity Line : %s\n", (cfg -> status_reg & 0x100) ? "Yes" : "No"); writestring(output); sprintf(output, "\tDevice Select Timing : %s\n", (((cfg -> status_reg & 0x600) >> 9) == 0) ? "Fast" : (((cfg -> status_reg & 0x600) >> 9) == 1) ? "Medium" : (((cfg -> status_reg & 0x600) >> 9) == 2) ? "Slow" : "(Unknown)"); writestring(output); sprintf(output, "\tSupports SIGABRT (sig-abort) : %s\n", (cfg -> status_reg & 0x800) ? "Yes" : "No"); writestring(output); sprintf(output, "\tSupports RCVABRT (rcv-abort) : %s\n", (cfg -> status_reg & 0x1000) ? "Yes" : "No"); writestring(output); sprintf(output, "\tSupports MSTABRT (mst-abort) : %s\n", (cfg -> status_reg & 0x2000) ? "Yes" : "No"); writestring(output); sprintf(output, "\tSupports System Error line (sig-serr) : %s\n", (cfg -> status_reg & 0x2000) ? "Yes" : "No"); writestring(output); sprintf(output, "\tDetects Parity Errors : %s\n", (cfg -> status_reg & 0x4000) ? "Yes" : "No"); writestring(output); writestring("\nOTHER DETAILS:\n\n"); strcpy(output, "\tDevice Type : "); // Write other features. switch (cfg->header_type & 0x7f) { case 0: strcat(output, "Non-Bridge"); break; case 1: strcat(output, "PCI-PCI Bridge"); break; case 2: strcat(output, "CardBus Bridge"); break; default: sprintf(output, "\tDevice Type : " "Other (%Xh)",cfg->header_type & 0x7f); break; } writestring(output); writestring("\n"); sprintf(output, "\tMulti-function Device : %s\n", (cfg -> header_type & 0x80) ? "Yes" : "No"); writestring(output); if (!(cfg -> header_type & 0x7f)) { // Non-bridge device. sprintf(output, "\tSubsystem Vendor ID : %04Xh\n", cfg -> nonbridge.subsystem_vendorID); writestring(output); sprintf(output, "\tSubsystem Device ID : %04Xh\n", cfg -> nonbridge.subsystem_deviceID); writestring(output); } else if ((cfg -> header_type & 0x7f) == 1) { } else if ((cfg -> header_type & 0x7f) == 2) { } else { } writestring("\n"); } fclose(fp); return 0; } void open_stderr() { fclose(&__dj_stdout); fclose(&__dj_stderr); if (fopen("nul", "wb") == NULL) exit(0x7f); if (fopen("nul", "wb") == NULL) exit(0x7f); if ((stderr = fopen("errors.$$$", "ab")) == NULL) exit(0x7f); } void get_cmdline() { if ((fp = fopen("cmdline.$$$", "rb")) == NULL) exit (0x7f); if (fscanf(fp, "%s", cmdline) != 1) { fclose(fp); exit (0x7f); } fclose(fp); unlink("cmdline.$$$"); } // The main function. int main(int argc, char **argv) { open_stderr(); get_cmdline(); if (!strcmp(cmdline, "sysinfo")) return (sysinfo()); return 0; }