root/branches/libfreebob-downloader/src/configrom.cpp

Revision 271, 12.4 kB (checked in by wagi, 17 years ago)

2006-06-21 Daniel Wagner <wagi@monom.org>

  • freebob-downloader first version added
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /* configrom.cpp
2  * Copyright (C) 2005 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
21 #include "configrom.h"
22 #include "libfreebobavc/ieee1394service.h"
23
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <iostream>
28 #include <iomanip>
29
30 using namespace std;
31
32 IMPL_DEBUG_MODULE( ConfigRom, ConfigRom, DEBUG_LEVEL_NORMAL );
33
34 static int busRead( struct csr1212_csr* csr,
35                     u_int64_t addr,
36                     u_int16_t length,
37                     void* buffer,
38                     void* private_data );
39
40 static int getMaxRom( u_int32_t* bus_info_data,
41                       void* private_data );
42
43 static struct csr1212_bus_ops configrom_csr1212_ops = {
44     busRead,
45     0,
46     0,
47     getMaxRom
48 };
49
50 struct config_csr_info {
51     Ieee1394Service* service;
52     fb_nodeid_t      nodeId;
53 };
54
55 //-------------------------------------------------------------
56
57 ConfigRom::ConfigRom( Ieee1394Service* ieee1394service, fb_nodeid_t nodeId )
58     : m_1394Service( ieee1394service )
59     , m_nodeId( nodeId )
60     , m_avcDevice( false )
61     , m_guid( 0 )
62     , m_vendorName( "" )
63     , m_modelName( "" )
64     , m_vendorId( 0 )
65     , m_modelId( 0 )
66     , m_isIsoResourceManager( false )
67     , m_isCycleMasterCapable( false )
68     , m_isSupportIsoOperations( false )
69     , m_isBusManagerCapable( false )
70     , m_cycleClkAcc( 0 )
71     , m_maxRec( 0 )
72     , m_nodeVendorId( 0 )
73     , m_chipIdHi( 0 )
74     , m_chipIdLow( 0 )
75     , m_vendorNameKv( 0 )
76     , m_modelNameKv( 0 )
77     , m_csr( 0 )
78 {
79 }
80
81 ConfigRom::~ConfigRom()
82 {
83 }
84
85 bool
86 ConfigRom::initialize()
87 {
88      struct config_csr_info csr_info;
89      csr_info.service = m_1394Service;
90      csr_info.nodeId = 0xffc0 | m_nodeId;
91
92      m_csr = csr1212_create_csr( &configrom_csr1212_ops,
93                                  5 * sizeof(fb_quadlet_t),   // XXX Why 5 ?!?
94                                  &csr_info );
95     if (!m_csr || csr1212_parse_csr( m_csr ) != CSR1212_SUCCESS) {
96         debugError( "Could not parse config rom of node %d on port %d", m_nodeId, m_1394Service->getPort() );
97         if (m_csr) {
98             csr1212_destroy_csr(m_csr);
99             m_csr = 0;
100         }
101         return false;
102     }
103
104     // Process Bus_Info_Block
105     m_isIsoResourceManager = m_csr->bus_info_data[2] >> 31;
106     m_isCycleMasterCapable = ( m_csr->bus_info_data[2] >> 30 ) & 0x1;
107     m_isSupportIsoOperations = ( m_csr->bus_info_data[2] >> 29 ) & 0x1;
108     m_isBusManagerCapable = ( m_csr->bus_info_data[2] >> 28 ) & 0x1;
109     m_cycleClkAcc = ( m_csr->bus_info_data[2] >> 16 ) & 0xff;
110     m_maxRec = ( m_csr->bus_info_data[2] >> 12 ) & 0xf;
111     m_nodeVendorId = ( m_csr->bus_info_data[3] >> 8 );
112     m_chipIdHi = ( m_csr->bus_info_data[3] ) & 0xff;
113     m_chipIdLow = m_csr->bus_info_data[4];
114
115     // Process Root Directory
116     processRootDirectory(m_csr);
117
118     if ( m_vendorNameKv ) {
119         int len = ( m_vendorNameKv->value.leaf.len - 2) * sizeof( quadlet_t );
120         char* buf = new char[len+2];
121         memcpy( buf,
122                 ( void* )CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA( m_vendorNameKv ),
123                 len );
124
125         while ((buf + len - 1) == '\0') {
126             len--;
127         }
128         // \todo XXX seems a bit strage to do this but the nodemgr.c code does
129         // it. try to figure out why this is needed (or not)
130         buf[len++] = ' ';
131         buf[len] = '\0';
132
133
134         debugOutput( DEBUG_LEVEL_VERBOSE, "Vendor name: '%s'\n", buf );
135         m_vendorName = buf;
136         delete[] buf;
137     }
138     if ( m_modelNameKv ) {
139         int len = ( m_modelNameKv->value.leaf.len - 2) * sizeof( quadlet_t );
140         char* buf = new char[len+2];
141         memcpy( buf,
142                 ( void* )CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA( m_modelNameKv ),
143                 len );
144         while ((buf + len - 1) == '\0') {
145             len--;
146         }
147         // \todo XXX for edirol fa-66 it seems somehow broken. see above
148         // todo as well.
149         buf[len++] = ' ';
150         buf[len] = '\0';
151
152         debugOutput( DEBUG_LEVEL_VERBOSE, "Model name: '%s'\n", buf);
153         m_modelName = buf;
154         delete[] buf;
155     }
156
157     m_guid = ((u_int64_t)CSR1212_BE32_TO_CPU(m_csr->bus_info_data[3]) << 32)
158              | CSR1212_BE32_TO_CPU(m_csr->bus_info_data[4]);
159
160     if ( m_vendorNameKv ) {
161         csr1212_release_keyval( m_vendorNameKv );
162         m_vendorNameKv = 0;
163     }
164     if ( m_modelNameKv ) {
165         csr1212_release_keyval( m_modelNameKv );
166         m_modelNameKv = 0;
167     }
168     if ( m_csr ) {
169         csr1212_destroy_csr(m_csr);
170         m_csr = 0;
171     }
172     return true;
173 }
174
175 const bool
176 ConfigRom::isAvcDevice() const
177 {
178     return m_avcDevice;
179 }
180
181 // XXX This might work only for the M-Audio Audiophile
182 // but can easily extended.
183 #define VENDOR_ID_MAUDIO    0x00000d6c
184 #define MODEL_ID_MAUDIO_BOOTLOADER 0x00010060
185
186 const bool
187 ConfigRom::isBootloader() const
188 {
189     if ( ( m_vendorId == VENDOR_ID_MAUDIO )
190          && ( m_modelId == MODEL_ID_MAUDIO_BOOTLOADER ) )
191     {
192         return true;
193     }
194     return false;
195 }
196
197 static int
198 busRead( struct csr1212_csr* csr,
199          u_int64_t addr,
200          u_int16_t length,
201          void* buffer,
202          void* private_data )
203 {
204     struct config_csr_info* csr_info = (struct config_csr_info*) private_data;
205
206     if ( !csr_info->service->read( csr_info->nodeId,
207                                    addr,
208                                    length/4,
209                                    ( quadlet_t* )buffer) )
210     {
211         //debugOutput( DEBUG_LEVEL_VERBOSE, "ConfigRom: Read failed\n");
212         return -1;
213     }
214
215     return 0;
216 }
217
218 static int
219 getMaxRom( u_int32_t* bus_info_data,
220            void* /*private_data*/)
221 {
222     return (CSR1212_BE32_TO_CPU( bus_info_data[2] ) >> 8) & 0x3;
223 }
224
225
226 void
227 ConfigRom::processUnitDirectory( struct csr1212_csr* csr,
228                                  struct csr1212_keyval* ud_kv,
229                                  unsigned int *id )
230 {
231     struct csr1212_dentry *dentry;
232     struct csr1212_keyval *kv;
233     unsigned int last_key_id = 0;
234     unsigned int specifier_id = 0;
235
236     debugOutput( DEBUG_LEVEL_VERBOSE, "process unit directory:\n" );
237     csr1212_for_each_dir_entry(csr, kv, ud_kv, dentry) {
238         switch (kv->key.id) {
239             case CSR1212_KV_ID_VENDOR:
240                 if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
241                     debugOutput( DEBUG_LEVEL_VERBOSE,
242                                  "\tvendor_id = 0x%08x\n",
243                                  kv->value.immediate);
244                     m_vendorId = kv->value.immediate;
245                 }
246                 break;
247
248             case CSR1212_KV_ID_MODEL:
249                 debugOutput( DEBUG_LEVEL_VERBOSE,
250                              "\tmodel_id = 0x%08x\n",
251                              kv->value.immediate);
252                 m_modelId = kv->value.immediate;
253                 break;
254
255             case CSR1212_KV_ID_SPECIFIER_ID:
256                 debugOutput( DEBUG_LEVEL_VERBOSE,
257                              "\tspecifier_id = 0x%08x\n",
258                              kv->value.immediate);
259                 specifier_id = kv->value.immediate;
260                 break;
261
262             case CSR1212_KV_ID_VERSION:
263                 debugOutput( DEBUG_LEVEL_VERBOSE,
264                              "\tversion = 0x%08x\n",
265                              kv->value.immediate);
266                 if ( specifier_id == 0x0000a02d ) // XXX
267                 {
268                     if ( kv->value.immediate == 0x10001 ) {
269                         m_avcDevice = true;
270                     }
271                 }
272                 break;
273
274             case CSR1212_KV_ID_DESCRIPTOR:
275                 if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
276                     CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
277                     CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
278                     CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
279                     CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
280                     CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0)
281                 {
282                     switch (last_key_id) {
283                         case CSR1212_KV_ID_VENDOR:
284                             csr1212_keep_keyval(kv);
285                             m_vendorNameKv = kv;
286                             break;
287
288                         case CSR1212_KV_ID_MODEL:
289                             m_modelNameKv = kv;
290                             csr1212_keep_keyval(kv);
291                             break;
292
293                     }
294                 } /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */
295                 break;
296
297             case CSR1212_KV_ID_DEPENDENT_INFO:
298                 if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {
299                     /* This should really be done in SBP2 as this is
300                      * doing SBP2 specific parsing. */
301                     processUnitDirectory(csr, kv, id);
302                 }
303
304                 break;
305
306             default:
307                 break;
308         }
309         last_key_id = kv->key.id;
310     }
311 }
312
313 void
314 ConfigRom::processRootDirectory(struct csr1212_csr* csr)
315 {
316     unsigned int ud_id = 0;
317     struct csr1212_dentry *dentry;
318     struct csr1212_keyval *kv;
319     unsigned int last_key_id = 0;
320
321     csr1212_for_each_dir_entry(csr, kv, csr->root_kv, dentry) {
322         switch (kv->key.id) {
323             case CSR1212_KV_ID_VENDOR:
324                 debugOutput( DEBUG_LEVEL_VERBOSE,
325                              "vendor id = 0x%08x\n", kv->value.immediate);
326                 break;
327
328             case CSR1212_KV_ID_NODE_CAPABILITIES:
329                 debugOutput( DEBUG_LEVEL_VERBOSE,
330                              "capabilities = 0x%08x\n", kv->value.immediate);
331                 break;
332
333             case CSR1212_KV_ID_UNIT:
334                 processUnitDirectory(csr, kv, &ud_id);
335                 break;
336
337             case CSR1212_KV_ID_DESCRIPTOR:
338                 if (last_key_id == CSR1212_KV_ID_VENDOR) {
339                     if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
340                         CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
341                         CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
342                         CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
343                         CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
344                         CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0)
345                     {
346                         m_vendorNameKv = kv;
347                         csr1212_keep_keyval(kv);
348                     }
349                 }
350                 break;
351         }
352         last_key_id = kv->key.id;
353     }
354
355 }
356
357 const fb_nodeid_t
358 ConfigRom::getNodeId() const
359 {
360     return m_nodeId;
361 }
362
363 const fb_octlet_t
364 ConfigRom::getGuid() const
365 {
366     return m_guid;
367 }
368
369 const std::string
370 ConfigRom::getModelName() const
371 {
372     return m_modelName;
373 }
374
375 const std::string
376 ConfigRom::getVendorName() const
377 {
378     return m_vendorName;
379 }
380
381 bool
382 ConfigRom::updatedNodeId()
383 {
384     for ( fb_nodeid_t nodeId = 0;
385           nodeId < m_1394Service->getNodeCount();
386           ++nodeId )
387     {
388         struct config_csr_info csr_info;
389         csr_info.service = m_1394Service;
390         csr_info.nodeId = 0xffc0 | nodeId;
391
392         struct csr1212_csr* csr =
393             csr1212_create_csr( &configrom_csr1212_ops,
394                                 5 * sizeof(fb_quadlet_t),   // XXX Why 5 ?!?
395                                 &csr_info );
396
397         if (!csr || csr1212_parse_csr( csr ) != CSR1212_SUCCESS) {
398             if (csr) {
399                 csr1212_destroy_csr(csr);
400             }
401             return false;
402         }
403
404
405         octlet_t guid =
406             ((u_int64_t)CSR1212_BE32_TO_CPU(csr->bus_info_data[3]) << 32)
407             | CSR1212_BE32_TO_CPU(csr->bus_info_data[4]);
408
409         if ( guid == m_guid ) {
410             if ( nodeId != m_nodeId ) {
411                 debugOutput( DEBUG_LEVEL_VERBOSE,
412                              "Device with GUID 0%08x%08x changed node id "
413                              "from %d to %d\n",
414                              m_guid >> 32,
415                              m_guid & 0xffffffff,
416                              m_nodeId,
417                              nodeId );
418                 m_nodeId = nodeId;
419             }
420             return true;
421         }
422     }
423
424     debugOutput( DEBUG_LEVEL_NORMAL,
425                  "Device with GUID 0x%08x%08x could not be found on "
426                  "the bus anymore (removed?)\n",
427                  m_guid >> 32,
428                  m_guid & 0xffffffff );
429     return false;
430 }
431
432 void
433 ConfigRom::printConfigRom() const
434 {
435     using namespace std;
436     cout << "Config ROM" << endl;
437     cout << "\tCurrent Node Id:\t" << getNodeId() << endl;
438     cout << "\tGUID:\t\t\t0x" << setfill( '0' ) << setw( 16 ) << hex << getGuid() << endl;
439     cout << "\tVendor Name:\t\t" << getVendorName() << endl;
440     cout << "\tModel Name:\t\t" << getModelName() << endl;
441 }
442
443 unsigned short
444 ConfigRom::getAsyMaxPayload() const
445 {
446     // XXX use pow instead
447     return 1 << ( m_maxRec + 1 );
448 }
Note: See TracBrowser for help on using the browser.