xf86pciBus.c revision e005038a
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->bus, info->domain, 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    /* Add max. 1 screen for the IgnorePrimary fallback path */
356    if (xf86ProbeIgnorePrimary && xf86NumScreens == 0)
357        return TRUE;
358
359    if (primaryBus.type == BUS_PCI)
360        return pPci == primaryBus.id.pci;
361#ifdef XSERVER_PLATFORM_BUS
362    if (primaryBus.type == BUS_PLATFORM)
363        if (primaryBus.id.plat->pdev)
364            if (MATCH_PCI_DEVICES(primaryBus.id.plat->pdev, pPci))
365                return TRUE;
366#endif
367    return FALSE;
368}
369
370/*
371 * xf86GetPciInfoForEntity() -- Get the pciVideoRec of entity.
372 */
373struct pci_device *
374xf86GetPciInfoForEntity(int entityIndex)
375{
376    EntityPtr p;
377
378    if (entityIndex >= xf86NumEntities)
379        return NULL;
380
381    p = xf86Entities[entityIndex];
382    switch (p->bus.type) {
383    case BUS_PCI:
384        return p->bus.id.pci;
385    case BUS_PLATFORM:
386        return p->bus.id.plat->pdev;
387    default:
388        break;
389    }
390    return NULL;
391}
392
393/*
394 * xf86CheckPciMemBase() checks that the memory base value matches one of the
395 * PCI base address register values for the given PCI device.
396 */
397Bool
398xf86CheckPciMemBase(struct pci_device *pPci, memType base)
399{
400    int i;
401
402    for (i = 0; i < 6; i++)
403        if (base == pPci->regions[i].base_addr)
404            return TRUE;
405    return FALSE;
406}
407
408/*
409 * Check if the slot requested is free.  If it is already in use, return FALSE.
410 */
411
412Bool
413xf86CheckPciSlot(const struct pci_device *d)
414{
415    int i;
416
417    for (i = 0; i < xf86NumEntities; i++) {
418        const EntityPtr p = xf86Entities[i];
419
420        if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
421            return FALSE;
422        }
423#ifdef XSERVER_PLATFORM_BUS
424        if ((p->bus.type == BUS_PLATFORM) && (p->bus.id.plat->pdev)) {
425            struct pci_device *ud = p->bus.id.plat->pdev;
426            if (MATCH_PCI_DEVICES(ud, d))
427                return FALSE;
428        }
429#endif
430    }
431    return TRUE;
432}
433
434#define END_OF_MATCHES(m) \
435    (((m).vendor_id == 0) && ((m).device_id == 0) && ((m).subvendor_id == 0))
436
437Bool
438xf86PciAddMatchingDev(DriverPtr drvp)
439{
440    const struct pci_id_match *const devices = drvp->supported_devices;
441    int j;
442    struct pci_device *pPci;
443    struct pci_device_iterator *iter;
444    int numFound = 0;
445
446    iter = pci_id_match_iterator_create(NULL);
447    while ((pPci = pci_device_next(iter)) != NULL) {
448        /* Determine if this device is supported by the driver.  If it is,
449         * add it to the list of devices to configure.
450         */
451        for (j = 0; !END_OF_MATCHES(devices[j]); j++) {
452            if (PCI_ID_COMPARE(devices[j].vendor_id, pPci->vendor_id)
453                && PCI_ID_COMPARE(devices[j].device_id, pPci->device_id)
454                && ((devices[j].device_class_mask & pPci->device_class)
455                    == devices[j].device_class)) {
456                if (xf86CheckPciSlot(pPci)) {
457                    GDevPtr pGDev =
458                        xf86AddBusDeviceToConfigure(drvp->driverName, BUS_PCI,
459                                                    pPci, -1);
460                    if (pGDev != NULL) {
461                        /* After configure pass 1, chipID and chipRev are
462                         * treated as over-rides, so clobber them here.
463                         */
464                        pGDev->chipID = -1;
465                        pGDev->chipRev = -1;
466                    }
467
468                    numFound++;
469                }
470
471                break;
472            }
473        }
474    }
475
476    pci_iterator_destroy(iter);
477
478    return numFound != 0;
479}
480
481Bool
482xf86PciProbeDev(DriverPtr drvp)
483{
484    int i, j;
485    struct pci_device *pPci;
486    Bool foundScreen = FALSE;
487    const struct pci_id_match *const devices = drvp->supported_devices;
488    GDevPtr *devList;
489    const unsigned numDevs = xf86MatchDevice(drvp->driverName, &devList);
490
491    for (i = 0; i < numDevs; i++) {
492        struct pci_device_iterator *iter;
493        unsigned device_id;
494
495        /* Find the pciVideoRec associated with this device section.
496         */
497        iter = pci_id_match_iterator_create(NULL);
498        while ((pPci = pci_device_next(iter)) != NULL) {
499            if (devList[i]->busID && *devList[i]->busID) {
500                if (xf86ComparePciBusString(devList[i]->busID,
501                                            ((pPci->domain << 8)
502                                             | pPci->bus),
503                                            pPci->dev, pPci->func)) {
504                    break;
505                }
506            }
507            else if (xf86IsPrimaryPci(pPci)) {
508                break;
509            }
510        }
511
512        pci_iterator_destroy(iter);
513
514        if (pPci == NULL) {
515            continue;
516        }
517        device_id = (devList[i]->chipID > 0)
518            ? devList[i]->chipID : pPci->device_id;
519
520        /* Once the pciVideoRec is found, determine if the device is supported
521         * by the driver.  If it is, probe it!
522         */
523        for (j = 0; !END_OF_MATCHES(devices[j]); j++) {
524            if (PCI_ID_COMPARE(devices[j].vendor_id, pPci->vendor_id)
525                && PCI_ID_COMPARE(devices[j].device_id, device_id)
526                && ((devices[j].device_class_mask & pPci->device_class)
527                    == devices[j].device_class)) {
528                int entry;
529
530                /* Allow the same entity to be used more than once for
531                 * devices with multiple screens per entity.  This assumes
532                 * implicitly that there will be a screen == 0 instance.
533                 *
534                 * FIXME Need to make sure that two different drivers don't
535                 * FIXME claim the same screen > 0 instance.
536                 */
537                if ((devList[i]->screen == 0) && !xf86CheckPciSlot(pPci))
538                    continue;
539
540                DebugF("%s: card at %d:%d:%d is claimed by a Device section\n",
541                       drvp->driverName, pPci->bus, pPci->dev, pPci->func);
542
543                /* Allocate an entry in the lists to be returned */
544                entry = xf86ClaimPciSlot(pPci, drvp, device_id,
545                                         devList[i], devList[i]->active);
546
547                if ((entry == -1) && (devList[i]->screen > 0)) {
548                    unsigned k;
549
550                    for (k = 0; k < xf86NumEntities; k++) {
551                        EntityPtr pEnt = xf86Entities[k];
552
553                        if (pEnt->bus.type != BUS_PCI)
554                            continue;
555                        if (pEnt->bus.id.pci == pPci) {
556                            entry = k;
557                            xf86AddDevToEntity(k, devList[i]);
558                            break;
559                        }
560                    }
561                }
562
563                if (entry != -1) {
564                    if ((*drvp->PciProbe) (drvp, entry, pPci,
565                                           devices[j].match_data)) {
566                        foundScreen = TRUE;
567                    }
568                    else
569                        xf86UnclaimPciSlot(pPci, devList[i]);
570                }
571
572                break;
573            }
574        }
575    }
576    free(devList);
577
578    return foundScreen;
579}
580
581void
582xf86PciIsolateDevice(const char *argument)
583{
584    int bus, device, func;
585
586    if (sscanf(argument, "PCI:%d:%d:%d", &bus, &device, &func) == 3) {
587        xf86IsolateDevice.domain = PCI_DOM_FROM_BUS(bus);
588        xf86IsolateDevice.bus = PCI_BUS_NO_DOMAIN(bus);
589        xf86IsolateDevice.dev = device;
590        xf86IsolateDevice.func = func;
591    }
592    else
593        FatalError("Invalid isolated device specification\n");
594}
595
596static Bool
597pciDeviceHasBars(struct pci_device *pci)
598{
599    int i;
600
601    for (i = 0; i < 6; i++)
602        if (pci->regions[i].size)
603            return TRUE;
604
605    if (pci->rom_size)
606        return TRUE;
607
608    return FALSE;
609}
610
611struct Inst {
612    struct pci_device *pci;
613    GDevPtr dev;
614    Bool foundHW;               /* PCIid in list of supported chipsets */
615    Bool claimed;               /* BusID matches with a device section */
616    int chip;
617    int screen;
618};
619
620/**
621 * Find set of unclaimed devices matching a given vendor ID.
622 *
623 * Used by drivers to find as yet unclaimed devices matching the specified
624 * vendor ID.
625 *
626 * \param driverName     Name of the driver.  This is used to find Device
627 *                       sections in the config file.
628 * \param vendorID       PCI vendor ID of associated devices.  If zero, then
629 *                       the true vendor ID must be encoded in the \c PCIid
630 *                       fields of the \c PCIchipsets entries.
631 * \param chipsets       Symbol table used to associate chipset names with
632 *                       PCI IDs.
633 * \param devList        List of Device sections parsed from the config file.
634 * \param numDevs        Number of entries in \c devList.
635 * \param drvp           Pointer the driver's control structure.
636 * \param foundEntities  Returned list of entity indicies associated with the
637 *                       driver.
638 *
639 * \returns
640 * The number of elements in returned in \c foundEntities on success or zero
641 * on failure.
642 *
643 * \todo
644 * This function does a bit more than short description says.  Fill in some
645 * more of the details of its operation.
646 *
647 * \todo
648 * The \c driverName parameter is redundant.  It is the same as
649 * \c DriverRec::driverName.  In a future version of this function, remove
650 * that parameter.
651 */
652int
653xf86MatchPciInstances(const char *driverName, int vendorID,
654                      SymTabPtr chipsets, PciChipsets * PCIchipsets,
655                      GDevPtr * devList, int numDevs, DriverPtr drvp,
656                      int **foundEntities)
657{
658    int i, j;
659    struct pci_device *pPci;
660    struct pci_device_iterator *iter;
661    struct Inst *instances = NULL;
662    int numClaimedInstances = 0;
663    int allocatedInstances = 0;
664    int numFound = 0;
665    SymTabRec *c;
666    PciChipsets *id;
667    int *retEntities = NULL;
668
669    *foundEntities = NULL;
670
671    /* Each PCI device will contribute at least one entry.  Each device
672     * section can contribute at most one entry.  The sum of the two is
673     * guaranteed to be larger than the maximum possible number of entries.
674     * Do this calculation and memory allocation once now to eliminate the
675     * need for realloc calls inside the loop.
676     */
677    if (!(xf86DoConfigure && xf86DoConfigurePass1)) {
678        unsigned max_entries = numDevs;
679
680        iter = pci_slot_match_iterator_create(NULL);
681        while ((pPci = pci_device_next(iter)) != NULL) {
682            max_entries++;
683        }
684
685        pci_iterator_destroy(iter);
686        instances = xnfallocarray(max_entries, sizeof(struct Inst));
687    }
688
689    iter = pci_slot_match_iterator_create(NULL);
690    while ((pPci = pci_device_next(iter)) != NULL) {
691        unsigned device_class = pPci->device_class;
692        Bool foundVendor = FALSE;
693
694        /* Convert the pre-PCI 2.0 device class for a VGA adapter to the
695         * 2.0 version of the same class.
696         */
697        if (device_class == 0x00000101) {
698            device_class = 0x00030000;
699        }
700
701        /* Find PCI devices that match the given vendor ID.  The vendor ID is
702         * either specified explicitly as a parameter to the function or
703         * implicitly encoded in the high bits of id->PCIid.
704         *
705         * The first device with a matching vendor is recorded, even if the
706         * device ID doesn't match.  This is done because the Device section
707         * in the xorg.conf file can over-ride the device ID.  A matching PCI
708         * ID might not be found now, but after the device ID over-ride is
709         * applied there /might/ be a match.
710         */
711        for (id = PCIchipsets; id->PCIid != -1; id++) {
712            const unsigned vendor_id = ((id->PCIid & 0xFFFF0000) >> 16)
713                | vendorID;
714            const unsigned device_id = (id->PCIid & 0x0000FFFF);
715            const unsigned match_class = 0x00030000 | id->PCIid;
716
717            if ((vendor_id == pPci->vendor_id)
718                || ((vendorID == PCI_VENDOR_GENERIC) &&
719                    (match_class == device_class))) {
720                if (!foundVendor && (instances != NULL)) {
721                    ++allocatedInstances;
722                    instances[allocatedInstances - 1].pci = pPci;
723                    instances[allocatedInstances - 1].dev = NULL;
724                    instances[allocatedInstances - 1].claimed = FALSE;
725                    instances[allocatedInstances - 1].foundHW = FALSE;
726                    instances[allocatedInstances - 1].screen = 0;
727                }
728
729                foundVendor = TRUE;
730
731                if ((device_id == pPci->device_id)
732                    || ((vendorID == PCI_VENDOR_GENERIC)
733                        && (match_class == device_class))) {
734                    if (instances != NULL) {
735                        instances[allocatedInstances - 1].foundHW = TRUE;
736                        instances[allocatedInstances - 1].chip = id->numChipset;
737                    }
738
739                    if (xf86DoConfigure && xf86DoConfigurePass1) {
740                        if (xf86CheckPciSlot(pPci)) {
741                            GDevPtr pGDev =
742                                xf86AddBusDeviceToConfigure(drvp->driverName,
743                                                            BUS_PCI, pPci, -1);
744
745                            if (pGDev) {
746                                /* After configure pass 1, chipID and chipRev
747                                 * are treated as over-rides, so clobber them
748                                 * here.
749                                 */
750                                pGDev->chipID = -1;
751                                pGDev->chipRev = -1;
752                            }
753
754                            numFound++;
755                        }
756                    }
757                    else {
758                        numFound++;
759                    }
760
761                    break;
762                }
763            }
764        }
765    }
766
767    pci_iterator_destroy(iter);
768
769    /* In "probe only" or "configure" mode (signaled by instances being NULL),
770     * our work is done.  Return the number of detected devices.
771     */
772    if (instances == NULL) {
773        return numFound;
774    }
775
776    /*
777     * This may be debatable, but if no PCI devices with a matching vendor
778     * type is found, return zero now.  It is probably not desirable to
779     * allow the config file to override this.
780     */
781    if (allocatedInstances <= 0) {
782        free(instances);
783        return 0;
784    }
785
786    DebugF("%s instances found: %d\n", driverName, allocatedInstances);
787
788    /*
789     * Check for devices that need duplicated instances.  This is required
790     * when there is more than one screen per entity.
791     *
792     * XXX This currently doesn't work for cases where the BusID isn't
793     * specified explicitly in the config file.
794     */
795
796    for (j = 0; j < numDevs; j++) {
797        if (devList[j]->screen > 0 && devList[j]->busID && *devList[j]->busID) {
798            for (i = 0; i < allocatedInstances; i++) {
799                pPci = instances[i].pci;
800                if (xf86ComparePciBusString(devList[j]->busID,
801                                            PCI_MAKE_BUS(pPci->domain,
802                                                         pPci->bus), pPci->dev,
803                                            pPci->func)) {
804                    allocatedInstances++;
805                    instances[allocatedInstances - 1] = instances[i];
806                    instances[allocatedInstances - 1].screen =
807                        devList[j]->screen;
808                    numFound++;
809                    break;
810                }
811            }
812        }
813    }
814
815    for (i = 0; i < allocatedInstances; i++) {
816        GDevPtr dev = NULL;
817        GDevPtr devBus = NULL;
818
819        pPci = instances[i].pci;
820        for (j = 0; j < numDevs; j++) {
821            if (devList[j]->busID && *devList[j]->busID) {
822                if (xf86ComparePciBusString(devList[j]->busID,
823                                            PCI_MAKE_BUS(pPci->domain,
824                                                         pPci->bus), pPci->dev,
825                                            pPci->func) &&
826                    devList[j]->screen == instances[i].screen) {
827
828                    if (devBus)
829                        xf86MsgVerb(X_WARNING, 0,
830                                    "%s: More than one matching Device section for "
831                                    "instances\n\t(BusID: %s) found: %s\n",
832                                    driverName, devList[j]->busID,
833                                    devList[j]->identifier);
834                    else
835                        devBus = devList[j];
836                }
837            }
838            else {
839                /*
840                 * if device section without BusID is found
841                 * only assign to it to the primary device.
842                 */
843                if (xf86IsPrimaryPci(pPci)) {
844                    xf86Msg(X_PROBED, "Assigning device section with no busID"
845                            " to primary device\n");
846                    if (dev || devBus)
847                        xf86MsgVerb(X_WARNING, 0,
848                                    "%s: More than one matching Device section "
849                                    "found: %s\n", driverName,
850                                    devList[j]->identifier);
851                    else
852                        dev = devList[j];
853                }
854            }
855        }
856        if (devBus)
857            dev = devBus;       /* busID preferred */
858        if (!dev) {
859            if (xf86CheckPciSlot(pPci) && pciDeviceHasBars(pPci)) {
860                xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section "
861                            "for instance (BusID PCI:%u@%u:%u:%u) found\n",
862                            driverName, pPci->bus, pPci->domain, pPci->dev,
863                            pPci->func);
864            }
865        }
866        else {
867            numClaimedInstances++;
868            instances[i].claimed = TRUE;
869            instances[i].dev = dev;
870        }
871    }
872    DebugF("%s instances found: %d\n", driverName, numClaimedInstances);
873    /*
874     * Now check that a chipset or chipID override in the device section
875     * is valid.  Chipset has precedence over chipID.
876     * If chipset is not valid ignore BusSlot completely.
877     */
878    for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
879        MessageType from = X_PROBED;
880
881        if (!instances[i].claimed) {
882            continue;
883        }
884        if (instances[i].dev->chipset) {
885            for (c = chipsets; c->token >= 0; c++) {
886                if (xf86NameCmp(c->name, instances[i].dev->chipset) == 0)
887                    break;
888            }
889            if (c->token == -1) {
890                instances[i].claimed = FALSE;
891                numClaimedInstances--;
892                xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device "
893                            "section \"%s\" isn't valid for this driver\n",
894                            driverName, instances[i].dev->chipset,
895                            instances[i].dev->identifier);
896            }
897            else {
898                instances[i].chip = c->token;
899
900                for (id = PCIchipsets; id->numChipset >= 0; id++) {
901                    if (id->numChipset == instances[i].chip)
902                        break;
903                }
904                if (id->numChipset >= 0) {
905                    xf86Msg(X_CONFIG, "Chipset override: %s\n",
906                            instances[i].dev->chipset);
907                    from = X_CONFIG;
908                }
909                else {
910                    instances[i].claimed = FALSE;
911                    numClaimedInstances--;
912                    xf86MsgVerb(X_WARNING, 0, "%s: Chipset \"%s\" in Device "
913                                "section \"%s\" isn't a valid PCI chipset\n",
914                                driverName, instances[i].dev->chipset,
915                                instances[i].dev->identifier);
916                }
917            }
918        }
919        else if (instances[i].dev->chipID > 0) {
920            for (id = PCIchipsets; id->numChipset >= 0; id++) {
921                if (id->PCIid == instances[i].dev->chipID)
922                    break;
923            }
924            if (id->numChipset == -1) {
925                instances[i].claimed = FALSE;
926                numClaimedInstances--;
927                xf86MsgVerb(X_WARNING, 0, "%s: ChipID 0x%04X in Device "
928                            "section \"%s\" isn't valid for this driver\n",
929                            driverName, instances[i].dev->chipID,
930                            instances[i].dev->identifier);
931            }
932            else {
933                instances[i].chip = id->numChipset;
934
935                xf86Msg(X_CONFIG, "ChipID override: 0x%04X\n",
936                        instances[i].dev->chipID);
937                from = X_CONFIG;
938            }
939        }
940        else if (!instances[i].foundHW) {
941            /*
942             * This means that there was no override and the PCI chipType
943             * doesn't match one that is supported
944             */
945            instances[i].claimed = FALSE;
946            numClaimedInstances--;
947        }
948        if (instances[i].claimed == TRUE) {
949            for (c = chipsets; c->token >= 0; c++) {
950                if (c->token == instances[i].chip)
951                    break;
952            }
953            xf86Msg(from, "Chipset %s found\n", c->name);
954        }
955    }
956
957    /*
958     * Of the claimed instances, check that another driver hasn't already
959     * claimed its slot.
960     */
961    numFound = 0;
962    for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
963        if (!instances[i].claimed)
964            continue;
965        pPci = instances[i].pci;
966
967        /*
968         * Allow the same entity to be used more than once for devices with
969         * multiple screens per entity.  This assumes implicitly that there
970         * will be a screen == 0 instance.
971         *
972         * XXX Need to make sure that two different drivers don't claim
973         * the same screen > 0 instance.
974         */
975        if (instances[i].screen == 0 && !xf86CheckPciSlot(pPci))
976            continue;
977
978        DebugF("%s: card at %d:%d:%d is claimed by a Device section\n",
979               driverName, pPci->bus, pPci->dev, pPci->func);
980
981        /* Allocate an entry in the lists to be returned */
982        numFound++;
983        retEntities = xnfreallocarray(retEntities, numFound, sizeof(int));
984        retEntities[numFound - 1] = xf86ClaimPciSlot(pPci, drvp,
985                                                     instances[i].chip,
986                                                     instances[i].dev,
987                                                     instances[i].dev->active);
988        if (retEntities[numFound - 1] == -1 && instances[i].screen > 0) {
989            for (j = 0; j < xf86NumEntities; j++) {
990                EntityPtr pEnt = xf86Entities[j];
991
992                if (pEnt->bus.type != BUS_PCI)
993                    continue;
994                if (pEnt->bus.id.pci == pPci) {
995                    retEntities[numFound - 1] = j;
996                    xf86AddDevToEntity(j, instances[i].dev);
997                    break;
998                }
999            }
1000        }
1001    }
1002    free(instances);
1003    if (numFound > 0) {
1004        *foundEntities = retEntities;
1005    }
1006
1007    return numFound;
1008}
1009
1010/*
1011 * xf86ConfigPciEntityInactive() -- This function can be used
1012 * to configure an inactive entity as well as to reconfigure an
1013 * previously active entity inactive. If the entity has been
1014 * assigned to a screen before it will be removed. If p_chip is
1015 * non-NULL all static resources listed there will be registered.
1016 */
1017static void
1018xf86ConfigPciEntityInactive(EntityInfoPtr pEnt, PciChipsets * p_chip,
1019                            EntityProc init, EntityProc enter,
1020                            EntityProc leave, void *private)
1021{
1022    ScrnInfoPtr pScrn;
1023
1024    if ((pScrn = xf86FindScreenForEntity(pEnt->index)))
1025        xf86RemoveEntityFromScreen(pScrn, pEnt->index);
1026}
1027
1028ScrnInfoPtr
1029xf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex,
1030                    PciChipsets * p_chip, void *dummy, EntityProc init,
1031                    EntityProc enter, EntityProc leave, void *private)
1032{
1033    EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex);
1034
1035    if (dummy || init || enter || leave)
1036        FatalError("Legacy entity access functions are unsupported\n");
1037
1038    if (!pEnt)
1039        return pScrn;
1040
1041    if (!(pEnt->location.type == BUS_PCI)
1042        || !xf86GetPciInfoForEntity(entityIndex)) {
1043        free(pEnt);
1044        return pScrn;
1045    }
1046    if (!pEnt->active) {
1047        xf86ConfigPciEntityInactive(pEnt, p_chip, init, enter, leave, private);
1048        free(pEnt);
1049        return pScrn;
1050    }
1051
1052    if (!pScrn)
1053        pScrn = xf86AllocateScreen(pEnt->driver, scrnFlag);
1054    if (xf86IsEntitySharable(entityIndex)) {
1055        xf86SetEntityShared(entityIndex);
1056    }
1057    xf86AddEntityToScreen(pScrn, entityIndex);
1058    if (xf86IsEntityShared(entityIndex)) {
1059        return pScrn;
1060    }
1061    free(pEnt);
1062
1063    return pScrn;
1064}
1065
1066void
1067xf86VideoPtrToDriverList(struct pci_device *dev, XF86MatchedDrivers *md)
1068{
1069    int i;
1070
1071    /* Add more entries here if we ever return more than 4 drivers for
1072       any device */
1073    const char *driverList[5] = { NULL, NULL, NULL, NULL, NULL };
1074
1075    switch (dev->vendor_id) {
1076        /* AMD Geode LX */
1077    case 0x1022:
1078        if (dev->device_id == 0x2081)
1079            driverList[0] = "geode";
1080        break;
1081        /* older Geode products acquired by AMD still carry an NSC vendor_id */
1082    case 0x100b:
1083        if (dev->device_id == 0x0030) {
1084            /* NSC Geode GX2 specifically */
1085            driverList[0] = "geode";
1086            /* GX2 support started its life in the NSC tree and was later
1087               forked by AMD for GEODE so we keep it as a backup */
1088            driverList[1] = "nsc";
1089        }
1090        else
1091            /* other NSC variant e.g. 0x0104 (SC1400), 0x0504 (SCx200) */
1092            driverList[0] = "nsc";
1093        break;
1094        /* Cyrix Geode GX1 */
1095    case 0x1078:
1096        if (dev->device_id == 0x0104)
1097            driverList[0] = "cyrix";
1098        break;
1099    case 0x1142:
1100        driverList[0] = "apm";
1101        break;
1102    case 0xedd8:
1103        driverList[0] = "ark";
1104        break;
1105    case 0x1a03:
1106        driverList[0] = "ast";
1107        break;
1108    case 0x1002:
1109        driverList[0] = "ati";
1110        break;
1111    case 0x102c:
1112        driverList[0] = "chips";
1113        break;
1114    case 0x1013:
1115        driverList[0] = "cirrus";
1116        break;
1117    case 0x3d3d:
1118        driverList[0] = "glint";
1119        break;
1120    case 0x105d:
1121        driverList[0] = "i128";
1122        break;
1123    case 0x8086:
1124	switch (dev->device_id)
1125	{
1126		/* Intel i740 */
1127		case 0x00d1:
1128		case 0x7800:
1129			driverList[0] = "i740";
1130			break;
1131		/* GMA500/Poulsbo */
1132		case 0x8108:
1133		case 0x8109:
1134			/* Try psb driver on Poulsbo - if available */
1135			driverList[0] = "psb";
1136			driverList[1] = "psb_drv";
1137			break;
1138		/* GMA600/Oaktrail */
1139		case 0x4100:
1140		case 0x4101:
1141		case 0x4102:
1142		case 0x4103:
1143		case 0x4104:
1144		case 0x4105:
1145		case 0x4106:
1146		case 0x4107:
1147		/* Atom E620/Oaktrail */
1148		case 0x4108:
1149		/* Medfield */
1150		case 0x0130:
1151		case 0x0131:
1152		case 0x0132:
1153		case 0x0133:
1154		case 0x0134:
1155		case 0x0135:
1156		case 0x0136:
1157		case 0x0137:
1158		/* GMA 3600/CDV */
1159		case 0x0be0:
1160		case 0x0be1:
1161		case 0x0be2:
1162		case 0x0be3:
1163		case 0x0be4:
1164		case 0x0be5:
1165		case 0x0be6:
1166		case 0x0be7:
1167		case 0x0be8:
1168		case 0x0be9:
1169		case 0x0bea:
1170		case 0x0beb:
1171		case 0x0bec:
1172		case 0x0bed:
1173		case 0x0bee:
1174		case 0x0bef:
1175			/* Use fbdev/vesa driver on Oaktrail, Medfield, CDV */
1176			break;
1177		default:
1178			driverList[0] = "intel";
1179			break;
1180        }
1181        break;
1182    case 0x102b:
1183        driverList[0] = "mga";
1184        break;
1185    case 0x10c8:
1186        driverList[0] = "neomagic";
1187        break;
1188    case 0x10de:
1189    case 0x12d2:
1190    {
1191        int idx = 0;
1192
1193#if defined(__linux__) || defined(__NetBSD__)
1194        driverList[idx++] = "nouveau";
1195#endif
1196        driverList[idx++] = "nv";
1197        break;
1198    }
1199    case 0x1106:
1200        driverList[0] = "openchrome";
1201        break;
1202    case 0x1b36:
1203        driverList[0] = "qxl";
1204        break;
1205    case 0x1163:
1206        driverList[0] = "rendition";
1207        break;
1208    case 0x5333:
1209        switch (dev->device_id) {
1210        case 0x88d0:
1211        case 0x88d1:
1212        case 0x88f0:
1213        case 0x8811:
1214        case 0x8812:
1215        case 0x8814:
1216        case 0x8901:
1217            driverList[0] = "s3";
1218            break;
1219        case 0x5631:
1220        case 0x883d:
1221        case 0x8a01:
1222        case 0x8a10:
1223        case 0x8c01:
1224        case 0x8c03:
1225        case 0x8904:
1226        case 0x8a13:
1227            driverList[0] = "s3virge";
1228            break;
1229        default:
1230            driverList[0] = "savage";
1231            break;
1232        }
1233        break;
1234    case 0x1039:
1235        driverList[0] = "sis";
1236        break;
1237    case 0x126f:
1238        driverList[0] = "siliconmotion";
1239        break;
1240    case 0x121a:
1241        if (dev->device_id < 0x0003)
1242            driverList[0] = "voodoo";
1243        else
1244            driverList[0] = "tdfx";
1245        break;
1246    case 0x1011:
1247        driverList[0] = "tga";
1248        break;
1249    case 0x1023:
1250        driverList[0] = "trident";
1251        break;
1252    case 0x100c:
1253        driverList[0] = "tseng";
1254        break;
1255    case 0x80ee:
1256        driverList[0] = "vboxvideo";
1257        break;
1258    case 0x15ad:
1259        driverList[0] = "vmware";
1260        break;
1261    case 0x18ca:
1262        if (dev->device_id == 0x47)
1263            driverList[0] = "xgixp";
1264        else
1265            driverList[0] = "xgi";
1266        break;
1267    default:
1268        break;
1269    }
1270    for (i = 0; driverList[i] != NULL; i++) {
1271        xf86AddMatchedDriver(md, driverList[i]);
1272    }
1273}
1274
1275#ifdef __linux__
1276static int
1277xchomp(char *line)
1278{
1279    size_t len = 0;
1280
1281    if (!line) {
1282        return 1;
1283    }
1284
1285    len = strlen(line);
1286    if (line[len - 1] == '\n' && len > 0) {
1287        line[len - 1] = '\0';
1288    }
1289    return 0;
1290}
1291
1292/* This function is used to provide a workaround for binary drivers that
1293 * don't export their PCI ID's properly. If distros don't end up using this
1294 * feature it can and should be removed because the symbol-based resolution
1295 * scheme should be the primary one */
1296void
1297xf86MatchDriverFromFiles(uint16_t match_vendor, uint16_t match_chip,
1298                         XF86MatchedDrivers *md)
1299{
1300    DIR *idsdir;
1301    FILE *fp;
1302    struct dirent *direntry;
1303    char *line = NULL, *tmpMatch;
1304    size_t len;
1305    ssize_t read;
1306    char path_name[512], vendor_str[5], chip_str[5];
1307    uint16_t vendor, chip;
1308    int j;
1309
1310    idsdir = opendir(PCI_TXT_IDS_PATH);
1311    if (!idsdir)
1312        return;
1313
1314    xf86Msg(X_INFO,
1315            "Scanning %s directory for additional PCI ID's supported by the drivers\n",
1316            PCI_TXT_IDS_PATH);
1317    direntry = readdir(idsdir);
1318    /* Read the directory */
1319    while (direntry) {
1320        if (direntry->d_name[0] == '.') {
1321            direntry = readdir(idsdir);
1322            continue;
1323        }
1324        len = strlen(direntry->d_name);
1325        /* A tiny bit of sanity checking. We should probably do better */
1326        if (strncmp(&(direntry->d_name[len - 4]), ".ids", 4) == 0) {
1327            /* We need the full path name to open the file */
1328            snprintf(path_name, sizeof(path_name), "%s/%s",
1329                     PCI_TXT_IDS_PATH, direntry->d_name);
1330            fp = fopen(path_name, "r");
1331            if (fp == NULL) {
1332                xf86Msg(X_ERROR, "Could not open %s for reading. Exiting.\n",
1333                        path_name);
1334                goto end;
1335            }
1336            /* Read the file */
1337#ifdef __GLIBC__
1338            while ((read = getline(&line, &len, fp)) != -1) {
1339#else
1340            while ((line = fgetln(fp, &len)) != (char *) NULL) {
1341#endif                          /* __GLIBC __ */
1342                xchomp(line);
1343                if (isdigit(line[0])) {
1344                    strlcpy(vendor_str, line, sizeof(vendor_str));
1345                    vendor = (int) strtol(vendor_str, NULL, 16);
1346                    if ((strlen(&line[4])) == 0) {
1347                        chip_str[0] = '\0';
1348                        chip = -1;
1349                    }
1350                    else {
1351                        /* Handle trailing whitespace */
1352                        if (isspace(line[4])) {
1353                            chip_str[0] = '\0';
1354                            chip = -1;
1355                        }
1356                        else {
1357                            /* Ok, it's a real ID */
1358                            strlcpy(chip_str, &line[4], sizeof(chip_str));
1359                            chip = (int) strtol(chip_str, NULL, 16);
1360                        }
1361                    }
1362                    if (vendor == match_vendor && chip == match_chip) {
1363                        tmpMatch =
1364                            (char *) malloc(sizeof(char) *
1365                                            strlen(direntry->d_name) - 3);
1366                        if (!tmpMatch) {
1367                            xf86Msg(X_ERROR,
1368                                    "Could not allocate space for the module name. Exiting.\n");
1369                            goto end;
1370                        }
1371                        /* hack off the .ids suffix. This should guard
1372                         * against other problems, but it will end up
1373                         * taking off anything after the first '.' */
1374                        for (j = 0; j < (strlen(direntry->d_name) - 3); j++) {
1375                            if (direntry->d_name[j] == '.') {
1376                                tmpMatch[j] = '\0';
1377                                break;
1378                            }
1379                            else {
1380                                tmpMatch[j] = direntry->d_name[j];
1381                            }
1382                        }
1383                        xf86AddMatchedDriver(md, tmpMatch);
1384                        xf86Msg(X_INFO, "Matched %s from file name %s\n",
1385                                tmpMatch, direntry->d_name);
1386                        free(tmpMatch);
1387                    }
1388                }
1389                else {
1390                    /* TODO Handle driver overrides here */
1391                }
1392            }
1393            fclose(fp);
1394        }
1395        direntry = readdir(idsdir);
1396    }
1397 end:
1398    free(line);
1399    closedir(idsdir);
1400}
1401#endif                          /* __linux__ */
1402
1403void
1404xf86PciMatchDriver(XF86MatchedDrivers *md)
1405{
1406    struct pci_device *info = NULL;
1407    struct pci_device_iterator *iter;
1408
1409    /* Find the primary device, and get some information about it. */
1410    iter = pci_slot_match_iterator_create(NULL);
1411    while ((info = pci_device_next(iter)) != NULL) {
1412        if (xf86IsPrimaryPci(info)) {
1413            break;
1414        }
1415    }
1416
1417    pci_iterator_destroy(iter);
1418#ifdef __linux__
1419    if (info)
1420        xf86MatchDriverFromFiles(info->vendor_id, info->device_id, md);
1421#endif
1422
1423    if (info != NULL) {
1424        xf86VideoPtrToDriverList(info, md);
1425    }
1426}
1427
1428Bool
1429xf86PciConfigure(void *busData, struct pci_device *pDev)
1430{
1431    struct pci_device *pVideo = NULL;
1432
1433    pVideo = (struct pci_device *) busData;
1434    if (pDev &&
1435        (pDev->domain == pVideo->domain) &&
1436        (pDev->bus == pVideo->bus) &&
1437        (pDev->dev == pVideo->dev) && (pDev->func == pVideo->func))
1438        return 0;
1439
1440    return 1;
1441}
1442
1443void
1444xf86PciConfigureNewDev(void *busData, struct pci_device *pVideo,
1445                       GDevRec * GDev, int *chipset)
1446{
1447    char busnum[8];
1448    char *tmp;
1449
1450    pVideo = (struct pci_device *) busData;
1451
1452    snprintf(busnum, sizeof(busnum), "%d", pVideo->bus);
1453
1454    XNFasprintf(&tmp, "PCI:%s:%d:%d",
1455                busnum, pVideo->dev, pVideo->func);
1456    GDev->busID = tmp;
1457
1458    GDev->chipID = pVideo->device_id;
1459    GDev->chipRev = pVideo->revision;
1460
1461    if (*chipset < 0)
1462        *chipset = (pVideo->vendor_id << 16) | pVideo->device_id;
1463}
1464
1465char *
1466DRICreatePCIBusID(const struct pci_device *dev)
1467{
1468    char *busID;
1469
1470    if (asprintf(&busID, "pci:%04x:%02x:%02x.%d",
1471                 dev->domain, dev->bus, dev->dev, dev->func) == -1)
1472        return NULL;
1473
1474    return busID;
1475}
1476