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.


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