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.


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