aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xfree86/common/xf86pciBus.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xfree86/common/xf86pciBus.c')
-rw-r--r--xorg-server/hw/xfree86/common/xf86pciBus.c746
1 files changed, 746 insertions, 0 deletions
diff --git a/xorg-server/hw/xfree86/common/xf86pciBus.c b/xorg-server/hw/xfree86/common/xf86pciBus.c
index 925751256..8d968dc39 100644
--- a/xorg-server/hw/xfree86/common/xf86pciBus.c
+++ b/xorg-server/hw/xfree86/common/xf86pciBus.c
@@ -41,6 +41,7 @@
#include "Pci.h"
#include "xf86.h"
#include "xf86Priv.h"
+#include "dirent.h" /* DIR, FILE type definitions */
/* Bus-specific headers */
#include "xf86Bus.h"
@@ -581,3 +582,748 @@ xf86PciIsolateDevice(char *argument)
} else
FatalError("Invalid isolated device specification\n");
}
+
+static Bool
+pciDeviceHasBars(struct pci_device *pci)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (pci->regions[i].size)
+ return TRUE;
+
+ if (pci->rom_size)
+ return TRUE;
+
+ return FALSE;
+}
+
+struct Inst {
+ struct pci_device * pci;
+ GDevPtr dev;
+ Bool foundHW; /* PCIid in list of supported chipsets */
+ Bool claimed; /* BusID matches with a device section */
+ int chip;
+ int screen;
+};
+
+
+/**
+ * Find set of unclaimed devices matching a given vendor ID.
+ *
+ * Used by drivers to find as yet unclaimed devices matching the specified
+ * vendor ID.
+ *
+ * \param driverName Name of the driver. This is used to find Device
+ * sections in the config file.
+ * \param vendorID PCI vendor ID of associated devices. If zero, then
+ * the true vendor ID must be encoded in the \c PCIid
+ * fields of the \c PCIchipsets entries.
+ * \param chipsets Symbol table used to associate chipset names with
+ * PCI IDs.
+ * \param devList List of Device sections parsed from the config file.
+ * \param numDevs Number of entries in \c devList.
+ * \param drvp Pointer the driver's control structure.
+ * \param foundEntities Returned list of entity indicies associated with the
+ * driver.
+ *
+ * \returns
+ * The number of elements in returned in \c foundEntities on success or zero
+ * on failure.
+ *
+ * \todo
+ * This function does a bit more than short description says. Fill in some
+ * more of the details of its operation.
+ *
+ * \todo
+ * The \c driverName parameter is redundant. It is the same as
+ * \c DriverRec::driverName. In a future version of this function, remove
+ * that parameter.
+ */
+int
+xf86MatchPciInstances(const char *driverName, int vendorID,
+ SymTabPtr chipsets, PciChipsets *PCIchipsets,
+ GDevPtr *devList, int numDevs, DriverPtr drvp,
+ int **foundEntities)
+{
+ int i,j;
+ struct pci_device * pPci;
+ struct pci_device_iterator *iter;
+ struct Inst *instances = NULL;
+ int numClaimedInstances = 0;
+ int allocatedInstances = 0;
+ int numFound = 0;
+ SymTabRec *c;
+ PciChipsets *id;
+ int *retEntities = NULL;
+
+ *foundEntities = NULL;
+
+
+ /* Each PCI device will contribute at least one entry. Each device
+ * section can contribute at most one entry. The sum of the two is
+ * guaranteed to be larger than the maximum possible number of entries.
+ * Do this calculation and memory allocation once now to eliminate the
+ * need for realloc calls inside the loop.
+ */
+ if (!(xf86DoConfigure && xf86DoConfigurePass1)) {
+ unsigned max_entries = numDevs;
+
+ iter = pci_slot_match_iterator_create(NULL);
+ while ((pPci = pci_device_next(iter)) != NULL) {
+ max_entries++;
+ }
+
+ pci_iterator_destroy(iter);
+ instances = xnfalloc(max_entries * sizeof(struct Inst));
+ }
+
+ iter = pci_slot_match_iterator_create(NULL);
+ while ((pPci = pci_device_next(iter)) != NULL) {
+ unsigned device_class = pPci->device_class;
+ Bool foundVendor = FALSE;
+
+
+ /* Convert the pre-PCI 2.0 device class for a VGA adapter to the
+ * 2.0 version of the same class.
+ */
+ if ( device_class == 0x00000101 ) {
+ device_class = 0x00030000;
+ }
+
+
+ /* Find PCI devices that match the given vendor ID. The vendor ID is
+ * either specified explicitly as a parameter to the function or
+ * implicitly encoded in the high bits of id->PCIid.
+ *
+ * The first device with a matching vendor is recorded, even if the
+ * device ID doesn't match. This is done because the Device section
+ * in the xorg.conf file can over-ride the device ID. A matching PCI
+ * ID might not be found now, but after the device ID over-ride is
+ * applied there /might/ be a match.
+ */
+ for (id = PCIchipsets; id->PCIid != -1; id++) {
+ const unsigned vendor_id = ((id->PCIid & 0xFFFF0000) >> 16)
+ | vendorID;
+ const unsigned device_id = (id->PCIid & 0x0000FFFF);
+ const unsigned match_class = 0x00030000 | id->PCIid;
+
+ if ((vendor_id == pPci->vendor_id)
+ || ((vendorID == PCI_VENDOR_GENERIC) && (match_class == device_class))) {
+ if (!foundVendor && (instances != NULL)) {
+ ++allocatedInstances;
+ instances[allocatedInstances - 1].pci = pPci;
+ instances[allocatedInstances - 1].dev = NULL;
+ instances[allocatedInstances - 1].claimed = FALSE;
+ instances[allocatedInstances - 1].foundHW = FALSE;
+ instances[allocatedInstances - 1].screen = 0;
+ }
+
+ foundVendor = TRUE;
+
+ if ( (device_id == pPci->device_id)
+ || ((vendorID == PCI_VENDOR_GENERIC)
+ && (match_class == device_class)) ) {
+ if ( instances != NULL ) {
+ instances[allocatedInstances - 1].foundHW = TRUE;
+ instances[allocatedInstances - 1].chip = id->numChipset;
+ }
+
+
+ if ( xf86DoConfigure && xf86DoConfigurePass1 ) {
+ if (xf86CheckPciSlot(pPci)) {
+ GDevPtr pGDev =
+ xf86AddBusDeviceToConfigure(drvp->driverName,
+ BUS_PCI, pPci, -1);
+ if (pGDev) {
+ /* After configure pass 1, chipID and chipRev
+ * are treated as over-rides, so clobber them
+ * here.
+ */
+ pGDev->chipID = -1;
+ pGDev->chipRev = -1;
+ }
+
+ numFound++;
+ }
+ }
+ else {
+ numFound++;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ pci_iterator_destroy(iter);
+
+
+ /* In "probe only" or "configure" mode (signaled by instances being NULL),
+ * our work is done. Return the number of detected devices.
+ */
+ if ( instances == NULL ) {
+ return numFound;
+ }
+
+
+ /*
+ * This may be debatable, but if no PCI devices with a matching vendor
+ * type is found, return zero now. It is probably not desirable to
+ * allow the config file to override this.
+ */
+ if (allocatedInstances <= 0) {
+ free(instances);
+ return 0;
+ }
+
+
+ DebugF("%s instances found: %d\n", driverName, allocatedInstances);
+
+ /*
+ * Check for devices that need duplicated instances. This is required
+ * when there is more than one screen per entity.
+ *
+ * XXX This currently doesn't work for cases where the BusID isn't
+ * specified explicitly in the config file.
+ */
+
+ for (j = 0; j < numDevs; j++) {
+ if (devList[j]->screen > 0 && devList[j]->busID
+ && *devList[j]->busID) {
+ for (i = 0; i < allocatedInstances; i++) {
+ pPci = instances[i].pci;
+ if (xf86ComparePciBusString(devList[j]->busID,
+ PCI_MAKE_BUS( pPci->domain, pPci->bus ),
+ pPci->dev,
+ pPci->func)) {
+ allocatedInstances++;
+ instances[allocatedInstances - 1] = instances[i];
+ instances[allocatedInstances - 1].screen = devList[j]->screen;
+ numFound++;
+ break;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < allocatedInstances; i++) {
+ GDevPtr dev = NULL;
+ GDevPtr devBus = NULL;
+
+ pPci = instances[i].pci;
+ for (j = 0; j < numDevs; j++) {
+ if (devList[j]->busID && *devList[j]->busID) {
+ if (xf86ComparePciBusString(devList[j]->busID,
+ PCI_MAKE_BUS( pPci->domain, pPci->bus ),
+ pPci->dev,
+ pPci->func) &&
+ devList[j]->screen == instances[i].screen) {
+
+ if (devBus)
+ xf86MsgVerb(X_WARNING,0,
+ "%s: More than one matching Device section for "
+ "instances\n\t(BusID: %s) found: %s\n",
+ driverName, devList[j]->busID,
+ devList[j]->identifier);
+ else
+ devBus = devList[j];
+ }
+ } else {
+ /*
+ * if device section without BusID is found
+ * only assign to it to the primary device.
+ */
+ if (xf86IsPrimaryPci(pPci)) {
+ xf86Msg(X_PROBED, "Assigning device section with no busID"
+ " to primary device\n");
+ if (dev || devBus)
+ xf86MsgVerb(X_WARNING, 0,
+ "%s: More than one matching Device section "
+ "found: %s\n", driverName, devList[j]->identifier);
+ else
+ dev = devList[j];
+ }
+ }
+ }
+ if (devBus) dev = devBus; /* busID preferred */
+ if (!dev) {
+ if (xf86CheckPciSlot(pPci) && pciDeviceHasBars(pPci)) {
+ xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section "
+ "for instance (BusID PCI:%u@%u:%u:%u) found\n",
+ driverName, pPci->domain, pPci->bus, pPci->dev,
+ pPci->func);
+ }
+ } else {
+ numClaimedInstances++;
+ instances[i].claimed = TRUE;
+ instances[i].dev = dev;
+ }
+ }
+ DebugF("%s instances found: %d\n", driverName, numClaimedInstances);
+ /*
+ * Now check that a chipset or chipID override in the device section
+ * is valid. Chipset has precedence over chipID.
+ * If chipset is not valid ignore BusSlot completely.
+ */
+ for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
+ MessageType from = X_PROBED;
+
+ if (!instances[i].claimed) {
+ continue;
+ }
+ if (instances[i].dev->chipset) {
+ for (c = chipsets; c->token >= 0; c++) {
+ if (xf86NameCmp(c->name, instances[i].dev->chipset) == 0)
+ break;
+ }
+ if (c->token == -1) {
+ instances[i].claimed = FALSE;
+ numClaimedInstances--;
+ xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device "
+ "section \"%s\" isn't valid for this driver\n",
+ driverName, instances[i].dev->chipset,
+ instances[i].dev->identifier);
+ } else {
+ instances[i].chip = c->token;
+
+ for (id = PCIchipsets; id->numChipset >= 0; id++) {
+ if (id->numChipset == instances[i].chip)
+ break;
+ }
+ if(id->numChipset >=0){
+ xf86Msg(X_CONFIG,"Chipset override: %s\n",
+ instances[i].dev->chipset);
+ from = X_CONFIG;
+ } else {
+ instances[i].claimed = FALSE;
+ numClaimedInstances--;
+ xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device "
+ "section \"%s\" isn't a valid PCI chipset\n",
+ driverName, instances[i].dev->chipset,
+ instances[i].dev->identifier);
+ }
+ }
+ } else if (instances[i].dev->chipID > 0) {
+ for (id = PCIchipsets; id->numChipset >= 0; id++) {
+ if (id->PCIid == instances[i].dev->chipID)
+ break;
+ }
+ if (id->numChipset == -1) {
+ instances[i].claimed = FALSE;
+ numClaimedInstances--;
+ xf86MsgVerb(X_WARNING, 0, "%s: ChipID 0x%04X in Device "
+ "section \"%s\" isn't valid for this driver\n",
+ driverName, instances[i].dev->chipID,
+ instances[i].dev->identifier);
+ } else {
+ instances[i].chip = id->numChipset;
+
+ xf86Msg( X_CONFIG,"ChipID override: 0x%04X\n",
+ instances[i].dev->chipID);
+ from = X_CONFIG;
+ }
+ } else if (!instances[i].foundHW) {
+ /*
+ * This means that there was no override and the PCI chipType
+ * doesn't match one that is supported
+ */
+ instances[i].claimed = FALSE;
+ numClaimedInstances--;
+ }
+ if (instances[i].claimed == TRUE){
+ for (c = chipsets; c->token >= 0; c++) {
+ if (c->token == instances[i].chip)
+ break;
+ }
+ xf86Msg(from,"Chipset %s found\n",
+ c->name);
+ }
+ }
+
+ /*
+ * Of the claimed instances, check that another driver hasn't already
+ * claimed its slot.
+ */
+ numFound = 0;
+ for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
+ if (!instances[i].claimed)
+ continue;
+ pPci = instances[i].pci;
+
+
+ /*
+ * Allow the same entity to be used more than once for devices with
+ * multiple screens per entity. This assumes implicitly that there
+ * will be a screen == 0 instance.
+ *
+ * XXX Need to make sure that two different drivers don't claim
+ * the same screen > 0 instance.
+ */
+ if (instances[i].screen == 0 && !xf86CheckPciSlot( pPci ))
+ continue;
+
+ DebugF("%s: card at %d:%d:%d is claimed by a Device section\n",
+ driverName, pPci->bus, pPci->dev, pPci->func);
+
+ /* Allocate an entry in the lists to be returned */
+ numFound++;
+ retEntities = xnfrealloc(retEntities, numFound * sizeof(int));
+ retEntities[numFound - 1] = xf86ClaimPciSlot( pPci, drvp,
+ instances[i].chip,
+ instances[i].dev,
+ instances[i].dev->active);
+ if (retEntities[numFound - 1] == -1 && instances[i].screen > 0) {
+ for (j = 0; j < xf86NumEntities; j++) {
+ EntityPtr pEnt = xf86Entities[j];
+ if (pEnt->bus.type != BUS_PCI)
+ continue;
+ if (pEnt->bus.id.pci == pPci) {
+ retEntities[numFound - 1] = j;
+ xf86AddDevToEntity(j, instances[i].dev);
+ break;
+ }
+ }
+ }
+ }
+ free(instances);
+ if (numFound > 0) {
+ *foundEntities = retEntities;
+ }
+
+ return numFound;
+}
+
+/*
+ * xf86ConfigPciEntityInactive() -- This function can be used
+ * to configure an inactive entity as well as to reconfigure an
+ * previously active entity inactive. If the entity has been
+ * assigned to a screen before it will be removed. If p_chip is
+ * non-NULL all static resources listed there will be registered.
+ */
+static void
+xf86ConfigPciEntityInactive(EntityInfoPtr pEnt, PciChipsets *p_chip,
+ EntityProc init, EntityProc enter,
+ EntityProc leave, pointer private)
+{
+ ScrnInfoPtr pScrn;
+
+ if ((pScrn = xf86FindScreenForEntity(pEnt->index)))
+ xf86RemoveEntityFromScreen(pScrn,pEnt->index);
+
+ /* shared resources are only needed when entity is active: remove */
+ xf86SetEntityFuncs(pEnt->index,init,enter,leave,private);
+}
+
+ScrnInfoPtr
+xf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex,
+ PciChipsets *p_chip, void *dummy, EntityProc init,
+ EntityProc enter, EntityProc leave, pointer private)
+{
+ EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex);
+ if (!pEnt) return pScrn;
+
+ if (!(pEnt->location.type == BUS_PCI)
+ || !xf86GetPciInfoForEntity(entityIndex)) {
+ free(pEnt);
+ return pScrn;
+ }
+ if (!pEnt->active) {
+ xf86ConfigPciEntityInactive(pEnt, p_chip, init, enter,
+ leave, private);
+ free(pEnt);
+ return pScrn;
+ }
+
+ if (!pScrn)
+ pScrn = xf86AllocateScreen(pEnt->driver,scrnFlag);
+ if (xf86IsEntitySharable(entityIndex)) {
+ xf86SetEntityShared(entityIndex);
+ }
+ xf86AddEntityToScreen(pScrn,entityIndex);
+ if (xf86IsEntityShared(entityIndex)) {
+ return pScrn;
+ }
+ free(pEnt);
+
+ xf86SetEntityFuncs(entityIndex,init,enter,leave,private);
+
+ return pScrn;
+}
+
+/*
+ * OBSOLETE ! xf86ConfigActivePciEntity() is an obsolete function.
+ * It is likely to be removed. Don't use!
+ */
+Bool
+xf86ConfigActivePciEntity(ScrnInfoPtr pScrn, int entityIndex,
+ PciChipsets *p_chip, void *dummy, EntityProc init,
+ EntityProc enter, EntityProc leave, pointer private)
+{
+ EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex);
+ if (!pEnt) return FALSE;
+
+ if (!pEnt->active || !(pEnt->location.type == BUS_PCI)) {
+ free(pEnt);
+ return FALSE;
+ }
+ xf86AddEntityToScreen(pScrn,entityIndex);
+
+ free(pEnt);
+ if (!xf86SetEntityFuncs(entityIndex,init,enter,leave,private))
+ return FALSE;
+
+ return TRUE;
+}
+
+static int
+videoPtrToDriverList(struct pci_device *dev,
+ char *returnList[], int returnListMax)
+{
+ int i;
+ /* Add more entries here if we ever return more than 4 drivers for
+ any device */
+ char *driverList[5] = { NULL, NULL, NULL, NULL, NULL };
+
+ switch (dev->vendor_id)
+ {
+ /* AMD Geode LX */
+ case 0x1022:
+ if (dev->device_id == 0x2081)
+ driverList[0] = "geode";
+ break;
+ /* older Geode products acquired by AMD still carry an NSC vendor_id */
+ case 0x100b:
+ if (dev->device_id == 0x0030) {
+ /* NSC Geode GX2 specifically */
+ driverList[0] = "geode";
+ /* GX2 support started its life in the NSC tree and was later
+ forked by AMD for GEODE so we keep it as a backup */
+ driverList[1] = "nsc";
+ } else
+ /* other NSC variant e.g. 0x0104 (SC1400), 0x0504 (SCx200) */
+ driverList[0] = "nsc";
+ break;
+ /* Cyrix Geode GX1 */
+ case 0x1078:
+ if (dev->device_id == 0x0104)
+ driverList[0] = "cyrix";
+ break;
+ case 0x1142: driverList[0] = "apm"; break;
+ case 0xedd8: driverList[0] = "ark"; break;
+ case 0x1a03: driverList[0] = "ast"; break;
+ case 0x1002: driverList[0] = "ati"; break;
+ case 0x102c: driverList[0] = "chips"; break;
+ case 0x1013: driverList[0] = "cirrus"; break;
+ case 0x3d3d: driverList[0] = "glint"; break;
+ case 0x105d: driverList[0] = "i128"; break;
+ case 0x8086:
+ if ((dev->device_id == 0x00d1) || (dev->device_id == 0x7800)) {
+ driverList[0] = "i740";
+ } else if (dev->device_id == 0x8108) {
+ break; /* "hooray" for poulsbo */
+ } else {
+ driverList[0] = "intel";
+ }
+ break;
+ case 0x102b: driverList[0] = "mga"; break;
+ case 0x10c8: driverList[0] = "neomagic"; break;
+ case 0x10de: case 0x12d2: driverList[0] = "nv"; break;
+ case 0x1106: driverList[0] = "openchrome"; break;
+ case 0x1b36: driverList[0] = "qxl"; break;
+ case 0x1163: driverList[0] = "rendition"; break;
+ case 0x5333:
+ switch (dev->device_id)
+ {
+ case 0x88d0: case 0x88d1: case 0x88f0: case 0x8811:
+ case 0x8812: case 0x8814: case 0x8901:
+ driverList[0] = "s3"; break;
+ case 0x5631: case 0x883d: case 0x8a01: case 0x8a10:
+ case 0x8c01: case 0x8c03: case 0x8904: case 0x8a13:
+ driverList[0] = "s3virge"; break;
+ default:
+ driverList[0] = "savage"; break;
+ }
+ break;
+ case 0x1039: driverList[0] = "sis"; break;
+ case 0x126f: driverList[0] = "siliconmotion"; break;
+ case 0x121a:
+ if (dev->device_id < 0x0003)
+ driverList[0] = "voodoo";
+ else
+ driverList[0] = "tdfx";
+ break;
+ case 0x1011: driverList[0] = "tga"; break;
+ case 0x1023: driverList[0] = "trident"; break;
+ case 0x100c: driverList[0] = "tseng"; break;
+ case 0x80ee: driverList[0] = "vboxvideo"; break;
+ case 0x15ad: driverList[0] = "vmware"; break;
+ case 0x18ca:
+ if (dev->device_id == 0x47)
+ driverList[0] = "xgixp";
+ else
+ driverList[0] = "xgi";
+ break;
+ default: break;
+ }
+ for (i = 0; (i < returnListMax) && (driverList[i] != NULL); i++) {
+ returnList[i] = xnfstrdup(driverList[i]);
+ }
+ return i; /* Number of entries added */
+}
+
+static int
+xchomp(char *line)
+{
+ size_t len = 0;
+
+ if (!line) {
+ return 1;
+ }
+
+ len = strlen(line);
+ if (line[len - 1] == '\n' && len > 0) {
+ line[len - 1] = '\0';
+ }
+ return 0;
+}
+
+#ifdef __linux__
+/* This function is used to provide a workaround for binary drivers that
+ * don't export their PCI ID's properly. If distros don't end up using this
+ * feature it can and should be removed because the symbol-based resolution
+ * scheme should be the primary one */
+static void
+matchDriverFromFiles (char** matches, uint16_t match_vendor, uint16_t match_chip)
+{
+ DIR *idsdir;
+ FILE *fp;
+ struct dirent *direntry;
+ char *line = NULL;
+ size_t len;
+ ssize_t read;
+ char path_name[256], vendor_str[5], chip_str[5];
+ uint16_t vendor, chip;
+ int i, j;
+
+ idsdir = opendir(PCI_TXT_IDS_PATH);
+ if (!idsdir)
+ return;
+
+ xf86Msg(X_INFO, "Scanning %s directory for additional PCI ID's supported by the drivers\n", PCI_TXT_IDS_PATH);
+ direntry = readdir(idsdir);
+ /* Read the directory */
+ while (direntry) {
+ if (direntry->d_name[0] == '.') {
+ direntry = readdir(idsdir);
+ continue;
+ }
+ len = strlen(direntry->d_name);
+ /* A tiny bit of sanity checking. We should probably do better */
+ if (strncmp(&(direntry->d_name[len-4]), ".ids", 4) == 0) {
+ /* We need the full path name to open the file */
+ strncpy(path_name, PCI_TXT_IDS_PATH, 256);
+ strncat(path_name, "/", 1);
+ strncat(path_name, direntry->d_name, (256 - strlen(path_name) - 1));
+ fp = fopen(path_name, "r");
+ if (fp == NULL) {
+ xf86Msg(X_ERROR, "Could not open %s for reading. Exiting.\n", path_name);
+ goto end;
+ }
+ /* Read the file */
+#ifdef __GLIBC__
+ while ((read = getline(&line, &len, fp)) != -1) {
+#else
+ while ((line = fgetln(fp, &len)) != (char *)NULL) {
+#endif /* __GLIBC __ */
+ xchomp(line);
+ if (isdigit(line[0])) {
+ strncpy(vendor_str, line, 4);
+ vendor_str[4] = '\0';
+ vendor = (int)strtol(vendor_str, NULL, 16);
+ if ((strlen(&line[4])) == 0) {
+ chip_str[0] = '\0';
+ chip = -1;
+ } else {
+ /* Handle trailing whitespace */
+ if (isspace(line[4])) {
+ chip_str[0] = '\0';
+ chip = -1;
+ } else {
+ /* Ok, it's a real ID */
+ strncpy(chip_str, &line[4], 4);
+ chip_str[4] = '\0';
+ chip = (int)strtol(chip_str, NULL, 16);
+ }
+ }
+ if (vendor == match_vendor && chip == match_chip ) {
+ i = 0;
+ while (matches[i]) {
+ i++;
+ }
+ matches[i] = (char*)malloc(sizeof(char) * strlen(direntry->d_name) - 3);
+ if (!matches[i]) {
+ xf86Msg(X_ERROR, "Could not allocate space for the module name. Exiting.\n");
+ goto end;
+ }
+ /* hack off the .ids suffix. This should guard
+ * against other problems, but it will end up
+ * taking off anything after the first '.' */
+ for (j = 0; j < (strlen(direntry->d_name) - 3) ; j++) {
+ if (direntry->d_name[j] == '.') {
+ matches[i][j] = '\0';
+ break;
+ } else {
+ matches[i][j] = direntry->d_name[j];
+ }
+ }
+ xf86Msg(X_INFO, "Matched %s from file name %s\n", matches[i], direntry->d_name);
+ }
+ } else {
+ /* TODO Handle driver overrides here */
+ }
+ }
+ fclose(fp);
+ }
+ direntry = readdir(idsdir);
+ }
+ end:
+ free(line);
+ closedir(idsdir);
+}
+#endif /* __linux__ */
+
+void
+xf86PciMatchDriver(char* matches[], int nmatches) {
+ int i;
+ struct pci_device * info = NULL;
+ struct pci_device_iterator *iter;
+
+ /* Find the primary device, and get some information about it. */
+ iter = pci_slot_match_iterator_create(NULL);
+ while ((info = pci_device_next(iter)) != NULL) {
+ if (xf86IsPrimaryPci(info)) {
+ break;
+ }
+ }
+
+ pci_iterator_destroy(iter);
+
+ if (!info) {
+ ErrorF("Primary device is not PCI\n");
+ }
+#ifdef __linux__
+ else {
+ matchDriverFromFiles(matches, info->vendor_id, info->device_id);
+ }
+#endif /* __linux__ */
+
+ for (i = 0; (i < nmatches) && (matches[i]); i++) {
+ /* find end of matches list */
+ }
+
+ if ((info != NULL) && (i < nmatches)) {
+ i += videoPtrToDriverList(info, &(matches[i]), nmatches - i);
+ }
+}