Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


updated test vm to current palacios version and fixed pci scan
[palacios.git] / misc / test_vm / src / geekos / pci.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Peter Dinda <pdinda@northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Peter Dinda <pdinda@northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <geekos/malloc.h>
21 #include <geekos/pci.h>
22 #include <geekos/io.h>
23 #include <geekos/debug.h>
24
25 #define PCI_CONFIG_ADDRESS 0xcf8  // 32 bit, little endian
26 #define PCI_CONFIG_DATA    0xcfc  // 32 bit, little endian
27
28 #define PCI_MAX_NUM_BUSES  4
29
30
31 struct pci_device_config {
32     ushort_t   vendor_id;
33     ushort_t   device_id;
34     ushort_t   command;
35     ushort_t   status;
36     uchar_t    revision;
37     uchar_t    class_code[3];  // in order: programming interface, subclass, class code
38
39 #define PROG_INTERFACE(x) ((x)[0])
40 #define SUBCLASS(x) ((x)[1])
41 #define CLASSCODE(x) ((x)[2])
42   
43   
44     uchar_t    cache_line_size;
45     uchar_t    latency_time;
46     uchar_t    header_type; // bits 6-0: 00: other, 01: pci-pci bridge, 02: pci-cardbus; bit 7: 1=multifunction
47     
48 #define HEADER_TYPE(x) ((x) & 0x7f)
49     
50 #define PCI_DEVICE 0x0
51 #define PCI_PCI_BRIDGE 0x1
52 #define PCI_CARDBUS_BRIDGE 0x2
53
54 #define MULTIFUNCTION(x) ((x) & 0x80)
55
56 #define IS_DEVICE(x) (HEADER_TYPE(x) == 0x0)
57 #define IS_PCI_PCI_BRIDGE(x) (HEADER_TYPE(x) == 0x1)
58 #define IS_PCI_CARDBUS_BRIDGE(x) (HEADER_TYPE(x) == 0x2)
59
60     uchar_t    BIST;
61   
62     union {  
63     
64         // header = 00 (Device)
65         struct {
66             uint_t     BAR[6];
67             
68 #define IS_IO_ADDR(x)   ((x) & 0x1)
69 #define IS_MEM_ADDR(x)  (!((x) & 0x1))
70 #define GET_IO_ADDR(x)  (((uint_t)(x)) & 0xfffffffc) 
71 #define GET_MEM_ADDR(x) (((uint_t)(x)) & 0xfffffff0)
72 #define GET_MEM_TYPE(x) (((x) & 0x6) >> 2)
73 #define GET_MEM_PREFETCHABLE(x) ((x) & 0x8)
74
75             uint_t     cardbus_cis_pointer;
76             ushort_t   subsystem_vendor_id;
77             ushort_t   subsystem_id;
78             uint_t     expansion_rom_address;
79             uchar_t    cap_ptr;  // capabilities list offset in config space
80             uchar_t    reserved[7];
81             uchar_t    intr_line; // 00=none, 01=IRQ1, etc.
82             uchar_t    intr_pin;  // 00=none, otherwise INTA# to INTD#
83             uchar_t    min_grant; // min busmaster time - units of 250ns
84             uchar_t    max_latency; // units of 250ns - busmasters
85             uint_t     device_data[48];
86         }  __attribute__((__packed__))  pci_device_config;
87         
88         // header = 01 (pci-pci bridge)
89         struct {
90             uint_t     BAR[2];
91             uchar_t    primary_bus;  // the one closer to the processor
92             uchar_t    secondary_bus; // the one further away
93             uchar_t    subordinate_bus;
94             uchar_t    secondary_lat_timer;
95             uchar_t    io_base;
96             uchar_t    io_limit;
97             ushort_t   secondary_status;
98             ushort_t   memory_base;
99             ushort_t   memory_limit;
100             ushort_t   prefetchable_memory_base;
101             ushort_t   prefetchable_memory_limit;
102             uint_t     prefetchable_memory_base_upper;  // for 64 bit?
103             uint_t     prefetchable_memory_limit_upper;
104             ushort_t   io_base_upper;  // upper 16
105             ushort_t   io_limit_upper; 
106             uint_t     reserved;
107             uint_t     expansion_rom_address;
108             uchar_t    intr_line;
109             uchar_t    intr_pin;
110             ushort_t   bridge_ctl;
111             uint_t     device_data[48];
112         }  __attribute__((__packed__))  pci_pci_bridge_config;
113         
114
115         // header = 02 (pci-cardbus bridge)
116         struct {
117             uint_t     cardbus_base_addr;
118             uchar_t    cap_ptr;
119             uchar_t    reserved;
120             ushort_t   secondary_status;
121             uchar_t    pci_bus;
122             uchar_t    cardbus_bus;
123             uchar_t    subordinate_bus;
124             uchar_t    cardbus_lat_timer;
125             uint_t     memory_base0;
126             uint_t     memory_limit0;
127             uint_t     memory_base1;
128             uint_t     memory_limit1;
129             ushort_t   io_base0;
130             ushort_t   io_base0_upper;
131             ushort_t   io_limit0;
132             ushort_t   io_limit0_upper;
133             ushort_t   io_base1;
134             ushort_t   io_base1_upper;
135             ushort_t   io_limit1;
136             ushort_t   io_limit1_upper;
137             uchar_t    intr_line;
138             uchar_t    intr_pin;
139             ushort_t   bridge_ctl;
140             ushort_t   subsystem_vendor_id;
141             ushort_t   subsystem_device_id;
142             uint_t     legacy_16bit_base_addr;
143             uint_t     reserved2[14];
144             uint_t     device_data[32];
145         }  __attribute__((__packed__)) pci_cardbus_bridge_config;
146         
147     }  __attribute__((__packed__)) u;
148     
149 };
150
151 struct pci_bus {
152     uint_t number;
153     struct pci_bus * next;
154     
155     struct pci_device * device_list;
156 };
157
158 struct pci_device {
159     uint_t number;
160     uint_t function;
161     struct pci_bus    * bus;
162     struct pci_device * next;
163   
164     struct pci_device_config config;
165 };
166
167 struct pci {
168     uint_t          num_buses;
169     struct pci_bus * bus_list;
170 };
171     
172
173 static uint_t ReadPCIDWord(uint_t bus, uint_t dev, uint_t func, uint_t offset) {
174     uint_t address;
175     uint_t data;
176  
177     address = ((bus << 16) | (dev << 11) |
178                (func << 8) | (offset & 0xfc) | ((uint_t)0x80000000));
179  
180     Out_DWord(PCI_CONFIG_ADDRESS, address);
181     data = In_DWord(PCI_CONFIG_DATA);
182
183     return data;
184 }
185
186
187 static ushort_t ReadPCIWord(uint_t bus, uint_t dev, uint_t func, uint_t offset) {
188     return (ushort_t) (ReadPCIDWord(bus, dev, func, offset) >> ((offset & 0x2) * 8));
189 }
190
191
192 static struct pci * NewPCI() {
193     struct pci * p = (struct pci *)Malloc(sizeof(struct pci));
194     p->bus_list = NULL;
195     p->num_buses = 0;
196     return p;
197 }
198
199 static void AddPCIBus(struct pci * p, struct pci_bus * bus) {
200     bus->next = p->bus_list;
201     p->bus_list = bus;
202 }
203     
204
205 static struct pci_bus * NewPCIBus(struct pci * p) {
206     struct pci_bus * pb = (struct pci_bus *)Malloc(sizeof(struct pci_bus));
207     pb->device_list = NULL;
208     pb->number = (p->num_buses);
209     p->num_buses++;
210     return pb;
211 }
212
213 static void AddPCIDevice(struct pci_bus * b, struct pci_device * d) {
214     d->bus = b;
215     d->next = b->device_list;
216     b->device_list = d;
217 }
218  
219 static struct pci_device * NewPCIDevice(struct pci_bus * pb) {
220     struct pci_device *pd = (struct pci_device *)Malloc(sizeof(struct pci_device));
221     pd->number = 0;
222     pd->bus = NULL;
223     pd->next = NULL;
224     return pd;
225 }
226
227 static void GetPCIDeviceConfig(uint_t bus, uint_t dev, uint_t fn, struct pci_device * d) {
228     uint_t numdwords = (sizeof(struct pci_device_config) / 4);
229     uint_t i;
230     uint_t * p = (uint_t *)&(d->config);
231
232     for (i = 0; i < numdwords; i++) {
233         p[i] = ReadPCIDWord(bus, dev, fn, i * 4);
234         PrintBoth("Reading Config Word %d (val=%x)\n", i * 4, p[i]);
235     }
236 }
237
238
239
240 static struct pci * ScanPCI() {
241     uint_t bus, dev, fn;
242     ushort_t vendor;
243     struct pci * thepci = NewPCI();
244     struct pci_bus * thebus;
245  
246     for (bus = 0; bus < PCI_MAX_NUM_BUSES; bus++) {
247
248         // Are there any devices on the bus?
249         for (dev = 0; dev < 32; dev++) { 
250             vendor = ReadPCIWord(bus, dev, 0, 0);
251
252             if (vendor != 0xffff) { 
253                 break;
254             }
255         }
256
257         if (dev == 32) { 
258             continue;
259         }
260
261         // There are devices.  Create a bus.
262         thebus = NewPCIBus(thepci);
263         thebus->number = bus;
264
265
266         // Add the devices to the bus
267         for (dev = 0; dev < 32; dev++) { 
268             for (fn = 0; fn < 7; fn++) {
269                 
270                 vendor = ReadPCIWord(bus, dev, fn, 0);
271
272                 if (vendor != 0xffff) { 
273                     struct pci_device * thedev = NewPCIDevice(thebus);
274                     
275                     thedev->number = dev;
276                     thedev->function = fn;
277
278                     GetPCIDeviceConfig(bus, dev, fn, thedev);
279                     
280                     AddPCIDevice(thebus, thedev);
281                 }
282             }
283         }
284
285         AddPCIBus(thepci,thebus);
286     }
287
288
289     return thepci;
290 }
291
292 static void PrintPCIShared(struct pci_device * thedev) {
293     PrintBoth("    Slot: %u.%u\n", thedev->number, thedev->function);
294     PrintBoth("      vendor_id:        0x%x\n", (uint_t) thedev->config.vendor_id);
295     PrintBoth("      device_id:        0x%x\n", (uint_t) thedev->config.device_id);
296     PrintBoth("      command:          0x%x\n", (uint_t) thedev->config.command);
297     PrintBoth("      status:           0x%x\n", (uint_t) thedev->config.status);
298     PrintBoth("      revision:         0x%x\n", (uint_t) thedev->config.revision);
299     PrintBoth("      class_code:       0x%x%x%x (prog_interface 0x%x, subclass 0x%x, classcode 0x%x)\n", 
300               (uint_t) thedev->config.class_code[0],
301               (uint_t) thedev->config.class_code[1],
302               (uint_t) thedev->config.class_code[2],
303               (uint_t) PROG_INTERFACE(thedev->config.class_code),
304               (uint_t) SUBCLASS(thedev->config.class_code),
305               (uint_t) CLASSCODE(thedev->config.class_code) );
306     PrintBoth("      cache_line_size:  0x%x\n", (uint_t) thedev->config.cache_line_size);
307     PrintBoth("      latency_time:     0x%x\n", (uint_t) thedev->config.latency_time);
308     PrintBoth("      header_type:      0x%x (%s%s)\n", (uint_t) thedev->config.header_type,
309               HEADER_TYPE(thedev->config.header_type)==PCI_DEVICE ? "PCI Device" :
310               HEADER_TYPE(thedev->config.header_type)==PCI_PCI_BRIDGE ? "PCI-PCI Bridge" :
311               HEADER_TYPE(thedev->config.header_type)==PCI_CARDBUS_BRIDGE ? "PCI-Cardbus Bridge" : "UNKNOWN",
312               MULTIFUNCTION(thedev->config.header_type) ? " Multifunction" : ""
313               );
314     PrintBoth("      BIST:             0x%x\n", (uint_t) thedev->config.BIST);
315 }
316
317 static void PrintPCIDevice(struct pci_device * thedev) {
318     int i;
319   
320     PrintBoth("     PCI Device:\n");
321
322     PrintPCIShared(thedev);
323
324     for (i = 0; i < 6; i++) { 
325         PrintBoth("      BAR[%d]:           0x%x (", i, (uint_t) thedev->config.u.pci_device_config.BAR[i]);
326
327         if (IS_IO_ADDR(thedev->config.u.pci_device_config.BAR[i])) { 
328
329             PrintBoth("IO Address 0x%x)\n", GET_IO_ADDR(thedev->config.u.pci_device_config.BAR[i]));
330
331         } else if (IS_MEM_ADDR(thedev->config.u.pci_device_config.BAR[i])) { 
332
333             PrintBoth("Memory Address 0x%x type=0x%x%s\n", 
334                       GET_MEM_ADDR(thedev->config.u.pci_device_config.BAR[i]),
335                       GET_MEM_TYPE(thedev->config.u.pci_device_config.BAR[i]),
336                       GET_MEM_PREFETCHABLE(thedev->config.u.pci_device_config.BAR[i]) ? " prefetchable)" : ")");
337
338         } else {
339             PrintBoth("UNKNOWN)\n");
340         }
341     }
342
343     PrintBoth("      cardbus_cis_ptr:  0x%x\n", (uint_t) thedev->config.u.pci_device_config.cardbus_cis_pointer);
344     PrintBoth("      subsystem_vendor: 0x%x\n", (uint_t) thedev->config.u.pci_device_config.subsystem_vendor_id);
345     PrintBoth("      subsystem_id:     0x%x\n", (uint_t) thedev->config.u.pci_device_config.subsystem_id);
346     PrintBoth("      exp_rom_address:  0x%x\n", (uint_t) thedev->config.u.pci_device_config.expansion_rom_address);
347     PrintBoth("      cap ptr           0x%x\n", (uint_t) thedev->config.u.pci_device_config.cap_ptr);
348
349     for (i = 0; i < 7; i++) { 
350         PrintBoth("      reserved[%d]:      0x%x\n", i, (uint_t) thedev->config.u.pci_device_config.reserved[i]);
351     }
352
353     PrintBoth("      intr_line:        0x%x\n", (uint_t) thedev->config.u.pci_device_config.intr_line);
354     PrintBoth("      intr_pin:         0x%x\n", (uint_t) thedev->config.u.pci_device_config.intr_pin);
355     PrintBoth("      min_grant:        0x%x\n", (uint_t) thedev->config.u.pci_device_config.min_grant);
356     PrintBoth("      max_latency:      0x%x\n", (uint_t) thedev->config.u.pci_device_config.max_latency);
357
358     for (i = 0; i < 48; i++) { 
359         PrintBoth("      device_data[%d]:   0x%x\n", i, (uint_t) thedev->config.u.pci_device_config.device_data[i]);
360     }
361 }
362
363 static void PrintPCIPCIBridge(struct pci_device * thedev) {
364     int i;
365   
366     PrintBoth("     PCI-PCI Bridge:\n");
367
368     PrintPCIShared(thedev);
369
370     for (i = 0; i < 2; i++) { 
371
372         PrintBoth("      BAR[%d]:           0x%x (", i, (uint_t) thedev->config.u.pci_pci_bridge_config.BAR[i]);
373
374         if (IS_IO_ADDR(thedev->config.u.pci_pci_bridge_config.BAR[i])) { 
375
376             PrintBoth("IO Address 0x%x)\n", GET_IO_ADDR(thedev->config.u.pci_pci_bridge_config.BAR[i]));
377
378         } else if (IS_MEM_ADDR(thedev->config.u.pci_pci_bridge_config.BAR[i])) { 
379
380             PrintBoth("Memory Address 0x%x type=0x%x%s\n",
381                       GET_MEM_ADDR(thedev->config.u.pci_pci_bridge_config.BAR[i]),
382                       GET_MEM_TYPE(thedev->config.u.pci_pci_bridge_config.BAR[i]),
383                       GET_MEM_PREFETCHABLE(thedev->config.u.pci_pci_bridge_config.BAR[i]) ? " prefetchable)" : ")");
384
385         } else {
386             PrintBoth("UNKNOWN)\n");
387         }
388     }
389
390     PrintBoth("      primary_bus:      0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.primary_bus);
391     PrintBoth("      secondary_bus:    0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.secondary_bus);
392     PrintBoth("      subordinate_bus:  0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.subordinate_bus);
393     PrintBoth("      second_lat_timer: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.secondary_lat_timer);
394     PrintBoth("      io_base:          0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.io_base);
395     PrintBoth("      io_limit:         0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.io_limit);
396     PrintBoth("      secondary_status: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.secondary_status);
397     PrintBoth("      memory_base:      0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.memory_base);
398     PrintBoth("      memory_limit:     0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.memory_limit);
399     PrintBoth("      prefetch_base:    0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.prefetchable_memory_base);
400     PrintBoth("      prefetch_limit:   0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.prefetchable_memory_limit);
401     PrintBoth("      prefetch_base_up: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.prefetchable_memory_base_upper);
402     PrintBoth("      prefetch_limit_u: 0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.prefetchable_memory_limit_upper);
403     PrintBoth("      memory_limit:     0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.memory_limit);
404     PrintBoth("      memory_limit:     0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.memory_limit);
405     PrintBoth("      io_base_up:       0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.io_base_upper);
406     PrintBoth("      io_limit_up:      0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.io_limit_upper);
407     PrintBoth("      reserved:         0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.reserved);
408     PrintBoth("      exp_rom_address:  0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.expansion_rom_address);
409     PrintBoth("      intr_line:        0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.intr_line);
410     PrintBoth("      intr_pin:         0x%x\n", (uint_t) thedev->config.u.pci_pci_bridge_config.intr_pin);
411
412     for (i = 0; i < 48; i++) { 
413         PrintBoth("      device_data[%d]:   0x%x\n", i, (uint_t) thedev->config.u.pci_pci_bridge_config.device_data[i]);
414     }
415 }
416
417 static void PrintPCICardbusBridge(struct pci_device * thedev) {
418     int i;
419   
420     PrintBoth("     PCI-Cardbus Bridge:\n");
421
422     PrintPCIShared(thedev);
423
424     PrintBoth("      cardbus_base_add: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.cardbus_base_addr);
425     PrintBoth("      cap_ptr:          0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.cap_ptr);
426     PrintBoth("      reserved:         0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.reserved);
427     PrintBoth("      secondary_status  0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.secondary_status);
428     PrintBoth("      pci_bus:          0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.pci_bus);
429     PrintBoth("      cardbus_bus:      0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.cardbus_bus);
430     PrintBoth("      subordinate_bus:  0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.subordinate_bus);
431     PrintBoth("      cardbus_lat_time: 0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.cardbus_lat_timer);
432     PrintBoth("      memory_base0      0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.memory_base0);
433     PrintBoth("      memory_limit0     0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.memory_limit0);
434     PrintBoth("      memory_base1      0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.memory_base1);
435     PrintBoth("      memory_limit1     0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.memory_limit1);
436     PrintBoth("      io_base0          0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_base0);
437     PrintBoth("      io_base0_up       0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_base0_upper);
438     PrintBoth("      io_limit0         0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_limit0);
439     PrintBoth("      io_limit0_up      0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_limit0_upper);
440     PrintBoth("      io_base1          0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_base1);
441     PrintBoth("      io_base1_up       0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_base1_upper);
442     PrintBoth("      io_limit1         0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_limit1);
443     PrintBoth("      io_limit1_up      0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.io_limit1_upper);
444     PrintBoth("      intr_line:        0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.intr_line);
445     PrintBoth("      intr_pin:         0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.intr_pin);
446     PrintBoth("      bridge_ctl:       0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.bridge_ctl);
447     PrintBoth("      subsys_vend_id:   0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.subsystem_vendor_id);
448     PrintBoth("      subsys_dev_id:    0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.subsystem_device_id);
449     PrintBoth("      legacy16_base:    0x%x\n", (uint_t) thedev->config.u.pci_cardbus_bridge_config.legacy_16bit_base_addr);
450     
451     for (i = 0; i < 14; i++) {
452         PrintBoth("      reserved2[%d]:    0x%x\n", 
453                   (uint_t)thedev->config.u.pci_cardbus_bridge_config.reserved2[i]);
454     }
455
456     for (i = 0; i < 48; i++) { 
457         PrintBoth("      device_data[%d]:   0x%x\n", i, 
458                   (uint_t)thedev->config.u.pci_cardbus_bridge_config.device_data[i]);
459     }
460 }
461
462 static void PrintPCIUnknown(struct pci_device * thedev) {
463     PrintBoth("    PCI Unknown Element\n");
464     PrintPCIShared(thedev);
465 }
466
467 static void PrintPCIElement(struct pci_device * thedev)  { 
468     switch (HEADER_TYPE(thedev->config.header_type)) { 
469
470         case PCI_DEVICE:
471             PrintPCIDevice(thedev);
472             break;
473
474         case PCI_PCI_BRIDGE:
475             PrintPCIPCIBridge(thedev);
476             break;
477
478         case PCI_CARDBUS_BRIDGE:
479             PrintPCICardbusBridge(thedev);
480             break;
481
482         default:
483             PrintPCIUnknown(thedev);
484             break;
485     }
486 }
487     
488
489 static void PrintPCIBus(struct pci_bus * thebus) {
490     struct pci_device * thedev;
491
492     PrintBoth("  PCI Bus:\n");
493     PrintBoth("   Number: %u\n",thebus->number);
494
495     thedev = thebus->device_list;
496
497     while (thedev) { 
498         PrintPCIElement(thedev);
499         thedev = thedev->next;
500     }
501 }
502
503 static void PrintPCI(struct pci * thepci) {
504     struct pci_bus * thebus;
505
506     PrintBoth("PCI Configuration:\n");
507     PrintBoth(" Number of Buses: %u\n", thepci->num_buses);
508
509     thebus = thepci->bus_list;
510
511     while (thebus) { 
512         PrintPCIBus(thebus);
513         thebus = thebus->next;
514     }
515
516 }
517
518 int Init_PCI() {
519     PrintPCI(ScanPCI());
520
521     return 0;
522
523 }