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

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

fix bus reset behavior

  • 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     m_generation = generation;
363     quadlet_t buf=0;
364
365     // do a simple read on ourself in order to update the internal structures
366     // this avoids failures after a bus reset
367     read_quadlet( getLocalNodeId() & 0xFFC0,
368                   CSR_REGISTER_BASE | CSR_CYCLE_TIME,
369                   &buf );
370
371     for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin();
372           it != m_busResetHandlers.end();
373           ++it )
374     {
375         Functor* func = *it;
376         ( *func )();
377     }
378
379     return true;
380 }
381
382 bool Ieee1394Service::registerARMHandler(ARMHandler *h) {
383     debugOutput(DEBUG_LEVEL_VERBOSE, "Registering ARM handler (%p) for 0x%016llX, length %u\n",
384         h, h->getStart(), h->getLength());
385
386     int err=raw1394_arm_register(m_resetHandle, h->getStart(),
387                          h->getLength(), h->getBuffer(), (octlet_t)h,
388                          h->getAccessRights(),
389                          h->getNotificationOptions(),
390                          h->getClientTransactions());
391     if (err) {
392         debugError("Failed to register ARM handler for 0x%016llX\n", h->getStart());
393         debugError(" Error: %s\n", strerror(errno));
394         return false;
395     }
396
397     m_armHandlers.push_back( h );
398
399     return true;
400 }
401
402 bool Ieee1394Service::unregisterARMHandler( ARMHandler *h ) {
403     debugOutput(DEBUG_LEVEL_VERBOSE, "Unregistering ARM handler (%p) for 0x%016llX\n",
404         h, h->getStart());
405
406     for ( arm_handler_vec_t::iterator it = m_armHandlers.begin();
407           it != m_armHandlers.end();
408           ++it )
409     {
410         if((*it) == h) {
411             int err=raw1394_arm_unregister(m_resetHandle, h->getStart());
412             if (err) {
413                 debugError("Failed to unregister ARM handler (%p)\n", h);
414                 debugError(" Error: %s\n", strerror(errno));
415             } else {
416                 m_armHandlers.erase(it);
417                 return true;
418             }
419         }
420     }
421     debugOutput(DEBUG_LEVEL_VERBOSE, " handler not found!\n");
422
423     return false;
424 }
425 /**
426  * @brief Tries to find a free ARM address range
427  *
428  * @param start  address to start with
429  * @param length length of the block needed (bytes)
430  * @param step   step to use when searching (bytes)
431  * @return The base address that is free, and 0xFFFFFFFFFFFFFFFF when failed
432  */
433 nodeaddr_t Ieee1394Service::findFreeARMBlock( nodeaddr_t start, size_t length, size_t step ) {
434     debugOutput(DEBUG_LEVEL_VERBOSE, "Finding free ARM block of %d bytes, from 0x%016llX in steps of %d bytes\n",
435         length, start, step);
436
437     int cnt=0;
438     const int maxcnt=10;
439     int err=1;
440     while(err && cnt++ < maxcnt) {
441         // try to register
442         err=raw1394_arm_register(m_resetHandle, start, length, 0, 0, 0, 0, 0);
443
444         if (err) {
445             debugOutput(DEBUG_LEVEL_VERBOSE, " -> cannot use 0x%016llX\n", start);
446             debugError("    Error: %s\n", strerror(errno));
447             start += step;
448         } else {
449             debugOutput(DEBUG_LEVEL_VERBOSE, " -> use 0x%016llX\n", start);
450             err=raw1394_arm_unregister(m_resetHandle, start);
451             if (err) {
452                 debugOutput(DEBUG_LEVEL_VERBOSE, " error unregistering test handler\n");
453                 debugError("    Error: %s\n", strerror(errno));
454                 return 0xFFFFFFFFFFFFFFFFLLU;
455             }
456             return start;
457         }
458     }
459     debugOutput(DEBUG_LEVEL_VERBOSE, " Could not find free block in %d tries\n",cnt);
460     return 0xFFFFFFFFFFFFFFFFLLU;
461 }
462
463 int
464 Ieee1394Service::armHandlerLowLevel(raw1394handle_t handle,
465                      unsigned long arm_tag,
466                      byte_t request_type, unsigned int requested_length,
467                      void *data)
468 {
469     Ieee1394Service* instance
470         = (Ieee1394Service*) raw1394_get_userdata( handle );
471     instance->armHandler( arm_tag, request_type, requested_length, data );
472
473     return 0;
474 }
475
476 bool
477 Ieee1394Service::armHandler(  unsigned long arm_tag,
478                      byte_t request_type, unsigned int requested_length,
479                      void *data)
480 {
481     for ( arm_handler_vec_t::iterator it = m_armHandlers.begin();
482           it != m_armHandlers.end();
483           ++it )
484     {
485         if((*it) == (ARMHandler *)arm_tag) {
486             struct raw1394_arm_request_response *arm_req_resp;
487             arm_req_resp  = (struct raw1394_arm_request_response *) data;
488             raw1394_arm_request_t arm_req=arm_req_resp->request;
489             raw1394_arm_response_t arm_resp=arm_req_resp->response;
490
491             debugOutput(DEBUG_LEVEL_VERBOSE,"ARM handler for address 0x%016llX called\n",
492                 (*it)->getStart());
493             debugOutput(DEBUG_LEVEL_VERBOSE," request type   : 0x%02X\n",request_type);
494             debugOutput(DEBUG_LEVEL_VERBOSE," request length : %04d\n",requested_length);
495
496             switch(request_type) {
497                 case RAW1394_ARM_READ:
498                     (*it)->handleRead(arm_req);
499                     *arm_resp=*((*it)->getResponse());
500                     break;
501                 case RAW1394_ARM_WRITE:
502                     (*it)->handleWrite(arm_req);
503                     *arm_resp=*((*it)->getResponse());
504                     break;
505                 case RAW1394_ARM_LOCK:
506                     (*it)->handleLock(arm_req);
507                     *arm_resp=*((*it)->getResponse());
508                     break;
509                 default:
510                     debugWarning("Unknown request type received, ignoring...\n");
511             }
512
513             return true;
514         }
515     }
516
517     debugOutput(DEBUG_LEVEL_VERBOSE,"default ARM handler called\n");
518
519     m_default_arm_handler(m_resetHandle, arm_tag, request_type, requested_length, data );
520     return true;
521 }
522
523 bool
524 Ieee1394Service::startRHThread()
525 {
526     int i;
527
528     if ( m_threadRunning ) {
529         return true;
530     }
531     pthread_mutex_lock( &m_mutex );
532     i = pthread_create( &m_thread, 0, rHThread, this );
533     pthread_mutex_unlock( &m_mutex );
534     if (i) {
535         debugFatal("Could not start ieee1394 service thread\n");
536         return false;
537     }
538     m_threadRunning = true;
539
540     return true;
541 }
542
543 void
544 Ieee1394Service::stopRHThread()
545 {
546     if ( m_threadRunning ) {
547         pthread_mutex_lock (&m_mutex);
548         pthread_cancel (m_thread);
549         pthread_join (m_thread, 0);
550         pthread_mutex_unlock (&m_mutex);
551         m_threadRunning = false;
552     }
553 }
554
555 void*
556 Ieee1394Service::rHThread( void* arg )
557 {
558     Ieee1394Service* pIeee1394Service = (Ieee1394Service*) arg;
559
560     while (true) {
561         raw1394_loop_iterate (pIeee1394Service->m_resetHandle);
562         pthread_testcancel ();
563     }
564
565     return 0;
566 }
567
568 bool
569 Ieee1394Service::addBusResetHandler( Functor* functor )
570 {
571     debugOutput(DEBUG_LEVEL_VERBOSE, "Adding busreset handler (%p)\n", functor);
572     m_busResetHandlers.push_back( functor );
573     return true;
574 }
575
576 bool
577 Ieee1394Service::remBusResetHandler( Functor* functor )
578 {
579     debugOutput(DEBUG_LEVEL_VERBOSE, "Removing busreset handler (%p)\n", functor);
580
581     for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin();
582           it != m_busResetHandlers.end();
583           ++it )
584     {
585         if ( *it == functor ) {
586             debugOutput(DEBUG_LEVEL_VERBOSE, " found\n");
587             m_busResetHandlers.erase( it );
588             return true;
589         }
590     }
591     debugOutput(DEBUG_LEVEL_VERBOSE, " not found\n");
592     return false;
593 }
594
595 /**
596  * Allocates an iso channel for use by the interface in a similar way to
597  * libiec61883.  Returns -1 on error (due to there being no free channels)
598  * or an allocated channel number.
599  *
600  * Does not perform anything other than registering the channel and the
601  * bandwidth at the IRM
602  *
603  * Also allocates the necessary bandwidth (in ISO allocation units).
604  *
605  * FIXME: As in libiec61883, channel 63 is not requested; this is either a
606  * bug or it's omitted since that's the channel preferred by video devices.
607  *
608  * @param bandwidth the bandwidth to allocate for this channel
609  * @return the channel number
610  */
611 signed int Ieee1394Service::allocateIsoChannelGeneric(unsigned int bandwidth) {
612     debugOutput(DEBUG_LEVEL_VERBOSE, "Allocating ISO channel using generic method...\n" );
613
614     struct ChannelInfo cinfo;
615
616     int c = -1;
617     for (c = 0; c < 63; c++) {
618         if (raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_ALLOC) == 0)
619             break;
620     }
621     if (c < 63) {
622         if (raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_ALLOC) < 0) {
623             debugFatal("Could not allocate bandwidth of %d\n", bandwidth);
624
625             raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE);
626             return -1;
627         } else {
628             cinfo.channel=c;
629             cinfo.bandwidth=bandwidth;
630             cinfo.alloctype=AllocGeneric;
631
632             cinfo.xmit_node=-1;
633             cinfo.xmit_plug=-1;
634             cinfo.recv_node=-1;
635             cinfo.recv_plug=-1;
636
637             if (registerIsoChannel(c, cinfo)) {
638                 return c;
639             } else {
640                 raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_FREE);
641                 raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE);
642                 return -1;
643             }
644         }
645     }
646     return -1;
647 }
648
649 /**
650  * Allocates an iso channel for use by the interface in a similar way to
651  * libiec61883.  Returns -1 on error (due to there being no free channels)
652  * or an allocated channel number.
653  *
654  * Uses IEC61883 Connection Management Procedure to establish the connection.
655  *
656  * Also allocates the necessary bandwidth (in ISO allocation units).
657  *
658  * @param xmit_node  node id of the transmitter
659  * @param xmit_plug  the output plug to use. If -1, find the first online plug, and
660  * upon return, contains the plug number used.
661  * @param recv_node  node id of the receiver
662  * @param recv_plug the input plug to use. If -1, find the first online plug, and
663  * upon return, contains the plug number used.
664  *
665  * @return the channel number
666  */
667
668 signed int Ieee1394Service::allocateIsoChannelCMP(
669     nodeid_t xmit_node, int xmit_plug,
670     nodeid_t recv_node, int recv_plug
671     ) {
672
673     debugOutput(DEBUG_LEVEL_VERBOSE, "Allocating ISO channel using IEC61883 CMP...\n" );
674
675     struct ChannelInfo cinfo;
676
677     int c = -1;
678     int bandwidth=1;
679
680     // do connection management: make connection
681     c = iec61883_cmp_connect(
682         m_handle,
683         xmit_node | 0xffc0,
684         &xmit_plug,
685         recv_node | 0xffc0,
686         &recv_plug,
687         &bandwidth);
688
689     if((c<0) || (c>63)) {
690         debugError("Could not do CMP from %04X:%02d to %04X:%02d\n",
691             xmit_node, xmit_plug, recv_node, recv_plug
692             );
693         return -1;
694     }
695
696     cinfo.channel=c;
697     cinfo.bandwidth=bandwidth;
698     cinfo.alloctype=AllocCMP;
699
700     cinfo.xmit_node=xmit_node;
701     cinfo.xmit_plug=xmit_plug;
702     cinfo.recv_node=recv_node;
703     cinfo.recv_plug=recv_plug;
704
705     if (registerIsoChannel(c, cinfo)) {
706         return c;
707     }
708
709     return -1;
710 }
711
712 /**
713  * Deallocates an iso channel.  Silently ignores a request to deallocate
714  * a negative channel number.
715  *
716  * Figures out the method that was used to allocate the channel (generic, cmp, ...)
717  * and uses the appropriate method to deallocate. Also frees the bandwidth
718  * that was reserved along with this channel.
719  *
720  * @param c channel number
721  * @return true if successful
722  */
723 bool Ieee1394Service::freeIsoChannel(signed int c) {
724     debugOutput(DEBUG_LEVEL_VERBOSE, "Freeing ISO channel %d...\n", c );
725
726     if (c < 0 || c > 63) {
727         debugWarning("Invalid channel number: %d\n", c);
728         return false;
729     }
730
731     switch (m_channels[c].alloctype) {
732         default:
733             debugError(" BUG: invalid allocation type!\n");
734             return false;
735
736         case AllocFree:
737             debugWarning(" Channel %d not registered\n", c);
738             return false;
739
740         case AllocGeneric:
741             debugOutput(DEBUG_LEVEL_VERBOSE, " allocated using generic routine...\n" );
742             debugOutput(DEBUG_LEVEL_VERBOSE, " freeing %d bandwidth units...\n", m_channels[c].bandwidth );
743             if (raw1394_bandwidth_modify(m_handle, m_channels[c].bandwidth, RAW1394_MODIFY_FREE) !=0) {
744                 debugWarning("Failed to deallocate bandwidth\n");
745             }
746             debugOutput(DEBUG_LEVEL_VERBOSE, " freeing channel %d...\n", m_channels[c].channel );
747             if (raw1394_channel_modify (m_handle, m_channels[c].channel, RAW1394_MODIFY_FREE) != 0) {
748                 debugWarning("Failed to free channel\n");
749             }
750             if (!unregisterIsoChannel(c))
751                 return false;
752             return true;
753
754         case AllocCMP:
755             debugOutput(DEBUG_LEVEL_VERBOSE, " allocated using IEC61883 CMP...\n" );
756             debugOutput(DEBUG_LEVEL_VERBOSE, " performing IEC61883 CMP disconnect...\n" );
757             if(iec61883_cmp_disconnect(
758                     m_handle,
759                     m_channels[c].xmit_node | 0xffc0,
760                     m_channels[c].xmit_plug,
761                     m_channels[c].recv_node | 0xffc0,
762                     m_channels[c].recv_plug,
763                     m_channels[c].channel,
764                     m_channels[c].bandwidth) != 0) {
765                 debugWarning("Could not do CMP disconnect for channel %d!\n",c);
766             }
767             if (!unregisterIsoChannel(c))
768                 return false;
769             return true;
770     }
771
772     // unreachable
773     debugError("BUG: unreachable code reached!\n");
774
775     return false;
776 }
777
778 /**
779  * Registers a channel as managed by this ieee1394service
780  * @param c channel number
781  * @param cinfo channel info struct
782  * @return true if successful
783  */
784 bool Ieee1394Service::registerIsoChannel(unsigned int c, struct ChannelInfo cinfo) {
785     if (c < 63) {
786         if (m_channels[c].alloctype != AllocFree) {
787             debugWarning("Channel %d already registered with bandwidth %d\n",
788                 m_channels[c].channel, m_channels[c].bandwidth);
789         }
790
791         memcpy(&m_channels[c], &cinfo, sizeof(struct ChannelInfo));
792
793     } else return false;
794     return true;
795 }
796
797 /**
798  * unegisters a channel from this ieee1394service
799  * @param c channel number
800  * @return true if successful
801  */
802 bool Ieee1394Service::unregisterIsoChannel(unsigned int c) {
803     if (c < 63) {
804         if (m_channels[c].alloctype == AllocFree) {
805             debugWarning("Channel %d not registered\n", c);
806             return false;
807         }
808
809         m_channels[c].channel=-1;
810         m_channels[c].bandwidth=-1;
811         m_channels[c].alloctype=AllocFree;
812         m_channels[c].xmit_node=0xFFFF;
813         m_channels[c].xmit_plug=-1;
814         m_channels[c].recv_node=0xFFFF;
815         m_channels[c].recv_plug=-1;
816
817     } else return false;
818     return true;
819 }
820
821 /**
822  * Returns the current value of the `bandwidth available' register on
823  * the IRM, or -1 on error.
824  * @return
825  */
826 signed int Ieee1394Service::getAvailableBandwidth() {
827     quadlet_t buffer;
828     signed int result = raw1394_read (m_handle, raw1394_get_irm_id (m_handle),
829         CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE,
830         sizeof (quadlet_t), &buffer);
831
832     if (result < 0)
833         return -1;
834     return ntohl(buffer);
835 }
836
837 void
838 Ieee1394Service::setVerboseLevel(int l)
839 {
840     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
841     setDebugLevel(l);
842 }
Note: See TracBrowser for help on using the browser.