root/trunk/libffado/src/libieee1394/IsoHandlerManager.cpp

Revision 864, 21.3 kB (checked in by ppalmers, 13 years ago)

update license to GPLv2 or GPLv3 instead of GPLv2 or any later version. Update copyrights to reflect the new year

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
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.
13  *
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.
18  *
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/>.
21  *
22  */
23
24 #include "config.h"
25 #include "IsoHandlerManager.h"
26 #include "ieee1394service.h"
27 #include "IsoHandler.h"
28 #include "libstreaming/generic/StreamProcessor.h"
29
30 #include "libutil/Atomic.h"
31
32 #include "libutil/PosixThread.h"
33
34 #include <assert.h>
35
36 IMPL_DEBUG_MODULE( IsoHandlerManager, IsoHandlerManager, DEBUG_LEVEL_NORMAL );
37
38 using namespace Streaming;
39
40 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service)
41    : m_State(E_Created)
42    , m_service( service )
43    , m_realtime(false), m_priority(0)
44    , m_Thread ( NULL )
45 {}
46
47 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio)
48    : m_State(E_Created)
49    , m_service( service )
50    , m_realtime(run_rt), m_priority(rt_prio)
51    , m_Thread ( NULL )
52 {}
53
54 IsoHandlerManager::~IsoHandlerManager()
55 {
56     stopHandlers();
57     pruneHandlers();
58     if(m_IsoHandlers.size() > 0) {
59         debugError("Still some handlers in use\n");
60     }
61     if (m_Thread) {
62         m_Thread->Stop();
63         delete m_Thread;
64     }
65 }
66
67 bool
68 IsoHandlerManager::setThreadParameters(bool rt, int priority) {
69     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) switch to: (rt=%d, prio=%d)...\n", this, rt, priority);
70     if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO; // cap the priority
71     m_realtime = rt;
72     m_priority = priority;
73     bool result = true;
74     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
75         it != m_IsoHandlers.end();
76         ++it )
77     {
78         result &= (*it)->setThreadParameters(m_realtime, m_priority);
79     }
80
81     if (m_Thread) {
82         if (m_realtime) {
83             m_Thread->AcquireRealTime(m_priority);
84         } else {
85             m_Thread->DropRealTime();
86         }
87     }
88
89     return result;
90 }
91
92 /**
93  * Update the shadow variables. Should only be called from
94  * the iso handler iteration thread
95  */
96 void
97 IsoHandlerManager::updateShadowVars()
98 {
99     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "updating shadow vars...\n");
100     unsigned int i, cnt, max;
101     max = m_IsoHandlers.size();
102     for (i = 0, cnt = 0; i < max; i++) {
103         IsoHandler *h = m_IsoHandlers.at(i);
104         assert(h);
105         if (h->isEnabled()) {
106             // receive handlers are always poll'ed
107             // transmit handlers only when the client is ready
108             if (h->getType() == IsoHandler::eHT_Receive || h->tryWaitForClient()) {
109                 m_IsoHandler_map_shadow[cnt] = h;
110                 m_poll_fds_shadow[cnt].fd = h->getFileDescriptor();
111                 m_poll_fds_shadow[cnt].revents = 0;
112                 m_poll_fds_shadow[cnt].events = POLLIN;
113                 cnt++;
114             } else {
115                 debugOutput(DEBUG_LEVEL_VERBOSE, "skipped handler %p\n", h);
116             }
117         }
118         if(cnt > ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT) {
119             debugWarning("Too much ISO Handlers in manager...\n");
120             break;
121         }
122     }
123     m_poll_nfds_shadow = cnt;
124     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " updated shadow vars...\n");
125 }
126
127 bool
128 IsoHandlerManager::Init() {
129     debugOutput( DEBUG_LEVEL_VERBOSE, "%p: Init thread...\n", this);
130     bool result = true;
131     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
132         it != m_IsoHandlers.end();
133         ++it )
134     {
135         result &= (*it)->Init();
136     }
137     return result;
138 }
139
140 bool
141 IsoHandlerManager::Execute() {
142     int err;
143     unsigned int i;
144
145     unsigned int m_poll_timeout = 100;
146
147     updateShadowVars();
148     // bypass if no handlers are registered
149     if (m_poll_nfds_shadow == 0) {
150         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "bypass iterate since no handlers to poll\n");
151         usleep(m_poll_timeout * 1000);
152         return true;
153     }
154
155     // Use a shadow map of the fd's such that the poll call is not in a critical section
156     uint64_t poll_enter = m_service.getCurrentTimeAsUsecs();
157     err = poll (m_poll_fds_shadow, m_poll_nfds_shadow, m_poll_timeout);
158     uint64_t poll_exit = m_service.getCurrentTimeAsUsecs();
159
160     if (err == -1) {
161         if (errno == EINTR) {
162             return true;
163         }
164         debugFatal("poll error: %s\n", strerror (errno));
165         return false;
166     }
167
168     int nb_rcv = 0;
169     int nb_xmit = 0;
170     uint64_t iter_enter = m_service.getCurrentTimeAsUsecs();
171     for (i = 0; i < m_poll_nfds_shadow; i++) {
172         if(m_poll_fds_shadow[i].revents) {
173             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "received events: %08X for (%p)\n",
174                 m_poll_fds_shadow[i].revents, m_IsoHandler_map_shadow[i]);
175         }
176         if (m_poll_fds_shadow[i].revents & POLLERR) {
177             debugWarning("error on fd for %d\n",i);
178         }
179
180         if (m_poll_fds_shadow[i].revents & POLLHUP) {
181             debugWarning("hangup on fd for %d\n",i);
182         }
183
184         if(m_poll_fds_shadow[i].revents & (POLLIN)) {
185             if (m_IsoHandler_map_shadow[i]->getType() == IsoHandler::eHT_Receive) {
186                 m_IsoHandler_map_shadow[i]->iterate();
187                 nb_rcv++;
188             } else {
189                 // only iterate the xmit handler if it makes sense
190                 if(m_IsoHandler_map_shadow[i]->tryWaitForClient()) {
191                     m_IsoHandler_map_shadow[i]->iterate();
192                     nb_xmit++;
193                 }
194             }
195         }
196     }
197     uint64_t iter_exit = m_service.getCurrentTimeAsUsecs();
198
199     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " poll took %6lldus, iterate took %6lldus, iterated (R: %2d, X: %2d) handlers\n",
200                 poll_exit-poll_enter, iter_exit-iter_enter,
201                 nb_rcv, nb_xmit);
202
203     return true;
204 }
205
206 bool IsoHandlerManager::init()
207 {
208     debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing ISO manager %p...\n", this);
209     // check state
210     if(m_State != E_Created) {
211         debugError("Manager already initialized...\n");
212         return false;
213     }
214
215 #if ISOHANDLER_PER_HANDLER_THREAD
216     // the IsoHandlers will create their own thread.
217 #else
218     // create a thread to iterate our handlers
219     debugOutput( DEBUG_LEVEL_VERBOSE, "Start thread for %p...\n", this);
220     m_Thread = new Util::PosixThread(this, m_realtime, m_priority,
221                                      PTHREAD_CANCEL_DEFERRED);
222     if(!m_Thread) {
223         debugFatal("No thread\n");
224         return false;
225     }
226     if (m_Thread->Start() != 0) {
227         debugFatal("Could not start update thread\n");
228         return false;
229     }
230 #endif
231
232     m_State=E_Running;
233     return true;
234 }
235
236 bool
237 IsoHandlerManager::disable(IsoHandler *h) {
238     bool result;
239     int i=0;
240     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Disable on IsoHandler %p\n", h);
241     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
242         it != m_IsoHandlers.end();
243         ++it )
244     {
245         if ((*it) == h) {
246             result = h->disable();
247             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " disabled\n");
248             return result;
249         }
250         i++;
251     }
252     debugError("Handler not found\n");
253     return false;
254 }
255
256 bool
257 IsoHandlerManager::enable(IsoHandler *h) {
258     bool result;
259     int i=0;
260     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Enable on IsoHandler %p\n", h);
261     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
262         it != m_IsoHandlers.end();
263         ++it )
264     {
265         if ((*it) == h) {
266             result = h->enable();
267             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " enabled\n");
268             return result;
269         }
270         i++;
271     }
272     debugError("Handler not found\n");
273     return false;
274 }
275
276 bool IsoHandlerManager::registerHandler(IsoHandler *handler)
277 {
278     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
279     assert(handler);
280     handler->setVerboseLevel(getDebugLevel());
281     m_IsoHandlers.push_back(handler);
282     updateShadowVars();
283     return true;
284 }
285
286 bool IsoHandlerManager::unregisterHandler(IsoHandler *handler)
287 {
288     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
289     assert(handler);
290
291     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
292       it != m_IsoHandlers.end();
293       ++it )
294     {
295         if ( *it == handler ) {
296             m_IsoHandlers.erase(it);
297             updateShadowVars();
298             return true;
299         }
300     }
301     debugFatal("Could not find handler (%p)\n", handler);
302     return false; //not found
303 }
304
305 /**
306  * Registers an StreamProcessor with the IsoHandlerManager.
307  *
308  * If nescessary, an IsoHandler is created to handle this stream.
309  * Once an StreamProcessor is registered to the handler, it will be included
310  * in the ISO streaming cycle (i.e. receive/transmit of it will occur).
311  *
312  * @param stream the stream to register
313  * @return true if registration succeeds
314  *
315  * \todo : currently there is a one-to-one mapping
316  *        between streams and handlers, this is not ok for
317  *        multichannel receive
318  */
319 bool IsoHandlerManager::registerStream(StreamProcessor *stream)
320 {
321     debugOutput( DEBUG_LEVEL_VERBOSE, "Registering stream %p\n",stream);
322     assert(stream);
323
324     IsoHandler* h = NULL;
325
326     // make sure the stream isn't already attached to a handler
327     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
328       it != m_IsoHandlers.end();
329       ++it )
330     {
331         if((*it)->isStreamRegistered(stream)) {
332             debugError( "stream already registered!\n");
333             return false;
334         }
335     }
336
337     // clean up all handlers that aren't used
338     pruneHandlers();
339
340     // allocate a handler for this stream
341     if (stream->getType()==StreamProcessor::ePT_Receive) {
342         // setup the optimal parameters for the raw1394 ISO buffering
343         unsigned int packets_per_period = stream->getPacketsPerPeriod();
344         unsigned int max_packet_size = stream->getMaxPacketSize();
345         unsigned int page_size = getpagesize() - 2; // for one reason or another this is necessary
346
347         // Ensure we don't request a packet size bigger than the
348         // kernel-enforced maximum which is currently 1 page.
349         if (max_packet_size > page_size) {
350             debugError("max packet size (%u) > page size (%u)\n", max_packet_size, page_size);
351             return false;
352         }
353
354         unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
355         if(irq_interval <= 0) irq_interval=1;
356        
357         // the receive buffer size doesn't matter for the latency,
358         // but it has a minimal value in order for libraw to operate correctly (300)
359         int buffers=400;
360
361         // create the actual handler
362         h = new IsoHandler(*this, IsoHandler::eHT_Receive,
363                            buffers, max_packet_size, irq_interval);
364
365         debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoRecvHandler\n");
366
367         if(!h) {
368             debugFatal("Could not create IsoRecvHandler\n");
369             return false;
370         }
371
372     } else if (stream->getType()==StreamProcessor::ePT_Transmit) {
373         // setup the optimal parameters for the raw1394 ISO buffering
374         unsigned int packets_per_period = stream->getPacketsPerPeriod();
375         unsigned int max_packet_size = stream->getMaxPacketSize();
376         unsigned int page_size = getpagesize();
377
378         // Ensure we don't request a packet size bigger than the
379         // kernel-enforced maximum which is currently 1 page.
380         if (max_packet_size > page_size) {
381             debugError("max packet size (%u) > page size (%u)\n", max_packet_size, page_size);
382             return false;
383         }
384
385         //max_packet_size = page_size; // HACK
386         unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
387         if(irq_interval <= 0) irq_interval=1;
388
389         // the SP specifies how many packets to ISO-buffer
390         int buffers = stream->getNbPacketsIsoXmitBuffer();
391
392         debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoXmitHandler\n");
393
394         // create the actual handler
395         h = new IsoHandler(*this, IsoHandler::eHT_Transmit,
396                            buffers, max_packet_size, irq_interval);
397
398         if(!h) {
399             debugFatal("Could not create IsoXmitHandler\n");
400             return false;
401         }
402
403     } else {
404         debugFatal("Bad stream type\n");
405         return false;
406     }
407
408     h->setVerboseLevel(getDebugLevel());
409
410     // init the handler
411     if(!h->init()) {
412         debugFatal("Could not initialize receive handler\n");
413         return false;
414     }
415
416     // set the handler's thread parameters
417     // receive handlers have lower priority than the client thread
418     // since they have ISO side buffering
419     // xmit handlers have higher priority since we want client side
420     // frames to be put into the ISO buffers ASAP
421     int thread_prio;
422     if (stream->getType()==StreamProcessor::ePT_Receive) {
423         thread_prio = m_priority - 1;
424         if (thread_prio < THREAD_MIN_RTPRIO) thread_prio = THREAD_MIN_RTPRIO;
425     } else {
426         thread_prio = m_priority + 1;
427         if (thread_prio > THREAD_MAX_RTPRIO) thread_prio = THREAD_MAX_RTPRIO;
428     }
429
430     if(!h->setThreadParameters(m_realtime, thread_prio)) {
431         debugFatal("Could not set handler thread parameters\n");
432         return false;
433     }
434
435     // register the stream with the handler
436     if(!h->registerStream(stream)) {
437         debugFatal("Could not register receive stream with handler\n");
438         return false;
439     }
440
441     // register the handler with the manager
442     if(!registerHandler(h)) {
443         debugFatal("Could not register receive handler with manager\n");
444         return false;
445     }
446     debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n", stream, h);
447
448     m_StreamProcessors.push_back(stream);
449     debugOutput( DEBUG_LEVEL_VERBOSE, " %d streams, %d handlers registered\n",
450                                       m_StreamProcessors.size(), m_IsoHandlers.size());
451     return true;
452 }
453
454 bool IsoHandlerManager::unregisterStream(StreamProcessor *stream)
455 {
456     debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering stream %p\n",stream);
457     assert(stream);
458
459     // make sure the stream isn't attached to a handler anymore
460     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
461       it != m_IsoHandlers.end();
462       ++it )
463     {
464         if((*it)->isStreamRegistered(stream)) {
465             if(!(*it)->unregisterStream(stream)) {
466                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not unregister stream (%p) from handler (%p)...\n",stream,*it);
467                 return false;
468             }
469             debugOutput( DEBUG_LEVEL_VERBOSE, " unregistered stream (%p) from handler (%p)...\n",stream,*it);
470         }
471     }
472
473     // clean up all handlers that aren't used
474     pruneHandlers();
475
476     // remove the stream from the registered streams list
477     for ( StreamProcessorVectorIterator it = m_StreamProcessors.begin();
478       it != m_StreamProcessors.end();
479       ++it )
480     {
481         if ( *it == stream ) {
482             m_StreamProcessors.erase(it);
483             debugOutput( DEBUG_LEVEL_VERBOSE, " deleted stream (%p) from list...\n", *it);
484             return true;
485         }
486     }
487     return false; //not found
488 }
489
490 /**
491  * @brief unregister a handler from the manager
492  * @note called without the lock held.
493  */
494 void IsoHandlerManager::pruneHandlers() {
495     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
496     IsoHandlerVector toUnregister;
497
498     // find all handlers that are not in use
499     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
500           it != m_IsoHandlers.end();
501           ++it )
502     {
503         if(!((*it)->inUse())) {
504             debugOutput( DEBUG_LEVEL_VERBOSE, " handler (%p) not in use\n",*it);
505             toUnregister.push_back(*it);
506         }
507     }
508     // delete them
509     for ( IsoHandlerVectorIterator it = toUnregister.begin();
510           it != toUnregister.end();
511           ++it )
512     {
513         unregisterHandler(*it);
514
515         debugOutput( DEBUG_LEVEL_VERBOSE, " deleting handler (%p)\n",*it);
516
517         // Now the handler's been unregistered it won't be reused
518         // again.  Therefore it really needs to be formally deleted
519         // to free up the raw1394 handle.  Otherwise things fall
520         // apart after several xrun recoveries as the system runs
521         // out of resources to support all the disused but still
522         // allocated raw1394 handles.  At least this is the current
523         // theory as to why we end up with "memory allocation"
524         // failures after several Xrun recoveries.
525         delete *it;
526     }
527 }
528
529 bool
530 IsoHandlerManager::stopHandlerForStream(Streaming::StreamProcessor *stream) {
531     // check state
532     if(m_State != E_Running) {
533         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
534         return false;
535     }
536     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
537       it != m_IsoHandlers.end();
538       ++it )
539     {
540         if((*it)->isStreamRegistered(stream)) {
541             bool result;
542             debugOutput( DEBUG_LEVEL_VERBOSE, " stopping handler %p for stream %p\n", *it, stream);
543             result = (*it)->disable();
544             if(!result) {
545                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not disable handler (%p)\n",*it);
546                 return false;
547             }
548             return true;
549         }
550     }
551     debugError("Stream %p has no attached handler\n", stream);
552     return false;
553 }
554
555 int
556 IsoHandlerManager::getPacketLatencyForStream(Streaming::StreamProcessor *stream) {
557     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
558       it != m_IsoHandlers.end();
559       ++it )
560     {
561         if((*it)->isStreamRegistered(stream)) {
562             return (*it)->getPacketLatency();
563         }
564     }
565     debugError("Stream %p has no attached handler\n", stream);
566     return 0;
567 }
568
569 void
570 IsoHandlerManager::flushHandlerForStream(Streaming::StreamProcessor *stream) {
571     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
572       it != m_IsoHandlers.end();
573       ++it )
574     {
575         if((*it)->isStreamRegistered(stream)) {
576             return (*it)->flush();
577         }
578     }
579     debugError("Stream %p has no attached handler\n", stream);
580     return;
581 }
582
583 bool
584 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream) {
585     return startHandlerForStream(stream, -1);
586 }
587
588 bool
589 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream, int cycle) {
590     // check state
591     if(m_State != E_Running) {
592         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
593         return false;
594     }
595     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
596       it != m_IsoHandlers.end();
597       ++it )
598     {
599         if((*it)->isStreamRegistered(stream)) {
600             bool result;
601             debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler %p for stream %p\n", *it, stream);
602             result = (*it)->enable(cycle);
603             if(!result) {
604                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not enable handler (%p)\n",*it);
605                 return false;
606             }
607             return true;
608         }
609     }
610     debugError("Stream %p has no attached handler\n", stream);
611     return false;
612 }
613
614 bool IsoHandlerManager::stopHandlers() {
615     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
616
617     // check state
618     if(m_State != E_Running) {
619         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
620         return false;
621     }
622
623     bool retval=true;
624
625     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
626         it != m_IsoHandlers.end();
627         ++it )
628     {
629         debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping handler (%p)\n",*it);
630         if(!(*it)->disable()){
631             debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it);
632             retval=false;
633         }
634     }
635
636     if (retval) {
637         m_State=E_Prepared;
638     } else {
639         m_State=E_Error;
640     }
641     return retval;
642 }
643
644 bool IsoHandlerManager::reset() {
645     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
646     // check state
647     if(m_State == E_Error) {
648         debugFatal("Resetting from error condition not yet supported...\n");
649         return false;
650     }
651     // if not in an error condition, reset means stop the handlers
652     return stopHandlers();
653 }
654
655 void IsoHandlerManager::setVerboseLevel(int i) {
656     setDebugLevel(i);
657     // propagate the debug level
658     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
659           it != m_IsoHandlers.end();
660           ++it )
661     {
662         (*it)->setVerboseLevel(i);
663     }
664 }
665
666 void IsoHandlerManager::dumpInfo() {
667     int i=0;
668     debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n");
669     debugOutputShort( DEBUG_LEVEL_NORMAL, " State: %d\n",(int)m_State);
670
671     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
672           it != m_IsoHandlers.end();
673           ++it )
674     {
675         debugOutputShort( DEBUG_LEVEL_NORMAL, " IsoHandler %d (%p)\n",i++,*it);
676         (*it)->dumpInfo();
677     }
678 }
679
680 const char *
681 IsoHandlerManager::eHSToString(enum eHandlerStates s) {
682     switch (s) {
683         default: return "Invalid";
684         case E_Created: return "Created";
685         case E_Prepared: return "Prepared";
686         case E_Running: return "Running";
687         case E_Error: return "Error";
688     }
689 }
Note: See TracBrowser for help on using the browser.