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

Revision 445, 14.4 kB (checked in by pieterpalmers, 15 years ago)

* name change from FreeBoB to FFADO
* replaced tabs by 4 spaces
* got rid of end-of-line spaces
* made all license and copyrights conform

library becomes LGPL, apps become GPL
explicitly state LGPL v2.1 and GPL v2 (don't like v3 draft)

copyrights are 2005-2007 Daniel & Pieter
except for the MotU stuff (C) Jonathan, Pieter

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