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

Revision 734, 14.6 kB (checked in by ppalmers, 13 years ago)

merge ppalmers-streaming branch

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