### Probe Device Details Source: https://context7.com/xorg/lib/llms.txt The `pci_device_probe()` function populates detailed information about a device, including memory regions (BARs), ROM size, and IRQ. This function must be called before accessing these details. The example iterates through all devices, probes them, and prints their details. ```c #include #include void probe_device_details(struct pci_device *dev) { int err; unsigned i; /* Probe the device to fill in detailed information */ err = pci_device_probe(dev); if (err != 0) { fprintf(stderr, "Failed to probe device: %d\n", err); return; } printf("Device %04x:%02x:%02x.%x probed:\n", dev->domain, dev->bus, dev->dev, dev->func); printf(" IRQ: %d\n", dev->irq); printf(" ROM Size: %lu bytes\n", (unsigned long)dev->rom_size); /* Print BAR (Base Address Register) information */ for (i = 0; i < 6; i++) { if (dev->regions[i].size != 0) { printf(" BAR%u: base=0x%lx size=%lu %s%s%s\n", i, (unsigned long)dev->regions[i].base_addr, (unsigned long)dev->regions[i].size, dev->regions[i].is_IO ? "I/O" : "MEM", dev->regions[i].is_64 ? " 64-bit" : "", dev->regions[i].is_prefetchable ? " prefetchable" : ""); } } } int main(void) { struct pci_device_iterator *iter; struct pci_device *dev; pci_system_init(); iter = pci_slot_match_iterator_create(NULL); while ((dev = pci_device_next(iter)) != NULL) { probe_device_details(dev); } pci_iterator_destroy(iter); pci_system_cleanup(); return 0; } ``` -------------------------------- ### Get PCI Device Vendor and Name Source: https://context7.com/xorg/lib/llms.txt Use pci_device_get_vendor_name() and pci_device_get_device_name() to look up human-readable names from the pci.ids database. Ensure the pci.ids file is accessible. ```c #include #include void print_device_names(struct pci_device *dev) { const char *vendor_name; const char *device_name; const char *subvendor_name; const char *subdevice_name; /* Get vendor and device names from pci.ids database */ vendor_name = pci_device_get_vendor_name(dev); device_name = pci_device_get_device_name(dev); subvendor_name = pci_device_get_subvendor_name(dev); subdevice_name = pci_device_get_subdevice_name(dev); printf("Device %04x:%02x:%02x.%x\n", dev->domain, dev->bus, dev->dev, dev->func); printf(" Vendor ID: 0x%04x", dev->vendor_id); if (vendor_name) { printf(" (%s)", vendor_name); } printf("\n"); printf(" Device ID: 0x%04x", dev->device_id); if (device_name) { printf(" (%s)", device_name); } printf("\n"); if (dev->subvendor_id != 0) { printf(" Subsystem Vendor: 0x%04x", dev->subvendor_id); if (subvendor_name) { printf(" (%s)", subvendor_name); } printf("\n"); printf(" Subsystem Device: 0x%04x", dev->subdevice_id); if (subdevice_name) { printf(" (%s)", subdevice_name); } printf("\n"); } } /* Alternative: Get all strings at once */ void get_all_names(struct pci_device *dev) { const char *device_name = NULL; const char *vendor_name = NULL; const char *subdevice_name = NULL; const char *subvendor_name = NULL; struct pci_id_match match = { .vendor_id = dev->vendor_id, .device_id = dev->device_id, .subvendor_id = dev->subvendor_id, .subdevice_id = dev->subdevice_id, .device_class = 0, .device_class_mask = 0 }; pci_get_strings(&match, &device_name, &vendor_name, &subdevice_name, &subvendor_name); printf("Vendor: %s\n", vendor_name ? vendor_name : "Unknown"); printf("Device: %s\n", device_name ? device_name : "Unknown"); } ``` -------------------------------- ### Enable Device Features via Command Register Source: https://context7.com/xorg/lib/llms.txt Modify the device's command register to enable bus mastering and memory space access. This example shows both direct write and atomic bit manipulation. ```c #include #include /* Enable bus mastering and memory space access */ void enable_device(struct pci_device *dev) { uint16_t command; int err; /* Read current command register value */ err = pci_device_cfg_read_u16(dev, &command, 0x04); if (err != 0) { fprintf(stderr, "Failed to read command register: %d\n", err); return; } printf("Original command register: 0x%04x\n", command); /* Set Bus Master Enable (bit 2) and Memory Space Enable (bit 1) */ command |= 0x0006; /* Write modified command register */ err = pci_device_cfg_write_u16(dev, command, 0x04); if (err != 0) { fprintf(stderr, "Failed to write command register: %d\n", err); return; } printf("New command register: 0x%04x\n", command); } ``` ```c /* Alternative using write_bits for atomic read-modify-write */ void enable_device_bits(struct pci_device *dev) { int err; /* Set bits 1 and 2 (Memory Space Enable and Bus Master Enable) * mask = 0x0006 (bits to modify) * data = 0x0006 (new values for those bits) */ err = pci_device_cfg_write_bits(dev, 0x0006, 0x0006, 0x04); if (err != 0) { fprintf(stderr, "Failed to modify command register: %d\n", err); return; } printf("Device enabled via write_bits\n"); } ``` -------------------------------- ### Read PCI Device Expansion ROM Source: https://context7.com/xorg/lib/llms.txt Use pci_device_read_rom() to read a device's expansion ROM. The buffer must be at least dev->rom_size bytes. Ensure the device is probed first using pci_device_probe() to get the correct rom_size. ```c #include #include #include void read_expansion_rom(struct pci_device *dev) { void *rom_buffer; int err; /* Probe device to get ROM size */ err = pci_device_probe(dev); if (err != 0) { fprintf(stderr, "Failed to probe device: %d\n", err); return; } if (dev->rom_size == 0) { printf("Device has no expansion ROM\n"); return; } printf("Reading expansion ROM (%lu bytes)\n", (unsigned long)dev->rom_size); /* Allocate buffer for ROM */ rom_buffer = malloc(dev->rom_size); if (rom_buffer == NULL) { fprintf(stderr, "Failed to allocate ROM buffer\n"); return; } /* Read ROM into buffer */ err = pci_device_read_rom(dev, rom_buffer); if (err != 0) { fprintf(stderr, "Failed to read ROM: %d\n", err); free(rom_buffer); return; } /* Check ROM signature (0x55 0xAA at offset 0) */ unsigned char *rom = (unsigned char *)rom_buffer; if (rom[0] == 0x55 && rom[1] == 0xAA) { printf("Valid ROM signature found\n"); printf("ROM size indicator: %u x 512 bytes\n", rom[2]); } else { printf("No valid ROM signature (got 0x%02x 0x%02x)\n", rom[0], rom[1]); } free(rom_buffer); } ``` -------------------------------- ### Perform Comprehensive PCI Device Scanning in C Source: https://context7.com/xorg/lib/llms.txt A complete workflow for initializing the PCI system, iterating through devices, and printing detailed hardware information including regions and kernel driver status. ```c #include #include #include void scan_pci_devices(int verbose) { struct pci_device_iterator *iter; struct pci_device *dev; int count = 0; iter = pci_slot_match_iterator_create(NULL); if (iter == NULL) { fprintf(stderr, "Failed to create iterator\n"); return; } while ((dev = pci_device_next(iter)) != NULL) { const char *vendor_name = pci_device_get_vendor_name(dev); const char *device_name = pci_device_get_device_name(dev); printf("%04x:%02x:%02x.%x [%04x:%04x] ", dev->domain, dev->bus, dev->dev, dev->func, dev->vendor_id, dev->device_id); if (vendor_name) printf("%s ", vendor_name); if (device_name) printf("%s", device_name); printf("\n"); if (verbose) { unsigned i; pci_device_probe(dev); printf(" Class: %02x:%02x:%02x Rev: %02x\n", (dev->device_class >> 16) & 0xff, (dev->device_class >> 8) & 0xff, dev->device_class & 0xff, dev->revision); for (i = 0; i < 6; i++) { if (dev->regions[i].size != 0) { printf(" Region %u: %s %016lx [size=%lu%s]\n", i, dev->regions[i].is_IO ? "I/O" : "Memory", (unsigned long)dev->regions[i].base_addr, (unsigned long)dev->regions[i].size, dev->regions[i].is_prefetchable ? " pref" : ""); } } if (pci_device_has_kernel_driver(dev)) { printf(" Kernel driver in use\n"); } } count++; } printf("\nTotal devices: %d\n", count); pci_iterator_destroy(iter); } int main(int argc, char **argv) { int err; int verbose = (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'v'); err = pci_system_init(); if (err != 0) { fprintf(stderr, "Failed to initialize PCI: %d\n", err); return 1; } scan_pci_devices(verbose); pci_system_cleanup(); return 0; } ``` -------------------------------- ### Initialize and Cleanup PCI Subsystem Source: https://context7.com/xorg/lib/llms.txt The pci_system_init and pci_system_cleanup functions must be called to manage the lifecycle of the PCI subsystem. ```c #include #include #include int main(void) { int err; /* Initialize PCI subsystem - must be called first */ err = pci_system_init(); if (err != 0) { fprintf(stderr, "Failed to initialize PCI system: %d\n", err); return 1; } printf("PCI system initialized successfully\n"); /* Perform PCI operations here... */ /* Cleanup when done - releases all resources */ pci_system_cleanup(); return 0; } ``` -------------------------------- ### Retrieve PCI Bridge Information in C Source: https://context7.com/xorg/lib/llms.txt Demonstrates using pci_device_get_bridge_info and pci_device_get_bridge_buses to inspect bridge device properties and bus hierarchies. ```c #include #include void print_bridge_info(struct pci_device *dev) { const struct pci_bridge_info *bridge; int primary, secondary, subordinate; int err; /* Check if this is a bridge device (class 0x06) */ if ((dev->device_class >> 16) != 0x06) { return; } /* Get detailed bridge information */ bridge = pci_device_get_bridge_info(dev); if (bridge != NULL) { printf("PCI Bridge %04x:%02x:%02x.%x:\n", dev->domain, dev->bus, dev->dev, dev->func); printf(" Primary bus: 0x%02x\n", bridge->primary_bus); printf(" Secondary bus: 0x%02x\n", bridge->secondary_bus); printf(" Subordinate bus: 0x%02x\n", bridge->subordinate_bus); printf(" Secondary latency: %u\n", bridge->secondary_latency_timer); printf(" I/O window: 0x%08x - 0x%08x\n", bridge->io_base, bridge->io_limit); printf(" Memory window: 0x%08x - 0x%08x\n", bridge->mem_base, bridge->mem_limit); printf(" Prefetchable memory: 0x%016lx - 0x%016lx\n", (unsigned long)bridge->prefetch_mem_base, (unsigned long)bridge->prefetch_mem_limit); } /* Alternative: get just the bus numbers */ err = pci_device_get_bridge_buses(dev, &primary, &secondary, &subordinate); if (err == 0) { printf(" Bus hierarchy: %d -> %d -> %d\n", primary, secondary, subordinate); } } int main(void) { struct pci_device_iterator *iter; struct pci_device *dev; pci_system_init(); iter = pci_slot_match_iterator_create(NULL); while ((dev = pci_device_next(iter)) != NULL) { pci_device_probe(dev); print_bridge_info(dev); } pci_iterator_destroy(iter); pci_system_cleanup(); return 0; } ``` -------------------------------- ### Access PCI I/O Ports Source: https://context7.com/xorg/lib/llms.txt Shows how to open an I/O handle for a device's I/O BAR and perform read operations at specific offsets. ```c #include #include void access_io_ports(struct pci_device *dev) { struct pci_io_handle *io_handle; unsigned i; int err; err = pci_device_probe(dev); if (err != 0) { return; } /* Find an I/O BAR */ for (i = 0; i < 6; i++) { if (dev->regions[i].size != 0 && dev->regions[i].is_IO) { printf("Opening I/O BAR%u: base=0x%lx size=%lu\n", i, (unsigned long)dev->regions[i].base_addr, (unsigned long)dev->regions[i].size); /* Open handle to I/O range */ io_handle = pci_device_open_io(dev, dev->regions[i].base_addr, dev->regions[i].size); if (io_handle == NULL) { fprintf(stderr, "Failed to open I/O range\n"); continue; } /* Read 8-bit value from offset 0 */ uint8_t val8 = pci_io_read8(io_handle, 0); printf(" Read8 [0x00]: 0x%02x\n", val8); /* Read 16-bit value from offset 0 */ uint16_t val16 = pci_io_read16(io_handle, 0); printf(" Read16[0x00]: 0x%04x\n", val16); /* Read 32-bit value from offset 0 */ uint32_t val32 = pci_io_read32(io_handle, 0); printf(" Read32[0x00]: 0x%08x\n", val32); /* Write example (commented for safety) * pci_io_write8(io_handle, 0x00, 0xff); * pci_io_write16(io_handle, 0x00, 0xffff); * pci_io_write32(io_handle, 0x00, 0xffffffff); */ /* Close I/O handle */ pci_device_close_io(dev, io_handle); break; } } } ``` -------------------------------- ### Iterate and Check Display Controller Status Source: https://context7.com/xorg/lib/llms.txt Initializes the PCI system, creates an iterator for display controllers, and iterates through them to check their status using `check_device_status`. Cleans up resources afterwards. ```c int main(void) { struct pci_device_iterator *iter; struct pci_device *dev; struct pci_id_match match = { .vendor_id = PCI_MATCH_ANY, .device_id = PCI_MATCH_ANY, .subvendor_id = PCI_MATCH_ANY, .subdevice_id = PCI_MATCH_ANY, .device_class = 0x030000, /* Display controllers */ .device_class_mask = 0xff0000 }; pci_system_init(); iter = pci_id_match_iterator_create(&match); while ((dev = pci_device_next(iter)) != NULL) { check_device_status(dev); } pci_iterator_destroy(iter); pci_system_cleanup(); return 0; } ``` -------------------------------- ### Enumerate PCI Devices with Iterators Source: https://context7.com/xorg/lib/llms.txt Use pci_slot_match_iterator_create to enumerate devices, optionally filtering by domain, bus, slot, or function using a pci_slot_match structure. ```c #include #include void enumerate_all_devices(void) { struct pci_device_iterator *iter; struct pci_device *dev; pci_system_init(); /* Create iterator for all devices (NULL = no filter) */ iter = pci_slot_match_iterator_create(NULL); if (iter == NULL) { fprintf(stderr, "Failed to create device iterator\n"); return; } /* Iterate through all PCI devices */ while ((dev = pci_device_next(iter)) != NULL) { printf("Device: %04x:%02x:%02x.%x - Vendor: 0x%04x, Device: 0x%04x\n", dev->domain, dev->bus, dev->dev, dev->func, dev->vendor_id, dev->device_id); } pci_iterator_destroy(iter); pci_system_cleanup(); } void enumerate_specific_bus(void) { struct pci_device_iterator *iter; struct pci_device *dev; struct pci_slot_match match = { .domain = 0, .bus = 0, /* Only bus 0 */ .dev = PCI_MATCH_ANY, .func = PCI_MATCH_ANY }; pci_system_init(); /* Create iterator filtered by bus */ iter = pci_slot_match_iterator_create(&match); while ((dev = pci_device_next(iter)) != NULL) { printf("Bus 0 Device: %02x.%x - 0x%04x:0x%04x\n", dev->dev, dev->func, dev->vendor_id, dev->device_id); } pci_iterator_destroy(iter); pci_system_cleanup(); } ``` -------------------------------- ### Initialize and Manage VGA Arbitration Source: https://context7.com/xorg/lib/llms.txt Initializes the VGA arbiter, sets the target device, locks and unlocks VGA resources, and cleans up. Handles potential errors during these operations. ```c #include #include void setup_vga_arbitration(struct pci_device *vga_dev) { int err; int vga_count; int rsrc_decodes; /* Initialize VGA arbiter (opens /dev/vga_arbiter) */ err = pci_device_vgaarb_init(); if (err != 0) { fprintf(stderr, "Failed to initialize VGA arbiter: %d\n", err); return; } /* Get current VGA count and resource decodes */ pci_device_vgaarb_get_info(vga_dev, &vga_count, &rsrc_decodes); printf("VGA devices in system: %d\n", vga_count); printf("Resource decodes: 0x%x\n", rsrc_decodes); /* Set target device for VGA arbitration */ err = pci_device_vgaarb_set_target(vga_dev); if (err != 0) { fprintf(stderr, "Failed to set VGA target: %d\n", err); goto cleanup; } /* Lock VGA resources (blocking) */ err = pci_device_vgaarb_lock(); if (err != 0) { fprintf(stderr, "Failed to lock VGA resources: %d\n", err); goto cleanup; } printf("VGA resources locked - performing VGA operations\n"); /* Perform VGA operations here... */ /* Unlock VGA resources */ err = pci_device_vgaarb_unlock(); if (err != 0) { fprintf(stderr, "Failed to unlock VGA resources: %d\n", err); } cleanup: pci_device_vgaarb_fini(); } ``` -------------------------------- ### Map and Access PCI Device Memory Source: https://context7.com/xorg/lib/llms.txt Demonstrates probing a device, identifying a memory BAR, mapping it into virtual address space, and unmapping it after use. ```c #include #include #include void access_device_memory(struct pci_device *dev) { void *mapped_addr = NULL; int err; unsigned i; /* First probe the device to get BAR information */ err = pci_device_probe(dev); if (err != 0) { fprintf(stderr, "Failed to probe device: %d\n", err); return; } /* Find first memory BAR (not I/O) */ for (i = 0; i < 6; i++) { if (dev->regions[i].size != 0 && !dev->regions[i].is_IO) { printf("Mapping BAR%u: base=0x%lx size=%lu\n", i, (unsigned long)dev->regions[i].base_addr, (unsigned long)dev->regions[i].size); /* Map the memory region with read/write access */ err = pci_device_map_range(dev, dev->regions[i].base_addr, dev->regions[i].size, PCI_DEV_MAP_FLAG_WRITABLE, &mapped_addr); if (err != 0) { fprintf(stderr, "Failed to map memory: %d\n", err); continue; } printf(" Mapped at virtual address: %p\n", mapped_addr); /* Read first 4 bytes as example */ uint32_t *regs = (uint32_t *)mapped_addr; printf(" First register value: 0x%08x\n", regs[0]); /* Unmap when done */ err = pci_device_unmap_range(dev, mapped_addr, dev->regions[i].size); if (err != 0) { fprintf(stderr, "Failed to unmap memory: %d\n", err); } break; /* Just map first memory BAR for demo */ } } } ``` -------------------------------- ### Find VGA Controllers by Device Class Source: https://context7.com/xorg/lib/llms.txt Uses `pci_id_match_iterator_create` to find devices classified as VGA compatible controllers (0x030000). The `device_class_mask` is set to `0xff0000` to ensure only the class is matched. Requires `pci_system_init()` before use and `pci_iterator_destroy()` and `pci_system_cleanup()` afterwards. ```c #include #include void find_vga_controllers(void) { struct pci_device_iterator *iter; struct pci_device *dev; struct pci_id_match match = { .vendor_id = PCI_MATCH_ANY, .device_id = PCI_MATCH_ANY, .subvendor_id = PCI_MATCH_ANY, .subdevice_id = PCI_MATCH_ANY, .device_class = 0x030000, /* VGA compatible controller */ .device_class_mask = 0xff0000 /* Match class only */ }; pci_system_init(); iter = pci_id_match_iterator_create(&match); printf("VGA controllers found:\n"); while ((dev = pci_device_next(iter)) != NULL) { printf(" %04x:%02x:%02x.%x - Vendor: 0x%04x, Device: 0x%04x\n", dev->domain, dev->bus, dev->dev, dev->func, dev->vendor_id, dev->device_id); } pci_iterator_destroy(iter); pci_system_cleanup(); } ``` -------------------------------- ### Find NVIDIA Devices by Vendor ID Source: https://context7.com/xorg/lib/llms.txt Uses `pci_id_match_iterator_create` to find all devices with the NVIDIA vendor ID (0x10de). Requires `pci_system_init()` before use and `pci_iterator_destroy()` and `pci_system_cleanup()` afterwards. ```c #include #include void find_nvidia_devices(void) { struct pci_device_iterator *iter; struct pci_device *dev; struct pci_id_match match = { .vendor_id = 0x10de, /* NVIDIA vendor ID */ .device_id = PCI_MATCH_ANY, .subvendor_id = PCI_MATCH_ANY, .subdevice_id = PCI_MATCH_ANY, .device_class = 0, .device_class_mask = 0 }; pci_system_init(); iter = pci_id_match_iterator_create(&match); printf("NVIDIA devices found:\n"); while ((dev = pci_device_next(iter)) != NULL) { printf(" %04x:%02x:%02x.%x - Device ID: 0x%04x\n", dev->domain, dev->bus, dev->dev, dev->func, dev->device_id); } pci_iterator_destroy(iter); pci_system_cleanup(); } ``` -------------------------------- ### Read PCI Configuration Space Values Source: https://context7.com/xorg/lib/llms.txt Use these functions to read byte, word, or dword values from a device's PCI configuration space. They automatically handle byte-swapping. Ensure proper error checking after reading. ```c #include #include void read_config_space(struct pci_device *dev) { uint8_t revision, header_type, cache_line; uint16_t command, status, subsystem_vendor, subsystem_device; uint32_t class_code; int err; /* Read revision ID (offset 0x08, 8-bit) */ err = pci_device_cfg_read_u8(dev, &revision, 0x08); if (err != 0) { fprintf(stderr, "Failed to read revision: %d\n", err); return; } /* Read command register (offset 0x04, 16-bit) */ pci_device_cfg_read_u16(dev, &command, 0x04); /* Read status register (offset 0x06, 16-bit) */ pci_device_cfg_read_u16(dev, &status, 0x06); /* Read header type (offset 0x0E, 8-bit) */ pci_device_cfg_read_u8(dev, &header_type, 0x0E); /* Read cache line size (offset 0x0C, 8-bit) */ pci_device_cfg_read_u8(dev, &cache_line, 0x0C); /* Read subsystem IDs (offsets 0x2C and 0x2E) */ pci_device_cfg_read_u16(dev, &subsystem_vendor, 0x2C); pci_device_cfg_read_u16(dev, &subsystem_device, 0x2E); printf("Device %04x:%02x:%02x.%x configuration:\n", dev->domain, dev->bus, dev->dev, dev->func); printf(" Revision: 0x%02x\n", revision); printf(" Command: 0x%04x\n", command); printf(" Status: 0x%04x\n", status); printf(" Header Type: 0x%02x\n", header_type); printf(" Cache Line: %u bytes\n", cache_line * 4); printf(" Subsystem: 0x%04x:0x%04x\n", subsystem_vendor, subsystem_device); } ``` -------------------------------- ### Find Device by Exact Slot Source: https://context7.com/xorg/lib/llms.txt Uses `pci_device_find_by_slot()` to directly locate a PCI device given its domain, bus, device, and function numbers. This is the most efficient method when the exact location is known. Requires `pci_system_init()` before use and `pci_system_cleanup()` afterwards. ```c #include #include int main(void) { struct pci_device *dev; pci_system_init(); /* Find device at domain 0, bus 0, device 2, function 0 */ dev = pci_device_find_by_slot(0, 0, 2, 0); if (dev != NULL) { printf("Found device at 0000:00:02.0\n"); printf(" Vendor ID: 0x%04x\n", dev->vendor_id); printf(" Device ID: 0x%04x\n", dev->device_id); printf(" Class: 0x%06x\n", dev->device_class); printf(" Revision: 0x%02x\n", dev->revision); } else { printf("No device found at 0000:00:02.0\n"); } pci_system_cleanup(); return 0; } ``` -------------------------------- ### Query PCI Device Status Source: https://context7.com/xorg/lib/llms.txt Checks if a PCI device has a kernel driver attached, if it is the boot VGA device, and if it is the boot display device. Prints the status for a given device. ```c #include #include void check_device_status(struct pci_device *dev) { int has_driver; int is_boot_vga; int is_boot_display; /* Check if a kernel driver is attached to the device */ has_driver = pci_device_has_kernel_driver(dev); /* Check if this is the boot VGA device */ is_boot_vga = pci_device_is_boot_vga(dev); /* Check if this is the boot display device */ is_boot_display = pci_device_is_boot_display(dev); printf("Device %04x:%02x:%02x.%x status:\n", dev->domain, dev->bus, dev->dev, dev->func); printf(" Kernel driver attached: %s\n", has_driver ? "yes" : "no"); printf(" Boot VGA device: %s\n", is_boot_vga ? "yes" : "no"); printf(" Boot display device: %s\n", is_boot_display ? "yes" : "no"); } ``` -------------------------------- ### Attempt Non-Blocking VGA Resource Lock Source: https://context7.com/xorg/lib/llms.txt Attempts to acquire the VGA lock without blocking. Reports success, failure due to busy resources, or other errors. Ensures cleanup by finalizing the arbiter. ```c /* Try to lock without blocking */ void try_vga_lock(void) { int err; pci_device_vgaarb_init(); pci_device_vgaarb_set_target(NULL); /* Use default VGA device */ /* Non-blocking lock attempt */ err = pci_device_vgaarb_trylock(); if (err == 0) { printf("Got VGA lock\n"); /* ... do work ... */ pci_device_vgaarb_unlock(); } else if (err == 2) { printf("VGA resources busy, try again later\n"); } else { printf("VGA lock failed: %d\n", err); } pci_device_vgaarb_fini(); } ``` -------------------------------- ### PCI Configuration Space Read Operations Source: https://context7.com/xorg/lib/llms.txt Functions to read 8, 16, or 32-bit values from a PCI device's configuration space with automatic byte-swapping. ```APIDOC ## PCI Configuration Space Read ### Description Reads data from the PCI configuration space of a device. These functions handle necessary byte-swapping automatically. ### Functions - pci_device_cfg_read_u8(struct pci_device *dev, uint8_t *data, uint32_t offset) - pci_device_cfg_read_u16(struct pci_device *dev, uint16_t *data, uint32_t offset) - pci_device_cfg_read_u32(struct pci_device *dev, uint32_t *data, uint32_t offset) ### Parameters - **dev** (struct pci_device*) - Required - Pointer to the PCI device structure. - **data** (uint8_t/uint16_t/uint32_t*) - Required - Pointer to the variable where the read value will be stored. - **offset** (uint32_t) - Required - The byte offset within the configuration space to read from. ### Response - **Return Value** (int) - Returns 0 on success, or an error code on failure. ``` -------------------------------- ### PCI Configuration Space Write Operations Source: https://context7.com/xorg/lib/llms.txt Functions to write values to a PCI device's configuration space, including an atomic read-modify-write variant. ```APIDOC ## PCI Configuration Space Write ### Description Writes data to the PCI configuration space of a device. The `_bits` variant allows for atomic modification of specific bits. ### Functions - pci_device_cfg_write_u8(struct pci_device *dev, uint8_t data, uint32_t offset) - pci_device_cfg_write_u16(struct pci_device *dev, uint16_t data, uint32_t offset) - pci_device_cfg_write_u32(struct pci_device *dev, uint32_t data, uint32_t offset) - pci_device_cfg_write_bits(struct pci_device *dev, uint32_t mask, uint32_t data, uint32_t offset) ### Parameters - **dev** (struct pci_device*) - Required - Pointer to the PCI device structure. - **data** (uint8_t/uint16_t/uint32_t) - Required - The value to write. - **mask** (uint32_t) - Required - (For write_bits) The mask of bits to modify. - **offset** (uint32_t) - Required - The byte offset within the configuration space to write to. ### Response - **Return Value** (int) - Returns 0 on success, or an error code on failure. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.