root/branches/libffado-2.0/src/libieee1394/ieee1394service.cpp

Revision 1292, 30.8 kB (checked in by ppalmers, 16 years ago)

- Improve bus reset handling. Bus resets now don't mess up a ffado client on an unrelated bus.

- add string id's to threads and mutexes to aid debugging

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2008 by Daniel Wagner
3  * Copyright (C) 2005-2008 by Pieter Palmers
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) version 3 of the License.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include "config.h"
26 #include "ieee1394service.h"
27 #include "cycletimer.h"
28 #include "IsoHandlerManager.h"
29 #include "CycleTimerHelper.h"
30
31 #include <libavc1394/avc1394.h>
32 #include <libraw1394/csr.h>
33 #include <libiec61883/iec61883.h>
34
35 #include "libutil/SystemTimeSource.h"
36 #include "libutil/Watchdog.h"
37 #include "libutil/PosixMutex.h"
38
39 #include <errno.h>
40 #include "libutil/ByteSwap.h"
41
42 #include <string.h>
43
44 #include <iostream>
45 #include <iomanip>
46
47 using namespace std;
48
49 IMPL_DEBUG_MODULE( Ieee1394Service, Ieee1394Service, DEBUG_LEVEL_NORMAL );
50
51 Ieee1394Service::Ieee1394Service()
52     : m_handle( 0 )
53     , m_handle_lock( new Util::PosixMutex("SRCVHND") )
54     , m_resetHandle( 0 )
55     , m_util_handle( 0 )
56     , m_port( -1 )
57     , m_RHThread_lock( new Util::PosixMutex("SRVCRH") )
58     , m_threadRunning( false )
59     , m_realtime ( false )
60     , m_base_priority ( 0 )
61     , m_pIsoManager( new IsoHandlerManager( *this ) )
62     , m_pCTRHelper ( new CycleTimerHelper( *this, IEEE1394SERVICE_CYCLETIMER_DLL_UPDATE_INTERVAL_USEC ) )
63     , m_have_new_ctr_read ( false )
64     , m_pWatchdog ( new Util::Watchdog() )
65 {
66     for (unsigned int i=0; i<64; i++) {
67         m_channels[i].channel=-1;
68         m_channels[i].bandwidth=-1;
69         m_channels[i].alloctype=AllocFree;
70         m_channels[i].xmit_node=0xFFFF;
71         m_channels[i].xmit_plug=-1;
72         m_channels[i].recv_node=0xFFFF;
73         m_channels[i].recv_plug=-1;
74     }
75 }
76
77 Ieee1394Service::Ieee1394Service(bool rt, int prio)
78     : m_handle( 0 )
79     , m_handle_lock( new Util::PosixMutex("SRCVHND") )
80     , m_resetHandle( 0 )
81     , m_util_handle( 0 )
82     , m_port( -1 )
83     , m_RHThread_lock( new Util::PosixMutex("SRVCRH") )
84     , m_threadRunning( false )
85     , m_realtime ( rt )
86     , m_base_priority ( prio )
87     , m_pIsoManager( new IsoHandlerManager( *this, rt, prio ) )
88     , m_pCTRHelper ( new CycleTimerHelper( *this, IEEE1394SERVICE_CYCLETIMER_DLL_UPDATE_INTERVAL_USEC,
89                                            rt && IEEE1394SERVICE_CYCLETIMER_HELPER_RUN_REALTIME,
90                                            prio + IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO_INCREASE ) )
91     , m_have_new_ctr_read ( false )
92     , m_pWatchdog ( new Util::Watchdog() )
93 {
94     for (unsigned int i=0; i<64; i++) {
95         m_channels[i].channel=-1;
96         m_channels[i].bandwidth=-1;
97         m_channels[i].alloctype=AllocFree;
98         m_channels[i].xmit_node=0xFFFF;
99         m_channels[i].xmit_plug=-1;
100         m_channels[i].recv_node=0xFFFF;
101         m_channels[i].recv_plug=-1;
102     }
103 }
104
105 Ieee1394Service::~Ieee1394Service()
106 {
107     delete m_pIsoManager;
108     delete m_pCTRHelper;
109     stopRHThread();
110
111     delete m_pWatchdog;
112     if ( m_handle ) {
113         raw1394_destroy_handle( m_handle );
114     }
115     delete m_handle_lock;
116
117     if ( m_resetHandle ) {
118         raw1394_destroy_handle( m_resetHandle );
119     }
120     delete m_RHThread_lock;
121     if ( m_util_handle ) {
122         raw1394_destroy_handle( m_util_handle );
123     }
124 }
125
126 int
127 Ieee1394Service::detectNbPorts()
128 {
129     raw1394handle_t tmp_handle = raw1394_new_handle();
130     if ( tmp_handle == NULL ) {
131         debugError("Could not get libraw1394 handle.\n");
132         return -1;
133     }
134     struct raw1394_portinfo pinf[IEEE1394SERVICE_MAX_FIREWIRE_PORTS];
135     int nb_detected_ports = raw1394_get_port_info(tmp_handle, pinf, IEEE1394SERVICE_MAX_FIREWIRE_PORTS);
136     raw1394_destroy_handle(tmp_handle);
137
138     if (nb_detected_ports < 0) {
139         debugError("Failed to detect number of ports\n");
140         return -1;
141     }
142     return nb_detected_ports;
143 }
144
145 void
146 Ieee1394Service::doBusReset() {
147     debugOutput(DEBUG_LEVEL_VERBOSE, "Issue bus reset on service %p (port %d).\n", this, getPort());
148     raw1394_reset_bus(m_handle);
149 }
150
151 bool
152 Ieee1394Service::initialize( int port )
153 {
154     using namespace std;
155
156     int nb_ports = detectNbPorts();
157     if (port + 1 > nb_ports) {
158         debugFatal("Requested port (%d) out of range (# ports: %d)\n", port, nb_ports);
159     }
160
161     if(!m_pWatchdog) {
162         debugError("No valid RT watchdog found.\n");
163         return false;
164     }
165     if(!m_pWatchdog->start()) {
166         debugError("Could not start RT watchdog.\n");
167         return false;
168     }
169
170     m_handle = raw1394_new_handle_on_port( port );
171     if ( !m_handle ) {
172         if ( !errno ) {
173             debugFatal("libraw1394 not compatible\n");
174         } else {
175             debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s\n",
176                 strerror(errno) );
177             debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
178         }
179         return false;
180     }
181
182     m_resetHandle = raw1394_new_handle_on_port( port );
183     if ( !m_resetHandle ) {
184         if ( !errno ) {
185             debugFatal("libraw1394 not compatible\n");
186         } else {
187             debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s",
188                 strerror(errno) );
189             debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
190         }
191         return false;
192     }
193
194     m_util_handle = raw1394_new_handle_on_port( port );
195     if ( !m_util_handle ) {
196         if ( !errno ) {
197             debugFatal("libraw1394 not compatible\n");
198         } else {
199             debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s",
200                 strerror(errno) );
201             debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
202         }
203         return false;
204     }
205
206     // test the cycle timer read function
207     int err;
208     uint32_t cycle_timer;
209     uint64_t local_time;
210     err=raw1394_read_cycle_timer(m_handle, &cycle_timer, &local_time);
211     if(err) {
212         debugOutput(DEBUG_LEVEL_VERBOSE, "raw1394_read_cycle_timer failed.\n");
213         debugOutput(DEBUG_LEVEL_VERBOSE, " Error descr: %s\n", strerror(err));
214         debugWarning("==================================================================\n");
215         debugWarning(" This system doesn't support the raw1394_read_cycle_timer call.   \n");
216         debugWarning(" Fallback to indirect CTR read method.                            \n");
217         debugWarning(" FFADO should work, but achieving low-latency might be a problem. \n");
218         debugWarning(" Upgrade the kernel to version 2.6.21 or higher to solve this.    \n");
219         debugWarning("==================================================================\n");
220         m_have_new_ctr_read = false;
221     } else {
222         debugOutput(DEBUG_LEVEL_VERBOSE, "This system supports the raw1394_read_cycle_timer call, using it.\n");
223         m_have_new_ctr_read = true;
224     }
225
226     m_port = port;
227
228     // obtain port name
229     raw1394handle_t tmp_handle = raw1394_new_handle();
230     if ( tmp_handle == NULL ) {
231         debugError("Could not get temporaty libraw1394 handle.\n");
232         return false;
233     }
234     struct raw1394_portinfo pinf[IEEE1394SERVICE_MAX_FIREWIRE_PORTS];
235     int nb_detected_ports = raw1394_get_port_info(tmp_handle, pinf, IEEE1394SERVICE_MAX_FIREWIRE_PORTS);
236     raw1394_destroy_handle(tmp_handle);
237
238     if (nb_detected_ports < 0) {
239         debugError("Failed to detect number of ports\n");
240         return false;
241     }
242
243     if(nb_detected_ports && port < IEEE1394SERVICE_MAX_FIREWIRE_PORTS) {
244         m_portName = pinf[port].name;
245     } else {
246         m_portName = "Unknown";
247     }
248     if (m_portName == "") {
249         m_portName = "Unknown";
250     }
251
252     raw1394_set_userdata( m_handle, this );
253     raw1394_set_userdata( m_resetHandle, this );
254     raw1394_set_userdata( m_util_handle, this );
255     raw1394_set_bus_reset_handler( m_resetHandle,
256                                    this->resetHandlerLowLevel );
257
258     if(!m_pCTRHelper) {
259         debugFatal("No CycleTimerHelper available, bad!\n");
260         return false;
261     }
262     m_pCTRHelper->setVerboseLevel(getDebugLevel());
263     if(!m_pCTRHelper->Start()) {
264         debugFatal("Could not start CycleTimerHelper\n");
265         return false;
266     }
267
268     if(!m_pIsoManager) {
269         debugFatal("No IsoHandlerManager available, bad!\n");
270         return false;
271     }
272     m_pIsoManager->setVerboseLevel(getDebugLevel());
273     if(!m_pIsoManager->init()) {
274         debugFatal("Could not initialize IsoHandlerManager\n");
275         return false;
276     }
277
278     startRHThread();
279
280     // make sure that the thread parameters of all our helper threads are OK
281     if(!setThreadParameters(m_realtime, m_base_priority)) {
282         debugFatal("Could not set thread parameters\n");
283         return false;
284     }
285     return true;
286 }
287
288 bool
289 Ieee1394Service::setThreadParameters(bool rt, int priority) {
290     bool result = true;
291     if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO;
292     m_base_priority = priority;
293     m_realtime = rt;
294     if (m_pIsoManager) {
295         debugOutput(DEBUG_LEVEL_VERBOSE, "Switching IsoManager to (rt=%d, prio=%d)\n",
296                                          rt, priority);
297         result &= m_pIsoManager->setThreadParameters(rt, priority);
298     }
299     if (m_pCTRHelper) {
300         debugOutput(DEBUG_LEVEL_VERBOSE, "Switching CycleTimerHelper to (rt=%d, prio=%d)\n",
301                                          rt && IEEE1394SERVICE_CYCLETIMER_HELPER_RUN_REALTIME,
302                                          priority + IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO_INCREASE);
303         result &= m_pCTRHelper->setThreadParameters(rt && IEEE1394SERVICE_CYCLETIMER_HELPER_RUN_REALTIME,
304                                                     priority + IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO_INCREASE);
305     }
306     return result;
307 }
308
309 int
310 Ieee1394Service::getNodeCount()
311 {
312     Util::MutexLockHelper lock(*m_handle_lock);
313     return raw1394_get_nodecount( m_handle );
314 }
315
316 nodeid_t Ieee1394Service::getLocalNodeId() {
317     Util::MutexLockHelper lock(*m_handle_lock);
318     return raw1394_get_local_id(m_handle) & 0x3F;
319 }
320
321 /**
322  * Returns the current value of the cycle timer (in ticks)
323  *
324  * @return the current value of the cycle timer (in ticks)
325  */
326
327 uint32_t
328 Ieee1394Service::getCycleTimerTicks() {
329     return m_pCTRHelper->getCycleTimerTicks();
330 }
331
332 /**
333  * Returns the current value of the cycle timer (as is)
334  *
335  * @return the current value of the cycle timer (as is)
336  */
337 uint32_t
338 Ieee1394Service::getCycleTimer() {
339     return m_pCTRHelper->getCycleTimer();
340 }
341
342 /**
343  * Returns the current value of the cycle timer (in ticks)
344  * for a specific time instant (usecs since epoch)
345  * @return the current value of the cycle timer (in ticks)
346  */
347
348 uint32_t
349 Ieee1394Service::getCycleTimerTicks(uint64_t t) {
350     return m_pCTRHelper->getCycleTimerTicks(t);
351 }
352
353 /**
354  * Returns the current value of the cycle timer (as is)
355  * for a specific time instant (usecs since epoch)
356  * @return the current value of the cycle timer (as is)
357  */
358 uint32_t
359 Ieee1394Service::getCycleTimer(uint64_t t) {
360     return m_pCTRHelper->getCycleTimer(t);
361 }
362
363 bool
364 Ieee1394Service::readCycleTimerReg(uint32_t *cycle_timer, uint64_t *local_time)
365 {
366     if(m_have_new_ctr_read) {
367         int err;
368         err = raw1394_read_cycle_timer(m_util_handle, cycle_timer, local_time);
369         if(err) {
370             debugWarning("raw1394_read_cycle_timer: %s\n", strerror(err));
371             return false;
372         }
373         return true;
374     } else {
375         // do a normal read of the CTR register
376         // the disadvantage is that local_time and cycle time are not
377         // read at the same time instant (scheduling issues)
378         *local_time = getCurrentTimeAsUsecs();
379         if ( raw1394_read( m_util_handle,
380                 getLocalNodeId() | 0xFFC0,
381                 CSR_REGISTER_BASE | CSR_CYCLE_TIME,
382                 sizeof(uint32_t), cycle_timer ) == 0 ) {
383             *cycle_timer = CondSwapFromBus32(*cycle_timer);
384             return true;
385         } else {
386             return false;
387         }
388     }
389 }
390
391 uint64_t
392 Ieee1394Service::getCurrentTimeAsUsecs() {
393     return Util::SystemTimeSource::getCurrentTimeAsUsecs();
394 }
395
396 bool
397 Ieee1394Service::read( fb_nodeid_t nodeId,
398                        fb_nodeaddr_t addr,
399                        size_t length,
400                        fb_quadlet_t* buffer )
401 {
402     Util::MutexLockHelper lock(*m_handle_lock);
403     if (nodeId == INVALID_NODE_ID) {
404         debugWarning("operation on invalid node\n");
405         return false;
406     }
407     if ( raw1394_read( m_handle, nodeId, addr, length*4, buffer ) == 0 ) {
408
409         #ifdef DEBUG
410         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
411             "read: node 0x%hX, addr = 0x%016llX, length = %u\n",
412             nodeId, addr, length);
413         printBuffer( DEBUG_LEVEL_VERY_VERBOSE, length, buffer );
414         #endif
415
416         return true;
417     } else {
418         #ifdef DEBUG
419         debugOutput(DEBUG_LEVEL_NORMAL,
420                     "raw1394_read failed: node 0x%hX, addr = 0x%016llX, length = %u\n",
421                     nodeId, addr, length);
422         #endif
423         return false;
424     }
425 }
426
427 bool
428 Ieee1394Service::read_quadlet( fb_nodeid_t nodeId,
429                                fb_nodeaddr_t addr,
430                                fb_quadlet_t* buffer )
431 {
432     return read( nodeId,  addr, sizeof( *buffer )/4, buffer );
433 }
434
435 bool
436 Ieee1394Service::read_octlet( fb_nodeid_t nodeId,
437                               fb_nodeaddr_t addr,
438                               fb_octlet_t* buffer )
439 {
440     return read( nodeId, addr, sizeof( *buffer )/4,
441                  reinterpret_cast<fb_quadlet_t*>( buffer ) );
442 }
443
444 bool
445 Ieee1394Service::write( fb_nodeid_t nodeId,
446                         fb_nodeaddr_t addr,
447                         size_t length,
448                         fb_quadlet_t* data )
449 {
450     Util::MutexLockHelper lock(*m_handle_lock);
451     if (nodeId == INVALID_NODE_ID) {
452         debugWarning("operation on invalid node\n");
453         return false;
454     }
455
456     #ifdef DEBUG
457     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"write: node 0x%hX, addr = 0x%016llX, length = %d\n",
458                 nodeId, addr, length);
459     printBuffer( DEBUG_LEVEL_VERY_VERBOSE, length, data );
460     #endif
461
462     return raw1394_write( m_handle, nodeId, addr, length*4, data ) == 0;
463 }
464
465 bool
466 Ieee1394Service::write_quadlet( fb_nodeid_t nodeId,
467                                 fb_nodeaddr_t addr,
468                                 fb_quadlet_t data )
469 {
470     return write( nodeId, addr, sizeof( data )/4, &data );
471 }
472
473 bool
474 Ieee1394Service::write_octlet( fb_nodeid_t nodeId,
475                                fb_nodeaddr_t addr,
476                                fb_octlet_t data )
477 {
478     return write( nodeId, addr, sizeof( data )/4,
479                   reinterpret_cast<fb_quadlet_t*>( &data ) );
480 }
481
482 bool
483 Ieee1394Service::lockCompareSwap64( fb_nodeid_t nodeId,
484                                     fb_nodeaddr_t addr,
485                                     fb_octlet_t compare_value,
486                                     fb_octlet_t swap_value,
487                                     fb_octlet_t* result )
488 {
489     if (nodeId == INVALID_NODE_ID) {
490         debugWarning("operation on invalid node\n");
491         return false;
492     }
493     #ifdef DEBUG
494     debugOutput(DEBUG_LEVEL_VERBOSE,"lockCompareSwap64: node 0x%X, addr = 0x%016llX\n",
495                 nodeId, addr);
496     debugOutput(DEBUG_LEVEL_VERBOSE,"  if (*(addr)==0x%016llX) *(addr)=0x%016llX\n",
497                 compare_value, swap_value);
498     fb_octlet_t buffer;
499     if(!read_octlet( nodeId, addr,&buffer )) {
500         debugWarning("Could not read register\n");
501     } else {
502         debugOutput(DEBUG_LEVEL_VERBOSE,"before = 0x%016llX\n", buffer);
503     }
504     #endif
505
506     // do endiannes swapping
507     compare_value = CondSwapToBus64(compare_value);
508     swap_value    = CondSwapToBus64(swap_value);
509
510     // do separate locking here (no MutexLockHelper) since
511     // we use read_octlet in the DEBUG code in this function
512     m_handle_lock->Lock();
513     int retval=raw1394_lock64(m_handle, nodeId, addr,
514                               RAW1394_EXTCODE_COMPARE_SWAP,
515                               swap_value, compare_value, result);
516     m_handle_lock->Unlock();
517
518     if(retval) {
519         debugError("raw1394_lock64 failed: %s\n", strerror(errno));
520     }
521
522     #ifdef DEBUG
523     if(!read_octlet( nodeId, addr,&buffer )) {
524         debugWarning("Could not read register\n");
525     } else {
526         debugOutput(DEBUG_LEVEL_VERBOSE,"after = 0x%016llX\n", buffer);
527     }
528     #endif
529
530     *result = CondSwapFromBus64(*result);
531
532     return (retval == 0);
533 }
534
535 fb_quadlet_t*
536 Ieee1394Service::transactionBlock( fb_nodeid_t nodeId,
537                                    fb_quadlet_t* buf,
538                                    int len,
539                                    unsigned int* resp_len )
540 {
541     if (nodeId == INVALID_NODE_ID) {
542         debugWarning("operation on invalid node\n");
543         return false;
544     }
545     // FIXME: this requires transactionBlockClose to unlock
546     m_handle_lock->Lock();
547     for (int i = 0; i < len; ++i) {
548         buf[i] = CondSwapFromBus32( buf[i] );
549     }
550
551     fb_quadlet_t* result =
552         avc1394_transaction_block2( m_handle,
553                                     nodeId,
554                                     buf,
555                                     len,
556                                     resp_len,
557                                     1 );
558
559     for ( unsigned int i = 0; i < *resp_len; ++i ) {
560         result[i] = CondSwapToBus32( result[i] );
561     }
562
563     return result;
564 }
565
566
567 bool
568 Ieee1394Service::transactionBlockClose()
569 {
570     avc1394_transaction_block_close( m_handle );
571     m_handle_lock->Unlock();
572     return true;
573 }
574
575 int
576 Ieee1394Service::getVerboseLevel()
577 {
578     return getDebugLevel();
579 }
580
581 void
582 Ieee1394Service::printBuffer( unsigned int level, size_t length, fb_quadlet_t* buffer ) const
583 {
584
585     for ( unsigned int i=0; i < length; ++i ) {
586         if ( ( i % 4 ) == 0 ) {
587             if ( i > 0 ) {
588                 debugOutputShort(level,"\n");
589             }
590             debugOutputShort(level," %4d: ",i*4);
591         }
592         debugOutputShort(level,"%08X ",buffer[i]);
593     }
594     debugOutputShort(level,"\n");
595 }
596 void
597 Ieee1394Service::printBufferBytes( unsigned int level, size_t length, byte_t* buffer ) const
598 {
599
600     for ( unsigned int i=0; i < length; ++i ) {
601         if ( ( i % 16 ) == 0 ) {
602             if ( i > 0 ) {
603                 debugOutputShort(level,"\n");
604             }
605             debugOutputShort(level," %4d: ",i*16);
606         }
607         debugOutputShort(level,"%02X ",buffer[i]);
608     }
609     debugOutputShort(level,"\n");
610 }
611
612 int
613 Ieee1394Service::resetHandlerLowLevel( raw1394handle_t handle,
614                                        unsigned int generation )
615 {
616     raw1394_update_generation ( handle, generation );
617     Ieee1394Service* instance
618         = (Ieee1394Service*) raw1394_get_userdata( handle );
619     instance->resetHandler( generation );
620
621     return 0;
622 }
623
624 bool
625 Ieee1394Service::resetHandler( unsigned int generation )
626 {
627     quadlet_t buf=0;
628
629     m_handle_lock->Lock();
630     raw1394_update_generation(m_handle, generation);
631     m_handle_lock->Unlock();
632
633     // do a simple read on ourself in order to update the internal structures
634     // this avoids failures after a bus reset
635     read_quadlet( getLocalNodeId() | 0xFFC0,
636                   CSR_REGISTER_BASE | CSR_CYCLE_TIME,
637                   &buf );
638
639     for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin();
640           it != m_busResetHandlers.end();
641           ++it )
642     {
643         Util::Functor* func = *it;
644         ( *func )();
645     }
646
647     return true;
648 }
649
650 bool
651 Ieee1394Service::startRHThread()
652 {
653     int i;
654
655     if ( m_threadRunning ) {
656         return true;
657     }
658     m_RHThread_lock->Lock();
659     i = pthread_create( &m_thread, 0, rHThread, this );
660     m_RHThread_lock->Unlock();
661     if (i) {
662         debugFatal("Could not start ieee1394 service thread\n");
663         return false;
664     }
665     m_threadRunning = true;
666
667     return true;
668 }
669
670 void
671 Ieee1394Service::stopRHThread()
672 {
673     if ( m_threadRunning ) {
674         // wait for the thread to finish it's work
675         m_RHThread_lock->Lock();
676         pthread_cancel (m_thread);
677         pthread_join (m_thread, 0);
678         m_RHThread_lock->Unlock();
679         m_threadRunning = false;
680     }
681 }
682
683 void*
684 Ieee1394Service::rHThread( void* arg )
685 {
686     Ieee1394Service* pIeee1394Service = (Ieee1394Service*) arg;
687
688     while (true) {
689         // protect ourselves from dying
690         {
691             // use a scoped lock such that it is unlocked
692             // even if we are cancelled while running
693             // FIXME: check if this is true!
694 //             Util::MutexLockHelper lock(*(pIeee1394Service->m_RHThread_lock));
695             raw1394_loop_iterate (pIeee1394Service->m_resetHandle);
696         }
697         pthread_testcancel ();
698     }
699
700     return 0;
701 }
702
703 bool
704 Ieee1394Service::addBusResetHandler( Util::Functor* functor )
705 {
706     debugOutput(DEBUG_LEVEL_VERBOSE, "Adding busreset handler (%p)\n", functor);
707     m_busResetHandlers.push_back( functor );
708     return true;
709 }
710
711 bool
712 Ieee1394Service::remBusResetHandler( Util::Functor* functor )
713 {
714     debugOutput(DEBUG_LEVEL_VERBOSE, "Removing busreset handler (%p)\n", functor);
715
716     for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin();
717           it != m_busResetHandlers.end();
718           ++it )
719     {
720         if ( *it == functor ) {
721             debugOutput(DEBUG_LEVEL_VERBOSE, " found\n");
722             m_busResetHandlers.erase( it );
723             return true;
724         }
725     }
726     debugOutput(DEBUG_LEVEL_VERBOSE, " not found\n");
727     return false;
728 }
729
730 /**
731  * Allocates an iso channel for use by the interface in a similar way to
732  * libiec61883.  Returns -1 on error (due to there being no free channels)
733  * or an allocated channel number.
734  *
735  * Does not perform anything other than registering the channel and the
736  * bandwidth at the IRM
737  *
738  * Also allocates the necessary bandwidth (in ISO allocation units).
739  *
740  * FIXME: As in libiec61883, channel 63 is not requested; this is either a
741  * bug or it's omitted since that's the channel preferred by video devices.
742  *
743  * @param bandwidth the bandwidth to allocate for this channel
744  * @return the channel number
745  */
746 signed int Ieee1394Service::allocateIsoChannelGeneric(unsigned int bandwidth) {
747     debugOutput(DEBUG_LEVEL_VERBOSE, "Allocating ISO channel using generic method...\n" );
748
749     Util::MutexLockHelper lock(*m_handle_lock);
750     struct ChannelInfo cinfo;
751
752     int c = -1;
753     for (c = 0; c < 63; c++) {
754         if (raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_ALLOC) == 0)
755             break;
756     }
757     if (c < 63) {
758         if (raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_ALLOC) < 0) {
759             debugFatal("Could not allocate bandwidth of %d\n", bandwidth);
760
761             raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE);
762             return -1;
763         } else {
764             cinfo.channel=c;
765             cinfo.bandwidth=bandwidth;
766             cinfo.alloctype=AllocGeneric;
767
768             cinfo.xmit_node=-1;
769             cinfo.xmit_plug=-1;
770             cinfo.recv_node=-1;
771             cinfo.recv_plug=-1;
772
773             if (registerIsoChannel(c, cinfo)) {
774                 return c;
775             } else {
776                 raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_FREE);
777                 raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE);
778                 return -1;
779             }
780         }
781     }
782     return -1;
783 }
784
785 /**
786  * Allocates an iso channel for use by the interface in a similar way to
787  * libiec61883.  Returns -1 on error (due to there being no free channels)
788  * or an allocated channel number.
789  *
790  * Uses IEC61883 Connection Management Procedure to establish the connection.
791  *
792  * Also allocates the necessary bandwidth (in ISO allocation units).
793  *
794  * @param xmit_node  node id of the transmitter
795  * @param xmit_plug  the output plug to use. If -1, find the first online plug, and
796  * upon return, contains the plug number used.
797  * @param recv_node  node id of the receiver
798  * @param recv_plug the input plug to use. If -1, find the first online plug, and
799  * upon return, contains the plug number used.
800  *
801  * @return the channel number
802  */
803
804 signed int Ieee1394Service::allocateIsoChannelCMP(
805     nodeid_t xmit_node, int xmit_plug,
806     nodeid_t recv_node, int recv_plug
807     ) {
808
809     if (xmit_node == INVALID_NODE_ID) {
810         debugWarning("operation on invalid node (XMIT)\n");
811         return -1;
812     }
813     if (recv_node == INVALID_NODE_ID) {
814         debugWarning("operation on invalid node (RECV)\n");
815         return -1;
816     }
817
818     debugOutput(DEBUG_LEVEL_VERBOSE, "Allocating ISO channel using IEC61883 CMP...\n" );
819     Util::MutexLockHelper lock(*m_handle_lock);
820
821     struct ChannelInfo cinfo;
822
823     int c = -1;
824     int bandwidth=1;
825     #if IEEE1394SERVICE_SKIP_IEC61883_BANDWIDTH_ALLOCATION
826     bandwidth=0;
827     #endif
828
829     // do connection management: make connection
830     c = iec61883_cmp_connect(
831         m_handle,
832         xmit_node | 0xffc0,
833         &xmit_plug,
834         recv_node | 0xffc0,
835         &recv_plug,
836         &bandwidth);
837
838     if((c<0) || (c>63)) {
839         debugError("Could not do CMP from %04X:%02d to %04X:%02d\n",
840             xmit_node, xmit_plug, recv_node, recv_plug
841             );
842         return -1;
843     }
844
845     cinfo.channel=c;
846     cinfo.bandwidth=bandwidth;
847     cinfo.alloctype=AllocCMP;
848
849     cinfo.xmit_node=xmit_node;
850     cinfo.xmit_plug=xmit_plug;
851     cinfo.recv_node=recv_node;
852     cinfo.recv_plug=recv_plug;
853
854     if (registerIsoChannel(c, cinfo)) {
855         return c;
856     }
857
858     return -1;
859 }
860
861 /**
862  * Deallocates an iso channel.  Silently ignores a request to deallocate
863  * a negative channel number.
864  *
865  * Figures out the method that was used to allocate the channel (generic, cmp, ...)
866  * and uses the appropriate method to deallocate. Also frees the bandwidth
867  * that was reserved along with this channel.
868  *
869  * @param c channel number
870  * @return true if successful
871  */
872 bool Ieee1394Service::freeIsoChannel(signed int c) {
873     debugOutput(DEBUG_LEVEL_VERBOSE, "Freeing ISO channel %d...\n", c );
874     Util::MutexLockHelper lock(*m_handle_lock);
875
876     if (c < 0 || c > 63) {
877         debugWarning("Invalid channel number: %d\n", c);
878         return false;
879     }
880
881     switch (m_channels[c].alloctype) {
882         default:
883             debugError(" BUG: invalid allocation type!\n");
884             return false;
885
886         case AllocFree:
887             debugWarning(" Channel %d not registered\n", c);
888             return false;
889
890         case AllocGeneric:
891             debugOutput(DEBUG_LEVEL_VERBOSE, " allocated using generic routine...\n" );
892             debugOutput(DEBUG_LEVEL_VERBOSE, " freeing %d bandwidth units...\n", m_channels[c].bandwidth );
893             if (raw1394_bandwidth_modify(m_handle, m_channels[c].bandwidth, RAW1394_MODIFY_FREE) !=0) {
894                 debugWarning("Failed to deallocate bandwidth\n");
895             }
896             debugOutput(DEBUG_LEVEL_VERBOSE, " freeing channel %d...\n", m_channels[c].channel );
897             if (raw1394_channel_modify (m_handle, m_channels[c].channel, RAW1394_MODIFY_FREE) != 0) {
898                 debugWarning("Failed to free channel\n");
899             }
900             if (!unregisterIsoChannel(c))
901                 return false;
902             return true;
903
904         case AllocCMP:
905             debugOutput(DEBUG_LEVEL_VERBOSE, " allocated using IEC61883 CMP...\n" );
906             debugOutput(DEBUG_LEVEL_VERBOSE, " performing IEC61883 CMP disconnect...\n" );
907             if(iec61883_cmp_disconnect(
908                     m_handle,
909                     m_channels[c].xmit_node | 0xffc0,
910                     m_channels[c].xmit_plug,
911                     m_channels[c].recv_node | 0xffc0,
912                     m_channels[c].recv_plug,
913                     m_channels[c].channel,
914                     m_channels[c].bandwidth) != 0) {
915                 debugWarning("Could not do CMP disconnect for channel %d!\n",c);
916             }
917             if (!unregisterIsoChannel(c))
918                 return false;
919             return true;
920     }
921
922     // unreachable
923     debugError("BUG: unreachable code reached!\n");
924
925     return false;
926 }
927
928 /**
929  * Registers a channel as managed by this ieee1394service
930  * @param c channel number
931  * @param cinfo channel info struct
932  * @return true if successful
933  */
934 bool Ieee1394Service::registerIsoChannel(unsigned int c, struct ChannelInfo cinfo) {
935     if (c < 63) {
936         if (m_channels[c].alloctype != AllocFree) {
937             debugWarning("Channel %d already registered with bandwidth %d\n",
938                 m_channels[c].channel, m_channels[c].bandwidth);
939         }
940
941         memcpy(&m_channels[c], &cinfo, sizeof(struct ChannelInfo));
942
943     } else return false;
944     return true;
945 }
946
947 /**
948  * unegisters a channel from this ieee1394service
949  * @param c channel number
950  * @return true if successful
951  */
952 bool Ieee1394Service::unregisterIsoChannel(unsigned int c) {
953     if (c < 63) {
954         if (m_channels[c].alloctype == AllocFree) {
955             debugWarning("Channel %d not registered\n", c);
956             return false;
957         }
958
959         m_channels[c].channel=-1;
960         m_channels[c].bandwidth=-1;
961         m_channels[c].alloctype=AllocFree;
962         m_channels[c].xmit_node=0xFFFF;
963         m_channels[c].xmit_plug=-1;
964         m_channels[c].recv_node=0xFFFF;
965         m_channels[c].recv_plug=-1;
966
967     } else return false;
968     return true;
969 }
970
971 /**
972  * Returns the current value of the `bandwidth available' register on
973  * the IRM, or -1 on error.
974  * @return
975  */
976 signed int Ieee1394Service::getAvailableBandwidth() {
977     quadlet_t buffer;
978     Util::MutexLockHelper lock(*m_handle_lock);
979     signed int result = raw1394_read (m_handle, raw1394_get_irm_id (m_handle),
980         CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE,
981         sizeof (quadlet_t), &buffer);
982
983     if (result < 0)
984         return -1;
985     return CondSwapFromBus32(buffer);
986 }
987
988 void
989 Ieee1394Service::setVerboseLevel(int l)
990 {
991     if (m_pIsoManager) m_pIsoManager->setVerboseLevel(l);
992     if (m_pCTRHelper) m_pCTRHelper->setVerboseLevel(l);
993     if (m_pWatchdog) m_pWatchdog->setVerboseLevel(l);
994     setDebugLevel(l);
995     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
996 }
997
998 void
999 Ieee1394Service::show()
1000 {
1001     #ifdef DEBUG
1002     uint32_t cycle_timer;
1003     uint64_t local_time;
1004     if(!readCycleTimerReg(&cycle_timer, &local_time)) {
1005         debugWarning("Could not read cycle timer register\n");
1006    
1007     }
1008     uint64_t ctr = CYCLE_TIMER_TO_TICKS( cycle_timer );
1009
1010     debugOutput( DEBUG_LEVEL_VERBOSE, "Port:  %d\n", getPort() );
1011     debugOutput( DEBUG_LEVEL_VERBOSE, " Name: %s\n", getPortName().c_str() );
1012     debugOutput( DEBUG_LEVEL_VERBOSE, " CycleTimerHelper: %p, IsoManager: %p, WatchDog: %p\n",
1013                  m_pCTRHelper, m_pIsoManager, m_pWatchdog );
1014     debugOutput( DEBUG_LEVEL_VERBOSE, " Time: %011llu (%03us %04ucy %04uticks)\n",
1015                 ctr,
1016                 (unsigned int)TICKS_TO_SECS( ctr ),
1017                 (unsigned int)TICKS_TO_CYCLES( ctr ),
1018                 (unsigned int)TICKS_TO_OFFSET( ctr ) );
1019     debugOutputShort( DEBUG_LEVEL_NORMAL, "Iso handler info:\n");
1020     #endif
1021     if (m_pIsoManager) m_pIsoManager->dumpInfo();
1022 }
Note: See TracBrowser for help on using the browser.