1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * fireworks_command.c - a part of driver for Fireworks based devices |
4 | * |
5 | * Copyright (c) 2013-2014 Takashi Sakamoto |
6 | */ |
7 | |
8 | #include "./fireworks.h" |
9 | |
10 | /* |
11 | * This driver uses transaction version 1 or later to use extended hardware |
12 | * information. Then too old devices are not available. |
13 | * |
14 | * Each commands are not required to have continuous sequence numbers. This |
15 | * number is just used to match command and response. |
16 | * |
17 | * This module support a part of commands. Please see FFADO if you want to see |
18 | * whole commands. But there are some commands which FFADO don't implement. |
19 | * |
20 | * Fireworks also supports AV/C general commands and AV/C Stream Format |
21 | * Information commands. But this module don't use them. |
22 | */ |
23 | |
24 | #define KERNEL_SEQNUM_MIN (SND_EFW_TRANSACTION_USER_SEQNUM_MAX + 2) |
25 | #define KERNEL_SEQNUM_MAX ((u32)~0) |
26 | |
27 | /* for clock source and sampling rate */ |
28 | struct efc_clock { |
29 | u32 source; |
30 | u32 sampling_rate; |
31 | u32 index; |
32 | }; |
33 | |
34 | /* command categories */ |
35 | enum efc_category { |
36 | EFC_CAT_HWINFO = 0, |
37 | EFC_CAT_TRANSPORT = 2, |
38 | EFC_CAT_HWCTL = 3, |
39 | }; |
40 | |
41 | /* hardware info category commands */ |
42 | enum efc_cmd_hwinfo { |
43 | EFC_CMD_HWINFO_GET_CAPS = 0, |
44 | EFC_CMD_HWINFO_GET_POLLED = 1, |
45 | EFC_CMD_HWINFO_SET_RESP_ADDR = 2 |
46 | }; |
47 | |
48 | enum efc_cmd_transport { |
49 | EFC_CMD_TRANSPORT_SET_TX_MODE = 0 |
50 | }; |
51 | |
52 | /* hardware control category commands */ |
53 | enum efc_cmd_hwctl { |
54 | EFC_CMD_HWCTL_SET_CLOCK = 0, |
55 | EFC_CMD_HWCTL_GET_CLOCK = 1, |
56 | EFC_CMD_HWCTL_IDENTIFY = 5 |
57 | }; |
58 | |
59 | /* return values in response */ |
60 | enum efr_status { |
61 | EFR_STATUS_OK = 0, |
62 | EFR_STATUS_BAD = 1, |
63 | EFR_STATUS_BAD_COMMAND = 2, |
64 | EFR_STATUS_COMM_ERR = 3, |
65 | EFR_STATUS_BAD_QUAD_COUNT = 4, |
66 | EFR_STATUS_UNSUPPORTED = 5, |
67 | EFR_STATUS_1394_TIMEOUT = 6, |
68 | EFR_STATUS_DSP_TIMEOUT = 7, |
69 | EFR_STATUS_BAD_RATE = 8, |
70 | EFR_STATUS_BAD_CLOCK = 9, |
71 | EFR_STATUS_BAD_CHANNEL = 10, |
72 | EFR_STATUS_BAD_PAN = 11, |
73 | EFR_STATUS_FLASH_BUSY = 12, |
74 | EFR_STATUS_BAD_MIRROR = 13, |
75 | EFR_STATUS_BAD_LED = 14, |
76 | EFR_STATUS_BAD_PARAMETER = 15, |
77 | EFR_STATUS_INCOMPLETE = 0x80000000 |
78 | }; |
79 | |
80 | static const char *const efr_status_names[] = { |
81 | [EFR_STATUS_OK] = "OK" , |
82 | [EFR_STATUS_BAD] = "bad" , |
83 | [EFR_STATUS_BAD_COMMAND] = "bad command" , |
84 | [EFR_STATUS_COMM_ERR] = "comm err" , |
85 | [EFR_STATUS_BAD_QUAD_COUNT] = "bad quad count" , |
86 | [EFR_STATUS_UNSUPPORTED] = "unsupported" , |
87 | [EFR_STATUS_1394_TIMEOUT] = "1394 timeout" , |
88 | [EFR_STATUS_DSP_TIMEOUT] = "DSP timeout" , |
89 | [EFR_STATUS_BAD_RATE] = "bad rate" , |
90 | [EFR_STATUS_BAD_CLOCK] = "bad clock" , |
91 | [EFR_STATUS_BAD_CHANNEL] = "bad channel" , |
92 | [EFR_STATUS_BAD_PAN] = "bad pan" , |
93 | [EFR_STATUS_FLASH_BUSY] = "flash busy" , |
94 | [EFR_STATUS_BAD_MIRROR] = "bad mirror" , |
95 | [EFR_STATUS_BAD_LED] = "bad LED" , |
96 | [EFR_STATUS_BAD_PARAMETER] = "bad parameter" , |
97 | [EFR_STATUS_BAD_PARAMETER + 1] = "incomplete" |
98 | }; |
99 | |
100 | static int |
101 | efw_transaction(struct snd_efw *efw, unsigned int category, |
102 | unsigned int command, |
103 | const __be32 *params, unsigned int param_bytes, |
104 | const __be32 *resp, unsigned int resp_bytes) |
105 | { |
106 | struct snd_efw_transaction *; |
107 | __be32 *buf; |
108 | u32 seqnum; |
109 | unsigned int buf_bytes, cmd_bytes; |
110 | int err; |
111 | |
112 | /* calculate buffer size*/ |
113 | buf_bytes = sizeof(struct snd_efw_transaction) + |
114 | max(param_bytes, resp_bytes); |
115 | |
116 | /* keep buffer */ |
117 | buf = kzalloc(size: buf_bytes, GFP_KERNEL); |
118 | if (buf == NULL) |
119 | return -ENOMEM; |
120 | |
121 | /* to keep consistency of sequence number */ |
122 | spin_lock(lock: &efw->lock); |
123 | if ((efw->seqnum < KERNEL_SEQNUM_MIN) || |
124 | (efw->seqnum >= KERNEL_SEQNUM_MAX - 2)) |
125 | efw->seqnum = KERNEL_SEQNUM_MIN; |
126 | else |
127 | efw->seqnum += 2; |
128 | seqnum = efw->seqnum; |
129 | spin_unlock(lock: &efw->lock); |
130 | |
131 | /* fill transaction header fields */ |
132 | cmd_bytes = sizeof(struct snd_efw_transaction) + param_bytes; |
133 | header = (struct snd_efw_transaction *)buf; |
134 | header->length = cpu_to_be32(cmd_bytes / sizeof(__be32)); |
135 | header->version = cpu_to_be32(1); |
136 | header->seqnum = cpu_to_be32(seqnum); |
137 | header->category = cpu_to_be32(category); |
138 | header->command = cpu_to_be32(command); |
139 | header->status = 0; |
140 | |
141 | /* fill transaction command parameters */ |
142 | memcpy(header->params, params, param_bytes); |
143 | |
144 | err = snd_efw_transaction_run(unit: efw->unit, cmd: buf, cmd_size: cmd_bytes, |
145 | resp: buf, resp_size: buf_bytes); |
146 | if (err < 0) |
147 | goto end; |
148 | |
149 | /* check transaction header fields */ |
150 | if ((be32_to_cpu(header->version) < 1) || |
151 | (be32_to_cpu(header->category) != category) || |
152 | (be32_to_cpu(header->command) != command) || |
153 | (be32_to_cpu(header->status) != EFR_STATUS_OK)) { |
154 | dev_err(&efw->unit->device, "EFW command failed [%u/%u]: %s\n" , |
155 | be32_to_cpu(header->category), |
156 | be32_to_cpu(header->command), |
157 | efr_status_names[be32_to_cpu(header->status)]); |
158 | err = -EIO; |
159 | goto end; |
160 | } |
161 | |
162 | if (resp == NULL) |
163 | goto end; |
164 | |
165 | /* fill transaction response parameters */ |
166 | memset((void *)resp, 0, resp_bytes); |
167 | resp_bytes = min_t(unsigned int, resp_bytes, |
168 | be32_to_cpu(header->length) * sizeof(__be32) - |
169 | sizeof(struct snd_efw_transaction)); |
170 | memcpy((void *)resp, &buf[6], resp_bytes); |
171 | end: |
172 | kfree(objp: buf); |
173 | return err; |
174 | } |
175 | |
176 | /* |
177 | * The address in host system for transaction response is changable when the |
178 | * device supports. struct hwinfo.flags includes its flag. The default is |
179 | * MEMORY_SPACE_EFW_RESPONSE. |
180 | */ |
181 | int snd_efw_command_set_resp_addr(struct snd_efw *efw, |
182 | u16 addr_high, u32 addr_low) |
183 | { |
184 | __be32 addr[2]; |
185 | |
186 | addr[0] = cpu_to_be32(addr_high); |
187 | addr[1] = cpu_to_be32(addr_low); |
188 | |
189 | if (!efw->resp_addr_changable) |
190 | return -ENOSYS; |
191 | |
192 | return efw_transaction(efw, category: EFC_CAT_HWCTL, |
193 | command: EFC_CMD_HWINFO_SET_RESP_ADDR, |
194 | params: addr, param_bytes: sizeof(addr), NULL, resp_bytes: 0); |
195 | } |
196 | |
197 | /* |
198 | * This is for timestamp processing. In Windows mode, all 32bit fields of second |
199 | * CIP header in AMDTP transmit packet is used for 'presentation timestamp'. In |
200 | * 'no data' packet the value of this field is 0x90ffffff. |
201 | */ |
202 | int snd_efw_command_set_tx_mode(struct snd_efw *efw, |
203 | enum snd_efw_transport_mode mode) |
204 | { |
205 | __be32 param = cpu_to_be32(mode); |
206 | return efw_transaction(efw, category: EFC_CAT_TRANSPORT, |
207 | command: EFC_CMD_TRANSPORT_SET_TX_MODE, |
208 | params: ¶m, param_bytes: sizeof(param), NULL, resp_bytes: 0); |
209 | } |
210 | |
211 | int snd_efw_command_get_hwinfo(struct snd_efw *efw, |
212 | struct snd_efw_hwinfo *hwinfo) |
213 | { |
214 | int err; |
215 | |
216 | err = efw_transaction(efw, category: EFC_CAT_HWINFO, |
217 | command: EFC_CMD_HWINFO_GET_CAPS, |
218 | NULL, param_bytes: 0, resp: (__be32 *)hwinfo, resp_bytes: sizeof(*hwinfo)); |
219 | if (err < 0) |
220 | goto end; |
221 | |
222 | be32_to_cpus(&hwinfo->flags); |
223 | be32_to_cpus(&hwinfo->guid_hi); |
224 | be32_to_cpus(&hwinfo->guid_lo); |
225 | be32_to_cpus(&hwinfo->type); |
226 | be32_to_cpus(&hwinfo->version); |
227 | be32_to_cpus(&hwinfo->supported_clocks); |
228 | be32_to_cpus(&hwinfo->amdtp_rx_pcm_channels); |
229 | be32_to_cpus(&hwinfo->amdtp_tx_pcm_channels); |
230 | be32_to_cpus(&hwinfo->phys_out); |
231 | be32_to_cpus(&hwinfo->phys_in); |
232 | be32_to_cpus(&hwinfo->phys_out_grp_count); |
233 | be32_to_cpus(&hwinfo->phys_in_grp_count); |
234 | be32_to_cpus(&hwinfo->midi_out_ports); |
235 | be32_to_cpus(&hwinfo->midi_in_ports); |
236 | be32_to_cpus(&hwinfo->max_sample_rate); |
237 | be32_to_cpus(&hwinfo->min_sample_rate); |
238 | be32_to_cpus(&hwinfo->dsp_version); |
239 | be32_to_cpus(&hwinfo->arm_version); |
240 | be32_to_cpus(&hwinfo->mixer_playback_channels); |
241 | be32_to_cpus(&hwinfo->mixer_capture_channels); |
242 | be32_to_cpus(&hwinfo->fpga_version); |
243 | be32_to_cpus(&hwinfo->amdtp_rx_pcm_channels_2x); |
244 | be32_to_cpus(&hwinfo->amdtp_tx_pcm_channels_2x); |
245 | be32_to_cpus(&hwinfo->amdtp_rx_pcm_channels_4x); |
246 | be32_to_cpus(&hwinfo->amdtp_tx_pcm_channels_4x); |
247 | |
248 | /* ensure terminated */ |
249 | hwinfo->vendor_name[HWINFO_NAME_SIZE_BYTES - 1] = '\0'; |
250 | hwinfo->model_name[HWINFO_NAME_SIZE_BYTES - 1] = '\0'; |
251 | end: |
252 | return err; |
253 | } |
254 | |
255 | int snd_efw_command_get_phys_meters(struct snd_efw *efw, |
256 | struct snd_efw_phys_meters *meters, |
257 | unsigned int len) |
258 | { |
259 | u32 *buf = (u32 *)meters; |
260 | unsigned int i; |
261 | int err; |
262 | |
263 | err = efw_transaction(efw, category: EFC_CAT_HWINFO, |
264 | command: EFC_CMD_HWINFO_GET_POLLED, |
265 | NULL, param_bytes: 0, resp: (__be32 *)meters, resp_bytes: len); |
266 | if (err >= 0) |
267 | for (i = 0; i < len / sizeof(u32); i++) |
268 | be32_to_cpus(&buf[i]); |
269 | |
270 | return err; |
271 | } |
272 | |
273 | static int |
274 | command_get_clock(struct snd_efw *efw, struct efc_clock *clock) |
275 | { |
276 | int err; |
277 | |
278 | err = efw_transaction(efw, category: EFC_CAT_HWCTL, |
279 | command: EFC_CMD_HWCTL_GET_CLOCK, |
280 | NULL, param_bytes: 0, |
281 | resp: (__be32 *)clock, resp_bytes: sizeof(struct efc_clock)); |
282 | if (err >= 0) { |
283 | be32_to_cpus(&clock->source); |
284 | be32_to_cpus(&clock->sampling_rate); |
285 | be32_to_cpus(&clock->index); |
286 | } |
287 | |
288 | return err; |
289 | } |
290 | |
291 | /* give UINT_MAX if set nothing */ |
292 | static int |
293 | command_set_clock(struct snd_efw *efw, |
294 | unsigned int source, unsigned int rate) |
295 | { |
296 | struct efc_clock clock = {0}; |
297 | int err; |
298 | |
299 | /* check arguments */ |
300 | if ((source == UINT_MAX) && (rate == UINT_MAX)) { |
301 | err = -EINVAL; |
302 | goto end; |
303 | } |
304 | |
305 | /* get current status */ |
306 | err = command_get_clock(efw, clock: &clock); |
307 | if (err < 0) |
308 | goto end; |
309 | |
310 | /* no need */ |
311 | if ((clock.source == source) && (clock.sampling_rate == rate)) |
312 | goto end; |
313 | |
314 | /* set params */ |
315 | if ((source != UINT_MAX) && (clock.source != source)) |
316 | clock.source = source; |
317 | if ((rate != UINT_MAX) && (clock.sampling_rate != rate)) |
318 | clock.sampling_rate = rate; |
319 | clock.index = 0; |
320 | |
321 | cpu_to_be32s(&clock.source); |
322 | cpu_to_be32s(&clock.sampling_rate); |
323 | cpu_to_be32s(&clock.index); |
324 | |
325 | err = efw_transaction(efw, category: EFC_CAT_HWCTL, |
326 | command: EFC_CMD_HWCTL_SET_CLOCK, |
327 | params: (__be32 *)&clock, param_bytes: sizeof(struct efc_clock), |
328 | NULL, resp_bytes: 0); |
329 | if (err < 0) |
330 | goto end; |
331 | |
332 | /* |
333 | * With firmware version 5.8, just after changing clock state, these |
334 | * parameters are not immediately retrieved by get command. In my |
335 | * trial, there needs to be 100msec to get changed parameters. |
336 | */ |
337 | msleep(msecs: 150); |
338 | end: |
339 | return err; |
340 | } |
341 | |
342 | int snd_efw_command_get_clock_source(struct snd_efw *efw, |
343 | enum snd_efw_clock_source *source) |
344 | { |
345 | int err; |
346 | struct efc_clock clock = {0}; |
347 | |
348 | err = command_get_clock(efw, clock: &clock); |
349 | if (err >= 0) |
350 | *source = clock.source; |
351 | |
352 | return err; |
353 | } |
354 | |
355 | int snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate) |
356 | { |
357 | int err; |
358 | struct efc_clock clock = {0}; |
359 | |
360 | err = command_get_clock(efw, clock: &clock); |
361 | if (err >= 0) |
362 | *rate = clock.sampling_rate; |
363 | |
364 | return err; |
365 | } |
366 | |
367 | int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate) |
368 | { |
369 | return command_set_clock(efw, UINT_MAX, rate); |
370 | } |
371 | |
372 | |