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

Revision 796, 16.4 kB (checked in by ppalmers, 13 years ago)

- move #define constants to config.h.in
- switch receive handler over to packet-per-buffer mode to improve latency performance

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