root/branches/streaming-rework/src/libfreebobavc/ieee1394service.cpp

Revision 408, 15.9 kB (checked in by pieterpalmers, 16 years ago)

- Implemented a mechanism to allocate and deallocate iso channels in a generic manner, being by cmp or otherwise.

- cleaned all commented out code from RME, as it is getting increasingly outdated.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /* ieee1394service.cpp
2  * Copyright (C) 2005,07 by Daniel Wagner
3  *
4  * This file is part of FreeBoB.
5  *
6  * FreeBoB is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * FreeBoB is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with FreeBoB; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18  * MA 02111-1307 USA.
19  */
20 #include "ieee1394service.h"
21
22 #include <libavc1394/avc1394.h>
23 #include <libraw1394/csr.h>
24 #include <libiec61883/iec61883.h>
25
26 #include <errno.h>
27 #include <netinet/in.h>
28
29 #include "string.h"
30
31 #include <iostream>
32 #include <iomanip>
33
34 IMPL_DEBUG_MODULE( Ieee1394Service, Ieee1394Service, DEBUG_LEVEL_NORMAL );
35
36 Ieee1394Service::Ieee1394Service()
37     : m_handle( 0 ), m_resetHandle( 0 )
38     , m_port( -1 )
39     , m_threadRunning( false )
40 {
41     pthread_mutex_init( &m_mutex, 0 );
42    
43     for (unsigned int i=0; i<64; i++) {
44         m_channels[i].channel=-1;
45         m_channels[i].bandwidth=-1;
46         m_channels[i].alloctype=AllocFree;
47         m_channels[i].xmit_node=0xFFFF;
48         m_channels[i].xmit_plug=-1;
49         m_channels[i].recv_node=0xFFFF;
50         m_channels[i].recv_plug=-1;
51     }
52 }
53
54 Ieee1394Service::~Ieee1394Service()
55 {
56     stopRHThread();
57
58     if ( m_handle ) {
59         raw1394_destroy_handle( m_handle );
60     }
61     if ( m_resetHandle ) {
62         raw1394_destroy_handle( m_resetHandle );
63     }
64 }
65
66 bool
67 Ieee1394Service::initialize( int port )
68 {
69     using namespace std;
70
71     m_handle = raw1394_new_handle_on_port( port );
72     if ( !m_handle ) {
73         if ( !errno ) {
74             debugFatal("libraw1394 not compatible\n");
75         } else {
76             debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s",
77                 strerror(errno) );
78             debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
79         }
80         return false;
81     }
82
83     m_resetHandle = raw1394_new_handle_on_port( port );
84     if ( !m_handle ) {
85         if ( !errno ) {
86             debugFatal("libraw1394 not compatible\n");
87         } else {
88             debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s",
89                 strerror(errno) );
90             debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
91         }
92         return false;
93     }
94
95     m_port = port;
96
97     raw1394_set_userdata( m_handle, this );
98     raw1394_set_userdata( m_resetHandle, this );
99     raw1394_set_bus_reset_handler( m_resetHandle,
100                                    this->resetHandlerLowLevel );
101     startRHThread();
102
103     return true;
104 }
105
106 int
107 Ieee1394Service::getNodeCount()
108 {
109     return raw1394_get_nodecount( m_handle );
110 }
111
112 nodeid_t Ieee1394Service::getLocalNodeId() {
113     return raw1394_get_local_id(m_handle) & 0x3F;
114 }
115
116 bool
117 Ieee1394Service::read( fb_nodeid_t nodeId,
118                        fb_nodeaddr_t addr,
119                        size_t length,
120                        fb_quadlet_t* buffer )
121 {
122     using namespace std;
123     if ( raw1394_read( m_handle, nodeId, addr, length*4, buffer ) == 0 ) {
124
125         #ifdef DEBUG
126         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
127             "read: node 0x%X, addr = 0x%016llX, length = %u\n",
128             nodeId, addr, length);
129         printBuffer( length, buffer );
130         #endif
131
132         return true;
133     } else {
134         #ifdef DEBUG
135         debugError("raw1394_read failed: node 0x%X, addr = 0x%016llX, length = %u\n",
136               nodeId, addr, length);
137         #endif
138
139         return false;
140     }
141 }
142
143
144 bool
145 Ieee1394Service::read_quadlet( fb_nodeid_t nodeId,
146                                fb_nodeaddr_t addr,
147                                fb_quadlet_t* buffer )
148 {
149     return read( nodeId,  addr, sizeof( *buffer )/4, buffer );
150 }
151
152 bool
153 Ieee1394Service::read_octlet( fb_nodeid_t nodeId,
154                               fb_nodeaddr_t addr,
155                               fb_octlet_t* buffer )
156 {
157     return read( nodeId, addr, sizeof( *buffer )/4,
158                  reinterpret_cast<fb_quadlet_t*>( buffer ) );
159 }
160
161
162 bool
163 Ieee1394Service::write( fb_nodeid_t nodeId,
164                         fb_nodeaddr_t addr,
165                         size_t length,
166                         fb_quadlet_t* data )
167 {
168     using namespace std;
169
170     #ifdef DEBUG
171     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"write: node 0x%X, addr = 0x%016X, length = %d\n",
172                 nodeId, addr, length);
173     printBuffer( length, data );
174     #endif
175
176     return raw1394_write( m_handle, nodeId, addr, length*4, data ) == 0;
177 }
178
179
180 bool
181 Ieee1394Service::write_quadlet( fb_nodeid_t nodeId,
182                                 fb_nodeaddr_t addr,
183                                 fb_quadlet_t data )
184 {
185     return write( nodeId, addr, sizeof( data )/4, &data );
186 }
187
188 bool
189 Ieee1394Service::write_octlet( fb_nodeid_t nodeId,
190                                fb_nodeaddr_t addr,
191                                fb_octlet_t data )
192 {
193     return write( nodeId, addr, sizeof( data )/4,
194                   reinterpret_cast<fb_quadlet_t*>( &data ) );
195 }
196
197 fb_quadlet_t*
198 Ieee1394Service::transactionBlock( fb_nodeid_t nodeId,
199                                    fb_quadlet_t* buf,
200                                    int len,
201                                    unsigned int* resp_len )
202 {
203     for (int i = 0; i < len; ++i) {
204         buf[i] = ntohl( buf[i] );
205     }
206
207     #ifdef DEBUG
208     debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "  pre avc1394_transaction_block2\n" );
209     printBuffer( len, buf );
210     #endif
211
212     fb_quadlet_t* result =
213         avc1394_transaction_block2( m_handle,
214                                     nodeId,
215                                     buf,
216                                     len,
217                                     resp_len,
218                                     10 );
219
220     #ifdef DEBUG
221     debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "  post avc1394_transaction_block2\n" );
222     printBuffer( *resp_len, result );
223     #endif
224
225     for ( unsigned int i = 0; i < *resp_len; ++i ) {
226         result[i] = htonl( result[i] );
227     }
228
229     return result;
230 }
231
232
233 bool
234 Ieee1394Service::transactionBlockClose()
235 {
236     avc1394_transaction_block_close( m_handle );
237     return true;
238 }
239
240 bool
241 Ieee1394Service::setVerbose( int verboseLevel )
242 {
243     setDebugLevel(verboseLevel);
244     return true;
245 }
246
247 int
248 Ieee1394Service::getVerboseLevel()
249 {
250     return getDebugLevel();
251 }
252
253 void
254 Ieee1394Service::printBuffer( size_t length, fb_quadlet_t* buffer ) const
255 {
256
257     for ( unsigned int i=0; i < length; ++i ) {
258         if ( ( i % 4 ) == 0 ) {
259             if ( i > 0 ) {
260                 debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE,"\n");
261             }
262             debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE," %4d: ",i*4);
263         }
264         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE,"%08X ",buffer[i]);
265     }
266     debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE,"\n");
267 }
268
269 int
270 Ieee1394Service::resetHandlerLowLevel( raw1394handle_t handle,
271                                        unsigned int generation )
272 {
273     raw1394_update_generation ( handle, generation );
274     Ieee1394Service* instance
275         = (Ieee1394Service*) raw1394_get_userdata( handle );
276     instance->resetHandler( generation );
277
278     return 0;
279 }
280
281 bool
282 Ieee1394Service::resetHandler( unsigned int generation )
283 {
284     m_generation = generation;
285
286     for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin();
287           it != m_busResetHandlers.end();
288           ++it )
289     {
290         Functor* func = *it;
291         ( *func )();
292     }
293
294     return true;
295 }
296
297 bool
298 Ieee1394Service::startRHThread()
299 {
300     int i;
301
302     if ( m_threadRunning ) {
303         return true;
304     }
305     pthread_mutex_lock( &m_mutex );
306     i = pthread_create( &m_thread, 0, rHThread, this );
307     pthread_mutex_unlock( &m_mutex );
308     if (i) {
309         debugFatal("Could not start ieee1394 service thread\n");
310         return false;
311     }
312     m_threadRunning = true;
313
314     return true;
315 }
316
317 void
318 Ieee1394Service::stopRHThread()
319 {
320     if ( m_threadRunning ) {
321         pthread_mutex_lock (&m_mutex);
322         pthread_cancel (m_thread);
323         pthread_join (m_thread, 0);
324         pthread_mutex_unlock (&m_mutex);
325         m_threadRunning = false;
326     }
327 }
328
329 void*
330 Ieee1394Service::rHThread( void* arg )
331 {
332     Ieee1394Service* pIeee1394Service = (Ieee1394Service*) arg;
333
334     while (true) {
335         raw1394_loop_iterate (pIeee1394Service->m_resetHandle);
336         pthread_testcancel ();
337     }
338
339     return 0;
340 }
341
342 bool
343 Ieee1394Service::addBusResetHandler( Functor* functor )
344 {
345     m_busResetHandlers.push_back( functor );
346     return true;
347 }
348
349 bool
350 Ieee1394Service::remBusResetHandler( Functor* functor )
351 {
352     for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin();
353           it != m_busResetHandlers.end();
354           ++it )
355     {
356         if ( *it == functor ) {
357             m_busResetHandlers.erase( it );
358             return true;
359         }
360     }
361     return false;
362 }
363
364 /**
365  * Allocates an iso channel for use by the interface in a similar way to
366  * libiec61883.  Returns -1 on error (due to there being no free channels)
367  * or an allocated channel number.
368  *
369  * Does not perform anything other than registering the channel and the
370  * bandwidth at the IRM
371  *
372  * Also allocates the necessary bandwidth (in ISO allocation units).
373  *
374  * FIXME: As in libiec61883, channel 63 is not requested; this is either a
375  * bug or it's omitted since that's the channel preferred by video devices.
376  *
377  * @param bandwidth the bandwidth to allocate for this channel
378  * @return the channel number
379  */
380 signed int Ieee1394Service::allocateIsoChannelGeneric(unsigned int bandwidth) {
381     struct ChannelInfo cinfo;
382
383     int c = -1;
384     for (c = 0; c < 63; c++) {
385         if (raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_ALLOC) == 0)
386             break;
387     }
388     if (c < 63) {
389         if (raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_ALLOC) < 0) {
390             debugFatal("Could not allocate bandwidth of %d\n", bandwidth);
391            
392             raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE);
393             return -1;
394         } else {
395             cinfo.channel=c;
396             cinfo.bandwidth=bandwidth;
397             cinfo.alloctype=AllocGeneric;
398            
399             if (registerIsoChannel(c, cinfo)) {
400                 return c;
401             } else {
402                 raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_FREE);
403                 raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE);
404                 return -1;
405             }
406         }
407     }
408     return -1;
409 }
410
411 /**
412  * Allocates an iso channel for use by the interface in a similar way to
413  * libiec61883.  Returns -1 on error (due to there being no free channels)
414  * or an allocated channel number.
415  *
416  * Uses IEC61883 Connection Management Procedure to establish the connection.
417  *
418  * Also allocates the necessary bandwidth (in ISO allocation units).
419  *
420  * @param xmit_node  node id of the transmitter
421  * @param xmit_plug  the output plug to use. If -1, find the first online plug, and
422  * upon return, contains the plug number used.
423  * @param recv_node  node id of the receiver
424  * @param recv_plug the input plug to use. If -1, find the first online plug, and
425  * upon return, contains the plug number used.
426  *
427  * @return the channel number
428  */
429
430 signed int Ieee1394Service::allocateIsoChannelCMP(
431     nodeid_t xmit_node, int xmit_plug,
432     nodeid_t recv_node, int recv_plug
433     ) {
434
435     struct ChannelInfo cinfo;
436    
437     int c = -1;
438     int bandwidth=1;
439    
440     // do connection management: make connection
441     c = iec61883_cmp_connect(
442         m_handle,
443         xmit_node | 0xffc0,
444         &xmit_plug,
445         recv_node | 0xffc0,
446         &recv_plug,
447         &bandwidth);
448
449     if((c<0) || (c>63)) {
450         debugError("Could not do CMP from %04X:%02d to %04X:%02d\n",
451             xmit_node, xmit_plug, recv_node, recv_plug
452             );
453         return -1;
454     }
455
456     cinfo.channel=c;
457     cinfo.bandwidth=bandwidth;
458     cinfo.alloctype=AllocCMP;
459    
460     cinfo.xmit_node=xmit_node;
461     cinfo.xmit_plug=xmit_plug;
462     cinfo.recv_node=recv_node;
463     cinfo.recv_plug=recv_plug;
464        
465     if (registerIsoChannel(c, cinfo)) {
466         return c;
467     }
468
469     return -1;
470 }
471
472 /**
473  * Deallocates an iso channel.  Silently ignores a request to deallocate
474  * a negative channel number.
475  *
476  * Figures out the method that was used to allocate the channel (generic, cmp, ...)
477  * and uses the appropriate method to deallocate. Also frees the bandwidth
478  * that was reserved along with this channel.
479  *
480  * @param c channel number
481  * @return true if successful
482  */
483 bool Ieee1394Service::freeIsoChannel(signed int c) {
484    
485     if (c < 0 || c > 63) {
486         debugWarning("Invalid channel number: %d", c);
487         return false;
488     }
489    
490     switch (m_channels[c].alloctype) {
491         default:
492             debugError("BUG: invalid allocation type!\n");
493             return false;
494            
495         case AllocFree:
496             debugWarning("Channel %d not registered\n", c);
497             return false;
498            
499         case AllocGeneric:
500             if (unregisterIsoChannel(c)) {
501                 return false;
502             } else {
503                 if (raw1394_bandwidth_modify(m_handle, m_channels[c].bandwidth, RAW1394_MODIFY_FREE) !=0) {
504                     debugWarning("Failed to deallocate bandwidth\n");
505                 }
506                 if (raw1394_channel_modify (m_handle, m_channels[c].channel, RAW1394_MODIFY_FREE) != 0) {
507                     debugWarning("Failed to free channel\n");
508                 }
509                 return true;
510             }
511            
512         case AllocCMP:
513             if (unregisterIsoChannel(c)) {
514                 return false;
515             } else {
516                 if(iec61883_cmp_disconnect(
517                         m_handle,
518                         m_channels[c].xmit_node | 0xffc0,
519                         m_channels[c].xmit_plug,
520                         m_channels[c].recv_node | 0xffc0,
521                         m_channels[c].recv_plug,
522                         m_channels[c].channel,
523                         m_channels[c].bandwidth) != 0) {
524                     debugWarning("Could not do CMP disconnect for channel %d!\n",c);
525                 }
526             }
527             return true;
528     }
529    
530     // unreachable
531     debugError("BUG: unreachable code reached!\n");
532    
533     return false;
534 }
535
536 /**
537  * Registers a channel as managed by this ieee1394service
538  * @param c channel number
539  * @param cinfo channel info struct
540  * @return true if successful
541  */
542 bool Ieee1394Service::registerIsoChannel(unsigned int c, struct ChannelInfo cinfo) {
543     if (c < 63) {
544         if (m_channels[c].alloctype != AllocFree) {
545             debugWarning("Channel %d already registered with bandwidth %d\n",
546                 m_channels[c].channel, m_channels[c].bandwidth);
547         }
548        
549         memcpy(&m_channels[c], &cinfo, sizeof(struct ChannelInfo));
550        
551     } else return false;
552     return true;
553 }
554
555 /**
556  * unegisters a channel from this ieee1394service
557  * @param c channel number
558  * @return true if successful
559  */
560 bool Ieee1394Service::unregisterIsoChannel(unsigned int c) {
561     if (c < 63) {
562         if (m_channels[c].alloctype == AllocFree) {
563             debugWarning("Channel %d not registered\n", c);
564             return false;
565         }
566        
567         m_channels[c].channel=-1;
568         m_channels[c].bandwidth=-1;
569         m_channels[c].alloctype=AllocFree;
570         m_channels[c].xmit_node=0xFFFF;
571         m_channels[c].xmit_plug=-1;
572         m_channels[c].recv_node=0xFFFF;
573         m_channels[c].recv_plug=-1;
574        
575     } else return false;
576     return true;
577 }
578
579 /**
580  * Returns the current value of the `bandwidth available' register on
581  * the IRM, or -1 on error.
582  * @return
583  */
584 signed int Ieee1394Service::getAvailableBandwidth() {
585     quadlet_t buffer;
586     signed int result = raw1394_read (m_handle, raw1394_get_irm_id (m_handle),
587         CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE,
588         sizeof (quadlet_t), &buffer);
589
590     if (result < 0)
591         return -1;
592     return ntohl(buffer);
593 }
Note: See TracBrowser for help on using the browser.