1706f2543Smrg/*
2706f2543Smrg * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Software"),
6706f2543Smrg * to deal in the Software without restriction, including without limitation
7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, subject to the following conditions:
10706f2543Smrg *
11706f2543Smrg * The above copyright notice and this permission notice shall be included in
12706f2543Smrg * all copies or substantial portions of the Software.
13706f2543Smrg *
14706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17706f2543Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20706f2543Smrg * OTHER DEALINGS IN THE SOFTWARE.
21706f2543Smrg *
22706f2543Smrg * Except as contained in this notice, the name of the copyright holder(s)
23706f2543Smrg * and author(s) shall not be used in advertising or otherwise to promote
24706f2543Smrg * the sale, use or other dealings in this Software without prior written
25706f2543Smrg * authorization from the copyright holder(s) and author(s).
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg/*
29706f2543Smrg * This file contains the interfaces to the bus-specific code
30706f2543Smrg */
31706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
32706f2543Smrg#include <xorg-config.h>
33706f2543Smrg#endif
34706f2543Smrg
35706f2543Smrg#include <ctype.h>
36706f2543Smrg#include <stdlib.h>
37706f2543Smrg#include <unistd.h>
38706f2543Smrg#include <X11/X.h>
39706f2543Smrg#include <pciaccess.h>
40706f2543Smrg#include "os.h"
41706f2543Smrg#include "Pci.h"
42706f2543Smrg#include "xf86.h"
43706f2543Smrg#include "xf86Priv.h"
44706f2543Smrg#include "dirent.h" /* DIR, FILE type definitions */
45706f2543Smrg
46706f2543Smrg/* Bus-specific headers */
47706f2543Smrg#include "xf86Bus.h"
48706f2543Smrg
49706f2543Smrg#define XF86_OS_PRIVS
50706f2543Smrg#include "xf86_OSproc.h"
51706f2543Smrg
52706f2543Smrg
53706f2543Smrg/* Bus-specific globals */
54706f2543SmrgBool pciSlotClaimed = FALSE;
55706f2543Smrg
56706f2543Smrg#define PCIINFOCLASSES(c) \
57706f2543Smrg    ( (((c) & 0x00ff0000) == (PCI_CLASS_PREHISTORIC << 16)) \
58706f2543Smrg      || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \
59706f2543Smrg      || ((((c) & 0x00ffff00) \
60706f2543Smrg	   == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) \
61706f2543Smrg      || ((((c) & 0x00ffff00) \
62706f2543Smrg	   == ((PCI_CLASS_PROCESSOR << 16) | (PCI_SUBCLASS_PROCESSOR_COPROC << 8)))) )
63706f2543Smrg
64706f2543Smrg/*
65706f2543Smrg * PCI classes that have messages printed always.  The others are only
66706f2543Smrg * have a message printed when the vendor/dev IDs are recognised.
67706f2543Smrg */
68706f2543Smrg#define PCIALWAYSPRINTCLASSES(c) \
69706f2543Smrg    ( (((c) & 0x00ffff00) \
70706f2543Smrg       == ((PCI_CLASS_PREHISTORIC << 16) | (PCI_SUBCLASS_PREHISTORIC_VGA << 8))) \
71706f2543Smrg      || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \
72706f2543Smrg      || ((((c) & 0x00ffff00) \
73706f2543Smrg	   == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) )
74706f2543Smrg
75706f2543Smrg#define IS_VGA(c) \
76706f2543Smrg    (((c) & 0x00ffff00) \
77706f2543Smrg	 == ((PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8)))
78706f2543Smrg
79706f2543Smrg
80706f2543Smrgstatic struct pci_slot_match xf86IsolateDevice = {
81706f2543Smrg    PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0
82706f2543Smrg};
83706f2543Smrg
84706f2543Smrgvoid
85706f2543Smrgxf86FormatPciBusNumber(int busnum, char *buffer)
86706f2543Smrg{
87706f2543Smrg    /* 'buffer' should be at least 8 characters long */
88706f2543Smrg    if (busnum < 256)
89706f2543Smrg	sprintf(buffer, "%d", busnum);
90706f2543Smrg    else
91706f2543Smrg	sprintf(buffer, "%d@%d", busnum & 0x00ff, busnum >> 8);
92706f2543Smrg}
93706f2543Smrg
94706f2543Smrg/*
95706f2543Smrg * xf86Bus.c interface
96706f2543Smrg */
97706f2543Smrg
98706f2543Smrgvoid
99706f2543Smrgxf86PciProbe(void)
100706f2543Smrg{
101706f2543Smrg    int i = 0, k;
102706f2543Smrg    int num = 0;
103706f2543Smrg    struct pci_device *info;
104706f2543Smrg    struct pci_device_iterator *iter;
105706f2543Smrg    struct pci_device ** xf86PciVideoInfo = NULL;
106706f2543Smrg
107706f2543Smrg
108706f2543Smrg    if (!xf86scanpci()) {
109706f2543Smrg	xf86PciVideoInfo = NULL;
110706f2543Smrg	return;
111706f2543Smrg    }
112706f2543Smrg
113706f2543Smrg    iter = pci_slot_match_iterator_create(& xf86IsolateDevice);
114706f2543Smrg    while ((info = pci_device_next(iter)) != NULL) {
115706f2543Smrg	if (PCIINFOCLASSES(info->device_class)) {
116706f2543Smrg	    num++;
117706f2543Smrg	    xf86PciVideoInfo = xnfrealloc(xf86PciVideoInfo,
118706f2543Smrg					  (sizeof(struct pci_device *)
119706f2543Smrg					   * (num + 1)));
120706f2543Smrg	    xf86PciVideoInfo[num] = NULL;
121706f2543Smrg	    xf86PciVideoInfo[num - 1] = info;
122706f2543Smrg
123706f2543Smrg	    pci_device_probe(info);
124706f2543Smrg#ifdef HAVE_PCI_DEVICE_IS_BOOT_VGA
125706f2543Smrg	    if (pci_device_is_boot_vga(info)) {
126706f2543Smrg                primaryBus.type = BUS_PCI;
127706f2543Smrg                primaryBus.id.pci = info;
128706f2543Smrg            }
129706f2543Smrg#endif
130706f2543Smrg	    info->user_data = 0;
131706f2543Smrg	}
132706f2543Smrg    }
133706f2543Smrg    free(iter);
134706f2543Smrg
135706f2543Smrg    /* If we haven't found a primary device try a different heuristic */
136706f2543Smrg    if (primaryBus.type == BUS_NONE && num) {
137706f2543Smrg	for (i = 0; i < num; i++) {
138706f2543Smrg	    uint16_t  command;
139706f2543Smrg
140706f2543Smrg	    info = xf86PciVideoInfo[i];
141706f2543Smrg	    pci_device_cfg_read_u16(info, & command, 4);
142706f2543Smrg
143706f2543Smrg	    if ((command & PCI_CMD_MEM_ENABLE)
144706f2543Smrg		&& ((num == 1) || IS_VGA(info->device_class))) {
145706f2543Smrg		if (primaryBus.type == BUS_NONE) {
146706f2543Smrg		    primaryBus.type = BUS_PCI;
147706f2543Smrg		    primaryBus.id.pci = info;
148706f2543Smrg		} else {
149706f2543Smrg		    xf86Msg(X_NOTICE,
150706f2543Smrg			    "More than one possible primary device found\n");
151706f2543Smrg		    primaryBus.type ^= (BusType)(-1);
152706f2543Smrg		}
153706f2543Smrg	    }
154706f2543Smrg	}
155706f2543Smrg    }
156706f2543Smrg
157706f2543Smrg    /* Print a summary of the video devices found */
158706f2543Smrg    for (k = 0; k < num; k++) {
159706f2543Smrg	const char *prim = " ";
160706f2543Smrg	Bool memdone = FALSE, iodone = FALSE;
161706f2543Smrg
162706f2543Smrg
163706f2543Smrg	info = xf86PciVideoInfo[k];
164706f2543Smrg
165706f2543Smrg	if (!PCIALWAYSPRINTCLASSES(info->device_class))
166706f2543Smrg	    continue;
167706f2543Smrg
168706f2543Smrg	if (xf86IsPrimaryPci(info))
169706f2543Smrg	    prim = "*";
170706f2543Smrg
171706f2543Smrg	xf86Msg(X_PROBED, "PCI:%s(%u:%u:%u:%u) %04x:%04x:%04x:%04x ", prim,
172706f2543Smrg		info->domain, info->bus, info->dev, info->func,
173706f2543Smrg		info->vendor_id, info->device_id,
174706f2543Smrg		info->subvendor_id, info->subdevice_id);
175706f2543Smrg
176706f2543Smrg	xf86ErrorF("rev %d", info->revision);
177706f2543Smrg
178706f2543Smrg	for (i = 0; i < 6; i++) {
179706f2543Smrg	    struct pci_mem_region * r = & info->regions[i];
180706f2543Smrg
181706f2543Smrg	    if ( r->size && ! r->is_IO ) {
182706f2543Smrg		if (!memdone) {
183706f2543Smrg		    xf86ErrorF(", Mem @ ");
184706f2543Smrg		    memdone = TRUE;
185706f2543Smrg		} else
186706f2543Smrg		    xf86ErrorF(", ");
187706f2543Smrg		xf86ErrorF("0x%08lx/%ld", (long)r->base_addr, (long)r->size);
188706f2543Smrg	    }
189706f2543Smrg	}
190706f2543Smrg
191706f2543Smrg	for (i = 0; i < 6; i++) {
192706f2543Smrg	    struct pci_mem_region * r = & info->regions[i];
193706f2543Smrg
194706f2543Smrg	    if ( r->size && r->is_IO ) {
195706f2543Smrg		if (!iodone) {
196706f2543Smrg		    xf86ErrorF(", I/O @ ");
197706f2543Smrg		    iodone = TRUE;
198706f2543Smrg		} else
199706f2543Smrg		    xf86ErrorF(", ");
200706f2543Smrg		xf86ErrorF("0x%08lx/%ld", (long)r->base_addr, (long)r->size);
201706f2543Smrg	    }
202706f2543Smrg	}
203706f2543Smrg
204706f2543Smrg	if ( info->rom_size ) {
205706f2543Smrg	    xf86ErrorF(", BIOS @ 0x\?\?\?\?\?\?\?\?/%ld", (long)info->rom_size);
206706f2543Smrg	}
207706f2543Smrg
208706f2543Smrg	xf86ErrorF("\n");
209706f2543Smrg    }
210706f2543Smrg    free(xf86PciVideoInfo);
211706f2543Smrg}
212706f2543Smrg
213706f2543Smrg/*
214706f2543Smrg * If the slot requested is already in use, return -1.
215706f2543Smrg * Otherwise, claim the slot for the screen requesting it.
216706f2543Smrg */
217706f2543Smrg
218706f2543Smrgint
219706f2543Smrgxf86ClaimPciSlot(struct pci_device * d, DriverPtr drvp,
220706f2543Smrg		 int chipset, GDevPtr dev, Bool active)
221706f2543Smrg{
222706f2543Smrg    EntityPtr p = NULL;
223706f2543Smrg    int num;
224706f2543Smrg
225706f2543Smrg    if (xf86CheckPciSlot(d)) {
226706f2543Smrg	num = xf86AllocateEntity();
227706f2543Smrg	p = xf86Entities[num];
228706f2543Smrg	p->driver = drvp;
229706f2543Smrg	p->chipset = chipset;
230706f2543Smrg	p->bus.type = BUS_PCI;
231706f2543Smrg	p->bus.id.pci = d;
232706f2543Smrg	p->active = active;
233706f2543Smrg	p->inUse = FALSE;
234706f2543Smrg	if (dev)
235706f2543Smrg            xf86AddDevToEntity(num, dev);
236706f2543Smrg	pciSlotClaimed = TRUE;
237706f2543Smrg
238706f2543Smrg	if (active) {
239706f2543Smrg	    /* Map in this domain's I/O space */
240706f2543Smrg	   p->domainIO = xf86MapLegacyIO(d);
241706f2543Smrg	}
242706f2543Smrg
243706f2543Smrg 	return num;
244706f2543Smrg    } else
245706f2543Smrg 	return -1;
246706f2543Smrg}
247706f2543Smrg
248706f2543Smrg/*
249706f2543Smrg * Unclaim PCI slot, e.g. if probing failed, so that a different driver can claim.
250706f2543Smrg */
251706f2543Smrgvoid
252706f2543Smrgxf86UnclaimPciSlot(struct pci_device *d)
253706f2543Smrg{
254706f2543Smrg    int i;
255706f2543Smrg
256706f2543Smrg    for (i = 0; i < xf86NumEntities; i++) {
257706f2543Smrg	const EntityPtr p = xf86Entities[i];
258706f2543Smrg
259706f2543Smrg	if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
260706f2543Smrg	    /* Probably the slot should be deallocated? */
261706f2543Smrg	    p->bus.type = BUS_NONE;
262706f2543Smrg	    return;
263706f2543Smrg	}
264706f2543Smrg    }
265706f2543Smrg}
266706f2543Smrg
267706f2543Smrg/*
268706f2543Smrg * Parse a BUS ID string, and return the PCI bus parameters if it was
269706f2543Smrg * in the correct format for a PCI bus id.
270706f2543Smrg */
271706f2543Smrg
272706f2543SmrgBool
273706f2543Smrgxf86ParsePciBusString(const char *busID, int *bus, int *device, int *func)
274706f2543Smrg{
275706f2543Smrg    /*
276706f2543Smrg     * The format is assumed to be "bus[@domain]:device[:func]", where domain,
277706f2543Smrg     * bus, device and func are decimal integers.  domain and func may be
278706f2543Smrg     * omitted and assumed to be zero, although doing this isn't encouraged.
279706f2543Smrg     */
280706f2543Smrg
281706f2543Smrg    char *p, *s, *d;
282706f2543Smrg    const char *id;
283706f2543Smrg    int i;
284706f2543Smrg
285706f2543Smrg    if (StringToBusType(busID, &id) != BUS_PCI)
286706f2543Smrg	return FALSE;
287706f2543Smrg
288706f2543Smrg    s = xstrdup(id);
289706f2543Smrg    p = strtok(s, ":");
290706f2543Smrg    if (p == NULL || *p == 0) {
291706f2543Smrg	free(s);
292706f2543Smrg	return FALSE;
293706f2543Smrg    }
294706f2543Smrg    d = strpbrk(p, "@");
295706f2543Smrg    if (d != NULL) {
296706f2543Smrg	*(d++) = 0;
297706f2543Smrg	for (i = 0; d[i] != 0; i++) {
298706f2543Smrg	    if (!isdigit(d[i])) {
299706f2543Smrg		free(s);
300706f2543Smrg		return FALSE;
301706f2543Smrg	    }
302706f2543Smrg	}
303706f2543Smrg    }
304706f2543Smrg    for (i = 0; p[i] != 0; i++) {
305706f2543Smrg	if (!isdigit(p[i])) {
306706f2543Smrg	    free(s);
307706f2543Smrg	    return FALSE;
308706f2543Smrg	}
309706f2543Smrg    }
310706f2543Smrg    *bus = atoi(p);
311706f2543Smrg    if (d != NULL && *d != 0)
312706f2543Smrg	*bus += atoi(d) << 8;
313706f2543Smrg    p = strtok(NULL, ":");
314706f2543Smrg    if (p == NULL || *p == 0) {
315706f2543Smrg	free(s);
316706f2543Smrg	return FALSE;
317706f2543Smrg    }
318706f2543Smrg    for (i = 0; p[i] != 0; i++) {
319706f2543Smrg	if (!isdigit(p[i])) {
320706f2543Smrg	    free(s);
321706f2543Smrg	    return FALSE;
322706f2543Smrg	}
323706f2543Smrg    }
324706f2543Smrg    *device = atoi(p);
325706f2543Smrg    *func = 0;
326706f2543Smrg    p = strtok(NULL, ":");
327706f2543Smrg    if (p == NULL || *p == 0) {
328706f2543Smrg	free(s);
329706f2543Smrg	return TRUE;
330706f2543Smrg    }
331706f2543Smrg    for (i = 0; p[i] != 0; i++) {
332706f2543Smrg	if (!isdigit(p[i])) {
333706f2543Smrg	    free(s);
334706f2543Smrg	    return FALSE;
335706f2543Smrg	}
336706f2543Smrg    }
337706f2543Smrg    *func = atoi(p);
338706f2543Smrg    free(s);
339706f2543Smrg    return TRUE;
340706f2543Smrg}
341706f2543Smrg
342706f2543Smrg/*
343706f2543Smrg * Compare a BUS ID string with a PCI bus id.  Return TRUE if they match.
344706f2543Smrg */
345706f2543Smrg
346706f2543SmrgBool
347706f2543Smrgxf86ComparePciBusString(const char *busID, int bus, int device, int func)
348706f2543Smrg{
349706f2543Smrg    int ibus, idevice, ifunc;
350706f2543Smrg
351706f2543Smrg    if (xf86ParsePciBusString(busID, &ibus, &idevice, &ifunc)) {
352706f2543Smrg	return bus == ibus && device == idevice && func == ifunc;
353706f2543Smrg    } else {
354706f2543Smrg	return FALSE;
355706f2543Smrg    }
356706f2543Smrg}
357706f2543Smrg
358706f2543Smrg/*
359706f2543Smrg * xf86IsPrimaryPci() -- return TRUE if primary device
360706f2543Smrg * is PCI and bus, dev and func numbers match.
361706f2543Smrg */
362706f2543Smrg
363706f2543SmrgBool
364706f2543Smrgxf86IsPrimaryPci(struct pci_device *pPci)
365706f2543Smrg{
366706f2543Smrg    return ((primaryBus.type == BUS_PCI) && (pPci == primaryBus.id.pci));
367706f2543Smrg}
368706f2543Smrg
369706f2543Smrg/*
370706f2543Smrg * xf86GetPciInfoForEntity() -- Get the pciVideoRec of entity.
371706f2543Smrg */
372706f2543Smrgstruct pci_device *
373706f2543Smrgxf86GetPciInfoForEntity(int entityIndex)
374706f2543Smrg{
375706f2543Smrg    EntityPtr p;
376706f2543Smrg
377706f2543Smrg    if (entityIndex >= xf86NumEntities)
378706f2543Smrg	return NULL;
379706f2543Smrg
380706f2543Smrg    p = xf86Entities[entityIndex];
381706f2543Smrg    return (p->bus.type == BUS_PCI) ? p->bus.id.pci : NULL;
382706f2543Smrg}
383706f2543Smrg
384706f2543Smrg/*
385706f2543Smrg * xf86CheckPciMemBase() checks that the memory base value matches one of the
386706f2543Smrg * PCI base address register values for the given PCI device.
387706f2543Smrg */
388706f2543SmrgBool
389706f2543Smrgxf86CheckPciMemBase( struct pci_device * pPci, memType base )
390706f2543Smrg{
391706f2543Smrg    int i;
392706f2543Smrg
393706f2543Smrg    for (i = 0; i < 6; i++)
394706f2543Smrg	if (base == pPci->regions[i].base_addr)
395706f2543Smrg	    return TRUE;
396706f2543Smrg    return FALSE;
397706f2543Smrg}
398706f2543Smrg
399706f2543Smrg/*
400706f2543Smrg * Check if the slot requested is free.  If it is already in use, return FALSE.
401706f2543Smrg */
402706f2543Smrg
403706f2543SmrgBool
404706f2543Smrgxf86CheckPciSlot(const struct pci_device *d)
405706f2543Smrg{
406706f2543Smrg    int i;
407706f2543Smrg
408706f2543Smrg    for (i = 0; i < xf86NumEntities; i++) {
409706f2543Smrg	const EntityPtr p = xf86Entities[i];
410706f2543Smrg
411706f2543Smrg	if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
412706f2543Smrg	    return FALSE;
413706f2543Smrg	}
414706f2543Smrg    }
415706f2543Smrg    return TRUE;
416706f2543Smrg}
417706f2543Smrg
418706f2543Smrg#define END_OF_MATCHES(m) \
419706f2543Smrg    (((m).vendor_id == 0) && ((m).device_id == 0) && ((m).subvendor_id == 0))
420706f2543Smrg
421706f2543SmrgBool
422706f2543Smrgxf86PciAddMatchingDev(DriverPtr drvp)
423706f2543Smrg{
424706f2543Smrg    const struct pci_id_match * const devices = drvp->supported_devices;
425706f2543Smrg    int j;
426706f2543Smrg    struct pci_device *pPci;
427706f2543Smrg    struct pci_device_iterator *iter;
428706f2543Smrg    int numFound = 0;
429706f2543Smrg
430706f2543Smrg
431706f2543Smrg    iter = pci_id_match_iterator_create(NULL);
432706f2543Smrg    while ((pPci = pci_device_next(iter)) != NULL) {
433706f2543Smrg    /* Determine if this device is supported by the driver.  If it is,
434706f2543Smrg     * add it to the list of devices to configure.
435706f2543Smrg     */
436706f2543Smrg    for (j = 0 ; ! END_OF_MATCHES(devices[j]) ; j++) {
437706f2543Smrg        if ( PCI_ID_COMPARE( devices[j].vendor_id, pPci->vendor_id )
438706f2543Smrg         && PCI_ID_COMPARE( devices[j].device_id, pPci->device_id )
439706f2543Smrg         && ((devices[j].device_class_mask & pPci->device_class)
440706f2543Smrg             == devices[j].device_class) ) {
441706f2543Smrg        if (xf86CheckPciSlot(pPci)) {
442706f2543Smrg            GDevPtr pGDev = xf86AddBusDeviceToConfigure(
443706f2543Smrg                    drvp->driverName, BUS_PCI, pPci, -1);
444706f2543Smrg            if (pGDev != NULL) {
445706f2543Smrg            /* After configure pass 1, chipID and chipRev are
446706f2543Smrg             * treated as over-rides, so clobber them here.
447706f2543Smrg             */
448706f2543Smrg            pGDev->chipID = -1;
449706f2543Smrg            pGDev->chipRev = -1;
450706f2543Smrg            }
451706f2543Smrg
452706f2543Smrg            numFound++;
453706f2543Smrg        }
454706f2543Smrg
455706f2543Smrg        break;
456706f2543Smrg        }
457706f2543Smrg    }
458706f2543Smrg    }
459706f2543Smrg
460706f2543Smrg    pci_iterator_destroy(iter);
461706f2543Smrg
462706f2543Smrg    return numFound != 0;
463706f2543Smrg}
464706f2543Smrg
465706f2543SmrgBool
466706f2543Smrgxf86PciProbeDev(DriverPtr drvp)
467706f2543Smrg{
468706f2543Smrg    int i, j;
469706f2543Smrg    struct pci_device * pPci;
470706f2543Smrg    Bool foundScreen = FALSE;
471706f2543Smrg    const struct pci_id_match * const devices = drvp->supported_devices;
472706f2543Smrg    GDevPtr *devList;
473706f2543Smrg    const unsigned numDevs = xf86MatchDevice(drvp->driverName, & devList);
474706f2543Smrg
475706f2543Smrg    for ( i = 0 ; i < numDevs ; i++ ) {
476706f2543Smrg       struct pci_device_iterator *iter;
477706f2543Smrg       unsigned device_id;
478706f2543Smrg
479706f2543Smrg
480706f2543Smrg       /* Find the pciVideoRec associated with this device section.
481706f2543Smrg        */
482706f2543Smrg       iter = pci_id_match_iterator_create(NULL);
483706f2543Smrg       while ((pPci = pci_device_next(iter)) != NULL) {
484706f2543Smrg           if (devList[i]->busID && *devList[i]->busID) {
485706f2543Smrg               if (xf86ComparePciBusString(devList[i]->busID,
486706f2543Smrg                                           ((pPci->domain << 8)
487706f2543Smrg                                            | pPci->bus),
488706f2543Smrg                                           pPci->dev,
489706f2543Smrg                                           pPci->func)) {
490706f2543Smrg                   break;
491706f2543Smrg               }
492706f2543Smrg           }
493706f2543Smrg           else if (xf86IsPrimaryPci(pPci)) {
494706f2543Smrg               break;
495706f2543Smrg           }
496706f2543Smrg       }
497706f2543Smrg
498706f2543Smrg       pci_iterator_destroy(iter);
499706f2543Smrg
500706f2543Smrg       if (pPci == NULL) {
501706f2543Smrg           continue;
502706f2543Smrg       }
503706f2543Smrg       device_id = (devList[i]->chipID > 0)
504706f2543Smrg         ? devList[i]->chipID : pPci->device_id;
505706f2543Smrg
506706f2543Smrg
507706f2543Smrg       /* Once the pciVideoRec is found, determine if the device is supported
508706f2543Smrg        * by the driver.  If it is, probe it!
509706f2543Smrg        */
510706f2543Smrg       for ( j = 0 ; ! END_OF_MATCHES( devices[j] ) ; j++ ) {
511706f2543Smrg           if ( PCI_ID_COMPARE( devices[j].vendor_id, pPci->vendor_id )
512706f2543Smrg                && PCI_ID_COMPARE( devices[j].device_id, device_id )
513706f2543Smrg                && ((devices[j].device_class_mask & pPci->device_class)
514706f2543Smrg                     == devices[j].device_class) ) {
515706f2543Smrg               int  entry;
516706f2543Smrg
517706f2543Smrg               /* Allow the same entity to be used more than once for
518706f2543Smrg                * devices with multiple screens per entity.  This assumes
519706f2543Smrg                * implicitly that there will be a screen == 0 instance.
520706f2543Smrg                *
521706f2543Smrg                * FIXME Need to make sure that two different drivers don't
522706f2543Smrg                * FIXME claim the same screen > 0 instance.
523706f2543Smrg                */
524706f2543Smrg               if ((devList[i]->screen == 0) && !xf86CheckPciSlot(pPci))
525706f2543Smrg                   continue;
526706f2543Smrg
527706f2543Smrg               DebugF("%s: card at %d:%d:%d is claimed by a Device section\n",
528706f2543Smrg                      drvp->driverName, pPci->bus, pPci->dev, pPci->func);
529706f2543Smrg
530706f2543Smrg               /* Allocate an entry in the lists to be returned */
531706f2543Smrg               entry = xf86ClaimPciSlot(pPci, drvp, device_id,
532706f2543Smrg                                         devList[i], devList[i]->active);
533706f2543Smrg
534706f2543Smrg               if ((entry == -1) && (devList[i]->screen > 0)) {
535706f2543Smrg                   unsigned k;
536706f2543Smrg
537706f2543Smrg                   for (k = 0; k < xf86NumEntities; k++ ) {
538706f2543Smrg                       EntityPtr pEnt = xf86Entities[k];
539706f2543Smrg                       if (pEnt->bus.type != BUS_PCI)
540706f2543Smrg                           continue;
541706f2543Smrg                       if (pEnt->bus.id.pci == pPci) {
542706f2543Smrg                           entry = k;
543706f2543Smrg                           xf86AddDevToEntity(k, devList[i]);
544706f2543Smrg                           break;
545706f2543Smrg                       }
546706f2543Smrg                   }
547706f2543Smrg               }
548706f2543Smrg
549706f2543Smrg               if (entry != -1) {
550706f2543Smrg                   if ((*drvp->PciProbe)(drvp, entry, pPci,
551706f2543Smrg                                         devices[j].match_data)) {
552706f2543Smrg                       foundScreen = TRUE;
553706f2543Smrg                   } else
554706f2543Smrg                       xf86UnclaimPciSlot(pPci);
555706f2543Smrg               }
556706f2543Smrg
557706f2543Smrg               break;
558706f2543Smrg           }
559706f2543Smrg       }
560706f2543Smrg    }
561706f2543Smrg    free(devList);
562706f2543Smrg
563706f2543Smrg    return foundScreen;
564706f2543Smrg}
565706f2543Smrg
566706f2543Smrgvoid
567706f2543Smrgxf86PciIsolateDevice(char *argument)
568706f2543Smrg{
569706f2543Smrg    int bus, device, func;
570706f2543Smrg
571706f2543Smrg    if (sscanf(argument, "PCI:%d:%d:%d", &bus, &device, &func) == 3) {
572706f2543Smrg        xf86IsolateDevice.domain = PCI_DOM_FROM_BUS(bus);
573706f2543Smrg        xf86IsolateDevice.bus = PCI_BUS_NO_DOMAIN(bus);
574706f2543Smrg        xf86IsolateDevice.dev = device;
575706f2543Smrg        xf86IsolateDevice.func = func;
576706f2543Smrg    } else
577706f2543Smrg        FatalError("Invalid isolated device specification\n");
578706f2543Smrg}
579706f2543Smrg
580706f2543Smrgstatic Bool
581706f2543SmrgpciDeviceHasBars(struct pci_device *pci)
582706f2543Smrg{
583706f2543Smrg    int i;
584706f2543Smrg
585706f2543Smrg    for (i = 0; i < 6; i++)
586706f2543Smrg	if (pci->regions[i].size)
587706f2543Smrg	    return TRUE;
588706f2543Smrg
589706f2543Smrg    if (pci->rom_size)
590706f2543Smrg	return TRUE;
591706f2543Smrg
592706f2543Smrg    return FALSE;
593706f2543Smrg}
594706f2543Smrg
595706f2543Smrgstruct Inst {
596706f2543Smrg    struct pci_device *	pci;
597706f2543Smrg    GDevPtr		dev;
598706f2543Smrg    Bool		foundHW;  /* PCIid in list of supported chipsets */
599706f2543Smrg    Bool		claimed;  /* BusID matches with a device section */
600706f2543Smrg    int 		chip;
601706f2543Smrg    int 		screen;
602706f2543Smrg};
603706f2543Smrg
604706f2543Smrg
605706f2543Smrg/**
606706f2543Smrg * Find set of unclaimed devices matching a given vendor ID.
607706f2543Smrg *
608706f2543Smrg * Used by drivers to find as yet unclaimed devices matching the specified
609706f2543Smrg * vendor ID.
610706f2543Smrg *
611706f2543Smrg * \param driverName     Name of the driver.  This is used to find Device
612706f2543Smrg *                       sections in the config file.
613706f2543Smrg * \param vendorID       PCI vendor ID of associated devices.  If zero, then
614706f2543Smrg *                       the true vendor ID must be encoded in the \c PCIid
615706f2543Smrg *                       fields of the \c PCIchipsets entries.
616706f2543Smrg * \param chipsets       Symbol table used to associate chipset names with
617706f2543Smrg *                       PCI IDs.
618706f2543Smrg * \param devList        List of Device sections parsed from the config file.
619706f2543Smrg * \param numDevs        Number of entries in \c devList.
620706f2543Smrg * \param drvp           Pointer the driver's control structure.
621706f2543Smrg * \param foundEntities  Returned list of entity indicies associated with the
622706f2543Smrg *                       driver.
623706f2543Smrg *
624706f2543Smrg * \returns
625706f2543Smrg * The number of elements in returned in \c foundEntities on success or zero
626706f2543Smrg * on failure.
627706f2543Smrg *
628706f2543Smrg * \todo
629706f2543Smrg * This function does a bit more than short description says.  Fill in some
630706f2543Smrg * more of the details of its operation.
631706f2543Smrg *
632706f2543Smrg * \todo
633706f2543Smrg * The \c driverName parameter is redundant.  It is the same as
634706f2543Smrg * \c DriverRec::driverName.  In a future version of this function, remove
635706f2543Smrg * that parameter.
636706f2543Smrg */
637706f2543Smrgint
638706f2543Smrgxf86MatchPciInstances(const char *driverName, int vendorID,
639706f2543Smrg		      SymTabPtr chipsets, PciChipsets *PCIchipsets,
640706f2543Smrg		      GDevPtr *devList, int numDevs, DriverPtr drvp,
641706f2543Smrg		      int **foundEntities)
642706f2543Smrg{
643706f2543Smrg    int i,j;
644706f2543Smrg    struct pci_device * pPci;
645706f2543Smrg    struct pci_device_iterator *iter;
646706f2543Smrg    struct Inst *instances = NULL;
647706f2543Smrg    int numClaimedInstances = 0;
648706f2543Smrg    int allocatedInstances = 0;
649706f2543Smrg    int numFound = 0;
650706f2543Smrg    SymTabRec *c;
651706f2543Smrg    PciChipsets *id;
652706f2543Smrg    int *retEntities = NULL;
653706f2543Smrg
654706f2543Smrg    *foundEntities = NULL;
655706f2543Smrg
656706f2543Smrg
657706f2543Smrg    /* Each PCI device will contribute at least one entry.  Each device
658706f2543Smrg     * section can contribute at most one entry.  The sum of the two is
659706f2543Smrg     * guaranteed to be larger than the maximum possible number of entries.
660706f2543Smrg     * Do this calculation and memory allocation once now to eliminate the
661706f2543Smrg     * need for realloc calls inside the loop.
662706f2543Smrg     */
663706f2543Smrg    if (!(xf86DoConfigure && xf86DoConfigurePass1)) {
664706f2543Smrg	unsigned max_entries = numDevs;
665706f2543Smrg
666706f2543Smrg	iter = pci_slot_match_iterator_create(NULL);
667706f2543Smrg	while ((pPci = pci_device_next(iter)) != NULL) {
668706f2543Smrg	    max_entries++;
669706f2543Smrg	}
670706f2543Smrg
671706f2543Smrg	pci_iterator_destroy(iter);
672706f2543Smrg	instances = xnfalloc(max_entries * sizeof(struct Inst));
673706f2543Smrg    }
674706f2543Smrg
675706f2543Smrg    iter = pci_slot_match_iterator_create(NULL);
676706f2543Smrg    while ((pPci = pci_device_next(iter)) != NULL) {
677706f2543Smrg	unsigned device_class = pPci->device_class;
678706f2543Smrg	Bool foundVendor = FALSE;
679706f2543Smrg
680706f2543Smrg
681706f2543Smrg	/* Convert the pre-PCI 2.0 device class for a VGA adapter to the
682706f2543Smrg	 * 2.0 version of the same class.
683706f2543Smrg	 */
684706f2543Smrg	if ( device_class == 0x00000101 ) {
685706f2543Smrg	    device_class = 0x00030000;
686706f2543Smrg	}
687706f2543Smrg
688706f2543Smrg
689706f2543Smrg	/* Find PCI devices that match the given vendor ID.  The vendor ID is
690706f2543Smrg	 * either specified explicitly as a parameter to the function or
691706f2543Smrg	 * implicitly encoded in the high bits of id->PCIid.
692706f2543Smrg	 *
693706f2543Smrg	 * The first device with a matching vendor is recorded, even if the
694706f2543Smrg	 * device ID doesn't match.  This is done because the Device section
695706f2543Smrg	 * in the xorg.conf file can over-ride the device ID.  A matching PCI
696706f2543Smrg	 * ID might not be found now, but after the device ID over-ride is
697706f2543Smrg	 * applied there /might/ be a match.
698706f2543Smrg	 */
699706f2543Smrg	for (id = PCIchipsets; id->PCIid != -1; id++) {
700706f2543Smrg	    const unsigned vendor_id = ((id->PCIid & 0xFFFF0000) >> 16)
701706f2543Smrg		| vendorID;
702706f2543Smrg	    const unsigned device_id = (id->PCIid & 0x0000FFFF);
703706f2543Smrg	    const unsigned match_class = 0x00030000 | id->PCIid;
704706f2543Smrg
705706f2543Smrg	    if ((vendor_id == pPci->vendor_id)
706706f2543Smrg		|| ((vendorID == PCI_VENDOR_GENERIC) && (match_class == device_class))) {
707706f2543Smrg		if (!foundVendor && (instances != NULL)) {
708706f2543Smrg		    ++allocatedInstances;
709706f2543Smrg		    instances[allocatedInstances - 1].pci = pPci;
710706f2543Smrg		    instances[allocatedInstances - 1].dev = NULL;
711706f2543Smrg		    instances[allocatedInstances - 1].claimed = FALSE;
712706f2543Smrg		    instances[allocatedInstances - 1].foundHW = FALSE;
713706f2543Smrg		    instances[allocatedInstances - 1].screen = 0;
714706f2543Smrg		}
715706f2543Smrg
716706f2543Smrg		foundVendor = TRUE;
717706f2543Smrg
718706f2543Smrg		if ( (device_id == pPci->device_id)
719706f2543Smrg		     || ((vendorID == PCI_VENDOR_GENERIC)
720706f2543Smrg			 && (match_class == device_class)) ) {
721706f2543Smrg		    if ( instances != NULL ) {
722706f2543Smrg			instances[allocatedInstances - 1].foundHW = TRUE;
723706f2543Smrg			instances[allocatedInstances - 1].chip = id->numChipset;
724706f2543Smrg		    }
725706f2543Smrg
726706f2543Smrg
727706f2543Smrg		    if ( xf86DoConfigure && xf86DoConfigurePass1 ) {
728706f2543Smrg			if (xf86CheckPciSlot(pPci)) {
729706f2543Smrg			    GDevPtr pGDev =
730706f2543Smrg			      xf86AddBusDeviceToConfigure(drvp->driverName,
731706f2543Smrg							  BUS_PCI, pPci, -1);
732706f2543Smrg			    if (pGDev) {
733706f2543Smrg				/* After configure pass 1, chipID and chipRev
734706f2543Smrg				 * are treated as over-rides, so clobber them
735706f2543Smrg				 * here.
736706f2543Smrg				 */
737706f2543Smrg				pGDev->chipID = -1;
738706f2543Smrg				pGDev->chipRev = -1;
739706f2543Smrg			    }
740706f2543Smrg
741706f2543Smrg			    numFound++;
742706f2543Smrg			}
743706f2543Smrg		    }
744706f2543Smrg		    else {
745706f2543Smrg			numFound++;
746706f2543Smrg		    }
747706f2543Smrg
748706f2543Smrg		    break;
749706f2543Smrg		}
750706f2543Smrg	    }
751706f2543Smrg	}
752706f2543Smrg    }
753706f2543Smrg
754706f2543Smrg    pci_iterator_destroy(iter);
755706f2543Smrg
756706f2543Smrg
757706f2543Smrg    /* In "probe only" or "configure" mode (signaled by instances being NULL),
758706f2543Smrg     * our work is done.  Return the number of detected devices.
759706f2543Smrg     */
760706f2543Smrg    if ( instances == NULL ) {
761706f2543Smrg	return numFound;
762706f2543Smrg    }
763706f2543Smrg
764706f2543Smrg
765706f2543Smrg    /*
766706f2543Smrg     * This may be debatable, but if no PCI devices with a matching vendor
767706f2543Smrg     * type is found, return zero now.  It is probably not desirable to
768706f2543Smrg     * allow the config file to override this.
769706f2543Smrg     */
770706f2543Smrg    if (allocatedInstances <= 0) {
771706f2543Smrg	free(instances);
772706f2543Smrg	return 0;
773706f2543Smrg    }
774706f2543Smrg
775706f2543Smrg
776706f2543Smrg    DebugF("%s instances found: %d\n", driverName, allocatedInstances);
777706f2543Smrg
778706f2543Smrg   /*
779706f2543Smrg    * Check for devices that need duplicated instances.  This is required
780706f2543Smrg    * when there is more than one screen per entity.
781706f2543Smrg    *
782706f2543Smrg    * XXX This currently doesn't work for cases where the BusID isn't
783706f2543Smrg    * specified explicitly in the config file.
784706f2543Smrg    */
785706f2543Smrg
786706f2543Smrg    for (j = 0; j < numDevs; j++) {
787706f2543Smrg        if (devList[j]->screen > 0 && devList[j]->busID
788706f2543Smrg	    && *devList[j]->busID) {
789706f2543Smrg	    for (i = 0; i < allocatedInstances; i++) {
790706f2543Smrg	        pPci = instances[i].pci;
791706f2543Smrg	        if (xf86ComparePciBusString(devList[j]->busID,
792706f2543Smrg					    PCI_MAKE_BUS( pPci->domain, pPci->bus ),
793706f2543Smrg					    pPci->dev,
794706f2543Smrg					    pPci->func)) {
795706f2543Smrg		    allocatedInstances++;
796706f2543Smrg		    instances[allocatedInstances - 1] = instances[i];
797706f2543Smrg		    instances[allocatedInstances - 1].screen = devList[j]->screen;
798706f2543Smrg		    numFound++;
799706f2543Smrg		    break;
800706f2543Smrg		}
801706f2543Smrg	    }
802706f2543Smrg	}
803706f2543Smrg    }
804706f2543Smrg
805706f2543Smrg    for (i = 0; i < allocatedInstances; i++) {
806706f2543Smrg	GDevPtr dev = NULL;
807706f2543Smrg	GDevPtr devBus = NULL;
808706f2543Smrg
809706f2543Smrg	pPci = instances[i].pci;
810706f2543Smrg	for (j = 0; j < numDevs; j++) {
811706f2543Smrg	    if (devList[j]->busID && *devList[j]->busID) {
812706f2543Smrg		if (xf86ComparePciBusString(devList[j]->busID,
813706f2543Smrg					    PCI_MAKE_BUS( pPci->domain, pPci->bus ),
814706f2543Smrg					    pPci->dev,
815706f2543Smrg					    pPci->func) &&
816706f2543Smrg		    devList[j]->screen == instances[i].screen) {
817706f2543Smrg
818706f2543Smrg		    if (devBus)
819706f2543Smrg                        xf86MsgVerb(X_WARNING,0,
820706f2543Smrg			    "%s: More than one matching Device section for "
821706f2543Smrg			    "instances\n\t(BusID: %s) found: %s\n",
822706f2543Smrg			    driverName, devList[j]->busID,
823706f2543Smrg			    devList[j]->identifier);
824706f2543Smrg		    else
825706f2543Smrg			devBus = devList[j];
826706f2543Smrg		}
827706f2543Smrg	    } else {
828706f2543Smrg		/*
829706f2543Smrg		 * if device section without BusID is found
830706f2543Smrg		 * only assign to it to the primary device.
831706f2543Smrg		 */
832706f2543Smrg		if (xf86IsPrimaryPci(pPci)) {
833706f2543Smrg		    xf86Msg(X_PROBED, "Assigning device section with no busID"
834706f2543Smrg			    " to primary device\n");
835706f2543Smrg		    if (dev || devBus)
836706f2543Smrg			xf86MsgVerb(X_WARNING, 0,
837706f2543Smrg			    "%s: More than one matching Device section "
838706f2543Smrg			    "found: %s\n", driverName, devList[j]->identifier);
839706f2543Smrg		    else
840706f2543Smrg			dev = devList[j];
841706f2543Smrg		}
842706f2543Smrg	    }
843706f2543Smrg	}
844706f2543Smrg	if (devBus) dev = devBus;  /* busID preferred */
845706f2543Smrg	if (!dev) {
846706f2543Smrg	    if (xf86CheckPciSlot(pPci) && pciDeviceHasBars(pPci)) {
847706f2543Smrg		xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section "
848706f2543Smrg			    "for instance (BusID PCI:%u@%u:%u:%u) found\n",
849706f2543Smrg			    driverName, pPci->domain, pPci->bus, pPci->dev,
850706f2543Smrg			    pPci->func);
851706f2543Smrg	    }
852706f2543Smrg	} else {
853706f2543Smrg	    numClaimedInstances++;
854706f2543Smrg	    instances[i].claimed = TRUE;
855706f2543Smrg	    instances[i].dev = dev;
856706f2543Smrg	}
857706f2543Smrg    }
858706f2543Smrg    DebugF("%s instances found: %d\n", driverName, numClaimedInstances);
859706f2543Smrg    /*
860706f2543Smrg     * Now check that a chipset or chipID override in the device section
861706f2543Smrg     * is valid.  Chipset has precedence over chipID.
862706f2543Smrg     * If chipset is not valid ignore BusSlot completely.
863706f2543Smrg     */
864706f2543Smrg    for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
865706f2543Smrg	MessageType from = X_PROBED;
866706f2543Smrg
867706f2543Smrg	if (!instances[i].claimed) {
868706f2543Smrg	    continue;
869706f2543Smrg	}
870706f2543Smrg	if (instances[i].dev->chipset) {
871706f2543Smrg	    for (c = chipsets; c->token >= 0; c++) {
872706f2543Smrg		if (xf86NameCmp(c->name, instances[i].dev->chipset) == 0)
873706f2543Smrg		    break;
874706f2543Smrg	    }
875706f2543Smrg	    if (c->token == -1) {
876706f2543Smrg		instances[i].claimed = FALSE;
877706f2543Smrg		numClaimedInstances--;
878706f2543Smrg		xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device "
879706f2543Smrg			    "section \"%s\" isn't valid for this driver\n",
880706f2543Smrg			    driverName, instances[i].dev->chipset,
881706f2543Smrg			    instances[i].dev->identifier);
882706f2543Smrg	    } else {
883706f2543Smrg		instances[i].chip = c->token;
884706f2543Smrg
885706f2543Smrg		for (id = PCIchipsets; id->numChipset >= 0; id++) {
886706f2543Smrg		    if (id->numChipset == instances[i].chip)
887706f2543Smrg			break;
888706f2543Smrg		}
889706f2543Smrg		if(id->numChipset >=0){
890706f2543Smrg		    xf86Msg(X_CONFIG,"Chipset override: %s\n",
891706f2543Smrg			     instances[i].dev->chipset);
892706f2543Smrg		    from = X_CONFIG;
893706f2543Smrg		} else {
894706f2543Smrg		    instances[i].claimed = FALSE;
895706f2543Smrg		    numClaimedInstances--;
896706f2543Smrg		    xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device "
897706f2543Smrg				"section \"%s\" isn't a valid PCI chipset\n",
898706f2543Smrg				driverName, instances[i].dev->chipset,
899706f2543Smrg				instances[i].dev->identifier);
900706f2543Smrg		}
901706f2543Smrg	    }
902706f2543Smrg	} else if (instances[i].dev->chipID > 0) {
903706f2543Smrg	    for (id = PCIchipsets; id->numChipset >= 0; id++) {
904706f2543Smrg		if (id->PCIid == instances[i].dev->chipID)
905706f2543Smrg		    break;
906706f2543Smrg	    }
907706f2543Smrg	    if (id->numChipset == -1) {
908706f2543Smrg		instances[i].claimed = FALSE;
909706f2543Smrg		numClaimedInstances--;
910706f2543Smrg		xf86MsgVerb(X_WARNING, 0, "%s: ChipID 0x%04X in Device "
911706f2543Smrg			    "section \"%s\" isn't valid for this driver\n",
912706f2543Smrg			    driverName, instances[i].dev->chipID,
913706f2543Smrg			    instances[i].dev->identifier);
914706f2543Smrg	    } else {
915706f2543Smrg		instances[i].chip = id->numChipset;
916706f2543Smrg
917706f2543Smrg		xf86Msg( X_CONFIG,"ChipID override: 0x%04X\n",
918706f2543Smrg			 instances[i].dev->chipID);
919706f2543Smrg		from = X_CONFIG;
920706f2543Smrg	    }
921706f2543Smrg	} else if (!instances[i].foundHW) {
922706f2543Smrg	    /*
923706f2543Smrg	     * This means that there was no override and the PCI chipType
924706f2543Smrg	     * doesn't match one that is supported
925706f2543Smrg	     */
926706f2543Smrg	    instances[i].claimed = FALSE;
927706f2543Smrg	    numClaimedInstances--;
928706f2543Smrg	}
929706f2543Smrg	if (instances[i].claimed == TRUE){
930706f2543Smrg	    for (c = chipsets; c->token >= 0; c++) {
931706f2543Smrg		if (c->token == instances[i].chip)
932706f2543Smrg		    break;
933706f2543Smrg	    }
934706f2543Smrg	    xf86Msg(from,"Chipset %s found\n",
935706f2543Smrg		    c->name);
936706f2543Smrg	}
937706f2543Smrg    }
938706f2543Smrg
939706f2543Smrg    /*
940706f2543Smrg     * Of the claimed instances, check that another driver hasn't already
941706f2543Smrg     * claimed its slot.
942706f2543Smrg     */
943706f2543Smrg    numFound = 0;
944706f2543Smrg    for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
945706f2543Smrg	if (!instances[i].claimed)
946706f2543Smrg	    continue;
947706f2543Smrg	pPci = instances[i].pci;
948706f2543Smrg
949706f2543Smrg
950706f2543Smrg        /*
951706f2543Smrg	 * Allow the same entity to be used more than once for devices with
952706f2543Smrg	 * multiple screens per entity.  This assumes implicitly that there
953706f2543Smrg	 * will be a screen == 0 instance.
954706f2543Smrg	 *
955706f2543Smrg	 * XXX Need to make sure that two different drivers don't claim
956706f2543Smrg	 * the same screen > 0 instance.
957706f2543Smrg	 */
958706f2543Smrg        if (instances[i].screen == 0 && !xf86CheckPciSlot( pPci ))
959706f2543Smrg	    continue;
960706f2543Smrg
961706f2543Smrg	DebugF("%s: card at %d:%d:%d is claimed by a Device section\n",
962706f2543Smrg	       driverName, pPci->bus, pPci->dev, pPci->func);
963706f2543Smrg
964706f2543Smrg	/* Allocate an entry in the lists to be returned */
965706f2543Smrg	numFound++;
966706f2543Smrg	retEntities = xnfrealloc(retEntities, numFound * sizeof(int));
967706f2543Smrg	retEntities[numFound - 1] = xf86ClaimPciSlot( pPci, drvp,
968706f2543Smrg						      instances[i].chip,
969706f2543Smrg						      instances[i].dev,
970706f2543Smrg						      instances[i].dev->active);
971706f2543Smrg        if (retEntities[numFound - 1] == -1 && instances[i].screen > 0) {
972706f2543Smrg	    for (j = 0; j < xf86NumEntities; j++) {
973706f2543Smrg	        EntityPtr pEnt = xf86Entities[j];
974706f2543Smrg	        if (pEnt->bus.type != BUS_PCI)
975706f2543Smrg		    continue;
976706f2543Smrg	        if (pEnt->bus.id.pci == pPci) {
977706f2543Smrg		    retEntities[numFound - 1] = j;
978706f2543Smrg		    xf86AddDevToEntity(j, instances[i].dev);
979706f2543Smrg		    break;
980706f2543Smrg		}
981706f2543Smrg	    }
982706f2543Smrg	}
983706f2543Smrg    }
984706f2543Smrg    free(instances);
985706f2543Smrg    if (numFound > 0) {
986706f2543Smrg	*foundEntities = retEntities;
987706f2543Smrg    }
988706f2543Smrg
989706f2543Smrg    return numFound;
990706f2543Smrg}
991706f2543Smrg
992706f2543Smrg/*
993706f2543Smrg * xf86ConfigPciEntityInactive() -- This function can be used
994706f2543Smrg * to configure an inactive entity as well as to reconfigure an
995706f2543Smrg * previously active entity inactive. If the entity has been
996706f2543Smrg * assigned to a screen before it will be removed. If p_chip is
997706f2543Smrg * non-NULL all static resources listed there will be registered.
998706f2543Smrg */
999706f2543Smrgstatic void
1000706f2543Smrgxf86ConfigPciEntityInactive(EntityInfoPtr pEnt, PciChipsets *p_chip,
1001706f2543Smrg			    EntityProc init, EntityProc enter,
1002706f2543Smrg			    EntityProc leave, pointer private)
1003706f2543Smrg{
1004706f2543Smrg    ScrnInfoPtr pScrn;
1005706f2543Smrg
1006706f2543Smrg    if ((pScrn = xf86FindScreenForEntity(pEnt->index)))
1007706f2543Smrg	xf86RemoveEntityFromScreen(pScrn,pEnt->index);
1008706f2543Smrg
1009706f2543Smrg    /* shared resources are only needed when entity is active: remove */
1010706f2543Smrg    xf86SetEntityFuncs(pEnt->index,init,enter,leave,private);
1011706f2543Smrg}
1012706f2543Smrg
1013706f2543SmrgScrnInfoPtr
1014706f2543Smrgxf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex,
1015706f2543Smrg			  PciChipsets *p_chip, void *dummy, EntityProc init,
1016706f2543Smrg			  EntityProc enter, EntityProc leave, pointer private)
1017706f2543Smrg{
1018706f2543Smrg    EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex);
1019706f2543Smrg    if (!pEnt) return pScrn;
1020706f2543Smrg
1021706f2543Smrg    if (!(pEnt->location.type == BUS_PCI)
1022706f2543Smrg	|| !xf86GetPciInfoForEntity(entityIndex)) {
1023706f2543Smrg	free(pEnt);
1024706f2543Smrg	return pScrn;
1025706f2543Smrg    }
1026706f2543Smrg    if (!pEnt->active) {
1027706f2543Smrg	xf86ConfigPciEntityInactive(pEnt, p_chip, init,  enter,
1028706f2543Smrg				    leave,  private);
1029706f2543Smrg	free(pEnt);
1030706f2543Smrg	return pScrn;
1031706f2543Smrg    }
1032706f2543Smrg
1033706f2543Smrg    if (!pScrn)
1034706f2543Smrg	pScrn = xf86AllocateScreen(pEnt->driver,scrnFlag);
1035706f2543Smrg    if (xf86IsEntitySharable(entityIndex)) {
1036706f2543Smrg        xf86SetEntityShared(entityIndex);
1037706f2543Smrg    }
1038706f2543Smrg    xf86AddEntityToScreen(pScrn,entityIndex);
1039706f2543Smrg    if (xf86IsEntityShared(entityIndex)) {
1040706f2543Smrg        return pScrn;
1041706f2543Smrg    }
1042706f2543Smrg    free(pEnt);
1043706f2543Smrg
1044706f2543Smrg    xf86SetEntityFuncs(entityIndex,init,enter,leave,private);
1045706f2543Smrg
1046706f2543Smrg    return pScrn;
1047706f2543Smrg}
1048706f2543Smrg
1049706f2543Smrg/*
1050706f2543Smrg *  OBSOLETE ! xf86ConfigActivePciEntity() is an obsolete function.
1051706f2543Smrg *             It is likely to be removed. Don't use!
1052706f2543Smrg */
1053706f2543SmrgBool
1054706f2543Smrgxf86ConfigActivePciEntity(ScrnInfoPtr pScrn, int entityIndex,
1055706f2543Smrg                          PciChipsets *p_chip, void *dummy, EntityProc init,
1056706f2543Smrg                          EntityProc enter, EntityProc leave, pointer private)
1057706f2543Smrg{
1058706f2543Smrg    EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex);
1059706f2543Smrg    if (!pEnt) return FALSE;
1060706f2543Smrg
1061706f2543Smrg    if (!pEnt->active || !(pEnt->location.type == BUS_PCI)) {
1062706f2543Smrg        free(pEnt);
1063706f2543Smrg        return FALSE;
1064706f2543Smrg    }
1065706f2543Smrg    xf86AddEntityToScreen(pScrn,entityIndex);
1066706f2543Smrg
1067706f2543Smrg    free(pEnt);
1068706f2543Smrg    if (!xf86SetEntityFuncs(entityIndex,init,enter,leave,private))
1069706f2543Smrg        return FALSE;
1070706f2543Smrg
1071706f2543Smrg    return TRUE;
1072706f2543Smrg}
1073706f2543Smrg
1074706f2543Smrgstatic int
1075706f2543SmrgvideoPtrToDriverList(struct pci_device *dev,
1076706f2543Smrg		     char *returnList[], int returnListMax)
1077706f2543Smrg{
1078706f2543Smrg    int i;
1079706f2543Smrg    /* Add more entries here if we ever return more than 4 drivers for
1080706f2543Smrg       any device */
1081706f2543Smrg    char *driverList[5] = { NULL, NULL, NULL, NULL, NULL };
1082706f2543Smrg
1083706f2543Smrg    switch (dev->vendor_id)
1084706f2543Smrg    {
1085706f2543Smrg	/* AMD Geode LX */
1086706f2543Smrg	case 0x1022:
1087706f2543Smrg	    if (dev->device_id == 0x2081)
1088706f2543Smrg		driverList[0] = "geode";
1089706f2543Smrg	    break;
1090706f2543Smrg	/* older Geode products acquired by AMD still carry an NSC vendor_id */
1091706f2543Smrg	case 0x100b:
1092706f2543Smrg	    if (dev->device_id == 0x0030) {
1093706f2543Smrg		/* NSC Geode GX2 specifically */
1094706f2543Smrg		driverList[0] = "geode";
1095706f2543Smrg		/* GX2 support started its life in the NSC tree and was later
1096706f2543Smrg		   forked by AMD for GEODE so we keep it as a backup */
1097706f2543Smrg		driverList[1] = "nsc";
1098706f2543Smrg	    } else
1099706f2543Smrg		/* other NSC variant e.g. 0x0104 (SC1400), 0x0504 (SCx200) */
1100706f2543Smrg		driverList[0] = "nsc";
1101706f2543Smrg	    break;
1102706f2543Smrg	/* Cyrix Geode GX1 */
1103706f2543Smrg	case 0x1078:
1104706f2543Smrg	    if (dev->device_id == 0x0104)
1105706f2543Smrg		driverList[0] = "cyrix";
1106706f2543Smrg	    break;
1107706f2543Smrg	case 0x1142:		    driverList[0] = "apm"; break;
1108706f2543Smrg	case 0xedd8:		    driverList[0] = "ark"; break;
1109706f2543Smrg	case 0x1a03:		    driverList[0] = "ast"; break;
1110706f2543Smrg	case 0x1002:		    driverList[0] = "ati"; break;
1111706f2543Smrg	case 0x102c:		    driverList[0] = "chips"; break;
1112706f2543Smrg	case 0x1013:		    driverList[0] = "cirrus"; break;
1113706f2543Smrg	case 0x3d3d:		    driverList[0] = "glint"; break;
1114706f2543Smrg	case 0x105d:		    driverList[0] = "i128"; break;
1115706f2543Smrg	case 0x8086:
1116706f2543Smrg	    if ((dev->device_id == 0x00d1) || (dev->device_id == 0x7800)) {
1117706f2543Smrg		driverList[0] = "i740";
1118706f2543Smrg            } else if (dev->device_id == 0x8108) {
1119706f2543Smrg                break; /* "hooray" for poulsbo */
1120706f2543Smrg	    } else {
1121706f2543Smrg		driverList[0] = "intel";
1122706f2543Smrg	    }
1123706f2543Smrg	    break;
1124706f2543Smrg	case 0x102b:		    driverList[0] = "mga";	break;
1125706f2543Smrg	case 0x10c8:		    driverList[0] = "neomagic"; break;
1126706f2543Smrg	case 0x10de:
1127706f2543Smrg	case 0x12d2:
1128706f2543Smrg	    driverList[0] = "nouveau";
1129706f2543Smrg	    driverList[1] = "nv";
1130706f2543Smrg	    break;
1131706f2543Smrg	case 0x1106:		    driverList[0] = "openchrome"; break;
1132706f2543Smrg        case 0x1b36:		    driverList[0] = "qxl"; break;
1133706f2543Smrg	case 0x1163:		    driverList[0] = "rendition"; break;
1134706f2543Smrg	case 0x5333:
1135706f2543Smrg	    switch (dev->device_id)
1136706f2543Smrg	    {
1137706f2543Smrg		case 0x88d0: case 0x88d1: case 0x88f0: case 0x8811:
1138706f2543Smrg		case 0x8812: case 0x8814: case 0x8901:
1139706f2543Smrg		    driverList[0] = "s3"; break;
1140706f2543Smrg		case 0x5631: case 0x883d: case 0x8a01: case 0x8a10:
1141706f2543Smrg		case 0x8c01: case 0x8c03: case 0x8904: case 0x8a13:
1142706f2543Smrg		    driverList[0] = "s3virge"; break;
1143706f2543Smrg		default:
1144706f2543Smrg		    driverList[0] = "savage"; break;
1145706f2543Smrg	    }
1146706f2543Smrg	    break;
1147706f2543Smrg	case 0x1039:		    driverList[0] = "sis";	break;
1148706f2543Smrg	case 0x126f:		    driverList[0] = "siliconmotion"; break;
1149706f2543Smrg	case 0x121a:
1150706f2543Smrg	    if (dev->device_id < 0x0003)
1151706f2543Smrg	        driverList[0] = "voodoo";
1152706f2543Smrg	    else
1153706f2543Smrg	        driverList[0] = "tdfx";
1154706f2543Smrg	    break;
1155706f2543Smrg	case 0x1011:		    driverList[0] = "tga"; break;
1156706f2543Smrg	case 0x1023:		    driverList[0] = "trident"; break;
1157706f2543Smrg	case 0x100c:		    driverList[0] = "tseng"; break;
1158706f2543Smrg	case 0x80ee:		    driverList[0] = "vboxvideo"; break;
1159706f2543Smrg	case 0x15ad:		    driverList[0] = "vmware"; break;
1160706f2543Smrg	case 0x18ca:
1161706f2543Smrg	    if (dev->device_id == 0x47)
1162706f2543Smrg		driverList[0] = "xgixp";
1163706f2543Smrg	    else
1164706f2543Smrg		driverList[0] = "xgi";
1165706f2543Smrg	    break;
1166706f2543Smrg	default: break;
1167706f2543Smrg    }
1168706f2543Smrg    for (i = 0; (i < returnListMax) && (driverList[i] != NULL); i++) {
1169706f2543Smrg	returnList[i] = xnfstrdup(driverList[i]);
1170706f2543Smrg    }
1171706f2543Smrg    return i;	/* Number of entries added */
1172706f2543Smrg}
1173706f2543Smrg
1174706f2543Smrg#ifdef __linux__
1175706f2543Smrgstatic int
1176706f2543Smrgxchomp(char *line)
1177706f2543Smrg{
1178706f2543Smrg    size_t len = 0;
1179706f2543Smrg
1180706f2543Smrg    if (!line) {
1181706f2543Smrg        return 1;
1182706f2543Smrg    }
1183706f2543Smrg
1184706f2543Smrg    len = strlen(line);
1185706f2543Smrg    if (line[len - 1] == '\n' && len > 0) {
1186706f2543Smrg        line[len - 1] = '\0';
1187706f2543Smrg    }
1188706f2543Smrg    return 0;
1189706f2543Smrg}
1190706f2543Smrg
1191706f2543Smrg/* This function is used to provide a workaround for binary drivers that
1192706f2543Smrg * don't export their PCI ID's properly. If distros don't end up using this
1193706f2543Smrg * feature it can and should be removed because the symbol-based resolution
1194706f2543Smrg * scheme should be the primary one */
1195706f2543Smrgstatic void
1196706f2543SmrgmatchDriverFromFiles (char** matches, uint16_t match_vendor, uint16_t match_chip)
1197706f2543Smrg{
1198706f2543Smrg    DIR *idsdir;
1199706f2543Smrg    FILE *fp;
1200706f2543Smrg    struct dirent *direntry;
1201706f2543Smrg    char *line = NULL;
1202706f2543Smrg    size_t len;
1203706f2543Smrg    ssize_t read;
1204706f2543Smrg    char path_name[256], vendor_str[5], chip_str[5];
1205706f2543Smrg    uint16_t vendor, chip;
1206706f2543Smrg    int i, j;
1207706f2543Smrg
1208706f2543Smrg    idsdir = opendir(PCI_TXT_IDS_PATH);
1209706f2543Smrg    if (!idsdir)
1210706f2543Smrg        return;
1211706f2543Smrg
1212706f2543Smrg    xf86Msg(X_INFO, "Scanning %s directory for additional PCI ID's supported by the drivers\n", PCI_TXT_IDS_PATH);
1213706f2543Smrg    direntry = readdir(idsdir);
1214706f2543Smrg    /* Read the directory */
1215706f2543Smrg    while (direntry) {
1216706f2543Smrg        if (direntry->d_name[0] == '.') {
1217706f2543Smrg            direntry = readdir(idsdir);
1218706f2543Smrg            continue;
1219706f2543Smrg        }
1220706f2543Smrg        len = strlen(direntry->d_name);
1221706f2543Smrg        /* A tiny bit of sanity checking. We should probably do better */
1222706f2543Smrg        if (strncmp(&(direntry->d_name[len-4]), ".ids", 4) == 0) {
1223706f2543Smrg            /* We need the full path name to open the file */
1224706f2543Smrg            strncpy(path_name, PCI_TXT_IDS_PATH, 256);
1225706f2543Smrg            strncat(path_name, "/", 1);
1226706f2543Smrg            strncat(path_name, direntry->d_name, (256 - strlen(path_name) - 1));
1227706f2543Smrg            fp = fopen(path_name, "r");
1228706f2543Smrg            if (fp == NULL) {
1229706f2543Smrg                xf86Msg(X_ERROR, "Could not open %s for reading. Exiting.\n", path_name);
1230706f2543Smrg                goto end;
1231706f2543Smrg            }
1232706f2543Smrg            /* Read the file */
1233706f2543Smrg#ifdef __GLIBC__
1234706f2543Smrg            while ((read = getline(&line, &len, fp)) != -1) {
1235706f2543Smrg#else
1236706f2543Smrg            while ((line = fgetln(fp, &len)) != (char *)NULL) {
1237706f2543Smrg#endif /* __GLIBC __ */
1238706f2543Smrg                xchomp(line);
1239706f2543Smrg                if (isdigit(line[0])) {
1240706f2543Smrg                    strncpy(vendor_str, line, 4);
1241706f2543Smrg                    vendor_str[4] = '\0';
1242706f2543Smrg                    vendor = (int)strtol(vendor_str, NULL, 16);
1243706f2543Smrg                    if ((strlen(&line[4])) == 0) {
1244706f2543Smrg                        chip_str[0] = '\0';
1245706f2543Smrg                        chip = -1;
1246706f2543Smrg                    } else {
1247706f2543Smrg                        /* Handle trailing whitespace */
1248706f2543Smrg                        if (isspace(line[4])) {
1249706f2543Smrg                            chip_str[0] = '\0';
1250706f2543Smrg                            chip = -1;
1251706f2543Smrg                        } else {
1252706f2543Smrg                            /* Ok, it's a real ID */
1253706f2543Smrg                            strncpy(chip_str, &line[4], 4);
1254706f2543Smrg                            chip_str[4] = '\0';
1255706f2543Smrg                            chip = (int)strtol(chip_str, NULL, 16);
1256706f2543Smrg                        }
1257706f2543Smrg                    }
1258706f2543Smrg                    if (vendor == match_vendor && chip == match_chip ) {
1259706f2543Smrg                        i = 0;
1260706f2543Smrg                        while (matches[i]) {
1261706f2543Smrg                            i++;
1262706f2543Smrg                        }
1263706f2543Smrg                        matches[i] = (char*)malloc(sizeof(char) * strlen(direntry->d_name) -  3);
1264706f2543Smrg                        if (!matches[i]) {
1265706f2543Smrg                            xf86Msg(X_ERROR, "Could not allocate space for the module name. Exiting.\n");
1266706f2543Smrg                            goto end;
1267706f2543Smrg                        }
1268706f2543Smrg                        /* hack off the .ids suffix. This should guard
1269706f2543Smrg                         * against other problems, but it will end up
1270706f2543Smrg                         * taking off anything after the first '.' */
1271706f2543Smrg                        for (j = 0; j < (strlen(direntry->d_name) - 3) ; j++) {
1272706f2543Smrg                            if (direntry->d_name[j] == '.') {
1273706f2543Smrg                                matches[i][j] = '\0';
1274706f2543Smrg                                break;
1275706f2543Smrg                            } else {
1276706f2543Smrg                                matches[i][j] = direntry->d_name[j];
1277706f2543Smrg                            }
1278706f2543Smrg                        }
1279706f2543Smrg                        xf86Msg(X_INFO, "Matched %s from file name %s\n", matches[i], direntry->d_name);
1280706f2543Smrg                    }
1281706f2543Smrg                } else {
1282706f2543Smrg                    /* TODO Handle driver overrides here */
1283706f2543Smrg                }
1284706f2543Smrg            }
1285706f2543Smrg            fclose(fp);
1286706f2543Smrg        }
1287706f2543Smrg        direntry = readdir(idsdir);
1288706f2543Smrg    }
1289706f2543Smrg end:
1290706f2543Smrg    free(line);
1291706f2543Smrg    closedir(idsdir);
1292706f2543Smrg}
1293706f2543Smrg#endif /* __linux__ */
1294706f2543Smrg
1295706f2543Smrg/**
1296706f2543Smrg *  @return The numbers of found devices that match with the current system
1297706f2543Smrg *  drivers.
1298706f2543Smrg */
1299706f2543Smrgint
1300706f2543Smrgxf86PciMatchDriver(char* matches[], int nmatches) {
1301706f2543Smrg    int i;
1302706f2543Smrg    struct pci_device * info = NULL;
1303706f2543Smrg    struct pci_device_iterator *iter;
1304706f2543Smrg
1305706f2543Smrg    /* Find the primary device, and get some information about it. */
1306706f2543Smrg    iter = pci_slot_match_iterator_create(NULL);
1307706f2543Smrg    while ((info = pci_device_next(iter)) != NULL) {
1308706f2543Smrg	if (xf86IsPrimaryPci(info)) {
1309706f2543Smrg	    break;
1310706f2543Smrg	}
1311706f2543Smrg    }
1312706f2543Smrg
1313706f2543Smrg    pci_iterator_destroy(iter);
1314706f2543Smrg#ifdef __linux__
1315706f2543Smrg    if (info)
1316706f2543Smrg	matchDriverFromFiles(matches, info->vendor_id, info->device_id);
1317706f2543Smrg#endif
1318706f2543Smrg
1319706f2543Smrg    for (i = 0; (i < nmatches) && (matches[i]); i++) {
1320706f2543Smrg	/* find end of matches list */
1321706f2543Smrg    }
1322706f2543Smrg
1323706f2543Smrg    if ((info != NULL) && (i < nmatches)) {
1324706f2543Smrg	i += videoPtrToDriverList(info, &(matches[i]), nmatches - i);
1325706f2543Smrg    }
1326706f2543Smrg
1327706f2543Smrg    return i;
1328706f2543Smrg}
1329706f2543Smrg
1330706f2543SmrgBool
1331706f2543Smrgxf86PciConfigure(void *busData, struct pci_device *pDev)
1332706f2543Smrg{
1333706f2543Smrg    struct pci_device * pVideo = NULL;
1334706f2543Smrg
1335706f2543Smrg    pVideo = (struct pci_device *) busData;
1336706f2543Smrg    if (pDev &&
1337706f2543Smrg        (pDev->domain == pVideo->domain) &&
1338706f2543Smrg        (pDev->bus == pVideo->bus) &&
1339706f2543Smrg        (pDev->dev == pVideo->dev) &&
1340706f2543Smrg        (pDev->func == pVideo->func))
1341706f2543Smrg        return 0;
1342706f2543Smrg
1343706f2543Smrg    return 1;
1344706f2543Smrg}
1345706f2543Smrg
1346706f2543Smrgvoid
1347706f2543Smrgxf86PciConfigureNewDev(void *busData, struct pci_device *pVideo,
1348706f2543Smrg                         GDevRec *GDev, int *chipset)
1349706f2543Smrg{
1350706f2543Smrg    char busnum[8];
1351706f2543Smrg
1352706f2543Smrg    pVideo = (struct pci_device *) busData;
1353706f2543Smrg
1354706f2543Smrg    xf86FormatPciBusNumber(pVideo->bus, busnum);
1355706f2543Smrg    XNFasprintf(&GDev->busID, "PCI:%s:%d:%d",
1356706f2543Smrg		busnum, pVideo->dev, pVideo->func);
1357706f2543Smrg
1358706f2543Smrg    GDev->chipID = pVideo->device_id;
1359706f2543Smrg    GDev->chipRev = pVideo->revision;
1360706f2543Smrg
1361706f2543Smrg    if (*chipset < 0)
1362706f2543Smrg        *chipset = (pVideo->vendor_id << 16) | pVideo->device_id;
1363706f2543Smrg}
1364