+2006-04-12 Ian Romanick <idr@us.ibm.com>
+
+ * configure.ac:
+ * src/Makefile.am:
+ Bump to version 0.4.0.
+
+ * include/pciaccess.h:
+ Add multiple-inclusion protection.
+
+ * src/common_interface.c: (pci_device_cfg_write_bits):
+ Add new function to write masked bits to PCI config space.
+ This mirrors functionality currently available in X.org that is slated
+ to be removed.
+
+ * src/common_iterator.c: (pci_slot_match_iterator_create),
+ (pci_id_match_iterator_create), (pci_iterator_destroy),
+ (pci_device_next), (pci_device_find_by_slot):
+ Gut old regex based search mechanism with a new mechanism that is
+ modeled after the Linux kernel. In addition to searching for
+ devices by device / vendor ID, it is possible to search for devices
+ by their domain / bus / slot / function.
+
+ * src/linux_sysfs.c: (pci_device_linux_sysfs_read_rom),
+ (pci_device_linux_sysfs_map_region),
+ (pci_device_linux_sysfs_unmap_region):
+ Fix serious bus in the reading of ROMs and in the unmapping of
+ regions. The main point is that the map routine depens on the
+ pci_mem_region::memory pointer being non-NULL only when the region
+ is mapped. Therefore, the unmap routine should set it to NULL after
+ unmapping.
+
+ * src/scanpci.c: (main):
+ Update to use new search API.
+
2006-03-27 Ian Romanick <idr@us.ibm.com>
* Makefile.am:
* \author Ian Romanick <idr@us.ibm.com>
*/
+#ifndef PCIACCESS_H
+#define PCIACCESS_H
+
#include <inttypes.h>
typedef uint64_t pciaddr_t;
struct pci_device;
struct pci_device_iterator;
struct pci_id_match;
+struct pci_slot_match;
int pci_device_read_rom( struct pci_device * dev, void * buffer );
void pci_system_cleanup( void );
-struct pci_device_iterator * pci_iterator_create( const char *regex );
+struct pci_device_iterator * pci_slot_match_iterator_create(
+ const struct pci_slot_match * match );
+
+struct pci_device_iterator * pci_id_match_iterator_create(
+ const struct pci_id_match * match );
void pci_iterator_destroy( struct pci_device_iterator * iter );
struct pci_device * pci_device_next( struct pci_device_iterator * iter );
+struct pci_device * pci_device_find_by_slot( uint32_t domain, uint32_t bus,
+ uint32_t dev, uint32_t func );
+
void pci_get_strings( const struct pci_id_match * m,
const char ** device_name, const char ** vendor_name,
const char ** subdevice_name, const char ** subvendor_name );
-const char * pci_get_name( const struct pci_id_match * m );
const char * pci_device_get_device_name( const struct pci_device * dev );
const char * pci_device_get_subdevice_name( const struct pci_device * dev );
const char * pci_device_get_vendor_name( const struct pci_device * dev );
pciaddr_t offset );
int pci_device_cfg_write_u32( struct pci_device * dev, const uint32_t * data,
pciaddr_t offset );
-
+int pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask,
+ uint32_t data, pciaddr_t offset );
#define PCI_MATCH_ANY (~0)
/**
+ * Compare two PCI ID values (either vendor or device). This is used
+ * internally to compare the fields of \c pci_id_match to the fields of
+ * \c pci_device.
+ */
+#define PCI_ID_COMPARE(a, b) \
+ (((a) == PCI_MATCH_ANY) || ((a) == (b)))
+
+/**
*/
struct pci_id_match {
/**
/**
+ */
+struct pci_slot_match {
+ /**
+ * \name Device slot matching controls
+ *
+ * Control the search based on the domain, bus, slot, and function of
+ * the device. Setting any of these fields to \c PCI_MATCH_ANY will cause
+ * the field to not be used in the comparison.
+ */
+ /*@{*/
+ uint32_t domain;
+ uint32_t bus;
+ uint32_t dev;
+ uint32_t func;
+ /*@}*/
+
+ intptr_t match_data;
+};
+
+/**
* BAR descriptor for a PCI device.
*/
struct pci_mem_region {
/*@}*/
/**
- * Device's class and subclass packed into a single 32-bit value.
+ * Device's class, subclass, and programming interface packed into a
+ * single 32-bit value. The class is at bits [23:16], subclass is at
+ * bits [15:8], and programming interface is at [7:0].
*/
uint32_t device_class;
* It is the user's responsability to free this memory before destroying
* the \c pci_device structure.
*/
- void * user_data;
+ intptr_t user_data;
};
uint8_t calibration_cycle_timing;
uint8_t max_requests;
};
+
+#endif /* PCIACCESS_H */
*/
#include <stdlib.h>
-#include <stdio.h>
#include <string.h>
-#include <regex.h>
#include "pciaccess.h"
#include "pciaccess_private.h"
*/
struct pci_device_iterator {
unsigned next_index;
- regex_t reg;
- int no_regex;
+
+ enum {
+ match_any,
+ match_slot,
+ match_id
+ } mode;
+
+ union {
+ struct pci_slot_match slot;
+ struct pci_id_match id;
+ } match;
};
+/**
+ * Create an iterator based on a regular expression.
+ *
+ * \return
+ * A pointer to a fully initialized \c pci_device_iterator structure on
+ * success, or \c NULL on failure.
+ *
+ * \sa pci_id_match_iterator_create, pci_device_next, pci_iterator_destroy
+ */
+struct pci_device_iterator *
+pci_slot_match_iterator_create( const struct pci_slot_match * match )
+{
+ struct pci_device_iterator * iter;
+
+ if ( pci_sys == NULL ) {
+ return NULL;
+ }
+
+ iter = malloc( sizeof( *iter ) );
+ if ( iter != NULL ) {
+ iter->next_index = 0;
+
+ if ( match != NULL ) {
+ iter->mode = match_slot;
+
+ (void) memcpy( & iter->match.slot, match, sizeof( *match ) );
+ }
+ else {
+ iter->mode = match_any;
+ }
+ }
+
+ return iter;
+}
+
/**
* Create an iterator based on a regular expression.
- *
- * The set of devices to be iterated is selected by the regular expression
- * passed in \c regex. The expression matches against an extended PCI bus
- * identifier string. The format of this string is
- * "domain:bus:slot.function:vendor:device_id:subvendor:subdevice_id:class".
- * Unlike classic X bus IDs, all values in the extened bus identifier string
- * are in hexadecimal. To simplify the required regular expressions, all hex
- * digits greater than 9 will be lower-case.
*
- * To match all devices in domain 0, the expression "0:.+" would be used. To
- * match all devices by ATI, the expression ".+:1002:.+". To match all devices
- * with a class of display, a class of multimedia and a subclass of video, or
- * a class of processor and a subclass of coprocessor, the expression
- * ".+:(03[[:hex:]]2|0400|0b40|0001)$" would be used. Since this is a fully
- * function regular expression, arbitrarilly complex matches can be requested.
- *
- * \param pci_sys Handle for the PCI subsystem.
- * \param regex Pointer to the regular expression to match against. If
- * \c NULL is passed, all devices will be matched.
- *
* \return
* A pointer to a fully initialized \c pci_device_iterator structure on
* success, or \c NULL on failure.
- *
- * \sa pci_device_next, pci_iterator_destroy
+ *
+ * \sa pci_slot_match_iterator_create, pci_device_next, pci_iterator_destroy
*/
struct pci_device_iterator *
-pci_iterator_create( const char * re )
+pci_id_match_iterator_create( const struct pci_id_match * match )
{
struct pci_device_iterator * iter;
if ( iter != NULL ) {
iter->next_index = 0;
- /* If the caller passed a NULL or empty expression, then we don't try
- * to compile the expression. Instead we set a flag that tells the
- * iterator routine to iterate every device in the list.
- */
- if ( (re != NULL) && (strlen( re ) > 0) ) {
- int err = regcomp( & iter->reg, re, REG_EXTENDED | REG_NOSUB );
- if ( err != 0 ) {
- free( iter );
- iter = NULL;
- }
+ if ( match != NULL ) {
+ iter->mode = match_id;
- iter->no_regex = 0;
+ (void) memcpy( & iter->match.id, match, sizeof( *match ) );
}
else {
- iter->no_regex = 1;
+ iter->mode = match_any;
}
}
pci_iterator_destroy( struct pci_device_iterator * iter )
{
if ( iter != NULL ) {
- if ( ! iter->no_regex ) {
- regfree( & iter->reg );
- }
-
free( iter );
}
}
-static void
-fill_device_string( struct pci_device_private * d )
-{
-
- if ( d->device_string == NULL ) {
- char * const string = malloc( 40 );
- if ( string != NULL ) {
- pci_device_probe( (struct pci_device *) d );
- sprintf( string, "%04x:%02x:%02x.%u:%04x:%04x:%04x:%04x:%06x",
- d->base.domain,
- d->base.bus,
- d->base.dev,
- d->base.func,
- d->base.vendor_id,
- d->base.device_id,
- d->base.subvendor_id,
- d->base.subdevice_id,
- d->base.device_class );
-
- d->device_string = string;
- }
- }
-}
-
-
/**
* Iterate to the next PCI device.
*
* \return
* A pointer to a \c pci_device, or \c NULL when all devices have been
* iterated.
- *
- * \bug
- * The only time this routine should be able to return \c NULL is when the
- * end of the list is hit. However, there is a memory allocation (via
- * \c fill_device_string) that can fail. If this allocation fails, \c NULL
- * will be erroneously returned. What should be done here? Pre-fill the
- * device strings in \c pci_iterator_create?
*/
struct pci_device *
pci_device_next( struct pci_device_iterator * iter )
{
struct pci_device_private * d = NULL;
- if ( iter->no_regex ) {
+ switch( iter->mode ) {
+ case match_any:
if ( iter->next_index < pci_sys->num_devices ) {
d = & pci_sys->devices[ iter->next_index ];
iter->next_index++;
}
- }
- else {
+
+ break;
+
+ case match_slot: {
while ( iter->next_index < pci_sys->num_devices ) {
struct pci_device_private * const temp =
& pci_sys->devices[ iter->next_index ];
- if ( temp->device_string == NULL ) {
- fill_device_string( temp );
- if ( temp->device_string == NULL ) {
- break;
- }
+ iter->next_index++;
+ if ( PCI_ID_COMPARE( iter->match.slot.domain, temp->base.domain )
+ && PCI_ID_COMPARE( iter->match.slot.bus, temp->base.bus )
+ && PCI_ID_COMPARE( iter->match.slot.dev, temp->base.dev )
+ && PCI_ID_COMPARE( iter->match.slot.func, temp->base.func ) ) {
+ d = temp;
+ break;
}
+ }
+
+ break;
+ }
- iter->next_index++;
+ case match_id: {
+ while ( iter->next_index < pci_sys->num_devices ) {
+ struct pci_device_private * const temp =
+ & pci_sys->devices[ iter->next_index ];
- if ( regexec( & iter->reg, temp->device_string, 0, NULL, 0 ) == 0 ) {
+ iter->next_index++;
+ if ( PCI_ID_COMPARE( iter->match.id.vendor_id, temp->base.vendor_id )
+ && PCI_ID_COMPARE( iter->match.id.device_id, temp->base.device_id )
+ && PCI_ID_COMPARE( iter->match.id.subvendor_id, temp->base.subvendor_id )
+ && PCI_ID_COMPARE( iter->match.id.subdevice_id, temp->base.subdevice_id )
+ && ((temp->base.device_class & iter->match.id.device_class_mask)
+ == iter->match.id.device_class) ) {
d = temp;
break;
}
}
+
+ break;
}
-
+ }
+
return (struct pci_device *) d;
}
+
+
+struct pci_device *
+pci_device_find_by_slot( uint32_t domain, uint32_t bus, uint32_t dev,
+ uint32_t func )
+{
+ struct pci_device_iterator iter;
+
+
+ iter.next_index = 0;
+ iter.mode = match_slot;
+ iter.match.slot.domain = domain;
+ iter.match.slot.bus = bus;
+ iter.match.slot.dev = dev;
+ iter.match.slot.func = func;
+
+ return pci_device_next( & iter );
+}
\ No newline at end of file
int fd;
struct stat st;
int err = 0;
+ size_t total_bytes;
snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/rom",
write( fd, "1", 1 );
lseek( fd, 0, SEEK_SET );
- if ( read( fd, buffer, st.st_size ) == -1 ) {
- err = errno;
+ for ( total_bytes = 0 ; total_bytes < st.st_size ; /* empty */ ) {
+ const int bytes = read( fd, (char *) buffer + total_bytes,
+ st.st_size - total_bytes );
+ if ( bytes == -1 ) {
+ err = errno;
+ break;
+ }
+ else if ( bytes == 0 ) {
+ break;
+ }
+
+ total_bytes += bytes;
}
+
lseek( fd, 0, SEEK_SET );
write( fd, "0", 1 );
char name[256];
int fd;
int err = 0;
- int prot = (write_enable) ? (PROT_READ | PROT_WRITE) : PROT_READ;
+ const int prot = (write_enable) ? (PROT_READ | PROT_WRITE) : PROT_READ;
snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/resource%u",
static int
pci_device_linux_sysfs_unmap_region( struct pci_device * dev, unsigned region )
{
- return munmap( dev->regions[ region ].memory,
- dev->regions[ region ].size );
+ int err = 0;
+
+ if ( munmap( dev->regions[ region ].memory, dev->regions[ region ].size )
+ == -1 ) {
+ err = errno;
+ }
+
+ dev->regions[ region ].memory = NULL;
+
+ return err;
}