You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1476 lines
45 KiB
C
1476 lines
45 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"
|
|
|
|
#define PCI_VENDOR_GENERIC 0x00FF
|
|
|
|
/* Bus-specific globals */
|
|
int pciSlotClaimed = 0;
|
|
|
|
#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
|
|
};
|
|
|
|
/*
|
|
* 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 = xnfreallocarray(xf86PciVideoInfo,
|
|
num + 1,
|
|
sizeof(struct pci_device *));
|
|
xf86PciVideoInfo[num] = NULL;
|
|
xf86PciVideoInfo[num - 1] = info;
|
|
|
|
pci_device_probe(info);
|
|
if (primaryBus.type == BUS_NONE && pci_device_is_boot_vga(info)) {
|
|
primaryBus.type = BUS_PCI;
|
|
primaryBus.id.pci = info;
|
|
}
|
|
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->bus, info->domain, 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++;
|
|
|
|
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, GDevPtr dev)
|
|
{
|
|
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? */
|
|
xf86RemoveDevFromEntity(i, dev);
|
|
pciSlotClaimed--;
|
|
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)
|
|
{
|
|
/* Add max. 1 screen for the IgnorePrimary fallback path */
|
|
if (xf86ProbeIgnorePrimary && xf86NumScreens == 0)
|
|
return TRUE;
|
|
|
|
if (primaryBus.type == BUS_PCI)
|
|
return pPci == primaryBus.id.pci;
|
|
#ifdef XSERVER_PLATFORM_BUS
|
|
if (primaryBus.type == BUS_PLATFORM)
|
|
if (primaryBus.id.plat->pdev)
|
|
if (MATCH_PCI_DEVICES(primaryBus.id.plat->pdev, pPci))
|
|
return TRUE;
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* xf86GetPciInfoForEntity() -- Get the pciVideoRec of entity.
|
|
*/
|
|
struct pci_device *
|
|
xf86GetPciInfoForEntity(int entityIndex)
|
|
{
|
|
EntityPtr p;
|
|
|
|
if (entityIndex >= xf86NumEntities)
|
|
return NULL;
|
|
|
|
p = xf86Entities[entityIndex];
|
|
switch (p->bus.type) {
|
|
case BUS_PCI:
|
|
return p->bus.id.pci;
|
|
case BUS_PLATFORM:
|
|
return p->bus.id.plat->pdev;
|
|
default:
|
|
break;
|
|
}
|
|
return 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;
|
|
}
|
|
#ifdef XSERVER_PLATFORM_BUS
|
|
if ((p->bus.type == BUS_PLATFORM) && (p->bus.id.plat->pdev)) {
|
|
struct pci_device *ud = p->bus.id.plat->pdev;
|
|
if (MATCH_PCI_DEVICES(ud, d))
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
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, devList[i]);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
free(devList);
|
|
|
|
return foundScreen;
|
|
}
|
|
|
|
void
|
|
xf86PciIsolateDevice(const 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 indices 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 = xnfallocarray(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->bus, pPci->domain, 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 = xnfreallocarray(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, void *private)
|
|
{
|
|
ScrnInfoPtr pScrn;
|
|
|
|
if ((pScrn = xf86FindScreenForEntity(pEnt->index)))
|
|
xf86RemoveEntityFromScreen(pScrn, pEnt->index);
|
|
}
|
|
|
|
ScrnInfoPtr
|
|
xf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex,
|
|
PciChipsets * p_chip, void *dummy, EntityProc init,
|
|
EntityProc enter, EntityProc leave, void *private)
|
|
{
|
|
EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex);
|
|
|
|
if (dummy || init || enter || leave)
|
|
FatalError("Legacy entity access functions are unsupported\n");
|
|
|
|
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);
|
|
|
|
return pScrn;
|
|
}
|
|
|
|
void
|
|
xf86VideoPtrToDriverList(struct pci_device *dev, XF86MatchedDrivers *md)
|
|
{
|
|
int i;
|
|
|
|
/* Add more entries here if we ever return more than 4 drivers for
|
|
any device */
|
|
const 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:
|
|
switch (dev->device_id)
|
|
{
|
|
/* Intel i740 */
|
|
case 0x00d1:
|
|
case 0x7800:
|
|
driverList[0] = "i740";
|
|
break;
|
|
/* GMA500/Poulsbo */
|
|
case 0x8108:
|
|
case 0x8109:
|
|
/* Try psb driver on Poulsbo - if available */
|
|
driverList[0] = "psb";
|
|
driverList[1] = "psb_drv";
|
|
break;
|
|
/* GMA600/Oaktrail */
|
|
case 0x4100:
|
|
case 0x4101:
|
|
case 0x4102:
|
|
case 0x4103:
|
|
case 0x4104:
|
|
case 0x4105:
|
|
case 0x4106:
|
|
case 0x4107:
|
|
/* Atom E620/Oaktrail */
|
|
case 0x4108:
|
|
/* Medfield */
|
|
case 0x0130:
|
|
case 0x0131:
|
|
case 0x0132:
|
|
case 0x0133:
|
|
case 0x0134:
|
|
case 0x0135:
|
|
case 0x0136:
|
|
case 0x0137:
|
|
/* GMA 3600/CDV */
|
|
case 0x0be0:
|
|
case 0x0be1:
|
|
case 0x0be2:
|
|
case 0x0be3:
|
|
case 0x0be4:
|
|
case 0x0be5:
|
|
case 0x0be6:
|
|
case 0x0be7:
|
|
case 0x0be8:
|
|
case 0x0be9:
|
|
case 0x0bea:
|
|
case 0x0beb:
|
|
case 0x0bec:
|
|
case 0x0bed:
|
|
case 0x0bee:
|
|
case 0x0bef:
|
|
/* Use fbdev/vesa driver on Oaktrail, Medfield, CDV */
|
|
break;
|
|
default:
|
|
driverList[0] = "intel";
|
|
break;
|
|
}
|
|
break;
|
|
case 0x102b:
|
|
driverList[0] = "mga";
|
|
break;
|
|
case 0x10c8:
|
|
driverList[0] = "neomagic";
|
|
break;
|
|
case 0x10de:
|
|
case 0x12d2:
|
|
{
|
|
int idx = 0;
|
|
|
|
#if defined(__linux__) || defined(__NetBSD__)
|
|
driverList[idx++] = "nouveau";
|
|
#endif
|
|
driverList[idx++] = "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; driverList[i] != NULL; i++) {
|
|
xf86AddMatchedDriver(md, driverList[i]);
|
|
}
|
|
}
|
|
|
|
#ifdef __linux__
|
|
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;
|
|
}
|
|
|
|
/* 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 */
|
|
void
|
|
xf86MatchDriverFromFiles(uint16_t match_vendor, uint16_t match_chip,
|
|
XF86MatchedDrivers *md)
|
|
{
|
|
DIR *idsdir;
|
|
FILE *fp;
|
|
struct dirent *direntry;
|
|
char *line = NULL, *tmpMatch;
|
|
size_t len;
|
|
ssize_t read;
|
|
char path_name[512], vendor_str[5], chip_str[5];
|
|
uint16_t vendor, chip;
|
|
int 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 */
|
|
snprintf(path_name, sizeof(path_name), "%s/%s",
|
|
PCI_TXT_IDS_PATH, direntry->d_name);
|
|
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])) {
|
|
strlcpy(vendor_str, line, sizeof(vendor_str));
|
|
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 */
|
|
strlcpy(chip_str, &line[4], sizeof(chip_str));
|
|
chip = (int) strtol(chip_str, NULL, 16);
|
|
}
|
|
}
|
|
if (vendor == match_vendor && chip == match_chip) {
|
|
tmpMatch =
|
|
(char *) malloc(sizeof(char) *
|
|
strlen(direntry->d_name) - 3);
|
|
if (!tmpMatch) {
|
|
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] == '.') {
|
|
tmpMatch[j] = '\0';
|
|
break;
|
|
}
|
|
else {
|
|
tmpMatch[j] = direntry->d_name[j];
|
|
}
|
|
}
|
|
xf86AddMatchedDriver(md, tmpMatch);
|
|
xf86Msg(X_INFO, "Matched %s from file name %s\n",
|
|
tmpMatch, direntry->d_name);
|
|
free(tmpMatch);
|
|
}
|
|
}
|
|
else {
|
|
/* TODO Handle driver overrides here */
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
direntry = readdir(idsdir);
|
|
}
|
|
end:
|
|
free(line);
|
|
closedir(idsdir);
|
|
}
|
|
#endif /* __linux__ */
|
|
|
|
void
|
|
xf86PciMatchDriver(XF86MatchedDrivers *md)
|
|
{
|
|
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)
|
|
xf86MatchDriverFromFiles(info->vendor_id, info->device_id, md);
|
|
#endif
|
|
|
|
if (info != NULL) {
|
|
xf86VideoPtrToDriverList(info, md);
|
|
}
|
|
}
|
|
|
|
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];
|
|
char *tmp;
|
|
|
|
pVideo = (struct pci_device *) busData;
|
|
|
|
snprintf(busnum, sizeof(busnum), "%d", pVideo->bus);
|
|
|
|
XNFasprintf(&tmp, "PCI:%s:%d:%d",
|
|
busnum, pVideo->dev, pVideo->func);
|
|
GDev->busID = tmp;
|
|
|
|
GDev->chipID = pVideo->device_id;
|
|
GDev->chipRev = pVideo->revision;
|
|
|
|
if (*chipset < 0)
|
|
*chipset = (pVideo->vendor_id << 16) | pVideo->device_id;
|
|
}
|
|
|
|
char *
|
|
DRICreatePCIBusID(const struct pci_device *dev)
|
|
{
|
|
char *busID;
|
|
|
|
if (asprintf(&busID, "pci:%04x:%02x:%02x.%d",
|
|
dev->domain, dev->bus, dev->dev, dev->func) == -1)
|
|
return NULL;
|
|
|
|
return busID;
|
|
}
|