<!-- Copyright (C) 2003 Red Hat, Inc. -->
|
<!-- Copyright (C) 2003 Red Hat, Inc. -->
|
<!-- This material may be distributed only subject to the terms -->
|
<!-- This material may be distributed only subject to the terms -->
|
<!-- and conditions set forth in the Open Publication License, v1.0 -->
|
<!-- and conditions set forth in the Open Publication License, v1.0 -->
|
<!-- or later (the latest version is presently available at -->
|
<!-- or later (the latest version is presently available at -->
|
<!-- http://www.opencontent.org/openpub/). -->
|
<!-- http://www.opencontent.org/openpub/). -->
|
<!-- Distribution of the work or derivative of the work in any -->
|
<!-- Distribution of the work or derivative of the work in any -->
|
<!-- standard (paper) book form is prohibited unless prior -->
|
<!-- standard (paper) book form is prohibited unless prior -->
|
<!-- permission is obtained from the copyright holder. -->
|
<!-- permission is obtained from the copyright holder. -->
|
<HTML
|
<HTML
|
><HEAD
|
><HEAD
|
><TITLE
|
><TITLE
|
>The eCos PCI Library</TITLE
|
>The eCos PCI Library</TITLE
|
><meta name="MSSmartTagsPreventParsing" content="TRUE">
|
><meta name="MSSmartTagsPreventParsing" content="TRUE">
|
<META
|
<META
|
NAME="GENERATOR"
|
NAME="GENERATOR"
|
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
"><LINK
|
"><LINK
|
REL="HOME"
|
REL="HOME"
|
TITLE="eCos Reference Manual"
|
TITLE="eCos Reference Manual"
|
HREF="ecos-ref.html"><LINK
|
HREF="ecos-ref.html"><LINK
|
REL="UP"
|
REL="UP"
|
TITLE="PCI Library"
|
TITLE="PCI Library"
|
HREF="io-pci.html"><LINK
|
HREF="io-pci.html"><LINK
|
REL="PREVIOUS"
|
REL="PREVIOUS"
|
TITLE="PCI Library"
|
TITLE="PCI Library"
|
HREF="io-pci.html"><LINK
|
HREF="io-pci.html"><LINK
|
REL="NEXT"
|
REL="NEXT"
|
TITLE="PCI Library reference"
|
TITLE="PCI Library reference"
|
HREF="pci-library-reference.html"></HEAD
|
HREF="pci-library-reference.html"></HEAD
|
><BODY
|
><BODY
|
CLASS="CHAPTER"
|
CLASS="CHAPTER"
|
BGCOLOR="#FFFFFF"
|
BGCOLOR="#FFFFFF"
|
TEXT="#000000"
|
TEXT="#000000"
|
LINK="#0000FF"
|
LINK="#0000FF"
|
VLINK="#840084"
|
VLINK="#840084"
|
ALINK="#0000FF"
|
ALINK="#0000FF"
|
><DIV
|
><DIV
|
CLASS="NAVHEADER"
|
CLASS="NAVHEADER"
|
><TABLE
|
><TABLE
|
SUMMARY="Header navigation table"
|
SUMMARY="Header navigation table"
|
WIDTH="100%"
|
WIDTH="100%"
|
BORDER="0"
|
BORDER="0"
|
CELLPADDING="0"
|
CELLPADDING="0"
|
CELLSPACING="0"
|
CELLSPACING="0"
|
><TR
|
><TR
|
><TH
|
><TH
|
COLSPAN="3"
|
COLSPAN="3"
|
ALIGN="center"
|
ALIGN="center"
|
>eCos Reference Manual</TH
|
>eCos Reference Manual</TH
|
></TR
|
></TR
|
><TR
|
><TR
|
><TD
|
><TD
|
WIDTH="10%"
|
WIDTH="10%"
|
ALIGN="left"
|
ALIGN="left"
|
VALIGN="bottom"
|
VALIGN="bottom"
|
><A
|
><A
|
HREF="io-pci.html"
|
HREF="io-pci.html"
|
ACCESSKEY="P"
|
ACCESSKEY="P"
|
>Prev</A
|
>Prev</A
|
></TD
|
></TD
|
><TD
|
><TD
|
WIDTH="80%"
|
WIDTH="80%"
|
ALIGN="center"
|
ALIGN="center"
|
VALIGN="bottom"
|
VALIGN="bottom"
|
></TD
|
></TD
|
><TD
|
><TD
|
WIDTH="10%"
|
WIDTH="10%"
|
ALIGN="right"
|
ALIGN="right"
|
VALIGN="bottom"
|
VALIGN="bottom"
|
><A
|
><A
|
HREF="pci-library-reference.html"
|
HREF="pci-library-reference.html"
|
ACCESSKEY="N"
|
ACCESSKEY="N"
|
>Next</A
|
>Next</A
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><HR
|
><HR
|
ALIGN="LEFT"
|
ALIGN="LEFT"
|
WIDTH="100%"></DIV
|
WIDTH="100%"></DIV
|
><DIV
|
><DIV
|
CLASS="CHAPTER"
|
CLASS="CHAPTER"
|
><H1
|
><H1
|
><A
|
><A
|
NAME="ECOS-PCI-LIBRARY">Chapter 30. The eCos PCI Library</H1
|
NAME="ECOS-PCI-LIBRARY">Chapter 30. The eCos PCI Library</H1
|
><DIV
|
><DIV
|
CLASS="TOC"
|
CLASS="TOC"
|
><DL
|
><DL
|
><DT
|
><DT
|
><B
|
><B
|
>Table of Contents</B
|
>Table of Contents</B
|
></DT
|
></DT
|
><DT
|
><DT
|
><A
|
><A
|
HREF="ecos-pci-library.html#PCI-LIBRARY"
|
HREF="ecos-pci-library.html#PCI-LIBRARY"
|
>PCI Library</A
|
>PCI Library</A
|
></DT
|
></DT
|
><DT
|
><DT
|
><A
|
><A
|
HREF="pci-library-reference.html"
|
HREF="pci-library-reference.html"
|
>PCI Library reference</A
|
>PCI Library reference</A
|
></DT
|
></DT
|
></DL
|
></DL
|
></DIV
|
></DIV
|
><P
|
><P
|
>The PCI library is an optional part of eCos, and is only
|
>The PCI library is an optional part of eCos, and is only
|
applicable to some platforms.</P
|
applicable to some platforms.</P
|
><DIV
|
><DIV
|
CLASS="SECT1"
|
CLASS="SECT1"
|
><H1
|
><H1
|
CLASS="SECT1"
|
CLASS="SECT1"
|
><A
|
><A
|
NAME="PCI-LIBRARY">PCI Library</H1
|
NAME="PCI-LIBRARY">PCI Library</H1
|
><P
|
><P
|
>The eCos PCI library provides the following functionality:</P
|
>The eCos PCI library provides the following functionality:</P
|
><P
|
><P
|
></P
|
></P
|
><OL
|
><OL
|
TYPE="1"
|
TYPE="1"
|
><LI
|
><LI
|
><P
|
><P
|
>Scan the PCI bus for specific devices or devices of a certain
|
>Scan the PCI bus for specific devices or devices of a certain
|
class.</P
|
class.</P
|
></LI
|
></LI
|
><LI
|
><LI
|
><P
|
><P
|
>Read and change generic PCI information.</P
|
>Read and change generic PCI information.</P
|
></LI
|
></LI
|
><LI
|
><LI
|
><P
|
><P
|
>Read and change device-specific PCI information.</P
|
>Read and change device-specific PCI information.</P
|
></LI
|
></LI
|
><LI
|
><LI
|
><P
|
><P
|
>Allocate PCI memory and IO space to devices.</P
|
>Allocate PCI memory and IO space to devices.</P
|
></LI
|
></LI
|
><LI
|
><LI
|
><P
|
><P
|
>Translate a device's PCI interrupts to equivalent HAL
|
>Translate a device's PCI interrupts to equivalent HAL
|
vectors.</P
|
vectors.</P
|
></LI
|
></LI
|
></OL
|
></OL
|
><P
|
><P
|
>Example code fragments are from the pci1 test (see <TT
|
>Example code fragments are from the pci1 test (see <TT
|
CLASS="FILENAME"
|
CLASS="FILENAME"
|
>io/pci/<release>/tests/pci1.c</TT
|
>io/pci/<release>/tests/pci1.c</TT
|
>).</P
|
>).</P
|
><P
|
><P
|
>All of the functions described below are declared in the header
|
>All of the functions described below are declared in the header
|
file <TT
|
file <TT
|
CLASS="FILENAME"
|
CLASS="FILENAME"
|
><cyg/io/pci.h></TT
|
><cyg/io/pci.h></TT
|
> which all
|
> which all
|
clients of the PCI library should include.</P
|
clients of the PCI library should include.</P
|
><DIV
|
><DIV
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><H2
|
><H2
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><A
|
><A
|
NAME="AEN12691">PCI Overview</H2
|
NAME="AEN12691">PCI Overview</H2
|
><P
|
><P
|
>The PCI bus supports several address spaces: memory, IO, and configuration. All PCI
|
>The PCI bus supports several address spaces: memory, IO, and configuration. All PCI
|
devices must support mandatory configuration space registers. Some devices may also present
|
devices must support mandatory configuration space registers. Some devices may also present
|
IO mapped and/or memory mapped resources. Before devices on the bus can be used, they must
|
IO mapped and/or memory mapped resources. Before devices on the bus can be used, they must
|
be configured. Basically, configuration will assign PCI IO and/or memory address ranges to
|
be configured. Basically, configuration will assign PCI IO and/or memory address ranges to
|
each device and then enable that device. All PCI devices have a unique address in
|
each device and then enable that device. All PCI devices have a unique address in
|
configuration space. This address is comprised of a bus number, a device number, and a
|
configuration space. This address is comprised of a bus number, a device number, and a
|
function number. Special devices called bridges are used to connect two PCI busses together.
|
function number. Special devices called bridges are used to connect two PCI busses together.
|
The PCI standard supports up to 255 busses with each bus having up to 32 devices and each
|
The PCI standard supports up to 255 busses with each bus having up to 32 devices and each
|
device having up to 8 functions.</P
|
device having up to 8 functions.</P
|
><P
|
><P
|
>The environment in which a platform operates will dictate if and how eCos should
|
>The environment in which a platform operates will dictate if and how eCos should
|
configure devices on the PCI bus. If the platform acts as a host on a single PCI bus,
|
configure devices on the PCI bus. If the platform acts as a host on a single PCI bus,
|
then devices may be configured individually from the relevant device driver. If the
|
then devices may be configured individually from the relevant device driver. If the
|
platform is not the primary host, such as a PCI card plugged into a PC, configuration
|
platform is not the primary host, such as a PCI card plugged into a PC, configuration
|
of PCI devices may be left to the PC BIOS. If PCI-PCI bridges are involved, configuration
|
of PCI devices may be left to the PC BIOS. If PCI-PCI bridges are involved, configuration
|
of all devices is best done all at once early in the boot process. This is because all
|
of all devices is best done all at once early in the boot process. This is because all
|
devices on the secondary side of a bridge must be evaluated for their IO and memory space
|
devices on the secondary side of a bridge must be evaluated for their IO and memory space
|
requirements before the bridge can be configured.</P
|
requirements before the bridge can be configured.</P
|
></DIV
|
></DIV
|
><DIV
|
><DIV
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><H2
|
><H2
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><A
|
><A
|
NAME="AEN12695">Initializing the bus</H2
|
NAME="AEN12695">Initializing the bus</H2
|
><P
|
><P
|
>The PCI bus needs to be initialized before it can be used.
|
>The PCI bus needs to be initialized before it can be used.
|
This only needs to be done once - some HALs may do it as part of
|
This only needs to be done once - some HALs may do it as part of
|
the platform initialization procedure, other HALs may leave it to
|
the platform initialization procedure, other HALs may leave it to
|
the application or device drivers to do it. The following function
|
the application or device drivers to do it. The following function
|
will do the initialization only once, so it's safe to call from
|
will do the initialization only once, so it's safe to call from
|
multiple drivers:</P
|
multiple drivers:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>void cyg_pci_init( void );</PRE
|
>void cyg_pci_init( void );</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
></DIV
|
></DIV
|
><DIV
|
><DIV
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><H2
|
><H2
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><A
|
><A
|
NAME="AEN12699">Scanning for devices</H2
|
NAME="AEN12699">Scanning for devices</H2
|
><P
|
><P
|
>After the bus has been initialized, it is possible to scan
|
>After the bus has been initialized, it is possible to scan
|
it for devices. This is done using the function:</P
|
it for devices. This is done using the function:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>cyg_bool cyg_pci_find_next( cyg_pci_device_id cur_devid,
|
>cyg_bool cyg_pci_find_next( cyg_pci_device_id cur_devid,
|
cyg_pci_device_id *next_devid );</PRE
|
cyg_pci_device_id *next_devid );</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>It will scan the bus for devices starting at <TT
|
>It will scan the bus for devices starting at <TT
|
CLASS="PARAMETER"
|
CLASS="PARAMETER"
|
><I
|
><I
|
>cur_devid</I
|
>cur_devid</I
|
></TT
|
></TT
|
>. If a device is found, its devid is stored in <TT
|
>. If a device is found, its devid is stored in <TT
|
CLASS="PARAMETER"
|
CLASS="PARAMETER"
|
><I
|
><I
|
>next_devid</I
|
>next_devid</I
|
></TT
|
></TT
|
> and the function returns <TT
|
> and the function returns <TT
|
CLASS="CONSTANT"
|
CLASS="CONSTANT"
|
>true</TT
|
>true</TT
|
>.</P
|
>.</P
|
><P
|
><P
|
>The <TT
|
>The <TT
|
CLASS="FILENAME"
|
CLASS="FILENAME"
|
>pci1</TT
|
>pci1</TT
|
> test's outer loop looks like:</P
|
> test's outer loop looks like:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
> cyg_pci_init();
|
> cyg_pci_init();
|
if (cyg_pci_find_next(CYG_PCI_NULL_DEVID, &devid)) {
|
if (cyg_pci_find_next(CYG_PCI_NULL_DEVID, &devid)) {
|
do {
|
do {
|
<use devid>
|
<use devid>
|
} while (cyg_pci_find_next(devid, &devid));
|
} while (cyg_pci_find_next(devid, &devid));
|
}</PRE
|
}</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>What happens is that the bus gets initialized and a scan is
|
>What happens is that the bus gets initialized and a scan is
|
started. <TT
|
started. <TT
|
CLASS="LITERAL"
|
CLASS="LITERAL"
|
>CYG_PCI_NULL_DEVID</TT
|
>CYG_PCI_NULL_DEVID</TT
|
> causes <TT
|
> causes <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_pci_find_next()</TT
|
>cyg_pci_find_next()</TT
|
> to restart its scan. If the bus does not
|
> to restart its scan. If the bus does not
|
contain any devices, the first call to <TT
|
contain any devices, the first call to <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_pci_find_next()</TT
|
>cyg_pci_find_next()</TT
|
>
|
>
|
will return <TT
|
will return <TT
|
CLASS="CONSTANT"
|
CLASS="CONSTANT"
|
>false</TT
|
>false</TT
|
>.</P
|
>.</P
|
><P
|
><P
|
>If the call returns <TT
|
>If the call returns <TT
|
CLASS="CONSTANT"
|
CLASS="CONSTANT"
|
>true</TT
|
>true</TT
|
>, a loop is entered where
|
>, a loop is entered where
|
the found devid is used. After devid processing has completed, the next device
|
the found devid is used. After devid processing has completed, the next device
|
on the bus is searched for; <TT
|
on the bus is searched for; <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_pci_find_next()</TT
|
>cyg_pci_find_next()</TT
|
>
|
>
|
continues its scan from the current devid. The loop terminates when
|
continues its scan from the current devid. The loop terminates when
|
no more devices are found on the bus.</P
|
no more devices are found on the bus.</P
|
><P
|
><P
|
>This is the generic way of scanning the bus, enumerating all
|
>This is the generic way of scanning the bus, enumerating all
|
the devices on the bus. But if the application is looking for a
|
the devices on the bus. But if the application is looking for a
|
device of a given device class (e.g., a SCSI controller), or a specific
|
device of a given device class (e.g., a SCSI controller), or a specific
|
vendor device, these functions simplify the task a bit:</P
|
vendor device, these functions simplify the task a bit:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>cyg_bool cyg_pci_find_class( cyg_uint32 dev_class,
|
>cyg_bool cyg_pci_find_class( cyg_uint32 dev_class,
|
cyg_pci_device_id *devid );
|
cyg_pci_device_id *devid );
|
cyg_bool cyg_pci_find_device( cyg_uint16 vendor, cyg_uint16 device,
|
cyg_bool cyg_pci_find_device( cyg_uint16 vendor, cyg_uint16 device,
|
cyg_pci_device_id *devid );</PRE
|
cyg_pci_device_id *devid );</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>They work just like <TT
|
>They work just like <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_pci_find_next()</TT
|
>cyg_pci_find_next()</TT
|
>,
|
>,
|
but only return true when the dev_class or vendor/device
|
but only return true when the dev_class or vendor/device
|
qualifiers match those of a device on the bus. The devid serves
|
qualifiers match those of a device on the bus. The devid serves
|
as both an input and an output operand: the scan starts at the given
|
as both an input and an output operand: the scan starts at the given
|
device, and if a device is found devid is updated with the value
|
device, and if a device is found devid is updated with the value
|
for the found device.</P
|
for the found device.</P
|
><P
|
><P
|
>The <TT
|
>The <TT
|
CLASS="FILENAME"
|
CLASS="FILENAME"
|
><cyg/io/pci_cfg.h></TT
|
><cyg/io/pci_cfg.h></TT
|
> header
|
> header
|
file (included by <TT
|
file (included by <TT
|
CLASS="FILENAME"
|
CLASS="FILENAME"
|
>pci.h</TT
|
>pci.h</TT
|
>) contains definitions for PCI
|
>) contains definitions for PCI
|
class, vendor and device codes which can be used as arguments to the find
|
class, vendor and device codes which can be used as arguments to the find
|
functions.
|
functions.
|
The list of vendor and device codes is not complete: add new codes
|
The list of vendor and device codes is not complete: add new codes
|
as necessary. If possible also register the codes at the PCI Code
|
as necessary. If possible also register the codes at the PCI Code
|
List (<A
|
List (<A
|
HREF="http://www.yourvote.com/pci"
|
HREF="http://www.yourvote.com/pci"
|
TARGET="_top"
|
TARGET="_top"
|
>http://www.yourvote.com/pci)</A
|
>http://www.yourvote.com/pci)</A
|
> which is where the eCos definitions are generated from.</P
|
> which is where the eCos definitions are generated from.</P
|
></DIV
|
></DIV
|
><DIV
|
><DIV
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><H2
|
><H2
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><A
|
><A
|
NAME="AEN12726">Generic config information</H2
|
NAME="AEN12726">Generic config information</H2
|
><P
|
><P
|
>When a valid device ID (devid) is found using one of the above
|
>When a valid device ID (devid) is found using one of the above
|
functions, the associated device can be queried and controlled using
|
functions, the associated device can be queried and controlled using
|
the functions:</P
|
the functions:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>void cyg_pci_get_device_info ( cyg_pci_device_id devid,
|
>void cyg_pci_get_device_info ( cyg_pci_device_id devid,
|
cyg_pci_device *dev_info );
|
cyg_pci_device *dev_info );
|
void cyg_pci_set_device_info ( cyg_pci_device_id devid,
|
void cyg_pci_set_device_info ( cyg_pci_device_id devid,
|
cyg_pci_device *dev_info );</PRE
|
cyg_pci_device *dev_info );</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>The <SPAN
|
>The <SPAN
|
CLASS="STRUCTNAME"
|
CLASS="STRUCTNAME"
|
>cyg_pci_device structure</SPAN
|
>cyg_pci_device structure</SPAN
|
> (defined in
|
> (defined in
|
<TT
|
<TT
|
CLASS="FILENAME"
|
CLASS="FILENAME"
|
>pci.h</TT
|
>pci.h</TT
|
>) primarily holds information as described by the PCI
|
>) primarily holds information as described by the PCI
|
specification <A
|
specification <A
|
HREF="ecos-pci-library.html#PCI-SPEC"
|
HREF="ecos-pci-library.html#PCI-SPEC"
|
>[1]</A
|
>[1]</A
|
>.
|
>.
|
The <TT
|
The <TT
|
CLASS="FILENAME"
|
CLASS="FILENAME"
|
>pci1</TT
|
>pci1</TT
|
> test prints out some of this information:</P
|
> test prints out some of this information:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
> // Get device info
|
> // Get device info
|
cyg_pci_get_device_info(devid, &dev_info);
|
cyg_pci_get_device_info(devid, &dev_info);
|
diag_printf("\n Command 0x%04x, Status 0x%04x\n",
|
diag_printf("\n Command 0x%04x, Status 0x%04x\n",
|
dev_info.command, dev_info.status);</PRE
|
dev_info.command, dev_info.status);</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>The command register can also be written to, controlling (among
|
>The command register can also be written to, controlling (among
|
other things) whether the device responds to IO and memory access
|
other things) whether the device responds to IO and memory access
|
from the bus. </P
|
from the bus. </P
|
></DIV
|
></DIV
|
><DIV
|
><DIV
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><H2
|
><H2
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><A
|
><A
|
NAME="AEN12737">Specific config information</H2
|
NAME="AEN12737">Specific config information</H2
|
><P
|
><P
|
>The above functions only allow access to generic PCI config
|
>The above functions only allow access to generic PCI config
|
registers. A device can have extra config registers not specified
|
registers. A device can have extra config registers not specified
|
by the PCI specification. These can be accessed with these functions:</P
|
by the PCI specification. These can be accessed with these functions:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>void cyg_pci_read_config_uint8( cyg_pci_device_id devid,
|
>void cyg_pci_read_config_uint8( cyg_pci_device_id devid,
|
cyg_uint8 offset, cyg_uint8 *val);
|
cyg_uint8 offset, cyg_uint8 *val);
|
void cyg_pci_read_config_uint16( cyg_pci_device_id devid,
|
void cyg_pci_read_config_uint16( cyg_pci_device_id devid,
|
cyg_uint8 offset, cyg_uint16 *val);
|
cyg_uint8 offset, cyg_uint16 *val);
|
void cyg_pci_read_config_uint32( cyg_pci_device_id devid,
|
void cyg_pci_read_config_uint32( cyg_pci_device_id devid,
|
cyg_uint8 offset, cyg_uint32 *val);
|
cyg_uint8 offset, cyg_uint32 *val);
|
void cyg_pci_write_config_uint8( cyg_pci_device_id devid,
|
void cyg_pci_write_config_uint8( cyg_pci_device_id devid,
|
cyg_uint8 offset, cyg_uint8 val);
|
cyg_uint8 offset, cyg_uint8 val);
|
void cyg_pci_write_config_uint16( cyg_pci_device_id devid,
|
void cyg_pci_write_config_uint16( cyg_pci_device_id devid,
|
cyg_uint8 offset, cyg_uint16 val);
|
cyg_uint8 offset, cyg_uint16 val);
|
void cyg_pci_write_config_uint32( cyg_pci_device_id devid,
|
void cyg_pci_write_config_uint32( cyg_pci_device_id devid,
|
cyg_uint8 offset, cyg_uint32 val);</PRE
|
cyg_uint8 offset, cyg_uint32 val);</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>The write functions should only be used for device-specific
|
>The write functions should only be used for device-specific
|
config registers since using them on generic registers may invalidate
|
config registers since using them on generic registers may invalidate
|
the contents of a previously fetched cyg_pci_device
|
the contents of a previously fetched cyg_pci_device
|
structure.</P
|
structure.</P
|
></DIV
|
></DIV
|
><DIV
|
><DIV
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><H2
|
><H2
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><A
|
><A
|
NAME="AEN12742">Allocating memory</H2
|
NAME="AEN12742">Allocating memory</H2
|
><P
|
><P
|
>A PCI device ignores all IO and memory access from the PCI
|
>A PCI device ignores all IO and memory access from the PCI
|
bus until it has been activated. Activation cannot happen until
|
bus until it has been activated. Activation cannot happen until
|
after device configuration. Configuration means telling the device
|
after device configuration. Configuration means telling the device
|
where it should map its IO and memory resources. This is done with
|
where it should map its IO and memory resources. This is done with
|
one of the following functions::</P
|
one of the following functions::</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>cyg_bool cyg_pci_configure_device( cyg_pci_device *dev_info );
|
>cyg_bool cyg_pci_configure_device( cyg_pci_device *dev_info );
|
cyg_bool cyg_pci_configure_bus( cyg_uint8 bus, cyg_uint8 *next_bus );</PRE
|
cyg_bool cyg_pci_configure_bus( cyg_uint8 bus, cyg_uint8 *next_bus );</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>The <TT
|
>The <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_pci_configure_device</TT
|
>cyg_pci_configure_device</TT
|
> handles all IO
|
> handles all IO
|
and memory regions that need configuration on non-bridge devices. On
|
and memory regions that need configuration on non-bridge devices. On
|
platforms with multiple busses connected by bridges, the <TT
|
platforms with multiple busses connected by bridges, the <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_pci_configure_bus</TT
|
>cyg_pci_configure_bus</TT
|
> function should be used. It will recursively
|
> function should be used. It will recursively
|
configure all devices on the given <TT
|
configure all devices on the given <TT
|
CLASS="PARAMETER"
|
CLASS="PARAMETER"
|
><I
|
><I
|
>bus</I
|
>bus</I
|
></TT
|
></TT
|
> and all
|
> and all
|
subordinate busses. <TT
|
subordinate busses. <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_pci_configure_bus</TT
|
>cyg_pci_configure_bus</TT
|
> will
|
> will
|
use <TT
|
use <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_pci_configure_device</TT
|
>cyg_pci_configure_device</TT
|
> to configure
|
> to configure
|
individual non-bridge devices.</P
|
individual non-bridge devices.</P
|
><P
|
><P
|
> Each region is represented in the PCI device's config space by BARs
|
> Each region is represented in the PCI device's config space by BARs
|
(Base Address Registers) and is handled individually according to type
|
(Base Address Registers) and is handled individually according to type
|
using these functions:</P
|
using these functions:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>cyg_bool cyg_pci_allocate_memory( cyg_pci_device *dev_info,
|
>cyg_bool cyg_pci_allocate_memory( cyg_pci_device *dev_info,
|
cyg_uint32 bar,
|
cyg_uint32 bar,
|
CYG_PCI_ADDRESS64 *base );
|
CYG_PCI_ADDRESS64 *base );
|
cyg_bool cyg_pci_allocate_io( cyg_pci_device *dev_info,
|
cyg_bool cyg_pci_allocate_io( cyg_pci_device *dev_info,
|
cyg_uint32 bar,
|
cyg_uint32 bar,
|
CYG_PCI_ADDRESS32 *base );</PRE
|
CYG_PCI_ADDRESS32 *base );</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>The memory bases (in two distinct address spaces) are increased
|
>The memory bases (in two distinct address spaces) are increased
|
as memory regions are allocated to devices. Allocation will fail
|
as memory regions are allocated to devices. Allocation will fail
|
(the function returns false) if the base exceeds the limits of the
|
(the function returns false) if the base exceeds the limits of the
|
address space (IO is 1MB, memory is 2^32 or 2^64 bytes).</P
|
address space (IO is 1MB, memory is 2^32 or 2^64 bytes).</P
|
><P
|
><P
|
>These functions can also be called directly by the application/driver
|
>These functions can also be called directly by the application/driver
|
if necessary, but this should not be necessary.</P
|
if necessary, but this should not be necessary.</P
|
><P
|
><P
|
>The bases are initialized with default values provided by
|
>The bases are initialized with default values provided by
|
the HAL. It is possible for an application to override these using
|
the HAL. It is possible for an application to override these using
|
the following functions: </P
|
the following functions: </P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>void cyg_pci_set_memory_base( CYG_PCI_ADDRESS64 base );
|
>void cyg_pci_set_memory_base( CYG_PCI_ADDRESS64 base );
|
void cyg_pci_set_io_base( CYG_PCI_ADDRESS32 base );</PRE
|
void cyg_pci_set_io_base( CYG_PCI_ADDRESS32 base );</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>When a device has been configured, the cyg_pci_device
|
>When a device has been configured, the cyg_pci_device
|
structure will contain the physical address in the CPU's
|
structure will contain the physical address in the CPU's
|
address space where the device's memory regions can be
|
address space where the device's memory regions can be
|
accessed. </P
|
accessed. </P
|
><P
|
><P
|
>This information is provided in <TT
|
>This information is provided in <TT
|
CLASS="VARNAME"
|
CLASS="VARNAME"
|
>base_map[]</TT
|
>base_map[]</TT
|
> -
|
> -
|
there is a 32 bit word for each of the device's BARs. For
|
there is a 32 bit word for each of the device's BARs. For
|
32 bit PCI memory regions, each 32 bit word will be an actual pointer
|
32 bit PCI memory regions, each 32 bit word will be an actual pointer
|
that can be used immediately by the driver: the memory space will normally
|
that can be used immediately by the driver: the memory space will normally
|
be linearly addressable by the CPU.</P
|
be linearly addressable by the CPU.</P
|
><P
|
><P
|
>However, for 64 bit PCI memory regions, some (or all) of the
|
>However, for 64 bit PCI memory regions, some (or all) of the
|
region may be outside of the CPUs address space. In this case the
|
region may be outside of the CPUs address space. In this case the
|
driver will need to know how to access the region in segments. This
|
driver will need to know how to access the region in segments. This
|
functionality may be adopted by the eCos HAL if deemed useful in
|
functionality may be adopted by the eCos HAL if deemed useful in
|
the future. The 2GB available on many systems should suffice though.</P
|
the future. The 2GB available on many systems should suffice though.</P
|
></DIV
|
></DIV
|
><DIV
|
><DIV
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><H2
|
><H2
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><A
|
><A
|
NAME="PCI-INTERRUPTS">Interrupts</H2
|
NAME="PCI-INTERRUPTS">Interrupts</H2
|
><P
|
><P
|
>A device may generate interrupts. The HAL vector associated
|
>A device may generate interrupts. The HAL vector associated
|
with a given device on the bus is platform specific. This function
|
with a given device on the bus is platform specific. This function
|
allows a driver to find the actual interrupt vector for a given
|
allows a driver to find the actual interrupt vector for a given
|
device:</P
|
device:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>cyg_bool cyg_pci_translate_interrupt( cyg_pci_device *dev_info,
|
>cyg_bool cyg_pci_translate_interrupt( cyg_pci_device *dev_info,
|
CYG_ADDRWORD *vec );</PRE
|
CYG_ADDRWORD *vec );</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>If the function returns false, no interrupts will be generated
|
>If the function returns false, no interrupts will be generated
|
by the device. If it returns true, the CYG_ADDRWORD pointed
|
by the device. If it returns true, the CYG_ADDRWORD pointed
|
to by vec is updated with the HAL interrupt vector the device will
|
to by vec is updated with the HAL interrupt vector the device will
|
be using. This is how the function is used in the <TT
|
be using. This is how the function is used in the <TT
|
CLASS="FILENAME"
|
CLASS="FILENAME"
|
>pci1</TT
|
>pci1</TT
|
>
|
>
|
test:</P
|
test:</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
> if (cyg_pci_translate_interrupt(&dev_info, &irq))
|
> if (cyg_pci_translate_interrupt(&dev_info, &irq))
|
diag_printf(" Wired to HAL vector %d\n", irq);
|
diag_printf(" Wired to HAL vector %d\n", irq);
|
else
|
else
|
diag_printf(" Does not generate interrupts.\n");</PRE
|
diag_printf(" Does not generate interrupts.\n");</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><P
|
><P
|
>The application/drive should attach an interrupt
|
>The application/drive should attach an interrupt
|
handler to a device's interrupt before activating the device.</P
|
handler to a device's interrupt before activating the device.</P
|
></DIV
|
></DIV
|
><DIV
|
><DIV
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><H2
|
><H2
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><A
|
><A
|
NAME="AEN12770">Activating a device</H2
|
NAME="AEN12770">Activating a device</H2
|
><P
|
><P
|
>When the device has been allocated memory space it can be
|
>When the device has been allocated memory space it can be
|
activated. This is not done by the library since a driver may have
|
activated. This is not done by the library since a driver may have
|
to initialize more state on the device before it can be safely activated.</P
|
to initialize more state on the device before it can be safely activated.</P
|
><P
|
><P
|
>Activating the device is done by enabling flags in its command
|
>Activating the device is done by enabling flags in its command
|
word. As an example, see the <TT
|
word. As an example, see the <TT
|
CLASS="FILENAME"
|
CLASS="FILENAME"
|
>pci1</TT
|
>pci1</TT
|
> test which can be
|
> test which can be
|
configured to enable the devices it finds. This allows these to be accessed from
|
configured to enable the devices it finds. This allows these to be accessed from
|
GDB (if a breakpoint is set on <TT
|
GDB (if a breakpoint is set on <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_test_exit</TT
|
>cyg_test_exit</TT
|
>):</P
|
>):</P
|
><TABLE
|
><TABLE
|
BORDER="5"
|
BORDER="5"
|
BGCOLOR="#E0E0F0"
|
BGCOLOR="#E0E0F0"
|
WIDTH="70%"
|
WIDTH="70%"
|
><TR
|
><TR
|
><TD
|
><TD
|
><PRE
|
><PRE
|
CLASS="PROGRAMLISTING"
|
CLASS="PROGRAMLISTING"
|
>#ifdef ENABLE_PCI_DEVICES
|
>#ifdef ENABLE_PCI_DEVICES
|
{
|
{
|
cyg_uint16 cmd;
|
cyg_uint16 cmd;
|
|
|
// Don't use cyg_pci_set_device_info since it clears
|
// Don't use cyg_pci_set_device_info since it clears
|
// some of the fields we want to print out below.
|
// some of the fields we want to print out below.
|
cyg_pci_read_config_uint16(dev_info.devid,
|
cyg_pci_read_config_uint16(dev_info.devid,
|
CYG_PCI_CFG_COMMAND, &cmd);
|
CYG_PCI_CFG_COMMAND, &cmd);
|
cmd |= CYG_PCI_CFG_COMMAND_IO|CYG_PCI_CFG_COMMAND_MEMORY;
|
cmd |= CYG_PCI_CFG_COMMAND_IO|CYG_PCI_CFG_COMMAND_MEMORY;
|
cyg_pci_write_config_uint16(dev_info.devid,
|
cyg_pci_write_config_uint16(dev_info.devid,
|
CYG_PCI_CFG_COMMAND, cmd);
|
CYG_PCI_CFG_COMMAND, cmd);
|
}
|
}
|
diag_printf(" **** Device IO and MEM access enabled\n");
|
diag_printf(" **** Device IO and MEM access enabled\n");
|
#endif</PRE
|
#endif</PRE
|
></TD
|
></TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
><DIV
|
><DIV
|
CLASS="NOTE"
|
CLASS="NOTE"
|
><BLOCKQUOTE
|
><BLOCKQUOTE
|
CLASS="NOTE"
|
CLASS="NOTE"
|
><P
|
><P
|
><B
|
><B
|
>Note: </B
|
>Note: </B
|
>The best way to activate a device is actually
|
>The best way to activate a device is actually
|
through <TT
|
through <TT
|
CLASS="FUNCTION"
|
CLASS="FUNCTION"
|
>cyg_pci_set_device_info()</TT
|
>cyg_pci_set_device_info()</TT
|
>,
|
>,
|
but in this particular case the <SPAN
|
but in this particular case the <SPAN
|
CLASS="STRUCTNAME"
|
CLASS="STRUCTNAME"
|
>cyg_pci_device</SPAN
|
>cyg_pci_device</SPAN
|
>
|
>
|
structure contents from before the activation is required for printout
|
structure contents from before the activation is required for printout
|
further down in the code.</P
|
further down in the code.</P
|
></BLOCKQUOTE
|
></BLOCKQUOTE
|
></DIV
|
></DIV
|
></DIV
|
></DIV
|
><DIV
|
><DIV
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><H2
|
><H2
|
CLASS="SECT2"
|
CLASS="SECT2"
|
><A
|
><A
|
NAME="AEN12782">Links</H2
|
NAME="AEN12782">Links</H2
|
><P
|
><P
|
>See these links for more information about PCI:</P
|
>See these links for more information about PCI:</P
|
><P
|
><P
|
></P
|
></P
|
><OL
|
><OL
|
TYPE="1"
|
TYPE="1"
|
><LI
|
><LI
|
><P
|
><P
|
><A
|
><A
|
NAME="PCI-SPEC"
|
NAME="PCI-SPEC"
|
></A
|
></A
|
><A
|
><A
|
HREF="http://www.pcisig.com/"
|
HREF="http://www.pcisig.com/"
|
TARGET="_top"
|
TARGET="_top"
|
>http://www.pcisig.com/</A
|
>http://www.pcisig.com/</A
|
> - information on the PCI specifications</P
|
> - information on the PCI specifications</P
|
></LI
|
></LI
|
><LI
|
><LI
|
><P
|
><P
|
><A
|
><A
|
HREF="http://www.yourvote.com/pci/"
|
HREF="http://www.yourvote.com/pci/"
|
TARGET="_top"
|
TARGET="_top"
|
>http://www.yourvote.com/pci/</A
|
>http://www.yourvote.com/pci/</A
|
> - list of vendor and device IDs</P
|
> - list of vendor and device IDs</P
|
></LI
|
></LI
|
><LI
|
><LI
|
><P
|
><P
|
><A
|
><A
|
HREF="http://www.picmg.org/"
|
HREF="http://www.picmg.org/"
|
TARGET="_top"
|
TARGET="_top"
|
>http://www.picmg.org/</A
|
>http://www.picmg.org/</A
|
> - PCI Industrial Computer Manufacturers Group</P
|
> - PCI Industrial Computer Manufacturers Group</P
|
></LI
|
></LI
|
></OL
|
></OL
|
></DIV
|
></DIV
|
></DIV
|
></DIV
|
></DIV
|
></DIV
|
><DIV
|
><DIV
|
CLASS="NAVFOOTER"
|
CLASS="NAVFOOTER"
|
><HR
|
><HR
|
ALIGN="LEFT"
|
ALIGN="LEFT"
|
WIDTH="100%"><TABLE
|
WIDTH="100%"><TABLE
|
SUMMARY="Footer navigation table"
|
SUMMARY="Footer navigation table"
|
WIDTH="100%"
|
WIDTH="100%"
|
BORDER="0"
|
BORDER="0"
|
CELLPADDING="0"
|
CELLPADDING="0"
|
CELLSPACING="0"
|
CELLSPACING="0"
|
><TR
|
><TR
|
><TD
|
><TD
|
WIDTH="33%"
|
WIDTH="33%"
|
ALIGN="left"
|
ALIGN="left"
|
VALIGN="top"
|
VALIGN="top"
|
><A
|
><A
|
HREF="io-pci.html"
|
HREF="io-pci.html"
|
ACCESSKEY="P"
|
ACCESSKEY="P"
|
>Prev</A
|
>Prev</A
|
></TD
|
></TD
|
><TD
|
><TD
|
WIDTH="34%"
|
WIDTH="34%"
|
ALIGN="center"
|
ALIGN="center"
|
VALIGN="top"
|
VALIGN="top"
|
><A
|
><A
|
HREF="ecos-ref.html"
|
HREF="ecos-ref.html"
|
ACCESSKEY="H"
|
ACCESSKEY="H"
|
>Home</A
|
>Home</A
|
></TD
|
></TD
|
><TD
|
><TD
|
WIDTH="33%"
|
WIDTH="33%"
|
ALIGN="right"
|
ALIGN="right"
|
VALIGN="top"
|
VALIGN="top"
|
><A
|
><A
|
HREF="pci-library-reference.html"
|
HREF="pci-library-reference.html"
|
ACCESSKEY="N"
|
ACCESSKEY="N"
|
>Next</A
|
>Next</A
|
></TD
|
></TD
|
></TR
|
></TR
|
><TR
|
><TR
|
><TD
|
><TD
|
WIDTH="33%"
|
WIDTH="33%"
|
ALIGN="left"
|
ALIGN="left"
|
VALIGN="top"
|
VALIGN="top"
|
>PCI Library</TD
|
>PCI Library</TD
|
><TD
|
><TD
|
WIDTH="34%"
|
WIDTH="34%"
|
ALIGN="center"
|
ALIGN="center"
|
VALIGN="top"
|
VALIGN="top"
|
><A
|
><A
|
HREF="io-pci.html"
|
HREF="io-pci.html"
|
ACCESSKEY="U"
|
ACCESSKEY="U"
|
>Up</A
|
>Up</A
|
></TD
|
></TD
|
><TD
|
><TD
|
WIDTH="33%"
|
WIDTH="33%"
|
ALIGN="right"
|
ALIGN="right"
|
VALIGN="top"
|
VALIGN="top"
|
>PCI Library reference</TD
|
>PCI Library reference</TD
|
></TR
|
></TR
|
></TABLE
|
></TABLE
|
></DIV
|
></DIV
|
></BODY
|
></BODY
|
></HTML
|
></HTML
|
|
|