Hello Everyone, I'm mentoring Haiku's GSoC project for porting DRM to Haiku (www.haiku-os.org). Since my student will be doing the bulk of the work on the DRM kernel drivers proper, I decided to start looking at some of the other packages that we'll have to port, the first being libDRM. Seeing as libpciaccess is a dependency and it hasn't been ported yet, I've gone ahead and prepared a patch that allows it to build on Haiku. Please review and if possible merge. Seeing as I don't really have a way to test it right now, there may be additional patches in the future to tweak the library to work for us. Please feel free to contact me with any questions or comments via email or on Freenode, my nick is Duggan.
Thank you.
From 92c358a983834b45068656bbba88346753588683 Mon Sep 17 00:00:00 2001 From: Dewey Taylor <[email protected]> Date: Sat, 6 May 2017 06:08:17 +0000 Subject: [PATCH libpciaccess] Add initial support for Haiku --- scanpci/scanpci.c | 2 +- src/common_init.c | 2 + src/common_interface.c | 6 + src/haiku_pci.c | 797 ++++++++++++++++++++++++++++++++++++++++++++++++ src/pciaccess_private.h | 1 + 5 files changed, 807 insertions(+), 1 deletion(-) create mode 100644 src/haiku_pci.c diff --git a/scanpci/scanpci.c b/scanpci/scanpci.c index 2f86833..bae5c74 100644 --- a/scanpci/scanpci.c +++ b/scanpci/scanpci.c @@ -31,7 +31,7 @@ #include <unistd.h> #include <inttypes.h> -#ifdef HAVE_ERR_H +#if defined(HAVE_ERR_H) && !defined(__HAIKU__) #include <err.h> #else # include <errno.h> diff --git a/src/common_init.c b/src/common_init.c index f7b59bd..5b09d31 100644 --- a/src/common_init.c +++ b/src/common_init.c @@ -67,6 +67,8 @@ pci_system_init( void ) err = pci_system_solx_devfs_create(); #elif defined(__GNU__) || defined(__CYGWIN__) err = pci_system_x86_create(); +#elif defined(__HAIKU__) + err = pci_system_haiku_create(); #else # error "Unsupported OS" #endif diff --git a/src/common_interface.c b/src/common_interface.c index cb95e90..34155f6 100644 --- a/src/common_interface.c +++ b/src/common_interface.c @@ -70,6 +70,12 @@ # define HTOLE_32(x) (x) #endif /* Solaris */ +#elif defined(__HAIKU__) +# define LETOH_16(x) (x) +# define HTOLE_16(x) (x) +# define LETOH_32(x) (x) +# define HTOLE_32(x) (x) + #else #include <sys/endian.h> diff --git a/src/haiku_pci.c b/src/haiku_pci.c new file mode 100644 index 0000000..7814bf2 --- /dev/null +++ b/src/haiku_pci.c @@ -0,0 +1,797 @@ +/* + * (C) Copyright Eric Anholt 2006 + * (C) Copyright IBM Corporation 2006 + * (C) Copyright Mark Kettenis 2011 + * (C) Copyright Robert Millan 2012 + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file haiku_pci.c + * + * Access the kernel PCI support using /dev/pci's ioctl and mmap interface. + * + * \author Eric Anholt <[email protected]> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/pciio.h> +#include <sys/mman.h> +#include <sys/memrange.h> + +#include "pciaccess.h" +#include "pciaccess_private.h" + +#define PCIC_DISPLAY 0x03 +#define PCIS_DISPLAY_VGA 0x00 +#define PCIS_DISPLAY_XGA 0x01 +#define PCIS_DISPLAY_3D 0x02 +#define PCIS_DISPLAY_OTHER 0x80 + +/* Registers taken from pcireg.h */ +#define PCIR_COMMAND 0x04 +#define PCIM_CMD_PORTEN 0x0001 +#define PCIM_CMD_MEMEN 0x0002 +#define PCIR_BIOS 0x30 +#define PCIM_BIOS_ENABLE 0x01 +#define PCIM_BIOS_ADDR_MASK 0xfffff800 + +#define PCIR_BARS 0x10 +#define PCIR_BAR(x) (PCIR_BARS + (x) * 4) +#define PCI_BAR_IO(x) (((x) & PCIM_BAR_SPACE) == PCIM_BAR_IO_SPACE) +#define PCI_BAR_MEM(x) (((x) & PCIM_BAR_SPACE) == PCIM_BAR_MEM_SPACE) +#define PCIM_BAR_MEM_TYPE 0x00000006 +#define PCIM_BAR_MEM_64 4 +#define PCIM_BAR_MEM_PREFETCH 0x00000008 +#define PCIM_BAR_SPACE 0x00000001 +#define PCIM_BAR_MEM_SPACE 0 +#define PCIM_BAR_IO_SPACE 1 + +/** + * haiku private pci_system structure that extends the base pci_system + * structure. + * + * It is initialized once and used as a global, just as pci_system is used. + */ +_pci_hidden +struct haiku_pci_system { + /* This must be the first entry in the structure, as pci_system_cleanup() + * frees pci_sys. + */ + struct pci_system pci_sys; + + int pcidev; /**< fd for /dev/pci */ +} *haiku_pci_sys; + +/** + * Map a memory region for a device using /dev/mem. + * + * \param dev Device whose memory region is to be mapped. + * \param map Parameters of the mapping that is to be created. + * + * \return + * Zero on success or an \c errno value on failure. + */ +static int +pci_device_haiku_map_range(struct pci_device *dev, + struct pci_device_mapping *map) +{ + const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) + ? (PROT_READ | PROT_WRITE) : PROT_READ; + struct mem_range_desc mrd; + struct mem_range_op mro; + + int fd, err = 0; + + fd = open("/dev/mem", O_RDWR | O_CLOEXEC); + if (fd == -1) + return errno; + + map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, map->base); + + if (map->memory == MAP_FAILED) { + err = errno; + } + + mrd.mr_base = map->base; + mrd.mr_len = map->size; + strncpy(mrd.mr_owner, "pciaccess", sizeof(mrd.mr_owner)); + if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE) + mrd.mr_flags = MDF_WRITEBACK; + else if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) + mrd.mr_flags = MDF_WRITECOMBINE; + else + mrd.mr_flags = MDF_UNCACHEABLE; + mro.mo_desc = &mrd; + mro.mo_arg[0] = MEMRANGE_SET_UPDATE; + + /* No need to set an MTRR if it's the default mode. */ + if (mrd.mr_flags != MDF_UNCACHEABLE) { + if (ioctl(fd, MEMRANGE_SET, &mro)) { + fprintf(stderr, "failed to set mtrr: %s\n", strerror(errno)); + } + } + + close(fd); + + return err; +} + +static int +pci_device_haiku_unmap_range( struct pci_device *dev, + struct pci_device_mapping *map ) +{ + struct mem_range_desc mrd; + struct mem_range_op mro; + int fd; + + if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) || + (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) + { + fd = open("/dev/mem", O_RDWR | O_CLOEXEC); + if (fd != -1) { + mrd.mr_base = map->base; + mrd.mr_len = map->size; + strncpy(mrd.mr_owner, "pciaccess", sizeof(mrd.mr_owner)); + mrd.mr_flags = MDF_UNCACHEABLE; + mro.mo_desc = &mrd; + mro.mo_arg[0] = MEMRANGE_SET_REMOVE; + + if (ioctl(fd, MEMRANGE_SET, &mro)) { + fprintf(stderr, "failed to unset mtrr: %s\n", strerror(errno)); + } + + close(fd); + } else { + fprintf(stderr, "Failed to open /dev/mem\n"); + } + } + + return pci_device_generic_unmap_range(dev, map); +} + +static int +pci_device_haiku_read( struct pci_device * dev, void * data, + pciaddr_t offset, pciaddr_t size, + pciaddr_t * bytes_read ) +{ + struct pci_io io; + +#if HAVE_PCI_IO_PC_DOMAIN + io.pi_sel.pc_domain = dev->domain; +#endif + io.pi_sel.pc_bus = dev->bus; + io.pi_sel.pc_dev = dev->dev; + io.pi_sel.pc_func = dev->func; + + *bytes_read = 0; + while ( size > 0 ) { + int toread = (size < 4) ? size : 4; + + /* Only power of two allowed. */ + if (toread == 3) + toread = 2; + + io.pi_reg = offset; + io.pi_width = toread; + + if ( ioctl( haiku_pci_sys->pcidev, PCIOCREAD, &io ) < 0 ) + return errno; + + memcpy(data, &io.pi_data, toread ); + + offset += toread; + data = (char *)data + toread; + size -= toread; + *bytes_read += toread; + } + + return 0; +} + + +static int +pci_device_haiku_write( struct pci_device * dev, const void * data, + pciaddr_t offset, pciaddr_t size, + pciaddr_t * bytes_written ) +{ + struct pci_io io; + +#if HAVE_PCI_IO_PC_DOMAIN + io.pi_sel.pc_domain = dev->domain; +#endif + io.pi_sel.pc_bus = dev->bus; + io.pi_sel.pc_dev = dev->dev; + io.pi_sel.pc_func = dev->func; + + *bytes_written = 0; + while ( size > 0 ) { + int towrite = (size < 4 ? size : 4); + + /* Only power of two allowed. */ + if (towrite == 3) + towrite = 2; + + io.pi_reg = offset; + io.pi_width = towrite; + memcpy( &io.pi_data, data, towrite ); + + if ( ioctl( haiku_pci_sys->pcidev, PCIOCWRITE, &io ) < 0 ) + return errno; + + offset += towrite; + data = (char *)data + towrite; + size -= towrite; + *bytes_written += towrite; + } + + return 0; +} + +/** + * Read a VGA rom using the 0xc0000 mapping. + * + * This function should be extended to handle access through PCI resources, + * which should be more reliable when available. + */ +static int +pci_device_haiku_read_rom( struct pci_device * dev, void * buffer ) +{ + struct pci_device_private *priv = (struct pci_device_private *) dev; + void *bios; + pciaddr_t rom_base; + uint32_t rom; + uint16_t reg; + int pci_rom, memfd; + + if ( ( dev->device_class & 0x00ffff00 ) != + ( ( PCIC_DISPLAY << 16 ) | ( PCIS_DISPLAY_VGA << 8 ) ) ) + { + return ENOSYS; + } + + if (priv->rom_base == 0) { +#if defined(__amd64__) || defined(__i386__) + rom_base = 0xc0000; + pci_rom = 0; +#else + return ENOSYS; +#endif + } else { + rom_base = priv->rom_base; + pci_rom = 1; + + pci_device_cfg_read_u16( dev, ®, PCIR_COMMAND ); + pci_device_cfg_write_u16( dev, reg | PCIM_CMD_MEMEN, PCIR_COMMAND ); + pci_device_cfg_read_u32( dev, &rom, PCIR_BIOS ); + pci_device_cfg_write_u32( dev, rom | PCIM_BIOS_ENABLE, PCIR_BIOS ); + } + + printf("Using rom_base = 0x%lx\n", (long)rom_base); + memfd = open( "/dev/mem", O_RDONLY | O_CLOEXEC ); + if ( memfd == -1 ) + return errno; + + bios = mmap( NULL, dev->rom_size, PROT_READ, 0, memfd, rom_base ); + if ( bios == MAP_FAILED ) { + close( memfd ); + return errno; + } + + memcpy( buffer, bios, dev->rom_size ); + + munmap( bios, dev->rom_size ); + close( memfd ); + + if (pci_rom) { + pci_device_cfg_write_u32( dev, PCIR_BIOS, rom ); + pci_device_cfg_write_u16( dev, PCIR_COMMAND, reg ); + } + + return 0; +} + +/** Returns the number of regions (base address registers) the device has */ + +static int +pci_device_haiku_get_num_regions( struct pci_device * dev ) +{ + struct pci_device_private *priv = (struct pci_device_private *) dev; + + switch (priv->header_type) { + case 0: + return 6; + case 1: + return 2; + case 2: + return 1; + default: + printf("unknown header type %02x\n", priv->header_type); + return 0; + } +} + +#ifdef PCIOCGETBAR + +static int +pci_device_haiku_probe( struct pci_device * dev ) +{ + struct pci_device_private *priv = (struct pci_device_private *) dev; + struct pci_bar_io bar; + uint8_t irq; + int err, i; + +#if HAVE_PCI_IO_PC_DOMAIN + bar.pbi_sel.pc_domain = dev->domain; +#endif + bar.pbi_sel.pc_bus = dev->bus; + bar.pbi_sel.pc_dev = dev->dev; + bar.pbi_sel.pc_func = dev->func; + + + /* 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, 60 ); + if (err) + return errno; + dev->irq = irq; + + for (i = 0; i < pci_device_haiku_get_num_regions( dev ); i++) { + bar.pbi_reg = PCIR_BAR(i); + if ( ioctl( haiku_pci_sys->pcidev, PCIOCGETBAR, &bar ) < 0 ) + continue; + + if (PCI_BAR_IO(bar.pbi_base)) + dev->regions[i].is_IO = 1; + + if ((bar.pbi_base & PCIM_BAR_MEM_TYPE) == PCIM_BAR_MEM_64) + dev->regions[i].is_64 = 1; + + if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH) + dev->regions[i].is_prefetchable = 1; + + dev->regions[i].base_addr = bar.pbi_base & ~((uint64_t)0xf); + dev->regions[i].size = bar.pbi_length; + } + + /* 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; +} + +#else + +/** 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 int +get_test_val_size( uint32_t testval ) +{ + if (testval == 0) + return 0; + + /* Mask out the flag bits */ + testval = get_map_base( testval ); + + return 1 << (ffs(testval) - 1); +} + +/** + * Sets the address and size information for the region from config space + * registers. + * + * This would be much better provided by a kernel interface. + * + * \return 0 on success, or an errno value. + */ +static int +pci_device_haiku_get_region_info( struct pci_device * dev, int region, + int bar ) +{ + uint32_t addr, testval; + uint16_t cmd; + int err; + + /* Get the base address */ + err = pci_device_cfg_read_u32( dev, &addr, bar ); + if (err != 0) + return err; + + /* + * We are going to be doing evil things to the registers here + * so disable them via the command register first. + */ + err = pci_device_cfg_read_u16( dev, &cmd, PCIR_COMMAND ); + if (err != 0) + return err; + + err = pci_device_cfg_write_u16( dev, + cmd & ~(PCI_BAR_MEM(addr) ? PCIM_CMD_MEMEN : PCIM_CMD_PORTEN), + PCIR_COMMAND ); + if (err != 0) + return err; + + /* Test write all ones to the register, then restore it. */ + err = pci_device_cfg_write_u32( dev, 0xffffffff, bar ); + if (err != 0) + return err; + err = pci_device_cfg_read_u32( dev, &testval, bar ); + if (err != 0) + return err; + err = pci_device_cfg_write_u32( dev, addr, bar ); + if (err != 0) + return err; + + /* Restore the command register */ + err = pci_device_cfg_write_u16( dev, cmd, PCIR_COMMAND ); + if (err != 0) + return err; + + if (addr & 0x01) + dev->regions[region].is_IO = 1; + if (addr & 0x04) + dev->regions[region].is_64 = 1; + if (addr & 0x08) + dev->regions[region].is_prefetchable = 1; + + /* Set the size */ + dev->regions[region].size = get_test_val_size( testval ); + printf("size = 0x%lx\n", (long)dev->regions[region].size); + + /* Set the base address value */ + if (dev->regions[region].is_64) { + uint32_t top; + + err = pci_device_cfg_read_u32( dev, &top, bar + 4 ); + if (err != 0) + return err; + + dev->regions[region].base_addr = ((uint64_t)top << 32) | + get_map_base(addr); + } else { + dev->regions[region].base_addr = get_map_base(addr); + } + + return 0; +} + +static int +pci_device_haiku_probe( struct pci_device * dev ) +{ + struct pci_device_private *priv = (struct pci_device_private *) dev; + uint32_t reg, size; + uint8_t irq; + 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, 60 ); + if (err) + return errno; + dev->irq = irq; + + bar = 0x10; + for (i = 0; i < pci_device_haiku_get_num_regions( dev ); i++) { + pci_device_haiku_get_region_info( dev, i, bar ); + if (dev->regions[i].is_64) { + bar += 0x08; + i++; + } else + bar += 0x04; + } + + /* If it's a VGA device, set up the rom size for read_rom */ + if ((dev->device_class & 0x00ffff00) == + ((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8))) + { + err = pci_device_cfg_read_u32( dev, ®, PCIR_BIOS ); + if (err) + return errno; + + if (reg == 0) { + dev->rom_size = 0x10000; + return 0; + } + + err = pci_device_cfg_write_u32( dev, ~PCIM_BIOS_ENABLE, PCIR_BIOS ); + if (err) + return errno; + pci_device_cfg_read_u32( dev, &size, PCIR_BIOS ); + pci_device_cfg_write_u32( dev, reg, PCIR_BIOS ); + + if ((reg & PCIM_BIOS_ADDR_MASK) != 0) { + priv->rom_base = (reg & PCIM_BIOS_ADDR_MASK); + dev->rom_size = -(size & PCIM_BIOS_ADDR_MASK); + } + } + + return 0; +} + +#endif + +static void +pci_system_haiku_destroy(void) +{ + close(haiku_pci_sys->pcidev); + free(haiku_pci_sys->pci_sys.devices); + haiku_pci_sys = NULL; +} + +#if defined(__i386__) || defined(__amd64__) +#include <machine/cpufunc.h> +#endif + +static struct pci_io_handle * +pci_device_haiku_open_legacy_io(struct pci_io_handle *ret, + struct pci_device *dev, pciaddr_t base, pciaddr_t size) +{ +#if defined(__i386__) || defined(__amd64__) + ret->fd = open("/dev/io", O_RDWR | O_CLOEXEC); + + if (ret->fd < 0) + return NULL; + + ret->base = base; + ret->size = size; + ret->is_legacy = 1; + return ret; +#elif defined(PCI_MAGIC_IO_RANGE) + ret->memory = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, + aperturefd, PCI_MAGIC_IO_RANGE + base); + if (ret->memory == MAP_FAILED) + return NULL; + + ret->base = base; + ret->size = size; + ret->is_legacy = 1; + return ret; +#else + return NULL; +#endif +} + +#if defined(__i386__) || defined(__amd64__) +static void +pci_device_haiku_close_io(struct pci_device *dev, struct pci_io_handle *handle) +{ + if (handle->fd > -1) + close(handle->fd); +} +#endif + +static uint32_t +pci_device_haiku_read32(struct pci_io_handle *handle, uint32_t reg) +{ +#if defined(__i386__) || defined(__amd64__) + return inl(handle->base + reg); +#else + return *(uint32_t *)((uintptr_t)handle->memory + reg); +#endif +} + +static uint16_t +pci_device_haiku_read16(struct pci_io_handle *handle, uint32_t reg) +{ +#if defined(__i386__) || defined(__amd64__) + return inw(handle->base + reg); +#else + return *(uint16_t *)((uintptr_t)handle->memory + reg); +#endif +} + +static uint8_t +pci_device_haiku_read8(struct pci_io_handle *handle, uint32_t reg) +{ +#if defined(__i386__) || defined(__amd64__) + return inb(handle->base + reg); +#else + return *(uint8_t *)((uintptr_t)handle->memory + reg); +#endif +} + +static void +pci_device_haiku_write32(struct pci_io_handle *handle, uint32_t reg, + uint32_t data) +{ +#if defined(__i386__) || defined(__amd64__) + outl(handle->base + reg, data); +#else + *(uint16_t *)((uintptr_t)handle->memory + reg) = data; +#endif +} + +static void +pci_device_haiku_write16(struct pci_io_handle *handle, uint32_t reg, + uint16_t data) +{ +#if defined(__i386__) || defined(__amd64__) + outw(handle->base + reg, data); +#else + *(uint8_t *)((uintptr_t)handle->memory + reg) = data; +#endif +} + +static void +pci_device_haiku_write8(struct pci_io_handle *handle, uint32_t reg, + uint8_t data) +{ +#if defined(__i386__) || defined(__amd64__) + outb(handle->base + reg, data); +#else + *(uint32_t *)((uintptr_t)handle->memory + reg) = data; +#endif +} + +static int +pci_device_haiku_map_legacy(struct pci_device *dev, pciaddr_t base, + pciaddr_t size, unsigned map_flags, void **addr) +{ + struct pci_device_mapping map; + int err; + + map.base = base; + map.size = size; + map.flags = map_flags; + map.memory = NULL; + err = pci_device_haiku_map_range(dev, &map); + *addr = map.memory; + + return err; +} + +static int +pci_device_haiku_unmap_legacy(struct pci_device *dev, void *addr, + pciaddr_t size) +{ + struct pci_device_mapping map; + + map.memory = addr; + map.size = size; + map.flags = 0; + return pci_device_haiku_unmap_range(dev, &map); +} + +static const struct pci_system_methods haiku_pci_methods = { + .destroy = pci_system_haiku_destroy, + .destroy_device = NULL, /* nothing to do for this */ + .read_rom = pci_device_haiku_read_rom, + .probe = pci_device_haiku_probe, + .map_range = pci_device_haiku_map_range, + .unmap_range = pci_device_haiku_unmap_range, + .read = pci_device_haiku_read, + .write = pci_device_haiku_write, + .fill_capabilities = pci_fill_capabilities_generic, + .open_legacy_io = pci_device_haiku_open_legacy_io, +#if defined(__i386__) || defined(__amd64__) + .close_io = pci_device_haiku_close_io, +#endif + .read32 = pci_device_haiku_read32, + .read16 = pci_device_haiku_read16, + .read8 = pci_device_haiku_read8, + .write32 = pci_device_haiku_write32, + .write16 = pci_device_haiku_write16, + .write8 = pci_device_haiku_write8, + .map_legacy = pci_device_haiku_map_legacy, + .unmap_legacy = pci_device_haiku_unmap_legacy, +}; + +/** + * Attempt to access the haiku PCI interface. + */ +_pci_hidden int +pci_system_haiku_create( void ) +{ + struct pci_conf_io pciconfio; + struct pci_conf pciconf[255]; + int pcidev; + int i; + + /* Try to open the PCI device */ + pcidev = open( "/dev/pci", O_RDWR | O_CLOEXEC ); + if ( pcidev == -1 ) + return ENXIO; + + haiku_pci_sys = calloc( 1, sizeof( struct haiku_pci_system ) ); + if ( haiku_pci_sys == NULL ) { + close( pcidev ); + return ENOMEM; + } + pci_sys = &haiku_pci_sys->pci_sys; + + pci_sys->methods = & haiku_pci_methods; + haiku_pci_sys->pcidev = pcidev; + + /* Probe the list of devices known by the system */ + bzero( &pciconfio, sizeof( struct pci_conf_io ) ); + pciconfio.match_buf_len = sizeof(pciconf); + pciconfio.matches = pciconf; + + if ( ioctl( pcidev, PCIOCGETCONF, &pciconfio ) == -1) { + free( pci_sys ); + close( pcidev ); + return errno; + } + + if (pciconfio.status == PCI_GETCONF_ERROR ) { + free( pci_sys ); + close( pcidev ); + return EINVAL; + } + + /* Translate the list of devices into pciaccess's format. */ + pci_sys->num_devices = pciconfio.num_matches; + pci_sys->devices = calloc( pciconfio.num_matches, + sizeof( struct pci_device_private ) ); + + for ( i = 0; i < pciconfio.num_matches; i++ ) { + struct pci_conf *p = &pciconf[ i ]; + +#if HAVE_PCI_IO_PC_DOMAIN + pci_sys->devices[ i ].base.domain = p->pc_sel.pc_domain; +#else + pci_sys->devices[ i ].base.domain = 0; +#endif + pci_sys->devices[ i ].base.bus = p->pc_sel.pc_bus; + pci_sys->devices[ i ].base.dev = p->pc_sel.pc_dev; + pci_sys->devices[ i ].base.func = p->pc_sel.pc_func; + pci_sys->devices[ i ].base.vendor_id = p->pc_vendor; + pci_sys->devices[ i ].base.device_id = p->pc_device; + pci_sys->devices[ i ].base.subvendor_id = p->pc_subvendor; + pci_sys->devices[ i ].base.subdevice_id = p->pc_subdevice; + pci_sys->devices[ i ].base.revision = p->pc_revid; + pci_sys->devices[ i ].base.device_class = (uint32_t)p->pc_class << 16 | + (uint32_t)p->pc_subclass << 8 | (uint32_t)p->pc_progif; + pci_sys->devices[ i ].header_type = p->pc_hdr & 0x7f; + } + + return 0; +} diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h index 2f05b29..39ae928 100644 --- a/src/pciaccess_private.h +++ b/src/pciaccess_private.h @@ -190,4 +190,5 @@ 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 int pci_system_haiku_create( void ); extern void pci_io_cleanup( void ); -- 2.12.2
_______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel
