root/branches/streaming-rework/src/bounce/bounce_slave_avdevice.cpp

Revision 424, 14.0 kB (checked in by pieterpalmers, 16 years ago)

- The library can now be started in 'slave mode', creating a BounceSlaveDevice?.

On a discovering node, this slave device is discovered as a BounceDevice?.
Streaming does not work yet, something wrong with the timestamps.

- Implemented the 'snoop mode', that allows a client to 'snoop' the streams

between another host and a device. It is only implemented for BeBoB devices.
The channel numbers and stream configuration are automatically detected.
Note that it currently relies on a rather hackish support for reading the
{i,o}PCR plugs by using private functions of libiec61883

- changed jack backend to support these two new features

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