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

Revision 1005, 16.1 kB (checked in by ppalmers, 13 years ago)

Improve thread synchronisation. Switch back to separate threads for transmit and
receive since it is not possible to statically schedule things properly. One
of the threads (i.e. the client thread) is out of our control, hence it's
execution can't be controlled. Using separate threads and correct priorities
will shift this problem to the OS. Note that the priority of the packet
receive thread should be lower than the client thread (such that the client
thread is woken ASAP), and the priority of the transmit thread should be
higher than the client thread (such that packets are queued ASAP).
Extra benefit: multi-cores are used.

Some other startup improvements.

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 "libstreaming/generic/StreamProcessor.h"
31 #include "libutil/PosixThread.h"
32
33 #include <errno.h>
34 #include <netinet/in.h>
35 #include <assert.h>
36 #include <unistd.h>
37 #include <string.h>
38
39 #include <iostream>
40 using namespace std;
41 using namespace Streaming;
42
43 IMPL_DEBUG_MODULE( IsoHandler, IsoHandler, DEBUG_LEVEL_NORMAL );
44
45 /* the C callbacks */
46 enum raw1394_iso_disposition
47 IsoHandler::iso_transmit_handler(raw1394handle_t handle,
48         unsigned char *data, unsigned int *length,
49         unsigned char *tag, unsigned char *sy,
50         int cycle, unsigned int dropped1) {
51
52     IsoHandler *xmitHandler = static_cast<IsoHandler *>(raw1394_get_userdata(handle));
53     assert(xmitHandler);
54     unsigned int skipped = (dropped1 & 0xFFFF0000) >> 16;
55     unsigned int dropped = dropped1 & 0xFFFF;
56
57     return xmitHandler->getPacket(data, length, tag, sy, cycle, dropped, skipped);
58 }
59
60 enum raw1394_iso_disposition
61 IsoHandler::iso_receive_handler(raw1394handle_t handle, unsigned char *data,
62                         unsigned int length, unsigned char channel,
63                         unsigned char tag, unsigned char sy, unsigned int cycle,
64                         unsigned int dropped1) {
65
66     IsoHandler *recvHandler = static_cast<IsoHandler *>(raw1394_get_userdata(handle));
67     assert(recvHandler);
68
69     unsigned int skipped = (dropped1 & 0xFFFF0000) >> 16;
70     unsigned int dropped = dropped1 & 0xFFFF;
71
72     return recvHandler->putPacket(data, length, channel, tag, sy, cycle, dropped, skipped);
73 }
74
75 int IsoHandler::busreset_handler(raw1394handle_t handle, unsigned int generation)
76 {
77     debugOutput( DEBUG_LEVEL_VERBOSE, "Busreset happened, generation %d...\n", generation);
78
79     IsoHandler *handler = static_cast<IsoHandler *>(raw1394_get_userdata(handle));
80     assert(handler);
81     return handler->handleBusReset(generation);
82 }
83
84 IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t)
85    : m_manager( manager )
86    , m_type ( t )
87    , m_handle( 0 )
88    , m_buf_packets( 400 )
89    , m_max_packet_size( 1024 )
90    , m_irq_interval( -1 )
91    , m_Client( 0 )
92    , m_speed( RAW1394_ISO_SPEED_400 )
93    , m_prebuffers( 0 )
94    , m_dont_exit_iterate_loop( true )
95    , m_State( E_Created )
96 #ifdef DEBUG
97    , m_packets ( 0 )
98 #endif
99 {
100 }
101
102 IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t,
103                        unsigned int buf_packets, unsigned int max_packet_size, int irq)
104    : m_manager( manager )
105    , m_type ( t )
106    , m_handle( 0 )
107    , m_buf_packets( buf_packets )
108    , m_max_packet_size( max_packet_size )
109    , m_irq_interval( irq )
110    , m_Client( 0 )
111    , m_speed( RAW1394_ISO_SPEED_400 )
112    , m_prebuffers( 0 )
113    , m_State( E_Created )
114 #ifdef DEBUG
115    , m_packets ( 0 )
116 #endif
117 {
118 }
119
120 IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t, unsigned int buf_packets,
121                        unsigned int max_packet_size, int irq,
122                        enum raw1394_iso_speed speed)
123    : m_manager( manager )
124    , m_type ( t )
125    , m_handle( 0 )
126    , m_buf_packets( buf_packets )
127    , m_max_packet_size( max_packet_size )
128    , m_irq_interval( irq )
129    , m_Client( 0 )
130    , m_speed( speed )
131    , m_prebuffers( 0 )
132    , m_State( E_Created )
133 #ifdef DEBUG
134    , m_packets ( 0 )
135 #endif
136 {
137 }
138
139 IsoHandler::~IsoHandler() {
140 // Don't call until libraw1394's raw1394_new_handle() function has been
141 // fixed to correctly initialise the iso_packet_infos field.  Bug is
142 // confirmed present in libraw1394 1.2.1.  In any case,
143 // raw1394_destroy_handle() will do any iso system shutdown required.
144 //     raw1394_iso_shutdown(m_handle);
145     if(m_handle) {
146         if (m_State == E_Running) {
147             disable();
148         }
149         raw1394_destroy_handle(m_handle);
150     }
151 }
152
153 bool
154 IsoHandler::canIterateClient()
155 {
156     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "checking...\n");
157     if(m_Client) {
158         bool result;
159         if (m_type == eHT_Receive) {
160             result = m_Client->canProducePacket();
161         } else {
162             result = m_Client->canConsumePacket();
163         }
164         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, " returns %d\n", result);
165         return result;
166     } else {
167         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, " no client\n");
168     }
169     return false;
170 }
171
172 bool
173 IsoHandler::iterate() {
174     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "(%p, %s) Iterating ISO handler...\n",
175                 this, getTypeString());
176     if(m_State == E_Running) {
177 #if ISOHANDLER_FLUSH_BEFORE_ITERATE
178         flush();
179 #endif
180         if(raw1394_loop_iterate(m_handle)) {
181             debugError( "IsoHandler (%p): Failed to iterate handler: %s\n",
182                         this, strerror(errno));
183             return false;
184         }
185         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "(%p, %s) done interating ISO handler...\n",
186                            this, getTypeString());
187         return true;
188     } else {
189         debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) Not iterating a non-running handler...\n",
190                     this, getTypeString());
191         return false;
192     }
193 }
194
195 bool
196 IsoHandler::init()
197 {
198     debugOutput( DEBUG_LEVEL_VERBOSE, "IsoHandler (%p) enter...\n",this);
199     // check the state
200     if(m_State != E_Created) {
201         debugError("Incorrect state, expected E_Created, got %d\n",(int)m_State);
202         return false;
203     }
204
205     // the main handle for the ISO traffic
206     m_handle = raw1394_new_handle_on_port( m_manager.get1394Service().getPort() );
207     if ( !m_handle ) {
208         if ( !errno ) {
209             debugError("libraw1394 not compatible\n");
210         } else {
211             debugError("Could not get 1394 handle: %s\n", strerror(errno) );
212             debugError("Are ieee1394 and raw1394 drivers loaded?\n");
213         }
214         return false;
215     }
216     raw1394_set_userdata(m_handle, static_cast<void *>(this));
217
218     // bus reset handling
219     if(raw1394_busreset_notify (m_handle, RAW1394_NOTIFY_ON)) {
220         debugWarning("Could not enable busreset notification.\n");
221         debugWarning(" Error message: %s\n",strerror(errno));
222         debugWarning("Continuing without bus reset support.\n");
223     } else {
224         // apparently this cannot fail
225         raw1394_set_bus_reset_handler(m_handle, busreset_handler);
226     }
227
228     // update the internal state
229     m_State=E_Initialized;
230     return true;
231 }
232
233 bool IsoHandler::disable()
234 {
235     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p, %s) enter...\n",
236                  this, (m_type==eHT_Receive?"Receive":"Transmit"));
237
238     // check state
239     if(m_State == E_Prepared) return true;
240     if(m_State != E_Running) {
241         debugError("Incorrect state, expected E_Running, got %d\n",(int)m_State);
242         return false;
243     }
244
245     // this is put here to try and avoid the
246     // Runaway context problem
247     // don't know if it will help though.
248     raw1394_iso_xmit_sync(m_handle);
249     raw1394_iso_stop(m_handle);
250     m_State = E_Prepared;
251     return true;
252 }
253
254 /**
255  * Bus reset handler
256  *
257  * @return ?
258  */
259
260 int
261 IsoHandler::handleBusReset(unsigned int generation)
262 {
263     debugOutput( DEBUG_LEVEL_VERBOSE, "bus reset...\n");
264
265     #define CSR_CYCLE_TIME            0x200
266     #define CSR_REGISTER_BASE  0xfffff0000000ULL
267     // do a simple read on ourself in order to update the internal structures
268     // this avoids read failures after a bus reset
269     quadlet_t buf=0;
270     raw1394_read(m_handle, raw1394_get_local_id(m_handle),
271                  CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf);
272
273     // notify the client of the fact that we have died
274     m_Client->handlerDied();
275
276     if(!disable()) {
277         debugError("(%p) Could not disable IsoHandler\n", this);
278     }
279
280     // request the manager to update it's shadow map
281     m_manager.requestShadowMapUpdate();
282     return 0;
283 }
284
285 void IsoHandler::dumpInfo()
286 {
287     int channel=-1;
288     if (m_Client) channel=m_Client->getChannel();
289
290     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Handler type................: %s\n",
291             getTypeString());
292     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Port, Channel...............: %2d, %2d\n",
293             m_manager.get1394Service().getPort(), channel);
294     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Buffer, MaxPacketSize, IRQ..: %4d, %4d, %4d\n",
295             m_buf_packets, m_max_packet_size, m_irq_interval);
296     if (this->getType() == eHT_Transmit) {
297         debugOutputShort( DEBUG_LEVEL_NORMAL, "  Speed, PreBuffers...........: %2d, %2d\n",
298                                             m_speed, m_prebuffers);
299     }
300 }
301
302 void IsoHandler::setVerboseLevel(int l)
303 {
304     setDebugLevel(l);
305 }
306
307 bool IsoHandler::registerStream(StreamProcessor *stream)
308 {
309     assert(stream);
310     debugOutput( DEBUG_LEVEL_VERBOSE, "registering stream (%p)\n", stream);
311
312     if (m_Client) {
313             debugFatal( "Generic IsoHandlers can have only one client\n");
314             return false;
315     }
316     m_Client=stream;
317     return true;
318 }
319
320 bool IsoHandler::unregisterStream(StreamProcessor *stream)
321 {
322     assert(stream);
323     debugOutput( DEBUG_LEVEL_VERBOSE, "unregistering stream (%p)\n", stream);
324
325     if(stream != m_Client) {
326             debugFatal( "no client registered\n");
327             return false;
328     }
329     m_Client=0;
330     return true;
331 }
332
333 void IsoHandler::flush()
334 {
335     if(m_type == eHT_Receive) {
336         raw1394_iso_recv_flush(m_handle);
337     } else {
338         // do nothing
339     }
340 }
341
342 // ISO packet interface
343 enum raw1394_iso_disposition IsoHandler::putPacket(
344                     unsigned char *data, unsigned int length,
345                     unsigned char channel, unsigned char tag, unsigned char sy,
346                     unsigned int cycle, unsigned int dropped, unsigned int skipped) {
347
348     debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE,
349                        "received packet: length=%d, channel=%d, cycle=%d\n",
350                        length, channel, cycle);
351     #ifdef DEBUG
352     m_packets++;
353     if (length > m_max_packet_size) {
354         debugWarning("(%p, %s) packet too large: len=%u max=%u\n",
355                      this, getTypeString(), length, m_max_packet_size);
356     }
357     #endif
358     if(m_Client) {
359         enum raw1394_iso_disposition retval = m_Client->putPacket(data, length, channel, tag, sy, cycle, dropped, skipped);
360         if (retval == RAW1394_ISO_OK) {
361             if (m_dont_exit_iterate_loop) {
362                 return RAW1394_ISO_OK;
363             } else {
364                 m_dont_exit_iterate_loop = true;
365                 debugOutput(DEBUG_LEVEL_VERBOSE,
366                                 "(%p) loop exit requested\n",
367                                 this);
368                 return RAW1394_ISO_DEFER;
369             }
370         } else {
371             return retval;
372         }
373     }
374
375     return RAW1394_ISO_OK;
376 }
377
378
379 enum raw1394_iso_disposition
380 IsoHandler::getPacket(unsigned char *data, unsigned int *length,
381                       unsigned char *tag, unsigned char *sy,
382                       int cycle, unsigned int dropped, unsigned int skipped) {
383
384     debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE,
385                        "sending packet: length=%d, cycle=%d\n",
386                        *length, cycle);
387     #ifdef DEBUG
388     m_packets++;
389     #endif
390     if(m_Client) {
391         enum raw1394_iso_disposition retval;
392         retval = m_Client->getPacket(data, length, tag, sy, cycle, dropped, skipped, m_max_packet_size);
393         #ifdef DEBUG
394         if (*length > m_max_packet_size) {
395             debugWarning("(%p, %s) packet too large: len=%u max=%u\n",
396                          this, getTypeString(), *length, m_max_packet_size);
397         }
398         #endif
399         if (retval == RAW1394_ISO_OK) {
400             if (m_dont_exit_iterate_loop) {
401                 return RAW1394_ISO_OK;
402             } else {
403                 m_dont_exit_iterate_loop = true;
404                 debugOutput(DEBUG_LEVEL_VERBOSE,
405                                 "(%p) loop exit requested\n",
406                                 this);
407                 return RAW1394_ISO_DEFER;
408             }
409         } else {
410             return retval;
411         }
412     }
413     *tag = 0;
414     *sy = 0;
415     *length = 0;
416     return RAW1394_ISO_OK;
417 }
418
419 bool IsoHandler::prepare()
420 {
421     // check the state
422     if(m_State != E_Initialized) {
423         debugError("Incorrect state, expected E_Initialized, got %d\n",(int)m_State);
424         return false;
425     }
426
427     // Don't call until libraw1394's raw1394_new_handle() function has been
428     // fixed to correctly initialise the iso_packet_infos field.  Bug is
429     // confirmed present in libraw1394 1.2.1.
430     //     raw1394_iso_shutdown(m_handle);
431     m_State = E_Prepared;
432
433     debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing iso handler (%p, client=%p)\n", this, m_Client);
434     dumpInfo();
435     if (getType() == eHT_Receive) {
436         if(m_irq_interval > 1) {
437             if(raw1394_iso_recv_init(m_handle,
438                                     iso_receive_handler,
439                                     m_buf_packets,
440                                     m_max_packet_size,
441                                     m_Client->getChannel(),
442                                     RAW1394_DMA_BUFFERFILL,
443 //                                     RAW1394_DMA_PACKET_PER_BUFFER,
444                                     m_irq_interval)) {
445                 debugFatal("Could not do receive initialisation (DMA_BUFFERFILL)!\n" );
446                 debugFatal("  %s\n",strerror(errno));
447                 return false;
448             }
449         } else {
450             if(raw1394_iso_recv_init(m_handle,
451                                     iso_receive_handler,
452                                     m_buf_packets,
453                                     m_max_packet_size,
454                                     m_Client->getChannel(),
455                                     RAW1394_DMA_PACKET_PER_BUFFER,
456                                     m_irq_interval)) {
457                 debugFatal("Could not do receive initialisation (PACKET_PER_BUFFER)!\n" );
458                 debugFatal("  %s\n",strerror(errno));
459                 return false;
460             }
461         }
462         return true;
463     } else {
464         if(raw1394_iso_xmit_init(m_handle,
465                                 iso_transmit_handler,
466                                 m_buf_packets,
467                                 m_max_packet_size,
468                                 m_Client->getChannel(),
469                                 m_speed,
470                                 m_irq_interval)) {
471             debugFatal("Could not do xmit initialisation!\n" );
472             return false;
473         }
474         return true;
475     }
476 }
477
478 bool IsoHandler::enable(int cycle)
479 {
480     debugOutput( DEBUG_LEVEL_VERBOSE, "start on cycle %d\n", cycle);
481     // check the state
482     if(m_State != E_Prepared) {
483         if(!prepare()) {
484             debugFatal("Could not prepare handler\n");
485             return false;
486         }
487     }
488
489     if (getType() == eHT_Receive) {
490         if(raw1394_iso_recv_start(m_handle, cycle, -1, 0)) {
491             debugFatal("Could not start receive handler (%s)\n",strerror(errno));
492             dumpInfo();
493             return false;
494         }
495     } else {
496         if(raw1394_iso_xmit_start(m_handle, cycle, m_prebuffers)) {
497             debugFatal("Could not start xmit handler (%s)\n",strerror(errno));
498             dumpInfo();
499             return false;
500         }
501     }
502
503     m_State = E_Running;
504     return true;
505 }
506
507 /**
508  * @brief convert a EHandlerType to a string
509  * @param t the type
510  * @return a char * describing the state
511  */
512 const char *
513 IsoHandler::eHTToString(enum EHandlerType t) {
514     switch (t) {
515         case eHT_Receive: return "Receive";
516         case eHT_Transmit: return "Transmit";
517         default: return "error: unknown type";
518     }
519 }
Note: See TracBrowser for help on using the browser.