aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire/bebob/bebob_maudio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/bebob/bebob_maudio.c')
-rw-r--r--sound/firewire/bebob/bebob_maudio.c792
1 files changed, 792 insertions, 0 deletions
diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c
new file mode 100644
index 000000000000..6af50eb80ea7
--- /dev/null
+++ b/sound/firewire/bebob/bebob_maudio.c
@@ -0,0 +1,792 @@
1/*
2 * bebob_maudio.c - a part of driver for BeBoB based devices
3 *
4 * Copyright (c) 2013-2014 Takashi Sakamoto
5 *
6 * Licensed under the terms of the GNU General Public License, version 2.
7 */
8
9#include "./bebob.h"
10#include <sound/control.h>
11
12/*
13 * Just powering on, Firewire 410/Audiophile/1814 and ProjectMix I/O wait to
14 * download firmware blob. To enable these devices, drivers should upload
15 * firmware blob and send a command to initialize configuration to factory
16 * settings when completing uploading. Then these devices generate bus reset
17 * and are recognized as new devices with the firmware.
18 *
19 * But with firmware version 5058 or later, the firmware is stored to flash
20 * memory in the device and drivers can tell bootloader to load the firmware
21 * by sending a cue. This cue must be sent one time.
22 *
23 * For streaming, both of output and input streams are needed for Firewire 410
24 * and Ozonic. The single stream is OK for the other devices even if the clock
25 * source is not SYT-Match (I note no devices use SYT-Match).
26 *
27 * Without streaming, the devices except for Firewire Audiophile can mix any
28 * input and output. For this reason, Audiophile cannot be used as standalone
29 * mixer.
30 *
31 * Firewire 1814 and ProjectMix I/O uses special firmware. It will be freezed
32 * when receiving any commands which the firmware can't understand. These
33 * devices utilize completely different system to control. It is some
34 * write-transaction directly into a certain address. All of addresses for mixer
35 * functionality is between 0xffc700700000 to 0xffc70070009c.
36 */
37
38/* Offset from information register */
39#define INFO_OFFSET_SW_DATE 0x20
40
41/* Bootloader Protocol Version 1 */
42#define MAUDIO_BOOTLOADER_CUE1 0x00000001
43/*
44 * Initializing configuration to factory settings (= 0x1101), (swapped in line),
45 * Command code is zero (= 0x00),
46 * the number of operands is zero (= 0x00)(at least significant byte)
47 */
48#define MAUDIO_BOOTLOADER_CUE2 0x01110000
49/* padding */
50#define MAUDIO_BOOTLOADER_CUE3 0x00000000
51
52#define MAUDIO_SPECIFIC_ADDRESS 0xffc700000000ULL
53
54#define METER_OFFSET 0x00600000
55
56/* some device has sync info after metering data */
57#define METER_SIZE_SPECIAL 84 /* with sync info */
58#define METER_SIZE_FW410 76 /* with sync info */
59#define METER_SIZE_AUDIOPHILE 60 /* with sync info */
60#define METER_SIZE_SOLO 52 /* with sync info */
61#define METER_SIZE_OZONIC 48
62#define METER_SIZE_NRV10 80
63
64/* labels for metering */
65#define ANA_IN "Analog In"
66#define ANA_OUT "Analog Out"
67#define DIG_IN "Digital In"
68#define SPDIF_IN "S/PDIF In"
69#define ADAT_IN "ADAT In"
70#define DIG_OUT "Digital Out"
71#define SPDIF_OUT "S/PDIF Out"
72#define ADAT_OUT "ADAT Out"
73#define STRM_IN "Stream In"
74#define AUX_OUT "Aux Out"
75#define HP_OUT "HP Out"
76/* for NRV */
77#define UNKNOWN_METER "Unknown"
78
79struct special_params {
80 bool is1814;
81 unsigned int clk_src;
82 unsigned int dig_in_fmt;
83 unsigned int dig_out_fmt;
84 unsigned int clk_lock;
85 struct snd_ctl_elem_id *ctl_id_sync;
86};
87
88/*
89 * For some M-Audio devices, this module just send cue to load firmware. After
90 * loading, the device generates bus reset and newly detected.
91 *
92 * If we make any transactions to load firmware, the operation may failed.
93 */
94int snd_bebob_maudio_load_firmware(struct fw_unit *unit)
95{
96 struct fw_device *device = fw_parent_device(unit);
97 int err, rcode;
98 u64 date;
99 __be32 cues[3] = {
100 MAUDIO_BOOTLOADER_CUE1,
101 MAUDIO_BOOTLOADER_CUE2,
102 MAUDIO_BOOTLOADER_CUE3
103 };
104
105 /* check date of software used to build */
106 err = snd_bebob_read_block(unit, INFO_OFFSET_SW_DATE,
107 &date, sizeof(u64));
108 if (err < 0)
109 goto end;
110 /*
111 * firmware version 5058 or later has date later than "20070401", but
112 * 'date' is not null-terminated.
113 */
114 if (date < 0x3230303730343031LL) {
115 dev_err(&unit->device,
116 "Use firmware version 5058 or later\n");
117 err = -ENOSYS;
118 goto end;
119 }
120
121 rcode = fw_run_transaction(device->card, TCODE_WRITE_BLOCK_REQUEST,
122 device->node_id, device->generation,
123 device->max_speed, BEBOB_ADDR_REG_REQ,
124 cues, sizeof(cues));
125 if (rcode != RCODE_COMPLETE) {
126 dev_err(&unit->device,
127 "Failed to send a cue to load firmware\n");
128 err = -EIO;
129 }
130end:
131 return err;
132}
133
134static inline int
135get_meter(struct snd_bebob *bebob, void *buf, unsigned int size)
136{
137 return snd_fw_transaction(bebob->unit, TCODE_READ_BLOCK_REQUEST,
138 MAUDIO_SPECIFIC_ADDRESS + METER_OFFSET,
139 buf, size, 0);
140}
141
142static int
143check_clk_sync(struct snd_bebob *bebob, unsigned int size, bool *sync)
144{
145 int err;
146 u8 *buf;
147
148 buf = kmalloc(size, GFP_KERNEL);
149 if (buf == NULL)
150 return -ENOMEM;
151
152 err = get_meter(bebob, buf, size);
153 if (err < 0)
154 goto end;
155
156 /* if synced, this value is the same as SFC of FDF in CIP header */
157 *sync = (buf[size - 2] != 0xff);
158end:
159 kfree(buf);
160 return err;
161}
162
163/*
164 * dig_fmt: 0x00:S/PDIF, 0x01:ADAT
165 * clk_lock: 0x00:unlock, 0x01:lock
166 */
167static int
168avc_maudio_set_special_clk(struct snd_bebob *bebob, unsigned int clk_src,
169 unsigned int dig_in_fmt, unsigned int dig_out_fmt,
170 unsigned int clk_lock)
171{
172 struct special_params *params = bebob->maudio_special_quirk;
173 int err;
174 u8 *buf;
175
176 if (amdtp_stream_running(&bebob->rx_stream) ||
177 amdtp_stream_running(&bebob->tx_stream))
178 return -EBUSY;
179
180 buf = kmalloc(12, GFP_KERNEL);
181 if (buf == NULL)
182 return -ENOMEM;
183
184 buf[0] = 0x00; /* CONTROL */
185 buf[1] = 0xff; /* UNIT */
186 buf[2] = 0x00; /* vendor dependent */
187 buf[3] = 0x04; /* company ID high */
188 buf[4] = 0x00; /* company ID middle */
189 buf[5] = 0x04; /* company ID low */
190 buf[6] = 0xff & clk_src; /* clock source */
191 buf[7] = 0xff & dig_in_fmt; /* input digital format */
192 buf[8] = 0xff & dig_out_fmt; /* output digital format */
193 buf[9] = 0xff & clk_lock; /* lock these settings */
194 buf[10] = 0x00; /* padding */
195 buf[11] = 0x00; /* padding */
196
197 err = fcp_avc_transaction(bebob->unit, buf, 12, buf, 12,
198 BIT(1) | BIT(2) | BIT(3) | BIT(4) |
199 BIT(5) | BIT(6) | BIT(7) | BIT(8) |
200 BIT(9));
201 if ((err > 0) && (err < 10))
202 err = -EIO;
203 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
204 err = -ENOSYS;
205 else if (buf[0] == 0x0a) /* REJECTED */
206 err = -EINVAL;
207 if (err < 0)
208 goto end;
209
210 params->clk_src = buf[6];
211 params->dig_in_fmt = buf[7];
212 params->dig_out_fmt = buf[8];
213 params->clk_lock = buf[9];
214
215 if (params->ctl_id_sync)
216 snd_ctl_notify(bebob->card, SNDRV_CTL_EVENT_MASK_VALUE,
217 params->ctl_id_sync);
218
219 err = 0;
220end:
221 kfree(buf);
222 return err;
223}
224static void
225special_stream_formation_set(struct snd_bebob *bebob)
226{
227 static const unsigned int ch_table[2][2][3] = {
228 /* AMDTP_OUT_STREAM */
229 { { 6, 6, 4 }, /* SPDIF */
230 { 12, 8, 4 } }, /* ADAT */
231 /* AMDTP_IN_STREAM */
232 { { 10, 10, 2 }, /* SPDIF */
233 { 16, 12, 2 } } /* ADAT */
234 };
235 struct special_params *params = bebob->maudio_special_quirk;
236 unsigned int i, max;
237
238 max = SND_BEBOB_STRM_FMT_ENTRIES - 1;
239 if (!params->is1814)
240 max -= 2;
241
242 for (i = 0; i < max; i++) {
243 bebob->tx_stream_formations[i + 1].pcm =
244 ch_table[AMDTP_IN_STREAM][params->dig_in_fmt][i / 2];
245 bebob->tx_stream_formations[i + 1].midi = 1;
246
247 bebob->rx_stream_formations[i + 1].pcm =
248 ch_table[AMDTP_OUT_STREAM][params->dig_out_fmt][i / 2];
249 bebob->rx_stream_formations[i + 1].midi = 1;
250 }
251}
252
253static int add_special_controls(struct snd_bebob *bebob);
254int
255snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814)
256{
257 struct special_params *params;
258 int err;
259
260 params = kzalloc(sizeof(struct special_params), GFP_KERNEL);
261 if (params == NULL)
262 return -ENOMEM;
263
264 mutex_lock(&bebob->mutex);
265
266 bebob->maudio_special_quirk = (void *)params;
267 params->is1814 = is1814;
268
269 /* initialize these parameters because driver is not allowed to ask */
270 bebob->rx_stream.context = ERR_PTR(-1);
271 bebob->tx_stream.context = ERR_PTR(-1);
272 err = avc_maudio_set_special_clk(bebob, 0x03, 0x00, 0x00, 0x00);
273 if (err < 0) {
274 dev_err(&bebob->unit->device,
275 "fail to initialize clock params: %d\n", err);
276 goto end;
277 }
278
279 err = add_special_controls(bebob);
280 if (err < 0)
281 goto end;
282
283 special_stream_formation_set(bebob);
284
285 if (params->is1814) {
286 bebob->midi_input_ports = 1;
287 bebob->midi_output_ports = 1;
288 } else {
289 bebob->midi_input_ports = 2;
290 bebob->midi_output_ports = 2;
291 }
292end:
293 if (err < 0) {
294 kfree(params);
295 bebob->maudio_special_quirk = NULL;
296 }
297 mutex_unlock(&bebob->mutex);
298 return err;
299}
300
301/* Input plug shows actual rate. Output plug is needless for this purpose. */
302static int special_get_rate(struct snd_bebob *bebob, unsigned int *rate)
303{
304 int err, trials;
305
306 trials = 0;
307 do {
308 err = avc_general_get_sig_fmt(bebob->unit, rate,
309 AVC_GENERAL_PLUG_DIR_IN, 0);
310 } while (err == -EAGAIN && ++trials < 3);
311
312 return err;
313}
314static int special_set_rate(struct snd_bebob *bebob, unsigned int rate)
315{
316 struct special_params *params = bebob->maudio_special_quirk;
317 int err;
318
319 err = avc_general_set_sig_fmt(bebob->unit, rate,
320 AVC_GENERAL_PLUG_DIR_OUT, 0);
321 if (err < 0)
322 goto end;
323
324 /*
325 * Just after changing sampling rate for output, a followed command
326 * for input is easy to fail. This is a workaround fot this issue.
327 */
328 msleep(100);
329
330 err = avc_general_set_sig_fmt(bebob->unit, rate,
331 AVC_GENERAL_PLUG_DIR_IN, 0);
332 if (err < 0)
333 goto end;
334
335 if (params->ctl_id_sync)
336 snd_ctl_notify(bebob->card, SNDRV_CTL_EVENT_MASK_VALUE,
337 params->ctl_id_sync);
338end:
339 return err;
340}
341
342/* Clock source control for special firmware */
343static char *const special_clk_labels[] = {
344 SND_BEBOB_CLOCK_INTERNAL " with Digital Mute", "Digital",
345 "Word Clock", SND_BEBOB_CLOCK_INTERNAL};
346static int special_clk_get(struct snd_bebob *bebob, unsigned int *id)
347{
348 struct special_params *params = bebob->maudio_special_quirk;
349 *id = params->clk_src;
350 return 0;
351}
352static int special_clk_ctl_info(struct snd_kcontrol *kctl,
353 struct snd_ctl_elem_info *einf)
354{
355 einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
356 einf->count = 1;
357 einf->value.enumerated.items = ARRAY_SIZE(special_clk_labels);
358
359 if (einf->value.enumerated.item >= einf->value.enumerated.items)
360 einf->value.enumerated.item = einf->value.enumerated.items - 1;
361
362 strcpy(einf->value.enumerated.name,
363 special_clk_labels[einf->value.enumerated.item]);
364
365 return 0;
366}
367static int special_clk_ctl_get(struct snd_kcontrol *kctl,
368 struct snd_ctl_elem_value *uval)
369{
370 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
371 struct special_params *params = bebob->maudio_special_quirk;
372 uval->value.enumerated.item[0] = params->clk_src;
373 return 0;
374}
375static int special_clk_ctl_put(struct snd_kcontrol *kctl,
376 struct snd_ctl_elem_value *uval)
377{
378 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
379 struct special_params *params = bebob->maudio_special_quirk;
380 int err, id;
381
382 mutex_lock(&bebob->mutex);
383
384 id = uval->value.enumerated.item[0];
385 if (id >= ARRAY_SIZE(special_clk_labels))
386 return 0;
387
388 err = avc_maudio_set_special_clk(bebob, id,
389 params->dig_in_fmt,
390 params->dig_out_fmt,
391 params->clk_lock);
392 mutex_unlock(&bebob->mutex);
393
394 return err >= 0;
395}
396static struct snd_kcontrol_new special_clk_ctl = {
397 .name = "Clock Source",
398 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
399 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
400 .info = special_clk_ctl_info,
401 .get = special_clk_ctl_get,
402 .put = special_clk_ctl_put
403};
404
405/* Clock synchronization control for special firmware */
406static int special_sync_ctl_info(struct snd_kcontrol *kctl,
407 struct snd_ctl_elem_info *einf)
408{
409 einf->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
410 einf->count = 1;
411 einf->value.integer.min = 0;
412 einf->value.integer.max = 1;
413
414 return 0;
415}
416static int special_sync_ctl_get(struct snd_kcontrol *kctl,
417 struct snd_ctl_elem_value *uval)
418{
419 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
420 int err;
421 bool synced = 0;
422
423 err = check_clk_sync(bebob, METER_SIZE_SPECIAL, &synced);
424 if (err >= 0)
425 uval->value.integer.value[0] = synced;
426
427 return 0;
428}
429static struct snd_kcontrol_new special_sync_ctl = {
430 .name = "Sync Status",
431 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
432 .access = SNDRV_CTL_ELEM_ACCESS_READ,
433 .info = special_sync_ctl_info,
434 .get = special_sync_ctl_get,
435};
436
437/* Digital interface control for special firmware */
438static char *const special_dig_iface_labels[] = {
439 "S/PDIF Optical", "S/PDIF Coaxial", "ADAT Optical"
440};
441static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl,
442 struct snd_ctl_elem_info *einf)
443{
444 einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
445 einf->count = 1;
446 einf->value.enumerated.items = ARRAY_SIZE(special_dig_iface_labels);
447
448 if (einf->value.enumerated.item >= einf->value.enumerated.items)
449 einf->value.enumerated.item = einf->value.enumerated.items - 1;
450
451 strcpy(einf->value.enumerated.name,
452 special_dig_iface_labels[einf->value.enumerated.item]);
453
454 return 0;
455}
456static int special_dig_in_iface_ctl_get(struct snd_kcontrol *kctl,
457 struct snd_ctl_elem_value *uval)
458{
459 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
460 struct special_params *params = bebob->maudio_special_quirk;
461 unsigned int dig_in_iface;
462 int err, val;
463
464 mutex_lock(&bebob->mutex);
465
466 err = avc_audio_get_selector(bebob->unit, 0x00, 0x04,
467 &dig_in_iface);
468 if (err < 0) {
469 dev_err(&bebob->unit->device,
470 "fail to get digital input interface: %d\n", err);
471 goto end;
472 }
473
474 /* encoded id for user value */
475 val = (params->dig_in_fmt << 1) | (dig_in_iface & 0x01);
476
477 /* for ADAT Optical */
478 if (val > 2)
479 val = 2;
480
481 uval->value.enumerated.item[0] = val;
482end:
483 mutex_unlock(&bebob->mutex);
484 return err;
485}
486static int special_dig_in_iface_ctl_set(struct snd_kcontrol *kctl,
487 struct snd_ctl_elem_value *uval)
488{
489 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
490 struct special_params *params = bebob->maudio_special_quirk;
491 unsigned int id, dig_in_fmt, dig_in_iface;
492 int err;
493
494 mutex_lock(&bebob->mutex);
495
496 id = uval->value.enumerated.item[0];
497
498 /* decode user value */
499 dig_in_fmt = (id >> 1) & 0x01;
500 dig_in_iface = id & 0x01;
501
502 err = avc_maudio_set_special_clk(bebob,
503 params->clk_src,
504 dig_in_fmt,
505 params->dig_out_fmt,
506 params->clk_lock);
507 if ((err < 0) || (params->dig_in_fmt > 0)) /* ADAT */
508 goto end;
509
510 err = avc_audio_set_selector(bebob->unit, 0x00, 0x04, dig_in_iface);
511 if (err < 0)
512 dev_err(&bebob->unit->device,
513 "fail to set digital input interface: %d\n", err);
514end:
515 special_stream_formation_set(bebob);
516 mutex_unlock(&bebob->mutex);
517 return err;
518}
519static struct snd_kcontrol_new special_dig_in_iface_ctl = {
520 .name = "Digital Input Interface",
521 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
522 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
523 .info = special_dig_in_iface_ctl_info,
524 .get = special_dig_in_iface_ctl_get,
525 .put = special_dig_in_iface_ctl_set
526};
527
528static int special_dig_out_iface_ctl_info(struct snd_kcontrol *kctl,
529 struct snd_ctl_elem_info *einf)
530{
531 einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
532 einf->count = 1;
533 einf->value.enumerated.items = ARRAY_SIZE(special_dig_iface_labels) - 1;
534
535 if (einf->value.enumerated.item >= einf->value.enumerated.items)
536 einf->value.enumerated.item = einf->value.enumerated.items - 1;
537
538 strcpy(einf->value.enumerated.name,
539 special_dig_iface_labels[einf->value.enumerated.item + 1]);
540
541 return 0;
542}
543static int special_dig_out_iface_ctl_get(struct snd_kcontrol *kctl,
544 struct snd_ctl_elem_value *uval)
545{
546 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
547 struct special_params *params = bebob->maudio_special_quirk;
548 mutex_lock(&bebob->mutex);
549 uval->value.enumerated.item[0] = params->dig_out_fmt;
550 mutex_unlock(&bebob->mutex);
551 return 0;
552}
553static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl,
554 struct snd_ctl_elem_value *uval)
555{
556 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
557 struct special_params *params = bebob->maudio_special_quirk;
558 unsigned int id;
559 int err;
560
561 mutex_lock(&bebob->mutex);
562
563 id = uval->value.enumerated.item[0];
564
565 err = avc_maudio_set_special_clk(bebob,
566 params->clk_src,
567 params->dig_in_fmt,
568 id, params->clk_lock);
569 if (err >= 0)
570 special_stream_formation_set(bebob);
571
572 mutex_unlock(&bebob->mutex);
573 return err;
574}
575static struct snd_kcontrol_new special_dig_out_iface_ctl = {
576 .name = "Digital Output Interface",
577 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
578 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
579 .info = special_dig_out_iface_ctl_info,
580 .get = special_dig_out_iface_ctl_get,
581 .put = special_dig_out_iface_ctl_set
582};
583
584static int add_special_controls(struct snd_bebob *bebob)
585{
586 struct snd_kcontrol *kctl;
587 struct special_params *params = bebob->maudio_special_quirk;
588 int err;
589
590 kctl = snd_ctl_new1(&special_clk_ctl, bebob);
591 err = snd_ctl_add(bebob->card, kctl);
592 if (err < 0)
593 goto end;
594
595 kctl = snd_ctl_new1(&special_sync_ctl, bebob);
596 err = snd_ctl_add(bebob->card, kctl);
597 if (err < 0)
598 goto end;
599 params->ctl_id_sync = &kctl->id;
600
601 kctl = snd_ctl_new1(&special_dig_in_iface_ctl, bebob);
602 err = snd_ctl_add(bebob->card, kctl);
603 if (err < 0)
604 goto end;
605
606 kctl = snd_ctl_new1(&special_dig_out_iface_ctl, bebob);
607 err = snd_ctl_add(bebob->card, kctl);
608end:
609 return err;
610}
611
612/* Hardware metering for special firmware */
613static char *const special_meter_labels[] = {
614 ANA_IN, ANA_IN, ANA_IN, ANA_IN,
615 SPDIF_IN,
616 ADAT_IN, ADAT_IN, ADAT_IN, ADAT_IN,
617 ANA_OUT, ANA_OUT,
618 SPDIF_OUT,
619 ADAT_OUT, ADAT_OUT, ADAT_OUT, ADAT_OUT,
620 HP_OUT, HP_OUT,
621 AUX_OUT
622};
623static int
624special_meter_get(struct snd_bebob *bebob, u32 *target, unsigned int size)
625{
626 u16 *buf;
627 unsigned int i, c, channels;
628 int err;
629
630 channels = ARRAY_SIZE(special_meter_labels) * 2;
631 if (size < channels * sizeof(u32))
632 return -EINVAL;
633
634 /* omit last 4 bytes because it's clock info. */
635 buf = kmalloc(METER_SIZE_SPECIAL - 4, GFP_KERNEL);
636 if (buf == NULL)
637 return -ENOMEM;
638
639 err = get_meter(bebob, (void *)buf, METER_SIZE_SPECIAL - 4);
640 if (err < 0)
641 goto end;
642
643 /* Its format is u16 and some channels are unknown. */
644 i = 0;
645 for (c = 2; c < channels + 2; c++)
646 target[i++] = be16_to_cpu(buf[c]) << 16;
647end:
648 kfree(buf);
649 return err;
650}
651
652/* last 4 bytes are omitted because it's clock info. */
653static char *const fw410_meter_labels[] = {
654 ANA_IN, DIG_IN,
655 ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, DIG_OUT,
656 HP_OUT
657};
658static char *const audiophile_meter_labels[] = {
659 ANA_IN, DIG_IN,
660 ANA_OUT, ANA_OUT, DIG_OUT,
661 HP_OUT, AUX_OUT,
662};
663static char *const solo_meter_labels[] = {
664 ANA_IN, DIG_IN,
665 STRM_IN, STRM_IN,
666 ANA_OUT, DIG_OUT
667};
668
669/* no clock info */
670static char *const ozonic_meter_labels[] = {
671 ANA_IN, ANA_IN,
672 STRM_IN, STRM_IN,
673 ANA_OUT, ANA_OUT
674};
675/* TODO: need testers. these positions are based on authour's assumption */
676static char *const nrv10_meter_labels[] = {
677 ANA_IN, ANA_IN, ANA_IN, ANA_IN,
678 DIG_IN,
679 ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT,
680 DIG_IN
681};
682static int
683normal_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)
684{
685 struct snd_bebob_meter_spec *spec = bebob->spec->meter;
686 unsigned int c, channels;
687 int err;
688
689 channels = spec->num * 2;
690 if (size < channels * sizeof(u32))
691 return -EINVAL;
692
693 err = get_meter(bebob, (void *)buf, size);
694 if (err < 0)
695 goto end;
696
697 for (c = 0; c < channels; c++)
698 be32_to_cpus(&buf[c]);
699
700 /* swap stream channels because inverted */
701 if (spec->labels == solo_meter_labels) {
702 swap(buf[4], buf[6]);
703 swap(buf[5], buf[7]);
704 }
705end:
706 return err;
707}
708
709/* for special customized devices */
710static struct snd_bebob_rate_spec special_rate_spec = {
711 .get = &special_get_rate,
712 .set = &special_set_rate,
713};
714static struct snd_bebob_clock_spec special_clk_spec = {
715 .num = ARRAY_SIZE(special_clk_labels),
716 .labels = special_clk_labels,
717 .get = &special_clk_get,
718};
719static struct snd_bebob_meter_spec special_meter_spec = {
720 .num = ARRAY_SIZE(special_meter_labels),
721 .labels = special_meter_labels,
722 .get = &special_meter_get
723};
724struct snd_bebob_spec maudio_special_spec = {
725 .clock = &special_clk_spec,
726 .rate = &special_rate_spec,
727 .meter = &special_meter_spec
728};
729
730/* Firewire 410 specification */
731static struct snd_bebob_rate_spec usual_rate_spec = {
732 .get = &snd_bebob_stream_get_rate,
733 .set = &snd_bebob_stream_set_rate,
734};
735static struct snd_bebob_meter_spec fw410_meter_spec = {
736 .num = ARRAY_SIZE(fw410_meter_labels),
737 .labels = fw410_meter_labels,
738 .get = &normal_meter_get
739};
740struct snd_bebob_spec maudio_fw410_spec = {
741 .clock = NULL,
742 .rate = &usual_rate_spec,
743 .meter = &fw410_meter_spec
744};
745
746/* Firewire Audiophile specification */
747static struct snd_bebob_meter_spec audiophile_meter_spec = {
748 .num = ARRAY_SIZE(audiophile_meter_labels),
749 .labels = audiophile_meter_labels,
750 .get = &normal_meter_get
751};
752struct snd_bebob_spec maudio_audiophile_spec = {
753 .clock = NULL,
754 .rate = &usual_rate_spec,
755 .meter = &audiophile_meter_spec
756};
757
758/* Firewire Solo specification */
759static struct snd_bebob_meter_spec solo_meter_spec = {
760 .num = ARRAY_SIZE(solo_meter_labels),
761 .labels = solo_meter_labels,
762 .get = &normal_meter_get
763};
764struct snd_bebob_spec maudio_solo_spec = {
765 .clock = NULL,
766 .rate = &usual_rate_spec,
767 .meter = &solo_meter_spec
768};
769
770/* Ozonic specification */
771static struct snd_bebob_meter_spec ozonic_meter_spec = {
772 .num = ARRAY_SIZE(ozonic_meter_labels),
773 .labels = ozonic_meter_labels,
774 .get = &normal_meter_get
775};
776struct snd_bebob_spec maudio_ozonic_spec = {
777 .clock = NULL,
778 .rate = &usual_rate_spec,
779 .meter = &ozonic_meter_spec
780};
781
782/* NRV10 specification */
783static struct snd_bebob_meter_spec nrv10_meter_spec = {
784 .num = ARRAY_SIZE(nrv10_meter_labels),
785 .labels = nrv10_meter_labels,
786 .get = &normal_meter_get
787};
788struct snd_bebob_spec maudio_nrv10_spec = {
789 .clock = NULL,
790 .rate = &usual_rate_spec,
791 .meter = &nrv10_meter_spec
792};