root/branches/libffado-2.0/src/libavc/general/avc_generic.cpp

Revision 1219, 9.4 kB (checked in by ppalmers, 16 years ago)

fix various problems with DM1x00 devices being flooded with data

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2008 by Daniel Wagner
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "avc_generic.h"
25 #include "libutil/cmd_serialize.h"
26 #include "libieee1394/ieee1394service.h"
27
28 #include "debugmodule/debugmodule.h"
29
30 #include "libutil/Time.h"
31
32 #include "libutil/ByteSwap.h"
33
34 #define DEBUG_EXTRA_VERBOSE 5
35
36
37 namespace AVC {
38
39 IMPL_DEBUG_MODULE( AVCCommand, AVCCommand, DEBUG_LEVEL_NORMAL );
40 IMPL_DEBUG_MODULE( IBusData, IBusData, DEBUG_LEVEL_VERBOSE );
41
42 int AVCCommand::m_time = 0;
43
44 AVCCommand::AVCCommand( Ieee1394Service& ieee1394service,
45                         opcode_t opcode )
46     : m_p1394Service( &ieee1394service )
47     , m_nodeId( 0 )
48     , m_ctype( eCT_Unknown )
49     , m_subunit( 0xff )
50     , m_opcode( opcode )
51     , m_eResponse( eR_Unknown )
52 {
53
54 }
55
56 bool
57 AVCCommand::serialize( Util::Cmd::IOSSerialize& se )
58 {
59     // XXX \todo improve Util::Cmd::IOSSerialize::write interface
60     char* buf;
61     asprintf( &buf, "AVCCommand ctype ('%s')",
62               responseToString( static_cast<AVCCommand::EResponse>( m_ctype ) ) );
63     se.write( m_ctype, buf );
64     free( buf );
65
66     asprintf( &buf, "AVCCommand subunit (subunit_type = %d, subunit_id = %d)",
67               getSubunitType(), getSubunitId() );
68     se.write( m_subunit, buf );
69     free( buf );
70
71     se.write( m_opcode, "AVCCommand opcode" );
72     return true;
73 }
74
75 bool
76 AVCCommand::deserialize( Util::Cmd::IISDeserialize& de )
77 {
78     de.read( &m_ctype );
79     de.read( &m_subunit );
80     de.read( &m_opcode );
81     return true;
82 }
83
84 bool
85 AVCCommand::setCommandType( ECommandType commandType )
86 {
87     m_ctype = commandType;
88     m_commandType = commandType;
89     return true;
90 }
91
92 AVCCommand::ECommandType
93 AVCCommand::getCommandType()
94 {
95     return m_commandType;
96 }
97
98 AVCCommand::EResponse
99 AVCCommand::getResponse()
100 {
101     return m_eResponse;
102 }
103
104 bool
105 AVCCommand::setSubunitType(ESubunitType subunitType)
106 {
107     byte_t subT = subunitType;
108
109     m_subunit = ( subT << 3 ) | ( m_subunit & 0x7 );
110     return true;
111 }
112
113 bool
114 AVCCommand::setNodeId( fb_nodeid_t nodeId )
115 {
116     m_nodeId = nodeId;
117     return true;
118 }
119
120 bool
121 AVCCommand::setSubunitId(subunit_id_t subunitId)
122 {
123     m_subunit = ( subunitId & 0x7 ) | ( m_subunit & 0xf8 );
124     return true;
125 }
126
127 ESubunitType
128 AVCCommand::getSubunitType()
129 {
130     return static_cast<ESubunitType>( ( m_subunit >> 3 ) );
131 }
132
133 subunit_id_t
134 AVCCommand::getSubunitId()
135 {
136     return m_subunit & 0x7;
137 }
138
139 bool
140 AVCCommand::setVerbose( int verboseLevel )
141 {
142     setDebugLevel(verboseLevel);
143     return true;
144 }
145
146 int
147 AVCCommand::getVerboseLevel()
148 {
149     return getDebugLevel();
150 }
151
152
153 void
154 AVCCommand::showFcpFrame( const unsigned char* buf,
155                           unsigned short frameSize ) const
156 {
157     // use an intermediate buffer to avoid a load of very small print's that cause the
158     // message ringbuffer to overflow
159     char msg[DEBUG_MAX_MESSAGE_LENGTH];
160     int chars_written=0;
161     for ( int i = 0; i < frameSize; ++i ) {
162         if ( ( i % 16 ) == 0 ) {
163             if ( i > 0 ) {
164                 debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "%s\n", msg);
165                 chars_written=0;
166             }
167             chars_written+=snprintf(msg+chars_written,DEBUG_MAX_MESSAGE_LENGTH-chars_written,"  %3d:\t", i );;
168         } else if ( ( i % 4 ) == 0 ) {
169             chars_written+=snprintf(msg+chars_written,DEBUG_MAX_MESSAGE_LENGTH-chars_written," ");
170         }
171         chars_written+=snprintf(msg+chars_written,DEBUG_MAX_MESSAGE_LENGTH-chars_written, "%02x ", buf[i] );
172     }
173     if (chars_written != 0) {
174         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "%s\n", msg );
175     } else {
176         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "\n" );
177     }
178 }
179
180 bool
181 AVCCommand::fire()
182 {
183     memset( &m_fcpFrame,  0x0,  sizeof( m_fcpFrame ) );
184
185     Util::Cmd::BufferSerialize se( m_fcpFrame, sizeof( m_fcpFrame ) );
186     if ( !serialize( se ) ) {
187         debugFatal(  "fire: Could not serialize\n" );
188         return false;
189     }
190
191     unsigned short fcpFrameSize = se.getNrOfProducesBytes();
192
193     if (getDebugLevel() >= DEBUG_LEVEL_VERY_VERBOSE) {
194         debugOutputShort( DEBUG_LEVEL_VERY_VERBOSE, "%s:\n", getCmdName() );
195         debugOutputShort( DEBUG_LEVEL_VERY_VERBOSE,  "  Request:\n");
196         showFcpFrame( m_fcpFrame, fcpFrameSize );
197
198         Util::Cmd::StringSerializer se_dbg;
199         serialize( se_dbg );
200        
201         // output the debug message in smaller chunks to avoid problems
202         // with a max message size
203         unsigned int chars_to_write=se_dbg.getString().size();
204         unsigned int chars_written=0;
205         while (chars_written<chars_to_write) {
206             debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "%s\n",
207                          se_dbg.getString().substr(chars_written, DEBUG_MAX_MESSAGE_LENGTH).c_str());
208             chars_written += DEBUG_MAX_MESSAGE_LENGTH-1;
209         }
210     }
211
212     int ntries = 10;
213     bool result = false;
214     while(ntries--) {
215         unsigned int resp_len;
216         quadlet_t* resp = m_p1394Service->transactionBlock( m_nodeId,
217                                                             (quadlet_t*)m_fcpFrame,
218                                                             ( fcpFrameSize+3 ) / 4,
219                                                             &resp_len );
220         if ( resp ) {
221             resp_len *= 4;
222             unsigned char* buf = ( unsigned char* ) resp;
223    
224             m_eResponse = ( EResponse )( *buf );
225             switch ( m_eResponse )
226             {
227                 case eR_Accepted:
228                 case eR_Implemented:
229                 case eR_Rejected:
230                 case eR_NotImplemented:
231                 {
232                     Util::Cmd::BufferDeserialize de( buf, resp_len );
233                     result = deserialize( de );
234        
235                     debugOutputShort( DEBUG_LEVEL_VERY_VERBOSE,"  Response:\n");
236                     showFcpFrame( buf, de.getNrOfConsumedBytes() );
237        
238                     Util::Cmd::StringSerializer se_dbg;
239                     serialize( se_dbg );
240        
241                     // output the debug message in smaller chunks to avoid problems
242                     // with a max message size
243                     unsigned int chars_to_write=se_dbg.getString().size();
244                     unsigned int chars_written=0;
245                     while (chars_written<chars_to_write) {
246                         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "%s\n",
247                                     se_dbg.getString().substr(chars_written, DEBUG_MAX_MESSAGE_LENGTH).c_str());
248                         chars_written += DEBUG_MAX_MESSAGE_LENGTH-1;
249                     }
250                 }
251                 break;
252                 default:
253                     debugWarning( "unexpected response received (0x%x)\n", m_eResponse );
254                     debugOutputShort( DEBUG_LEVEL_VERY_VERBOSE,"  Response:\n");
255        
256                     Util::Cmd::BufferDeserialize de( buf, resp_len );
257                     deserialize( de );
258        
259                     showFcpFrame( buf, de.getNrOfConsumedBytes() );
260    
261             }
262             debugOutputShort( DEBUG_LEVEL_VERY_VERBOSE, "\n" );
263             m_p1394Service->transactionBlockClose();
264             break; // response received
265         } else {
266             debugOutput( DEBUG_LEVEL_VERBOSE, "no response (ntries: %d)\n", ntries );
267             m_p1394Service->transactionBlockClose();
268             SleepRelativeUsec( m_time * 10 );
269         }
270     }
271
272     if (!ntries) {
273         debugWarning( "transaction failed\n" );
274     }
275
276     SleepRelativeUsec( m_time );
277
278     return result;
279 }
280
281 void
282 AVCCommand::setSleepAfterAVCCommand( int time )
283 {
284     m_time = time;
285 }
286
287 const char* subunitTypeStrings[] =
288 {
289     "Monitor",
290     "Audio",
291     "Printer",
292     "Disc recorder",
293     "Tape recorder/VCR",
294     "Tuner",
295     "CA",
296     "Video camera",
297     "unknown",
298     "Panel",
299     "Bulletin board",
300     "Camera storage",
301     "Music",
302 };
303
304 const char*
305 subunitTypeToString( subunit_type_t subunitType )
306 {
307     if ( subunitType == eST_Unit ) {
308         return "Unit";
309     }
310     if ( subunitType > ( int ) ( sizeof( subunitTypeStrings )
311              / sizeof( subunitTypeStrings[0] ) ) ) {
312         return "unknown";
313     } else {
314         return subunitTypeStrings[subunitType];
315     }
316 }
317
318 const char* responseToStrings[] =
319 {
320     "control",
321     "status",
322     "specific inquiry",
323     "notify",
324     "general inquiry",
325     "reserved for future specification",
326     "reserved for future specification",
327     "reserved for future specification",
328     "not implemented",
329     "accepted",
330     "rejected",
331     "in transition",
332     "implemented/stable",
333     "changed"
334     "reserved for future specification",
335     "interim",
336 };
337
338 const char*
339 responseToString( AVCCommand::EResponse eResponse )
340 {
341     if ( eResponse > ( int )( sizeof( responseToStrings ) / sizeof( responseToStrings[0] ) ) ) {
342         return "unknown";
343     }
344     return responseToStrings[eResponse];
345 }
346
347 }
Note: See TracBrowser for help on using the browser.