Library of Bus-Adapters
/home/cschwick/hal/busAdapter/pci/src/common/PCILinuxBusAdapter.cc
Go to the documentation of this file.
00001 #include "hal/PCILinuxBusAdapter.hh"
00002 
00003 #include <sstream>
00004 #include <iomanip>
00005 
00006 HAL::PCILinuxBusAdapter::PCILinuxBusAdapter() throw (HAL::BusAdapterException)
00007   try
00008   : PCIBusAdapterInterface(),
00009     pciBus_() {}
00010   catch ( xpci::exception::IOError &e ) {
00011     std::string err = std::string( e.what() );
00012     throw BusAdapterException(  e.what(),  __FILE__, __LINE__, __FUNCTION__ );
00013   }
00014 
00015 HAL::PCILinuxBusAdapter::~PCILinuxBusAdapter() {
00016 }
00017 
00018 void HAL::PCILinuxBusAdapter::findDeviceByBus( uint32_t busID, 
00019                                                uint32_t slotID,
00020                                                uint32_t functionID,
00021                                                const PCIAddressTable& pciAddressTable,
00022                                                PCIDeviceIdentifier** deviceIdentifierPtr,
00023                                                std::vector<uint32_t>& baseAddresses,
00024                                                bool swapFlag )
00025   throw (BusAdapterException,
00026          NoSuchDeviceException) {
00027   
00028   xpci::Address deviceConfigAddress = 
00029     xpci::Address::getConfigSpaceAddressByBus(busID, slotID, functionID);
00030 
00031   findDevice( deviceConfigAddress,
00032               pciAddressTable,
00033               deviceIdentifierPtr,
00034               baseAddresses,
00035               swapFlag );
00036 }
00037     
00038 void HAL::PCILinuxBusAdapter::findDeviceByVendor( uint32_t vendorID, 
00039                                                   uint32_t deviceID,
00040                                                   uint32_t index,
00041                                                   const PCIAddressTable& pciAddressTable,
00042                                                   PCIDeviceIdentifier** deviceIdentifierPtr,
00043                                                   std::vector<uint32_t>& baseAddresses,
00044                                                   bool swapFlag )
00045   throw (BusAdapterException,
00046          NoSuchDeviceException) {
00047 
00048   xpci::Address deviceConfigAddress = 
00049     xpci::Address::getConfigSpaceAddressByVendor(vendorID, deviceID, index);
00050 
00051   findDevice( deviceConfigAddress,
00052               pciAddressTable,
00053               deviceIdentifierPtr,
00054               baseAddresses,
00055               swapFlag );
00056 }
00057     
00058 void HAL::PCILinuxBusAdapter::findDevice( xpci::Address& deviceConfigAddress,
00059                                           const PCIAddressTable& pciAddressTable,
00060                                           PCIDeviceIdentifier** deviceIdentifierPtr,
00061                                           std::vector<uint32_t>& baseAddresses,
00062                                           bool swapFlag )
00063 throw (BusAdapterException,
00064        NoSuchDeviceException) {
00065 
00066   *deviceIdentifierPtr = (PCIDeviceIdentifier*) 0; // default: unvalid
00067 
00068   // check if the device has been found, otherwise throw exception
00069   try {
00070     uint32_t val;
00071     pciBus_.read (deviceConfigAddress, 0x00000010, val);
00072   } catch ( xpci::exception::IOError e) {
00073     std::stringstream text;
00074     text << "Could not find PCI device \n"
00075          << std::ends;
00076     std::string textStr = text.str();
00077     throw ( NoSuchDeviceException( textStr, __FILE__, __LINE__, __FUNCTION__ ));
00078   }
00079   HAL::PCILinuxDeviceIdentifier* newIdentifierPtr = 
00080     new HAL::PCILinuxDeviceIdentifier(deviceConfigAddress, swapFlag);
00081   uint32_t minConfigAddress, maxConfigAddress;
00082   std::vector<uint32_t> minAddresses, maxAddresses;
00083   pciAddressTable.getAddressBoundaries( minConfigAddress, maxConfigAddress,
00084                                         minAddresses, maxAddresses );
00085   baseAddresses.clear();
00086   
00087   try {
00088     for ( int ix = 0; ix<6; ix++ ) {
00089       xpci::Address ba = pciBus_.BAR(ix, deviceConfigAddress);
00090       baseAddresses.push_back(ba.getAddress());
00091     }
00092   } catch ( xpci::exception::IOError &e ) {
00093     throw BusAdapterException( e.what(), __FILE__, __LINE__, __FUNCTION__ );
00094   } 
00095 
00096 
00097   *deviceIdentifierPtr = newIdentifierPtr;
00098 }
00099 
00100 void HAL::PCILinuxBusAdapter::configWrite( PCIDeviceIdentifier& pciDevice,
00101                                      uint32_t address,
00102                                      uint32_t data) 
00103   throw( BusAdapterException ){
00104   if ( (address%4 != 0) ) {
00105     std::stringstream text;
00106     text << "address or length not aligned to 4 byte boundary " 
00107          << "\n     address (hex) : " << std::hex << address 
00108          << std::ends;
00109     throw( BusAdapterException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00110   }
00111   xpci::Address pciConfigAddress 
00112     = (dynamic_cast<HAL::PCILinuxDeviceIdentifier&>(pciDevice)).getConfigAddress();
00113   try {
00114     pciBus_.write(pciConfigAddress, address, data);
00115   } catch( xpci::exception::IOError &e ) {
00116     std::stringstream text;
00117     text << "error during write to address  " 
00118          << std::hex << address 
00119          << " (data : " << data << ")"
00120          << std::ends;
00121     throw( BusAdapterException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00122   }
00123 }
00124 
00125 void HAL::PCILinuxBusAdapter::configRead( PCIDeviceIdentifier& pciDevice,
00126                                           uint32_t address,
00127                                           uint32_t* data) 
00128   throw( BusAdapterException ){
00129   if ( (address%4 != 0) ) {
00130     std::stringstream text;
00131     text << "address or length not aligned to 4 byte boundary " 
00132          << "\n     address (hex) : " << std::hex << address 
00133          << std::ends;
00134     throw( BusAdapterException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00135   }
00136   xpci::Address pciConfigAddress 
00137     = (dynamic_cast<HAL::PCILinuxDeviceIdentifier&>(pciDevice)).getConfigAddress();
00138   try {
00139         uint32_t val;
00140      pciBus_.read(pciConfigAddress, address, val);
00141     *data = val;
00142   } catch( xpci::exception::IOError &e ) {
00143     std::stringstream text;
00144     text << "error during read from address  " 
00145          << std::hex << address 
00146          << std::ends;
00147     throw( BusAdapterException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00148   }
00149 }
00150 
00151 void HAL::PCILinuxBusAdapter::write( PCIDeviceIdentifier& device,
00152                                      uint32_t address, 
00153                                      uint32_t data ) 
00154   throw( BusAdapterException ) {
00155   if ( (address%4 != 0) ) {
00156     std::stringstream text;
00157     text << "address or length not aligned to 4 byte boundary " 
00158          << "\n     address (hex) : " << std::hex << address 
00159          << std::ends;
00160     throw( BusAdapterException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00161   }
00162 
00163   xpci::Address pciAddress = xpci::Address::getMemorySpaceAddress( address );
00164   try {
00165     if ( device.doSwap() ){
00166       pciBus_.write( pciAddress, 0, bswap_32(data) );
00167     } else {
00168       pciBus_.write( pciAddress, 0, data );
00169     }
00170   } catch( xpci::exception::IOError &e ) {
00171     std::stringstream text;
00172     text << "error during write to address  " 
00173          << std::hex << address 
00174          << " (data : " << data << ")"
00175          << std::ends;
00176     throw( BusAdapterException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00177   }
00178 }
00179 
00180 void HAL::PCILinuxBusAdapter::read( PCIDeviceIdentifier& device,
00181                                    uint32_t address, 
00182                                    uint32_t* result ) 
00183   throw( BusAdapterException ) {
00184   if ( (address%4 != 0) ) {
00185     std::stringstream text;
00186     text << "address or length not aligned to 4 byte boundary " 
00187          << "\n     address (hex) : " << std::hex << address 
00188          << std::ends;
00189     throw( BusAdapterException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00190   }
00191 
00192   xpci::Address pciAddress = xpci::Address::getMemorySpaceAddress( address );
00193   try {
00194     if ( device.doSwap() ){
00195         uint32_t val;
00196         pciBus_.read( pciAddress, 0 , val );
00197         *result = bswap_32( val );
00198     } else {
00199          uint32_t val;
00200         pciBus_.read( pciAddress, 0, val );
00201         *result = val;
00202     }
00203   } catch( xpci::exception::IOError &e ) {
00204     std::stringstream text;
00205     text << "error during read from address  " 
00206          << std::hex << address 
00207          << std::ends;
00208     throw( BusAdapterException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00209   }
00210 
00211 }
00212 
00213 void HAL::PCILinuxBusAdapter::writeBlock( PCIDeviceIdentifier& device,
00214                                     uint32_t startAddress,
00215                                     uint32_t length,
00216                                     char *buffer,
00217                                     HalAddressIncrement addressBehaviour) 
00218   throw( BusAdapterException ) {
00219   // let's require the address to be aligned to 32 bit and then read
00220   // uint32_ts
00221   if ( (startAddress%4 != 0) || 
00222        (length%4 != 0) ) {
00223     std::stringstream text;
00224     text << "Start address or length not aligned to 4 byte boundary " 
00225          << "\n     StartAddress (hex) : " << std::hex << startAddress 
00226          << "\n     BlockLength  (hex) : " << std::hex << length
00227          << std::ends;
00228     std::string textStr = text.str();
00229     throw( BusAdapterException( textStr, __FILE__, __LINE__, __FUNCTION__ ) );
00230   }
00231 
00232   uint32_t* sourcePtr = (uint32_t*) buffer;
00233   uint32_t nWords = length/4;
00234   uint32_t ioff=0;
00235   xpci::Address pciAddress = xpci::Address::getMemorySpaceAddress( startAddress );
00236 
00237   try {
00238     if ( device.doSwap() ) {
00239       
00240       if ( addressBehaviour == HAL_DO_INCREMENT ) {
00241         for ( uint32_t ic = 0; ic<nWords; ic++, sourcePtr++, ioff+=4 ) {
00242           pciBus_.write( pciAddress, ioff, bswap_32(*sourcePtr) );
00243         }
00244       } else { // do not increment destination address 
00245         for (uint32_t ic = 0; ic<nWords; ic++, sourcePtr++ ) {
00246           pciBus_.write( pciAddress, 0, bswap_32(*sourcePtr) );
00247         }
00248       }
00249 
00250     } else {
00251       if ( addressBehaviour == HAL_DO_INCREMENT ) {
00252         for ( uint32_t ic = 0; ic<nWords; ic++, ioff+=4, sourcePtr++ ) {
00253           pciBus_.write( pciAddress, ioff, *sourcePtr );
00254         }
00255       } else { // do not increment destination address 
00256         for (uint32_t ic = 0; ic<nWords; ic++, sourcePtr++ ) {
00257           pciBus_.write( pciAddress, 0, *sourcePtr );
00258         }
00259       }
00260     }
00261   } catch( xpci::exception::IOError &e ) {
00262     std::stringstream text;
00263     text << "error during writeBlock to address  " 
00264          << std::hex << startAddress 
00265          << std::ends;
00266     throw( BusAdapterException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00267   }
00268 }
00269   
00270 void HAL::PCILinuxBusAdapter::readBlock(  PCIDeviceIdentifier& device,
00271                                     uint32_t startAddress,
00272                                     uint32_t length,
00273                                     char *buffer,
00274                                     HalAddressIncrement addressBehaviour) 
00275   throw( BusAdapterException ) {
00276   // let's require the address to be aligned to 32 bit and then read
00277   // uint32_ts
00278   if ( (startAddress%4 != 0) || 
00279        (length%4 != 0) ) {
00280     std::stringstream text;
00281     text << "Start address or length not aligned to 4 byte boundary " 
00282          << "\n     StartAddress (hex) : " << std::hex << startAddress 
00283          << "\n     BlockLength  (hex) : " << std::hex << length
00284          << std::ends;
00285     std::string textStr = text.str();
00286     throw( BusAdapterException( textStr, __FILE__, __LINE__, __FUNCTION__ ) );
00287   }
00288 
00289   uint32_t* destPtr   = (uint32_t*) buffer;
00290   uint32_t nWords = length/4;
00291   uint32_t ioff = 0;
00292   xpci::Address pciAddress = xpci::Address::getMemorySpaceAddress( startAddress );
00293   try {
00294     if ( device.doSwap() ){
00295       // byte swapping
00296       if ( addressBehaviour == HAL_DO_INCREMENT ) {
00297         for ( uint32_t ic = 0; ic<nWords; ic++, destPtr++, ioff+=4 ) {
00298            uint32_t val;
00299           pciBus_.read( pciAddress, ioff, val );
00300           *destPtr = bswap_32( val );
00301         }
00302       } else {                // do not increment source address 
00303         for (uint32_t ic = 0; ic<nWords; ic++, destPtr++ ) {
00304            uint32_t val;
00305         pciBus_.read( pciAddress, 0, val ); 
00306           *destPtr = bswap_32( val );
00307         }
00308       }
00309       // no byte swapping
00310     } else {
00311       if ( addressBehaviour == HAL_DO_INCREMENT ) {
00312         for ( uint32_t ic = 0; ic<nWords; ic++, destPtr++, ioff+=4 ) {
00313         uint32_t val;
00314         pciBus_.read( pciAddress, ioff , val );
00315           *destPtr = val;
00316         }
00317       } else {                // do not increment source address 
00318         for (uint32_t ic = 0; ic<nWords; ic++, destPtr++ ) {
00319         uint32_t val;
00320            pciBus_.read( pciAddress, 0, val );
00321           *destPtr = val;
00322         }
00323       }
00324     }
00325   } catch( xpci::exception::IOError &e ) {
00326     std::stringstream text;
00327     text << "error during readBlock from startAddress  " 
00328          << std::hex << startAddress 
00329          << std::ends;
00330     throw( BusAdapterException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00331   }
00332 }
00333   
00334 void HAL::PCILinuxBusAdapter::closeDevice( PCIDeviceIdentifier* deviceIdentifierPtr )
00335   throw() {
00336   delete(deviceIdentifierPtr); // this destroys the maps !!!
00337 }
00338