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

Revision 2803, 13.9 kB (checked in by jwoithe, 1 year ago)

Cosmetic: capitalise "L" in "Linux".

"Linux" is a proper noun so it should start with a capital letter. These
changes are almost all within comments.

This patch was originally proposed by pander on the ffado-devel mailing
list. It has been expanded to cover all similar cases to maintain
consistency throughout the source tree.

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