diff -up libpciaccess-0.10.6/src/common_interface.c.da libpciaccess-0.10.6/src/common_interface.c --- libpciaccess-0.10.6/src/common_interface.c.da 2009-08-04 11:48:05.000000000 +1000 +++ libpciaccess-0.10.6/src/common_interface.c 2009-08-04 11:48:12.000000000 +1000 @@ -124,6 +124,21 @@ pci_device_is_boot_vga( struct pci_devic } /** + * Probe a PCI device to determine if a kernel driver is attached. + * + * \param dev Device to query + * \return + * Zero if no driver attached, 1 if attached kernel drviver + */ +int +pci_device_has_kernel_driver( struct pci_device * dev ) +{ + if (!pci_sys->methods->has_kernel_driver) + return 0; + return pci_sys->methods->has_kernel_driver( dev ); +} + +/** * Probe a PCI device to learn information about the device. * * Probes a PCI device to learn various information about the device. Before diff -up /dev/null libpciaccess-0.10.6/src/common_vgaarb_stub.c --- /dev/null 2009-08-04 11:11:12.269252600 +1000 +++ libpciaccess-0.10.6/src/common_vgaarb_stub.c 2009-08-04 11:48:12.000000000 +1000 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009 Tiago Vignatti + * + * 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 the rights to use, + * copy, modify, merge, publish, distribute, sublicense, 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 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS 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. + * + */ + +#include +#include "pciaccess.h" + +int +pci_device_vgaarb_init(struct pci_device *dev) +{ +#ifdef DEBUG + fprintf(stderr, "%s: You're using VGA arbiter stub functions!\n", + __FUNCTION__); +#endif + return 0; +} + +void +pci_device_vgaarb_fini(struct pci_device *dev) +{ +} + +int +pci_device_vgaarb_set_target(struct pci_device *dev) +{ + return 0; +} + +int +pci_device_vgaarb_decodes(struct pci_device *dev) +{ + return 0; +} + +int +pci_device_vgaarb_lock(struct pci_device *dev) +{ + return 0; +} + +int +pci_device_vgaarb_trylock(struct pci_device *dev) +{ + return 0; +} + +int +pci_device_vgaarb_unlock(struct pci_device *dev) +{ + return 0; +} diff -up libpciaccess-0.10.6/src/linux_sysfs.c.da libpciaccess-0.10.6/src/linux_sysfs.c --- libpciaccess-0.10.6/src/linux_sysfs.c.da 2009-08-04 11:48:05.000000000 +1000 +++ libpciaccess-0.10.6/src/linux_sysfs.c 2009-08-04 11:48:12.000000000 +1000 @@ -78,6 +78,7 @@ static int pci_device_linux_sysfs_write( pciaddr_t * bytes_written ); static int pci_device_linux_sysfs_boot_vga( struct pci_device * dev ); +static int pci_device_linux_sysfs_has_kernel_driver(struct pci_device *dev); static const struct pci_system_methods linux_sysfs_methods = { .destroy = pci_device_linux_sysfs_destroy, @@ -93,6 +94,7 @@ static const struct pci_system_methods l .fill_capabilities = pci_fill_capabilities_generic, .enable = pci_device_linux_sysfs_enable, .boot_vga = pci_device_linux_sysfs_boot_vga, + .has_kernel_driver = pci_device_linux_sysfs_has_kernel_driver, }; #define SYS_BUS_PCI "/sys/bus/pci/devices" @@ -761,3 +763,22 @@ out: close(fd); return ret; } + +static int pci_device_linux_sysfs_has_kernel_driver(struct pci_device *dev) +{ + char name[256]; + struct stat dummy; + int ret; + + snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/driver", + SYS_BUS_PCI, + dev->domain, + dev->bus, + dev->dev, + dev->func ); + + ret = stat(name, &dummy); + if (ret < 0) + return 0; + return 1; +} diff -up /dev/null libpciaccess-0.10.6/src/common_vgaarb.c --- /dev/null 2009-08-04 11:11:12.269252600 +1000 +++ libpciaccess-0.10.6/src/common_vgaarb.c 2009-08-04 11:48:12.000000000 +1000 @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti + * 2009 Tiago Vignatti + * + * 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 the rights to use, + * copy, modify, merge, publish, distribute, sublicense, 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 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pciaccess.h" +#include "pciaccess_private.h" + +#define BUFSIZE 64 + +static int +parse_string_to_decodes_rsrc(char *input, int *vga_count, struct pci_slot_match *match) +{ + char *tok; + char *input_sp, *count_sp, *pci_sp; + char tmp[32]; + + tok = strtok_r(input,",",&input_sp); + if (!tok) + goto fail; + + strncpy(tmp, input, 15); + tmp[15] = 0; + + tok = strtok_r(tmp,":",&count_sp); + if (!tok) + goto fail; + tok = strtok_r(NULL, ":",&count_sp); + if (!tok) + goto fail; + + *vga_count = strtoul(tok, NULL, 10); + if (*vga_count == LONG_MAX) + goto fail; + +#ifdef DEBUG + fprintf(stderr,"vga count is %d\n", *vga_count); +#endif + + tok = strtok_r(NULL, ",",&input_sp); + if (!tok) + goto fail; + + if (match) { + strncpy(tmp, tok, 32); + tmp[31] = 0; + tok = strtok_r(tmp, ":", &pci_sp); + if (!tok) + goto fail; + tok = strtok_r(NULL, ":", &pci_sp); + if (!tok) + goto fail; + match->domain = strtoul(tok, NULL, 16); + + tok = strtok_r(NULL, ":", &pci_sp); + if (!tok) + goto fail; + match->bus = strtoul(tok, NULL, 16); + + tok = strtok_r(NULL, ".", &pci_sp); + if (!tok) + goto fail; + match->dev = strtoul(tok, NULL, 16); + + tok = strtok_r(NULL, ".", &pci_sp); + if (!tok) + goto fail; + match->func = strtoul(tok, NULL, 16); + } + + tok = strtok_r(NULL, ",",&input_sp); + if (!tok) + goto fail; + tok = strtok_r(tok, "=", &input_sp); + if (!tok) + goto fail; + tok = strtok_r(NULL, "=", &input_sp); + if (!tok) + goto fail; + + if (!strncmp(tok, "io+mem", 6)) + return VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM; + if (!strncmp(tok, "io", 2)) + return VGA_ARB_RSRC_LEGACY_IO; + if (!strncmp(tok, "mem", 3)) + return VGA_ARB_RSRC_LEGACY_MEM; +fail: + return VGA_ARB_RSRC_NONE; +} + +int +pci_device_vgaarb_init(void) +{ + struct pci_slot_match match; + char buf[BUFSIZE]; + int ret, rsrc; + if ((pci_sys->vgaarb_fd = open ("/dev/vga_arbiter", O_RDWR)) < 0) { + return errno; + } + + ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); + if (ret <= 0) + return -1; + + memset(&match, 0xff, sizeof(match)); + /* need to find the device to go back to and what it was decoding */ + rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, &match); + + pci_sys->vga_default_dev = pci_device_find_by_slot(match.domain, match.bus, match.dev, match.func); + + if (pci_sys->vga_default_dev) + pci_sys->vga_default_dev->vgaarb_rsrc = rsrc; + return 0; +} + +void +pci_device_vgaarb_fini(void) +{ + close(pci_sys->vgaarb_fd); +} + +/** + * Writes message on vga device. The messages are defined by the kernel + * implementation. + * + * \param fd vga arbiter device. + * \param buf message itself. + * \param len message length. + * + * \return + * Zero on success, 1 if something gets wrong and 2 if fd is busy (only for + * 'trylock') + */ +static int +vgaarb_write(int fd, char *buf, int len) +{ + int ret; + + + buf[len] = '\0'; + + ret = write(fd, buf, len); + if (ret == -1) { + /* the user may have called "trylock" and didn't get the lock */ + if (errno == EBUSY) + return 2; + +#ifdef DEBUG + fprintf(stderr, "write error"); +#endif + return 1; + } + else if (ret != len) { + /* it's need to receive the exactly amount required. */ +#ifdef DEBUG + fprintf(stderr, "write error: wrote different than expected\n"); +#endif + return 1; + } + +#ifdef DEBUG + fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf); +#endif + + return 0; +} + + +static const char * +rsrc_to_str(int iostate) +{ + switch (iostate) { + case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM: + return "io+mem"; + case VGA_ARB_RSRC_LEGACY_IO: + return "io"; + case VGA_ARB_RSRC_LEGACY_MEM: + return "mem"; + } + + return "none"; +} + +int +pci_device_vgaarb_set_target(struct pci_device *dev) +{ + int len; + char buf[BUFSIZE]; + int ret; + + if (!dev) + dev = pci_sys->vga_default_dev; + if (!dev) + return -1; + + len = snprintf(buf, BUFSIZE, "target PCI:%04x:%02x:%02x.%x", + dev->domain, dev->bus, dev->dev, dev->func); + + ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len); + if (ret) + return ret; + + ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); + if (ret <= 0) + return -1; + + dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL); + pci_sys->vga_target = dev; + return 0; +} + +int +pci_device_vgaarb_decodes(int new_vgaarb_rsrc) +{ + int len; + char buf[BUFSIZE]; + int ret; + struct pci_device *dev = pci_sys->vga_target; + + if (!dev) + return -1; + if (dev->vgaarb_rsrc == new_vgaarb_rsrc) + return 0; + + len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(dev->vgaarb_rsrc)); + ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len); + if (ret == 0) + dev->vgaarb_rsrc = new_vgaarb_rsrc; + return ret; +} + +int +pci_device_vgaarb_lock(void) +{ + int len; + char buf[BUFSIZE]; + struct pci_device *dev = pci_sys->vga_target; + + if (!dev) + return -1; + + if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) + return 0; + + len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc)); + + return vgaarb_write(pci_sys->vgaarb_fd, buf, len); +} + +int +pci_device_vgaarb_trylock(void) +{ + int len; + char buf[BUFSIZE]; + struct pci_device *dev = pci_sys->vga_target; + + if (!dev) + return -1; + + if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) + return 0; + + len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc)); + + return vgaarb_write(pci_sys->vgaarb_fd, buf, len); +} + +int +pci_device_vgaarb_unlock(void) +{ + int len; + char buf[BUFSIZE]; + struct pci_device *dev = pci_sys->vga_target; + + if (!dev) + return -1; + + if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) + return 0; + + len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc)); + + return vgaarb_write(pci_sys->vgaarb_fd, buf, len); +} + +int pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count, int *rsrc_decodes) +{ + *vga_count = pci_sys->vga_count; + if (!dev) + return 0; + *rsrc_decodes = dev->vgaarb_rsrc; + return 0; +} diff -up libpciaccess-0.10.6/src/Makefile.am.da libpciaccess-0.10.6/src/Makefile.am --- libpciaccess-0.10.6/src/Makefile.am.da 2009-04-18 15:01:36.000000000 +1000 +++ libpciaccess-0.10.6/src/Makefile.am 2009-08-04 11:48:12.000000000 +1000 @@ -45,6 +45,12 @@ if SOLARIS OS_SUPPORT = solx_devfs.c pci_tools.h endif +if LINUX +VGA_ARBITER = common_vgaarb.c +else +VGA_ARBITER = common_vgaarb_stub.c +endif + libpciaccess_la_SOURCES = common_bridge.c \ common_iterator.c \ common_init.c \ @@ -53,6 +59,7 @@ libpciaccess_la_SOURCES = common_bridge. common_device_name.c \ common_map.c \ pciaccess_private.h \ + $(VGA_ARBITER) \ $(OS_SUPPORT) INCLUDES = -I$(top_srcdir)/include diff -up libpciaccess-0.10.6/src/pciaccess_private.h.da libpciaccess-0.10.6/src/pciaccess_private.h --- libpciaccess-0.10.6/src/pciaccess_private.h.da 2009-08-04 11:48:05.000000000 +1000 +++ libpciaccess-0.10.6/src/pciaccess_private.h 2009-08-04 11:48:12.000000000 +1000 @@ -61,6 +61,7 @@ struct pci_system_methods { int (*fill_capabilities)( struct pci_device * dev ); void (*enable)( struct pci_device *dev ); int (*boot_vga)( struct pci_device *dev ); + int (*has_kernel_driver)( struct pci_device *dev ); }; struct pci_device_mapping { @@ -131,6 +132,10 @@ struct pci_system { #ifdef HAVE_MTRR int mtrr_fd; #endif + int vgaarb_fd; + int vga_count; + struct pci_device *vga_target; + struct pci_device *vga_default_dev; }; extern struct pci_system * pci_sys; diff -up libpciaccess-0.10.6/include/pciaccess.h.da libpciaccess-0.10.6/include/pciaccess.h --- libpciaccess-0.10.6/include/pciaccess.h.da 2009-08-04 11:48:05.000000000 +1000 +++ libpciaccess-0.10.6/include/pciaccess.h 2009-08-04 11:48:12.000000000 +1000 @@ -21,6 +21,31 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +/* + * Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti + * + * 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 the rights to use, + * copy, modify, merge, publish, distribute, sublicense, 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 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS 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 pciaccess.h @@ -50,6 +75,8 @@ struct pci_slot_match; extern "C" { #endif +int pci_device_has_kernel_driver(struct pci_device *dev); + int pci_device_is_boot_vga(struct pci_device *dev); int pci_device_read_rom(struct pci_device *dev, void *buffer); @@ -350,6 +377,11 @@ struct pci_device { * the \c pci_device structure. */ intptr_t user_data; + + /** + * Used by the VGA arbiter. Type of resource decoded by the device and + * the file descriptor (/dev/vga_arbiter). */ + int vgaarb_rsrc; }; @@ -449,4 +481,28 @@ struct pci_pcmcia_bridge_info { }; + +/** + * VGA Arbiter definitions, functions and related. + */ + +/* Legacy VGA regions */ +#define VGA_ARB_RSRC_NONE 0x00 +#define VGA_ARB_RSRC_LEGACY_IO 0x01 +#define VGA_ARB_RSRC_LEGACY_MEM 0x02 +/* Non-legacy access */ +#define VGA_ARB_RSRC_NORMAL_IO 0x04 +#define VGA_ARB_RSRC_NORMAL_MEM 0x08 + +int pci_device_vgaarb_init (void); +void pci_device_vgaarb_fini (void); +int pci_device_vgaarb_set_target (struct pci_device *dev); +/* use the targetted device */ +int pci_device_vgaarb_decodes (int new_vga_rsrc); +int pci_device_vgaarb_lock (void); +int pci_device_vgaarb_trylock (void); +int pci_device_vgaarb_unlock (void); +/* return the current device count + resource decodes for the device */ +int pci_device_vgaarb_get_info (struct pci_device *dev, int *vga_count, int *rsrc_decodes); + #endif /* PCIACCESS_H */