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 
11 /*
12  * Just powering on, Firewire 410/Audiophile wait to
13  * download firmware blob. To enable these devices, drivers should upload
14  * firmware blob and send a command to initialize configuration to factory
15  * settings when completing uploading. Then these devices generate bus reset
16  * and are recognized as new devices with the firmware.
17  *
18  * For streaming, both of output and input streams are needed for Firewire 410
19  * and Ozonic. The single stream is OK for the other devices even if the clock
20  * source is not SYT-Match (I note no devices use SYT-Match).
21  *
22  * Without streaming, the devices except for Firewire Audiophile can mix any
23  * input and output. For this reason, Audiophile cannot be used as standalone
24  * mixer.
25  */
26 
27 #define MAUDIO_SPECIFIC_ADDRESS	0xffc700000000
28 
29 #define METER_OFFSET		0x00600000
30 
31 /* some device has sync info after metering data */
32 #define METER_SIZE_FW410	76	/* with sync info */
33 #define METER_SIZE_AUDIOPHILE	60	/* with sync info */
34 #define METER_SIZE_SOLO		52	/* with sync info */
35 #define METER_SIZE_OZONIC	48
36 #define METER_SIZE_NRV10	80
37 
38 /* labels for metering */
39 #define ANA_IN		"Analog In"
40 #define ANA_OUT		"Analog Out"
41 #define DIG_IN		"Digital In"
42 #define SPDIF_IN	"S/PDIF In"
43 #define ADAT_IN		"ADAT In"
44 #define DIG_OUT		"Digital Out"
45 #define SPDIF_OUT	"S/PDIF Out"
46 #define ADAT_OUT	"ADAT Out"
47 #define STRM_IN		"Stream In"
48 #define AUX_OUT		"Aux Out"
49 #define HP_OUT		"HP Out"
50 /* for NRV */
51 #define UNKNOWN_METER	"Unknown"
52 
53 static inline int
54 get_meter(struct snd_bebob *bebob, void *buf, unsigned int size)
55 {
56 	return snd_fw_transaction(bebob->unit, TCODE_READ_BLOCK_REQUEST,
57 				  MAUDIO_SPECIFIC_ADDRESS + METER_OFFSET,
58 				  buf, size, 0);
59 }
60 
61 /* last 4 bytes are omitted because it's clock info. */
62 static char *const fw410_meter_labels[] = {
63 	ANA_IN, DIG_IN,
64 	ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, DIG_OUT,
65 	HP_OUT
66 };
67 static char *const audiophile_meter_labels[] = {
68 	ANA_IN, DIG_IN,
69 	ANA_OUT, ANA_OUT, DIG_OUT,
70 	HP_OUT, AUX_OUT,
71 };
72 static char *const solo_meter_labels[] = {
73 	ANA_IN, DIG_IN,
74 	STRM_IN, STRM_IN,
75 	ANA_OUT, DIG_OUT
76 };
77 
78 /* no clock info */
79 static char *const ozonic_meter_labels[] = {
80 	ANA_IN, ANA_IN,
81 	STRM_IN, STRM_IN,
82 	ANA_OUT, ANA_OUT
83 };
84 /* TODO: need testers. these positions are based on authour's assumption */
85 static char *const nrv10_meter_labels[] = {
86 	ANA_IN, ANA_IN, ANA_IN, ANA_IN,
87 	DIG_IN,
88 	ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT,
89 	DIG_IN
90 };
91 static int
92 normal_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)
93 {
94 	struct snd_bebob_meter_spec *spec = bebob->spec->meter;
95 	unsigned int c, channels;
96 	int err;
97 
98 	channels = spec->num * 2;
99 	if (size < channels * sizeof(u32))
100 		return -EINVAL;
101 
102 	err = get_meter(bebob, (void *)buf, size);
103 	if (err < 0)
104 		goto end;
105 
106 	for (c = 0; c < channels; c++)
107 		be32_to_cpus(&buf[c]);
108 
109 	/* swap stream channels because inverted */
110 	if (spec->labels == solo_meter_labels) {
111 		swap(buf[4], buf[6]);
112 		swap(buf[5], buf[7]);
113 	}
114 end:
115 	return err;
116 }
117 
118 /* Firewire 410 specification */
119 static struct snd_bebob_rate_spec usual_rate_spec = {
120 	.get	= &snd_bebob_stream_get_rate,
121 	.set	= &snd_bebob_stream_set_rate,
122 };
123 static struct snd_bebob_meter_spec fw410_meter_spec = {
124 	.num	= ARRAY_SIZE(fw410_meter_labels),
125 	.labels	= fw410_meter_labels,
126 	.get	= &normal_meter_get
127 };
128 struct snd_bebob_spec maudio_fw410_spec = {
129 	.clock	= NULL,
130 	.rate	= &usual_rate_spec,
131 	.meter	= &fw410_meter_spec
132 };
133 
134 /* Firewire Audiophile specification */
135 static struct snd_bebob_meter_spec audiophile_meter_spec = {
136 	.num	= ARRAY_SIZE(audiophile_meter_labels),
137 	.labels	= audiophile_meter_labels,
138 	.get	= &normal_meter_get
139 };
140 struct snd_bebob_spec maudio_audiophile_spec = {
141 	.clock	= NULL,
142 	.rate	= &usual_rate_spec,
143 	.meter	= &audiophile_meter_spec
144 };
145 
146 /* Firewire Solo specification */
147 static struct snd_bebob_meter_spec solo_meter_spec = {
148 	.num	= ARRAY_SIZE(solo_meter_labels),
149 	.labels	= solo_meter_labels,
150 	.get	= &normal_meter_get
151 };
152 struct snd_bebob_spec maudio_solo_spec = {
153 	.clock	= NULL,
154 	.rate	= &usual_rate_spec,
155 	.meter	= &solo_meter_spec
156 };
157 
158 /* Ozonic specification */
159 static struct snd_bebob_meter_spec ozonic_meter_spec = {
160 	.num	= ARRAY_SIZE(ozonic_meter_labels),
161 	.labels	= ozonic_meter_labels,
162 	.get	= &normal_meter_get
163 };
164 struct snd_bebob_spec maudio_ozonic_spec = {
165 	.clock	= NULL,
166 	.rate	= &usual_rate_spec,
167 	.meter	= &ozonic_meter_spec
168 };
169 
170 /* NRV10 specification */
171 static struct snd_bebob_meter_spec nrv10_meter_spec = {
172 	.num	= ARRAY_SIZE(nrv10_meter_labels),
173 	.labels	= nrv10_meter_labels,
174 	.get	= &normal_meter_get
175 };
176 struct snd_bebob_spec maudio_nrv10_spec = {
177 	.clock	= NULL,
178 	.rate	= &usual_rate_spec,
179 	.meter	= &nrv10_meter_spec
180 };
181