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

Revision 783, 14.6 kB (checked in by ppalmers, 15 years ago)

cleanup time/wait/sleep code

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 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 3 of the License, or
13  * (at your option) any later version.
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.