source: rtems/c/src/lib/libbsp/powerpc/shared/pci/pci.c @ e79a1947

4.104.114.84.95
Last change on this file since e79a1947 was e79a1947, checked in by Joel Sherrill <joel.sherrill@…>, on 11/10/04 at 23:51:17

2004-11-10 Richard Campbell <richard.campbell@…>

  • Makefile.am, bootloader/misc.c, bootloader/pci.c, bootloader/pci.h, console/console.c, console/inch.c, console/reboot.c, console/uart.c, console/uart.h, irq/irq.c, irq/irq.h, irq/irq_init.c, motorola/motorola.c, motorola/motorola.h, openpic/openpic.c, openpic/openpic.h, pci/detect_raven_bridge.c, pci/pci.c, start/start.S, startup/bspstart.c, vectors/vectors_init.c, vme/vmeconfig.c: Add MVME2100 BSP and MPC8240 support. There was also a significant amount of spelling and whitespace cleanup.
  • tod/todcfg.c: New file.
  • Property mode set to 100644
File size: 18.2 KB
RevLine 
[acc25ee]1/*
2 * pci.c :  this file contains basic PCI Io functions.
3 *
[e79a1947]4 *  Copyright (C) 1999 valette@crf.canon.fr
[acc25ee]5 *
[e79a1947]6 *  This code is heavily inspired by the public specification of STREAM V2
[acc25ee]7 *  that can be found at :
8 *
9 *      <http://www.chorus.com/Documentation/index.html> by following
10 *  the STREAM API Specification Document link.
11 *
12 *  The license and distribution terms for this file may be
13 *  found in found in the file LICENSE in this distribution or at
[e831de8]14 *  http://www.rtems.com/license/LICENSE.
[acc25ee]15 *
16 *  $Id$
[69ed59f]17 *
18 *  Till Straumann, <strauman@slac.stanford.edu>, 1/2002
19 *   - separated bridge detection code out of this file
[acc25ee]20 */
21
22#include <libcpu/io.h>
23#include <bsp/pci.h>
[e79a1947]24#include <rtems/bspIo.h>
[acc25ee]25
[69ed59f]26/* allow for overriding these definitions */
27#ifndef PCI_CONFIG_ADDR
[acc25ee]28#define PCI_CONFIG_ADDR                 0xcf8
[69ed59f]29#endif
30#ifndef PCI_CONFIG_DATA
[acc25ee]31#define PCI_CONFIG_DATA                 0xcfc
[69ed59f]32#endif
33
[acc25ee]34#define PCI_INVALID_VENDORDEVICEID      0xffffffff
35#define PCI_MULTI_FUNCTION              0x80
36
[69ed59f]37/* define a shortcut */
38#define pci     BSP_pci_configuration
[acc25ee]39
40/*
41 * Bit encode for PCI_CONFIG_HEADER_TYPE register
42 */
43unsigned char ucMaxPCIBus;
44
45static int
46indirect_pci_read_config_byte(unsigned char bus, unsigned char slot,
[6128a4a]47                              unsigned char function,
[acc25ee]48                              unsigned char offset, unsigned char *val) {
[6128a4a]49        out_be32((unsigned int*) pci.pci_config_addr,
[acc25ee]50                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
51        *val = in_8(pci.pci_config_data + (offset&3));
52        return PCIBIOS_SUCCESSFUL;
53}
54
55static int
56indirect_pci_read_config_word(unsigned char bus, unsigned char slot,
[6128a4a]57                              unsigned char function,
[acc25ee]58                              unsigned char offset, unsigned short *val) {
[6128a4a]59        *val = 0xffff;
[acc25ee]60        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
[6128a4a]61        out_be32((unsigned int*) pci.pci_config_addr,
[acc25ee]62                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
63        *val = in_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)));
64        return PCIBIOS_SUCCESSFUL;
65}
66
67static int
68indirect_pci_read_config_dword(unsigned char bus, unsigned char slot,
[6128a4a]69                              unsigned char function,
[acc25ee]70                              unsigned char offset, unsigned int *val) {
[6128a4a]71        *val = 0xffffffff;
[acc25ee]72        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
[6128a4a]73        out_be32((unsigned int*) pci.pci_config_addr,
[acc25ee]74                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
75        *val = in_le32((volatile unsigned int *)pci.pci_config_data);
76        return PCIBIOS_SUCCESSFUL;
77}
78
79static int
80indirect_pci_write_config_byte(unsigned char bus, unsigned char slot,
[6128a4a]81                               unsigned char function,
[acc25ee]82                               unsigned char offset, unsigned char val) {
[6128a4a]83        out_be32((unsigned int*) pci.pci_config_addr,
[acc25ee]84                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
85        out_8(pci.pci_config_data + (offset&3), val);
86        return PCIBIOS_SUCCESSFUL;
87}
88
89static int
90indirect_pci_write_config_word(unsigned char bus, unsigned char slot,
[6128a4a]91                               unsigned char function,
[acc25ee]92                               unsigned char offset, unsigned short val) {
93        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
[6128a4a]94        out_be32((unsigned int*) pci.pci_config_addr,
[acc25ee]95                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
96        out_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)), val);
97        return PCIBIOS_SUCCESSFUL;
98}
99
100static int
101indirect_pci_write_config_dword(unsigned char bus, unsigned char slot,
[6128a4a]102                                unsigned char function,
[acc25ee]103                                unsigned char offset, unsigned int val) {
104        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
[6128a4a]105        out_be32((unsigned int*) pci.pci_config_addr,
[acc25ee]106                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
107        out_le32((volatile unsigned int *)pci.pci_config_data, val);
108        return PCIBIOS_SUCCESSFUL;
109}
110
[69ed59f]111const pci_config_access_functions pci_indirect_functions = {
[acc25ee]112        indirect_pci_read_config_byte,
113        indirect_pci_read_config_word,
114        indirect_pci_read_config_dword,
115        indirect_pci_write_config_byte,
116        indirect_pci_write_config_word,
117        indirect_pci_write_config_dword
118};
119
[69ed59f]120pci_config BSP_pci_configuration = {(volatile unsigned char*)PCI_CONFIG_ADDR,
[acc25ee]121                         (volatile unsigned char*)PCI_CONFIG_DATA,
[69ed59f]122                         &pci_indirect_functions};
[acc25ee]123
124static int
125direct_pci_read_config_byte(unsigned char bus, unsigned char slot,
[6128a4a]126                            unsigned char function,
[acc25ee]127                            unsigned char offset, unsigned char *val) {
128        if (bus != 0 || (1<<slot & 0xff8007fe)) {
129                *val=0xff;
130                return PCIBIOS_DEVICE_NOT_FOUND;
131        }
[6128a4a]132        *val=in_8(pci.pci_config_data + ((1<<slot)&~1)
[acc25ee]133                  + (function<<8) + offset);
134        return PCIBIOS_SUCCESSFUL;
135}
136
137static int
138direct_pci_read_config_word(unsigned char bus, unsigned char slot,
[6128a4a]139                            unsigned char function,
[acc25ee]140                            unsigned char offset, unsigned short *val) {
[6128a4a]141        *val = 0xffff;
[acc25ee]142        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
143        if (bus != 0 || (1<<slot & 0xff8007fe)) {
144                return PCIBIOS_DEVICE_NOT_FOUND;
145        }
146        *val=in_le16((volatile unsigned short *)
147                     (pci.pci_config_data + ((1<<slot)&~1)
148                      + (function<<8) + offset));
149        return PCIBIOS_SUCCESSFUL;
150}
151
152static int
153direct_pci_read_config_dword(unsigned char bus, unsigned char slot,
[6128a4a]154                             unsigned char function,
[acc25ee]155                             unsigned char offset, unsigned int *val) {
[6128a4a]156        *val = 0xffffffff;
[acc25ee]157        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
158        if (bus != 0 || (1<<slot & 0xff8007fe)) {
159                return PCIBIOS_DEVICE_NOT_FOUND;
160        }
161        *val=in_le32((volatile unsigned int *)
162                     (pci.pci_config_data + ((1<<slot)&~1)
163                      + (function<<8) + offset));
164        return PCIBIOS_SUCCESSFUL;
165}
166
167static int
168direct_pci_write_config_byte(unsigned char bus, unsigned char slot,
[6128a4a]169                             unsigned char function,
[acc25ee]170                             unsigned char offset, unsigned char val) {
171        if (bus != 0 || (1<<slot & 0xff8007fe)) {
172                return PCIBIOS_DEVICE_NOT_FOUND;
173        }
[6128a4a]174        out_8(pci.pci_config_data + ((1<<slot)&~1)
175              + (function<<8) + offset,
[acc25ee]176              val);
177        return PCIBIOS_SUCCESSFUL;
178}
179
180static int
181direct_pci_write_config_word(unsigned char bus, unsigned char slot,
[6128a4a]182                             unsigned char function,
[acc25ee]183                             unsigned char offset, unsigned short val) {
184        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
185        if (bus != 0 || (1<<slot & 0xff8007fe)) {
186                return PCIBIOS_DEVICE_NOT_FOUND;
187        }
188        out_le16((volatile unsigned short *)
189                 (pci.pci_config_data + ((1<<slot)&~1)
190                  + (function<<8) + offset),
191                 val);
192        return PCIBIOS_SUCCESSFUL;
193}
194
195static int
196direct_pci_write_config_dword(unsigned char bus, unsigned char slot,
[6128a4a]197                              unsigned char function,
[acc25ee]198                              unsigned char offset, unsigned int val) {
199        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
200        if (bus != 0 || (1<<slot & 0xff8007fe)) {
201                return PCIBIOS_DEVICE_NOT_FOUND;
202        }
203        out_le32((volatile unsigned int *)
204                 (pci.pci_config_data + ((1<<slot)&~1)
205                  + (function<<8) + offset),
206                 val);
207        return PCIBIOS_SUCCESSFUL;
208}
209
[69ed59f]210const pci_config_access_functions pci_direct_functions = {
[acc25ee]211        direct_pci_read_config_byte,
212        direct_pci_read_config_word,
213        direct_pci_read_config_dword,
214        direct_pci_write_config_byte,
215        direct_pci_write_config_word,
216        direct_pci_write_config_dword
217};
218
[3a3e0b0e]219#define PRINT_MSG() \
220             printk("pci : Device %d:%02x routed to interrupt_line %d\n", pbus, pslot, int_name )
221
[6128a4a]222/*
[3a3e0b0e]223** Validate a test interrupt name and print a warning if its not one of
224** the names defined in the routing record.
225*/
[da3b8d3]226static int test_intname(
[e79a1947]227  const struct _int_map *row,
228  int pbus,
229  int pslot,
230  int int_pin,
231  int int_name
232)
[3a3e0b0e]233{
[e79a1947]234   int j, k;
[3a3e0b0e]235   int _nopin= -1, _noname= -1;
236
237   for(j=0; row->pin_route[j].pin > -1; j++)
238   {
[6128a4a]239      if( row->pin_route[j].pin == int_pin )
[3a3e0b0e]240      {
241         _nopin = 0;
[6128a4a]242
[3a3e0b0e]243         for(k=0; k<4 && row->pin_route[j].int_name[k] > -1; k++ )
244         {
[6128a4a]245            if( row->pin_route[j].int_name[k] == int_name ){ _noname=0; break; }
[3a3e0b0e]246         }
247         break;
248      }
249   }
250
[6128a4a]251   if( _nopin  )
[3a3e0b0e]252   {
253      printk("pci : Device %d:%02x supplied a bogus interrupt_pin %d\n", pbus, pslot, int_pin );
254      return -1;
255   }
256   else
257   {
258      if( _noname )
259         printk("pci : Device %d:%02x supplied a suspicious interrupt_line %d, using it anyway\n", pbus, pslot, int_name );
260   }
261   return 0;
262}
263
264struct pcibridge
265{
266      int bus,slot;
267};
268
269static int FindPCIbridge( int mybus, struct pcibridge *pb )
270{
271   int          pbus, pslot;
[bde7f268]272   uint8_t      bussec, buspri;
273   uint16_t     devid, vendorid, dclass;
[3a3e0b0e]274
275   for(pbus=0; pbus< BusCountPCI(); pbus++)
276   {
277      for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++)
[6128a4a]278      {
[3a3e0b0e]279         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
280         if( devid == 0xffff ) continue;
281
282         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &vendorid);
283         if( vendorid == 0xffff ) continue;
284
285         pci_read_config_word(pbus, pslot, 0, PCI_CLASS_DEVICE, &dclass);
286
[6128a4a]287         if( dclass == PCI_CLASS_BRIDGE_PCI )
[3a3e0b0e]288         {
289            pci_read_config_byte(pbus, pslot, 0, PCI_PRIMARY_BUS,    &buspri);
290            pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS,  &bussec);
291
292#if 0
293            printk("pci : Found bridge at %d:%d, mybus %d, pribus %d, secbus %d  ", pbus, pslot, mybus, buspri, bussec );
294#endif
295            if( bussec == mybus )
296            {
297#if 0
298               printk("match\n");
299#endif
300               /* found our nearest bridge going towards the root */
301               pb->bus = pbus;
302               pb->slot = pslot;
303
304               return 0;
305            }
306#if 0
307            printk("no match\n");
308#endif
309         }
310
311      }
312   }
313   return -1;
314}
315
[da3b8d3]316void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) )
[3a3e0b0e]317{
318   unsigned char        cvalue;
[bde7f268]319   uint16_t             devid;
[3a3e0b0e]320   int                  ismatch, i, j, pbus, pslot, int_pin, int_name;
321
322   /*
323   ** If the device has a non-zero INTERRUPT_PIN, assign a bsp-specific
324   ** INTERRUPT_NAME if one isn't already in place.  Then, drivers can
325   ** trivially use INTERRUPT_NAME to hook up with devices.
326   */
327
328   for(pbus=0; pbus< BusCountPCI(); pbus++)
329   {
330      for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++)
[6128a4a]331      {
[3a3e0b0e]332         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
333         if( devid == 0xffff ) continue;
334
335         /* got a device */
336
337         pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_PIN, &cvalue);
338         int_pin = cvalue;
339
340         pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_LINE, &cvalue);
341         int_name = cvalue;
342
343/* printk("pci : device %d:%02x devid %04x, intpin %d, intline  %d\n", pbus, pslot, devid, int_pin, int_name ); */
344
[513b6c4b]345#if 0
346         {
347            unsigned short cmd,stat;
348            unsigned char  lat, seclat, csize;
349
350            pci_read_config_word(pbus,pslot,0,PCI_COMMAND, &cmd );
351            pci_read_config_word(pbus,pslot,0,PCI_STATUS, &stat );
352            pci_read_config_byte(pbus,pslot,0,PCI_LATENCY_TIMER, &lat );
353            pci_read_config_byte(pbus,pslot,0,PCI_SEC_LATENCY_TIMER, &seclat );
354            pci_read_config_byte(pbus,pslot,0,PCI_CACHE_LINE_SIZE, &csize );
355           
356
357            printk("pci : device %d:%02x  cmd %04X, stat %04X, latency %d, sec_latency %d, clsize %d\n", pbus, pslot,
358                   cmd,
359                   stat,
360                   lat,
361                   seclat,
362                   csize);
363         }
364#endif
365
[3a3e0b0e]366         if( int_pin > 0 )
367         {
368            ismatch = 0;
369
370            /*
371            ** first run thru the bspmap table and see if we have an explicit configuration
372            */
373            for(i=0; bspmap[i].bus > -1; i++)
374            {
375               if( bspmap[i].bus == pbus && bspmap[i].slot == pslot )
376               {
377                  ismatch = -1;
378                  /* we have a record in the table that gives specific
379                   * pins and interrupts for devices in this slot */
380                  if( int_name == 255 )
381                  {
382                     /* find the vector associated with whatever pin the device gives us */
383                     for( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ )
384                     {
385                        if( bspmap[i].pin_route[j].pin == int_pin )
386                        {
387                           int_name = bspmap[i].pin_route[j].int_name[0];
388                           break;
389                        }
390                     }
391                     if( int_name == -1 )
392                     {
[513b6c4b]393                        printk("pci : Unable to resolve device %d:%d w/ swizzled int pin %i to an interrupt_line.\n", pbus, pslot, int_pin );
[3a3e0b0e]394                     }
395                     else
396                     {
397                        PRINT_MSG();
398                        pci_write_config_byte(pbus,pslot,0,PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
399                     }
400                  }
401                  else
402                  {
403                     test_intname( &bspmap[i],pbus,pslot,int_pin,int_name);
404                  }
405                  break;
406               }
407            }
408
409            if( !ismatch )
410            {
[6128a4a]411               /*
[3a3e0b0e]412               ** no match, which means we're on a bus someplace.  Work
413               ** backwards from it to one of our defined busses,
[6128a4a]414               ** swizzling thru each bridge on the way.
[3a3e0b0e]415               */
416
417               /* keep pbus, pslot pointed to the device being
418               configured while we track down the bridges using
419               tbus,tslot.  We keep searching the routing table because
420               we may end up finding our bridge in it */
421
422               int tbus= pbus, tslot= pslot;
423
424               for(;;)
425               {
426
427                  for(i=0; bspmap[i].bus > -1; i++)
428                  {
429                     if( bspmap[i].bus == tbus && (bspmap[i].slot == tslot || bspmap[i].slot == -1) )
430                     {
431                        ismatch = -1;
432                        /* found a record for this bus, so swizzle the
433                         * int_pin which we then use to find the
434                         * interrupt_name.
435                         */
436
437                        if( int_name == 255 )
438                        {
439                           /*
440                           ** FIXME.  I can't believe this little hack
441                           ** is right.  It does not yield an error in
442                           ** convienently simple situations.
443                           */
444                           if( tbus ) int_pin = (*swizzler)(tslot,int_pin);
445
446                           /*
447                           ** int_pin points to the interrupt channel
448                           ** this card ends up delivering interrupts
449                           ** on.  Find the int_name servicing it.
450                           */
451                           for( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ )
452                           {
453                              if( bspmap[i].pin_route[j].pin == int_pin )
454                              {
455                                 int_name = bspmap[i].pin_route[j].int_name[0];
456                                 break;
457                              }
458                           }
459                           if( int_name == -1 )
460                           {
[513b6c4b]461                              printk("pci : Unable to resolve device %d:%d w/ swizzled int pin %i to an interrupt_line.\n", pbus, pslot, int_pin );
[3a3e0b0e]462                           }
463                           else
464                           {
465                              PRINT_MSG();
466                              pci_write_config_byte(pbus,pslot,0,PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
467                           }
468                        }
469                        else
470                        {
471                           test_intname(&bspmap[i],pbus,pslot,int_pin,int_name);
472                        }
473                        goto donesearch;
474                     }
475                  }
476
477                  if( !ismatch )
478                  {
479                     struct pcibridge   pb;
480
[6128a4a]481                     /*
[3a3e0b0e]482                     ** Haven't found our bus in the int map, so work
483                     ** upwards thru the bridges till we find it.
484                     */
485
486                     if( FindPCIbridge( tbus, &pb )== 0 )
487                     {
488                        int_pin = (*swizzler)(tslot,int_pin);
489
490                        /* our next bridge up is on pb.bus, pb.slot- now
491                        ** instead of pointing to the device we're
492                        ** trying to configure, we move from bridge to
493                        ** bridge.
494                        */
495
496                        tbus = pb.bus;
497                        tslot = pb.slot;
498                     }
499                     else
500                     {
[513b6c4b]501                        printk("pci : No bridge from bus %i towards root found\n", tbus );
[3a3e0b0e]502                        goto donesearch;
503                     }
[6128a4a]504
[3a3e0b0e]505                  }
506
507               }
508            }
509           donesearch:
510
511            if( !ismatch && int_pin != 0 && int_name == 255 )
512            {
513               printk("pci : Unable to match device %d:%d with an int routing table entry\n", pbus, pslot  );
514            }
515
516         }
517      }
518   }
519}
520
[acc25ee]521/*
522 * This routine determines the maximum bus number in the system
523 */
524void InitializePCI()
525{
[69ed59f]526  extern void detect_host_bridge();
[acc25ee]527  unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
528  unsigned char ucHeader;
529  unsigned char ucMaxSubordinate;
530  unsigned int  ulClass, ulDeviceID;
531
532  detect_host_bridge();
[3a3e0b0e]533
[acc25ee]534  /*
535   * Scan PCI bus 0 looking for PCI-PCI bridges
536   */
537  for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
538    (void)pci_read_config_dword(0,
539                                ucSlotNumber,
540                                0,
541                                PCI_VENDOR_ID,
542                                &ulDeviceID);
543    if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
544      /*
545       * This slot is empty
546       */
547      continue;
548    }
549    (void)pci_read_config_byte(0,
550                               ucSlotNumber,
551                               0,
552                               PCI_HEADER_TYPE,
553                               &ucHeader);
554    if(ucHeader&PCI_MULTI_FUNCTION)     {
555      ucNumFuncs=PCI_MAX_FUNCTIONS;
556    }
557    else {
558      ucNumFuncs=1;
559    }
560    for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
561      (void)pci_read_config_dword(0,
562                                  ucSlotNumber,
563                                  ucFnNumber,
564                                  PCI_VENDOR_ID,
565                                  &ulDeviceID);
566      if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
567                                /*
568                                 * This slot/function is empty
569                                 */
570        continue;
571      }
572
573      /*
574       * This slot/function has a device fitted.
575       */
576      (void)pci_read_config_dword(0,
577                                  ucSlotNumber,
578                                  ucFnNumber,
579                                  PCI_CLASS_REVISION,
580                                  &ulClass);
581      ulClass >>= 16;
582      if (ulClass == PCI_CLASS_BRIDGE_PCI) {
583                                /*
584                                 * We have found a PCI-PCI bridge
585                                 */
586        (void)pci_read_config_byte(0,
587                                   ucSlotNumber,
588                                   ucFnNumber,
589                                   PCI_SUBORDINATE_BUS,
590                                   &ucMaxSubordinate);
591        if(ucMaxSubordinate>ucMaxPCIBus) {
592          ucMaxPCIBus=ucMaxSubordinate;
593        }
594      }
595    }
596  }
597}
598
599/*
600 * Return the number of PCI busses in the system
601 */
602unsigned char BusCountPCI()
603{
604  return(ucMaxPCIBus+1);
605}
Note: See TracBrowser for help on using the repository browser.