xref: /libpciaccess/src/common_iterator.c (revision b4ee1ccf)
1 /*
2  * (C) Copyright IBM Corporation 2006
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * on the rights to use, copy, modify, merge, publish, distribute, sub
9  * license, and/or sell copies of the Software, and to permit persons to whom
10  * the Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19  * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 /**
26  * \file common_iterator.c
27  * Platform independent iterator support routines.
28  *
29  * \author Ian Romanick <[email protected]>
30  */
31 
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "pciaccess.h"
36 #include "pciaccess_private.h"
37 
38 /**
39  * Track device iteration state
40  *
41  * \private
42  */
43 struct pci_device_iterator {
44     unsigned next_index;
45 
46     enum {
47 	match_any,
48 	match_slot,
49 	match_id
50     } mode;
51 
52     union {
53 	struct pci_slot_match   slot;
54 	struct pci_id_match     id;
55     } match;
56 };
57 
58 
59 /**
60  * Create an iterator based on a regular expression.
61  *
62  * \return
63  * A pointer to a fully initialized \c pci_device_iterator structure on
64  * success, or \c NULL on failure.
65  *
66  * \sa pci_id_match_iterator_create, pci_device_next, pci_iterator_destroy
67  */
68 struct pci_device_iterator *
69 pci_slot_match_iterator_create( const struct pci_slot_match * match )
70 {
71     struct pci_device_iterator * iter;
72 
73     if ( pci_sys == NULL ) {
74 	return NULL;
75     }
76 
77     iter = malloc( sizeof( *iter ) );
78     if ( iter != NULL ) {
79 	iter->next_index = 0;
80 
81 	if ( match != NULL ) {
82 	    iter->mode = match_slot;
83 
84 	    (void) memcpy( & iter->match.slot, match, sizeof( *match ) );
85 	}
86 	else {
87 	    iter->mode = match_any;
88 	}
89     }
90 
91     return iter;
92 }
93 
94 
95 /**
96  * Create an iterator based on a regular expression.
97  *
98  * \return
99  * A pointer to a fully initialized \c pci_device_iterator structure on
100  * success, or \c NULL on failure.
101  *
102  * \sa pci_slot_match_iterator_create, pci_device_next, pci_iterator_destroy
103  */
104 struct pci_device_iterator *
105 pci_id_match_iterator_create( const struct pci_id_match * match )
106 {
107     struct pci_device_iterator * iter;
108 
109     if ( pci_sys == NULL ) {
110 	return NULL;
111     }
112 
113     iter = malloc( sizeof( *iter ) );
114     if ( iter != NULL ) {
115 	iter->next_index = 0;
116 
117 	if ( match != NULL ) {
118 	    iter->mode = match_id;
119 
120 	    (void) memcpy( & iter->match.id, match, sizeof( *match ) );
121 	}
122 	else {
123 	    iter->mode = match_any;
124 	}
125     }
126 
127     return iter;
128 }
129 
130 
131 /**
132  * Destroy an iterator previously created with \c pci_iterator_create.
133  *
134  * \param iter  Iterator to be destroyed.
135  *
136  * \sa pci_device_next, pci_iterator_create
137  */
138 void
139 pci_iterator_destroy( struct pci_device_iterator * iter )
140 {
141     if ( iter != NULL ) {
142 	free( iter );
143     }
144 }
145 
146 
147 /**
148  * Iterate to the next PCI device.
149  *
150  * \param iter  Device iterator returned by \c pci_device_iterate.
151  *
152  * \return
153  * A pointer to a \c pci_device, or \c NULL when all devices have been
154  * iterated.
155  */
156 struct pci_device *
157 pci_device_next( struct pci_device_iterator * iter )
158 {
159     struct pci_device_private * d = NULL;
160 
161     if (!iter)
162 	return NULL;
163 
164     switch( iter->mode ) {
165     case match_any:
166 	if ( iter->next_index < pci_sys->num_devices ) {
167 	    d = & pci_sys->devices[ iter->next_index ];
168 	    iter->next_index++;
169 	}
170 
171 	break;
172 
173     case match_slot: {
174 	while ( iter->next_index < pci_sys->num_devices ) {
175 	    struct pci_device_private * const temp =
176 	      & pci_sys->devices[ iter->next_index ];
177 
178 	    iter->next_index++;
179 	    if ( PCI_ID_COMPARE( iter->match.slot.domain, temp->base.domain )
180 		 && PCI_ID_COMPARE( iter->match.slot.bus, temp->base.bus )
181 		 && PCI_ID_COMPARE( iter->match.slot.dev, temp->base.dev )
182 		 && PCI_ID_COMPARE( iter->match.slot.func, temp->base.func ) ) {
183 		d = temp;
184 		break;
185 	    }
186 	}
187 
188 	break;
189     }
190 
191     case match_id: {
192 	while ( iter->next_index < pci_sys->num_devices ) {
193 	    struct pci_device_private * const temp =
194 	      & pci_sys->devices[ iter->next_index ];
195 
196 	    iter->next_index++;
197 	    if ( PCI_ID_COMPARE( iter->match.id.vendor_id, temp->base.vendor_id )
198 		 && PCI_ID_COMPARE( iter->match.id.device_id, temp->base.device_id )
199 		 && PCI_ID_COMPARE( iter->match.id.subvendor_id, temp->base.subvendor_id )
200 		 && PCI_ID_COMPARE( iter->match.id.subdevice_id, temp->base.subdevice_id )
201 		 && ((temp->base.device_class & iter->match.id.device_class_mask)
202 		     == iter->match.id.device_class) ) {
203 		d = temp;
204 		break;
205 	    }
206 	}
207 
208 	break;
209     }
210     }
211 
212     return (struct pci_device *) d;
213 }
214 
215 
216 struct pci_device *
217 pci_device_find_by_slot( uint32_t domain, uint32_t bus, uint32_t dev,
218 			 uint32_t func )
219 {
220     struct pci_device_iterator  iter;
221 
222 
223     iter.next_index = 0;
224     iter.mode = match_slot;
225     iter.match.slot.domain = domain;
226     iter.match.slot.bus = bus;
227     iter.match.slot.dev = dev;
228     iter.match.slot.func = func;
229 
230     return pci_device_next( & iter );
231 }
232