libpciaccess x86 backend

Tiago Vignatti tiago.vignatti at nokia.com
Tue Jan 19 08:44:06 PST 2010


Hi,

I put some minor comments bellow. Make sure you send your future patches to
xorg-devel at lists.freedesktop.org instead. 

On Sun, Jan 17, 2010 at 06:30:00PM +0100, ext Samuel Thibault wrote:
> 
> This adds support on x86 for OSes that do not have a PCI interface,
> tinkering with I/O ports, and makes use of it on GNU/Hurd.
> 
> diff --git a/configure.ac b/configure.ac
> index ffc1c8d..535d704 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -90,6 +90,9 @@ case $host_os in
>                 solaris=yes
>                 PCIACCESS_LIBS="$PCIACCESS_LIBS -ldevinfo"
>                 ;;
> +       gnu*)
> +               gnu=yes
> +               ;;
>  esac
> 
>  AM_CONDITIONAL(LINUX, [test "x$linux" = xyes])
> @@ -97,6 +100,7 @@ AM_CONDITIONAL(FREEBSD, [test "x$freebsd" = xyes])
>  AM_CONDITIONAL(NETBSD, [test "x$netbsd" = xyes])
>  AM_CONDITIONAL(OPENBSD, [test "x$openbsd" = xyes])
>  AM_CONDITIONAL(SOLARIS, [test "x$solaris" = xyes])
> +AM_CONDITIONAL(GNU, [test "x$gnu" = xyes])
> 
>  AC_SYS_LARGEFILE
> 
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 4c06c25..8afd53b 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -51,6 +51,10 @@ else
>  VGA_ARBITER = common_vgaarb_stub.c
>  endif
> 
> +if GNU
> +OS_SUPPORT = x86_pci.c
> +endif

change the name for gnuhurd_pci.c makes more sense for me, given all file
there now are OS related.


>  libpciaccess_la_SOURCES = common_bridge.c \
>         common_iterator.c \
>         common_init.c \
> diff --git a/src/common_init.c b/src/common_init.c
> index 6b9b936..89c56ad 100644
> --- a/src/common_init.c
> +++ b/src/common_init.c
> @@ -62,6 +62,8 @@ pci_system_init( void )
>      err = pci_system_openbsd_create();
>  #elif defined(__sun)
>      err = pci_system_solx_devfs_create();
> +#elif defined(__GNU__)
> +    err = pci_system_x86_create();

I think the same name idea applies for all functions. So I'd prefer something
like pci_system_gnuhurd_create(), etc.


