/usr/X11/bin/scanpci
usage:
======
NAME
scanpci - scan/probe PCI buses
SYNOPSIS
/usr/X11/bin/scanpci [-v12OfV]
DESCRIPTION
Scanpci is a utility that can be used to scan PCI buses and
report information about the configuration space settings
for each PCI device. On most platforms, scanpci can only be
run by the root user.
OPTIONS
-v Print the configuration space information for each
device in a verbose format. Without this option,
only a brief description is printed for each device.
-1 Use PCI config type 1.
-2 Use PCI config type 2.
-f Used in conjunction with the above two options, this
forces the specified configuration type to be used
for config space access.
-O Use the OS's PCI config space access mechanism to
access the PCI config space (when available).
-V n Set the verbosity level to n for the internal PCI
scanner. This is primarily for debugging use.
SEE ALSO
pcitweak(1)
man scanpci for more information.
compile:
========
I donwloaded libpciaccess here without knowing whether there is a better place. The verison i am building is 0.10.3.
configure
make
make install
Reffer to README in the source tree for more compiling information
implementation:
===============
libpciaccess has the similar architecture of libpci in pciutils. Here is the implement of scanpci utility based on libpciaccess:
179 int main( int argc, char ** argv )
180 {
181 struct pci_device_iterator * iter;
182 struct pci_device * dev;
183 int ret;
184
185 ret = pci_system_init();
186 if (ret != 0)
187 err(1, "Couldn't initialize PCI system");
188
189 iter = pci_slot_match_iterator_create( NULL );
190
191 while ( (dev = pci_device_next( iter )) != NULL ) {
192 print_pci_device( dev, 1 );
193 }
194
195 pci_system_cleanup();
196 return 0;
197 }
OS dependent initialization, including the access methods, is implement in pci_system_init(). For Solaris Operating System, the method is defined as:
137 static const struct pci_system_methods solx_devfs_methods = {
138 .destroy = pci_system_solx_devfs_destroy,
139 .destroy_device = NULL,
140 .read_rom = pci_device_solx_devfs_read_rom,
141 .probe = pci_device_solx_devfs_probe,
142 .map_range = pci_device_solx_devfs_map_range,
143 .unmap_range = pci_device_generic_unmap_range,
144
145 .read = pci_device_solx_devfs_read,
146 .write = pci_device_solx_devfs_write,
147
148 .fill_capabilities = pci_fill_capabilities_generic
149 };
These methods are based on the pci-tools in Solaris kernel. Below is the example if read method:
730 /*
731 * solaris version: Read the configurations space of the devices
732 */
733 static int
734 pci_device_solx_devfs_read( struct pci_device * dev, void * data,
735 pciaddr_t offset, pciaddr_t size,
736 pciaddr_t * bytes_read )
737 {
738 pcitool_reg_t cfg_prg;
739 int err = 0;
740 int i = 0;
741
742 cfg_prg.offset = offset;
743 cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN;
744 cfg_prg.bus_no = dev->bus;
745 cfg_prg.dev_no = dev->dev;
746 cfg_prg.func_no = dev->func;
747 cfg_prg.barnum = 0;
748 cfg_prg.user_version = PCITOOL_USER_VERSION;
749 *bytes_read = 0;
750
751 for (i = 0; i < size; i = i + PCITOOL_ACC_ATTR_SIZE(PCITOOL_ACC_ATTR_SIZE_1)) {
752
753 cfg_prg.offset = offset + i;
754 if ((err = ioctl(root_fd, PCITOOL_DEVICE_GET_REG,
755 &cfg_prg)) != 0) {
756 fprintf(stderr, "read bdf<%x,%x,%x,%llx> config space failure/n",
757 cfg_prg.bus_no,
758 cfg_prg.dev_no,
759 cfg_prg.func_no,
760 cfg_prg.offset);
761 fprintf(stderr, "Failure cause = %x/n", err);
762 break;
763 }
764
765 ((uint8_t *)data)[i] = (uint8_t)cfg_prg.data;
766 /*
767 * DWORDS Offset or bytes Offset ??
768 */
769 }
770 *bytes_read = i;
771
772 return (err);
773 }
interface:
==========
(1) pci_device_read_rom( )
77 /**
78 * Read a device's expansion ROM.
79 *
80 * Reads the device's expansion ROM and stores the data in the memory pointed
81 * to by /c buffer. The buffer must be at least /c pci_device::rom_size
82 * bytes.
83 *
84 * /param dev Device whose expansion ROM is to be read.
85 * /param buffer Memory in which to store the ROM.
86 *
87 * /return
88 * Zero on success or an /c errno value on failure.
89 */
90 int
91 pci_device_read_rom( struct pci_device * dev, void * buffer )
(2) pci_device_probe( )
102 /**
103 * Probe a PCI device to learn information about the device.
104 *
105 * Probes a PCI device to learn various information about the device. Before
106 * calling this function, the only public fields in the /c pci_device
107 * structure that have valid values are /c pci_device::domain,
108 * /c pci_device::bus, /c pci_device::dev, and /c pci_device::func.
109 *
110 * /param dev Device to be probed.
111 *
112 * /return
113 * Zero on succes or an /c errno value on failure.
114 */
115 int
116 pci_device_probe( struct pci_device * dev )
(3) pci_device_map_region( )
127 /**
128 * Map the specified BAR so that it can be accessed by the CPU.
129 *
130 * Maps the specified BAR for acces by the processor. The pointer to the
131 * mapped region is stored in the /c pci_mem_region::memory pointer for the
132 * BAR.
133 *
134 * /param dev Device whose memory region is to be mapped.
135 * /param region Region, on the range [0, 5], that is to be mapped.
136 * /param write_enable Map for writing (non-zero).
137 *
138 * /return
139 * Zero on success or an /c errno value on failure.
140 *
141 * /sa pci_device_map_range, pci_device_unmap_range
142 * /deprecated
143 */
144 int
145 pci_device_map_region(struct pci_device * dev, unsigned region,
146 int write_enable)
(4) pci_device_unmap_region( )
291 /**
292 * Unmap the specified BAR so that it can no longer be accessed by the CPU.
293 *
294 * Unmaps the specified BAR that was previously mapped via
295 * /c pci_device_map_region.
296 *
297 * /param dev Device whose memory region is to be mapped.
298 * /param region Region, on the range [0, 5], that is to be mapped.
299 *
300 * /return
301 * Zero on success or an /c errno value on failure.
302 *
303 * /sa pci_device_map_range, pci_device_unmap_range
304 * /deprecated
305 */
306 int
307 pci_device_unmap_region( struct pci_device * dev, unsigned region )
(5) pci_device_cfg_read( )
413 /**
414 * Read arbitrary bytes from device's PCI config space
415 *
416 * Reads data from the device's PCI configuration space. As with the system
417 * read command, less data may be returned, without an error, than was
418 * requested. This is particuarly the case if a non-root user tries to read
419 * beyond the first 64-bytes of configuration space.
420 *
421 * /param dev Device whose PCI configuration data is to be read.
422 * /param data Location to store the data
423 * /param offset Initial byte offset to read
424 * /param size Total number of bytes to read
425 * /param bytes_read Location to store the actual number of bytes read. This
426 * pointer may be /c NULL.
427 *
428 * /returns
429 * Zero on success or an errno value on failure.
430 *
431 * /note
432 * Data read from PCI configuartion space using this routine is /b not
433 * byte-swapped to the host's byte order. PCI configuration data is always
434 * stored in little-endian order, and that is what this routine returns.
435 */
436 int
437 pci_device_cfg_read( struct pci_device * dev, void * data,
438 pciaddr_t offset, pciaddr_t size,
439 pciaddr_t * bytes_read )
(6) pci_device_cfg_write( )
500 /**
501 * Write arbitrary bytes to device's PCI config space
502 *
503 * Writess data to the device's PCI configuration space. As with the system
504 * write command, less data may be written, without an error, than was
505 * requested.
506 *
507 * /param dev Device whose PCI configuration data is to be written.
508 * /param data Location of the source data
509 * /param offset Initial byte offset to write
510 * /param size Total number of bytes to write
511 * /param bytes_read Location to store the actual number of bytes written.
512 * This pointer may be /c NULL.
513 *
514 * /returns
515 * Zero on success or an errno value on failure.
516 *
517 * /note
518 * Data written to PCI configuartion space using this routine is /b not
519 * byte-swapped from the host's byte order. PCI configuration data is always
520 * stored in little-endian order, so data written with this routine should be
521 * put in that order in advance.
522 */
523 int
524 pci_device_cfg_write( struct pci_device * dev, const void * data,
525 pciaddr_t offset, pciaddr_t size,
526 pciaddr_t * bytes_written )
usage:
======
NAME
scanpci - scan/probe PCI buses
SYNOPSIS
/usr/X11/bin/scanpci [-v12OfV]
DESCRIPTION
Scanpci is a utility that can be used to scan PCI buses and
report information about the configuration space settings
for each PCI device. On most platforms, scanpci can only be
run by the root user.
OPTIONS
-v Print the configuration space information for each
device in a verbose format. Without this option,
only a brief description is printed for each device.
-1 Use PCI config type 1.
-2 Use PCI config type 2.
-f Used in conjunction with the above two options, this
forces the specified configuration type to be used
for config space access.
-O Use the OS's PCI config space access mechanism to
access the PCI config space (when available).
-V n Set the verbosity level to n for the internal PCI
scanner. This is primarily for debugging use.
SEE ALSO
pcitweak(1)
man scanpci for more information.
compile:
========
I donwloaded libpciaccess here without knowing whether there is a better place. The verison i am building is 0.10.3.
configure
make
make install
Reffer to README in the source tree for more compiling information
implementation:
===============
libpciaccess has the similar architecture of libpci in pciutils. Here is the implement of scanpci utility based on libpciaccess:
179 int main( int argc, char ** argv )
180 {
181 struct pci_device_iterator * iter;
182 struct pci_device * dev;
183 int ret;
184
185 ret = pci_system_init();
186 if (ret != 0)
187 err(1, "Couldn't initialize PCI system");
188
189 iter = pci_slot_match_iterator_create( NULL );
190
191 while ( (dev = pci_device_next( iter )) != NULL ) {
192 print_pci_device( dev, 1 );
193 }
194
195 pci_system_cleanup();
196 return 0;
197 }
OS dependent initialization, including the access methods, is implement in pci_system_init(). For Solaris Operating System, the method is defined as:
137 static const struct pci_system_methods solx_devfs_methods = {
138 .destroy = pci_system_solx_devfs_destroy,
139 .destroy_device = NULL,
140 .read_rom = pci_device_solx_devfs_read_rom,
141 .probe = pci_device_solx_devfs_probe,
142 .map_range = pci_device_solx_devfs_map_range,
143 .unmap_range = pci_device_generic_unmap_range,
144
145 .read = pci_device_solx_devfs_read,
146 .write = pci_device_solx_devfs_write,
147
148 .fill_capabilities = pci_fill_capabilities_generic
149 };
These methods are based on the pci-tools in Solaris kernel. Below is the example if read method:
730 /*
731 * solaris version: Read the configurations space of the devices
732 */
733 static int
734 pci_device_solx_devfs_read( struct pci_device * dev, void * data,
735 pciaddr_t offset, pciaddr_t size,
736 pciaddr_t * bytes_read )
737 {
738 pcitool_reg_t cfg_prg;
739 int err = 0;
740 int i = 0;
741
742 cfg_prg.offset = offset;
743 cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN;
744 cfg_prg.bus_no = dev->bus;
745 cfg_prg.dev_no = dev->dev;
746 cfg_prg.func_no = dev->func;
747 cfg_prg.barnum = 0;
748 cfg_prg.user_version = PCITOOL_USER_VERSION;
749 *bytes_read = 0;
750
751 for (i = 0; i < size; i = i + PCITOOL_ACC_ATTR_SIZE(PCITOOL_ACC_ATTR_SIZE_1)) {
752
753 cfg_prg.offset = offset + i;
754 if ((err = ioctl(root_fd, PCITOOL_DEVICE_GET_REG,
755 &cfg_prg)) != 0) {
756 fprintf(stderr, "read bdf<%x,%x,%x,%llx> config space failure/n",
757 cfg_prg.bus_no,
758 cfg_prg.dev_no,
759 cfg_prg.func_no,
760 cfg_prg.offset);
761 fprintf(stderr, "Failure cause = %x/n", err);
762 break;
763 }
764
765 ((uint8_t *)data)[i] = (uint8_t)cfg_prg.data;
766 /*
767 * DWORDS Offset or bytes Offset ??
768 */
769 }
770 *bytes_read = i;
771
772 return (err);
773 }
interface:
==========
(1) pci_device_read_rom( )
77 /**
78 * Read a device's expansion ROM.
79 *
80 * Reads the device's expansion ROM and stores the data in the memory pointed
81 * to by /c buffer. The buffer must be at least /c pci_device::rom_size
82 * bytes.
83 *
84 * /param dev Device whose expansion ROM is to be read.
85 * /param buffer Memory in which to store the ROM.
86 *
87 * /return
88 * Zero on success or an /c errno value on failure.
89 */
90 int
91 pci_device_read_rom( struct pci_device * dev, void * buffer )
(2) pci_device_probe( )
102 /**
103 * Probe a PCI device to learn information about the device.
104 *
105 * Probes a PCI device to learn various information about the device. Before
106 * calling this function, the only public fields in the /c pci_device
107 * structure that have valid values are /c pci_device::domain,
108 * /c pci_device::bus, /c pci_device::dev, and /c pci_device::func.
109 *
110 * /param dev Device to be probed.
111 *
112 * /return
113 * Zero on succes or an /c errno value on failure.
114 */
115 int
116 pci_device_probe( struct pci_device * dev )
(3) pci_device_map_region( )
127 /**
128 * Map the specified BAR so that it can be accessed by the CPU.
129 *
130 * Maps the specified BAR for acces by the processor. The pointer to the
131 * mapped region is stored in the /c pci_mem_region::memory pointer for the
132 * BAR.
133 *
134 * /param dev Device whose memory region is to be mapped.
135 * /param region Region, on the range [0, 5], that is to be mapped.
136 * /param write_enable Map for writing (non-zero).
137 *
138 * /return
139 * Zero on success or an /c errno value on failure.
140 *
141 * /sa pci_device_map_range, pci_device_unmap_range
142 * /deprecated
143 */
144 int
145 pci_device_map_region(struct pci_device * dev, unsigned region,
146 int write_enable)
(4) pci_device_unmap_region( )
291 /**
292 * Unmap the specified BAR so that it can no longer be accessed by the CPU.
293 *
294 * Unmaps the specified BAR that was previously mapped via
295 * /c pci_device_map_region.
296 *
297 * /param dev Device whose memory region is to be mapped.
298 * /param region Region, on the range [0, 5], that is to be mapped.
299 *
300 * /return
301 * Zero on success or an /c errno value on failure.
302 *
303 * /sa pci_device_map_range, pci_device_unmap_range
304 * /deprecated
305 */
306 int
307 pci_device_unmap_region( struct pci_device * dev, unsigned region )
(5) pci_device_cfg_read( )
413 /**
414 * Read arbitrary bytes from device's PCI config space
415 *
416 * Reads data from the device's PCI configuration space. As with the system
417 * read command, less data may be returned, without an error, than was
418 * requested. This is particuarly the case if a non-root user tries to read
419 * beyond the first 64-bytes of configuration space.
420 *
421 * /param dev Device whose PCI configuration data is to be read.
422 * /param data Location to store the data
423 * /param offset Initial byte offset to read
424 * /param size Total number of bytes to read
425 * /param bytes_read Location to store the actual number of bytes read. This
426 * pointer may be /c NULL.
427 *
428 * /returns
429 * Zero on success or an errno value on failure.
430 *
431 * /note
432 * Data read from PCI configuartion space using this routine is /b not
433 * byte-swapped to the host's byte order. PCI configuration data is always
434 * stored in little-endian order, and that is what this routine returns.
435 */
436 int
437 pci_device_cfg_read( struct pci_device * dev, void * data,
438 pciaddr_t offset, pciaddr_t size,
439 pciaddr_t * bytes_read )
(6) pci_device_cfg_write( )
500 /**
501 * Write arbitrary bytes to device's PCI config space
502 *
503 * Writess data to the device's PCI configuration space. As with the system
504 * write command, less data may be written, without an error, than was
505 * requested.
506 *
507 * /param dev Device whose PCI configuration data is to be written.
508 * /param data Location of the source data
509 * /param offset Initial byte offset to write
510 * /param size Total number of bytes to write
511 * /param bytes_read Location to store the actual number of bytes written.
512 * This pointer may be /c NULL.
513 *
514 * /returns
515 * Zero on success or an errno value on failure.
516 *
517 * /note
518 * Data written to PCI configuartion space using this routine is /b not
519 * byte-swapped from the host's byte order. PCI configuration data is always
520 * stored in little-endian order, so data written with this routine should be
521 * put in that order in advance.
522 */
523 int
524 pci_device_cfg_write( struct pci_device * dev, const void * data,
525 pciaddr_t offset, pciaddr_t size,
526 pciaddr_t * bytes_written )