root/trunk/freebob/src/avdevice.cpp

Revision 60, 16.5 kB (checked in by wagi, 19 years ago)

Connection management implementation start.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /* avdevice.cpp
2  * Copyright (C) 2004 by Daniel Wagner, Pieter Palmers
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 <errno.h>
21 #include <libavc1394/avc1394.h>
22 #include <libavc1394/avc1394_vcr.h>
23 #include "threads.h"
24 #include "avdevice.h"
25 #include "avdevicepool.h"
26 #include "avdevicesubunit.h"
27 #include "avdeviceaudiosubunit.h"
28 #include "avdevicemusicsubunit.h"
29 #include "cmhandler.h"
30
31 #undef AVC1394_GET_RESPONSE_OPERAN
32 #define AVC1394_GET_RESPONSE_OPERAND(x, n) (((x) & (0xFF000000 >> (((n)%4)*8))) >> (((3-(n))%4)*8))
33
34 AvDevice::AvDevice(octlet_t oGuid)
35     : m_iNodeId( -1 )
36     , m_iPort( -1 )
37     , m_bInitialised( false )
38     , m_oGuid( oGuid )
39     , m_iGeneration( 0 )
40     , cSubUnits( 0 )
41     , m_iNbAsyncDestinationPlugs( 0 )
42     , m_iNbAsyncSourcePlugs( 0 )
43     , m_iNbIsoDestinationPlugs( 0 )
44     , m_iNbIsoSourcePlugs( 0 )
45     , m_iNbExtDestinationPlugs( 0 )
46     , m_iNbExtSourcePlugs( 0 )
47 {
48     setDebugLevel( DEBUG_LEVEL_MODERATE );
49     AvDevicePool::instance()->registerAvDevice( this );
50 }
51
52
53 AvDevice::~AvDevice()
54 {
55     vector<AvDeviceSubunit *>::iterator it;
56     for( it = cSubUnits.begin(); it != cSubUnits.end(); it++ ) {
57         delete *it;
58     }
59     AvDevicePool::instance()->unregisterAvDevice( this );
60 }
61
62 void
63 AvDevice::execute( EStates state )
64 {
65     switch ( state ) {
66     case eScanAndCreate:
67         if ( initialize() == eFBRC_Success ) {
68             // Initiate connection
69             asyncCall( CMHandler::instance(),
70                        &CMHandler::createConnection,
71                        this );
72             // Put ourself to sleep until a something happends
73             sleepCall( this, &AvDevice::execute, eCheckState );
74         } else {
75             asyncCall( CMHandler::instance(),
76                        &CMHandler::destroyConnection,
77                        this );
78             asyncCall( this, &AvDevice::execute, eDestroy );
79         }
80         break;
81     case eCheckState:
82         {
83             if ( m_iGeneration
84                  != Ieee1394Service::instance()->getGenerationCount() ) {
85                 asyncCall( this, &AvDevice::execute, eDestroy );
86             }
87         }
88         break;
89     case eDestroy:
90         destroyCall( this );
91         break;
92     default:
93         debugError( "Invalid state: %d\n", state );
94     }
95 }
96
97 FBReturnCodes
98 AvDevice::initialize()
99 {
100     if ( !m_bInitialised ) {
101         FBReturnCodes eStatus = enumerateSubUnits();
102         if ( eStatus != eFBRC_Success ) {
103             debugError( "Could not enumrate SubUnits\n" );
104             return eStatus;
105         }
106
107         m_bInitialised = true;
108     }
109     return eFBRC_Success;
110 }
111
112 bool AvDevice::isInitialised()
113 {
114     return m_bInitialised;
115 }
116
117 FBReturnCodes
118 AvDevice::enumerateSubUnits()
119 {
120     // enumerate the subunits present in this device, create an
121     // AvDeviceSubunit for them, and add this object to the cSubUnits
122     // vector
123     unsigned char table_entry;
124     unsigned char subunit_maxid;
125     unsigned char subunit_type;
126     // buffer these table entries, because the memory content pointed
127     // to by the response pointer can change due to other libraw
128     // operations on this handle
129     quadlet_t table_entries;
130     quadlet_t request[6];
131     quadlet_t *response;
132     AvDeviceSubunit *tmpAvDeviceSubunit=NULL;
133
134     Ieee1394Service* p1394Service = Ieee1394Service::instance();
135
136     // check the number of I/O plugs
137     request[0] = AVC1394_CTYPE_STATUS
138                  | AVC1394_SUBUNIT_TYPE_UNIT
139                  | AVC1394_SUBUNIT_ID_IGNORE
140                  | AVC1394_COMMAND_PLUG_INFO
141                  | 0x0000;
142     request[1] = 0xFFFFFFFF;
143     response = p1394Service->avcExecuteTransaction( m_iNodeId, request, 2, 2 );
144     request[1] = 0x02020606;
145     response = request;
146     if ( response ) {
147         m_iNbIsoDestinationPlugs
148             = AVC1394_GET_RESPONSE_OPERAND( response[1], 0 );
149         m_iNbIsoSourcePlugs
150             = AVC1394_GET_RESPONSE_OPERAND( response[1], 1 );
151         m_iNbExtDestinationPlugs
152             = AVC1394_GET_RESPONSE_OPERAND( response[1], 2 );
153         m_iNbExtSourcePlugs
154             = AVC1394_GET_RESPONSE_OPERAND( response[1], 3 );
155     }
156
157     request[0] = AVC1394_CTYPE_STATUS
158                  | AVC1394_SUBUNIT_TYPE_UNIT
159                  | AVC1394_SUBUNIT_ID_IGNORE
160                  | AVC1394_COMMAND_PLUG_INFO
161                  | 0x01;
162     request[1] = 0xFFFFFFFF;
163     response = p1394Service->avcExecuteTransaction( m_iNodeId, request, 2, 2 );
164     if ( response != NULL ) {
165         m_iNbAsyncDestinationPlugs
166             = AVC1394_GET_RESPONSE_OPERAND( response[1], 0 );
167         m_iNbAsyncSourcePlugs
168             = AVC1394_GET_RESPONSE_OPERAND( response[1], 1 );
169     }
170
171     debugPrint( DEBUG_LEVEL_DEVICE,
172                 "AvDevice: %d Isochronous source plugs, "
173                 "%d Isochronous destination plugs\n",
174                 m_iNbIsoSourcePlugs, m_iNbIsoDestinationPlugs);
175     debugPrint( DEBUG_LEVEL_DEVICE,
176                 "AvDevice: %d External source plugs, "
177                 "%d External destination plugs\n",
178                 m_iNbExtSourcePlugs, m_iNbExtDestinationPlugs);
179     debugPrint( DEBUG_LEVEL_DEVICE,
180                 "AvDevice: %d Asynchronous source plugs, "
181                 "%d Asynchronous destination plugs\n",
182                 m_iNbAsyncSourcePlugs, m_iNbAsyncDestinationPlugs);
183
184
185     // create the subunits
186     for (unsigned int i = 0; i < 8; i++ ) {
187         // cycle through the 8 pages (max 32 subunits; 4
188         // subunits/page)
189
190
191         request[0] = AVC1394_CTYPE_STATUS
192                      | AVC1394_SUBUNIT_TYPE_UNIT
193                      | AVC1394_SUBUNIT_ID_IGNORE
194                      | AVC1394_COMMAND_SUBUNIT_INFO
195                      | ((i<<4) & 0xF0) | 0x07;
196         request[1] = 0xFFFFFFFF;
197         response = p1394Service->avcExecuteTransaction( m_iNodeId, request, 6, 2 );
198
199         table_entries=response[1]; /// XXX buggy code! response could be 0!
200
201         if ( response != NULL ) {
202             // this way of processing the table entries assumes that
203             // the subunit type is not "extended"
204
205             // stop processing when a "not implemented" is received
206             // (according to spec)
207             if ( (response[0]&0xFF000000) == AVC1394_RESPONSE_NOT_IMPLEMENTED) {
208                 break;
209             }
210
211             // warning: don't do unsigned int j!
212             // comparison >= 0 is always true for uint
213             for ( int j = 3; j >= 0; j-- ) {
214                 // cycle through the 8 pages (max 32
215                 // subunits; 4 subunits/page)
216                 table_entry   = (table_entries >> (j*8)) & 0xFF;
217                 subunit_maxid = table_entry & 0x07;
218                 subunit_type  = (table_entry >> 3) & 0x1F;
219
220                 //debugPrint (DEBUG_LEVEL_DEVICE,"AvDevice: Page %d, item %d: Table entry=0x%02X, subunit_maxid=0x%02X, subunit_type=0x%02X\n",i,j,table_entry,subunit_maxid,subunit_type);
221
222                 // according to spec we could stop processing at the
223                 // first 0xFF entry, but doing it this way is a little
224                 // more robust
225
226                 if ( table_entry != 0xFF ) {
227                     for ( unsigned char subunit_id = 0;
228                           subunit_id < subunit_maxid+1;
229                           subunit_id++ )
230                     {
231
232                         // only two types of specific subunits are
233                         // supported: audio and music
234                         switch ( subunit_type ) {
235                         case 0x01: // audio subunit
236                             tmpAvDeviceSubunit
237                                 = new AvDeviceAudioSubunit( this,  subunit_id);
238                             if ( tmpAvDeviceSubunit ) {
239                                 // test code
240                                 //tmpAvDeviceSubunit->printOutputPlugConnections();
241                             }
242                             break;
243                         case 0x0C: // music subunit
244                             tmpAvDeviceSubunit=new AvDeviceMusicSubunit(this,subunit_id);
245                             /*{ // just a test
246                               AvDeviceMusicSubunit tmpAvDeviceSubunit2(this,subunit_id);
247                               tmpAvDeviceSubunit2.printMusicPlugInfo();
248                               tmpAvDeviceSubunit2.printMusicPlugConfigurations();
249                               tmpAvDeviceSubunit2.printOutputPlugConnections();
250                               tmpAvDeviceSubunit2.test();
251                               }*/
252                             break;
253
254                         default: // generic
255                             tmpAvDeviceSubunit=new AvDeviceSubunit(this,subunit_type,subunit_id);
256                             break;
257                         }
258
259                         if ( tmpAvDeviceSubunit
260                              && tmpAvDeviceSubunit->isValid() )
261                         {
262                             cSubUnits.push_back(tmpAvDeviceSubunit);
263                             //setDebugLevel(DEBUG_LEVEL_ALL);
264                             debugPrint( DEBUG_LEVEL_DEVICE,
265                                         "Trying to reserve the "
266                                         "subunit...\n" );
267                             tmpAvDeviceSubunit->reserve( 0x01 );
268                             debugPrint( DEBUG_LEVEL_DEVICE,
269                                         "  isReserved?: %d\n",
270                                         tmpAvDeviceSubunit->isReserved());
271                             tmpAvDeviceSubunit->unReserve();
272                             //setDebugLevel(DEBUG_LEVEL_MODERATE);
273                         } else {
274                             if ( tmpAvDeviceSubunit ) {
275                                 debugPrint( DEBUG_LEVEL_DEVICE,  "AvDevice: Unsupported AvDeviceSubunit encountered. Page %d, item %d: Table entry=0x%02X, subunit_maxid=0x%02X, subunit_type=0x%02X, subunit_id=%0x02X\n",i,j,table_entry,subunit_maxid,subunit_type,subunit_id);
276
277                                 delete tmpAvDeviceSubunit;
278                             } else {
279                                 debugPrint( DEBUG_LEVEL_DEVICE,
280                                             "AvDevice: Could not create AvDeviceSubunit object.\n");
281                             }
282                         }
283                     }
284                 }
285             }
286         }
287     }
288     return eFBRC_Success;
289 }
290
291
292 FBReturnCodes AvDevice::setInputPlugSignalFormat(unsigned char plug, unsigned char fmt, quadlet_t fdf) {
293         quadlet_t request[6];
294         quadlet_t *response;
295
296         request[0] = AVC1394_CTYPE_CONTROL | AVC1394_SUBUNIT_TYPE_UNIT | AVC1394_SUBUNIT_ID_IGNORE
297                                         | AVC1394_COMMAND_INPUT_PLUG_SIGNAL_FORMAT | plug;
298         request[1] = (0x80000000) | ((fmt & 0x3F)<<24) | (fdf & 0x00FFFFFF);
299         response = Ieee1394Service::instance()->avcExecuteTransaction( m_iNodeId, request, 2, 2);
300         if (response != NULL) {
301
302         }
303         return eFBRC_Success;
304 }
305
306 FBReturnCodes AvDevice::getInputPlugSignalFormat(unsigned char plug, unsigned char *fmt, quadlet_t *fdf) {
307         quadlet_t request[6];
308         quadlet_t *response;
309
310         request[0] = AVC1394_CTYPE_STATUS | AVC1394_SUBUNIT_TYPE_UNIT | AVC1394_SUBUNIT_ID_IGNORE
311                                         | AVC1394_COMMAND_INPUT_PLUG_SIGNAL_FORMAT | plug;
312         request[1] = 0xFFFFFFFF;
313         response = Ieee1394Service::instance()->avcExecuteTransaction( m_iNodeId, request, 2, 2);
314         if (response != NULL) {
315                 *fmt=((response[1] >> 24) & 0x3F);
316                 *fdf=response[1]& 0x00FFFFFF;
317         }
318         return eFBRC_Success;
319 }
320
321 FBReturnCodes AvDevice::setOutputPlugSignalFormat(unsigned char plug, unsigned char fmt, quadlet_t fdf) {
322         quadlet_t request[6];
323         quadlet_t *response;
324
325         request[0] = AVC1394_CTYPE_CONTROL | AVC1394_SUBUNIT_TYPE_UNIT | AVC1394_SUBUNIT_ID_IGNORE
326                                         | AVC1394_COMMAND_OUTPUT_PLUG_SIGNAL_FORMAT | plug;
327         request[1] = (0x80000000) | ((fmt & 0x3F)<<24) | (fdf & 0x00FFFFFF);
328         response = Ieee1394Service::instance()->avcExecuteTransaction(m_iNodeId, request, 2, 2);
329         if (response != NULL) {
330
331         }
332         return eFBRC_Success;
333 }
334
335 FBReturnCodes AvDevice::getOutputPlugSignalFormat(unsigned char plug, unsigned char *fmt, quadlet_t *fdf) {
336         quadlet_t request[6];
337         quadlet_t *response;
338
339         request[0] = AVC1394_CTYPE_STATUS | AVC1394_SUBUNIT_TYPE_UNIT | AVC1394_SUBUNIT_ID_IGNORE
340                                         | AVC1394_COMMAND_OUTPUT_PLUG_SIGNAL_FORMAT | plug;
341         request[1] = 0xFFFFFFFF;
342         response = Ieee1394Service::instance()->avcExecuteTransaction(m_iNodeId, request, 2, 2);
343         if (response != NULL) {
344                 *fmt=((response[1] >> 24) & 0x3F);
345                 *fdf=response[1]& 0x00FFFFFF;
346         }
347         return eFBRC_Success;
348 }
349
350 AvDeviceSubunit *AvDevice::getSubunit(unsigned char type, unsigned char id) {
351         vector<AvDeviceSubunit *>::iterator it;
352         for( it = cSubUnits.begin(); it != cSubUnits.end(); it++ ) {
353                 if ((*it) && ((*it)->getType()==type) && ((*it)->getId()==id)) {
354                         return *it;
355                 }
356         }
357         return NULL;
358 }
359
360 #define AVC1394_COMMAND_SIGNAL_SOURCE 0x00001A00
361
362 void AvDevice::printConnections() {
363     quadlet_t request[6];
364     quadlet_t *response;
365     //setDebugLevel(DEBUG_LEVEL_ALL);
366
367     debugPrint (DEBUG_LEVEL_DEVICE,"AvDevice: ISO source connections:\n");
368
369     for (unsigned int i=0;i<getNbIsoSourcePlugs();i++) {
370         request[0] = AVC1394_CTYPE_STATUS
371                      | AVC1394_SUBUNIT_TYPE_UNIT
372                      | AVC1394_SUBUNIT_ID_IGNORE
373                      | AVC1394_COMMAND_SIGNAL_SOURCE
374                      | 0x00FF;
375         request[1]=0xFFFEFF00 | ((i & 0xFF));
376
377         response = Ieee1394Service::instance()->avcExecuteTransaction(m_iNodeId, request, 2, 2);
378
379         if ( response ) {
380             unsigned char output_status=(response[0]&0xE0) >> 5;
381             unsigned char conv=(response[0]&0x10) >> 4;
382             unsigned char signal_status=(response[0]&0x0F);
383
384             unsigned int signal_source=((response[1]>>16)&0xFFFF);
385
386             unsigned char source_subunit_type=(signal_source>>11)&0x1F;
387             unsigned char source_subunit_id=(signal_source>>8)&0x07;
388             unsigned char source_plug=signal_source&0xFF;
389
390             debugPrint (DEBUG_LEVEL_DEVICE,"AvDevice:   OPCR 0x%02X <- subunit: 0x%02X/0x%02X, plug: 0x%02X (0x%02X / %d / 0x%02X)\n",i, source_subunit_type,source_subunit_id,source_plug,output_status,conv,signal_status);
391             // find the subunit this plug is connected to
392             AvDeviceSubunit *tmpSubunit=getSubunit(source_subunit_type,source_subunit_id);
393             if ( tmpSubunit ) {
394                 tmpSubunit->printSourcePlugConnections(source_plug);
395             }
396
397         }
398     }
399
400     debugPrint (DEBUG_LEVEL_DEVICE,"AvDevice: External source connections:\n");
401
402     for (unsigned int i=0;i<getNbExtSourcePlugs();i++) {
403         request[0] = AVC1394_CTYPE_STATUS
404                      | AVC1394_SUBUNIT_TYPE_UNIT
405                      | AVC1394_SUBUNIT_ID_IGNORE
406                      | AVC1394_COMMAND_SIGNAL_SOURCE
407                      | 0x00FF;
408         request[1]=0xFFFEFF00 | ((i & 0xFF)|0x80);
409
410         response = Ieee1394Service::instance()->avcExecuteTransaction(m_iNodeId, request, 2, 2);
411
412         if ( response ) {
413             unsigned char output_status=(response[0]&0xE0) >> 5;
414             unsigned char conv=(response[0]&0x10) >> 4;
415             unsigned char signal_status=(response[0]&0x0F);
416
417             unsigned int signal_source=((response[1]>>16)&0xFFFF);
418
419             unsigned char source_subunit_type=(signal_source>>11)&0x1F;
420             unsigned char source_subunit_id=(signal_source>>8)&0x07;
421             unsigned char source_plug=signal_source&0xFF;
422
423             debugPrint (DEBUG_LEVEL_DEVICE,"AvDevice:   EXTOUT 0x%02X <- subunit: 0x%02X/0x%02X, plug: 0x%02X (0x%02X / %d / 0x%02X)\n",i, source_subunit_type,source_subunit_id,source_plug,output_status,conv,signal_status);
424
425             // find the subunit this plug is connected to
426             AvDeviceSubunit *tmpSubunit=getSubunit(source_subunit_type,source_subunit_id);
427             if ( tmpSubunit ) {
428                 tmpSubunit->printSourcePlugConnections(source_plug);
429             }
430         }
431     }
432
433     debugPrint (DEBUG_LEVEL_DEVICE,"AvDevice: ISO sink connections:\n");
434
435     for (unsigned int i=0;i<getNbIsoDestinationPlugs();i++) {
436         request[0] = AVC1394_CTYPE_STATUS
437                      | AVC1394_SUBUNIT_TYPE_UNIT
438                      | AVC1394_SUBUNIT_ID_IGNORE
439                      | AVC1394_COMMAND_SIGNAL_SOURCE
440                      | 0x00FF;
441         request[1] = 0xFFFEFF00 | ((i & 0xFF));
442
443         response = Ieee1394Service::instance()->avcExecuteTransaction(m_iNodeId, request, 2, 2);
444
445         if ( response ) {
446             unsigned char output_status=(response[0]&0xE0) >> 5;
447             unsigned char conv=(response[0]&0x10) >> 4;
448             unsigned char signal_status=(response[0]&0x0F);
449
450             unsigned int signal_source=((response[1]>>16)&0xFFFF);
451
452             unsigned char source_subunit_type=(signal_source>>11)&0x1F;
453             unsigned char source_subunit_id=(signal_source>>8)&0x07;
454             unsigned char source_plug=signal_source&0xFF;
455
456             debugPrint (DEBUG_LEVEL_DEVICE,"AvDevice:   OPCR 0x%02X <- subunit: 0x%02X/0x%02X, plug: 0x%02X (0x%02X / %d / 0x%02X)\n",i, source_subunit_type,source_subunit_id,source_plug,output_status,conv,signal_status);
457             // find the subunit this plug is connected to
458             AvDeviceSubunit *tmpSubunit
459                 = getSubunit(source_subunit_type,source_subunit_id);
460             if ( tmpSubunit ) {
461                 //tmpSubunit->printDestinationPlugConnections(source_plug);
462             }
463
464         }
465     }
466
467     debugPrint (DEBUG_LEVEL_DEVICE,"AvDevice: External sink connections:\n");
468
469     for (unsigned int i=0;i<getNbExtDestinationPlugs();i++) {
470         request[0] = AVC1394_CTYPE_STATUS
471                      | AVC1394_SUBUNIT_TYPE_UNIT
472                      | AVC1394_SUBUNIT_ID_IGNORE
473                      | AVC1394_COMMAND_SIGNAL_SOURCE
474                      | 0x00FF;
475         request[1]=0xFFFEFF00 | ((i & 0xFF)|0x80);
476
477         response = Ieee1394Service::instance()->avcExecuteTransaction(m_iNodeId, request, 2, 2);
478
479         if ( response ) {
480             unsigned char output_status=(response[0]&0xE0) >> 5;
481             unsigned char conv=(response[0]&0x10) >> 4;
482             unsigned char signal_status=(response[0]&0x0F);
483
484             unsigned int signal_source=((response[1]>>16)&0xFFFF);
485
486             unsigned char source_subunit_type=(signal_source>>11)&0x1F;
487             unsigned char source_subunit_id=(signal_source>>8)&0x07;
488             unsigned char source_plug=signal_source&0xFF;
489
490             debugPrint (DEBUG_LEVEL_DEVICE,"AvDevice:   EXTOUT 0x%02X <- subunit: 0x%02X/0x%02X, plug: 0x%02X (0x%02X / %d / 0x%02X)\n",i, source_subunit_type,source_subunit_id,source_plug,output_status,conv,signal_status);
491
492             // find the subunit this plug is connected to
493             AvDeviceSubunit *tmpSubunit
494                 = getSubunit(source_subunit_type,source_subunit_id);
495             if ( tmpSubunit ) {
496                 //tmpSubunit->printDestinationPlugConnections(source_plug);
497             }
498         }
499     }
500 }
Note: See TracBrowser for help on using the browser.