>  #endif
> 
>      return err;
> diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h
> index 77eb57b..1111ef0 100644
> --- a/src/pciaccess_private.h
> +++ b/src/pciaccess_private.h
> @@ -167,4 +167,5 @@ extern int pci_system_netbsd_create( void );
>  extern int pci_system_openbsd_create( void );
>  extern void pci_system_openbsd_init_dev_mem( int );
>  extern int pci_system_solx_devfs_create( void );
> +extern int pci_system_x86_create( void );
>  extern void pci_io_cleanup( void );
> diff --git a/src/x86_pci.c b/src/x86_pci.c
> new file mode 100644
> index 0000000..b5725ef
> --- /dev/null
> +++ b/src/x86_pci.c
> @@ -0,0 +1,669 @@
> +/*
> + * Copyright (c) 2009 Samuel Thibault
> + * Heavily inspired from the freebsd, netbsd, and openbsd backends
> + * (C) Copyright Eric Anholt 2006
> + * (C) Copyright IBM Corporation 2006
> + * Copyright (c) 2008 Juan Romero Pardines
> + * Copyright (c) 2008 Mark Kettenis
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#define _GNU_SOURCE
> +#include <unistd.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <sys/mman.h>
> +#include <string.h>
> +#include <strings.h>
> +
> +#include "pciaccess.h"
> +#include "pciaccess_private.h"
> +
> +#if defined(__GNU__)
> +
> +#include <sys/io.h>
> +
> +static int
> +x86_enable_io(void)
> +{
> +    if (!ioperm(0, 0xffff, 1))
> +        return 0;
> +    return errno;
> +}
> +
> +static int
> +x86_disable_io(void)
> +{
> +    if (!ioperm(0, 0xffff, 0))
> +        return 0;
> +    return errno;
> +}
> +
> +#elif defined(__GLIBC__)
> +
> +#include <sys/io.h>

I'd put hearders on the top...

> +
> +static int
> +x86_enable_io(void)
> +{
> +    if (!iopl(3))
> +        return 0;
> +    return errno;
> +}
> +
> +static int
> +x86_disable_io(void)
> +{
> +    if (!iopl(0))
> +        return 0;
> +    return errno;
> +}
> +
> +#else
> +
> +#error How to enable IO ports on this system?
> +
> +#endif
> +
> +#define PCI_VENDOR(reg)                ((reg) & 0xFFFF)
> +#define PCI_VENDOR_INVALID     0xFFFF
> +
> +#define PCI_VENDOR_ID          0x00
> +#define PCI_SUB_VENDOR_ID      0x2c
> +#define PCI_VENDOR_ID_COMPAQ           0x0e11
> +#define PCI_VENDOR_ID_INTEL            0x8086
> +
> +#define PCI_DEVICE(reg)                (((reg) >> 16) & 0xFFFF)
> +#define PCI_DEVICE_INVALID     0xFFFF
> +
> +#define PCI_CLASS              0x08
> +#define PCI_CLASS_DEVICE       0x0a
> +#define PCI_CLASS_DISPLAY_VGA          0x0300
> +#define PCI_CLASS_BRIDGE_HOST          0x0600
> +
> +#define        PCIC_DISPLAY    0x03
> +#define        PCIS_DISPLAY_VGA        0x00
> +
> +#define PCI_HDRTYPE    0x0E
> +#define PCI_IRQ                0x3C

No, you're being selfish :) 

We should pick all PCI Vendors and Devices ID instead. Basically import all
hw/xfree86/common/xf86PciInfo.h and patch X server to remove it.


> +
> +struct pci_system_x86 {
> +    struct pci_system system;
> +    int (*read)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size);
> +    int (*write)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size);
> +};
> +
> +static int
> +pci_x86_conf1_probe(void)

again: I'd use the "default" pci_device_*, which is being used in the other
files..


> +{
> +    unsigned long sav;
> +    int res = ENODEV;
> +
> +    outb(0x01, 0xCFB);
> +    sav = inl(0xCF8);
> +    outl(0x80000000, 0xCF8);
> +    if (inl(0xCF8) == 0x80000000)
> +       res = 0;
> +    outl(sav, 0xCF8);
> +
> +    return res;
> +}
> +
> +static int
> +pci_x86_conf1_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size)
> +{
> +    unsigned addr = 0xCFC + (reg & 3);
> +    unsigned long sav;
> +    int ret = 0;
> +
> +    if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3)
> +       return EIO;
> +
> +    sav = inl(0xCF8);
> +    outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8);
> +    /* NOTE: x86 is already LE */
> +    switch (size) {
> +       case 1: {
> +           uint8_t *val = data;
> +           *val = inb(addr);
> +           break;
> +       }
> +       case 2: {
> +           uint16_t *val = data;
> +           *val = inw(addr);
> +           break;
> +       }
> +       case 4: {
> +           uint32_t *val = data;
> +           *val = inl(addr);
> +           break;
> +       }
> +    }
> +    outl(sav, 0xCF8);
> +
> +    return ret;
> +}
> +
> +static int
> +pci_x86_conf1_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size)
> +{
> +    unsigned addr = 0xCFC + (reg & 3);
> +    unsigned long sav;
> +    int ret = 0;
> +
> +    if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3)
> +       return EIO;
> +
> +    sav = inl(0xCF8);
> +    outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8);
> +    /* NOTE: x86 is already LE */
> +    switch (size) {
> +       case 1: {
> +           const uint8_t *val = data;
> +           outb(*val, addr);
> +           break;
> +       }
> +       case 2: {
> +           const uint16_t *val = data;
> +           outw(*val, addr);
> +           break;
> +       }
> +       case 4: {
> +           const uint32_t *val = data;
> +           outl(*val, addr);
> +           break;
> +       }
> +    }
> +    outl(sav, 0xCF8);
> +
> +    return ret;
> +}
> +
> +static int
> +pci_x86_conf2_probe(void)
> +{
> +    outb(0, 0xCFB);
> +    outb(0, 0xCF8);
> +    outb(0, 0xCFA);
> +    if (inb(0xCF8) == 0 && inb(0xCFA) == 0)
> +       return 0;
> +
> +    return ENODEV;
> +}
> +
> +static int
> +pci_x86_conf2_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size)
> +{
> +    unsigned addr = 0xC000 | dev << 8 | reg;
> +    int ret = 0;
> +
> +    if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100)
> +       return EIO;
> +
> +    outb((func << 1) | 0xF0, 0xCF8);
> +    outb(bus, 0xCFA);
> +    /* NOTE: x86 is already LE */
> +    switch (size) {
> +       case 1: {
> +           uint8_t *val = data;
> +           *val = inb(addr);
> +           break;
> +       }
> +       case 2: {
> +           uint16_t *val = data;
> +           *val = inw(addr);
> +           break;
> +       }
> +       case 4: {
> +           uint32_t *val = data;
> +           *val = inl(addr);
> +           break;
> +       }
> +       default:
> +           ret = EIO;
> +           break;
> +    }
> +    outb(0, 0xCF8);
> +
> +    return ret;
> +}
> +
> +static int
> +pci_x86_conf2_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size)
> +{
> +    unsigned addr = 0xC000 | dev << 8 | reg;
> +    int ret = 0;
> +
> +    if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100)
> +       return EIO;
> +
> +    outb((func << 1) | 0xF0, 0xCF8);
> +    outb(bus, 0xCFA);
> +    /* NOTE: x86 is already LE */
> +    switch (size) {
> +       case 1: {
> +           const uint8_t *val = data;
> +           outb(*val, addr);
> +           break;
> +       }
> +       case 2: {
> +           const uint16_t *val = data;
> +           outw(*val, addr);
> +           break;
> +       }
> +       case 4: {
> +           const uint32_t *val = data;
> +           outl(*val, addr);
> +           break;
> +       }
> +       default:
> +           ret = EIO;
> +           break;
> +    }
> +    outb(0, 0xCF8);
> +
> +    return ret;
> +}
> +
> +/* Check that this really looks like a PCI configuration. */
> +static int
> +pci_x86_check(struct pci_system_x86 *pci_sys_x86)
> +{
> +    int dev;
> +    uint16_t class, vendor;
> +
> +    /* Look on bus 0 for a device that is a host bridge, a VGA card,
> +     * or an intel or compaq device.  */
> +
> +    for (dev = 0; dev < 32; dev++) {
> +       if (pci_sys_x86->read(0, dev, 0, PCI_CLASS_DEVICE, &class, sizeof(class)))
> +           continue;
> +       if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA)
> +           return 0;
> +       if (pci_sys_x86->read(0, dev, 0, PCI_VENDOR_ID, &vendor, sizeof(vendor)))
> +           continue;
> +       if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ)
> +           return 0;
> +    }
> +
> +    return ENODEV;
> +}
> +
> +static int
> +pci_nfuncs(struct pci_system_x86 *pci_sys_x86, int bus, int dev)
> +{
> +    uint8_t hdr;
> +    int err;
> +
> +    err = pci_sys_x86->read(bus, dev, 0, PCI_HDRTYPE, &hdr, sizeof(hdr));
> +
> +    if (err)
> +       return err;
> +
> +    return hdr & 0x80 ? 8 : 1;
> +}
> +
> +/**
> + * Read a VGA rom using the 0xc0000 mapping.
> + */
> +static int
> +pci_device_x86_read_rom(struct pci_device *dev, void *buffer)
> +{
> +    void *bios;
> +    int memfd;
> +
> +    if ((dev->device_class & 0x00ffff00) !=
> +        ((PCIC_DISPLAY << 16) | ( PCIS_DISPLAY_VGA << 8))) {
> +       return ENOSYS;
> +    }
> +
> +    memfd = open("/dev/mem", O_RDONLY);
> +    if (memfd == -1)
> +       return errno;
> +
> +    bios = mmap(NULL, dev->rom_size, PROT_READ, 0, memfd, 0xc0000);
> +    if (bios == MAP_FAILED) {
> +       close(memfd);
> +       return errno;
> +    }
> +
> +    memcpy(buffer, bios, dev->rom_size);
> +
> +    munmap(bios, dev->rom_size);
> +    close(memfd);
> +
> +    return 0;
> +}
> +
> +/** Returns the number of regions (base address registers) the device has */
> +static int
> +pci_device_x86_get_num_regions(uint8_t header_type)
> +{
> +    switch (header_type & 0x7f) {
> +       case 0:
> +           return 6;
> +       case 1:
> +           return 2;
> +       case 2:
> +           return 1;
> +       default:
> +           fprintf(stderr,"unknown header type %02x\n", header_type);
> +           return 0;
> +    }
> +}
> +
> +/** Masks out the flag bigs of the base address register value */
> +static uint32_t
> +get_map_base( uint32_t val )
> +{
> +    if (val & 0x01)
> +       return val & ~0x03;
> +    else
> +       return val & ~0x0f;
> +}
> +
> +/** Returns the size of a region based on the all-ones test value */
> +static unsigned
> +get_test_val_size( uint32_t testval )
> +{
> +    unsigned size = 1;
> +
> +    if (testval == 0)
> +       return 0;
> +
> +    /* Mask out the flag bits */
> +    testval = get_map_base( testval );
> +    if (!testval)
> +       return 0;
> +
> +    while ((testval & 1) == 0) {
> +       size <<= 1;
> +       testval >>= 1;
> +    }
> +
> +    return size;
> +}
> +
> +static int
> +pci_device_x86_probe(struct pci_device *dev)
> +{
> +    uint8_t irq, hdrtype;
> +    int err, i, bar;
> +
> +    /* Many of the fields were filled in during initial device enumeration.
> +     * At this point, we need to fill in regions, rom_size, and irq.
> +     */
> +
> +    err = pci_device_cfg_read_u8(dev, &irq, PCI_IRQ);
> +    if (err)
> +       return err;
> +    dev->irq = irq;
> +
> +    err = pci_device_cfg_read_u8(dev, &hdrtype, PCI_HDRTYPE);
> +    if (err)
> +       return err;
> +
> +    bar = 0x10;
> +    for (i = 0; i < pci_device_x86_get_num_regions(hdrtype); i++, bar += 4) {
> +       uint32_t addr, testval;
> +
> +       /* Get the base address */
> +       err = pci_device_cfg_read_u32(dev, &addr, bar);
> +       if (err != 0)
> +           continue;
> +
> +       /* Test write all ones to the register, then restore it. */
> +       err = pci_device_cfg_write_u32(dev, 0xffffffff, bar);
> +       if (err != 0)
> +           continue;
> +       pci_device_cfg_read_u32(dev, &testval, bar);
> +       err = pci_device_cfg_write_u32(dev, addr, bar);
> +
> +       if (addr & 0x01)
> +           dev->regions[i].is_IO = 1;
> +       if (addr & 0x04)
> +           dev->regions[i].is_64 = 1;
> +       if (addr & 0x08)
> +           dev->regions[i].is_prefetchable = 1;
> +
> +       /* Set the size */
> +       dev->regions[i].size = get_test_val_size(testval);
> +
> +       /* Set the base address value */
> +       if (dev->regions[i].is_64) {
> +           uint32_t top;
> +
> +           err = pci_device_cfg_read_u32(dev, &top, bar + 4);
> +           if (err != 0)
> +               continue;
> +
> +           dev->regions[i].base_addr = ((uint64_t)top << 32) |
> +                                       get_map_base(addr);
> +           bar += 4;
> +           i++;
> +       } else {
> +           dev->regions[i].base_addr = get_map_base(addr);
> +       }
> +    }
> +
> +    /* If it's a VGA device, set up the rom size for read_rom using the
> +     * 0xc0000 mapping.
> +     */
> +    if ((dev->device_class & 0x00ffff00) ==
> +       ((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8)))
> +    {
> +       dev->rom_size = 64 * 1024;
> +    }
> +
> +    return 0;
> +}
> +
> +static int
> +pci_device_x86_map_range(struct pci_device *dev,
> +    struct pci_device_mapping *map)
> +{
> +    int memfd = open("/dev/mem", O_RDWR);
> +    int prot = PROT_READ;
> +
> +    if (memfd == -1)
> +       return errno;
> +
> +    if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
> +       prot |= PROT_WRITE;
> +
> +    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, memfd, map->base);
> +    close(memfd);
> +    if (map->memory == MAP_FAILED)
> +       return errno;
> +
> +    return 0;
> +}
> +
> +static int
> +pci_device_x86_read(struct pci_device *dev, void *data,
> +    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
> +{
> +    struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys;
> +    int err;
> +
> +    *bytes_read = 0;
> +    while (size > 0) {
> +       int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1);
> +       if (toread > size)
> +           toread = size;
> +
> +       err = pci_sys_x86->read(dev->bus, dev->dev, dev->func, offset, data, toread);
> +       if (err)
> +           return err;
> +
> +       offset += toread;
> +       data = (char*)data + toread;
> +       size -= toread;
> +       *bytes_read += toread;
> +    }
> +    return 0;
> +}
> +
> +static int
> +pci_device_x86_write(struct pci_device *dev, const void *data,
> +    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
> +{
> +    struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys;
> +    int err;
> +
> +    *bytes_written = 0;
> +    while (size > 0) {
> +       int towrite = 4;
> +       if (towrite > size)
> +           towrite = size;
> +       if (towrite > 4 - (offset & 0x3))
> +           towrite = 4 - (offset & 0x3);
> +
> +       err = pci_sys_x86->write(dev->bus, dev->dev, dev->func, offset, data, towrite);
> +       if (err)
> +           return err;
> +
> +       offset += towrite;
> +       data = (const char*)data + towrite;
> +       size -= towrite;
> +       *bytes_written += towrite;
> +    }
> +    return 0;
> +}
> +
> +static void
> +pci_system_x86_destroy(void)
> +{
> +    x86_disable_io();
> +}
> +
> +static const struct pci_system_methods x86_pci_methods = {
> +    .destroy = pci_system_x86_destroy,
> +    .read_rom = pci_device_x86_read_rom,
> +    .probe = pci_device_x86_probe,
> +    .map_range = pci_device_x86_map_range,
> +    .unmap_range = pci_device_generic_unmap_range,
> +    .read = pci_device_x86_read,
> +    .write = pci_device_x86_write,
> +    .fill_capabilities = pci_fill_capabilities_generic,
> +};
> +
> +static int pci_probe(struct pci_system_x86 *pci_sys_x86)
> +{
> +    if (pci_x86_conf1_probe() == 0) {
> +       pci_sys_x86->read = pci_x86_conf1_read;
> +       pci_sys_x86->write = pci_x86_conf1_write;
> +       if (pci_x86_check(pci_sys_x86) == 0)
> +           return 0;
> +    }
> +
> +    if (pci_x86_conf2_probe() == 0) {
> +       pci_sys_x86->read = pci_x86_conf2_read;
> +       pci_sys_x86->write = pci_x86_conf2_write;
> +       if (pci_x86_check(pci_sys_x86) == 0)
> +           return 0;
> +    }
> +
> +    return ENODEV;
> +}
> +
> +_pci_hidden int
> +pci_system_x86_create(void)
> +{
> +    struct pci_device_private *device;
> +    int ret, bus, dev, ndevs, func, nfuncs;
> +    struct pci_system_x86 *pci_sys_x86;
> +    uint32_t reg;
> +
> +    ret = x86_enable_io();
> +    if (ret)
> +       return ret;
> +
> +    pci_sys_x86 = calloc(1, sizeof(struct pci_system_x86));
> +    if (pci_sys_x86 == NULL) {
> +       x86_disable_io();
> +       return ENOMEM;
> +    }
> +    pci_sys = &pci_sys_x86->system;
> +
> +    ret = pci_probe(pci_sys_x86);
> +    if (ret) {
> +       x86_disable_io();
> +       free(pci_sys_x86);
> +       pci_sys = NULL;
> +       return ret;
> +    }
> +
> +    pci_sys->methods = &x86_pci_methods;
> +
> +    ndevs = 0;
> +    for (bus = 0; bus < 256; bus++) {
> +       for (dev = 0; dev < 32; dev++) {
> +           nfuncs = pci_nfuncs(pci_sys_x86, bus, dev);
> +           for (func = 0; func < nfuncs; func++) {
> +               if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, &reg, sizeof(reg)) != 0)
> +                   continue;
> +               if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
> +                   PCI_VENDOR(reg) == 0)
> +                   continue;
> +               ndevs++;
> +           }
> +       }
> +    }
> +
> +    pci_sys->num_devices = ndevs;
> +    pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
> +    if (pci_sys->devices == NULL) {
> +       x86_disable_io();
> +       free(pci_sys_x86);
> +       pci_sys = NULL;
> +       return ENOMEM;
> +    }
> +
> +    device = pci_sys->devices;
> +    for (bus = 0; bus < 256; bus++) {
> +       for (dev = 0; dev < 32; dev++) {
> +           nfuncs = pci_nfuncs(pci_sys_x86, bus, dev);
> +           for (func = 0; func < nfuncs; func++) {
> +               if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, &reg, sizeof(reg)) != 0)
> +                   continue;
> +               if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
> +                   PCI_VENDOR(reg) == 0)
> +                   continue;
> +               device->base.domain = 0;
> +               device->base.bus = bus;
> +               device->base.dev = dev;
> +               device->base.func = func;
> +               device->base.vendor_id = PCI_VENDOR(reg);
> +               device->base.device_id = PCI_DEVICE(reg);
> +
> +               if (pci_sys_x86->read(bus, dev, func, PCI_CLASS, &reg, sizeof(reg)) != 0)
> +                   continue;
> +               device->base.device_class = reg >> 8;
> +               device->base.revision = reg & 0xFF;
> +
> +               if (pci_sys_x86->read(bus, dev, func, PCI_SUB_VENDOR_ID, &reg, sizeof(reg)) != 0)
> +                   continue;
> +               device->base.subvendor_id = PCI_VENDOR(reg);
> +               device->base.subdevice_id = PCI_DEVICE(reg);
> +
> +               device++;
> +           }
> +       }
> +    }
> +
> +    return 0;
> +}

The rest looks okay for me.


Thanks,

            Tiago



More information about the xorg mailing list