/* $XFree86: xc/programs/Xserver/hw/xfree86/scanpci/xf86ScanPci.c,v 1.13 2003/08/24 17:37:10 dawes Exp $ */ /* * Display the Subsystem Vendor Id and Subsystem Id in order to identify * the cards installed in this computer * * A lot of this comes from Robin Cutshaw's scanpci * */ /* * Copyright (c) 1995-2002 by The XFree86 Project, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of the copyright holder(s) * and author(s) shall not be used in advertising or otherwise to promote * the sale, use or other dealings in this Software without prior written * authorization from the copyright holder(s) and author(s). */ /* * This file is used to build both the scanpci and pcidata modules. * The interfaces have changed compared with XFree86 4.2.0 and earlier. * The data is no longer exported directly. Lookup functions are provided. * This means that the data format can change in the future without affecting * the exported interfaces. * * The namespaces for pcidata and scanpci clash, so both modules can't be * loaded at the same time. The X server should only load the scanpci module * when run with the '-scanpci' flag. The main difference between the * two modules is size. pcidata only holds the subset of data that is * "interesting" to the X server. "Interesting" is determined by the * PCI_VENDOR_* defines in ../common/xf86PciInfo.h. */ /* XXX This is including a lot of stuff that modules should not include! */ #include "X.h" #include "os.h" #include "xf86.h" #include "xf86Priv.h" #include "xf86Pci.h" #include "xf86_OSproc.h" #ifndef IN_MODULE #include #include #else #include #endif #ifndef PCIDATA #define VENDOR_INCLUDE_NONVIDEO #endif #define INIT_SUBSYS_INFO #define INIT_VENDOR_SUBSYS_INFO #include "xf86PciStr.h" #include "xf86PciIds.h" #include "xf86ScanPci.h" /* * PCI classes that have messages printed always. The others are only * have a message printed when the vendor/dev IDs are recognised. */ #define PCIALWAYSPRINTCLASSES(b,s) \ (((b) == PCI_CLASS_PREHISTORIC && (s) == PCI_SUBCLASS_PREHISTORIC_VGA) || \ ((b) == PCI_CLASS_DISPLAY) || \ ((b) == PCI_CLASS_MULTIMEDIA && (s) == PCI_SUBCLASS_MULTIMEDIA_VIDEO)) #ifdef XFree86LOADER #include "xf86Module.h" #ifdef PCIDATA static XF86ModuleVersionInfo pciDataVersRec = { "pcidata", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XF86_VERSION_CURRENT, 1, 0, 0, ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, NULL, {0, 0, 0, 0} }; XF86ModuleData pcidataModuleData = { &pciDataVersRec, NULL, NULL }; #else static XF86ModuleVersionInfo scanPciVersRec = { "scanpci", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XF86_VERSION_CURRENT, 1, 0, 0, ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, NULL, {0, 0, 0, 0} }; XF86ModuleData scanpciModuleData = { &scanPciVersRec, NULL, NULL }; #endif /* PCIDATA */ #endif /* XFree86LOADER */ /* Initialisation/Close hooks, in case they're ever needed. */ Bool ScanPciSetupPciIds(void) { return TRUE; } void ScanPciClosePciIds(void) { return; } /* * The return value is the number of strings found, or -1 for an error. * Requested strings that aren't found are set to NULL. */ int ScanPciFindPciNamesByDevice(unsigned short vendor, unsigned short device, unsigned short svendor, unsigned short subsys, const char **vname, const char **dname, const char **svname, const char **sname) { int i, j, k; const pciDeviceInfo **pDev; const pciSubsystemInfo **pSub; /* It's an error to not provide the Vendor */ if (vendor == NOVENDOR) return -1; /* Initialise returns requested/provided to NULL */ if (vname) *vname = NULL; if (device != NODEVICE && dname) *dname = NULL; if (svendor != NOVENDOR && svname) *svname = NULL; if (subsys != NOSUBSYS && sname) *sname = NULL; for (i = 0; pciVendorInfoList[i].VendorName; i++) { if (vendor == pciVendorInfoList[i].VendorID) { if (vname) { *vname = pciVendorInfoList[i].VendorName; } if (device == NODEVICE) { return 1; } pDev = pciVendorInfoList[i].Device; if (!pDev) { return 1; } for (j = 0; pDev[j]; j++) { if (device == pDev[j]->DeviceID) { if (dname) { *dname = pDev[j]->DeviceName; } if (svendor == NOVENDOR) { return 2; } for (k = 0; pciVendorInfoList[k].VendorName; k++) { if (svendor && svendor == pciVendorInfoList[k].VendorID) { if (svname) { *svname = pciVendorInfoList[k].VendorName; } if (subsys == NOSUBSYS) { return 3; } break; } } if (!pciVendorInfoList[k].VendorName) { return 2; } pSub = pDev[j]->Subsystem; if (!pSub) { return 3; } for (k = 0; pSub[k]; k++) { if (svendor == pSub[k]->VendorID && subsys == pSub[k]->SubsystemID) { if (sname) *sname = pSub[k]->SubsystemName; return 4; } } /* No vendor/subsys match */ return 3; } } /* No device match */ return 1; } } /* No vendor match */ return 0; } Bool ScanPciFindPciNamesBySubsys(unsigned short svendor, unsigned short subsys, const char **svname, const char **sname) { int i, j; const pciSubsystemInfo **pSub; /* It's an error to not provide the Vendor */ if (svendor == NOVENDOR) return -1; /* Initialise returns requested/provided to NULL */ if (svname) *svname = NULL; if (subsys != NOSUBSYS && sname) *sname = NULL; for (i = 0; pciVendorSubsysInfoList[i].VendorName; i++) { if (svendor == pciVendorSubsysInfoList[i].VendorID) { if (svname) { *svname = pciVendorSubsysInfoList[i].VendorName; } if (subsys == NOSUBSYS) { return 1; } pSub = pciVendorSubsysInfoList[i].Subsystem; if (!pSub) { return 1; } for (j = 0; pSub[j]; j++) { if (subsys == pSub[j]->SubsystemID) { if (sname) { *sname = pSub[j]->SubsystemName; } } } /* No subsys match */ return 1; } } /* No vendor match */ return 0; } CARD32 ScanPciFindPciClassBySubsys(unsigned short vendor, unsigned short subsys) { int i, j; const pciSubsystemInfo **pSub; if (vendor == NOVENDOR || subsys == NOSUBSYS) return 0; for (i = 0; pciVendorSubsysInfoList[i].VendorName; i++) { if (vendor == pciVendorSubsysInfoList[i].VendorID) { pSub = pciVendorSubsysInfoList[i].Subsystem; if (!pSub) { return 0; } for (j = 0; pSub[j]; j++) { if (subsys == pSub[j]->SubsystemID) { return pSub[j]->class; } } break; } } return 0; } CARD32 ScanPciFindPciClassByDevice(unsigned short vendor, unsigned short device) { int i, j; const pciDeviceInfo **pDev; if (vendor == NOVENDOR || device == NODEVICE) return 0; for (i = 0; pciVendorInfoList[i].VendorName; i++) { if (vendor == pciVendorInfoList[i].VendorID) { pDev = pciVendorInfoList[i].Device; if (!pDev) { return 0; } for (j = 0; pDev[j]; j++) { if (device == pDev[j]->DeviceID) { return pDev[j]->class; } } break; } } return 0; } #ifndef PCIDATA void ScanPciDisplayPCICardInfo(int verbosity) { pciConfigPtr pcrp, *pcrpp; int i; xf86EnableIO(); pcrpp = xf86scanpci(0); if (pcrpp == NULL) { xf86MsgVerb(X_NONE,0,"No PCI info available\n"); return; } xf86MsgVerb(X_NONE,0,"Probing for PCI devices (Bus:Device:Function)\n\n"); for (i = 0; (pcrp = pcrpp[i]); i++) { const char *svendorname = NULL, *subsysname = NULL; const char *vendorname = NULL, *devicename = NULL; Bool noCard = FALSE; const char *prefix1 = "", *prefix2 = ""; xf86MsgVerb(X_NONE, -verbosity, "(%d:%d:%d) ", pcrp->busnum, pcrp->devnum, pcrp->funcnum); /* * Lookup as much as we can about the device. */ if (pcrp->pci_subsys_vendor || pcrp->pci_subsys_card) { ScanPciFindPciNamesByDevice(pcrp->pci_vendor, pcrp->pci_device, NOVENDOR, NOSUBSYS, &vendorname, &devicename, NULL, NULL); } else { ScanPciFindPciNamesByDevice(pcrp->pci_vendor, pcrp->pci_device, pcrp->pci_subsys_vendor, pcrp->pci_subsys_card, &vendorname, &devicename, &svendorname, &subsysname); } if (svendorname) xf86MsgVerb(X_NONE, -verbosity, "%s ", svendorname); if (subsysname) xf86MsgVerb(X_NONE, -verbosity, "%s ", subsysname); if (svendorname && !subsysname) { if (pcrp->pci_subsys_card && pcrp->pci_subsys_card != NOSUBSYS) { xf86MsgVerb(X_NONE, -verbosity, "unknown card (0x%04x) ", pcrp->pci_subsys_card); } else { xf86MsgVerb(X_NONE, -verbosity, "card "); } } if (!svendorname && !subsysname) { /* * We didn't find a text representation of the information * about the card. */ if (pcrp->pci_subsys_vendor || pcrp->pci_subsys_card) { /* * If there was information and we just couldn't interpret * it, print it out as unknown, anyway. */ xf86MsgVerb(X_NONE, -verbosity, "unknown card (0x%04x/0x%04x) ", pcrp->pci_subsys_vendor, pcrp->pci_subsys_card); } else noCard = TRUE; } if (!noCard) { prefix1 = "using a "; prefix2 = "using an "; } if (vendorname && devicename) { xf86MsgVerb(X_NONE, -verbosity,"%s%s %s\n", prefix1, vendorname, devicename); } else if (vendorname) { xf86MsgVerb(X_NONE, -verbosity, "%sunknown chip (DeviceId 0x%04x) from %s\n", prefix2, pcrp->pci_device, vendorname); } else { xf86MsgVerb(X_NONE, -verbosity, "%sunknown chipset(0x%04x/0x%04x)\n", prefix2, pcrp->pci_vendor, pcrp->pci_device); } } } #endif