1 /* ----------------------------------------------------------------------- *
3 * Copyright 2006-2007 Erwan Velu - All Rights Reserved
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
26 * ----------------------------------------------------------------------- */
31 * A module to extract pci informations
44 # define dprintf printf
46 # define dprintf(...) ((void)0)
51 /* searching the next char that is not a space */
52 static char *skipspace(char *p
)
54 while (*p
&& *p
<= ' ')
60 /* removing any \n found in a string */
61 static void remove_eol(char *string
)
63 int j
= strlen(string
);
65 for(i
= 0; i
< j
; i
++) if(string
[i
] == '\n') string
[i
] = 0;
68 /* converting a hexa string into its numerical value*/
69 static int hex_to_int(char *hexa
)
71 return strtoul(hexa
, NULL
, 16);
74 /* Try to match any pci device to the appropriate kernel module */
75 /* it uses the modules.pcimap from the boot device*/
76 void get_module_name_from_pci_ids(struct pci_device_list
*pci_device_list
)
79 char module_name
[21]; // the module name field is 21 char long
80 char delims
[]=" "; // colums are separated by spaces
83 char sub_vendor_id
[16];
84 char sub_product_id
[16];
88 /* Intializing the linux_kernel_module for each pci device to "unknow" */
89 /* adding a pci_dev_info member if needed*/
90 for (pci_dev
=0; pci_dev
< pci_device_list
->count
; pci_dev
++) {
91 struct pci_device
*pci_device
= &(pci_device_list
->pci_device
[pci_dev
]);
93 /* initialize the pci_dev_info structure if it doesn't exist yet. */
94 if (! pci_device
->pci_dev_info
) {
95 pci_device
->pci_dev_info
= calloc(1,sizeof (struct pci_device
));
96 if (!pci_device
->pci_dev_info
) {
97 printf("Can't allocate memory\n");
101 pci_device
->pci_dev_info
->linux_kernel_module
=strdup("unknown");
104 /* Opening the modules.pcimap (ofa linux kernel) from the boot device*/
105 f
=fopen("modules.pcimap","r");
109 strcpy(vendor_id
,"0000");
110 strcpy(product_id
,"0000");
111 strcpy(sub_product_id
,"0000");
112 strcpy(sub_vendor_id
,"0000");
114 /* for each line we found in the modules.pcimap*/
115 while ( fgets(line
, sizeof line
, f
) ) {
116 /*skipping unecessary lines */
117 if ((line
[0] == '#') || (line
[0] == ' ') || (line
[0] == 10))
123 /* looking for the next field */
124 result
= strtok(line
, delims
);
125 while( result
!= NULL
) {
126 /* if the column is larger than 1 char */
127 /* multiple spaces generates some empty fields*/
128 if (strlen(result
)>1) {
130 case 0:strcpy(module_name
,result
); break;
131 case 1:strcpy(vendor_id
,result
); break;
132 case 2:strcpy(product_id
,result
); break;
133 case 3:strcpy(sub_vendor_id
,result
); break;
134 case 4:strcpy(sub_product_id
,result
); break;
138 /* Searching the next field*/
139 result
= strtok( NULL
, delims
);
141 /* if a pci_device match an entry, fill the linux_kernel_module with
142 the appropriate kernel module */
143 for (pci_dev
=0; pci_dev
< pci_device_list
->count
; pci_dev
++) {
144 struct pci_device
*pci_device
=
145 &pci_device_list
->pci_device
[pci_dev
];
147 if (hex_to_int(vendor_id
) == pci_device
->vendor
&&
148 hex_to_int(product_id
) == pci_device
->product
&&
149 (hex_to_int(sub_product_id
) & pci_device
->sub_product
)
150 == pci_device
->sub_product
&&
151 (hex_to_int(sub_vendor_id
) & pci_device
->sub_vendor
)
152 == pci_device
->sub_vendor
)
153 strcpy(pci_device
->pci_dev_info
->linux_kernel_module
,
160 /* Try to match any pci device to the appropriate vendor and product name */
161 /* it uses the pci.ids from the boot device*/
162 void get_name_from_pci_ids(struct pci_device_list
*pci_device_list
)
169 char sub_product_id
[5];
170 char sub_vendor_id
[5];
174 /* Intializing the vendor/product name for each pci device to "unknow" */
175 /* adding a pci_dev_info member if needed*/
176 for (pci_dev
=0; pci_dev
< pci_device_list
->count
; pci_dev
++) {
177 struct pci_device
*pci_device
= &pci_device_list
->pci_device
[pci_dev
];
179 /* initialize the pci_dev_info structure if it doesn't exist yet. */
180 if (! pci_device
->pci_dev_info
) {
181 pci_device
->pci_dev_info
= calloc(1,sizeof (struct pci_device
));
183 if (!pci_device
->pci_dev_info
) {
184 printf("Can't allocate memory\n");
189 pci_device
->pci_dev_info
->vendor_name
=strdup("unknown");
190 pci_device
->pci_dev_info
->product_name
=strdup("unknown");
193 /* Opening the pci.ids from the boot device*/
194 f
=fopen("pci.ids","r");
198 strcpy(vendor_id
,"0000");
199 strcpy(product_id
,"0000");
200 strcpy(sub_product_id
,"0000");
201 strcpy(sub_vendor_id
,"0000");
204 /* for each line we found in the pci.ids*/
205 while ( fgets(line
, sizeof line
, f
) ) {
207 /* Skipping uncessary lines */
208 if ((line
[0] == '#') || (line
[0] == ' ') || (line
[0] == 'C') ||
211 /* If the line doesn't start with a tab, it means that's a vendor id */
212 if (line
[0] != '\t') {
214 /* the 4th first chars are the vendor_id */
215 strncpy(vendor_id
,line
,4);
217 /* the vendor name is the next field*/
219 vendor
=strdup(skipspace(strstr(line
," ")));
222 /* init product_id, sub_product and sub_vendor */
223 strcpy(product_id
,"0000");
224 strcpy(sub_product_id
,"0000");
225 strcpy(sub_vendor_id
,"0000");
227 /* ffff is an invalid vendor id */
228 if (strstr(vendor_id
,"ffff")) break;
230 /* assign the vendor_name to any matching pci device*/
231 for (pci_dev
=0; pci_dev
< pci_device_list
->count
; pci_dev
++) {
232 struct pci_device
*pci_device
=
233 &pci_device_list
->pci_device
[pci_dev
];
235 if (hex_to_int(vendor_id
) == pci_device
->vendor
)
236 pci_device
->pci_dev_info
->vendor_name
=strdup(vendor
);
238 /* if we have a tab + a char, it means this is a product id */
239 } else if ((line
[0] == '\t') && (line
[1] != '\t')) {
241 /* the product name the second field */
242 product
=strdup(skipspace(strstr(line
," ")));
245 /* the product id is first field */
246 strncpy(product_id
,&line
[1],4);
249 /* init sub_product and sub_vendor */
250 strcpy(sub_product_id
,"0000");
251 strcpy(sub_vendor_id
,"0000");
253 /* assign the product_name to any matching pci device*/
254 for (pci_dev
=0; pci_dev
< pci_device_list
->count
; pci_dev
++) {
255 struct pci_device
*pci_device
=
256 &pci_device_list
->pci_device
[pci_dev
];
257 if (hex_to_int(vendor_id
) == pci_device
->vendor
&&
258 hex_to_int(product_id
) == pci_device
->product
)
259 pci_device
->pci_dev_info
->product_name
=strdup(product
);
262 /* if we have two tabs, it means this is a sub product */
263 } else if ((line
[0] == '\t') && (line
[1] == '\t')) {
265 /* the product name is last field */
266 product
=skipspace(strstr(line
," "));
267 product
=strdup(skipspace(strstr(product
," ")));
270 /* the sub_vendor id is first field */
271 strncpy(sub_vendor_id
,&line
[2],4);
274 /* the sub_vendor id is second field */
275 strncpy(sub_product_id
,&line
[7],4);
278 /* assign the product_name to any matching pci device*/
279 for (pci_dev
=0; pci_dev
< pci_device_list
->count
; pci_dev
++) {
280 struct pci_device
*pci_device
=
281 &pci_device_list
->pci_device
[pci_dev
];
283 if (hex_to_int(vendor_id
) == pci_device
->vendor
&&
284 hex_to_int(product_id
) == pci_device
->product
&&
285 hex_to_int(sub_product_id
) == pci_device
->sub_product
&&
286 hex_to_int(sub_vendor_id
) == pci_device
->sub_vendor
)
287 pci_device
->pci_dev_info
->product_name
=strdup(product
);
294 /* searching if any pcidevice match our query */
295 struct match
*find_pci_device(struct pci_device_list
* pci_device_list
,
301 /* for all matches we have to search */
302 for (m
= list
; m
; m
= m
->next
) {
303 /* for each pci device we know */
304 for (pci_dev
= 0; pci_dev
< pci_device_list
->count
; pci_dev
++) {
305 struct pci_device
*pci_device
=
306 &pci_device_list
->pci_device
[pci_dev
];
308 /* sid & did are the easiest way to compare devices */
309 /* they are made of vendor/product subvendor/subproduct ids */
311 ((pci_device
->sub_product
) << 16 | (pci_device
->
313 did
= ((pci_device
->product
<< 16) | (pci_device
->vendor
));
315 /*if the current device match */
316 if (((did
^ m
->did
) & m
->did_mask
) == 0 &&
317 ((sid
^ m
->sid
) & m
->sid_mask
) == 0 &&
318 pci_device
->revision
>= m
->rid_min
319 && pci_device
->revision
<= m
->rid_max
) {
320 dprintf("PCI Match: Vendor=%04x Product=%04x Sub_vendor=%04x Sub_Product=%04x Release=%02x\n",
321 pci_device
->vendor
, pci_device
->product
,
322 pci_device
->sub_vendor
,
323 pci_device
->sub_product
,
324 pci_device
->revision
);
325 /* returning the matched pci device */
333 /* scanning the pci bus to find pci devices */
334 int pci_scan(struct pci_bus_list
* pci_bus_list
, struct pci_device_list
* pci_device_list
)
336 unsigned int bus
, dev
, func
, maxfunc
;
338 uint8_t hdrtype
, rid
;
342 pci_device_list
->count
= 0;
346 printf("Poking at port CF8 = %#08x\n", inl(0xcf8));
350 cfgtype
= pci_set_config_type(PCI_CFG_AUTO
);
353 dprintf("PCI configuration type %d\n", cfgtype
);
354 dprintf("Scanning PCI Buses\n");
356 /* We try to detect 255 buses */
357 for (bus
= 0; bus
<= MAX_PCI_BUSES
; bus
++) {
359 dprintf("Probing bus 0x%02x... \n", bus
);
361 pci_bus_list
->pci_bus
[bus
].id
= bus
;
362 pci_bus_list
->pci_bus
[bus
].pci_device_count
= 0;
363 pci_bus_list
->count
= 0;;
365 for (dev
= 0; dev
<= 0x1f; dev
++) {
367 for (func
= 0; func
<= maxfunc
; func
++) {
368 a
= pci_mkaddr(bus
, dev
, func
, 0);
372 if (did
== 0xffffffff || did
== 0xffff0000 ||
373 did
== 0x0000ffff || did
== 0x00000000)
376 hdrtype
= pci_readb(a
+ 0x0e);
379 maxfunc
= 7; /* Multifunction device */
381 rid
= pci_readb(a
+ 0x08);
382 sid
= pci_readl(a
+ 0x2c);
383 struct pci_device
*pci_device
=
385 pci_device
[pci_device_list
->count
];
386 pci_device
->product
= did
>> 16;
387 pci_device
->sub_product
= sid
>> 16;
388 pci_device
->vendor
= (did
<< 16) >> 16;
389 pci_device
->sub_vendor
= (sid
<< 16) >> 16;
390 pci_device
->revision
= rid
;
391 pci_device_list
->count
++;
393 ("Scanning: BUS %02x DID %08x (%04x:%04x) SID %08x RID %02x\n",
394 bus
, did
, did
>> 16, (did
<< 16) >> 16,
396 /* Adding the detected pci device to the bus */
397 pci_bus_list
->pci_bus
[bus
].
398 pci_device
[pci_bus_list
->pci_bus
[bus
].
399 pci_device_count
] = pci_device
;
400 pci_bus_list
->pci_bus
[bus
].pci_device_count
++;
405 /* Detecting pci buses that have pci devices connected */
406 for (bus
= 0; bus
<= 0xff; bus
++) {
407 if (pci_bus_list
->pci_bus
[bus
].pci_device_count
> 0) {
408 pci_bus_list
->count
++;