xf86pciBus.c revision f7df2e56
1/*
2 * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Except as contained in this notice, the name of the copyright holder(s)
23 * and author(s) shall not be used in advertising or otherwise to promote
24 * the sale, use or other dealings in this Software without prior written
25 * authorization from the copyright holder(s) and author(s).
26 */
27
28/*
29 * This file contains the interfaces to the bus-specific code
30 */
31#ifdef HAVE_XORG_CONFIG_H
32#include <xorg-config.h>
33#endif
34
35#include <ctype.h>
36#include <stdlib.h>
37#include <unistd.h>
38#include <X11/X.h>
39#include <pciaccess.h>
40#include "os.h"
41#include "Pci.h"
42#include "xf86.h"
43#include "xf86Priv.h"
44#include "dirent.h"             /* DIR, FILE type definitions */
45
46/* Bus-specific headers */
47#include "xf86Bus.h"
48
49#define XF86_OS_PRIVS
50#include "xf86_OSproc.h"
51
52#define PCI_VENDOR_GENERIC		0x00FF
53
54/* Bus-specific globals */
55int pciSlotClaimed = 0;
56
57#define PCIINFOCLASSES(c) \
58    ( (((c) & 0x00ff0000) == (PCI_CLASS_PREHISTORIC << 16)) \
59      || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \
60      || ((((c) & 0x00ffff00) \
61	   == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) \
62      || ((((c) & 0x00ffff00) \
63	   == ((PCI_CLASS_PROCESSOR << 16) | (PCI_SUBCLASS_PROCESSOR_COPROC << 8)))) )
64
65/*
66 * PCI classes that have messages printed always.  The others are only
67 * have a message printed when the vendor/dev IDs are recognised.
68 */
69#define PCIALWAYSPRINTCLASSES(c) \
70    ( (((c) & 0x00ffff00) \
71       == ((PCI_CLASS_PREHISTORIC << 16) | (PCI_SUBCLASS_PREHISTORIC_VGA << 8))) \
72      || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \
73      || ((((c) & 0x00ffff00) \
74	   == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) )
75
76#define IS_VGA(c) \
77    (((c) & 0x00ffff00) \
78	 == ((PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8)))
79
80static struct pci_slot_match xf86IsolateDevice = {
81    PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0
82};
83
84/*
85 * xf86Bus.c interface
86 */
87
88void
89xf86PciProbe(void)
90{
91    int i = 0, k;
92    int num = 0;
93    struct pci_device *info;
94    struct pci_device_iterator *iter;
95    struct pci_device **xf86PciVideoInfo = NULL;
96
97    if (!xf86scanpci()) {
98        xf86PciVideoInfo = NULL;
99        return;
100    }
101
102    iter = pci_slot_match_iterator_create(&xf86IsolateDevice);
103    while ((info = pci_device_next(iter)) != NULL) {
104        if (PCIINFOCLASSES(info->device_class)) {
105            num++;
106            xf86PciVideoInfo = xnfreallocarray(xf86PciVideoInfo,
107                                               num + 1,
108                                               sizeof(struct pci_device *));
109            xf86PciVideoInfo[num] = NULL;
110            xf86PciVideoInfo[num - 1] = info;
111
112            pci_device_probe(info);
113            if (primaryBus.type == BUS_NONE && pci_device_is_boot_vga(info)) {
114                primaryBus.type = BUS_PCI;
115                primaryBus.id.pci = info;
116            }
117            info->user_data = 0;
118        }
119    }
120    free(iter);
121
122    /* If we haven't found a primary device try a different heuristic */
123    if (primaryBus.type == BUS_NONE && num) {
124        for (i = 0; i < num; i++) {
125            uint16_t command;
126
127            info = xf86PciVideoInfo[i];
128            pci_device_cfg_read_u16(info, &command, 4);
129
130            if ((command & PCI_CMD_MEM_ENABLE)
131                && ((num == 1) || IS_VGA(info->device_class))) {
132                if (primaryBus.type == BUS_NONE) {
133                    primaryBus.type = BUS_PCI;
134                    primaryBus.id.pci = info;
135                }
136                else {
137                    xf86Msg(X_NOTICE,
138                            "More than one possible primary device found\n");
139                    primaryBus.type ^= (BusType) (-1);
140                }
141            }
142        }
143    }
144
145    /* Print a summary of the video devices found */
146    for (k = 0; k < num; k++) {
147        const char *prim = " ";
148        Bool memdone = FALSE, iodone = FALSE;
149
150        info = xf86PciVideoInfo[k];
151
152        if (!PCIALWAYSPRINTCLASSES(info->device_class))
153            continue;
154
155        if (xf86IsPrimaryPci(info))
156            prim = "*";
157
158        xf86Msg(X_PROBED, "PCI:%s(%u:%u:%u:%u) %04x:%04x:%04x:%04x ", prim,
159                info->domain, info->bus, info->dev, info->func,
160                info->vendor_id, info->device_id,
161                info->subvendor_id, info->subdevice_id);
162
163        xf86ErrorF("rev %d", info->revision);
164
165        for (i = 0; i < 6; i++) {
166            struct pci_mem_region *r = &info->regions[i];
167
168            if (r->size && !r->is_IO) {
169                if (!memdone) {
170                    xf86ErrorF(", Mem @ ");
171                    memdone = TRUE;
172                }
173                else
174                    xf86ErrorF(", ");
175                xf86ErrorF("0x%08lx/%ld", (long) r->base_addr, (long) r->size);
176            }
177        }
178
179        for (i = 0; i < 6; i++) {
180            struct pci_mem_region *r = &info->regions[i];
181
182            if (r->size && r->is_IO) {
183                if (!iodone) {
184                    xf86ErrorF(", I/O @ ");
185                    iodone = TRUE;
186                }
187                else
188                    xf86ErrorF(", ");
189                xf86ErrorF("0x%08lx/%ld", (long) r->base_addr, (long) r->size);
190            }
191        }
192
193        if (info->rom_size) {
194            xf86ErrorF(", BIOS @ 0x\?\?\?\?\?\?\?\?/%ld",
195                       (long) info->rom_size);
196        }
197
198        xf86ErrorF("\n");
199    }
200    free(xf86PciVideoInfo);
201}
202
203/*
204 * If the slot requested is already in use, return -1.
205 * Otherwise, claim the slot for the screen requesting it.
206 */
207
208int
209xf86ClaimPciSlot(struct pci_device *d, DriverPtr drvp,
210                 int chipset, GDevPtr dev, Bool active)
211{
212    EntityPtr p = NULL;
213    int num;
214
215    if (xf86CheckPciSlot(d)) {
216        num = xf86AllocateEntity();
217        p = xf86Entities[num];
218        p->driver = drvp;
219        p->chipset = chipset;
220        p->bus.type = BUS_PCI;
221        p->bus.id.pci = d;
222        p->active = active;
223        p->inUse = FALSE;
224        if (dev)
225            xf86AddDevToEntity(num, dev);
226        pciSlotClaimed++;
227
228        return num;
229    }
230    else
231        return -1;
232}
233
234/*
235 * Unclaim PCI slot, e.g. if probing failed, so that a different driver can claim.
236 */
237void
238xf86UnclaimPciSlot(struct pci_device *d, GDevPtr dev)
239{
240    int i;
241
242    for (i = 0; i < xf86NumEntities; i++) {
243        const EntityPtr p = xf86Entities[i];
244
245        if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
246            /* Probably the slot should be deallocated? */
247            xf86RemoveDevFromEntity(i, dev);
248            pciSlotClaimed--;
249            p->bus.type = BUS_NONE;
250            return;
251        }
252    }
253}
254
255/*
256 * Parse a BUS ID string, and return the PCI bus parameters if it was
257 * in the correct format for a PCI bus id.
258 */
259
260Bool
261xf86ParsePciBusString(const char *busID, int *bus, int *device, int *func)
262{
263    /*
264     * The format is assumed to be "bus[@domain]:device[:func]", where domain,
265     * bus, device and func are decimal integers.  domain and func may be
266     * omitted and assumed to be zero, although doing this isn't encouraged.
267     */
268
269    char *p, *s, *d;
270    const char *id;
271    int i;
272
273    if (StringToBusType(busID, &id) != BUS_PCI)
274        return FALSE;
275
276    s = xstrdup(id);
277    p = strtok(s, ":");
278    if (p == NULL || *p == 0) {
279        free(s);
280        return FALSE;
281    }
282    d = strpbrk(p, "@");
283    if (d != NULL) {
284        *(d++) = 0;
285        for (i = 0; d[i] != 0; i++) {
286            if (!isdigit(d[i])) {
287                free(s);
288                return FALSE;
289            }
290        }
291    }
292    for (i = 0; p[i] != 0; i++) {
293        if (!isdigit(p[i])) {
294            free(s);
295            return FALSE;
296        }
297    }
298    *bus = atoi(p);
299    if (d != NULL && *d != 0)
300        *bus += atoi(d) << 8;
301    p = strtok(NULL, ":");
302    if (p == NULL || *p == 0) {
303        free(s);
304        return FALSE;
305    }
306    for (i = 0; p[i] != 0; i++) {
307        if (!isdigit(p[i])) {
308            free(s);
309            return FALSE;
310        }
311    }
312    *device = atoi(p);
313    *func = 0;
314    p = strtok(NULL, ":");
315    if (p == NULL || *p == 0) {
316        free(s);
317        return TRUE;
318    }
319    for (i = 0; p[i] != 0; i++) {
320        if (!isdigit(p[i])) {
321            free(s);
322            return FALSE;
323        }
324    }
325    *func = atoi(p);
326    free(s);
327    return TRUE;
328}
329
330/*
331 * Compare a BUS ID string with a PCI bus id.  Return TRUE if they match.
332 */
333
334Bool
335xf86ComparePciBusString(const char *busID, int bus, int device, int func)
336{
337    int ibus, idevice, ifunc;
338
339    if (xf86ParsePciBusString(busID, &ibus, &idevice, &ifunc)) {
340        return bus == ibus && device == idevice && func == ifunc;
341    }
342    else {
343        return FALSE;
344    }
345}
346
347/*
348 * xf86IsPrimaryPci() -- return TRUE if primary device
349 * is PCI and bus, dev and func numbers match.
350 */
351
352Bool
353xf86IsPrimaryPci(struct pci_device *pPci)
354{
355    if (primaryBus.type == BUS_PCI)
356        return pPci == primaryBus.id.pci;
357#ifdef XSERVER_PLATFORM_BUS
358    if (primaryBus.type == BUS_PLATFORM)
359        if (primaryBus.id.plat->pdev)
360            if (MATCH_PCI_DEVICES(primaryBus.id.plat->pdev, pPci))
361                return TRUE;
362#endif
363    return FALSE;
364}
365
366/*
367 * xf86GetPciInfoForEntity() -- Get the pciVideoRec of entity.
368 */
369struct pci_device *
370xf86GetPciInfoForEntity(int entityIndex)
371{
372    EntityPtr p;
373
374    if (entityIndex >= xf86NumEntities)
375        return NULL;
376
377    p = xf86Entities[entityIndex];
378    switch (p->bus.type) {
379    case BUS_PCI:
380        return p->bus.id.pci;
381    case BUS_PLATFORM:
382        return p->bus.id.plat->pdev;
383    default:
384        break;
385    }
386    return NULL;
387}
388
389/*
390 * xf86CheckPciMemBase() checks that the memory base value matches one of the
391 * PCI base address register values for the given PCI device.
392 */
393Bool
394xf86CheckPciMemBase(struct pci_device *pPci, memType base)
395{
396    int i;
397
398    for (i = 0; i < 6; i++)
399        if (base == pPci->regions[i].base_addr)
400            return TRUE;
401    return FALSE;
402}
403
404/*
405 * Check if the slot requested is free.  If it is already in use, return FALSE.
406 */
407
408Bool
409xf86CheckPciSlot(const struct pci_device *d)
410{
411    int i;
412
413    for (i = 0; i < xf86NumEntities; i++) {
414        const EntityPtr p = xf86Entities[i];
415
416        if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
417            return FALSE;
418        }
419#ifdef XSERVER_PLATFORM_BUS
420        if ((p->bus.type == BUS_PLATFORM) && (p->bus.id.plat->pdev)) {
421            struct pci_device *ud = p->bus.id.plat->pdev;
422            if (MATCH_PCI_DEVICES(ud, d))
423                return FALSE;
424        }
425#endif
426    }
427    return TRUE;
428}
429
430#define END_OF_MATCHES(m) \
431    (((m).vendor_id == 0) && ((m).device_id == 0) && ((m).subvendor_id == 0))
432
433Bool
434xf86PciAddMatchingDev(DriverPtr drvp)
435{
436    const struct pci_id_match *const devices = drvp->supported_devices;
437    int j;
438    struct pci_device *pPci;
439    struct pci_device_iterator *iter;
440    int numFound = 0;
441
442    iter = pci_id_match_iterator_create(NULL);
443    while ((pPci = pci_device_next(iter)) != NULL) {
444        /* Determine if this device is supported by the driver.  If it is,
445         * add it to the list of devices to configure.
446         */
447        for (j = 0; !END_OF_MATCHES(devices[j]); j++) {
448            if (PCI_ID_COMPARE(devices[j].vendor_id, pPci->vendor_id)
449                && PCI_ID_COMPARE(devices[j].device_id, pPci->device_id)
450                && ((devices[j].device_class_mask & pPci->device_class)
451                    == devices[j].device_class)) {
452                if (xf86CheckPciSlot(pPci)) {
453                    GDevPtr pGDev =
454                        xf86AddBusDeviceToConfigure(drvp->driverName, BUS_PCI,
455                                                    pPci, -1);
456                    if (pGDev != NULL) {
457                        /* After configure pass 1, chipID and chipRev are
458                         * treated as over-rides, so clobber them here.
459                         */
460                        pGDev->chipID = -1;
461                        pGDev->chipRev = -1;
462                    }
463
464                    numFound++;
465                }
466
467                break;
468            }
469        }
470    }
471
472    pci_iterator_destroy(iter);
473
474    return numFound != 0;
475}
476
477Bool
478xf86PciProbeDev(DriverPtr drvp)
479{
480    int i, j;
481    struct pci_device *pPci;
482    Bool foundScreen = FALSE;
483    const struct pci_id_match *const devices = drvp->supported_devices;
484    GDevPtr *devList;
485    const unsigned numDevs = xf86MatchDevice(drvp->driverName, &devList);
486
487    for (i = 0; i < numDevs; i++) {
488        struct pci_device_iterator *iter;
489        unsigned device_id;
490
491        /* Find the pciVideoRec associated with this device section.
492         */
493        iter = pci_id_match_iterator_create(NULL);
494        while ((pPci = pci_device_next(iter)) != NULL) {
495            if (devList[i]->busID && *devList[i]->busID) {
496                if (xf86ComparePciBusString(devList[i]->busID,
497                                            ((pPci->domain << 8)
498                                             | pPci->bus),
499                                            pPci->dev, pPci->func)) {
500                    break;
501                }
502            }
503            else if (xf86IsPrimaryPci(pPci)) {
504                break;
505            }
506        }
507
508        pci_iterator_destroy(iter);
509
510        if (pPci == NULL) {
511            continue;
512        }
513        device_id = (devList[i]->chipID > 0)
514            ? devList[i]->chipID : pPci->device_id;
515
516        /* Once the pciVideoRec is found, determine if the device is supported
517         * by the driver.  If it is, probe it!
518         */
519        for (j = 0; !END_OF_MATCHES(devices[j]); j++) {
520            if (PCI_ID_COMPARE(devices[j].vendor_id, pPci->vendor_id)
521                && PCI_ID_COMPARE(devices[j].device_id, device_id)
522                && ((devices[j].device_class_mask & pPci->device_class)
523                    == devices[j].device_class)) {
524                int entry;
525
526                /* Allow the same entity to be used more than once for
527                 * devices with multiple screens per entity.  This assumes
528                 * implicitly that there will be a screen == 0 instance.
529                 *
530                 * FIXME Need to make sure that two different drivers don't
531                 * FIXME claim the same screen > 0 instance.
532                 */
533                if ((devList[i]->screen == 0) && !xf86CheckPciSlot(pPci))
534                    continue;
535
536                DebugF("%s: card at %d:%d:%d is claimed by a Device section\n",
537                       drvp->driverName, pPci->bus, pPci->dev, pPci->func);
538
539                /* Allocate an entry in the lists to be returned */
540                entry = xf86ClaimPciSlot(pPci, drvp, device_id,
541                                         devList[i], devList[i]->active);
542
543                if ((entry == -1) && (devList[i]->screen > 0)) {
544                    unsigned k;
545
546                    for (k = 0; k < xf86NumEntities; k++) {
547                        EntityPtr pEnt = xf86Entities[k];
548
549                        if (pEnt->bus.type != BUS_PCI)
550                            continue;
551                        if (pEnt->bus.id.pci == pPci) {
552                            entry = k;
553                            xf86AddDevToEntity(k, devList[i]);
554                            break;
555                        }
556                    }
557                }
558
559                if (entry != -1) {
560                    if ((*drvp->PciProbe) (drvp, entry, pPci,
561                                           devices[j].match_data)) {
562                        foundScreen = TRUE;
563                    }
564                    else
565                        xf86UnclaimPciSlot(pPci, devList[i]);
566                }
567
568                break;
569            }
570        }
571    }
572    free(devList);
573
574    return foundScreen;
575}
576
577void
578xf86PciIsolateDevice(const char *argument)
579{
580    int bus, device, func;
581
582    if (sscanf(argument, "PCI:%d:%d:%d", &bus, &device, &func) == 3) {
583        xf86IsolateDevice.domain = PCI_DOM_FROM_BUS(bus);
584        xf86IsolateDevice.bus = PCI_BUS_NO_DOMAIN(bus);
585        xf86IsolateDevice.dev = device;
586        xf86IsolateDevice.func = func;
587    }
588    else
589        FatalError("Invalid isolated device specification\n");
590}
591
592static Bool
593pciDeviceHasBars(struct pci_device *pci)
594{
595    int i;
596
597    for (i = 0; i < 6; i++)
598        if (pci->regions[i].size)
599            return TRUE;
600
601    if (pci->rom_size)
602        return TRUE;
603
604    return FALSE;
605}
606
607struct Inst {
608    struct pci_device *pci;
609    GDevPtr dev;
610    Bool foundHW;               /* PCIid in list of supported chipsets */
611    Bool claimed;               /* BusID matches with a device section */
612    int chip;
613    int screen;
614};
615
616/**
617 * Find set of unclaimed devices matching a given vendor ID.
618 *
619 * Used by drivers to find as yet unclaimed devices matching the specified
620 * vendor ID.
621 *
622 * \param driverName     Name of the driver.  This is used to find Device
623 *                       sections in the config file.
624 * \param vendorID       PCI vendor ID of associated devices.  If zero, then
625 *                       the true vendor ID must be encoded in the \c PCIid
626 *                       fields of the \c PCIchipsets entries.
627 * \param chipsets       Symbol table used to associate chipset names with
628 *                       PCI IDs.
629 * \param devList        List of Device sections parsed from the config file.
630 * \param numDevs        Number of entries in \c devList.
631 * \param drvp           Pointer the driver's control structure.
632 * \param foundEntities  Returned list of entity indicies associated with the
633 *                       driver.
634 *
635 * \returns
636 * The number of elements in returned in \c foundEntities on success or zero
637 * on failure.
638 *
639 * \todo
640 * This function does a bit more than short description says.  Fill in some
641 * more of the details of its operation.
642 *
643 * \todo
644 * The \c driverName parameter is redundant.  It is the same as
645 * \c DriverRec::driverName.  In a future version of this function, remove
646 * that parameter.
647 */
648int
649xf86MatchPciInstances(const char *driverName, int vendorID,
650                      SymTabPtr chipsets, PciChipsets * PCIchipsets,
651                      GDevPtr * devList, int numDevs, DriverPtr drvp,
652                      int **foundEntities)
653{
654    int i, j;
655    struct pci_device *pPci;
656    struct pci_device_iterator *iter;
657    struct Inst *instances = NULL;
658    int numClaimedInstances = 0;
659    int allocatedInstances = 0;
660    int numFound = 0;
661    SymTabRec *c;
662    PciChipsets *id;
663    int *retEntities = NULL;
664
665    *foundEntities = NULL;
666
667    /* Each PCI device will contribute at least one entry.  Each device
668     * section can contribute at most one entry.  The sum of the two is
669     * guaranteed to be larger than the maximum possible number of entries.
670     * Do this calculation and memory allocation once now to eliminate the
671     * need for realloc calls inside the loop.
672     */
673    if (!(xf86DoConfigure && xf86DoConfigurePass1)) {
674        unsigned max_entries = numDevs;
675
676        iter = pci_slot_match_iterator_create(NULL);
677        while ((pPci = pci_device_next(iter)) != NULL) {
678            max_entries++;
679        }
680
681        pci_iterator_destroy(iter);
682        instances = xnfallocarray(max_entries, sizeof(struct Inst));
683    }
684
685    iter = pci_slot_match_iterator_create(NULL);
686    while ((pPci = pci_device_next(iter)) != NULL) {
687        unsigned device_class = pPci->device_class;
688        Bool foundVendor = FALSE;
689
690        /* Convert the pre-PCI 2.0 device class for a VGA adapter to the
691         * 2.0 version of the same class.
692         */
693        if (device_class == 0x00000101) {
694            device_class = 0x00030000;
695        }
696
697        /* Find PCI devices that match the given vendor ID.  The vendor ID is
698         * either specified explicitly as a parameter to the function or
699         * implicitly encoded in the high bits of id->PCIid.
700         *
701         * The first device with a matching vendor is recorded, even if the
702         * device ID doesn't match.  This is done because the Device section
703         * in the xorg.conf file can over-ride the device ID.  A matching PCI
704         * ID might not be found now, but after the device ID over-ride is
705         * applied there /might/ be a match.
706         */
707        for (id = PCIchipsets; id->PCIid != -1; id++) {
708            const unsigned vendor_id = ((id->PCIid & 0xFFFF0000) >> 16)
709                | vendorID;
710            const unsigned device_id = (id->PCIid & 0x0000FFFF);
711            const unsigned match_class = 0x00030000 | id->PCIid;
712
713            if ((vendor_id == pPci->vendor_id)
714                || ((vendorID == PCI_VENDOR_GENERIC) &&
715                    (match_class == device_class))) {
716                if (!foundVendor && (instances != NULL)) {
717                    ++allocatedInstances;
718                    instances[allocatedInstances - 1].pci = pPci;
719                    instances[allocatedInstances - 1].dev = NULL;
720                    instances[allocatedInstances - 1].claimed = FALSE;
721                    instances[allocatedInstances - 1].foundHW = FALSE;
722                    instances[allocatedInstances - 1].screen = 0;
723                }
724
725                foundVendor = TRUE;
726
727                if ((device_id == pPci->device_id)
728                    || ((vendorID == PCI_VENDOR_GENERIC)
729                        && (match_class == device_class))) {
730                    if (instances != NULL) {
731                        instances[allocatedInstances - 1].foundHW = TRUE;
732                        instances[allocatedInstances - 1].chip = id->numChipset;
733                    }
734
735                    if (xf86DoConfigure && xf86DoConfigurePass1) {
736                        if (xf86CheckPciSlot(pPci)) {
737                            GDevPtr pGDev =
738                                xf86AddBusDeviceToConfigure(drvp->driverName,
739                                                            BUS_PCI, pPci, -1);
740
741                            if (pGDev) {
742                                /* After configure pass 1, chipID and chipRev
743                                 * are treated as over-rides, so clobber them
744                                 * here.
745                                 */
746                                pGDev->chipID = -1;
747                                pGDev->chipRev = -1;
748                            }
749
750                            numFound++;
751                        }
752                    }
753                    else {
754                        numFound++;
755                    }
756
757                    break;
758                }
759            }
760        }
761    }
762
763    pci_iterator_destroy(iter);
764
765    /* In "probe only" or "configure" mode (signaled by instances being NULL),
766     * our work is done.  Return the number of detected devices.
767     */
768    if (instances == NULL) {
769        return numFound;
770    }
771
772    /*
773     * This may be debatable, but if no PCI devices with a matching vendor
774     * type is found, return zero now.  It is probably not desirable to
775     * allow the config file to override this.
776     */
777    if (allocatedInstances <= 0) {
778        free(instances);
779        return 0;
780    }
781
782    DebugF("%s instances found: %d\n", driverName, allocatedInstances);
783
784    /*
785     * Check for devices that need duplicated instances.  This is required
786     * when there is more than one screen per entity.
787     *
788     * XXX This currently doesn't work for cases where the BusID isn't
789     * specified explicitly in the config file.
790     */
791
792    for (j = 0; j < numDevs; j++) {
793        if (devList[j]->screen > 0 && devList[j]->busID && *devList[j]->busID) {
794            for (i = 0; i < allocatedInstances; i++) {
795                pPci = instances[i].pci;
796                if (xf86ComparePciBusString(devList[j]->busID,
797                                            PCI_MAKE_BUS(pPci->domain,
798                                                         pPci->bus), pPci->dev,
799                                            pPci->func)) {
800                    allocatedInstances++;
801                    instances[allocatedInstances - 1] = instances[i];
802                    instances[allocatedInstances - 1].screen =
803                        devList[j]->screen;
804                    numFound++;
805                    break;
806                }
807            }
808        }
809    }
810
811    for (i = 0; i < allocatedInstances; i++) {
812        GDevPtr dev = NULL;
813        GDevPtr devBus = NULL;
814
815        pPci = instances[i].pci;
816        for (j = 0; j < numDevs; j++) {
817            if (devList[j]->busID && *devList[j]->busID) {
818                if (xf86ComparePciBusString(devList[j]->busID,
819                                            PCI_MAKE_BUS(pPci->domain,
820                                                         pPci->bus), pPci->dev,
821                                            pPci->func) &&
822                    devList[j]->screen == instances[i].screen) {
823
824                    if (devBus)
825                        xf86MsgVerb(X_WARNING, 0,
826                                    "%s: More than one matching Device section for "
827                                    "instances\n\t(BusID: %s) found: %s\n",
828                                    driverName, devList[j]->busID,
829                                    devList[j]->identifier);
830                    else
831                        devBus = devList[j];
832                }
833            }
834            else {
835                /*
836                 * if device section without BusID is found
837                 * only assign to it to the primary device.
838                 */
839                if (xf86IsPrimaryPci(pPci)) {
840                    xf86Msg(X_PROBED, "Assigning device section with no busID"
841                            " to primary device\n");
842                    if (dev || devBus)
843                        xf86MsgVerb(X_WARNING, 0,
844                                    "%s: More than one matching Device section "
845                                    "found: %s\n", driverName,
846                                    devList[j]->identifier);
847                    else
848                        dev = devList[j];
849                }
850            }
851        }
852        if (devBus)
853            dev = devBus;       /* busID preferred */
854        if (!dev) {
855            if (xf86CheckPciSlot(pPci) && pciDeviceHasBars(pPci)) {
856                xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section "
857                            "for instance (BusID PCI:%u@%u:%u:%u) found\n",
858                            driverName, pPci->domain, pPci->bus, pPci->dev,
859                            pPci->func);
860            }
861        }
862        else {
863            numClaimedInstances++;
864            instances[i].claimed = TRUE;
865            instances[i].dev = dev;
866        }
867    }
868    DebugF("%s instances found: %d\n", driverName, numClaimedInstances);
869    /*
870     * Now check that a chipset or chipID override in the device section
871     * is valid.  Chipset has precedence over chipID.
872     * If chipset is not valid ignore BusSlot completely.
873     */
874    for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
875        MessageType from = X_PROBED;
876
877        if (!instances[i].claimed) {
878            continue;
879        }
880        if (instances[i].dev->chipset) {
881            for (c = chipsets; c->token >= 0; c++) {
882                if (xf86NameCmp(c->name, instances[i].dev->chipset) == 0)
883                    break;
884            }
885            if (c->token == -1) {
886                instances[i].claimed = FALSE;
887                numClaimedInstances--;
888                xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device "
889                            "section \"%s\" isn't valid for this driver\n",
890                            driverName, instances[i].dev->chipset,
891                            instances[i].dev->identifier);
892            }
893            else {
894                instances[i].chip = c->token;
895
896                for (id = PCIchipsets; id->numChipset >= 0; id++) {
897                    if (id->numChipset == instances[i].chip)
898                        break;
899                }
900                if (id->numChipset >= 0) {
901                    xf86Msg(X_CONFIG, "Chipset override: %s\n",
902                            instances[i].dev->chipset);
903                    from = X_CONFIG;
904                }
905                else {
906                    instances[i].claimed = FALSE;
907                    numClaimedInstances--;
908                    xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device "
909                                "section \"%s\" isn't a valid PCI chipset\n",
910                                driverName, instances[i].dev->chipset,
911                                instances[i].dev->identifier);
912                }
913            }
914        }
915        else if (instances[i].dev->chipID > 0) {
916            for (id = PCIchipsets; id->numChipset >= 0; id++) {
917                if (id->PCIid == instances[i].dev->chipID)
918                    break;
919            }
920            if (id->numChipset == -1) {
921                instances[i].claimed = FALSE;
922                numClaimedInstances--;
923                xf86MsgVerb(X_WARNING, 0, "%s: ChipID 0x%04X in Device "
924                            "section \"%s\" isn't valid for this driver\n",
925                            driverName, instances[i].dev->chipID,
926                            instances[i].dev->identifier);
927            }
928            else {
929                instances[i].chip = id->numChipset;
930
931                xf86Msg(X_CONFIG, "ChipID override: 0x%04X\n",
932                        instances[i].dev->chipID);
933                from = X_CONFIG;
934            }
935        }
936        else if (!instances[i].foundHW) {
937            /*
938             * This means that there was no override and the PCI chipType
939             * doesn't match one that is supported
940             */
941            instances[i].claimed = FALSE;
942            numClaimedInstances--;
943        }
944        if (instances[i].claimed == TRUE) {
945            for (c = chipsets; c->token >= 0; c++) {
946                if (c->token == instances[i].chip)
947                    break;
948            }
949            xf86Msg(from, "Chipset %s found\n", c->name);
950        }
951    }
952
953    /*
954     * Of the claimed instances, check that another driver hasn't already
955     * claimed its slot.
956     */
957    numFound = 0;
958    for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
959        if (!instances[i].claimed)
960            continue;
961        pPci = instances[i].pci;
962
963        /*
964         * Allow the same entity to be used more than once for devices with
965         * multiple screens per entity.  This assumes implicitly that there
966         * will be a screen == 0 instance.
967         *
968         * XXX Need to make sure that two different drivers don't claim
969         * the same screen > 0 instance.
970         */
971        if (instances[i].screen == 0 && !xf86CheckPciSlot(pPci))
972            continue;
973
974        DebugF("%s: card at %d:%d:%d is claimed by a Device section\n",
975               driverName, pPci->bus, pPci->dev, pPci->func);
976
977        /* Allocate an entry in the lists to be returned */
978        numFound++;
979        retEntities = xnfreallocarray(retEntities, numFound, sizeof(int));
980        retEntities[numFound - 1] = xf86ClaimPciSlot(pPci, drvp,
981                                                     instances[i].chip,
982                                                     instances[i].dev,
983                                                     instances[i].dev->active);
984        if (retEntities[numFound - 1] == -1 && instances[i].screen > 0) {
985            for (j = 0; j < xf86NumEntities; j++) {
986                EntityPtr pEnt = xf86Entities[j];
987
988                if (pEnt->bus.type != BUS_PCI)
989                    continue;
990                if (pEnt->bus.id.pci == pPci) {
991                    retEntities[numFound - 1] = j;
992                    xf86AddDevToEntity(j, instances[i].dev);
993                    break;
994                }
995            }
996        }
997    }
998    free(instances);
999    if (numFound > 0) {
1000        *foundEntities = retEntities;
1001    }
1002
1003    return numFound;
1004}
1005
1006/*
1007 * xf86ConfigPciEntityInactive() -- This function can be used
1008 * to configure an inactive entity as well as to reconfigure an
1009 * previously active entity inactive. If the entity has been
1010 * assigned to a screen before it will be removed. If p_chip is
1011 * non-NULL all static resources listed there will be registered.
1012 */
1013static void
1014xf86ConfigPciEntityInactive(EntityInfoPtr pEnt, PciChipsets * p_chip,
1015                            EntityProc init, EntityProc enter,
1016                            EntityProc leave, void *private)
1017{
1018    ScrnInfoPtr pScrn;
1019
1020    if ((pScrn = xf86FindScreenForEntity(pEnt->index)))
1021        xf86RemoveEntityFromScreen(pScrn, pEnt->index);
1022
1023    /* shared resources are only needed when entity is active: remove */
1024    xf86SetEntityFuncs(pEnt->index, init, enter, leave, private);
1025}
1026
1027ScrnInfoPtr
1028xf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex,
1029                    PciChipsets * p_chip, void *dummy, EntityProc init,
1030                    EntityProc enter, EntityProc leave, void *private)
1031{
1032    EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex);
1033
1034    if (!pEnt)
1035        return pScrn;
1036
1037    if (!(pEnt->location.type == BUS_PCI)
1038        || !xf86GetPciInfoForEntity(entityIndex)) {
1039        free(pEnt);
1040        return pScrn;
1041    }
1042    if (!pEnt->active) {
1043        xf86ConfigPciEntityInactive(pEnt, p_chip, init, enter, leave, private);
1044        free(pEnt);
1045        return pScrn;
1046    }
1047
1048    if (!pScrn)
1049        pScrn = xf86AllocateScreen(pEnt->driver, scrnFlag);
1050    if (xf86IsEntitySharable(entityIndex)) {
1051        xf86SetEntityShared(entityIndex);
1052    }
1053    xf86AddEntityToScreen(pScrn, entityIndex);
1054    if (xf86IsEntityShared(entityIndex)) {
1055        return pScrn;
1056    }
1057    free(pEnt);
1058
1059    xf86SetEntityFuncs(entityIndex, init, enter, leave, private);
1060
1061    return pScrn;
1062}
1063
1064int
1065xf86VideoPtrToDriverList(struct pci_device *dev,
1066                     char *returnList[], int returnListMax)
1067{
1068    int i;
1069
1070    /* Add more entries here if we ever return more than 4 drivers for
1071       any device */
1072    const char *driverList[5] = { NULL, NULL, NULL, NULL, NULL };
1073
1074    switch (dev->vendor_id) { /* AMD Geode LX */
1075    case 0x1022:
1076        if (dev->device_id == 0x2081)
1077            driverList[0] = "geode";
1078        break;
1079        /* older Geode products acquired by AMD still carry an NSC vendor_id */
1080    case 0x100b:
1081        if (dev->device_id == 0x0030) {
1082            /* NSC Geode GX2 specifically */
1083            driverList[0] = "geode";
1084            /* GX2 support started its life in the NSC tree and was later
1085               forked by AMD for GEODE so we keep it as a backup */
1086            driverList[1] = "nsc";
1087        }
1088        else
1089            /* other NSC variant e.g. 0x0104 (SC1400), 0x0504 (SCx200) */
1090            driverList[0] = "nsc";
1091        break;
1092        /* Cyrix Geode GX1 */
1093    case 0x1078:
1094        if (dev->device_id == 0x0104)
1095            driverList[0] = "cyrix";
1096        break;
1097    case 0x1142:
1098        driverList[0] = "apm";
1099        break;
1100    case 0xedd8:
1101        driverList[0] = "ark";
1102        break;
1103    case 0x1a03:
1104        driverList[0] = "ast";
1105        break;
1106    case 0x1002:
1107        driverList[0] = "ati";
1108        break;
1109    case 0x102c:
1110        driverList[0] = "chips";
1111        break;
1112    case 0x1013:
1113        driverList[0] = "cirrus";
1114        break;
1115    case 0x3d3d:
1116        driverList[0] = "glint";
1117        break;
1118    case 0x105d:
1119        driverList[0] = "i128";
1120        break;
1121    case 0x8086:
1122	switch (dev->device_id)
1123	{
1124		/* Intel i740 */
1125		case 0x00d1:
1126		case 0x7800:
1127			driverList[0] = "i740";
1128			break;
1129		/* GMA500/Poulsbo */
1130		case 0x8108:
1131		case 0x8109:
1132			/* Try psb driver on Poulsbo - if available */
1133			driverList[0] = "psb";
1134			driverList[1] = "psb_drv";
1135			break;
1136		/* GMA600/Oaktrail */
1137		case 0x4100:
1138		case 0x4101:
1139		case 0x4102:
1140		case 0x4103:
1141		case 0x4104:
1142		case 0x4105:
1143		case 0x4106:
1144		case 0x4107:
1145		/* Atom E620/Oaktrail */
1146		case 0x4108:
1147		/* Medfield */
1148		case 0x0130:
1149		case 0x0131:
1150		case 0x0132:
1151		case 0x0133:
1152		case 0x0134:
1153		case 0x0135:
1154		case 0x0136:
1155		case 0x0137:
1156		/* GMA 3600/CDV */
1157		case 0x0be0:
1158		case 0x0be1:
1159		case 0x0be2:
1160		case 0x0be3:
1161		case 0x0be4:
1162		case 0x0be5:
1163		case 0x0be6:
1164		case 0x0be7:
1165		case 0x0be8:
1166		case 0x0be9:
1167		case 0x0bea:
1168		case 0x0beb:
1169		case 0x0bec:
1170		case 0x0bed:
1171		case 0x0bee:
1172		case 0x0bef:
1173			/* Use fbdev/vesa driver on Oaktrail, Medfield, CDV */
1174			break;
1175		default:
1176			driverList[0] = "intel";
1177			break;
1178        }
1179        break;
1180    case 0x102b:
1181        driverList[0] = "mga";
1182        break;
1183    case 0x10c8:
1184        driverList[0] = "neomagic";
1185        break;
1186    case 0x10de:
1187    case 0x12d2:
1188    {
1189        int idx = 0;
1190
1191#if defined(__linux__) || defined(__NetBSD__)
1192        driverList[idx++] = "nouveau";
1193#endif
1194        driverList[idx++] = "nv";
1195        break;
1196    }
1197    case 0x1106:
1198        driverList[0] = "openchrome";
1199        break;
1200    case 0x1b36:
1201        driverList[0] = "qxl";
1202        break;
1203    case 0x1163:
1204        driverList[0] = "rendition";
1205        break;
1206    case 0x5333:
1207        switch (dev->device_id) {
1208        case 0x88d0:
1209        case 0x88d1:
1210        case 0x88f0:
1211        case 0x8811:
1212        case 0x8812:
1213        case 0x8814:
1214        case 0x8901:
1215            driverList[0] = "s3";
1216            break;
1217        case 0x5631:
1218        case 0x883d:
1219        case 0x8a01:
1220        case 0x8a10:
1221        case 0x8c01:
1222        case 0x8c03:
1223        case 0x8904:
1224        case 0x8a13:
1225            driverList[0] = "s3virge";
1226            break;
1227        default:
1228            driverList[0] = "savage";
1229            break;
1230        }
1231        break;
1232    case 0x1039:
1233        driverList[0] = "sis";
1234        break;
1235    case 0x126f:
1236        driverList[0] = "siliconmotion";
1237        break;
1238    case 0x121a:
1239        if (dev->device_id < 0x0003)
1240            driverList[0] = "voodoo";
1241        else
1242            driverList[0] = "tdfx";
1243        break;
1244    case 0x1011:
1245        driverList[0] = "tga";
1246        break;
1247    case 0x1023:
1248        driverList[0] = "trident";
1249        break;
1250    case 0x100c:
1251        driverList[0] = "tseng";
1252        break;
1253    case 0x80ee:
1254        driverList[0] = "vboxvideo";
1255        break;
1256    case 0x15ad:
1257        driverList[0] = "vmware";
1258        break;
1259    case 0x18ca:
1260        if (dev->device_id == 0x47)
1261            driverList[0] = "xgixp";
1262        else
1263            driverList[0] = "xgi";
1264        break;
1265    default:
1266        break;
1267    }
1268    for (i = 0; (i < returnListMax) && (driverList[i] != NULL); i++) {
1269        returnList[i] = xnfstrdup(driverList[i]);
1270    }
1271    return i;                   /* Number of entries added */
1272}
1273
1274#ifdef __linux__
1275static int
1276xchomp(char *line)
1277{
1278    size_t len = 0;
1279
1280    if (!line) {
1281        return 1;
1282    }
1283
1284    len = strlen(line);
1285    if (line[len - 1] == '\n' && len > 0) {
1286        line[len - 1] = '\0';
1287    }
1288    return 0;
1289}
1290
1291/* This function is used to provide a workaround for binary drivers that
1292 * don't export their PCI ID's properly. If distros don't end up using this
1293 * feature it can and should be removed because the symbol-based resolution
1294 * scheme should be the primary one */
1295int
1296xf86MatchDriverFromFiles(uint16_t match_vendor, uint16_t match_chip,
1297                         char *matches[], int nmatches)
1298{
1299    DIR *idsdir;
1300    FILE *fp;
1301    struct dirent *direntry;
1302    char *line = NULL;
1303    size_t len;
1304    ssize_t read;
1305    char path_name[256], vendor_str[5], chip_str[5];
1306    uint16_t vendor, chip;
1307    int i = 0, j;
1308
1309    idsdir = opendir(PCI_TXT_IDS_PATH);
1310    if (!idsdir)
1311        return 0;
1312
1313    xf86Msg(X_INFO,
1314            "Scanning %s directory for additional PCI ID's supported by the drivers\n",
1315            PCI_TXT_IDS_PATH);
1316    direntry = readdir(idsdir);
1317    /* Read the directory */
1318    while (direntry) {
1319        if (direntry->d_name[0] == '.') {
1320            direntry = readdir(idsdir);
1321            continue;
1322        }
1323        len = strlen(direntry->d_name);
1324        /* A tiny bit of sanity checking. We should probably do better */
1325        if (strncmp(&(direntry->d_name[len - 4]), ".ids", 4) == 0) {
1326            /* We need the full path name to open the file */
1327            snprintf(path_name, sizeof(path_name), "%s/%s",
1328                     PCI_TXT_IDS_PATH, direntry->d_name);
1329            fp = fopen(path_name, "r");
1330            if (fp == NULL) {
1331                xf86Msg(X_ERROR, "Could not open %s for reading. Exiting.\n",
1332                        path_name);
1333                goto end;
1334            }
1335            /* Read the file */
1336#ifdef __GLIBC__
1337            while ((read = getline(&line, &len, fp)) != -1) {
1338#else
1339            while ((line = fgetln(fp, &len)) != (char *) NULL) {
1340#endif                          /* __GLIBC __ */
1341                xchomp(line);
1342                if (isdigit(line[0])) {
1343                    strlcpy(vendor_str, line, sizeof(vendor_str));
1344                    vendor = (int) strtol(vendor_str, NULL, 16);
1345                    if ((strlen(&line[4])) == 0) {
1346                        chip_str[0] = '\0';
1347                        chip = -1;
1348                    }
1349                    else {
1350                        /* Handle trailing whitespace */
1351                        if (isspace(line[4])) {
1352                            chip_str[0] = '\0';
1353                            chip = -1;
1354                        }
1355                        else {
1356                            /* Ok, it's a real ID */
1357                            strlcpy(chip_str, &line[4], sizeof(chip_str));
1358                            chip = (int) strtol(chip_str, NULL, 16);
1359                        }
1360                    }
1361                    if (vendor == match_vendor && chip == match_chip) {
1362                        matches[i] =
1363                            (char *) malloc(sizeof(char) *
1364                                            strlen(direntry->d_name) - 3);
1365                        if (!matches[i]) {
1366                            xf86Msg(X_ERROR,
1367                                    "Could not allocate space for the module name. Exiting.\n");
1368                            goto end;
1369                        }
1370                        /* hack off the .ids suffix. This should guard
1371                         * against other problems, but it will end up
1372                         * taking off anything after the first '.' */
1373                        for (j = 0; j < (strlen(direntry->d_name) - 3); j++) {
1374                            if (direntry->d_name[j] == '.') {
1375                                matches[i][j] = '\0';
1376                                break;
1377                            }
1378                            else {
1379                                matches[i][j] = direntry->d_name[j];
1380                            }
1381                        }
1382                        xf86Msg(X_INFO, "Matched %s from file name %s\n",
1383                                matches[i], direntry->d_name);
1384                        i++;
1385                    }
1386                }
1387                else {
1388                    /* TODO Handle driver overrides here */
1389                }
1390            }
1391            fclose(fp);
1392        }
1393        direntry = readdir(idsdir);
1394    }
1395 end:
1396    free(line);
1397    closedir(idsdir);
1398    return i;
1399}
1400#endif                          /* __linux__ */
1401
1402/**
1403 *  @return The numbers of found devices that match with the current system
1404 *  drivers.
1405 */
1406int
1407xf86PciMatchDriver(char *matches[], int nmatches)
1408{
1409    int i = 0;
1410    struct pci_device *info = NULL;
1411    struct pci_device_iterator *iter;
1412
1413    /* Find the primary device, and get some information about it. */
1414    iter = pci_slot_match_iterator_create(NULL);
1415    while ((info = pci_device_next(iter)) != NULL) {
1416        if (xf86IsPrimaryPci(info)) {
1417            break;
1418        }
1419    }
1420
1421    pci_iterator_destroy(iter);
1422#ifdef __linux__
1423    if (info)
1424        i += xf86MatchDriverFromFiles(info->vendor_id, info->device_id,
1425                                      matches, nmatches);
1426#endif
1427
1428    if ((info != NULL) && (i < nmatches)) {
1429        i += xf86VideoPtrToDriverList(info, &(matches[i]), nmatches - i);
1430    }
1431
1432    return i;
1433}
1434
1435Bool
1436xf86PciConfigure(void *busData, struct pci_device *pDev)
1437{
1438    struct pci_device *pVideo = NULL;
1439
1440    pVideo = (struct pci_device *) busData;
1441    if (pDev &&
1442        (pDev->domain == pVideo->domain) &&
1443        (pDev->bus == pVideo->bus) &&
1444        (pDev->dev == pVideo->dev) && (pDev->func == pVideo->func))
1445        return 0;
1446
1447    return 1;
1448}
1449
1450void
1451xf86PciConfigureNewDev(void *busData, struct pci_device *pVideo,
1452                       GDevRec * GDev, int *chipset)
1453{
1454    char busnum[8];
1455    char *tmp;
1456
1457    pVideo = (struct pci_device *) busData;
1458
1459    if (pVideo->bus < 256)
1460        snprintf(busnum, sizeof(busnum), "%d", pVideo->bus);
1461    else
1462        snprintf(busnum, sizeof(busnum), "%d@%d",
1463                 pVideo->bus & 0x00ff, pVideo->bus >> 8);
1464
1465    XNFasprintf(&tmp, "PCI:%s:%d:%d",
1466                busnum, pVideo->dev, pVideo->func);
1467    GDev->busID = tmp;
1468
1469    GDev->chipID = pVideo->device_id;
1470    GDev->chipRev = pVideo->revision;
1471
1472    if (*chipset < 0)
1473        *chipset = (pVideo->vendor_id << 16) | pVideo->device_id;
1474}
1475