root/trunk/libffado/src/bounce/bounce_slave_avdevice.cpp

Revision 435, 14.7 kB (checked in by pieterpalmers, 15 years ago)

src/devicemanager:
- start OSC server for the device manager

src/devicemanager,
src/iavdevice,
src/libieee1394/configrom:
- inherit from OscNode? to become Osc'able

src/bounce,
src/libstreaming/AmdtpStreamProcessor,
src/libstreaming/AmdtpSlaveStreamProcessor:
- fixed bounce device implementation, now working

src/bebob:
- fixed midi bug

General:
- removed 'intermediate XML'
- removed obsolete tests
- removed obsolete files
- removed obsolete API calls

Line 
1 /* $Id$ */
2
3 /*
4  *   FreeBob Streaming API
5  *   FreeBob = Firewire (pro-)audio for linux
6  *
7  *   http://freebob.sf.net
8  *
9  *   Copyright (C) 2007 Pieter Palmers <pieterpalmers@users.sourceforge.net>
10  *
11  *   This program is free software {} you can redistribute it and/or modify
12  *   it under the terms of the GNU General Public License as published by
13  *   the Free Software Foundation {} either version 2 of the License, or
14  *   (at your option) any later version.
15  *
16  *   This program is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY {} without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with this program {} if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  *
26  *
27  */
28
29 #include "libstreaming/AmdtpSlaveStreamProcessor.h"
30
31 #include "libieee1394/configrom.h"
32 #include "libieee1394/ieee1394service.h"
33
34 #include "bounce_slave_avdevice.h"
35
36 #include <libraw1394/raw1394.h>
37 #include <libavc1394/rom1394.h>
38
39 namespace Bounce {
40
41 static VendorModelEntry supportedDeviceList[] =
42 {
43   //{vendor_id, model_id, unit_specifier_id, vendor_name, model_name},
44     {0x0B0001, 0x0B0001, 0x0B0001, "FreeBoB", "Bounce Slave"},
45 };
46
47 BounceSlaveDevice::BounceSlaveDevice( std::auto_ptr< ConfigRom >( configRom ),
48                             Ieee1394Service& ieee1394service )
49     : BounceDevice( configRom,
50                     ieee1394service,
51                     ieee1394service.getLocalNodeId() )
52 {
53     addOption(Util::OptionContainer::Option("isoTimeoutSecs",(int64_t)120));
54 }
55
56 BounceSlaveDevice::~BounceSlaveDevice() {
57
58 }
59
60 bool
61 BounceSlaveDevice::probe( ConfigRom& configRom )
62 {
63     // we are always capable of constructing a slave device
64     return true;
65 }
66
67 bool
68 BounceSlaveDevice::discover()
69 {
70     m_model = &(supportedDeviceList[0]);
71     if (m_model != NULL) {
72         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
73                 m_model->vendor_name, m_model->model_name);
74         return true;
75     }
76     return false;
77 }
78
79 bool BounceSlaveDevice::initMemSpace() {
80     debugOutput(DEBUG_LEVEL_VERBOSE, "Initializing memory space...\n");
81     fb_quadlet_t result=0xFFFFFFFFLU;
82    
83     // initialize the ISO channel registers
84     // this will write to our own registers
85     if (!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, result)) {
86         debugError("Could not initalize ISO channel register for TX\n");
87         return false;
88     }
89     if (!writeReg(BOUNCE_REGISTER_RX_ISOCHANNEL, result)) {
90         debugError("Could not initalize ISO channel register for TX\n");
91         return false;
92     }
93    
94     // set everything such that we can be discovered
95     m_original_config_rom=save_config_rom( m_p1394Service->getHandle() );
96    
97     if ( init_config_rom( m_p1394Service->getHandle() ) < 0 ) {
98         debugError("Could not initalize local config rom\n");
99         return false;
100     }
101    
102     // refresh our config rom cache
103     if ( !m_pConfigRom->initialize() ) {
104         // \todo If a PHY on the bus is in power safe mode then
105         // the config rom is missing. So this might be just
106         // such this case and we can safely skip it. But it might
107         // be there is a real software problem on our side.
108         // This should be handled more carefuly.
109         debugError( "Could not reread config rom from device (node id %d).\n",
110                      m_nodeId );
111         return false;
112     }
113     return true;
114 }
115
116 bool BounceSlaveDevice::restoreMemSpace() {
117     debugOutput(DEBUG_LEVEL_VERBOSE, "Restoring memory space...\n");
118     restore_config_rom( m_p1394Service->getHandle(), m_original_config_rom);
119     return true;
120 }
121
122 bool
123 BounceSlaveDevice::lock() {
124     debugOutput(DEBUG_LEVEL_VERBOSE, "Locking %s %s at node %d\n",
125         m_model->vendor_name, m_model->model_name, m_nodeId);
126    
127     // get a notifier to handle device notifications
128     nodeaddr_t notify_address;
129     notify_address = m_p1394Service->findFreeARMBlock(
130                         BOUNCE_REGISTER_BASE,
131                         BOUNCE_REGISTER_LENGTH,
132                         BOUNCE_REGISTER_LENGTH);
133    
134     if (notify_address == 0xFFFFFFFFFFFFFFFFLLU) {
135         debugError("Could not find free ARM block for notification\n");
136         return false;
137     }
138    
139     m_Notifier=new BounceSlaveDevice::BounceSlaveNotifier(this, notify_address);
140    
141     if(!m_Notifier) {
142         debugError("Could not allocate notifier\n");
143         return false;
144     }
145    
146     if (!m_p1394Service->registerARMHandler(m_Notifier)) {
147         debugError("Could not register notifier\n");
148         delete m_Notifier;
149         m_Notifier=NULL;
150         return false;
151     }
152    
153     // (re)initialize the memory space
154     if (!initMemSpace()) {
155         debugError("Could not initialize memory space\n");
156         return false;
157     }
158    
159     return true;
160 }
161
162 bool
163 BounceSlaveDevice::unlock() {
164     // (re)initialize the memory space
165     if (!restoreMemSpace()) {
166         debugError("Could not restore memory space\n");
167         return false;
168     }
169     m_p1394Service->unregisterARMHandler(m_Notifier);
170     delete m_Notifier;
171     m_Notifier=NULL;
172
173     return true;
174 }
175
176 bool
177 BounceSlaveDevice::prepare() {
178     debugOutput(DEBUG_LEVEL_NORMAL, "Preparing BounceSlaveDevice...\n" );
179    
180     // create & add streamprocessors
181     Streaming::StreamProcessor *p;
182    
183     p=new Streaming::AmdtpSlaveReceiveStreamProcessor(
184                              m_p1394Service->getPort(),
185                              m_samplerate,
186                              BOUNCE_NB_AUDIO_CHANNELS);
187
188     if(!p->init()) {
189         debugFatal("Could not initialize receive processor!\n");
190         delete p;
191         return false;
192     }
193
194     if (!addPortsToProcessor(p,
195             Streaming::Port::E_Capture)) {
196         debugFatal("Could not add plug to processor!\n");
197         delete p;
198         return false;
199     }
200
201     m_receiveProcessors.push_back(p);
202
203     // do the transmit processor
204     p=new Streaming::AmdtpSlaveTransmitStreamProcessor(
205                                 m_p1394Service->getPort(),
206                                 m_samplerate,
207                                 BOUNCE_NB_AUDIO_CHANNELS);
208    
209     if(!p->init()) {
210         debugFatal("Could not initialize transmit processor!\n");
211         delete p;
212         return false;
213     }
214
215     if (!addPortsToProcessor(p,
216         Streaming::Port::E_Playback)) {
217         debugFatal("Could not add plug to processor!\n");
218         delete p;
219         return false;
220     }
221     m_transmitProcessors.push_back(p);
222
223     return true;
224 }
225
226 // this has to wait until the ISO channel numbers are written
227 bool
228 BounceSlaveDevice::startStreamByIndex(int i) {
229    
230     if (i<(int)m_receiveProcessors.size()) {
231         int n=i;
232         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
233        
234         // the other side sends on this channel
235         nodeaddr_t iso_channel_offset = BOUNCE_REGISTER_RX_ISOCHANNEL;
236         iso_channel_offset += ((unsigned)n)*4;
237        
238         if (!waitForRegisterNotEqualTo(iso_channel_offset, 0xFFFFFFFFLU)) {
239             debugError("Timeout waiting for stream %d to get an ISO channel\n",i);
240             return false;
241         }
242        
243         fb_quadlet_t result;
244         // this will read from our own registers
245         if (!readReg(iso_channel_offset, &result)) {
246             debugError("Could not read ISO channel register for stream %d\n",i);
247             return false;
248         }
249        
250         // set ISO channel
251         p->setChannel(result);
252
253         return true;
254        
255     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
256         int n=i-m_receiveProcessors.size();
257         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
258        
259         // the other side sends on this channel
260         nodeaddr_t iso_channel_offset = BOUNCE_REGISTER_TX_ISOCHANNEL;
261         iso_channel_offset += ((unsigned)n)*4;
262        
263         if (!waitForRegisterNotEqualTo(iso_channel_offset, 0xFFFFFFFF)) {
264             debugError("Timeout waiting for stream %d to get an ISO channel\n",i);
265             return false;
266         }
267        
268         fb_quadlet_t result;
269         // this will read from our own registers
270         if (!readReg(iso_channel_offset, &result)) {
271             debugError("Could not read ISO channel register for stream %d\n",i);
272             return false;
273         }
274        
275         // set ISO channel
276         p->setChannel(result);
277
278         return true;
279
280     }
281    
282     debugError("SP index %d out of range!\n",i);
283    
284     return false;
285 }
286
287 bool
288 BounceSlaveDevice::stopStreamByIndex(int i) {
289     // nothing special to do I guess...
290     return false;
291 }
292
293 // helpers
294 bool
295 BounceSlaveDevice::waitForRegisterNotEqualTo(nodeaddr_t offset, fb_quadlet_t v) {
296     debugOutput( DEBUG_LEVEL_VERBOSE, "Waiting for StreamProcessor streams to start running...\n");
297     // we have to wait until all streamprocessors indicate that they are running
298     // i.e. that there is actually some data stream flowing
299     int timeoutSecs=120;
300     if(!getOption("isoTimeoutSecs", timeoutSecs)) {
301         debugWarning("Could not retrieve isoTimeoutSecs parameter, defauling to 120secs\n");
302     }
303    
304     int wait_cycles=timeoutSecs*10; // two seconds
305    
306     fb_quadlet_t reg=v;
307    
308     while ((v == reg) && wait_cycles) {
309         wait_cycles--;
310         if (!readReg(offset,&reg)) {
311             debugError("Could not read register\n");
312             return false;
313         }
314         usleep(100000);
315     }
316
317     if(!wait_cycles) { // timout has occurred
318         return false;
319     }
320    
321     return true;
322 }
323
324 // configrom helpers
325 // FIXME: should be changed into a better framework
326
327
328 struct BounceSlaveDevice::configrom_backup
329 BounceSlaveDevice::save_config_rom(raw1394handle_t handle)
330 {
331     int retval;
332     struct configrom_backup tmp;
333     /* get the current rom image */
334     retval=raw1394_get_config_rom(handle, tmp.rom, 0x100, &tmp.rom_size, &tmp.rom_version);
335 //      tmp.rom_size=rom1394_get_size(tmp.rom);
336 //     printf("save_config_rom get_config_rom returned %d, romsize %d, rom_version %d:\n",retval,tmp.rom_size,tmp.rom_version);
337
338     return tmp;
339 }
340
341 int
342 BounceSlaveDevice::restore_config_rom(raw1394handle_t handle, struct BounceSlaveDevice::configrom_backup old)
343 {
344     int retval;
345 //     int i;
346    
347     quadlet_t current_rom[0x100];
348     size_t current_rom_size;
349     unsigned char current_rom_version;
350
351     retval=raw1394_get_config_rom(handle, current_rom, 0x100, &current_rom_size, &current_rom_version);
352 //     printf("restore_config_rom get_config_rom returned %d, romsize %d, rom_version %d:\n",retval,current_rom_size,current_rom_version);
353
354 //     printf("restore_config_rom restoring to romsize %d, rom_version %d:\n",old.rom_size,old.rom_version);
355
356     retval = raw1394_update_config_rom(handle, old.rom, old.rom_size, current_rom_version);
357 //     printf("restore_config_rom update_config_rom returned %d\n",retval);
358
359     /* get the current rom image */
360     retval=raw1394_get_config_rom(handle, current_rom, 0x100, &current_rom_size, &current_rom_version);
361     current_rom_size = rom1394_get_size(current_rom);
362 //     printf("get_config_rom returned %d, romsize %d, rom_version %d:",retval,current_rom_size,current_rom_version);
363 //     for (i = 0; i < current_rom_size; i++)
364 //     {
365 //         if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
366 //         printf(" %08x", ntohl(current_rom[i]));
367 //     }
368 //     printf("\n");
369
370     return retval;
371 }
372
373 int
374 BounceSlaveDevice::init_config_rom(raw1394handle_t handle)
375 {
376     int retval, i;
377     quadlet_t rom[0x100];
378     size_t rom_size;
379     unsigned char rom_version;
380     rom1394_directory dir;
381     char *leaf;
382    
383     /* get the current rom image */
384     retval=raw1394_get_config_rom(handle, rom, 0x100, &rom_size, &rom_version);
385     rom_size = rom1394_get_size(rom);
386 //     printf("get_config_rom returned %d, romsize %d, rom_version %d:",retval,rom_size,rom_version);
387 //     for (i = 0; i < rom_size; i++)
388 //     {
389 //         if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
390 //         printf(" %08x", ntohl(rom[i]));
391 //     }
392 //     printf("\n");
393    
394     /* get the local directory */
395     rom1394_get_directory( handle, raw1394_get_local_id(handle) & 0x3f, &dir);
396    
397     /* change the vendor description for kicks */
398     i = strlen(dir.textual_leafs[0]);
399     strncpy(dir.textual_leafs[0], FREEBOB_BOUNCE_SERVER_VENDORNAME "                                          ", i);
400    
401     dir.vendor_id=FREEBOB_BOUNCE_SERVER_VENDORID;
402     dir.model_id=FREEBOB_BOUNCE_SERVER_MODELID;
403    
404     /* update the rom */
405     retval = rom1394_set_directory(rom, &dir);
406 //     printf("rom1394_set_directory returned %d, romsize %d:",retval,rom_size);
407 //     for (i = 0; i < rom_size; i++)
408 //     {
409 //         if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
410 //         printf(" %08x", ntohl(rom[i]));
411 //     }
412 //     printf("\n");
413    
414     /* free the allocated mem for the textual leaves */
415     rom1394_free_directory( &dir);
416    
417     /* add an AV/C unit directory */
418     dir.unit_spec_id    = FREEBOB_BOUNCE_SERVER_SPECID;
419     dir.unit_sw_version = 0x00010001;
420     leaf = FREEBOB_BOUNCE_SERVER_MODELNAME;
421     dir.nr_textual_leafs = 1;
422     dir.textual_leafs = &leaf;
423    
424     /* manipulate the rom */
425     retval = rom1394_add_unit( rom, &dir);
426    
427     /* get the computed size of the rom image */
428     rom_size = rom1394_get_size(rom);
429    
430 //     printf("rom1394_add_unit_directory returned %d, romsize %d:",retval,rom_size);
431 //     for (i = 0; i < rom_size; i++)
432 //     {
433 //         if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
434 //         printf(" %08x", ntohl(rom[i]));
435 //     }
436 //     printf("\n");
437 //     
438     /* convert computed rom size from quadlets to bytes before update */
439     rom_size *= sizeof(quadlet_t);
440     retval = raw1394_update_config_rom(handle, rom, rom_size, rom_version);
441 //     printf("update_config_rom returned %d\n",retval);
442    
443     retval=raw1394_get_config_rom(handle, rom, 0x100, &rom_size, &rom_version);
444 //     printf("get_config_rom returned %d, romsize %d, rom_version %d:",retval,rom_size,rom_version);
445 //     for (i = 0; i < rom_size; i++)
446 //     {
447 //         if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
448 //         printf(" %08x", ntohl(rom[i]));
449 //     }
450 //     printf("\n");
451    
452 //      printf("You need to reload your ieee1394 modules to reset the rom.\n");
453    
454     return 0;
455 }
456
457
458 // the notifier
459
460 BounceSlaveDevice::BounceSlaveNotifier::BounceSlaveNotifier(BounceSlaveDevice *d, nodeaddr_t start)
461  : ARMHandler(start, BOUNCE_REGISTER_LENGTH,
462               RAW1394_ARM_READ | RAW1394_ARM_WRITE, // allowed operations
463               0, //RAW1394_ARM_READ | RAW1394_ARM_WRITE, // operations to be notified of
464               0)                                    // operations that are replied to by us (instead of kernel)
465  , m_bounceslavedevice(d)
466 {
467
468 }
469
470 BounceSlaveDevice::BounceSlaveNotifier::~BounceSlaveNotifier()
471 {
472
473 }
474
475 } // end of namespace Bounce
Note: See TracBrowser for help on using the browser.