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

Revision 1526, 25.7 kB (checked in by ppalmers, 12 years ago)

fix the freewheeling issue. clean up the IsoHandler? and the interactions with the Manager.

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
26 #include "IsoHandler.h"
27 #include "ieee1394service.h"
28 #include "IsoHandlerManager.h"
29
30 #include "cycletimer.h"
31
32 #include "libstreaming/generic/StreamProcessor.h"
33 #include "libutil/PosixThread.h"
34
35 #include <errno.h>
36 #include "libutil/ByteSwap.h"
37 #include <assert.h>
38 #include <unistd.h>
39 #include <string.h>
40
41 #include <iostream>
42 using namespace std;
43 using namespace Streaming;
44
45 IMPL_DEBUG_MODULE( IsoHandler, IsoHandler, DEBUG_LEVEL_NORMAL );
46
47 /* the C callbacks */
48 enum raw1394_iso_disposition
49 IsoHandler::iso_transmit_handler(raw1394handle_t handle,
50         unsigned char *data, unsigned int *length,
51         unsigned char *tag, unsigned char *sy,
52         int cycle, unsigned int dropped1) {
53
54     IsoHandler *xmitHandler = static_cast<IsoHandler *>(raw1394_get_userdata(handle));
55     assert(xmitHandler);
56     unsigned int skipped = (dropped1 & 0xFFFF0000) >> 16;
57     unsigned int dropped = dropped1 & 0xFFFF;
58     return xmitHandler->getPacket(data, length, tag, sy, cycle, dropped, skipped);
59 }
60
61 enum raw1394_iso_disposition
62 IsoHandler::iso_receive_handler(raw1394handle_t handle, unsigned char *data,
63                         unsigned int length, unsigned char channel,
64                         unsigned char tag, unsigned char sy, unsigned int cycle,
65                         unsigned int dropped) {
66
67     IsoHandler *recvHandler = static_cast<IsoHandler *>(raw1394_get_userdata(handle));
68     assert(recvHandler);
69
70     return recvHandler->putPacket(data, length, channel, tag, sy, cycle, dropped);
71 }
72
73 IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t)
74    : m_manager( manager )
75    , m_type ( t )
76    , m_handle( NULL )
77    , m_buf_packets( 400 )
78    , m_max_packet_size( 1024 )
79    , m_irq_interval( -1 )
80    , m_last_cycle( -1 )
81    , m_last_now( 0xFFFFFFFF )
82    , m_last_packet_handled_at( 0xFFFFFFFF )
83    , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER )
84    , m_Client( 0 )
85    , m_speed( RAW1394_ISO_SPEED_400 )
86    , m_prebuffers( 0 )
87    , m_dont_exit_iterate_loop( true )
88    , m_State( eHS_Stopped )
89    , m_NextState( eHS_Stopped )
90    , m_switch_on_cycle(0)
91 #ifdef DEBUG
92    , m_packets ( 0 )
93    , m_dropped( 0 )
94    , m_skipped( 0 )
95    , m_min_ahead( 7999 )
96 #endif
97 {
98 }
99
100 IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t,
101                        unsigned int buf_packets, unsigned int max_packet_size, int irq)
102    : m_manager( manager )
103    , m_type ( t )
104    , m_handle( NULL )
105    , m_buf_packets( buf_packets )
106    , m_max_packet_size( max_packet_size )
107    , m_irq_interval( irq )
108    , m_last_cycle( -1 )
109    , m_last_now( 0xFFFFFFFF )
110    , m_last_packet_handled_at( 0xFFFFFFFF )
111    , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER )
112    , m_Client( 0 )
113    , m_speed( RAW1394_ISO_SPEED_400 )
114    , m_prebuffers( 0 )
115    , m_State( eHS_Stopped )
116    , m_NextState( eHS_Stopped )
117    , m_switch_on_cycle(0)
118 #ifdef DEBUG
119    , m_packets ( 0 )
120    , m_dropped( 0 )
121    , m_skipped( 0 )
122    , m_min_ahead( 7999 )
123 #endif
124 {
125 }
126
127 IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t, unsigned int buf_packets,
128                        unsigned int max_packet_size, int irq,
129                        enum raw1394_iso_speed speed)
130    : m_manager( manager )
131    , m_type ( t )
132    , m_handle( NULL )
133    , m_buf_packets( buf_packets )
134    , m_max_packet_size( max_packet_size )
135    , m_irq_interval( irq )
136    , m_last_cycle( -1 )
137    , m_last_now( 0xFFFFFFFF )
138    , m_last_packet_handled_at( 0xFFFFFFFF )
139    , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER )
140    , m_Client( 0 )
141    , m_speed( speed )
142    , m_prebuffers( 0 )
143    , m_State( eHS_Stopped )
144    , m_NextState( eHS_Stopped )
145    , m_switch_on_cycle(0)
146 #ifdef DEBUG
147    , m_packets( 0 )
148    , m_dropped( 0 )
149    , m_skipped( 0 )
150    , m_min_ahead( 7999 )
151 #endif
152 {
153 }
154
155 IsoHandler::~IsoHandler() {
156 // Don't call until libraw1394's raw1394_new_handle() function has been
157 // fixed to correctly initialise the iso_packet_infos field.  Bug is
158 // confirmed present in libraw1394 1.2.1.  In any case,
159 // raw1394_destroy_handle() will do any iso system shutdown required.
160 //     raw1394_iso_shutdown(m_handle);
161     if(m_handle) {
162         if (m_State == eHS_Running) {
163             debugError("BUG: Handler still running!\n");
164             disable();
165         }
166     }
167 }
168
169 bool
170 IsoHandler::canIterateClient()
171 {
172     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "checking...\n");
173     if(m_Client) {
174         bool result;
175
176         if (m_type == eHT_Receive) {
177             result = m_Client->canProducePacket();
178         } else {
179             result = m_Client->canConsumePacket();
180         }
181         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, " returns %d\n", result);
182         return result && (m_State != eHS_Error);
183     } else {
184         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, " no client\n");
185     }
186     return false;
187 }
188
189 bool
190 IsoHandler::iterate() {
191     return iterate(m_manager.get1394Service().getCycleTimer());
192 }
193
194 bool
195 IsoHandler::iterate(uint32_t cycle_timer_now) {
196     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "(%p, %s) Iterating ISO handler at %08X...\n",
197                        this, getTypeString(), cycle_timer_now);
198     m_last_now = cycle_timer_now;
199     if(m_State == eHS_Running) {
200         assert(m_handle);
201
202         #if ISOHANDLER_FLUSH_BEFORE_ITERATE
203         // this flushes all packets received since the poll() returned
204         // from kernel to userspace such that they are processed by this
205         // iterate. Doing so might result in lower latency capability
206         // and/or better reliability
207         if(m_type == eHT_Receive) {
208             raw1394_iso_recv_flush(m_handle);
209         }
210         #endif
211
212         if(raw1394_loop_iterate(m_handle)) {
213             debugError( "IsoHandler (%p): Failed to iterate handler: %s\n",
214                         this, strerror(errno));
215             return false;
216         }
217         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "(%p, %s) done interating ISO handler...\n",
218                            this, getTypeString());
219         return true;
220     } else {
221         debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) Not iterating a non-running handler...\n",
222                     this, getTypeString());
223         return false;
224     }
225 }
226
227 /**
228  * Bus reset handler
229  *
230  * @return ?
231  */
232
233 bool
234 IsoHandler::handleBusReset()
235 {
236     debugOutput( DEBUG_LEVEL_NORMAL, "bus reset...\n");
237     m_last_packet_handled_at = 0xFFFFFFFF;
238
239     #define CSR_CYCLE_TIME            0x200
240     #define CSR_REGISTER_BASE  0xfffff0000000ULL
241     // do a simple read on ourself in order to update the internal structures
242     // this avoids read failures after a bus reset
243     quadlet_t buf=0;
244     raw1394_read(m_handle, raw1394_get_local_id(m_handle),
245                  CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf);
246
247     return m_Client->handleBusReset();
248 }
249
250 /**
251  * Call this if you find out that this handler has died for some
252  * external reason.
253  */
254 void
255 IsoHandler::notifyOfDeath()
256 {
257     m_State = eHS_Error;
258     m_NextState = eHS_Error;
259
260     // notify the client of the fact that we have died
261     m_Client->handlerDied();
262
263     // wake ourselves up
264     raw1394_wake_up(m_handle);
265 }
266
267 void IsoHandler::dumpInfo()
268 {
269     int channel=-1;
270     if (m_Client) channel=m_Client->getChannel();
271
272     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Handler type................: %s\n",
273             getTypeString());
274     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Port, Channel...............: %2d, %2d\n",
275             m_manager.get1394Service().getPort(), channel);
276     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Buffer, MaxPacketSize, IRQ..: %4d, %4d, %4d\n",
277             m_buf_packets, m_max_packet_size, m_irq_interval);
278     if (this->getType() == eHT_Transmit) {
279         debugOutputShort( DEBUG_LEVEL_NORMAL, "  Speed, PreBuffers...........: %2d, %2d\n",
280                                             m_speed, m_prebuffers);
281         #ifdef DEBUG
282         debugOutputShort( DEBUG_LEVEL_NORMAL, "  Min ISOXMT bufferfill : %04d\n", m_min_ahead);
283         #endif
284     }
285     #ifdef DEBUG
286     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Last cycle, dropped.........: %4d, %4u, %4u\n",
287             m_last_cycle, m_dropped, m_skipped);
288     #endif
289
290 }
291
292 void IsoHandler::setVerboseLevel(int l)
293 {
294     setDebugLevel(l);
295     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
296 }
297
298 bool IsoHandler::registerStream(StreamProcessor *stream)
299 {
300     assert(stream);
301     debugOutput( DEBUG_LEVEL_VERBOSE, "registering stream (%p)\n", stream);
302
303     if (m_Client) {
304             debugFatal( "Generic IsoHandlers can have only one client\n");
305             return false;
306     }
307     m_Client=stream;
308     return true;
309 }
310
311 bool IsoHandler::unregisterStream(StreamProcessor *stream)
312 {
313     assert(stream);
314     debugOutput( DEBUG_LEVEL_VERBOSE, "unregistering stream (%p)\n", stream);
315
316     if(stream != m_Client) {
317             debugFatal( "no client registered\n");
318             return false;
319     }
320     m_Client=0;
321     return true;
322 }
323
324 // ISO packet interface
325 enum raw1394_iso_disposition IsoHandler::putPacket(
326                     unsigned char *data, unsigned int length,
327                     unsigned char channel, unsigned char tag, unsigned char sy,
328                     unsigned int cycle, unsigned int dropped) {
329     // keep track of dropped cycles
330     int dropped_cycles = 0;
331     if (m_last_cycle != (int)cycle && m_last_cycle != -1) {
332         dropped_cycles = diffCycles(cycle, m_last_cycle) - 1;
333         #ifdef DEBUG
334         if (dropped_cycles < 0) {
335             debugWarning("(%p) dropped < 1 (%d), cycle: %d, last_cycle: %d, dropped: %d\n",
336                          this, dropped_cycles, cycle, m_last_cycle, dropped);
337         }
338         if (dropped_cycles > 0) {
339             debugOutput(DEBUG_LEVEL_VERBOSE,
340                         "(%p) dropped %d packets on cycle %u, 'dropped'=%u, cycle=%d, m_last_cycle=%d\n",
341                         this, dropped_cycles, cycle, dropped, cycle, m_last_cycle);
342             m_dropped += dropped_cycles;
343         }
344         #endif
345     }
346     m_last_cycle = cycle;
347
348     // the m_last_now value is set when the iterate() function is called.
349     uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(m_last_now);
350
351     // two cases can occur:
352     // (1) this packet has been received before iterate() was called (normal case).
353     // (2) this packet has been received after iterate() was called.
354     //     happens when the kernel flushes more packets while we are already processing.
355     //
356     // In case (1) now_cycles is a small number of cycles larger than cycle. In
357     // case (2) now_cycles is a small number of cycles smaller than cycle.
358     // hence  abs(diffCycles(now_cycles, cycles)) has to be 'small'
359
360     // we can calculate the time of arrival for this packet as
361     // 'now' + diffCycles(cycles, now_cycles) * TICKS_PER_CYCLE
362     // in its properly wrapped version
363     int64_t diff_cycles = diffCycles(cycle, now_cycles);
364     int64_t tmp = CYCLE_TIMER_TO_TICKS(m_last_now);
365     tmp += diff_cycles * (int64_t)TICKS_PER_CYCLE;
366     uint64_t pkt_ctr_ticks = wrapAtMinMaxTicks(tmp);
367     uint32_t pkt_ctr = TICKS_TO_CYCLE_TIMER(pkt_ctr_ticks);
368     #ifdef DEBUG
369     if( (now_cycles < cycle)
370         && diffCycles(now_cycles, cycle) < 0
371         // ignore this on dropped cycles, since it's normal
372         // that now is ahead on the received packets (as we miss packets)
373         && dropped_cycles == 0)
374     {
375         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Special non-unwrapping happened\n");
376     }
377     #endif
378
379     #if ISOHANDLER_CHECK_CTR_RECONSTRUCTION
380     // add a seconds field
381     uint32_t now = m_manager.get1394Service().getCycleTimer();
382     uint32_t now_secs_ref = CYCLE_TIMER_GET_SECS(now);
383     // causality results in the fact that 'now' is always after 'cycle'
384     // or at best, equal (if this handler was called within 125us after
385     // the packet was on the wire).
386     if(CYCLE_TIMER_GET_CYCLES(now) < cycle) {
387         // the cycle field has wrapped, substract one second
388         if(now_secs_ref == 0) {
389             now_secs_ref = 127;
390         } else  {
391             now_secs_ref -= 1;
392         }
393     }
394     uint32_t pkt_ctr_ref = cycle << 12;
395     pkt_ctr_ref |= (now_secs_ref & 0x7F) << 25;
396
397     if((pkt_ctr & ~0x0FFFL) != pkt_ctr_ref) {
398         debugWarning("reconstructed CTR counter discrepancy\n");
399         debugWarning(" ingredients: %X, %lX, %lX, %lX, %lX, %ld, %ld, %ld, %lld\n",
400                        cycle, pkt_ctr_ref, pkt_ctr, now, m_last_now, now_secs_ref, CYCLE_TIMER_GET_SECS(now), CYCLE_TIMER_GET_SECS(m_last_now), tmp);
401         debugWarning(" diffcy = %ld \n", diff_cycles);
402     }
403     #endif
404     m_last_packet_handled_at = pkt_ctr;
405
406     // leave the offset field (for now?)
407
408     debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE,
409                 "received packet: length=%d, channel=%d, cycle=%d, at %08X\n",
410                 length, channel, cycle, pkt_ctr);
411     m_packets++;
412     #ifdef DEBUG
413     if (length > m_max_packet_size) {
414         debugWarning("(%p, %s) packet too large: len=%u max=%u\n",
415                      this, getTypeString(), length, m_max_packet_size);
416     }
417     if(m_last_cycle == -1) {
418         debugOutput(DEBUG_LEVEL_VERBOSE, "Handler for %s SP %p is alive (cycle = %u)\n", getTypeString(), this, cycle);
419     }
420     #endif
421
422     // iterate the client if required
423     if(m_Client) {
424         enum raw1394_iso_disposition retval = m_Client->putPacket(data, length, channel, tag, sy, pkt_ctr, dropped_cycles);
425         if (retval == RAW1394_ISO_OK) {
426             if (m_dont_exit_iterate_loop) {
427                 return RAW1394_ISO_OK;
428             } else {
429                 m_dont_exit_iterate_loop = true;
430                 debugOutput(DEBUG_LEVEL_VERBOSE,
431                                 "(%p) loop exit requested\n",
432                                 this);
433                 return RAW1394_ISO_DEFER;
434             }
435         } else {
436             return retval;
437         }
438     }
439
440     return RAW1394_ISO_OK;
441 }
442
443 enum raw1394_iso_disposition
444 IsoHandler::getPacket(unsigned char *data, unsigned int *length,
445                       unsigned char *tag, unsigned char *sy,
446                       int cycle, unsigned int dropped, unsigned int skipped) {
447
448     uint32_t pkt_ctr;
449     if (cycle < 0) {
450         // mark invalid
451         pkt_ctr = 0xFFFFFFFF;
452     } else {
453         // the m_last_now value is set when the iterate() function is called.
454         uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(m_last_now);
455
456         // two cases can occur:
457         // (1) this packet has been received before iterate() was called (normal case).
458         // (2) this packet has been received after iterate() was called.
459         //     happens when the kernel flushes more packets while we are already processing.
460         //
461         // In case (1) now_cycles is a small number of cycles larger than cycle. In
462         // case (2) now_cycles is a small number of cycles smaller than cycle.
463         // hence  abs(diffCycles(now_cycles, cycles)) has to be 'small'
464
465         // we can calculate the time of arrival for this packet as
466         // 'now' + diffCycles(cycles, now_cycles) * TICKS_PER_CYCLE
467         // in its properly wrapped version
468         int64_t diff_cycles = diffCycles(cycle, now_cycles);
469         int64_t tmp = CYCLE_TIMER_TO_TICKS(m_last_now);
470         tmp += diff_cycles * (int64_t)TICKS_PER_CYCLE;
471         uint64_t pkt_ctr_ticks = wrapAtMinMaxTicks(tmp);
472         pkt_ctr = TICKS_TO_CYCLE_TIMER(pkt_ctr_ticks);
473
474         #if ISOHANDLER_CHECK_CTR_RECONSTRUCTION
475         // add a seconds field
476         uint32_t now = m_manager.get1394Service().getCycleTimer();
477         uint32_t now_secs_ref = CYCLE_TIMER_GET_SECS(now);
478         // causality results in the fact that 'now' is always after 'cycle'
479         if(CYCLE_TIMER_GET_CYCLES(now) > (unsigned int)cycle) {
480             // the cycle field has wrapped, add one second
481             now_secs_ref += 1;
482             // no need for this:
483             if(now_secs_ref == 128) {
484                now_secs_ref = 0;
485             }
486         }
487         uint32_t pkt_ctr_ref = cycle << 12;
488         pkt_ctr_ref |= (now_secs_ref & 0x7F) << 25;
489
490         if(((pkt_ctr & ~0x0FFFL) != pkt_ctr_ref) && (m_packets > m_buf_packets)) {
491             debugWarning("reconstructed CTR counter discrepancy\n");
492             debugWarning(" ingredients: %X, %lX, %lX, %lX, %lX, %ld, %ld, %ld, %lld\n",
493                         cycle, pkt_ctr_ref, pkt_ctr, now, m_last_now, now_secs_ref, CYCLE_TIMER_GET_SECS(now), CYCLE_TIMER_GET_SECS(m_last_now), tmp);
494             debugWarning(" diffcy = %ld \n", diff_cycles);
495         }
496         #endif
497     }
498     if (m_packets < m_buf_packets) { // these are still prebuffer packets
499         m_last_packet_handled_at = 0xFFFFFFFF;
500     } else {
501         m_last_packet_handled_at = pkt_ctr;
502     }
503     debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE,
504                 "sending packet: length=%d, cycle=%d, at %08X\n",
505                 *length, cycle, pkt_ctr);
506
507     m_packets++;
508
509     #ifdef DEBUG
510     if(m_last_cycle == -1) {
511         debugOutput(DEBUG_LEVEL_VERBOSE, "Handler for %s SP %p is alive (cycle = %d)\n", getTypeString(), this, cycle);
512     }
513     #endif
514
515     // keep track of dropped cycles
516     int dropped_cycles = 0;
517     if (m_last_cycle != cycle && m_last_cycle != -1) {
518         dropped_cycles = diffCycles(cycle, m_last_cycle) - 1;
519         // correct for skipped packets
520         // since those are not dropped, but only delayed
521         dropped_cycles -= skipped;
522
523         #ifdef DEBUG
524         if(skipped) {
525             debugOutput(DEBUG_LEVEL_VERBOSE,
526                         "(%p) skipped %d cycles, cycle: %d, last_cycle: %d, dropped: %d\n",
527                         this, skipped, cycle, m_last_cycle, dropped);
528             m_skipped += skipped;
529         }
530         if (dropped_cycles < 0) {
531             debugWarning("(%p) dropped < 1 (%d), cycle: %d, last_cycle: %d, dropped: %d, skipped: %d\n",
532                          this, dropped_cycles, cycle, m_last_cycle, dropped, skipped);
533         }
534         if (dropped_cycles > 0) {
535             debugOutput(DEBUG_LEVEL_VERBOSE,
536                         "(%p) dropped %d packets on cycle %u (last_cycle=%u, dropped=%d, skipped: %d)\n",
537                         this, dropped_cycles, cycle, m_last_cycle, dropped, skipped);
538             m_dropped += dropped_cycles - skipped;
539         }
540         #endif
541     }
542     if (cycle >= 0) {
543         m_last_cycle = cycle;
544        
545         #ifdef DEBUG
546 /*        int ahead = diffCycles(cycle, now_cycles);
547         if (ahead < m_min_ahead) m_min_ahead = ahead;
548 */
549         #endif
550     }
551
552     #ifdef DEBUG
553     if (dropped > 0) {
554         debugOutput(DEBUG_LEVEL_VERBOSE,
555                     "(%p) OHCI issue on cycle %u (dropped_cycles=%d, last_cycle=%u, dropped=%d, skipped: %d)\n",
556                     this, cycle, dropped_cycles, m_last_cycle, dropped, skipped);
557     }
558     #endif
559
560     if(m_Client) {
561         enum raw1394_iso_disposition retval;
562         retval = m_Client->getPacket(data, length, tag, sy, pkt_ctr, dropped_cycles, skipped, m_max_packet_size);
563         #ifdef DEBUG
564         if (*length > m_max_packet_size) {
565             debugWarning("(%p, %s) packet too large: len=%u max=%u\n",
566                          this, getTypeString(), *length, m_max_packet_size);
567         }
568         #endif
569         if (retval == RAW1394_ISO_OK) {
570             if (m_dont_exit_iterate_loop) {
571                 return RAW1394_ISO_OK;
572             } else {
573                 m_dont_exit_iterate_loop = true;
574                 debugOutput(DEBUG_LEVEL_VERBOSE,
575                                 "(%p) loop exit requested\n",
576                                 this);
577                 return RAW1394_ISO_DEFER;
578             }
579         } else {
580             return retval;
581         }
582     }
583
584     *tag = 0;
585     *sy = 0;
586     *length = 0;
587     return RAW1394_ISO_OK;
588 }
589
590 bool
591 IsoHandler::enable(int cycle)
592 {
593     debugOutput( DEBUG_LEVEL_VERBOSE, "start on cycle %d\n", cycle);
594
595     // check the state
596     if(m_State != eHS_Stopped) {
597         debugError("Incorrect state, expected eHS_Stopped, got %d\n",(int)m_State);
598         return false;
599     }
600
601     assert(m_handle == NULL);
602
603     // create a handle for the ISO traffic
604     m_handle = raw1394_new_handle_on_port( m_manager.get1394Service().getPort() );
605     if ( !m_handle ) {
606         if ( !errno ) {
607             debugError("libraw1394 not compatible\n");
608         } else {
609             debugError("Could not get 1394 handle: %s\n", strerror(errno) );
610             debugError("Are ieee1394 and raw1394 drivers loaded?\n");
611         }
612         return false;
613     }
614     raw1394_set_userdata(m_handle, static_cast<void *>(this));
615
616     // prepare the handler, allocate the resources
617     debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing iso handler (%p, client=%p)\n", this, m_Client);
618     dumpInfo();
619     if (getType() == eHT_Receive) {
620         if(raw1394_iso_recv_init(m_handle,
621                                 iso_receive_handler,
622                                 m_buf_packets,
623                                 m_max_packet_size,
624                                 m_Client->getChannel(),
625                                 m_receive_mode,
626                                 m_irq_interval)) {
627             debugFatal("Could not do receive initialisation!\n" );
628             debugFatal("  %s\n",strerror(errno));
629             return false;
630         }
631
632         if(raw1394_iso_recv_start(m_handle, cycle, -1, 0)) {
633             debugFatal("Could not start receive handler (%s)\n",strerror(errno));
634             dumpInfo();
635             return false;
636         }
637     } else {
638         if(raw1394_iso_xmit_init(m_handle,
639                                 iso_transmit_handler,
640                                 m_buf_packets,
641                                 m_max_packet_size,
642                                 m_Client->getChannel(),
643                                 m_speed,
644                                 m_irq_interval)) {
645             debugFatal("Could not do xmit initialisation!\n" );
646             return false;
647         }
648
649         if(raw1394_iso_xmit_start(m_handle, cycle, m_prebuffers)) {
650             debugFatal("Could not start xmit handler (%s)\n",strerror(errno));
651             dumpInfo();
652             return false;
653         }
654     }
655
656 #ifdef DEBUG
657     m_min_ahead = 7999;
658 #endif
659
660     m_packets = 0;
661
662     // indicate that the first iterate() still has to occur.
663     m_last_now = 0xFFFFFFFF;
664     m_last_packet_handled_at = 0xFFFFFFFF;
665
666     m_State = eHS_Running;
667     m_NextState = eHS_Running;
668     return true;
669 }
670
671 bool
672 IsoHandler::disable()
673 {
674     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p, %s) enter...\n",
675                  this, (m_type==eHT_Receive?"Receive":"Transmit"));
676
677     // check state
678     if(m_State != eHS_Running) {
679         debugError("Incorrect state, expected eHS_Running, got %d\n",(int)m_State);
680         return false;
681     }
682
683     assert(m_handle != NULL);
684
685     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p, %s) wake up handle...\n",
686                  this, (m_type==eHT_Receive?"Receive":"Transmit"));
687
688     // wake up any waiting reads/polls
689     raw1394_wake_up(m_handle);
690
691     // this is put here to try and avoid the
692     // Runaway context problem
693     // don't know if it will help though.
694 /*    if(m_State != eHS_Error) { // if the handler is dead, this might block forever
695         raw1394_iso_xmit_sync(m_handle);
696     }*/
697     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p, %s) stop...\n",
698                  this, (m_type==eHT_Receive?"Receive":"Transmit"));
699     // stop iso traffic
700     raw1394_iso_stop(m_handle);
701     // deallocate resources
702
703     // Don't call until libraw1394's raw1394_new_handle() function has been
704     // fixed to correctly initialise the iso_packet_infos field.  Bug is
705     // confirmed present in libraw1394 1.2.1.
706     raw1394_iso_shutdown(m_handle);
707
708     raw1394_destroy_handle(m_handle);
709     m_handle = NULL;
710
711     m_State = eHS_Stopped;
712     m_NextState = eHS_Stopped;
713     return true;
714 }
715
716 // functions to request enable or disable at the next opportunity
717 bool
718 IsoHandler::requestEnable(int cycle)
719 {
720     if (m_State == eHS_Running) {
721         debugError("Enable requested on enabled stream\n");
722         return false;
723     }
724     if (m_State != eHS_Stopped) {
725         debugError("Enable requested on stream with state: %d\n", m_State);
726         return false;
727     }
728     m_NextState = eHS_Running;
729     return true;
730 }
731
732 bool
733 IsoHandler::requestDisable()
734 {
735     if (m_State == eHS_Stopped) {
736         debugError("Disable requested on disabled stream\n");
737         return false;
738     }
739     if (m_State != eHS_Running) {
740         debugError("Disable requested on stream with state=%d\n", m_State);
741         return false;
742     }
743     m_NextState = eHS_Stopped;
744     return true;
745 }
746
747 void
748 IsoHandler::updateState()
749 {
750     // execute state changes requested
751     if(m_State != m_NextState) {
752         debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) handler needs state update from %d => %d\n", this, m_State, m_NextState);
753         if(m_State == eHS_Stopped && m_NextState == eHS_Running) {
754             debugOutput(DEBUG_LEVEL_VERBOSE, "handler has to be enabled\n");
755             enable(m_switch_on_cycle);
756         } else if(m_State == eHS_Running && m_NextState == eHS_Stopped) {
757             debugOutput(DEBUG_LEVEL_VERBOSE, "handler has to be disabled\n");
758             disable();
759         } else {
760             debugError("Unknown state transition\n");
761         }
762     }
763 }
764
765 /**
766  * @brief convert a EHandlerType to a string
767  * @param t the type
768  * @return a char * describing the state
769  */
770 const char *
771 IsoHandler::eHTToString(enum EHandlerType t) {
772     switch (t) {
773         case eHT_Receive: return "Receive";
774         case eHT_Transmit: return "Transmit";
775         default: return "error: unknown type";
776     }
777 }
Note: See TracBrowser for help on using the browser.