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

Revision 864, 14.6 kB (checked in by ppalmers, 16 years ago)

update license to GPLv2 or GPLv3 instead of GPLv2 or any later version. Update copyrights to reflect the new year

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  * Copyright (C) 2005-2008 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 program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) version 3 of the License.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include "libstreaming/amdtp/AmdtpSlaveStreamProcessor.h"
26
27 #include "libieee1394/configrom.h"
28 #include "libieee1394/ieee1394service.h"
29
30 #include "libutil/Time.h"
31
32 #include "bounce_slave_avdevice.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     {FW_VENDORID_FFADO, 0x0B0001, 0x0B0001, "FFADO", "Bounce Slave"},
43 };
44
45 BounceSlaveDevice::BounceSlaveDevice( Ieee1394Service& ieee1394Service,
46                                       std::auto_ptr<ConfigRom>( configRom ))
47     : BounceDevice( ieee1394Service, configRom )
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 FFADODevice *
64 BounceSlaveDevice::createDevice( Ieee1394Service& ieee1394Service,
65                             std::auto_ptr<ConfigRom>( configRom ))
66 {
67     return new BounceSlaveDevice(ieee1394Service, configRom );
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_pConfigRom->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                      getNodeId() );
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, getNodeId());
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     debugOutput(DEBUG_LEVEL_NORMAL, "Preparing BounceSlaveDevice...\n" );
182
183     // create & add streamprocessors
184     Streaming::StreamProcessor *p;
185
186     p=new Streaming::AmdtpSlaveReceiveStreamProcessor(
187                              m_p1394Service->getPort(),
188                              m_samplerate,
189                              BOUNCE_NB_AUDIO_CHANNELS);
190
191     if(!p->init()) {
192         debugFatal("Could not initialize receive processor!\n");
193         delete p;
194         return false;
195     }
196
197     if (!addPortsToProcessor(p,
198             Streaming::Port::E_Capture)) {
199         debugFatal("Could not add plug to processor!\n");
200         delete p;
201         return false;
202     }
203
204     m_receiveProcessors.push_back(p);
205
206     // do the transmit processor
207     p=new Streaming::AmdtpSlaveTransmitStreamProcessor(
208                                 m_p1394Service->getPort(),
209                                 m_samplerate,
210                                 BOUNCE_NB_AUDIO_CHANNELS);
211
212     if(!p->init()) {
213         debugFatal("Could not initialize transmit processor!\n");
214         delete p;
215         return false;
216     }
217
218     if (!addPortsToProcessor(p,
219         Streaming::Port::E_Playback)) {
220         debugFatal("Could not add plug to processor!\n");
221         delete p;
222         return false;
223     }
224     m_transmitProcessors.push_back(p);
225
226     return true;
227 }
228
229 // this has to wait until the ISO channel numbers are written
230 bool
231 BounceSlaveDevice::startStreamByIndex(int i) {
232
233     if (i<(int)m_receiveProcessors.size()) {
234         int n=i;
235         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
236
237         // the other side sends on this channel
238         nodeaddr_t iso_channel_offset = BOUNCE_REGISTER_RX_ISOCHANNEL;
239         iso_channel_offset += ((unsigned)n)*4;
240
241         if (!waitForRegisterNotEqualTo(iso_channel_offset, 0xFFFFFFFFLU)) {
242             debugError("Timeout waiting for stream %d to get an ISO channel\n",i);
243             return false;
244         }
245
246         fb_quadlet_t result;
247         // this will read from our own registers
248         if (!readReg(iso_channel_offset, &result)) {
249             debugError("Could not read ISO channel register for stream %d\n",i);
250             return false;
251         }
252
253         // set ISO channel
254         p->setChannel(result);
255
256         return true;
257
258     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
259         int n=i-m_receiveProcessors.size();
260         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
261
262         // the other side sends on this channel
263         nodeaddr_t iso_channel_offset = BOUNCE_REGISTER_TX_ISOCHANNEL;
264         iso_channel_offset += ((unsigned)n)*4;
265
266         if (!waitForRegisterNotEqualTo(iso_channel_offset, 0xFFFFFFFF)) {
267             debugError("Timeout waiting for stream %d to get an ISO channel\n",i);
268             return false;
269         }
270
271         fb_quadlet_t result;
272         // this will read from our own registers
273         if (!readReg(iso_channel_offset, &result)) {
274             debugError("Could not read ISO channel register for stream %d\n",i);
275             return false;
276         }
277
278         // set ISO channel
279         p->setChannel(result);
280
281         return true;
282
283     }
284
285     debugError("SP index %d out of range!\n",i);
286
287     return false;
288 }
289
290 bool
291 BounceSlaveDevice::stopStreamByIndex(int i) {
292     // nothing special to do I guess...
293     return false;
294 }
295
296 // helpers
297 bool
298 BounceSlaveDevice::waitForRegisterNotEqualTo(nodeaddr_t offset, fb_quadlet_t v) {
299     debugOutput( DEBUG_LEVEL_VERBOSE, "Waiting for StreamProcessor streams to start running...\n");
300     // we have to wait until all streamprocessors indicate that they are running
301     // i.e. that there is actually some data stream flowing
302     int timeoutSecs=120;
303     if(!getOption("isoTimeoutSecs", timeoutSecs)) {
304         debugWarning("Could not retrieve isoTimeoutSecs parameter, defauling to 120secs\n");
305     }
306
307     int wait_cycles=timeoutSecs*10; // two seconds
308
309     fb_quadlet_t reg=v;
310
311     while ((v == reg) && wait_cycles) {
312         wait_cycles--;
313         if (!readReg(offset,&reg)) {
314             debugError("Could not read register\n");
315             return false;
316         }
317         SleepRelativeUsec(100000);
318     }
319
320     if(!wait_cycles) { // timout has occurred
321         return false;
322     }
323
324     return true;
325 }
326
327 // configrom helpers
328 // FIXME: should be changed into a better framework
329
330
331 struct BounceSlaveDevice::configrom_backup
332 BounceSlaveDevice::save_config_rom(raw1394handle_t handle)
333 {
334     int retval;
335     struct configrom_backup tmp;
336     /* get the current rom image */
337     retval=raw1394_get_config_rom(handle, tmp.rom, 0x100, &tmp.rom_size, &tmp.rom_version);
338 //     tmp.rom_size=rom1394_get_size(tmp.rom);
339 //     printf("save_config_rom get_config_rom returned %d, romsize %d, rom_version %d:\n",retval,tmp.rom_size,tmp.rom_version);
340
341     return tmp;
342 }
343
344 int
345 BounceSlaveDevice::restore_config_rom(raw1394handle_t handle, struct BounceSlaveDevice::configrom_backup old)
346 {
347     int retval;
348 //     int i;
349
350     quadlet_t current_rom[0x100];
351     size_t current_rom_size;
352     unsigned char current_rom_version;
353
354     retval=raw1394_get_config_rom(handle, current_rom, 0x100, &current_rom_size, &current_rom_version);
355 //     printf("restore_config_rom get_config_rom returned %d, romsize %d, rom_version %d:\n",retval,current_rom_size,current_rom_version);
356
357 //     printf("restore_config_rom restoring to romsize %d, rom_version %d:\n",old.rom_size,old.rom_version);
358
359     retval = raw1394_update_config_rom(handle, old.rom, old.rom_size, current_rom_version);
360 //     printf("restore_config_rom update_config_rom returned %d\n",retval);
361
362     /* get the current rom image */
363     retval=raw1394_get_config_rom(handle, current_rom, 0x100, &current_rom_size, &current_rom_version);
364     current_rom_size = rom1394_get_size(current_rom);
365 //     printf("get_config_rom returned %d, romsize %d, rom_version %d:",retval,current_rom_size,current_rom_version);
366 //     for (i = 0; i < current_rom_size; i++)
367 //     {
368 //         if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
369 //         printf(" %08x", ntohl(current_rom[i]));
370 //     }
371 //     printf("\n");
372
373     return retval;
374 }
375
376 int
377 BounceSlaveDevice::init_config_rom(raw1394handle_t handle)
378 {
379     int retval, i;
380     quadlet_t rom[0x100];
381     size_t rom_size;
382     unsigned char rom_version;
383     rom1394_directory dir;
384     char *leaf;
385
386     /* get the current rom image */
387     retval=raw1394_get_config_rom(handle, rom, 0x100, &rom_size, &rom_version);
388     rom_size = rom1394_get_size(rom);
389 //     printf("get_config_rom returned %d, romsize %d, rom_version %d:",retval,rom_size,rom_version);
390 //     for (i = 0; i < rom_size; i++)
391 //     {
392 //         if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
393 //         printf(" %08x", ntohl(rom[i]));
394 //     }
395 //     printf("\n");
396
397     /* get the local directory */
398     rom1394_get_directory( handle, raw1394_get_local_id(handle) & 0x3f, &dir);
399
400     /* change the vendor description for kicks */
401     i = strlen(dir.textual_leafs[0]);
402     strncpy(dir.textual_leafs[0], FFADO_BOUNCE_SERVER_VENDORNAME "                                          ", i);
403
404     dir.vendor_id=FFADO_BOUNCE_SERVER_VENDORID;
405     dir.model_id=FFADO_BOUNCE_SERVER_MODELID;
406
407     /* update the rom */
408     retval = rom1394_set_directory(rom, &dir);
409 //     printf("rom1394_set_directory returned %d, romsize %d:",retval,rom_size);
410 //     for (i = 0; i < rom_size; i++)
411 //     {
412 //         if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
413 //         printf(" %08x", ntohl(rom[i]));
414 //     }
415 //     printf("\n");
416
417     /* free the allocated mem for the textual leaves */
418     rom1394_free_directory( &dir);
419
420     /* add an AV/C unit directory */
421     dir.unit_spec_id    = FFADO_BOUNCE_SERVER_SPECID;
422     dir.unit_sw_version = 0x00010001;
423     leaf = FFADO_BOUNCE_SERVER_MODELNAME;
424     dir.nr_textual_leafs = 1;
425     dir.textual_leafs = &leaf;
426
427     /* manipulate the rom */
428     retval = rom1394_add_unit( rom, &dir);
429
430     /* get the computed size of the rom image */
431     rom_size = rom1394_get_size(rom);
432
433 //     printf("rom1394_add_unit_directory returned %d, romsize %d:",retval,rom_size);
434 //     for (i = 0; i < rom_size; i++)
435 //     {
436 //         if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
437 //         printf(" %08x", ntohl(rom[i]));
438 //     }
439 //     printf("\n");
440 //
441     /* convert computed rom size from quadlets to bytes before update */
442     rom_size *= sizeof(quadlet_t);
443     retval = raw1394_update_config_rom(handle, rom, rom_size, rom_version);
444 //     printf("update_config_rom returned %d\n",retval);
445
446     retval=raw1394_get_config_rom(handle, rom, 0x100, &rom_size, &rom_version);
447 //     printf("get_config_rom returned %d, romsize %d, rom_version %d:",retval,rom_size,rom_version);
448 //     for (i = 0; i < rom_size; i++)
449 //     {
450 //         if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
451 //         printf(" %08x", ntohl(rom[i]));
452 //     }
453 //     printf("\n");
454
455 //     printf("You need to reload your ieee1394 modules to reset the rom.\n");
456
457     return 0;
458 }
459
460
461 // the notifier
462
463 BounceSlaveDevice::BounceSlaveNotifier::BounceSlaveNotifier(BounceSlaveDevice *d, nodeaddr_t start)
464  : ARMHandler(start, BOUNCE_REGISTER_LENGTH,
465               RAW1394_ARM_READ | RAW1394_ARM_WRITE, // allowed operations
466               0, //RAW1394_ARM_READ | RAW1394_ARM_WRITE, // operations to be notified of
467               0)                                    // operations that are replied to by us (instead of kernel)
468  , m_bounceslavedevice(d)
469 {
470
471 }
472
473 BounceSlaveDevice::BounceSlaveNotifier::~BounceSlaveNotifier()
474 {
475
476 }
477
478 } // end of namespace Bounce
Note: See TracBrowser for help on using the browser.