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

Revision 426, 13.8 kB (checked in by pieterpalmers, 16 years ago)

- changed the IAvDevice from an interface to a base class,

since there is some code duplication starting to
appear.

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