[BeBoB/MAudio] Add PreSonus::FireboxDevice class to support functionality to switch...
[ffado.git] / libffado / src / bebob / bebob_dl_mgr.cpp
blob6490af2e4e648b3107ab2dcede7f38120a3d33ee
1 /*
2 * Copyright (C) 2005-2008 by Daniel Wagner
4 * This file is part of FFADO
5 * FFADO = Free Firewire (pro-)audio drivers for linux
7 * FFADO is based upon FreeBoB
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) version 3 of the License.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "bebob_dl_mgr.h"
25 #include "bebob_dl_codes.h"
26 #include "bebob_dl_bcd.h"
28 #include "libieee1394/configrom.h"
29 #include "libieee1394/ieee1394service.h"
31 #include "libutil/cmd_serialize.h"
32 #include "libutil/Time.h"
34 #include "libutil/ByteSwap.h"
36 #include <cstdio>
37 #include <cstring>
38 #include <unistd.h>
40 namespace BeBoB {
41 enum {
42 AddrRegInfo = 0xffffc8020000ULL,
43 AddrRegReq = 0xffffc8021000ULL,
44 AddrRegReqBuf = 0xffffc8021040ULL,
45 AddrRegResp = 0xffffc8029000ULL,
46 AddrRegRespBuf = 0xffffc8029040ULL,
49 enum {
50 RegInfoManufactorIdOffset = 0x00,
51 RegInfoProtocolVersionOffset = 0x08,
52 RegInfoBootloaderVersionOffset = 0x0c,
53 RegInfoGUID = 0x10,
54 RegInfoHardwareModelId = 0x18,
55 RegInfoHardwareRevision = 0x1c,
56 RegInfoSoftwareDate = 0x20,
57 RegInfoSoftwareTime = 0x28,
58 RegInfoSoftwareId = 0x30,
59 RegInfoSoftwareVersion = 0x34,
60 RegInfoBaseAddress = 0x38,
61 RegInfoMaxImageLen = 0x3c,
62 RegInfoBootloaderDate = 0x40,
63 RegInfoBootloaderTime = 0x48,
64 RegInfoDebuggerDate = 0x50,
65 RegInfoDebuggerTime = 0x58,
66 RegInfoDebuggerId = 0x60,
67 RegInfoDebuggerVersion = 0x64
70 enum {
71 MaxRetries = 10,
74 IMPL_DEBUG_MODULE( BootloaderManager, BootloaderManager, DEBUG_LEVEL_NORMAL );
77 BeBoB::BootloaderManager::BootloaderManager(Ieee1394Service& ieee1349service,
78 fb_nodeid_t nodeId )
79 : m_ieee1394service( &ieee1349service )
80 , m_protocolVersion( eBPV_Unknown )
81 , m_isAppRunning( false )
82 , m_forceEnabled( false )
83 , m_bStartBootloader( true )
85 memset( &m_cachedInfoRegs, 0, sizeof( m_cachedInfoRegs ) );
87 m_configRom = new ConfigRom( *m_ieee1394service, nodeId );
88 // XXX throw exception if initialize fails!
89 m_configRom->initialize();
90 if ( !cacheInfoRegisters() ) {
91 debugError( "BootloaderManager: could not cache info registers\n" );
94 switch( m_cachedInfoRegs.m_protocolVersion ) {
95 case 1:
96 m_protocolVersion = eBPV_V1;
97 break;
98 case 3:
99 m_protocolVersion = eBPV_V3;
100 break;
101 default:
102 // exception?
103 break;
106 pthread_mutex_init( &m_mutex, 0 );
107 pthread_cond_init( &m_cond, 0 );
109 m_functor = new MemberFunctor0< BeBoB::BootloaderManager*,
110 void (BeBoB::BootloaderManager::*)() >
111 ( this, &BeBoB::BootloaderManager::busresetHandler, false );
112 m_ieee1394service->addBusResetHandler( m_functor );
115 BeBoB::BootloaderManager::~BootloaderManager()
117 m_ieee1394service->remBusResetHandler( m_functor );
118 delete( m_functor );
120 delete m_configRom;
122 pthread_cond_destroy( &m_cond );
123 pthread_mutex_destroy( &m_mutex );
126 bool
127 BeBoB::BootloaderManager::cacheInfoRegisters()
129 if ( !m_configRom->updatedNodeId() ) {
130 debugError( "cacheInfoRegisters: did not find device anymore\n" );
131 return false;
134 if ( !m_ieee1394service->read(
135 0xffc0 | m_configRom->getNodeId(),
136 AddrRegInfo,
137 sizeof( m_cachedInfoRegs )/4,
138 reinterpret_cast<fb_quadlet_t*>( &m_cachedInfoRegs ) ) )
140 return false;
143 if ( m_cachedInfoRegs.m_bootloaderVersion != 0x0 ) {
144 m_isAppRunning = false;
145 } else {
146 m_isAppRunning = true;
149 m_cachedInfoRegs.m_guid = ( m_cachedInfoRegs.m_guid >> 32 )
150 | ( m_cachedInfoRegs.m_guid << 32 );
152 return true;
155 bool
156 BeBoB::BootloaderManager::cacheInfoRegisters( int retries )
158 for ( int i = 0; i < retries; ++i ) {
159 if ( cacheInfoRegisters() ) {
160 return true;
162 sleep( 1 );
163 printf(".");
164 fflush(stdout);
167 return false;
170 std::string
171 BeBoB::BootloaderManager::getSoftwareDate()
173 return makeDate( m_cachedInfoRegs.m_softwareDate );
176 std::string
177 BeBoB::BootloaderManager::getSoftwareTime()
179 return makeDate( m_cachedInfoRegs.m_softwareTime );
182 void
183 BeBoB::BootloaderManager::printInfoRegisters()
185 using namespace std;
187 if ( !cacheInfoRegisters() ) {
188 debugError( "Could not read info registers\n" );
189 return;
192 printf( "Info Registers\n" );
193 printf( "\tManufactors Id:\t\t%s\n",
194 makeString( m_cachedInfoRegs.m_manId ).c_str() );
195 printf( "\tProtocol Version:\t0x%08x\n",
196 m_cachedInfoRegs.m_protocolVersion );
197 printf( "\tBootloader Version:\t0x%08x\n",
198 m_cachedInfoRegs.m_bootloaderVersion );
199 printf( "\tGUID:\t\t\t0x%08x%08x\n",
200 ( unsigned int )( m_cachedInfoRegs.m_guid >> 32 ),
201 ( unsigned int )( m_cachedInfoRegs.m_guid & 0xffffffff ) );
202 printf( "\tHardware Model ID:\t0x%08x\n",
203 m_cachedInfoRegs.m_hardwareModelId );
204 printf( "\tHardware Revision:\t0x%08x\n",
205 m_cachedInfoRegs.m_hardwareRevision );
206 if ( m_cachedInfoRegs.m_softwareDate
207 && m_cachedInfoRegs.m_softwareTime )
209 printf( "\tSoftware Date:\t\t%s, %s\n",
210 makeDate( m_cachedInfoRegs.m_softwareDate ).c_str(),
211 makeTime( m_cachedInfoRegs.m_softwareTime ).c_str() );
213 printf( "\tSoftware Id:\t\t0x%08x\n", m_cachedInfoRegs.m_softwareId );
214 printf( "\tSoftware Version:\t0x%08x\n",
215 m_cachedInfoRegs.m_softwareVersion );
216 printf( "\tBase Address:\t\t0x%08x\n", m_cachedInfoRegs.m_baseAddress );
217 printf( "\tMax. Image Len:\t\t0x%08x\n", m_cachedInfoRegs.m_maxImageLen );
218 if ( m_cachedInfoRegs.m_bootloaderDate
219 && m_cachedInfoRegs.m_bootloaderTime )
221 printf( "\tBootloader Date:\t%s, %s\n",
222 makeDate( m_cachedInfoRegs.m_bootloaderDate ).c_str(),
223 makeTime( m_cachedInfoRegs.m_bootloaderTime ).c_str() );
225 if ( m_cachedInfoRegs.m_debuggerDate
226 && m_cachedInfoRegs.m_debuggerTime )
228 printf( "\tDebugger Date:\t\t%s, %s\n",
229 makeDate( m_cachedInfoRegs.m_debuggerDate ).c_str(),
230 makeTime( m_cachedInfoRegs.m_debuggerTime ).c_str() );
232 printf( "\tDebugger Id:\t\t0x%08x\n", m_cachedInfoRegs.m_debuggerId );
233 printf( "\tDebugger Version:\t0x%08x\n",
234 m_cachedInfoRegs.m_debuggerVersion );
237 bool
238 BeBoB::BootloaderManager::downloadFirmware( std::string filename )
240 using namespace std;
242 printf( "parse BCD file\n" );
243 std::auto_ptr<BCD> bcd = std::auto_ptr<BCD>( new BCD( filename ) );
244 if ( !bcd.get() ) {
245 debugError( "downloadFirmware: Could not open or parse BCD '%s'\n",
246 filename.c_str() );
247 return false;
249 if ( !bcd->parse() ) {
250 debugError( "downloadFirmware: BCD parsing failed\n" );
251 return false;
254 printf( "check firmware device compatibility... " );
255 if ( !m_forceEnabled ) {
256 if ( !checkDeviceCompatibility( *bcd ) ) {
257 printf( "failed.\n" );
258 return false;
260 printf( "ok\n" );
261 } else {
262 printf( "forced\n" );
265 if ( m_bStartBootloader ) {
266 printf( "prepare for download (start bootloader)\n" );
267 if ( !startBootloaderCmd() ) {
268 debugError( "downloadFirmware: Could not start bootloader\n" );
269 return false;
273 printf( "start downloading protocol for application image\n" );
274 if ( !downloadObject( *bcd, eOT_Application ) ) {
275 debugError( "downloadFirmware: Firmware download failed\n" );
276 return false;
279 printf( "start downloading protocol for CnE\n" );
280 if ( !downloadObject( *bcd, eOT_CnE ) ) {
281 debugError( "downloadFirmware: CnE download failed\n" );
282 return false;
285 printf( "setting CnE to factory default settings\n" );
286 if ( !initializeConfigToFactorySettingCmd() ) {
287 debugError( "downloadFirmware: Could not reinitalize CnE\n" );
288 return false;
291 printf( "start application\n" );
292 if ( !startApplicationCmd() ) {
293 debugError( "downloadFirmware: Could not restart application\n" );
294 return false;
297 return true;
300 bool
301 BeBoB::BootloaderManager::downloadCnE( std::string filename )
303 using namespace std;
305 printf( "parse BCD file\n" );
306 std::auto_ptr<BCD> bcd = std::auto_ptr<BCD>( new BCD( filename ) );
307 if ( !bcd.get() ) {
308 debugError( "downloadCnE: Could not open or parse BCD '%s'\n",
309 filename.c_str() );
310 return false;
312 if ( !bcd->parse() ) {
313 debugError( "downloadCnE: BCD parsing failed\n" );
314 return false;
317 printf( "check firmware device compatibility... " );
318 if ( !m_forceEnabled ) {
319 if ( !checkDeviceCompatibility( *bcd ) ) {
320 printf( "failed.\n" );
321 return false;
323 printf( "ok\n" );
324 } else {
325 printf( "forced\n" );
328 if ( m_bStartBootloader ) {
329 printf( "prepare for download (start bootloader)\n" );
330 if ( !startBootloaderCmd() ) {
331 debugError( "downloadCnE: Could not start bootloader\n" );
332 return false;
336 printf( "start downloading protocol for CnE\n" );
337 if ( !downloadObject( *bcd, eOT_CnE ) ) {
338 debugError( "downloadCnE: CnE download failed\n" );
339 return false;
342 printf( "setting CnE to factory default settings\n" );
343 if ( !initializeConfigToFactorySettingCmd() ) {
344 debugError( "downloadFirmware: Could not reinitalize CnE\n" );
345 return false;
348 printf( "start application\n" );
349 if ( !startApplicationCmd() ) {
350 debugError( "downloadCnE: Could not restart application\n" );
351 return false;
354 return true;
358 bool
359 BeBoB::BootloaderManager::downloadObject( BCD& bcd, EObjectType eObject )
361 using namespace std;
363 CommandCodesDownloadStart::EObject eCCDSObject;
364 fb_quadlet_t baseAddress;
365 fb_quadlet_t imageLength;
366 fb_quadlet_t crc;
367 fb_quadlet_t offset;
369 switch ( eObject ) {
370 case eOT_Application:
371 eCCDSObject = CommandCodesDownloadStart::eO_Application;
372 baseAddress = bcd.getImageBaseAddress();
373 imageLength = bcd.getImageLength();
374 crc = bcd.getImageCRC();
375 offset = bcd.getImageOffset();
376 break;
377 case eOT_CnE:
378 eCCDSObject = CommandCodesDownloadStart::eO_Config;
379 baseAddress = 0;
380 imageLength = bcd.getCnELength();
381 crc = bcd.getCnECRC();
382 offset = bcd.getCnEOffset();
383 break;
384 default:
385 return false;
388 CommandCodesDownloadStart ccDStart ( m_protocolVersion, eCCDSObject );
389 ccDStart.setDate( bcd.getSoftwareDate() );
390 ccDStart.setTime( bcd.getSoftwareTime() );
391 ccDStart.setId( bcd.getSoftwareId() );
392 ccDStart.setVersion( bcd.getSoftwareVersion() );
393 ccDStart.setBaseAddress( baseAddress );
394 ccDStart.setLength( imageLength );
395 ccDStart.setCRC( crc );
397 if ( !writeRequest( ccDStart ) ) {
398 debugError( "downloadObject: start command write request failed\n" );
399 return false;
402 // bootloader erases the flash, have to wait until is ready
403 // to answer our next request
404 printf( "wait until flash erasing has terminated\n" );
405 int cnt = 30;
406 while(cnt--) {
407 sleep( 1 );
408 printf(".");
409 fflush(stdout);
411 printf("\n");
413 if ( !readResponse( ccDStart ) ) {
414 debugError( "downloadObject: (start) command read request failed\n" );
415 return false;
418 if ( ccDStart.getMaxBlockSize() < 0 ) {
419 debugError( "downloadObject: (start) command reported error %d\n",
420 ccDStart.getMaxBlockSize() );
421 return false;
424 unsigned int maxBlockSize = m_configRom->getAsyMaxPayload();
425 unsigned int i = 0;
426 fb_quadlet_t address = 0;
427 bool result = true;
428 int totalBytes = imageLength;
429 int downloadedBytes = 0;
430 while ( imageLength > 0 ) {
431 unsigned int blockSize = imageLength > maxBlockSize ?
432 maxBlockSize : imageLength;
434 fb_byte_t block[blockSize];
435 if ( !bcd.read( offset, block, blockSize ) ) {
436 result = false;
437 break;
440 if ( !get1394Serivce()->write(
441 0xffc0 | getConfigRom()->getNodeId(),
442 AddrRegReqBuf,
443 ( blockSize + 3 ) / 4,
444 reinterpret_cast<fb_quadlet_t*>( block ) ) )
446 debugError( "downloadObject: Could not write to node %d\n",
447 getConfigRom()->getNodeId() );
448 return false;
451 CommandCodesDownloadBlock ccBlock( m_protocolVersion );
452 ccBlock.setSeqNumber( i );
453 ccBlock.setAddress( baseAddress + address );
454 ccBlock.setNumberBytes( blockSize );
456 if ( !writeRequest( ccBlock ) ) {
457 debugError( "downloadObject: (block) write request failed\n" );
458 result = false;
459 break;
461 SleepRelativeUsec( 100 );
463 if ( !readResponse( ccBlock ) ) {
464 debugError( "downloadObject: (block) read request failed\n" );
465 result = false;
466 break;
469 if ( i != ccBlock.getRespSeqNumber() ) {
470 debugError( "downloadObject: (block) wrong sequence number "
471 "reported. %d expected, %d reported\n",
472 i, ccBlock.getRespSeqNumber() );
473 result = false;
474 break;
476 if ( ccBlock.getRespErrorCode() != 0 ) {
477 debugError( "downloadObject: (block) failed download with "
478 "error code 0x%08x\n", ccBlock.getRespErrorCode() );
479 result = false;
480 break;
483 downloadedBytes += blockSize;
484 if ( ( i % 100 ) == 0 ) {
485 printf( "%10d/%d bytes downloaded\r",
486 downloadedBytes, totalBytes );
487 fflush(stdout);
490 imageLength -= blockSize;
491 address += blockSize;
492 offset += blockSize;
493 i++;
495 printf( "%10d/%d bytes downloaded\n",
496 downloadedBytes, totalBytes );
498 if ( !result ) {
499 debugError( "downloadObject: seqNumber = %d, "
500 "address = 0%08x, offset = 0x%08x, "
501 "restImageLength = 0x%08x\n",
502 i, address, offset, imageLength );
505 CommandCodesDownloadEnd ccEnd( m_protocolVersion );
506 if ( !writeRequest( ccEnd ) ) {
507 debugError( "downloadObject: (end) command write failed\n" );
510 printf( "wait for transaction completion\n" );
511 cnt = 10;
512 while(cnt--) {
513 sleep( 1 );
514 printf(".");
515 fflush(stdout);
517 printf("\n");
519 if ( !readResponse( ccEnd ) ) {
520 debugError( "downloadObject: (end) command read failed\n" );
523 if ( result ) {
524 if ( ccEnd.getRespIsValid() ) {
525 if ( ccEnd.getRespCrc32() == crc ) {
526 debugOutput( DebugModule::eDL_Normal,
527 "downloadObject: CRC match\n" );
528 } else {
529 debugError( "downloadObject: CRC mismatch. 0x%08x expected, "
530 "0x%08x reported",
531 crc, ccEnd.getRespCrc32() );
532 result = false;
534 } else {
535 debugError( "downloadObject: (end) object is not valid\n" );
536 result = false;
539 printf( "download protocol successfuly completed\n" );
540 return result;
543 bool
544 BeBoB::BootloaderManager::programGUID( fb_octlet_t guid )
546 if ( m_bStartBootloader ) {
547 if ( !startBootloaderCmd() ) {
548 debugError( "programGUID: Could not start bootloader\n" );
549 return false;
553 if ( !programGUIDCmd( guid ) ) {
554 debugError( "programGUID: Could not program guid\n" );
555 return false;
558 if ( !startApplicationCmd() ) {
559 debugError( "Could not restart application\n");
560 return false;
563 return true;
566 void
567 BeBoB::BootloaderManager::busresetHandler()
569 pthread_cond_signal( &m_cond );
572 void
573 BeBoB::BootloaderManager::waitForBusReset()
575 struct timespec timeout;
576 int retcode;
577 // pthread_cond_timedwait() uses CLOCK_REALTIME to evaluate its
578 // timeout argument.
579 clock_gettime(CLOCK_REALTIME, &timeout);
580 do {
581 printf(".");
582 fflush(stdout);
583 timeout.tv_sec = timeout.tv_sec + 1;
584 retcode = pthread_cond_timedwait( &m_cond, &m_mutex, &timeout );
585 } while (retcode == ETIMEDOUT);
588 bool
589 BeBoB::BootloaderManager::writeRequest( CommandCodes& cmd )
591 unsigned char buf[ ( ( cmd.getMaxSize()+3 )/4 ) * 4 ];
592 memset( buf, 0, sizeof( buf ) );
594 Util::Cmd::BufferSerialize se( buf, sizeof( buf ) );
595 if ( !cmd.serialize( se ) ) {
596 debugError( "writeRequest: Could not serialize command code %d\n",
597 cmd.getCommandCode() );
598 return false;
601 if ( !get1394Serivce()->write(
602 0xffc0 | getConfigRom()->getNodeId(),
603 AddrRegReq,
604 sizeof( buf )/4,
605 reinterpret_cast<fb_quadlet_t*>( buf ) ) )
607 debugError( "writeRequest: Could not ARM write to node %d\n",
608 getConfigRom()->getNodeId() );
609 return false;
612 return true;
615 bool
616 BeBoB::BootloaderManager::readResponse( CommandCodes& writeRequestCmd )
618 const size_t buf_length = 0x40;
619 unsigned char raw[buf_length];
620 if ( !get1394Serivce()->read(
621 0xffc0 | getConfigRom()->getNodeId(),
622 AddrRegResp,
623 writeRequestCmd.getRespSizeInQuadlets(),
624 reinterpret_cast<fb_quadlet_t*>( raw ) ) )
626 return false;
629 Util::Cmd::BufferDeserialize de( raw, buf_length );
630 if ( !writeRequestCmd.deserialize( de ) ) {
631 debugError( "readResponse: deserialize failed\n" );
632 return false;
635 bool result =
636 writeRequestCmd.getProtocolVersion()
637 == writeRequestCmd.getRespProtocolVersion();
638 result &=
639 writeRequestCmd.getCommandId()
640 == writeRequestCmd.getRespCommandId();
641 result &=
642 writeRequestCmd.getCommandCode()
643 == writeRequestCmd.getRespCommandCode();
644 #ifdef DEBUG
645 if ( !result ) {
646 debugError( "readResponse: protocol version: %d expected, "
647 " %d reported\n",
648 writeRequestCmd.getProtocolVersion(),
649 writeRequestCmd.getRespProtocolVersion() );
650 debugError( "readResponse: command id: %d expected, "
651 " %d reported\n",
652 writeRequestCmd.getCommandId(),
653 writeRequestCmd.getRespCommandId() );
654 debugError( "readResponse: command code: %d expected, "
655 " %d reported\n",
656 writeRequestCmd.getCommandCode(),
657 writeRequestCmd.getRespCommandCode() );
659 #endif
660 return result;
663 bool
664 BeBoB::BootloaderManager::startBootloaderCmd()
666 CommandCodesReset cmd( m_protocolVersion,
667 CommandCodesReset::eSM_Bootloader ) ;
668 if ( !writeRequest( cmd ) ) {
669 debugError( "startBootloaderCmd: writeRequest failed\n" );
670 return false;
673 waitForBusReset();
674 if ( !cacheInfoRegisters( MaxRetries ) ) {
675 debugError( "startBootloaderCmd: Could not read info registers\n" );
676 return false;
679 // wait for bootloader finish startup sequence
680 // there is no way to find out when it has finished
681 sleep( 10 );
682 int cnt = 10;
683 while(cnt--) {
684 sleep( 1 );
685 printf(".");
686 fflush(stdout);
688 printf("\n");
690 return true;
693 bool
694 BeBoB::BootloaderManager::startApplicationCmd()
696 CommandCodesGo cmd( m_protocolVersion,
697 CommandCodesGo::eSM_Application ) ;
698 if ( !writeRequest( cmd ) ) {
699 debugError( "startApplicationCmd: writeRequest failed\n" );
700 return false;
703 return true;
706 bool
707 BeBoB::BootloaderManager::programGUIDCmd( fb_octlet_t guid )
709 CommandCodesProgramGUID cmd( m_protocolVersion, guid );
710 if ( !writeRequest( cmd ) ) {
711 debugError( "programGUIDCmd: writeRequest failed\n" );
712 return false;
715 sleep( 1 );
717 return true;
720 bool
721 BeBoB::BootloaderManager::initializePersParamCmd()
723 CommandCodesInitializePersParam cmd( m_protocolVersion );
724 if ( !writeRequest( cmd ) ) {
725 debugError( "initializePersParamCmd: writeRequest failed\n" );
726 return false;
729 sleep( 1 );
731 return true;
734 bool
735 BeBoB::BootloaderManager::initializeConfigToFactorySettingCmd()
737 CommandCodesInitializeConfigToFactorySetting cmd( m_protocolVersion );
738 if ( !writeRequest( cmd ) ) {
739 debugError( "initializeConfigToFactorySettingCmd: writeRequest failed\n" );
740 return false;
743 sleep( 5 );
744 int cnt = 5;
745 while(cnt--) {
746 sleep( 1 );
747 printf(".");
748 fflush(stdout);
750 printf("\n");
752 return true;
755 bool
756 BeBoB::BootloaderManager::checkDeviceCompatibility( BCD& bcd )
758 fb_quadlet_t vendorOUI = ( m_cachedInfoRegs.m_guid >> 40 );
761 if ( ( vendorOUI == bcd.getVendorOUI() )
762 && ( m_cachedInfoRegs.m_softwareId == bcd.getSoftwareId() ) )
764 return true;
767 printf( "vendorOUI = 0x%08x\n", vendorOUI );
768 printf( "BCD vendorOUI = 0x%08x\n", bcd.getVendorOUI() );
769 printf( "software ID = 0x%08x\n", m_cachedInfoRegs.m_softwareId );
770 printf( "BCD software ID = 0x%08x\n", bcd.getSoftwareId() );
772 return false;