root/trunk/libffado/src/fireworks/fireworks_session_block.cpp

Revision 2802, 15.0 kB (checked in by jwoithe, 3 years ago)

Cosmetic: "Firewire" becomes "FireWire?".

Officially both the "F" and "W" were capitalised in the FireWire? name, so
reflect this throughout FFADO's source tree. This mostly affects comments.

This patch originated from pander on the ffado-devel mailing list. To
maintain consistency, the committed version has been expanded to include
files not originally included in the original patch.

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free FireWire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program 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
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "fireworks_session_block.h"
25 #include "fireworks_device.h"
26
27 #include "libutil/ByteSwap.h"
28
29 #include <fstream>
30 // These classes provide support for reading/writing session blocks on
31 // echo fireworks based devices
32
33 // does not support legacy (v1) sessions
34
35 using namespace std;
36
37 namespace FireWorks {
38
39 const uint32_t ECHO_SESSION_CRC_TABLE[256] =
40 {
41     0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
42     0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
43     0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
44     0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
45     0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
46     0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
47     0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
48     0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
49     0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
50     0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
51     0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
52     0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
53     0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
54     0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
55     0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
56     0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
57     0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
58     0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
59     0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
60     0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
61     0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
62     0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
63     0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
64     0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
65     0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
66     0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
67     0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
68     0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
69     0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
70     0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
71     0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
72     0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
73     0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
74     0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
75     0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
76     0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
77     0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
78     0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
79     0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
80     0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
81     0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
82     0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
83     0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
84     0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
85     0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
86     0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
87     0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
88     0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
89     0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
90     0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
91     0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
92     0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
93     0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
94     0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
95     0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
96     0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
97     0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
98     0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
99     0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
100     0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
101     0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
102     0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
103     0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
104     0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
105 };
106
107 IMPL_DEBUG_MODULE( Session, Session, DEBUG_LEVEL_NORMAL );
108
109 Session::Session()
110 {
111 }
112
113 Session::~Session()
114 {
115 }
116
117 bool
118 Session::loadFromDevice(Device &d)
119 {
120     size_t len = sizeof(SessionHeader) + sizeof(SubSession);
121     size_t start = d.getSessionBase();
122     if (start == 0) {
123         debugError("Invalid session base\n");
124         return false;
125     }
126
127     uint32_t data[len/4];
128     if(!d.readFlash(start, len/4, data)) {
129         debugError("Flash read failed\n");
130         return false;
131     }
132
133     if(!loadFromMemory(data, len)) {
134         debugError("Could not load session block from device memory dump\n");
135         return false;
136     }
137     return true;
138 }
139
140 bool
141 Session::saveToDevice(Device &d)
142 {
143     size_t len = sizeof(SessionHeader) + sizeof(SubSession);
144     size_t start = d.getSessionBase();
145     if (start == 0) {
146         debugError("Invalid session base\n");
147         return false;
148     }
149
150     // update the CRC
151     h.crc = calculateCRC();
152
153     uint32_t data[len/4];
154     if(!saveToMemory(data, len)) {
155         debugError("Could not save session to memory block\n");
156         return false;
157     }
158
159     if (!d.lockFlash(true)) {
160         debugError("  Could not lock flash\n");
161         return false;
162     }
163
164     if (!d.eraseFlashBlocks(start, len/4)) {
165         debugError("  Could not erase memory\n");
166         return false;
167     }
168
169     if(!d.writeFlash(start, len/4, data)) {
170         debugError("Writing to flash failed.\n");
171         return false;
172     }
173
174     if (!d.lockFlash(false)) {
175         debugError("  Could not unlock flash\n");
176         return false;
177     }
178
179     return true;
180 }
181
182 bool
183 Session::loadFromFile(std::string filename)
184 {
185     debugOutput(DEBUG_LEVEL_VERBOSE, "Loading session from file %s\n", filename.c_str());
186     fstream sessfile;
187    
188     debugOutput(DEBUG_LEVEL_VERBOSE, " Loading file...\n");
189     sessfile.open( filename.c_str(), ios::in | ios::ate | ios::binary);
190     if ( !sessfile.is_open() ) {
191         debugError("Could not open file.\n");
192         return false;
193     }
194     // get file size
195     int size;
196     size = (int)sessfile.tellg() - ECHO_SESSION_FILE_START_OFFSET;
197
198     sessfile.seekg(ECHO_SESSION_FILE_START_OFFSET, ios_base::beg);
199     debugOutput(DEBUG_LEVEL_VERBOSE, " Reading data, size = %d bytes, %d quads...\n", size, size/4);
200     char data[size];
201     sessfile.read(data, size);
202     sessfile.close();
203     if (sessfile.eof()) {
204         debugError("EOF while reading file\n");
205         return false;
206     }
207    
208     if(!loadFromMemory(data, size)) {
209         debugError("Could not load session block from file\n");
210         return false;
211     }
212     return true;
213 }
214
215 bool
216 Session::saveToFile(std::string filename)
217 {
218     debugOutput(DEBUG_LEVEL_VERBOSE, "Saving session to file %s\n", filename.c_str());
219     fstream sessfile;
220
221     debugOutput(DEBUG_LEVEL_VERBOSE, " Loading file...\n");
222     sessfile.open( filename.c_str(), ios::out | ios::trunc | ios::binary);
223     if ( !sessfile.is_open() ) {
224         debugError("Could not open file.\n");
225         return false;
226     }
227
228     // FIXME: figure out what the file header means
229     debugOutput(DEBUG_LEVEL_VERBOSE, " Writing file header...\n");
230     char header[ECHO_SESSION_FILE_START_OFFSET];
231     sessfile.write(header, ECHO_SESSION_FILE_START_OFFSET);
232
233     debugOutput(DEBUG_LEVEL_VERBOSE, " Writing session data...\n");
234     int size = sizeof(SessionHeader) + sizeof(SubSession);
235     char data[size];
236     if(!saveToMemory(data, size)) {
237         debugError("Could not save session to memory block\n");
238         return false;
239     }
240     sessfile.write(data, size);
241     sessfile.close();
242     return true;
243 }
244
245 bool
246 Session::loadFromMemory(void *buff, size_t len)
247 {
248     if (len != sizeof(SessionHeader) + sizeof(SubSession)) {
249         debugError("Invalid session length\n");
250         return false;
251     }
252     char *raw = (char *)buff;
253     memcpy(&h, raw, sizeof(SessionHeader));
254     memcpy(&s, raw+sizeof(SessionHeader), sizeof(SubSession));
255
256     if (len != h.size_quads*4) {
257         debugWarning("size not correct: got %zd, should be %d according to data\n", len, h.size_quads*4);
258     }
259
260 #if __BYTE_ORDER == __BIG_ENDIAN
261     unsigned int i=0;
262     uint32_t *data = (uint32_t *)(&s);
263     for(; i < sizeof(SubSession)/4; i++) {
264         *data = ByteSwap32(*data);
265         data++;
266     }
267 #endif
268
269     return true;
270 }
271
272 bool
273 Session::saveToMemory(void *buff, size_t max_len)
274 {
275     if (max_len < sizeof(SessionHeader) + sizeof(SubSession)) {
276         debugError("Max length too small\n");
277         return false;
278     }
279     char *raw = (char *)buff;
280     memcpy(raw, &h, sizeof(SessionHeader));
281     memcpy(raw+sizeof(SessionHeader), &s, sizeof(SubSession));
282
283 #if __BYTE_ORDER == __BIG_ENDIAN
284     unsigned int i=0;
285     uint32_t *data = (uint32_t *)(raw+sizeof(SessionHeader));
286     for(; i < sizeof(SubSession)/4; i++) {
287         *data = ByteSwap32(*data);
288         data++;
289     }
290 #endif
291
292     return true;
293 }
294
295 uint32_t
296 Session::calculateCRC()
297 {
298     size_t len = sizeof(SessionHeader) + sizeof(SubSession);
299     char data[len];
300     memcpy(data, &h, sizeof(SessionHeader));
301     memcpy(data+sizeof(SessionHeader), &s, sizeof(SubSession));
302     return calculateCRC(data, len);
303 }
304
305 uint32_t
306 Session::calculateCRC(void *memblock, size_t max_len)
307 {
308     if (max_len < sizeof(SessionHeader) + sizeof(SubSession)) {
309         debugError("block too small\n");
310         return 0;
311     }
312
313     // based upon CRC code provided by ECHO
314     byte_t *data = (byte_t*)memblock;
315     uint32_t b;
316     int bytecount;
317     uint32_t remainder = ECHO_SESSION_CRC_INITIAL_REMAINDER;
318
319     // skip the first two fields (length and CRC)
320     data += ECHO_SESSION_CRC_START_OFFSET_BYTES;
321
322     // total bytecount
323     bytecount = sizeof(SessionHeader) + sizeof(SubSession)
324                 - ECHO_SESSION_CRC_START_OFFSET_BYTES;
325
326 #if __BYTE_ORDER == __BIG_ENDIAN
327     //
328     // This is a big-endian machine; calculate the CRC for the first part
329     // of the data structure using big-endian mode
330     //
331     int bebytes, offset;
332
333     offset = 3;
334     bebytes = bytecount - sizeof(SubSession);
335     while (bebytes > 0)
336     {
337         b = data[offset];
338         b = ( remainder ^ b) & 0xFF;
339         remainder = ECHO_SESSION_CRC_TABLE[b] ^ ( remainder >> 8 );
340
341         offset--;
342         if (offset < 0)
343         {
344             offset = 3;
345             bebytes -= sizeof(uint32_t);
346             data += sizeof(uint32_t);
347         }
348     }
349 #endif
350
351     //
352     // Do the little-endian part of the session
353     //
354     // Compute the CRC a byte at time, starting with the LSB of each quad
355     //
356     while (bytecount > 0)
357     {
358         b = ( remainder ^ *data ) & 0xFF;
359         remainder = ECHO_SESSION_CRC_TABLE[b] ^ ( remainder >> 8 );
360
361         data++;
362         bytecount--;
363     }
364
365     //
366     // The final remainder is the CRC result.
367     //
368     return (remainder ^ ECHO_SESSION_CRC_FINAL_XOR_VALUE);
369 }
370
371 void
372 Session::show()
373 {
374     debugOutput(DEBUG_LEVEL_NORMAL, "Session Block\n");
375     debugOutput(DEBUG_LEVEL_NORMAL, " Size.............: %u (%08X)\n", h.size_quads, h.size_quads);
376     debugOutput(DEBUG_LEVEL_NORMAL, " CRC read.........: %12u (%08X)\n", h.crc, h.crc);
377     uint32_t crc = calculateCRC();
378     debugOutput(DEBUG_LEVEL_NORMAL, " CRC calculated...: %12u (%08X)\n", crc, crc);
379     debugOutput(DEBUG_LEVEL_NORMAL, " Version..........: %u (%08X)\n", h.version, h.version);
380     debugOutput(DEBUG_LEVEL_NORMAL, " Flags............: %u (%08X)\n", h.flags, h.flags);
381     debugOutput(DEBUG_LEVEL_NORMAL, " Mirror Channel...: %d (%08X)\n", h.mirror_channel, h.mirror_channel);
382     debugOutput(DEBUG_LEVEL_NORMAL, " Digital Mode.....: %d (%08X)\n", h.digital_mode, h.digital_mode);
383     debugOutput(DEBUG_LEVEL_NORMAL, " Clock............: %d (%08X)\n", h.clock, h.clock);
384     debugOutput(DEBUG_LEVEL_NORMAL, " Rate.............: %d (%08X)\n", h.rate, h.rate);
385
386     debugOutput(DEBUG_LEVEL_NORMAL, " Gains:\n");
387     for(unsigned int in = 0; in < ECHO_SESSION_MAX_PHY_AUDIO_IN; in++) {
388         debugOutput(DEBUG_LEVEL_NORMAL, "  MON %02u: ", in);
389         for(unsigned int out = 0; out < ECHO_SESSION_MAX_PHY_AUDIO_OUT; out++) {
390             debugOutputShort(DEBUG_LEVEL_NORMAL, "%08X ", h.monitorgains[in][out]);
391             flushDebugOutput();
392         }
393         debugOutputShort(DEBUG_LEVEL_NORMAL, "\n");
394     }
395
396     debugOutput(DEBUG_LEVEL_NORMAL, "  PGAIN : ");
397     for(unsigned int out = 0; out < ECHO_SESSION_MAX_PHY_AUDIO_OUT; out++) {
398         debugOutputShort(DEBUG_LEVEL_NORMAL, "%08X ", h.playbackgains[out]);
399         flushDebugOutput();
400     }
401     debugOutputShort(DEBUG_LEVEL_NORMAL, "\n");
402
403     debugOutput(DEBUG_LEVEL_NORMAL, "  OGAIN : ");
404     for(unsigned int out = 0; out < ECHO_SESSION_MAX_PHY_AUDIO_OUT; out++) {
405         debugOutputShort(DEBUG_LEVEL_NORMAL, "%08X ", h.outputgains[out]);
406         flushDebugOutput();
407     }
408     debugOutputShort(DEBUG_LEVEL_NORMAL, "\n");
409
410     debugOutput(DEBUG_LEVEL_NORMAL, " Input settings:\n");
411     for(unsigned int in = 0; in < ECHO_SESSION_MAX_PHY_AUDIO_IN; in++) {
412         debugOutput(DEBUG_LEVEL_NORMAL,
413                     "  IN %02u: shift: %02X, pad: %02X, label: %s\n",
414                     in, s.inputs[in].shift, s.inputs[in].pad, s.inputs[in].label);
415         flushDebugOutput();
416     }
417
418     debugOutput(DEBUG_LEVEL_NORMAL, " Pans:\n");
419     for(unsigned int in = 0; in < ECHO_SESSION_MAX_PHY_AUDIO_IN; in++) {
420         debugOutput(DEBUG_LEVEL_NORMAL, "  IN %02u: ", in);
421         for(unsigned int out = 0; out < ECHO_SESSION_MAX_PHY_AUDIO_OUT; out++) {
422             debugOutputShort(DEBUG_LEVEL_NORMAL, "%03u ", s.monitorpans[in][out]);
423             flushDebugOutput();
424         }
425         debugOutputShort(DEBUG_LEVEL_NORMAL, "\n");
426     }
427     debugOutput(DEBUG_LEVEL_NORMAL, " Flags:\n");
428     for(unsigned int in = 0; in < ECHO_SESSION_MAX_PHY_AUDIO_IN; in++) {
429         debugOutput(DEBUG_LEVEL_NORMAL, "  IN %02u: ", in);
430         for(unsigned int out = 0; out < ECHO_SESSION_MAX_PHY_AUDIO_OUT; out++) {
431             debugOutputShort(DEBUG_LEVEL_NORMAL, "%02X ", s.monitorflags[in][out]);
432             flushDebugOutput();
433         }
434         debugOutputShort(DEBUG_LEVEL_NORMAL, "\n");
435     }
436
437     debugOutput(DEBUG_LEVEL_NORMAL, " Playback settings:\n");
438     for(unsigned int out = 0; out < ECHO_SESSION_MAX_PHY_AUDIO_OUT; out++) {
439         debugOutput(DEBUG_LEVEL_NORMAL,
440                     "  PBK %02u: mute: %02X, solo: %02X, label: %s\n",
441                     out, s.playbacks[out].mute, s.playbacks[out].solo, s.playbacks[out].label);
442     }
443     debugOutput(DEBUG_LEVEL_NORMAL, " Output settings:\n");
444     for(unsigned int out = 0; out < ECHO_SESSION_MAX_PHY_AUDIO_OUT; out++) {
445         debugOutput(DEBUG_LEVEL_NORMAL,
446                     "  OUT %02u: mute: %02X, shift: %02X, label: %s\n",
447                     out, s.outputs[out].mute, s.outputs[out].shift, s.outputs[out].label);
448         flushDebugOutput();
449     }
450
451 }
452
453 void
454 Session::dumpData()
455 {
456
457 }
458
459 } // FireWorks
Note: See TracBrowser for help on using the browser.