14f5e7dd7Smrg/*
24f5e7dd7Smrg * (C) Copyright IBM Corporation 2006
34f5e7dd7Smrg * All Rights Reserved.
44f5e7dd7Smrg *
54f5e7dd7Smrg * Permission is hereby granted, free of charge, to any person obtaining a
64f5e7dd7Smrg * copy of this software and associated documentation files (the "Software"),
74f5e7dd7Smrg * to deal in the Software without restriction, including without limitation
84f5e7dd7Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
94f5e7dd7Smrg * license, and/or sell copies of the Software, and to permit persons to whom
104f5e7dd7Smrg * the Software is furnished to do so, subject to the following conditions:
114f5e7dd7Smrg *
124f5e7dd7Smrg * The above copyright notice and this permission notice (including the next
134f5e7dd7Smrg * paragraph) shall be included in all copies or substantial portions of the
144f5e7dd7Smrg * Software.
154f5e7dd7Smrg *
164f5e7dd7Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
174f5e7dd7Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
184f5e7dd7Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
194f5e7dd7Smrg * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
204f5e7dd7Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
214f5e7dd7Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
224f5e7dd7Smrg * DEALINGS IN THE SOFTWARE.
234f5e7dd7Smrg */
244f5e7dd7Smrg
254f5e7dd7Smrg/**
264f5e7dd7Smrg * \file common_iterator.c
274f5e7dd7Smrg * Platform independent iterator support routines.
28cad31331Smrg *
294f5e7dd7Smrg * \author Ian Romanick <idr@us.ibm.com>
304f5e7dd7Smrg */
3149310723Smrg#ifdef HAVE_CONFIG_H
3249310723Smrg#include "config.h"
3349310723Smrg#endif
344f5e7dd7Smrg
354f5e7dd7Smrg#include <stdlib.h>
364f5e7dd7Smrg#include <string.h>
374f5e7dd7Smrg
384f5e7dd7Smrg#include "pciaccess.h"
394f5e7dd7Smrg#include "pciaccess_private.h"
404f5e7dd7Smrg
414f5e7dd7Smrg/**
424f5e7dd7Smrg * Track device iteration state
43cad31331Smrg *
444f5e7dd7Smrg * \private
454f5e7dd7Smrg */
464f5e7dd7Smrgstruct pci_device_iterator {
474f5e7dd7Smrg    unsigned next_index;
484f5e7dd7Smrg
494f5e7dd7Smrg    enum {
504f5e7dd7Smrg	match_any,
514f5e7dd7Smrg	match_slot,
524f5e7dd7Smrg	match_id
534f5e7dd7Smrg    } mode;
544f5e7dd7Smrg
554f5e7dd7Smrg    union {
564f5e7dd7Smrg	struct pci_slot_match   slot;
574f5e7dd7Smrg	struct pci_id_match     id;
584f5e7dd7Smrg    } match;
594f5e7dd7Smrg};
604f5e7dd7Smrg
614f5e7dd7Smrg
624f5e7dd7Smrg/**
634f5e7dd7Smrg * Create an iterator based on a regular expression.
644f5e7dd7Smrg *
654f5e7dd7Smrg * \return
664f5e7dd7Smrg * A pointer to a fully initialized \c pci_device_iterator structure on
674f5e7dd7Smrg * success, or \c NULL on failure.
684f5e7dd7Smrg *
694f5e7dd7Smrg * \sa pci_id_match_iterator_create, pci_device_next, pci_iterator_destroy
704f5e7dd7Smrg */
714f5e7dd7Smrgstruct pci_device_iterator *
724f5e7dd7Smrgpci_slot_match_iterator_create( const struct pci_slot_match * match )
734f5e7dd7Smrg{
744f5e7dd7Smrg    struct pci_device_iterator * iter;
75cad31331Smrg
764f5e7dd7Smrg    if ( pci_sys == NULL ) {
774f5e7dd7Smrg	return NULL;
784f5e7dd7Smrg    }
794f5e7dd7Smrg
804f5e7dd7Smrg    iter = malloc( sizeof( *iter ) );
814f5e7dd7Smrg    if ( iter != NULL ) {
824f5e7dd7Smrg	iter->next_index = 0;
834f5e7dd7Smrg
844f5e7dd7Smrg	if ( match != NULL ) {
854f5e7dd7Smrg	    iter->mode = match_slot;
864f5e7dd7Smrg
874f5e7dd7Smrg	    (void) memcpy( & iter->match.slot, match, sizeof( *match ) );
884f5e7dd7Smrg	}
894f5e7dd7Smrg	else {
904f5e7dd7Smrg	    iter->mode = match_any;
914f5e7dd7Smrg	}
924f5e7dd7Smrg    }
934f5e7dd7Smrg
944f5e7dd7Smrg    return iter;
954f5e7dd7Smrg}
964f5e7dd7Smrg
974f5e7dd7Smrg
984f5e7dd7Smrg/**
994f5e7dd7Smrg * Create an iterator based on a regular expression.
1004f5e7dd7Smrg *
1014f5e7dd7Smrg * \return
1024f5e7dd7Smrg * A pointer to a fully initialized \c pci_device_iterator structure on
1034f5e7dd7Smrg * success, or \c NULL on failure.
1044f5e7dd7Smrg *
1054f5e7dd7Smrg * \sa pci_slot_match_iterator_create, pci_device_next, pci_iterator_destroy
1064f5e7dd7Smrg */
1074f5e7dd7Smrgstruct pci_device_iterator *
1084f5e7dd7Smrgpci_id_match_iterator_create( const struct pci_id_match * match )
1094f5e7dd7Smrg{
1104f5e7dd7Smrg    struct pci_device_iterator * iter;
111cad31331Smrg
1124f5e7dd7Smrg    if ( pci_sys == NULL ) {
1134f5e7dd7Smrg	return NULL;
1144f5e7dd7Smrg    }
1154f5e7dd7Smrg
1164f5e7dd7Smrg    iter = malloc( sizeof( *iter ) );
1174f5e7dd7Smrg    if ( iter != NULL ) {
1184f5e7dd7Smrg	iter->next_index = 0;
1194f5e7dd7Smrg
1204f5e7dd7Smrg	if ( match != NULL ) {
1214f5e7dd7Smrg	    iter->mode = match_id;
1224f5e7dd7Smrg
1234f5e7dd7Smrg	    (void) memcpy( & iter->match.id, match, sizeof( *match ) );
1244f5e7dd7Smrg	}
1254f5e7dd7Smrg	else {
1264f5e7dd7Smrg	    iter->mode = match_any;
1274f5e7dd7Smrg	}
1284f5e7dd7Smrg    }
1294f5e7dd7Smrg
1304f5e7dd7Smrg    return iter;
1314f5e7dd7Smrg}
1324f5e7dd7Smrg
1334f5e7dd7Smrg
1344f5e7dd7Smrg/**
1354f5e7dd7Smrg * Destroy an iterator previously created with \c pci_iterator_create.
136cad31331Smrg *
1374f5e7dd7Smrg * \param iter  Iterator to be destroyed.
138cad31331Smrg *
1394f5e7dd7Smrg * \sa pci_device_next, pci_iterator_create
1404f5e7dd7Smrg */
1414f5e7dd7Smrgvoid
1424f5e7dd7Smrgpci_iterator_destroy( struct pci_device_iterator * iter )
1434f5e7dd7Smrg{
1444f5e7dd7Smrg    if ( iter != NULL ) {
1454f5e7dd7Smrg	free( iter );
1464f5e7dd7Smrg    }
1474f5e7dd7Smrg}
1484f5e7dd7Smrg
1494f5e7dd7Smrg
1504f5e7dd7Smrg/**
1514f5e7dd7Smrg * Iterate to the next PCI device.
152cad31331Smrg *
1534f5e7dd7Smrg * \param iter  Device iterator returned by \c pci_device_iterate.
154cad31331Smrg *
1554f5e7dd7Smrg * \return
1564f5e7dd7Smrg * A pointer to a \c pci_device, or \c NULL when all devices have been
1574f5e7dd7Smrg * iterated.
1584f5e7dd7Smrg */
1594f5e7dd7Smrgstruct pci_device *
1604f5e7dd7Smrgpci_device_next( struct pci_device_iterator * iter )
1614f5e7dd7Smrg{
1624f5e7dd7Smrg    struct pci_device_private * d = NULL;
1634f5e7dd7Smrg
1644f5e7dd7Smrg    if (!iter)
1654f5e7dd7Smrg	return NULL;
1664f5e7dd7Smrg
1674f5e7dd7Smrg    switch( iter->mode ) {
1684f5e7dd7Smrg    case match_any:
1694f5e7dd7Smrg	if ( iter->next_index < pci_sys->num_devices ) {
1704f5e7dd7Smrg	    d = & pci_sys->devices[ iter->next_index ];
1714f5e7dd7Smrg	    iter->next_index++;
1724f5e7dd7Smrg	}
1734f5e7dd7Smrg
1744f5e7dd7Smrg	break;
1754f5e7dd7Smrg
1764f5e7dd7Smrg    case match_slot: {
1774f5e7dd7Smrg	while ( iter->next_index < pci_sys->num_devices ) {
178cad31331Smrg	    struct pci_device_private * const temp =
1794f5e7dd7Smrg	      & pci_sys->devices[ iter->next_index ];
1804f5e7dd7Smrg
1814f5e7dd7Smrg	    iter->next_index++;
1824f5e7dd7Smrg	    if ( PCI_ID_COMPARE( iter->match.slot.domain, temp->base.domain )
1834f5e7dd7Smrg		 && PCI_ID_COMPARE( iter->match.slot.bus, temp->base.bus )
1844f5e7dd7Smrg		 && PCI_ID_COMPARE( iter->match.slot.dev, temp->base.dev )
1854f5e7dd7Smrg		 && PCI_ID_COMPARE( iter->match.slot.func, temp->base.func ) ) {
1864f5e7dd7Smrg		d = temp;
1874f5e7dd7Smrg		break;
1884f5e7dd7Smrg	    }
1894f5e7dd7Smrg	}
190cad31331Smrg
1914f5e7dd7Smrg	break;
1924f5e7dd7Smrg    }
1934f5e7dd7Smrg
1944f5e7dd7Smrg    case match_id: {
1954f5e7dd7Smrg	while ( iter->next_index < pci_sys->num_devices ) {
196cad31331Smrg	    struct pci_device_private * const temp =
1974f5e7dd7Smrg	      & pci_sys->devices[ iter->next_index ];
1984f5e7dd7Smrg
1994f5e7dd7Smrg	    iter->next_index++;
2004f5e7dd7Smrg	    if ( PCI_ID_COMPARE( iter->match.id.vendor_id, temp->base.vendor_id )
2014f5e7dd7Smrg		 && PCI_ID_COMPARE( iter->match.id.device_id, temp->base.device_id )
2024f5e7dd7Smrg		 && PCI_ID_COMPARE( iter->match.id.subvendor_id, temp->base.subvendor_id )
2034f5e7dd7Smrg		 && PCI_ID_COMPARE( iter->match.id.subdevice_id, temp->base.subdevice_id )
204cad31331Smrg		 && ((temp->base.device_class & iter->match.id.device_class_mask)
2054f5e7dd7Smrg		     == iter->match.id.device_class) ) {
2064f5e7dd7Smrg		d = temp;
2074f5e7dd7Smrg		break;
2084f5e7dd7Smrg	    }
2094f5e7dd7Smrg	}
210cad31331Smrg
2114f5e7dd7Smrg	break;
2124f5e7dd7Smrg    }
2134f5e7dd7Smrg    }
2144f5e7dd7Smrg
2154f5e7dd7Smrg    return (struct pci_device *) d;
2164f5e7dd7Smrg}
2174f5e7dd7Smrg
2184f5e7dd7Smrg
2194f5e7dd7Smrgstruct pci_device *
2204f5e7dd7Smrgpci_device_find_by_slot( uint32_t domain, uint32_t bus, uint32_t dev,
2214f5e7dd7Smrg			 uint32_t func )
2224f5e7dd7Smrg{
2234f5e7dd7Smrg    struct pci_device_iterator  iter;
224cad31331Smrg
225cad31331Smrg
2264f5e7dd7Smrg    iter.next_index = 0;
2274f5e7dd7Smrg    iter.mode = match_slot;
2284f5e7dd7Smrg    iter.match.slot.domain = domain;
2294f5e7dd7Smrg    iter.match.slot.bus = bus;
2304f5e7dd7Smrg    iter.match.slot.dev = dev;
2314f5e7dd7Smrg    iter.match.slot.func = func;
2324f5e7dd7Smrg
2334f5e7dd7Smrg    return pci_device_next( & iter );
2344f5e7dd7Smrg}
235