1360 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1360 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Copyright (c) 1997-2003 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 contains the interfaces to the bus-specific code
 | 
						|
 */
 | 
						|
#ifdef HAVE_XORG_CONFIG_H
 | 
						|
#include <xorg-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <ctype.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <X11/X.h>
 | 
						|
#include <pciaccess.h>
 | 
						|
#include "os.h"
 | 
						|
#include "Pci.h"
 | 
						|
#include "xf86.h"
 | 
						|
#include "xf86Priv.h"
 | 
						|
#include "dirent.h" /* DIR, FILE type definitions */
 | 
						|
 | 
						|
/* Bus-specific headers */
 | 
						|
#include "xf86Bus.h"
 | 
						|
 | 
						|
#define XF86_OS_PRIVS
 | 
						|
#include "xf86_OSproc.h"
 | 
						|
 | 
						|
 | 
						|
/* Bus-specific globals */
 | 
						|
Bool pciSlotClaimed = FALSE;
 | 
						|
 | 
						|
#define PCIINFOCLASSES(c) \
 | 
						|
    ( (((c) & 0x00ff0000) == (PCI_CLASS_PREHISTORIC << 16)) \
 | 
						|
      || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \
 | 
						|
      || ((((c) & 0x00ffff00) \
 | 
						|
	   == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) \
 | 
						|
      || ((((c) & 0x00ffff00) \
 | 
						|
	   == ((PCI_CLASS_PROCESSOR << 16) | (PCI_SUBCLASS_PROCESSOR_COPROC << 8)))) )
 | 
						|
 | 
						|
/*
 | 
						|
 * PCI classes that have messages printed always.  The others are only
 | 
						|
 * have a message printed when the vendor/dev IDs are recognised.
 | 
						|
 */
 | 
						|
#define PCIALWAYSPRINTCLASSES(c) \
 | 
						|
    ( (((c) & 0x00ffff00) \
 | 
						|
       == ((PCI_CLASS_PREHISTORIC << 16) | (PCI_SUBCLASS_PREHISTORIC_VGA << 8))) \
 | 
						|
      || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \
 | 
						|
      || ((((c) & 0x00ffff00) \
 | 
						|
	   == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) )
 | 
						|
 | 
						|
#define IS_VGA(c) \
 | 
						|
    (((c) & 0x00ffff00) \
 | 
						|
	 == ((PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8)))
 | 
						|
 | 
						|
 | 
						|
static struct pci_slot_match xf86IsolateDevice = {
 | 
						|
    PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0
 | 
						|
};
 | 
						|
 | 
						|
void
 | 
						|
xf86FormatPciBusNumber(int busnum, char *buffer)
 | 
						|
{
 | 
						|
    /* 'buffer' should be at least 8 characters long */
 | 
						|
    if (busnum < 256)
 | 
						|
	sprintf(buffer, "%d", busnum);
 | 
						|
    else
 | 
						|
	sprintf(buffer, "%d@%d", busnum & 0x00ff, busnum >> 8);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * xf86Bus.c interface
 | 
						|
 */
 | 
						|
 | 
						|
void
 | 
						|
xf86PciProbe(void)
 | 
						|
{
 | 
						|
    int i = 0, k;
 | 
						|
    int num = 0;
 | 
						|
    struct pci_device *info;
 | 
						|
    struct pci_device_iterator *iter;
 | 
						|
    struct pci_device ** xf86PciVideoInfo = NULL;
 | 
						|
 | 
						|
 | 
						|
    if (!xf86scanpci()) {
 | 
						|
	xf86PciVideoInfo = NULL;
 | 
						|
	return;
 | 
						|
    }
 | 
						|
 | 
						|
    iter = pci_slot_match_iterator_create(& xf86IsolateDevice);
 | 
						|
    while ((info = pci_device_next(iter)) != NULL) {
 | 
						|
	if (PCIINFOCLASSES(info->device_class)) {
 | 
						|
	    num++;
 | 
						|
	    xf86PciVideoInfo = xnfrealloc(xf86PciVideoInfo,
 | 
						|
					  (sizeof(struct pci_device *)
 | 
						|
					   * (num + 1)));
 | 
						|
	    xf86PciVideoInfo[num] = NULL;
 | 
						|
	    xf86PciVideoInfo[num - 1] = info;
 | 
						|
 | 
						|
	    pci_device_probe(info);
 | 
						|
#ifdef HAVE_PCI_DEVICE_IS_BOOT_VGA
 | 
						|
	    if (pci_device_is_boot_vga(info)) {
 | 
						|
                primaryBus.type = BUS_PCI;
 | 
						|
                primaryBus.id.pci = info;
 | 
						|
            }
 | 
						|
#endif
 | 
						|
	    info->user_data = 0;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    free(iter);
 | 
						|
 | 
						|
    /* If we haven't found a primary device try a different heuristic */
 | 
						|
    if (primaryBus.type == BUS_NONE && num) {
 | 
						|
	for (i = 0; i < num; i++) {
 | 
						|
	    uint16_t  command;
 | 
						|
 | 
						|
	    info = xf86PciVideoInfo[i];
 | 
						|
	    pci_device_cfg_read_u16(info, & command, 4);
 | 
						|
 | 
						|
	    if ((command & PCI_CMD_MEM_ENABLE) 
 | 
						|
		&& ((num == 1) || IS_VGA(info->device_class))) {
 | 
						|
		if (primaryBus.type == BUS_NONE) {
 | 
						|
		    primaryBus.type = BUS_PCI;
 | 
						|
		    primaryBus.id.pci = info;
 | 
						|
		} else {
 | 
						|
		    xf86Msg(X_NOTICE,
 | 
						|
			    "More than one possible primary device found\n");
 | 
						|
		    primaryBus.type ^= (BusType)(-1);
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
    
 | 
						|
    /* Print a summary of the video devices found */
 | 
						|
    for (k = 0; k < num; k++) {
 | 
						|
	const char *prim = " ";
 | 
						|
	Bool memdone = FALSE, iodone = FALSE;
 | 
						|
 | 
						|
 | 
						|
	info = xf86PciVideoInfo[k];
 | 
						|
 | 
						|
	if (!PCIALWAYSPRINTCLASSES(info->device_class))
 | 
						|
	    continue;
 | 
						|
 | 
						|
	if (xf86IsPrimaryPci(info))
 | 
						|
	    prim = "*";
 | 
						|
 | 
						|
	xf86Msg(X_PROBED, "PCI:%s(%u:%u:%u:%u) %04x:%04x:%04x:%04x ", prim,
 | 
						|
		info->domain, info->bus, info->dev, info->func,
 | 
						|
		info->vendor_id, info->device_id,
 | 
						|
		info->subvendor_id, info->subdevice_id);
 | 
						|
 | 
						|
	xf86ErrorF("rev %d", info->revision);
 | 
						|
 | 
						|
	for (i = 0; i < 6; i++) {
 | 
						|
	    struct pci_mem_region * r = & info->regions[i];
 | 
						|
 | 
						|
	    if ( r->size && ! r->is_IO ) {
 | 
						|
		if (!memdone) {
 | 
						|
		    xf86ErrorF(", Mem @ ");
 | 
						|
		    memdone = TRUE;
 | 
						|
		} else
 | 
						|
		    xf86ErrorF(", ");
 | 
						|
		xf86ErrorF("0x%08lx/%ld", (long)r->base_addr, (long)r->size);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < 6; i++) {
 | 
						|
	    struct pci_mem_region * r = & info->regions[i];
 | 
						|
 | 
						|
	    if ( r->size && r->is_IO ) {
 | 
						|
		if (!iodone) {
 | 
						|
		    xf86ErrorF(", I/O @ ");
 | 
						|
		    iodone = TRUE;
 | 
						|
		} else
 | 
						|
		    xf86ErrorF(", ");
 | 
						|
		xf86ErrorF("0x%08lx/%ld", (long)r->base_addr, (long)r->size);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
	if ( info->rom_size ) {
 | 
						|
	    xf86ErrorF(", BIOS @ 0x\?\?\?\?\?\?\?\?/%ld", (long)info->rom_size);
 | 
						|
	}
 | 
						|
 | 
						|
	xf86ErrorF("\n");
 | 
						|
    }
 | 
						|
    free(xf86PciVideoInfo);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * If the slot requested is already in use, return -1.
 | 
						|
 * Otherwise, claim the slot for the screen requesting it.
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
xf86ClaimPciSlot(struct pci_device * d, DriverPtr drvp,
 | 
						|
		 int chipset, GDevPtr dev, Bool active)
 | 
						|
{
 | 
						|
    EntityPtr p = NULL;
 | 
						|
    int num;
 | 
						|
    
 | 
						|
    if (xf86CheckPciSlot(d)) {
 | 
						|
	num = xf86AllocateEntity();
 | 
						|
	p = xf86Entities[num];
 | 
						|
	p->driver = drvp;
 | 
						|
	p->chipset = chipset;
 | 
						|
	p->bus.type = BUS_PCI;
 | 
						|
	p->bus.id.pci = d;
 | 
						|
	p->active = active;
 | 
						|
	p->inUse = FALSE;
 | 
						|
	if (dev)
 | 
						|
            xf86AddDevToEntity(num, dev);
 | 
						|
	pciSlotClaimed = TRUE;
 | 
						|
 | 
						|
	if (active) {
 | 
						|
	    /* Map in this domain's I/O space */
 | 
						|
	   p->domainIO = xf86MapLegacyIO(d);
 | 
						|
	}
 | 
						|
	
 | 
						|
 	return num;
 | 
						|
    } else
 | 
						|
 	return -1;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Unclaim PCI slot, e.g. if probing failed, so that a different driver can claim.
 | 
						|
 */
 | 
						|
void
 | 
						|
xf86UnclaimPciSlot(struct pci_device *d)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; i < xf86NumEntities; i++) {
 | 
						|
	const EntityPtr p = xf86Entities[i];
 | 
						|
 | 
						|
	if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
 | 
						|
	    /* Probably the slot should be deallocated? */
 | 
						|
	    p->bus.type = BUS_NONE;
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Parse a BUS ID string, and return the PCI bus parameters if it was
 | 
						|
 * in the correct format for a PCI bus id.
 | 
						|
 */
 | 
						|
 | 
						|
Bool
 | 
						|
xf86ParsePciBusString(const char *busID, int *bus, int *device, int *func)
 | 
						|
{
 | 
						|
    /*
 | 
						|
     * The format is assumed to be "bus[@domain]:device[:func]", where domain,
 | 
						|
     * bus, device and func are decimal integers.  domain and func may be
 | 
						|
     * omitted and assumed to be zero, although doing this isn't encouraged.
 | 
						|
     */
 | 
						|
 | 
						|
    char *p, *s, *d;
 | 
						|
    const char *id;
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (StringToBusType(busID, &id) != BUS_PCI)
 | 
						|
	return FALSE;
 | 
						|
 | 
						|
    s = xstrdup(id);
 | 
						|
    p = strtok(s, ":");
 | 
						|
    if (p == NULL || *p == 0) {
 | 
						|
	free(s);
 | 
						|
	return FALSE;
 | 
						|
    }
 | 
						|
    d = strpbrk(p, "@");
 | 
						|
    if (d != NULL) {
 | 
						|
	*(d++) = 0;
 | 
						|
	for (i = 0; d[i] != 0; i++) {
 | 
						|
	    if (!isdigit(d[i])) {
 | 
						|
		free(s);
 | 
						|
		return FALSE;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
    for (i = 0; p[i] != 0; i++) {
 | 
						|
	if (!isdigit(p[i])) {
 | 
						|
	    free(s);
 | 
						|
	    return FALSE;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    *bus = atoi(p);
 | 
						|
    if (d != NULL && *d != 0)
 | 
						|
	*bus += atoi(d) << 8;
 | 
						|
    p = strtok(NULL, ":");
 | 
						|
    if (p == NULL || *p == 0) {
 | 
						|
	free(s);
 | 
						|
	return FALSE;
 | 
						|
    }
 | 
						|
    for (i = 0; p[i] != 0; i++) {
 | 
						|
	if (!isdigit(p[i])) {
 | 
						|
	    free(s);
 | 
						|
	    return FALSE;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    *device = atoi(p);
 | 
						|
    *func = 0;
 | 
						|
    p = strtok(NULL, ":");
 | 
						|
    if (p == NULL || *p == 0) {
 | 
						|
	free(s);
 | 
						|
	return TRUE;
 | 
						|
    }
 | 
						|
    for (i = 0; p[i] != 0; i++) {
 | 
						|
	if (!isdigit(p[i])) {
 | 
						|
	    free(s);
 | 
						|
	    return FALSE;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    *func = atoi(p);
 | 
						|
    free(s);
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Compare a BUS ID string with a PCI bus id.  Return TRUE if they match.
 | 
						|
 */
 | 
						|
 | 
						|
Bool
 | 
						|
xf86ComparePciBusString(const char *busID, int bus, int device, int func)
 | 
						|
{
 | 
						|
    int ibus, idevice, ifunc;
 | 
						|
 | 
						|
    if (xf86ParsePciBusString(busID, &ibus, &idevice, &ifunc)) {
 | 
						|
	return bus == ibus && device == idevice && func == ifunc;
 | 
						|
    } else {
 | 
						|
	return FALSE;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * xf86IsPrimaryPci() -- return TRUE if primary device
 | 
						|
 * is PCI and bus, dev and func numbers match.
 | 
						|
 */
 | 
						|
 
 | 
						|
Bool
 | 
						|
xf86IsPrimaryPci(struct pci_device *pPci)
 | 
						|
{
 | 
						|
    return ((primaryBus.type == BUS_PCI) && (pPci == primaryBus.id.pci));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * xf86GetPciInfoForEntity() -- Get the pciVideoRec of entity.
 | 
						|
 */
 | 
						|
struct pci_device *
 | 
						|
xf86GetPciInfoForEntity(int entityIndex)
 | 
						|
{
 | 
						|
    EntityPtr p;
 | 
						|
    
 | 
						|
    if (entityIndex >= xf86NumEntities)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    p = xf86Entities[entityIndex];
 | 
						|
    return (p->bus.type == BUS_PCI) ? p->bus.id.pci : NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * xf86CheckPciMemBase() checks that the memory base value matches one of the
 | 
						|
 * PCI base address register values for the given PCI device.
 | 
						|
 */
 | 
						|
Bool
 | 
						|
xf86CheckPciMemBase( struct pci_device * pPci, memType base )
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; i < 6; i++)
 | 
						|
	if (base == pPci->regions[i].base_addr)
 | 
						|
	    return TRUE;
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Check if the slot requested is free.  If it is already in use, return FALSE.
 | 
						|
 */
 | 
						|
 | 
						|
Bool
 | 
						|
xf86CheckPciSlot(const struct pci_device *d)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; i < xf86NumEntities; i++) {
 | 
						|
	const EntityPtr p = xf86Entities[i];
 | 
						|
 | 
						|
	if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
 | 
						|
	    return FALSE;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
#define END_OF_MATCHES(m) \
 | 
						|
    (((m).vendor_id == 0) && ((m).device_id == 0) && ((m).subvendor_id == 0))
 | 
						|
 | 
						|
Bool
 | 
						|
xf86PciAddMatchingDev(DriverPtr drvp)
 | 
						|
{
 | 
						|
    const struct pci_id_match * const devices = drvp->supported_devices;
 | 
						|
    int j;
 | 
						|
    struct pci_device *pPci;
 | 
						|
    struct pci_device_iterator *iter;
 | 
						|
    int numFound = 0;
 | 
						|
 | 
						|
 | 
						|
    iter = pci_id_match_iterator_create(NULL);
 | 
						|
    while ((pPci = pci_device_next(iter)) != NULL) {
 | 
						|
    /* Determine if this device is supported by the driver.  If it is,
 | 
						|
     * add it to the list of devices to configure.
 | 
						|
     */
 | 
						|
    for (j = 0 ; ! END_OF_MATCHES(devices[j]) ; j++) {
 | 
						|
        if ( PCI_ID_COMPARE( devices[j].vendor_id, pPci->vendor_id )
 | 
						|
         && PCI_ID_COMPARE( devices[j].device_id, pPci->device_id )
 | 
						|
         && ((devices[j].device_class_mask & pPci->device_class)
 | 
						|
             == devices[j].device_class) ) {
 | 
						|
        if (xf86CheckPciSlot(pPci)) {
 | 
						|
            GDevPtr pGDev = xf86AddBusDeviceToConfigure(
 | 
						|
                    drvp->driverName, BUS_PCI, pPci, -1);
 | 
						|
            if (pGDev != NULL) {
 | 
						|
            /* After configure pass 1, chipID and chipRev are
 | 
						|
             * treated as over-rides, so clobber them here.
 | 
						|
             */
 | 
						|
            pGDev->chipID = -1;
 | 
						|
            pGDev->chipRev = -1;
 | 
						|
            }
 | 
						|
 | 
						|
            numFound++;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    }
 | 
						|
 | 
						|
    pci_iterator_destroy(iter);
 | 
						|
 | 
						|
    return numFound != 0;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86PciProbeDev(DriverPtr drvp)
 | 
						|
{
 | 
						|
    int i, j;
 | 
						|
    struct pci_device * pPci;
 | 
						|
    Bool foundScreen = FALSE;
 | 
						|
    const struct pci_id_match * const devices = drvp->supported_devices;
 | 
						|
    GDevPtr *devList;
 | 
						|
    const unsigned numDevs = xf86MatchDevice(drvp->driverName, & devList);
 | 
						|
 | 
						|
    for ( i = 0 ; i < numDevs ; i++ ) {
 | 
						|
       struct pci_device_iterator *iter;
 | 
						|
       unsigned device_id;
 | 
						|
 | 
						|
 | 
						|
       /* Find the pciVideoRec associated with this device section.
 | 
						|
        */
 | 
						|
       iter = pci_id_match_iterator_create(NULL);
 | 
						|
       while ((pPci = pci_device_next(iter)) != NULL) {
 | 
						|
           if (devList[i]->busID && *devList[i]->busID) {
 | 
						|
               if (xf86ComparePciBusString(devList[i]->busID,
 | 
						|
                                           ((pPci->domain << 8)
 | 
						|
                                            | pPci->bus),
 | 
						|
                                           pPci->dev,
 | 
						|
                                           pPci->func)) {
 | 
						|
                   break;
 | 
						|
               }
 | 
						|
           }
 | 
						|
           else if (xf86IsPrimaryPci(pPci)) {
 | 
						|
               break;
 | 
						|
           }
 | 
						|
       }
 | 
						|
 | 
						|
       pci_iterator_destroy(iter);
 | 
						|
 | 
						|
       if (pPci == NULL) {
 | 
						|
           continue;
 | 
						|
       }
 | 
						|
       device_id = (devList[i]->chipID > 0)
 | 
						|
         ? devList[i]->chipID : pPci->device_id;
 | 
						|
 | 
						|
 | 
						|
       /* Once the pciVideoRec is found, determine if the device is supported
 | 
						|
        * by the driver.  If it is, probe it!
 | 
						|
        */
 | 
						|
       for ( j = 0 ; ! END_OF_MATCHES( devices[j] ) ; j++ ) {
 | 
						|
           if ( PCI_ID_COMPARE( devices[j].vendor_id, pPci->vendor_id )
 | 
						|
                && PCI_ID_COMPARE( devices[j].device_id, device_id )
 | 
						|
                && ((devices[j].device_class_mask & pPci->device_class)
 | 
						|
                     == devices[j].device_class) ) {
 | 
						|
               int  entry;
 | 
						|
 | 
						|
               /* 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.
 | 
						|
                *
 | 
						|
                * FIXME Need to make sure that two different drivers don't
 | 
						|
                * FIXME claim the same screen > 0 instance.
 | 
						|
                */
 | 
						|
               if ((devList[i]->screen == 0) && !xf86CheckPciSlot(pPci))
 | 
						|
                   continue;
 | 
						|
 | 
						|
               DebugF("%s: card at %d:%d:%d is claimed by a Device section\n",
 | 
						|
                      drvp->driverName, pPci->bus, pPci->dev, pPci->func);
 | 
						|
 | 
						|
               /* Allocate an entry in the lists to be returned */
 | 
						|
               entry = xf86ClaimPciSlot(pPci, drvp, device_id,
 | 
						|
                                         devList[i], devList[i]->active);
 | 
						|
 | 
						|
               if ((entry == -1) && (devList[i]->screen > 0)) {
 | 
						|
                   unsigned k;
 | 
						|
 | 
						|
                   for (k = 0; k < xf86NumEntities; k++ ) {
 | 
						|
                       EntityPtr pEnt = xf86Entities[k];
 | 
						|
                       if (pEnt->bus.type != BUS_PCI)
 | 
						|
                           continue;
 | 
						|
                       if (pEnt->bus.id.pci == pPci) {
 | 
						|
                           entry = k;
 | 
						|
                           xf86AddDevToEntity(k, devList[i]);
 | 
						|
                           break;
 | 
						|
                       }
 | 
						|
                   }
 | 
						|
               }
 | 
						|
 | 
						|
               if (entry != -1) {
 | 
						|
                   if ((*drvp->PciProbe)(drvp, entry, pPci,
 | 
						|
                                         devices[j].match_data)) {
 | 
						|
                       foundScreen = TRUE;
 | 
						|
                   } else
 | 
						|
                       xf86UnclaimPciSlot(pPci);
 | 
						|
               }
 | 
						|
 | 
						|
               break;
 | 
						|
           }
 | 
						|
       }
 | 
						|
    }
 | 
						|
    free(devList);
 | 
						|
 | 
						|
    return foundScreen;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xf86PciIsolateDevice(char *argument)
 | 
						|
{
 | 
						|
    int bus, device, func;
 | 
						|
 | 
						|
    if (sscanf(argument, "PCI:%d:%d:%d", &bus, &device, &func) == 3) {
 | 
						|
        xf86IsolateDevice.domain = PCI_DOM_FROM_BUS(bus);
 | 
						|
        xf86IsolateDevice.bus = PCI_BUS_NO_DOMAIN(bus);
 | 
						|
        xf86IsolateDevice.dev = device;
 | 
						|
        xf86IsolateDevice.func = func;
 | 
						|
    } 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__ */
 | 
						|
 | 
						|
/**
 | 
						|
 *  @return The numbers of found devices that match with the current system
 | 
						|
 *  drivers.
 | 
						|
 */
 | 
						|
int
 | 
						|
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);
 | 
						|
#ifdef __linux__
 | 
						|
    if (info)
 | 
						|
	matchDriverFromFiles(matches, info->vendor_id, info->device_id);
 | 
						|
#endif
 | 
						|
 | 
						|
    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);
 | 
						|
    }
 | 
						|
 | 
						|
    return i;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86PciConfigure(void *busData, struct pci_device *pDev)
 | 
						|
{
 | 
						|
    struct pci_device * pVideo = NULL;
 | 
						|
 | 
						|
    pVideo = (struct pci_device *) busData;
 | 
						|
    if (pDev &&
 | 
						|
        (pDev->domain == pVideo->domain) &&
 | 
						|
        (pDev->bus == pVideo->bus) &&
 | 
						|
        (pDev->dev == pVideo->dev) &&
 | 
						|
        (pDev->func == pVideo->func))
 | 
						|
        return 0;
 | 
						|
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xf86PciConfigureNewDev(void *busData, struct pci_device *pVideo,
 | 
						|
                         GDevRec *GDev, int *chipset)
 | 
						|
{
 | 
						|
    char busnum[8];
 | 
						|
 | 
						|
    pVideo = (struct pci_device *) busData;
 | 
						|
 | 
						|
    GDev->busID = xnfalloc(16);
 | 
						|
    xf86FormatPciBusNumber(pVideo->bus, busnum);
 | 
						|
    sprintf(GDev->busID, "PCI:%s:%d:%d", busnum, pVideo->dev, pVideo->func);
 | 
						|
 | 
						|
    GDev->chipID = pVideo->device_id;
 | 
						|
    GDev->chipRev = pVideo->revision;
 | 
						|
 | 
						|
    if (*chipset < 0)
 | 
						|
        *chipset = (pVideo->vendor_id << 16) | pVideo->device_id;
 | 
						|
}
 |