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

Revision 677, 24.7 kB (checked in by ppalmers, 16 years ago)

make generation unambiguous.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2007 by Daniel Wagner
3  * Copyright (C) 2005-2007 by Pieter Palmers
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License version 2.1, as published by the Free Software Foundation;
13  *
14  * This library 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 GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1301 USA
23  */
24
25 #include "ieee1394service.h"
26 #include "ARMHandler.h"
27
28 #include <libavc1394/avc1394.h>
29 #include <libraw1394/csr.h>
30 #include <libiec61883/iec61883.h>
31
32 #include <errno.h>
33 #include <netinet/in.h>
34
35 #include <string.h>
36
37 #include <iostream>
38 #include <iomanip>
39
40 IMPL_DEBUG_MODULE( Ieee1394Service, Ieee1394Service, DEBUG_LEVEL_NORMAL );
41
42 Ieee1394Service::Ieee1394Service()
43     : m_handle( 0 ), m_resetHandle( 0 )
44     , m_port( -1 )
45     , m_threadRunning( false )
46 {
47     pthread_mutex_init( &m_mutex, 0 );
48
49     for (unsigned int i=0; i<64; i++) {
50         m_channels[i].channel=-1;
51         m_channels[i].bandwidth=-1;
52         m_channels[i].alloctype=AllocFree;
53         m_channels[i].xmit_node=0xFFFF;
54         m_channels[i].xmit_plug=-1;
55         m_channels[i].recv_node=0xFFFF;
56         m_channels[i].recv_plug=-1;
57     }
58 }
59
60 Ieee1394Service::~Ieee1394Service()
61 {
62     stopRHThread();
63
64     for ( arm_handler_vec_t::iterator it = m_armHandlers.begin();
65           it != m_armHandlers.end();
66           ++it )
67     {
68         debugOutput(DEBUG_LEVEL_VERBOSE, "Unregistering ARM handler for 0x%016llX\n", (*it)->getStart());
69         int err=raw1394_arm_unregister(m_resetHandle, (*it)->getStart());
70         if (err) {
71             debugError(" Failed to unregister ARM handler for 0x%016llX\n", (*it)->getStart());
72             debugError(" Error: %s\n", strerror(errno));
73         }
74     }
75
76     if ( m_handle ) {
77         raw1394_destroy_handle( m_handle );
78     }
79
80     if ( m_resetHandle ) {
81         raw1394_destroy_handle( m_resetHandle );
82     }
83 }
84
85 bool
86 Ieee1394Service::initialize( int port )
87 {
88     using namespace std;
89
90     m_handle = raw1394_new_handle_on_port( port );
91     if ( !m_handle ) {
92         if ( !errno ) {
93             debugFatal("libraw1394 not compatible\n");
94         } else {
95             debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s\n",
96                 strerror(errno) );
97             debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
98         }
99         return false;
100     }
101
102     m_resetHandle = raw1394_new_handle_on_port( port );
103     if ( !m_handle ) {
104         if ( !errno ) {
105             debugFatal("libraw1394 not compatible\n");
106         } else {
107             debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s",
108                 strerror(errno) );
109             debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
110         }
111         return false;
112     }
113
114     m_port = port;
115
116     raw1394_set_userdata( m_handle, this );
117     raw1394_set_userdata( m_resetHandle, this );
118     raw1394_set_bus_reset_handler( m_resetHandle,
119                                    this->resetHandlerLowLevel );
120
121     m_default_arm_handler = raw1394_set_arm_tag_handler( m_resetHandle,
122                                    this->armHandlerLowLevel );
123
124     startRHThread();
125
126     return true;
127 }
128
129 int
130 Ieee1394Service::getNodeCount()
131 {
132     return raw1394_get_nodecount( m_handle );
133 }
134
135 nodeid_t Ieee1394Service::getLocalNodeId() {
136     return raw1394_get_local_id(m_handle) & 0x3F;
137 }
138
139 bool
140 Ieee1394Service::read( fb_nodeid_t nodeId,
141                        fb_nodeaddr_t addr,
142                        size_t length,
143                        fb_quadlet_t* buffer )
144 {
145     using namespace std;
146     if ( raw1394_read( m_handle, nodeId, addr, length*4, buffer ) == 0 ) {
147
148         #ifdef DEBUG
149         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
150             "read: node 0x%X, addr = 0x%016llX, length = %u\n",
151             nodeId, addr, length);
152         printBuffer( DEBUG_LEVEL_VERY_VERBOSE, length, buffer );
153         #endif
154
155         return true;
156     } else {
157         #ifdef DEBUG
158         debugError("raw1394_read failed: node 0x%X, addr = 0x%016llX, length = %u\n",
159               nodeId, addr, length);
160         #endif
161
162         return false;
163     }
164 }
165
166
167 bool
168 Ieee1394Service::read_quadlet( fb_nodeid_t nodeId,
169                                fb_nodeaddr_t addr,
170                                fb_quadlet_t* buffer )
171 {
172     return read( nodeId,  addr, sizeof( *buffer )/4, buffer );
173 }
174
175 bool
176 Ieee1394Service::read_octlet( fb_nodeid_t nodeId,
177                               fb_nodeaddr_t addr,
178                               fb_octlet_t* buffer )
179 {
180     return read( nodeId, addr, sizeof( *buffer )/4,
181                  reinterpret_cast<fb_quadlet_t*>( buffer ) );
182 }
183
184
185 bool
186 Ieee1394Service::write( fb_nodeid_t nodeId,
187                         fb_nodeaddr_t addr,
188                         size_t length,
189                         fb_quadlet_t* data )
190 {
191     using namespace std;
192
193     #ifdef DEBUG
194     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"write: node 0x%X, addr = 0x%016X, length = %d\n",
195                 nodeId, addr, length);
196     printBuffer( DEBUG_LEVEL_VERY_VERBOSE, length, data );
197     #endif
198
199     return raw1394_write( m_handle, nodeId, addr, length*4, data ) == 0;
200 }
201
202
203 bool
204 Ieee1394Service::write_quadlet( fb_nodeid_t nodeId,
205                                 fb_nodeaddr_t addr,
206                                 fb_quadlet_t data )
207 {
208     return write( nodeId, addr, sizeof( data )/4, &data );
209 }
210
211 bool
212 Ieee1394Service::write_octlet( fb_nodeid_t nodeId,
213                                fb_nodeaddr_t addr,
214                                fb_octlet_t data )
215 {
216     return write( nodeId, addr, sizeof( data )/4,
217                   reinterpret_cast<fb_quadlet_t*>( &data ) );
218 }
219
220 fb_octlet_t
221 Ieee1394Service::byteSwap_octlet(fb_octlet_t value) {
222     #if __BYTE_ORDER == __BIG_ENDIAN
223         return value;
224     #elif __BYTE_ORDER == __LITTLE_ENDIAN
225         fb_octlet_t value_new;
226         fb_quadlet_t *in_ptr=reinterpret_cast<fb_quadlet_t *>(&value);
227         fb_quadlet_t *out_ptr=reinterpret_cast<fb_quadlet_t *>(&value_new);
228         *(out_ptr+1)=htonl(*(in_ptr));
229         *(out_ptr)=htonl(*(in_ptr+1));
230         return value_new;
231     #else
232         #error Unknown endiannes
233     #endif
234 }
235
236 bool
237 Ieee1394Service::lockCompareSwap64(  fb_nodeid_t nodeId,
238                         fb_nodeaddr_t addr,
239                         fb_octlet_t  compare_value,
240                         fb_octlet_t  swap_value,
241                         fb_octlet_t* result )
242 {
243     #ifdef DEBUG
244     debugOutput(DEBUG_LEVEL_VERBOSE,"lockCompareSwap64: node 0x%X, addr = 0x%016llX\n",
245                 nodeId, addr);
246     debugOutput(DEBUG_LEVEL_VERBOSE,"  if (*(addr)==0x%016llX) *(addr)=0x%016llX\n",
247                 compare_value, swap_value);
248     fb_octlet_t buffer;
249     if(!read_octlet( nodeId, addr,&buffer )) {
250         debugWarning("Could not read register\n");
251     } else {
252         debugOutput(DEBUG_LEVEL_VERBOSE,"before = 0x%016llX\n", buffer);
253     }
254
255     #endif
256
257     // do endiannes swapping
258     compare_value=byteSwap_octlet(compare_value);
259     swap_value=byteSwap_octlet(swap_value);
260
261     int retval=raw1394_lock64(m_handle, nodeId, addr, RAW1394_EXTCODE_COMPARE_SWAP,
262                           swap_value, compare_value, result);
263
264     #ifdef DEBUG
265     if(!read_octlet( nodeId, addr,&buffer )) {
266         debugWarning("Could not read register\n");
267     } else {
268         debugOutput(DEBUG_LEVEL_VERBOSE,"after = 0x%016llX\n", buffer);
269     }
270     #endif
271
272     *result=byteSwap_octlet(*result);
273
274     return (retval == 0);
275 }
276
277 fb_quadlet_t*
278 Ieee1394Service::transactionBlock( fb_nodeid_t nodeId,
279                                    fb_quadlet_t* buf,
280                                    int len,
281                                    unsigned int* resp_len )
282 {
283     for (int i = 0; i < len; ++i) {
284         buf[i] = ntohl( buf[i] );
285     }
286
287     fb_quadlet_t* result =
288         avc1394_transaction_block2( m_handle,
289                                     nodeId,
290                                     buf,
291                                     len,
292                                     resp_len,
293                                     10 );
294
295     for ( unsigned int i = 0; i < *resp_len; ++i ) {
296         result[i] = htonl( result[i] );
297     }
298
299     return result;
300 }
301
302
303 bool
304 Ieee1394Service::transactionBlockClose()
305 {
306     avc1394_transaction_block_close( m_handle );
307     return true;
308 }
309
310 int
311 Ieee1394Service::getVerboseLevel()
312 {
313     return getDebugLevel();
314 }
315
316 void
317 Ieee1394Service::printBuffer( unsigned int level, size_t length, fb_quadlet_t* buffer ) const
318 {
319
320     for ( unsigned int i=0; i < length; ++i ) {
321         if ( ( i % 4 ) == 0 ) {
322             if ( i > 0 ) {
323                 debugOutputShort(level,"\n");
324             }
325             debugOutputShort(level," %4d: ",i*4);
326         }
327         debugOutputShort(level,"%08X ",buffer[i]);
328     }
329     debugOutputShort(level,"\n");
330 }
331 void
332 Ieee1394Service::printBufferBytes( unsigned int level, size_t length, byte_t* buffer ) const
333 {
334
335     for ( unsigned int i=0; i < length; ++i ) {
336         if ( ( i % 16 ) == 0 ) {
337             if ( i > 0 ) {
338                 debugOutputShort(level,"\n");
339             }
340             debugOutputShort(level," %4d: ",i*16);
341         }
342         debugOutputShort(level,"%02X ",buffer[i]);
343     }
344     debugOutputShort(level,"\n");
345 }
346
347 int
348 Ieee1394Service::resetHandlerLowLevel( raw1394handle_t handle,
349                                        unsigned int generation )
350 {
351     raw1394_update_generation ( handle, generation );
352     Ieee1394Service* instance
353         = (Ieee1394Service*) raw1394_get_userdata( handle );
354     instance->resetHandler( generation );
355
356     return 0;
357 }
358
359 bool
360 Ieee1394Service::resetHandler( unsigned int generation )
361 {
362     quadlet_t buf=0;
363
364     // do a simple read on ourself in order to update the internal structures
365     // this avoids failures after a bus reset
366     read_quadlet( getLocalNodeId() & 0xFFC0,
367                   CSR_REGISTER_BASE | CSR_CYCLE_TIME,
368                   &buf );
369
370     for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin();
371           it != m_busResetHandlers.end();
372           ++it )
373     {
374         Functor* func = *it;
375         ( *func )();
376     }
377
378     return true;
379 }
380
381 bool Ieee1394Service::registerARMHandler(ARMHandler *h) {
382     debugOutput(DEBUG_LEVEL_VERBOSE, "Registering ARM handler (%p) for 0x%016llX, length %u\n",
383         h, h->getStart(), h->getLength());
384
385     int err=raw1394_arm_register(m_resetHandle, h->getStart(),
386                          h->getLength(), h->getBuffer(), (octlet_t)h,
387                          h->getAccessRights(),
388                          h->getNotificationOptions(),
389                          h->getClientTransactions());
390     if (err) {
391         debugError("Failed to register ARM handler for 0x%016llX\n", h->getStart());
392         debugError(" Error: %s\n", strerror(errno));
393         return false;
394     }
395
396     m_armHandlers.push_back( h );
397
398     return true;
399 }
400
401 bool Ieee1394Service::unregisterARMHandler( ARMHandler *h ) {
402     debugOutput(DEBUG_LEVEL_VERBOSE, "Unregistering ARM handler (%p) for 0x%016llX\n",
403         h, h->getStart());
404
405     for ( arm_handler_vec_t::iterator it = m_armHandlers.begin();
406           it != m_armHandlers.end();
407           ++it )
408     {
409         if((*it) == h) {
410             int err=raw1394_arm_unregister(m_resetHandle, h->getStart());
411             if (err) {
412                 debugError("Failed to unregister ARM handler (%p)\n", h);
413                 debugError(" Error: %s\n", strerror(errno));
414             } else {
415                 m_armHandlers.erase(it);
416                 return true;
417             }
418         }
419     }
420     debugOutput(DEBUG_LEVEL_VERBOSE, " handler not found!\n");
421
422     return false;
423 }
424 /**
425  * @brief Tries to find a free ARM address range
426  *
427  * @param start  address to start with
428  * @param length length of the block needed (bytes)
429  * @param step   step to use when searching (bytes)
430  * @return The base address that is free, and 0xFFFFFFFFFFFFFFFF when failed
431  */
432 nodeaddr_t Ieee1394Service::findFreeARMBlock( nodeaddr_t start, size_t length, size_t step ) {
433     debugOutput(DEBUG_LEVEL_VERBOSE, "Finding free ARM block of %d bytes, from 0x%016llX in steps of %d bytes\n",
434         length, start, step);
435
436     int cnt=0;
437     const int maxcnt=10;
438     int err=1;
439     while(err && cnt++ < maxcnt) {
440         // try to register
441         err=raw1394_arm_register(m_resetHandle, start, length, 0, 0, 0, 0, 0);
442
443         if (err) {
444             debugOutput(DEBUG_LEVEL_VERBOSE, " -> cannot use 0x%016llX\n", start);
445             debugError("    Error: %s\n", strerror(errno));
446             start += step;
447         } else {
448             debugOutput(DEBUG_LEVEL_VERBOSE, " -> use 0x%016llX\n", start);
449             err=raw1394_arm_unregister(m_resetHandle, start);
450             if (err) {
451                 debugOutput(DEBUG_LEVEL_VERBOSE, " error unregistering test handler\n");
452                 debugError("    Error: %s\n", strerror(errno));
453                 return 0xFFFFFFFFFFFFFFFFLLU;
454             }
455             return start;
456         }
457     }
458     debugOutput(DEBUG_LEVEL_VERBOSE, " Could not find free block in %d tries\n",cnt);
459     return 0xFFFFFFFFFFFFFFFFLLU;
460 }
461
462 int
463 Ieee1394Service::armHandlerLowLevel(raw1394handle_t handle,
464                      unsigned long arm_tag,
465                      byte_t request_type, unsigned int requested_length,
466                      void *data)
467 {
468     Ieee1394Service* instance
469         = (Ieee1394Service*) raw1394_get_userdata( handle );
470     instance->armHandler( arm_tag, request_type, requested_length, data );
471
472     return 0;
473 }
474
475 bool
476 Ieee1394Service::armHandler(  unsigned long arm_tag,
477                      byte_t request_type, unsigned int requested_length,
478                      void *data)
479 {
480     for ( arm_handler_vec_t::iterator it = m_armHandlers.begin();
481           it != m_armHandlers.end();
482           ++it )
483     {
484         if((*it) == (ARMHandler *)arm_tag) {
485             struct raw1394_arm_request_response *arm_req_resp;
486             arm_req_resp  = (struct raw1394_arm_request_response *) data;
487             raw1394_arm_request_t arm_req=arm_req_resp->request;
488             raw1394_arm_response_t arm_resp=arm_req_resp->response;
489
490             debugOutput(DEBUG_LEVEL_VERBOSE,"ARM handler for address 0x%016llX called\n",
491                 (*it)->getStart());
492             debugOutput(DEBUG_LEVEL_VERBOSE," request type   : 0x%02X\n",request_type);
493             debugOutput(DEBUG_LEVEL_VERBOSE," request length : %04d\n",requested_length);
494
495             switch(request_type) {
496                 case RAW1394_ARM_READ:
497                     (*it)->handleRead(arm_req);
498                     *arm_resp=*((*it)->getResponse());
499                     break;
500                 case RAW1394_ARM_WRITE:
501                     (*it)->handleWrite(arm_req);
502                     *arm_resp=*((*it)->getResponse());
503                     break;
504                 case RAW1394_ARM_LOCK:
505                     (*it)->handleLock(arm_req);
506                     *arm_resp=*((*it)->getResponse());
507                     break;
508                 default:
509                     debugWarning("Unknown request type received, ignoring...\n");
510             }
511
512             return true;
513         }
514     }
515
516     debugOutput(DEBUG_LEVEL_VERBOSE,"default ARM handler called\n");
517
518     m_default_arm_handler(m_resetHandle, arm_tag, request_type, requested_length, data );
519     return true;
520 }
521
522 bool
523 Ieee1394Service::startRHThread()
524 {
525     int i;
526
527     if ( m_threadRunning ) {
528         return true;
529     }
530     pthread_mutex_lock( &m_mutex );
531     i = pthread_create( &m_thread, 0, rHThread, this );
532     pthread_mutex_unlock( &m_mutex );
533     if (i) {
534         debugFatal("Could not start ieee1394 service thread\n");
535         return false;
536     }
537     m_threadRunning = true;
538
539     return true;
540 }
541
542 void
543 Ieee1394Service::stopRHThread()
544 {
545     if ( m_threadRunning ) {
546         pthread_mutex_lock (&m_mutex);
547         pthread_cancel (m_thread);
548         pthread_join (m_thread, 0);
549         pthread_mutex_unlock (&m_mutex);
550         m_threadRunning = false;
551     }
552 }
553
554 void*
555 Ieee1394Service::rHThread( void* arg )
556 {
557     Ieee1394Service* pIeee1394Service = (Ieee1394Service*) arg;
558
559     while (true) {
560         raw1394_loop_iterate (pIeee1394Service->m_resetHandle);
561         pthread_testcancel ();
562     }
563
564     return 0;
565 }
566
567 bool
568 Ieee1394Service::addBusResetHandler( Functor* functor )
569 {
570     debugOutput(DEBUG_LEVEL_VERBOSE, "Adding busreset handler (%p)\n", functor);
571     m_busResetHandlers.push_back( functor );
572     return true;
573 }
574
575 bool
576 Ieee1394Service::remBusResetHandler( Functor* functor )
577 {
578     debugOutput(DEBUG_LEVEL_VERBOSE, "Removing busreset handler (%p)\n", functor);
579
580     for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin();
581           it != m_busResetHandlers.end();
582           ++it )
583     {
584         if ( *it == functor ) {
585             debugOutput(DEBUG_LEVEL_VERBOSE, " found\n");
586             m_busResetHandlers.erase( it );
587             return true;
588         }
589     }
590     debugOutput(DEBUG_LEVEL_VERBOSE, " not found\n");
591     return false;
592 }
593
594 /**
595  * Allocates an iso channel for use by the interface in a similar way to
596  * libiec61883.  Returns -1 on error (due to there being no free channels)
597  * or an allocated channel number.
598  *
599  * Does not perform anything other than registering the channel and the
600  * bandwidth at the IRM
601  *
602  * Also allocates the necessary bandwidth (in ISO allocation units).
603  *
604  * FIXME: As in libiec61883, channel 63 is not requested; this is either a
605  * bug or it's omitted since that's the channel preferred by video devices.
606  *
607  * @param bandwidth the bandwidth to allocate for this channel
608  * @return the channel number
609  */
610 signed int Ieee1394Service::allocateIsoChannelGeneric(unsigned int bandwidth) {
611     debugOutput(DEBUG_LEVEL_VERBOSE, "Allocating ISO channel using generic method...\n" );
612
613     struct ChannelInfo cinfo;
614
615     int c = -1;
616     for (c = 0; c < 63; c++) {
617         if (raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_ALLOC) == 0)
618             break;
619     }
620     if (c < 63) {
621         if (raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_ALLOC) < 0) {
622             debugFatal("Could not allocate bandwidth of %d\n", bandwidth);
623
624             raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE);
625             return -1;
626         } else {
627             cinfo.channel=c;
628             cinfo.bandwidth=bandwidth;
629             cinfo.alloctype=AllocGeneric;
630
631             cinfo.xmit_node=-1;
632             cinfo.xmit_plug=-1;
633             cinfo.recv_node=-1;
634             cinfo.recv_plug=-1;
635
636             if (registerIsoChannel(c, cinfo)) {
637                 return c;
638             } else {
639                 raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_FREE);
640                 raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE);
641                 return -1;
642             }
643         }
644     }
645     return -1;
646 }
647
648 /**
649  * Allocates an iso channel for use by the interface in a similar way to
650  * libiec61883.  Returns -1 on error (due to there being no free channels)
651  * or an allocated channel number.
652  *
653  * Uses IEC61883 Connection Management Procedure to establish the connection.
654  *
655  * Also allocates the necessary bandwidth (in ISO allocation units).
656  *
657  * @param xmit_node  node id of the transmitter
658  * @param xmit_plug  the output plug to use. If -1, find the first online plug, and
659  * upon return, contains the plug number used.
660  * @param recv_node  node id of the receiver
661  * @param recv_plug the input plug to use. If -1, find the first online plug, and
662  * upon return, contains the plug number used.
663  *
664  * @return the channel number
665  */
666
667 signed int Ieee1394Service::allocateIsoChannelCMP(
668     nodeid_t xmit_node, int xmit_plug,
669     nodeid_t recv_node, int recv_plug
670     ) {
671
672     debugOutput(DEBUG_LEVEL_VERBOSE, "Allocating ISO channel using IEC61883 CMP...\n" );
673
674     struct ChannelInfo cinfo;
675
676     int c = -1;
677     int bandwidth=1;
678
679     // do connection management: make connection
680     c = iec61883_cmp_connect(
681         m_handle,
682         xmit_node | 0xffc0,
683         &xmit_plug,
684         recv_node | 0xffc0,
685         &recv_plug,
686         &bandwidth);
687
688     if((c<0) || (c>63)) {
689         debugError("Could not do CMP from %04X:%02d to %04X:%02d\n",
690             xmit_node, xmit_plug, recv_node, recv_plug
691             );
692         return -1;
693     }
694
695     cinfo.channel=c;
696     cinfo.bandwidth=bandwidth;
697     cinfo.alloctype=AllocCMP;
698
699     cinfo.xmit_node=xmit_node;
700     cinfo.xmit_plug=xmit_plug;
701     cinfo.recv_node=recv_node;
702     cinfo.recv_plug=recv_plug;
703
704     if (registerIsoChannel(c, cinfo)) {
705         return c;
706     }
707
708     return -1;
709 }
710
711 /**
712  * Deallocates an iso channel.  Silently ignores a request to deallocate
713  * a negative channel number.
714  *
715  * Figures out the method that was used to allocate the channel (generic, cmp, ...)
716  * and uses the appropriate method to deallocate. Also frees the bandwidth
717  * that was reserved along with this channel.
718  *
719  * @param c channel number
720  * @return true if successful
721  */
722 bool Ieee1394Service::freeIsoChannel(signed int c) {
723     debugOutput(DEBUG_LEVEL_VERBOSE, "Freeing ISO channel %d...\n", c );
724
725     if (c < 0 || c > 63) {
726         debugWarning("Invalid channel number: %d\n", c);
727         return false;
728     }
729
730     switch (m_channels[c].alloctype) {
731         default:
732             debugError(" BUG: invalid allocation type!\n");
733             return false;
734
735         case AllocFree:
736             debugWarning(" Channel %d not registered\n", c);
737             return false;
738
739         case AllocGeneric:
740             debugOutput(DEBUG_LEVEL_VERBOSE, " allocated using generic routine...\n" );
741             debugOutput(DEBUG_LEVEL_VERBOSE, " freeing %d bandwidth units...\n", m_channels[c].bandwidth );
742             if (raw1394_bandwidth_modify(m_handle, m_channels[c].bandwidth, RAW1394_MODIFY_FREE) !=0) {
743                 debugWarning("Failed to deallocate bandwidth\n");
744             }
745             debugOutput(DEBUG_LEVEL_VERBOSE, " freeing channel %d...\n", m_channels[c].channel );
746             if (raw1394_channel_modify (m_handle, m_channels[c].channel, RAW1394_MODIFY_FREE) != 0) {
747                 debugWarning("Failed to free channel\n");
748             }
749             if (!unregisterIsoChannel(c))
750                 return false;
751             return true;
752
753         case AllocCMP:
754             debugOutput(DEBUG_LEVEL_VERBOSE, " allocated using IEC61883 CMP...\n" );
755             debugOutput(DEBUG_LEVEL_VERBOSE, " performing IEC61883 CMP disconnect...\n" );
756             if(iec61883_cmp_disconnect(
757                     m_handle,
758                     m_channels[c].xmit_node | 0xffc0,
759                     m_channels[c].xmit_plug,
760                     m_channels[c].recv_node | 0xffc0,
761                     m_channels[c].recv_plug,
762                     m_channels[c].channel,
763                     m_channels[c].bandwidth) != 0) {
764                 debugWarning("Could not do CMP disconnect for channel %d!\n",c);
765             }
766             if (!unregisterIsoChannel(c))
767                 return false;
768             return true;
769     }
770
771     // unreachable
772     debugError("BUG: unreachable code reached!\n");
773
774     return false;
775 }
776
777 /**
778  * Registers a channel as managed by this ieee1394service
779  * @param c channel number
780  * @param cinfo channel info struct
781  * @return true if successful
782  */
783 bool Ieee1394Service::registerIsoChannel(unsigned int c, struct ChannelInfo cinfo) {
784     if (c < 63) {
785         if (m_channels[c].alloctype != AllocFree) {
786             debugWarning("Channel %d already registered with bandwidth %d\n",
787                 m_channels[c].channel, m_channels[c].bandwidth);
788         }
789
790         memcpy(&m_channels[c], &cinfo, sizeof(struct ChannelInfo));
791
792     } else return false;
793     return true;
794 }
795
796 /**
797  * unegisters a channel from this ieee1394service
798  * @param c channel number
799  * @return true if successful
800  */
801 bool Ieee1394Service::unregisterIsoChannel(unsigned int c) {
802     if (c < 63) {
803         if (m_channels[c].alloctype == AllocFree) {
804             debugWarning("Channel %d not registered\n", c);
805             return false;
806         }
807
808         m_channels[c].channel=-1;
809         m_channels[c].bandwidth=-1;
810         m_channels[c].alloctype=AllocFree;
811         m_channels[c].xmit_node=0xFFFF;
812         m_channels[c].xmit_plug=-1;
813         m_channels[c].recv_node=0xFFFF;
814         m_channels[c].recv_plug=-1;
815
816     } else return false;
817     return true;
818 }
819
820 /**
821  * Returns the current value of the `bandwidth available' register on
822  * the IRM, or -1 on error.
823  * @return
824  */
825 signed int Ieee1394Service::getAvailableBandwidth() {
826     quadlet_t buffer;
827     signed int result = raw1394_read (m_handle, raw1394_get_irm_id (m_handle),
828         CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE,
829         sizeof (quadlet_t), &buffer);
830
831     if (result < 0)
832         return -1;
833     return ntohl(buffer);
834 }
835
836 void
837 Ieee1394Service::setVerboseLevel(int l)
838 {
839     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
840     setDebugLevel(l);
841 }
Note: See TracBrowser for help on using the browser.