diff options
Diffstat (limited to 'sound/firewire/fireworks')
-rw-r--r-- | sound/firewire/fireworks/Makefile | 4 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.c | 353 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.h | 233 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_command.c | 372 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_hwdep.c | 298 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_midi.c | 168 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_pcm.c | 403 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_proc.c | 232 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_stream.c | 372 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_transaction.c | 326 |
10 files changed, 2761 insertions, 0 deletions
diff --git a/sound/firewire/fireworks/Makefile b/sound/firewire/fireworks/Makefile new file mode 100644 index 000000000000..0c7440826db8 --- /dev/null +++ b/sound/firewire/fireworks/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | snd-fireworks-objs := fireworks_transaction.o fireworks_command.o \ | ||
2 | fireworks_stream.o fireworks_proc.o fireworks_midi.o \ | ||
3 | fireworks_pcm.o fireworks_hwdep.o fireworks.o | ||
4 | obj-m += snd-fireworks.o | ||
diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c new file mode 100644 index 000000000000..996fdc44c83c --- /dev/null +++ b/sound/firewire/fireworks/fireworks.c | |||
@@ -0,0 +1,353 @@ | |||
1 | /* | ||
2 | * fireworks.c - a part of driver for Fireworks based devices | ||
3 | * | ||
4 | * Copyright (c) 2009-2010 Clemens Ladisch | ||
5 | * Copyright (c) 2013-2014 Takashi Sakamoto | ||
6 | * | ||
7 | * Licensed under the terms of the GNU General Public License, version 2. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Fireworks is a board module which Echo Audio produced. This module consists | ||
12 | * of three chipsets: | ||
13 | * - Communication chipset for IEEE1394 PHY/Link and IEC 61883-1/6 | ||
14 | * - DSP or/and FPGA for signal processing | ||
15 | * - Flash Memory to store firmwares | ||
16 | */ | ||
17 | |||
18 | #include "fireworks.h" | ||
19 | |||
20 | MODULE_DESCRIPTION("Echo Fireworks driver"); | ||
21 | MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>"); | ||
22 | MODULE_LICENSE("GPL v2"); | ||
23 | |||
24 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
25 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
26 | static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
27 | unsigned int snd_efw_resp_buf_size = 1024; | ||
28 | bool snd_efw_resp_buf_debug = false; | ||
29 | |||
30 | module_param_array(index, int, NULL, 0444); | ||
31 | MODULE_PARM_DESC(index, "card index"); | ||
32 | module_param_array(id, charp, NULL, 0444); | ||
33 | MODULE_PARM_DESC(id, "ID string"); | ||
34 | module_param_array(enable, bool, NULL, 0444); | ||
35 | MODULE_PARM_DESC(enable, "enable Fireworks sound card"); | ||
36 | module_param_named(resp_buf_size, snd_efw_resp_buf_size, uint, 0444); | ||
37 | MODULE_PARM_DESC(resp_buf_size, | ||
38 | "response buffer size (max 4096, default 1024)"); | ||
39 | module_param_named(resp_buf_debug, snd_efw_resp_buf_debug, bool, 0444); | ||
40 | MODULE_PARM_DESC(resp_buf_debug, "store all responses to buffer"); | ||
41 | |||
42 | static DEFINE_MUTEX(devices_mutex); | ||
43 | static DECLARE_BITMAP(devices_used, SNDRV_CARDS); | ||
44 | |||
45 | #define VENDOR_LOUD 0x000ff2 | ||
46 | #define MODEL_MACKIE_400F 0x00400f | ||
47 | #define MODEL_MACKIE_1200F 0x01200f | ||
48 | |||
49 | #define VENDOR_ECHO 0x001486 | ||
50 | #define MODEL_ECHO_AUDIOFIRE_12 0x00af12 | ||
51 | #define MODEL_ECHO_AUDIOFIRE_12HD 0x0af12d | ||
52 | #define MODEL_ECHO_AUDIOFIRE_12_APPLE 0x0af12a | ||
53 | /* This is applied for AudioFire8 (until 2009 July) */ | ||
54 | #define MODEL_ECHO_AUDIOFIRE_8 0x000af8 | ||
55 | #define MODEL_ECHO_AUDIOFIRE_2 0x000af2 | ||
56 | #define MODEL_ECHO_AUDIOFIRE_4 0x000af4 | ||
57 | /* AudioFire9 is applied for AudioFire8(since 2009 July) and AudioFirePre8 */ | ||
58 | #define MODEL_ECHO_AUDIOFIRE_9 0x000af9 | ||
59 | /* unknown as product */ | ||
60 | #define MODEL_ECHO_FIREWORKS_8 0x0000f8 | ||
61 | #define MODEL_ECHO_FIREWORKS_HDMI 0x00afd1 | ||
62 | |||
63 | #define VENDOR_GIBSON 0x00075b | ||
64 | /* for Robot Interface Pack of Dark Fire, Dusk Tiger, Les Paul Standard 2010 */ | ||
65 | #define MODEL_GIBSON_RIP 0x00afb2 | ||
66 | /* unknown as product */ | ||
67 | #define MODEL_GIBSON_GOLDTOP 0x00afb9 | ||
68 | |||
69 | /* part of hardware capability flags */ | ||
70 | #define FLAG_RESP_ADDR_CHANGABLE 0 | ||
71 | |||
72 | static int | ||
73 | get_hardware_info(struct snd_efw *efw) | ||
74 | { | ||
75 | struct fw_device *fw_dev = fw_parent_device(efw->unit); | ||
76 | struct snd_efw_hwinfo *hwinfo; | ||
77 | char version[12] = {0}; | ||
78 | int err; | ||
79 | |||
80 | hwinfo = kzalloc(sizeof(struct snd_efw_hwinfo), GFP_KERNEL); | ||
81 | if (hwinfo == NULL) | ||
82 | return -ENOMEM; | ||
83 | |||
84 | err = snd_efw_command_get_hwinfo(efw, hwinfo); | ||
85 | if (err < 0) | ||
86 | goto end; | ||
87 | |||
88 | /* firmware version for communication chipset */ | ||
89 | snprintf(version, sizeof(version), "%u.%u", | ||
90 | (hwinfo->arm_version >> 24) & 0xff, | ||
91 | (hwinfo->arm_version >> 16) & 0xff); | ||
92 | efw->firmware_version = hwinfo->arm_version; | ||
93 | |||
94 | strcpy(efw->card->driver, "Fireworks"); | ||
95 | strcpy(efw->card->shortname, hwinfo->model_name); | ||
96 | strcpy(efw->card->mixername, hwinfo->model_name); | ||
97 | snprintf(efw->card->longname, sizeof(efw->card->longname), | ||
98 | "%s %s v%s, GUID %08x%08x at %s, S%d", | ||
99 | hwinfo->vendor_name, hwinfo->model_name, version, | ||
100 | hwinfo->guid_hi, hwinfo->guid_lo, | ||
101 | dev_name(&efw->unit->device), 100 << fw_dev->max_speed); | ||
102 | |||
103 | if (hwinfo->flags & BIT(FLAG_RESP_ADDR_CHANGABLE)) | ||
104 | efw->resp_addr_changable = true; | ||
105 | |||
106 | efw->supported_sampling_rate = 0; | ||
107 | if ((hwinfo->min_sample_rate <= 22050) | ||
108 | && (22050 <= hwinfo->max_sample_rate)) | ||
109 | efw->supported_sampling_rate |= SNDRV_PCM_RATE_22050; | ||
110 | if ((hwinfo->min_sample_rate <= 32000) | ||
111 | && (32000 <= hwinfo->max_sample_rate)) | ||
112 | efw->supported_sampling_rate |= SNDRV_PCM_RATE_32000; | ||
113 | if ((hwinfo->min_sample_rate <= 44100) | ||
114 | && (44100 <= hwinfo->max_sample_rate)) | ||
115 | efw->supported_sampling_rate |= SNDRV_PCM_RATE_44100; | ||
116 | if ((hwinfo->min_sample_rate <= 48000) | ||
117 | && (48000 <= hwinfo->max_sample_rate)) | ||
118 | efw->supported_sampling_rate |= SNDRV_PCM_RATE_48000; | ||
119 | if ((hwinfo->min_sample_rate <= 88200) | ||
120 | && (88200 <= hwinfo->max_sample_rate)) | ||
121 | efw->supported_sampling_rate |= SNDRV_PCM_RATE_88200; | ||
122 | if ((hwinfo->min_sample_rate <= 96000) | ||
123 | && (96000 <= hwinfo->max_sample_rate)) | ||
124 | efw->supported_sampling_rate |= SNDRV_PCM_RATE_96000; | ||
125 | if ((hwinfo->min_sample_rate <= 176400) | ||
126 | && (176400 <= hwinfo->max_sample_rate)) | ||
127 | efw->supported_sampling_rate |= SNDRV_PCM_RATE_176400; | ||
128 | if ((hwinfo->min_sample_rate <= 192000) | ||
129 | && (192000 <= hwinfo->max_sample_rate)) | ||
130 | efw->supported_sampling_rate |= SNDRV_PCM_RATE_192000; | ||
131 | |||
132 | /* the number of MIDI ports, not of MIDI conformant data channels */ | ||
133 | if (hwinfo->midi_out_ports > SND_EFW_MAX_MIDI_OUT_PORTS || | ||
134 | hwinfo->midi_in_ports > SND_EFW_MAX_MIDI_IN_PORTS) { | ||
135 | err = -EIO; | ||
136 | goto end; | ||
137 | } | ||
138 | efw->midi_out_ports = hwinfo->midi_out_ports; | ||
139 | efw->midi_in_ports = hwinfo->midi_in_ports; | ||
140 | |||
141 | if (hwinfo->amdtp_tx_pcm_channels > AMDTP_MAX_CHANNELS_FOR_PCM || | ||
142 | hwinfo->amdtp_tx_pcm_channels_2x > AMDTP_MAX_CHANNELS_FOR_PCM || | ||
143 | hwinfo->amdtp_tx_pcm_channels_4x > AMDTP_MAX_CHANNELS_FOR_PCM || | ||
144 | hwinfo->amdtp_rx_pcm_channels > AMDTP_MAX_CHANNELS_FOR_PCM || | ||
145 | hwinfo->amdtp_rx_pcm_channels_2x > AMDTP_MAX_CHANNELS_FOR_PCM || | ||
146 | hwinfo->amdtp_rx_pcm_channels_4x > AMDTP_MAX_CHANNELS_FOR_PCM) { | ||
147 | err = -ENOSYS; | ||
148 | goto end; | ||
149 | } | ||
150 | efw->pcm_capture_channels[0] = hwinfo->amdtp_tx_pcm_channels; | ||
151 | efw->pcm_capture_channels[1] = hwinfo->amdtp_tx_pcm_channels_2x; | ||
152 | efw->pcm_capture_channels[2] = hwinfo->amdtp_tx_pcm_channels_4x; | ||
153 | efw->pcm_playback_channels[0] = hwinfo->amdtp_rx_pcm_channels; | ||
154 | efw->pcm_playback_channels[1] = hwinfo->amdtp_rx_pcm_channels_2x; | ||
155 | efw->pcm_playback_channels[2] = hwinfo->amdtp_rx_pcm_channels_4x; | ||
156 | |||
157 | /* Hardware metering. */ | ||
158 | if (hwinfo->phys_in_grp_count > HWINFO_MAX_CAPS_GROUPS || | ||
159 | hwinfo->phys_out_grp_count > HWINFO_MAX_CAPS_GROUPS) { | ||
160 | err = -EIO; | ||
161 | goto end; | ||
162 | } | ||
163 | efw->phys_in = hwinfo->phys_in; | ||
164 | efw->phys_out = hwinfo->phys_out; | ||
165 | efw->phys_in_grp_count = hwinfo->phys_in_grp_count; | ||
166 | efw->phys_out_grp_count = hwinfo->phys_out_grp_count; | ||
167 | memcpy(&efw->phys_in_grps, hwinfo->phys_in_grps, | ||
168 | sizeof(struct snd_efw_phys_grp) * hwinfo->phys_in_grp_count); | ||
169 | memcpy(&efw->phys_out_grps, hwinfo->phys_out_grps, | ||
170 | sizeof(struct snd_efw_phys_grp) * hwinfo->phys_out_grp_count); | ||
171 | end: | ||
172 | kfree(hwinfo); | ||
173 | return err; | ||
174 | } | ||
175 | |||
176 | static void | ||
177 | efw_card_free(struct snd_card *card) | ||
178 | { | ||
179 | struct snd_efw *efw = card->private_data; | ||
180 | |||
181 | if (efw->card_index >= 0) { | ||
182 | mutex_lock(&devices_mutex); | ||
183 | clear_bit(efw->card_index, devices_used); | ||
184 | mutex_unlock(&devices_mutex); | ||
185 | } | ||
186 | |||
187 | mutex_destroy(&efw->mutex); | ||
188 | kfree(efw->resp_buf); | ||
189 | } | ||
190 | |||
191 | static int | ||
192 | efw_probe(struct fw_unit *unit, | ||
193 | const struct ieee1394_device_id *entry) | ||
194 | { | ||
195 | struct snd_card *card; | ||
196 | struct snd_efw *efw; | ||
197 | int card_index, err; | ||
198 | |||
199 | mutex_lock(&devices_mutex); | ||
200 | |||
201 | /* check registered cards */ | ||
202 | for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) { | ||
203 | if (!test_bit(card_index, devices_used) && enable[card_index]) | ||
204 | break; | ||
205 | } | ||
206 | if (card_index >= SNDRV_CARDS) { | ||
207 | err = -ENOENT; | ||
208 | goto end; | ||
209 | } | ||
210 | |||
211 | err = snd_card_new(&unit->device, index[card_index], id[card_index], | ||
212 | THIS_MODULE, sizeof(struct snd_efw), &card); | ||
213 | if (err < 0) | ||
214 | goto end; | ||
215 | efw = card->private_data; | ||
216 | efw->card_index = card_index; | ||
217 | set_bit(card_index, devices_used); | ||
218 | card->private_free = efw_card_free; | ||
219 | |||
220 | efw->card = card; | ||
221 | efw->unit = unit; | ||
222 | mutex_init(&efw->mutex); | ||
223 | spin_lock_init(&efw->lock); | ||
224 | init_waitqueue_head(&efw->hwdep_wait); | ||
225 | |||
226 | /* prepare response buffer */ | ||
227 | snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, | ||
228 | SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U); | ||
229 | efw->resp_buf = kzalloc(snd_efw_resp_buf_size, GFP_KERNEL); | ||
230 | if (efw->resp_buf == NULL) { | ||
231 | err = -ENOMEM; | ||
232 | goto error; | ||
233 | } | ||
234 | efw->pull_ptr = efw->push_ptr = efw->resp_buf; | ||
235 | snd_efw_transaction_add_instance(efw); | ||
236 | |||
237 | err = get_hardware_info(efw); | ||
238 | if (err < 0) | ||
239 | goto error; | ||
240 | if (entry->model_id == MODEL_ECHO_AUDIOFIRE_9) | ||
241 | efw->is_af9 = true; | ||
242 | |||
243 | snd_efw_proc_init(efw); | ||
244 | |||
245 | if (efw->midi_out_ports || efw->midi_in_ports) { | ||
246 | err = snd_efw_create_midi_devices(efw); | ||
247 | if (err < 0) | ||
248 | goto error; | ||
249 | } | ||
250 | |||
251 | err = snd_efw_create_pcm_devices(efw); | ||
252 | if (err < 0) | ||
253 | goto error; | ||
254 | |||
255 | err = snd_efw_create_hwdep_device(efw); | ||
256 | if (err < 0) | ||
257 | goto error; | ||
258 | |||
259 | err = snd_efw_stream_init_duplex(efw); | ||
260 | if (err < 0) | ||
261 | goto error; | ||
262 | |||
263 | err = snd_card_register(card); | ||
264 | if (err < 0) { | ||
265 | snd_efw_stream_destroy_duplex(efw); | ||
266 | goto error; | ||
267 | } | ||
268 | |||
269 | dev_set_drvdata(&unit->device, efw); | ||
270 | end: | ||
271 | mutex_unlock(&devices_mutex); | ||
272 | return err; | ||
273 | error: | ||
274 | snd_efw_transaction_remove_instance(efw); | ||
275 | mutex_unlock(&devices_mutex); | ||
276 | snd_card_free(card); | ||
277 | return err; | ||
278 | } | ||
279 | |||
280 | static void efw_update(struct fw_unit *unit) | ||
281 | { | ||
282 | struct snd_efw *efw = dev_get_drvdata(&unit->device); | ||
283 | |||
284 | snd_efw_transaction_bus_reset(efw->unit); | ||
285 | snd_efw_stream_update_duplex(efw); | ||
286 | } | ||
287 | |||
288 | static void efw_remove(struct fw_unit *unit) | ||
289 | { | ||
290 | struct snd_efw *efw = dev_get_drvdata(&unit->device); | ||
291 | |||
292 | snd_efw_stream_destroy_duplex(efw); | ||
293 | snd_efw_transaction_remove_instance(efw); | ||
294 | |||
295 | snd_card_disconnect(efw->card); | ||
296 | snd_card_free_when_closed(efw->card); | ||
297 | } | ||
298 | |||
299 | static const struct ieee1394_device_id efw_id_table[] = { | ||
300 | SND_EFW_DEV_ENTRY(VENDOR_LOUD, MODEL_MACKIE_400F), | ||
301 | SND_EFW_DEV_ENTRY(VENDOR_LOUD, MODEL_MACKIE_1200F), | ||
302 | SND_EFW_DEV_ENTRY(VENDOR_ECHO, MODEL_ECHO_AUDIOFIRE_8), | ||
303 | SND_EFW_DEV_ENTRY(VENDOR_ECHO, MODEL_ECHO_AUDIOFIRE_12), | ||
304 | SND_EFW_DEV_ENTRY(VENDOR_ECHO, MODEL_ECHO_AUDIOFIRE_12HD), | ||
305 | SND_EFW_DEV_ENTRY(VENDOR_ECHO, MODEL_ECHO_AUDIOFIRE_12_APPLE), | ||
306 | SND_EFW_DEV_ENTRY(VENDOR_ECHO, MODEL_ECHO_AUDIOFIRE_2), | ||
307 | SND_EFW_DEV_ENTRY(VENDOR_ECHO, MODEL_ECHO_AUDIOFIRE_4), | ||
308 | SND_EFW_DEV_ENTRY(VENDOR_ECHO, MODEL_ECHO_AUDIOFIRE_9), | ||
309 | SND_EFW_DEV_ENTRY(VENDOR_ECHO, MODEL_ECHO_FIREWORKS_8), | ||
310 | SND_EFW_DEV_ENTRY(VENDOR_ECHO, MODEL_ECHO_FIREWORKS_HDMI), | ||
311 | SND_EFW_DEV_ENTRY(VENDOR_GIBSON, MODEL_GIBSON_RIP), | ||
312 | SND_EFW_DEV_ENTRY(VENDOR_GIBSON, MODEL_GIBSON_GOLDTOP), | ||
313 | {} | ||
314 | }; | ||
315 | MODULE_DEVICE_TABLE(ieee1394, efw_id_table); | ||
316 | |||
317 | static struct fw_driver efw_driver = { | ||
318 | .driver = { | ||
319 | .owner = THIS_MODULE, | ||
320 | .name = "snd-fireworks", | ||
321 | .bus = &fw_bus_type, | ||
322 | }, | ||
323 | .probe = efw_probe, | ||
324 | .update = efw_update, | ||
325 | .remove = efw_remove, | ||
326 | .id_table = efw_id_table, | ||
327 | }; | ||
328 | |||
329 | static int __init snd_efw_init(void) | ||
330 | { | ||
331 | int err; | ||
332 | |||
333 | err = snd_efw_transaction_register(); | ||
334 | if (err < 0) | ||
335 | goto end; | ||
336 | |||
337 | err = driver_register(&efw_driver.driver); | ||
338 | if (err < 0) | ||
339 | snd_efw_transaction_unregister(); | ||
340 | |||
341 | end: | ||
342 | return err; | ||
343 | } | ||
344 | |||
345 | static void __exit snd_efw_exit(void) | ||
346 | { | ||
347 | snd_efw_transaction_unregister(); | ||
348 | driver_unregister(&efw_driver.driver); | ||
349 | mutex_destroy(&devices_mutex); | ||
350 | } | ||
351 | |||
352 | module_init(snd_efw_init); | ||
353 | module_exit(snd_efw_exit); | ||
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h new file mode 100644 index 000000000000..d2b36be4d2f8 --- /dev/null +++ b/sound/firewire/fireworks/fireworks.h | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * fireworks.h - a part of driver for Fireworks based devices | ||
3 | * | ||
4 | * Copyright (c) 2009-2010 Clemens Ladisch | ||
5 | * Copyright (c) 2013-2014 Takashi Sakamoto | ||
6 | * | ||
7 | * Licensed under the terms of the GNU General Public License, version 2. | ||
8 | */ | ||
9 | #ifndef SOUND_FIREWORKS_H_INCLUDED | ||
10 | #define SOUND_FIREWORKS_H_INCLUDED | ||
11 | |||
12 | #include <linux/compat.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/firewire.h> | ||
15 | #include <linux/firewire-constants.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/mod_devicetable.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #include <sound/core.h> | ||
22 | #include <sound/initval.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/info.h> | ||
25 | #include <sound/rawmidi.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/firewire.h> | ||
28 | #include <sound/hwdep.h> | ||
29 | |||
30 | #include "../packets-buffer.h" | ||
31 | #include "../iso-resources.h" | ||
32 | #include "../amdtp.h" | ||
33 | #include "../cmp.h" | ||
34 | #include "../lib.h" | ||
35 | |||
36 | #define SND_EFW_MAX_MIDI_OUT_PORTS 2 | ||
37 | #define SND_EFW_MAX_MIDI_IN_PORTS 2 | ||
38 | |||
39 | #define SND_EFW_MULTIPLIER_MODES 3 | ||
40 | #define HWINFO_NAME_SIZE_BYTES 32 | ||
41 | #define HWINFO_MAX_CAPS_GROUPS 8 | ||
42 | |||
43 | /* | ||
44 | * This should be greater than maximum bytes for EFW response content. | ||
45 | * Currently response against command for isochronous channel mapping is | ||
46 | * confirmed to be the maximum one. But for flexibility, use maximum data | ||
47 | * payload for asynchronous primary packets at S100 (Cable base rate) in | ||
48 | * IEEE Std 1394-1995. | ||
49 | */ | ||
50 | #define SND_EFW_RESPONSE_MAXIMUM_BYTES 0x200U | ||
51 | |||
52 | extern unsigned int snd_efw_resp_buf_size; | ||
53 | extern bool snd_efw_resp_buf_debug; | ||
54 | |||
55 | struct snd_efw_phys_grp { | ||
56 | u8 type; /* see enum snd_efw_grp_type */ | ||
57 | u8 count; | ||
58 | } __packed; | ||
59 | |||
60 | struct snd_efw { | ||
61 | struct snd_card *card; | ||
62 | struct fw_unit *unit; | ||
63 | int card_index; | ||
64 | |||
65 | struct mutex mutex; | ||
66 | spinlock_t lock; | ||
67 | |||
68 | /* for transaction */ | ||
69 | u32 seqnum; | ||
70 | bool resp_addr_changable; | ||
71 | |||
72 | /* for quirks */ | ||
73 | bool is_af9; | ||
74 | u32 firmware_version; | ||
75 | |||
76 | unsigned int midi_in_ports; | ||
77 | unsigned int midi_out_ports; | ||
78 | |||
79 | unsigned int supported_sampling_rate; | ||
80 | unsigned int pcm_capture_channels[SND_EFW_MULTIPLIER_MODES]; | ||
81 | unsigned int pcm_playback_channels[SND_EFW_MULTIPLIER_MODES]; | ||
82 | |||
83 | struct amdtp_stream *master; | ||
84 | struct amdtp_stream tx_stream; | ||
85 | struct amdtp_stream rx_stream; | ||
86 | struct cmp_connection out_conn; | ||
87 | struct cmp_connection in_conn; | ||
88 | atomic_t capture_substreams; | ||
89 | atomic_t playback_substreams; | ||
90 | |||
91 | /* hardware metering parameters */ | ||
92 | unsigned int phys_out; | ||
93 | unsigned int phys_in; | ||
94 | unsigned int phys_out_grp_count; | ||
95 | unsigned int phys_in_grp_count; | ||
96 | struct snd_efw_phys_grp phys_out_grps[HWINFO_MAX_CAPS_GROUPS]; | ||
97 | struct snd_efw_phys_grp phys_in_grps[HWINFO_MAX_CAPS_GROUPS]; | ||
98 | |||
99 | /* for uapi */ | ||
100 | int dev_lock_count; | ||
101 | bool dev_lock_changed; | ||
102 | wait_queue_head_t hwdep_wait; | ||
103 | |||
104 | /* response queue */ | ||
105 | u8 *resp_buf; | ||
106 | u8 *pull_ptr; | ||
107 | u8 *push_ptr; | ||
108 | unsigned int resp_queues; | ||
109 | }; | ||
110 | |||
111 | int snd_efw_transaction_cmd(struct fw_unit *unit, | ||
112 | const void *cmd, unsigned int size); | ||
113 | int snd_efw_transaction_run(struct fw_unit *unit, | ||
114 | const void *cmd, unsigned int cmd_size, | ||
115 | void *resp, unsigned int resp_size); | ||
116 | int snd_efw_transaction_register(void); | ||
117 | void snd_efw_transaction_unregister(void); | ||
118 | void snd_efw_transaction_bus_reset(struct fw_unit *unit); | ||
119 | void snd_efw_transaction_add_instance(struct snd_efw *efw); | ||
120 | void snd_efw_transaction_remove_instance(struct snd_efw *efw); | ||
121 | |||
122 | struct snd_efw_hwinfo { | ||
123 | u32 flags; | ||
124 | u32 guid_hi; | ||
125 | u32 guid_lo; | ||
126 | u32 type; | ||
127 | u32 version; | ||
128 | char vendor_name[HWINFO_NAME_SIZE_BYTES]; | ||
129 | char model_name[HWINFO_NAME_SIZE_BYTES]; | ||
130 | u32 supported_clocks; | ||
131 | u32 amdtp_rx_pcm_channels; | ||
132 | u32 amdtp_tx_pcm_channels; | ||
133 | u32 phys_out; | ||
134 | u32 phys_in; | ||
135 | u32 phys_out_grp_count; | ||
136 | struct snd_efw_phys_grp phys_out_grps[HWINFO_MAX_CAPS_GROUPS]; | ||
137 | u32 phys_in_grp_count; | ||
138 | struct snd_efw_phys_grp phys_in_grps[HWINFO_MAX_CAPS_GROUPS]; | ||
139 | u32 midi_out_ports; | ||
140 | u32 midi_in_ports; | ||
141 | u32 max_sample_rate; | ||
142 | u32 min_sample_rate; | ||
143 | u32 dsp_version; | ||
144 | u32 arm_version; | ||
145 | u32 mixer_playback_channels; | ||
146 | u32 mixer_capture_channels; | ||
147 | u32 fpga_version; | ||
148 | u32 amdtp_rx_pcm_channels_2x; | ||
149 | u32 amdtp_tx_pcm_channels_2x; | ||
150 | u32 amdtp_rx_pcm_channels_4x; | ||
151 | u32 amdtp_tx_pcm_channels_4x; | ||
152 | u32 reserved[16]; | ||
153 | } __packed; | ||
154 | enum snd_efw_grp_type { | ||
155 | SND_EFW_CH_TYPE_ANALOG = 0, | ||
156 | SND_EFW_CH_TYPE_SPDIF = 1, | ||
157 | SND_EFW_CH_TYPE_ADAT = 2, | ||
158 | SND_EFW_CH_TYPE_SPDIF_OR_ADAT = 3, | ||
159 | SND_EFW_CH_TYPE_ANALOG_MIRRORING = 4, | ||
160 | SND_EFW_CH_TYPE_HEADPHONES = 5, | ||
161 | SND_EFW_CH_TYPE_I2S = 6, | ||
162 | SND_EFW_CH_TYPE_GUITAR = 7, | ||
163 | SND_EFW_CH_TYPE_PIEZO_GUITAR = 8, | ||
164 | SND_EFW_CH_TYPE_GUITAR_STRING = 9, | ||
165 | SND_EFW_CH_TYPE_VIRTUAL = 0x10000, | ||
166 | SND_EFW_CH_TYPE_DUMMY | ||
167 | }; | ||
168 | struct snd_efw_phys_meters { | ||
169 | u32 status; /* guitar state/midi signal/clock input detect */ | ||
170 | u32 reserved0; | ||
171 | u32 reserved1; | ||
172 | u32 reserved2; | ||
173 | u32 reserved3; | ||
174 | u32 out_meters; | ||
175 | u32 in_meters; | ||
176 | u32 reserved4; | ||
177 | u32 reserved5; | ||
178 | u32 values[0]; | ||
179 | } __packed; | ||
180 | enum snd_efw_clock_source { | ||
181 | SND_EFW_CLOCK_SOURCE_INTERNAL = 0, | ||
182 | SND_EFW_CLOCK_SOURCE_SYTMATCH = 1, | ||
183 | SND_EFW_CLOCK_SOURCE_WORDCLOCK = 2, | ||
184 | SND_EFW_CLOCK_SOURCE_SPDIF = 3, | ||
185 | SND_EFW_CLOCK_SOURCE_ADAT_1 = 4, | ||
186 | SND_EFW_CLOCK_SOURCE_ADAT_2 = 5, | ||
187 | SND_EFW_CLOCK_SOURCE_CONTINUOUS = 6 /* internal variable clock */ | ||
188 | }; | ||
189 | enum snd_efw_transport_mode { | ||
190 | SND_EFW_TRANSPORT_MODE_WINDOWS = 0, | ||
191 | SND_EFW_TRANSPORT_MODE_IEC61883 = 1, | ||
192 | }; | ||
193 | int snd_efw_command_set_resp_addr(struct snd_efw *efw, | ||
194 | u16 addr_high, u32 addr_low); | ||
195 | int snd_efw_command_set_tx_mode(struct snd_efw *efw, | ||
196 | enum snd_efw_transport_mode mode); | ||
197 | int snd_efw_command_get_hwinfo(struct snd_efw *efw, | ||
198 | struct snd_efw_hwinfo *hwinfo); | ||
199 | int snd_efw_command_get_phys_meters(struct snd_efw *efw, | ||
200 | struct snd_efw_phys_meters *meters, | ||
201 | unsigned int len); | ||
202 | int snd_efw_command_get_clock_source(struct snd_efw *efw, | ||
203 | enum snd_efw_clock_source *source); | ||
204 | int snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate); | ||
205 | int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate); | ||
206 | |||
207 | int snd_efw_stream_init_duplex(struct snd_efw *efw); | ||
208 | int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate); | ||
209 | void snd_efw_stream_stop_duplex(struct snd_efw *efw); | ||
210 | void snd_efw_stream_update_duplex(struct snd_efw *efw); | ||
211 | void snd_efw_stream_destroy_duplex(struct snd_efw *efw); | ||
212 | void snd_efw_stream_lock_changed(struct snd_efw *efw); | ||
213 | int snd_efw_stream_lock_try(struct snd_efw *efw); | ||
214 | void snd_efw_stream_lock_release(struct snd_efw *efw); | ||
215 | |||
216 | void snd_efw_proc_init(struct snd_efw *efw); | ||
217 | |||
218 | int snd_efw_create_midi_devices(struct snd_efw *efw); | ||
219 | |||
220 | int snd_efw_create_pcm_devices(struct snd_efw *efw); | ||
221 | int snd_efw_get_multiplier_mode(unsigned int sampling_rate, unsigned int *mode); | ||
222 | |||
223 | int snd_efw_create_hwdep_device(struct snd_efw *efw); | ||
224 | |||
225 | #define SND_EFW_DEV_ENTRY(vendor, model) \ | ||
226 | { \ | ||
227 | .match_flags = IEEE1394_MATCH_VENDOR_ID | \ | ||
228 | IEEE1394_MATCH_MODEL_ID, \ | ||
229 | .vendor_id = vendor,\ | ||
230 | .model_id = model \ | ||
231 | } | ||
232 | |||
233 | #endif | ||
diff --git a/sound/firewire/fireworks/fireworks_command.c b/sound/firewire/fireworks/fireworks_command.c new file mode 100644 index 000000000000..166f80584c2a --- /dev/null +++ b/sound/firewire/fireworks/fireworks_command.c | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * fireworks_command.c - a part of driver for Fireworks 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 "./fireworks.h" | ||
10 | |||
11 | /* | ||
12 | * This driver uses transaction version 1 or later to use extended hardware | ||
13 | * information. Then too old devices are not available. | ||
14 | * | ||
15 | * Each commands are not required to have continuous sequence numbers. This | ||
16 | * number is just used to match command and response. | ||
17 | * | ||
18 | * This module support a part of commands. Please see FFADO if you want to see | ||
19 | * whole commands. But there are some commands which FFADO don't implement. | ||
20 | * | ||
21 | * Fireworks also supports AV/C general commands and AV/C Stream Format | ||
22 | * Information commands. But this module don't use them. | ||
23 | */ | ||
24 | |||
25 | #define KERNEL_SEQNUM_MIN (SND_EFW_TRANSACTION_USER_SEQNUM_MAX + 2) | ||
26 | #define KERNEL_SEQNUM_MAX ((u32)~0) | ||
27 | |||
28 | /* for clock source and sampling rate */ | ||
29 | struct efc_clock { | ||
30 | u32 source; | ||
31 | u32 sampling_rate; | ||
32 | u32 index; | ||
33 | }; | ||
34 | |||
35 | /* command categories */ | ||
36 | enum efc_category { | ||
37 | EFC_CAT_HWINFO = 0, | ||
38 | EFC_CAT_TRANSPORT = 2, | ||
39 | EFC_CAT_HWCTL = 3, | ||
40 | }; | ||
41 | |||
42 | /* hardware info category commands */ | ||
43 | enum efc_cmd_hwinfo { | ||
44 | EFC_CMD_HWINFO_GET_CAPS = 0, | ||
45 | EFC_CMD_HWINFO_GET_POLLED = 1, | ||
46 | EFC_CMD_HWINFO_SET_RESP_ADDR = 2 | ||
47 | }; | ||
48 | |||
49 | enum efc_cmd_transport { | ||
50 | EFC_CMD_TRANSPORT_SET_TX_MODE = 0 | ||
51 | }; | ||
52 | |||
53 | /* hardware control category commands */ | ||
54 | enum efc_cmd_hwctl { | ||
55 | EFC_CMD_HWCTL_SET_CLOCK = 0, | ||
56 | EFC_CMD_HWCTL_GET_CLOCK = 1, | ||
57 | EFC_CMD_HWCTL_IDENTIFY = 5 | ||
58 | }; | ||
59 | |||
60 | /* return values in response */ | ||
61 | enum efr_status { | ||
62 | EFR_STATUS_OK = 0, | ||
63 | EFR_STATUS_BAD = 1, | ||
64 | EFR_STATUS_BAD_COMMAND = 2, | ||
65 | EFR_STATUS_COMM_ERR = 3, | ||
66 | EFR_STATUS_BAD_QUAD_COUNT = 4, | ||
67 | EFR_STATUS_UNSUPPORTED = 5, | ||
68 | EFR_STATUS_1394_TIMEOUT = 6, | ||
69 | EFR_STATUS_DSP_TIMEOUT = 7, | ||
70 | EFR_STATUS_BAD_RATE = 8, | ||
71 | EFR_STATUS_BAD_CLOCK = 9, | ||
72 | EFR_STATUS_BAD_CHANNEL = 10, | ||
73 | EFR_STATUS_BAD_PAN = 11, | ||
74 | EFR_STATUS_FLASH_BUSY = 12, | ||
75 | EFR_STATUS_BAD_MIRROR = 13, | ||
76 | EFR_STATUS_BAD_LED = 14, | ||
77 | EFR_STATUS_BAD_PARAMETER = 15, | ||
78 | EFR_STATUS_INCOMPLETE = 0x80000000 | ||
79 | }; | ||
80 | |||
81 | static const char *const efr_status_names[] = { | ||
82 | [EFR_STATUS_OK] = "OK", | ||
83 | [EFR_STATUS_BAD] = "bad", | ||
84 | [EFR_STATUS_BAD_COMMAND] = "bad command", | ||
85 | [EFR_STATUS_COMM_ERR] = "comm err", | ||
86 | [EFR_STATUS_BAD_QUAD_COUNT] = "bad quad count", | ||
87 | [EFR_STATUS_UNSUPPORTED] = "unsupported", | ||
88 | [EFR_STATUS_1394_TIMEOUT] = "1394 timeout", | ||
89 | [EFR_STATUS_DSP_TIMEOUT] = "DSP timeout", | ||
90 | [EFR_STATUS_BAD_RATE] = "bad rate", | ||
91 | [EFR_STATUS_BAD_CLOCK] = "bad clock", | ||
92 | [EFR_STATUS_BAD_CHANNEL] = "bad channel", | ||
93 | [EFR_STATUS_BAD_PAN] = "bad pan", | ||
94 | [EFR_STATUS_FLASH_BUSY] = "flash busy", | ||
95 | [EFR_STATUS_BAD_MIRROR] = "bad mirror", | ||
96 | [EFR_STATUS_BAD_LED] = "bad LED", | ||
97 | [EFR_STATUS_BAD_PARAMETER] = "bad parameter", | ||
98 | [EFR_STATUS_BAD_PARAMETER + 1] = "incomplete" | ||
99 | }; | ||
100 | |||
101 | static int | ||
102 | efw_transaction(struct snd_efw *efw, unsigned int category, | ||
103 | unsigned int command, | ||
104 | const __be32 *params, unsigned int param_bytes, | ||
105 | const __be32 *resp, unsigned int resp_bytes) | ||
106 | { | ||
107 | struct snd_efw_transaction *header; | ||
108 | __be32 *buf; | ||
109 | u32 seqnum; | ||
110 | unsigned int buf_bytes, cmd_bytes; | ||
111 | int err; | ||
112 | |||
113 | /* calculate buffer size*/ | ||
114 | buf_bytes = sizeof(struct snd_efw_transaction) + | ||
115 | max(param_bytes, resp_bytes); | ||
116 | |||
117 | /* keep buffer */ | ||
118 | buf = kzalloc(buf_bytes, GFP_KERNEL); | ||
119 | if (buf == NULL) | ||
120 | return -ENOMEM; | ||
121 | |||
122 | /* to keep consistency of sequence number */ | ||
123 | spin_lock(&efw->lock); | ||
124 | if ((efw->seqnum < KERNEL_SEQNUM_MIN) || | ||
125 | (efw->seqnum >= KERNEL_SEQNUM_MAX - 2)) | ||
126 | efw->seqnum = KERNEL_SEQNUM_MIN; | ||
127 | else | ||
128 | efw->seqnum += 2; | ||
129 | seqnum = efw->seqnum; | ||
130 | spin_unlock(&efw->lock); | ||
131 | |||
132 | /* fill transaction header fields */ | ||
133 | cmd_bytes = sizeof(struct snd_efw_transaction) + param_bytes; | ||
134 | header = (struct snd_efw_transaction *)buf; | ||
135 | header->length = cpu_to_be32(cmd_bytes / sizeof(__be32)); | ||
136 | header->version = cpu_to_be32(1); | ||
137 | header->seqnum = cpu_to_be32(seqnum); | ||
138 | header->category = cpu_to_be32(category); | ||
139 | header->command = cpu_to_be32(command); | ||
140 | header->status = 0; | ||
141 | |||
142 | /* fill transaction command parameters */ | ||
143 | memcpy(header->params, params, param_bytes); | ||
144 | |||
145 | err = snd_efw_transaction_run(efw->unit, buf, cmd_bytes, | ||
146 | buf, buf_bytes); | ||
147 | if (err < 0) | ||
148 | goto end; | ||
149 | |||
150 | /* check transaction header fields */ | ||
151 | if ((be32_to_cpu(header->version) < 1) || | ||
152 | (be32_to_cpu(header->category) != category) || | ||
153 | (be32_to_cpu(header->command) != command) || | ||
154 | (be32_to_cpu(header->status) != EFR_STATUS_OK)) { | ||
155 | dev_err(&efw->unit->device, "EFW command failed [%u/%u]: %s\n", | ||
156 | be32_to_cpu(header->category), | ||
157 | be32_to_cpu(header->command), | ||
158 | efr_status_names[be32_to_cpu(header->status)]); | ||
159 | err = -EIO; | ||
160 | goto end; | ||
161 | } | ||
162 | |||
163 | if (resp == NULL) | ||
164 | goto end; | ||
165 | |||
166 | /* fill transaction response parameters */ | ||
167 | memset((void *)resp, 0, resp_bytes); | ||
168 | resp_bytes = min_t(unsigned int, resp_bytes, | ||
169 | be32_to_cpu(header->length) * sizeof(__be32) - | ||
170 | sizeof(struct snd_efw_transaction)); | ||
171 | memcpy((void *)resp, &buf[6], resp_bytes); | ||
172 | end: | ||
173 | kfree(buf); | ||
174 | return err; | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * The address in host system for transaction response is changable when the | ||
179 | * device supports. struct hwinfo.flags includes its flag. The default is | ||
180 | * MEMORY_SPACE_EFW_RESPONSE. | ||
181 | */ | ||
182 | int snd_efw_command_set_resp_addr(struct snd_efw *efw, | ||
183 | u16 addr_high, u32 addr_low) | ||
184 | { | ||
185 | __be32 addr[2]; | ||
186 | |||
187 | addr[0] = cpu_to_be32(addr_high); | ||
188 | addr[1] = cpu_to_be32(addr_low); | ||
189 | |||
190 | if (!efw->resp_addr_changable) | ||
191 | return -ENOSYS; | ||
192 | |||
193 | return efw_transaction(efw, EFC_CAT_HWCTL, | ||
194 | EFC_CMD_HWINFO_SET_RESP_ADDR, | ||
195 | addr, sizeof(addr), NULL, 0); | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * This is for timestamp processing. In Windows mode, all 32bit fields of second | ||
200 | * CIP header in AMDTP transmit packet is used for 'presentation timestamp'. In | ||
201 | * 'no data' packet the value of this field is 0x90ffffff. | ||
202 | */ | ||
203 | int snd_efw_command_set_tx_mode(struct snd_efw *efw, | ||
204 | enum snd_efw_transport_mode mode) | ||
205 | { | ||
206 | __be32 param = cpu_to_be32(mode); | ||
207 | return efw_transaction(efw, EFC_CAT_TRANSPORT, | ||
208 | EFC_CMD_TRANSPORT_SET_TX_MODE, | ||
209 | ¶m, sizeof(param), NULL, 0); | ||
210 | } | ||
211 | |||
212 | int snd_efw_command_get_hwinfo(struct snd_efw *efw, | ||
213 | struct snd_efw_hwinfo *hwinfo) | ||
214 | { | ||
215 | int err; | ||
216 | |||
217 | err = efw_transaction(efw, EFC_CAT_HWINFO, | ||
218 | EFC_CMD_HWINFO_GET_CAPS, | ||
219 | NULL, 0, (__be32 *)hwinfo, sizeof(*hwinfo)); | ||
220 | if (err < 0) | ||
221 | goto end; | ||
222 | |||
223 | be32_to_cpus(&hwinfo->flags); | ||
224 | be32_to_cpus(&hwinfo->guid_hi); | ||
225 | be32_to_cpus(&hwinfo->guid_lo); | ||
226 | be32_to_cpus(&hwinfo->type); | ||
227 | be32_to_cpus(&hwinfo->version); | ||
228 | be32_to_cpus(&hwinfo->supported_clocks); | ||
229 | be32_to_cpus(&hwinfo->amdtp_rx_pcm_channels); | ||
230 | be32_to_cpus(&hwinfo->amdtp_tx_pcm_channels); | ||
231 | be32_to_cpus(&hwinfo->phys_out); | ||
232 | be32_to_cpus(&hwinfo->phys_in); | ||
233 | be32_to_cpus(&hwinfo->phys_out_grp_count); | ||
234 | be32_to_cpus(&hwinfo->phys_in_grp_count); | ||
235 | be32_to_cpus(&hwinfo->midi_out_ports); | ||
236 | be32_to_cpus(&hwinfo->midi_in_ports); | ||
237 | be32_to_cpus(&hwinfo->max_sample_rate); | ||
238 | be32_to_cpus(&hwinfo->min_sample_rate); | ||
239 | be32_to_cpus(&hwinfo->dsp_version); | ||
240 | be32_to_cpus(&hwinfo->arm_version); | ||
241 | be32_to_cpus(&hwinfo->mixer_playback_channels); | ||
242 | be32_to_cpus(&hwinfo->mixer_capture_channels); | ||
243 | be32_to_cpus(&hwinfo->fpga_version); | ||
244 | be32_to_cpus(&hwinfo->amdtp_rx_pcm_channels_2x); | ||
245 | be32_to_cpus(&hwinfo->amdtp_tx_pcm_channels_2x); | ||
246 | be32_to_cpus(&hwinfo->amdtp_rx_pcm_channels_4x); | ||
247 | be32_to_cpus(&hwinfo->amdtp_tx_pcm_channels_4x); | ||
248 | |||
249 | /* ensure terminated */ | ||
250 | hwinfo->vendor_name[HWINFO_NAME_SIZE_BYTES - 1] = '\0'; | ||
251 | hwinfo->model_name[HWINFO_NAME_SIZE_BYTES - 1] = '\0'; | ||
252 | end: | ||
253 | return err; | ||
254 | } | ||
255 | |||
256 | int snd_efw_command_get_phys_meters(struct snd_efw *efw, | ||
257 | struct snd_efw_phys_meters *meters, | ||
258 | unsigned int len) | ||
259 | { | ||
260 | __be32 *buf = (__be32 *)meters; | ||
261 | unsigned int i; | ||
262 | int err; | ||
263 | |||
264 | err = efw_transaction(efw, EFC_CAT_HWINFO, | ||
265 | EFC_CMD_HWINFO_GET_POLLED, | ||
266 | NULL, 0, (__be32 *)meters, len); | ||
267 | if (err >= 0) | ||
268 | for (i = 0; i < len / sizeof(u32); i++) | ||
269 | be32_to_cpus(&buf[i]); | ||
270 | |||
271 | return err; | ||
272 | } | ||
273 | |||
274 | static int | ||
275 | command_get_clock(struct snd_efw *efw, struct efc_clock *clock) | ||
276 | { | ||
277 | int err; | ||
278 | |||
279 | err = efw_transaction(efw, EFC_CAT_HWCTL, | ||
280 | EFC_CMD_HWCTL_GET_CLOCK, | ||
281 | NULL, 0, | ||
282 | (__be32 *)clock, sizeof(struct efc_clock)); | ||
283 | if (err >= 0) { | ||
284 | be32_to_cpus(&clock->source); | ||
285 | be32_to_cpus(&clock->sampling_rate); | ||
286 | be32_to_cpus(&clock->index); | ||
287 | } | ||
288 | |||
289 | return err; | ||
290 | } | ||
291 | |||
292 | /* give UINT_MAX if set nothing */ | ||
293 | static int | ||
294 | command_set_clock(struct snd_efw *efw, | ||
295 | unsigned int source, unsigned int rate) | ||
296 | { | ||
297 | struct efc_clock clock = {0}; | ||
298 | int err; | ||
299 | |||
300 | /* check arguments */ | ||
301 | if ((source == UINT_MAX) && (rate == UINT_MAX)) { | ||
302 | err = -EINVAL; | ||
303 | goto end; | ||
304 | } | ||
305 | |||
306 | /* get current status */ | ||
307 | err = command_get_clock(efw, &clock); | ||
308 | if (err < 0) | ||
309 | goto end; | ||
310 | |||
311 | /* no need */ | ||
312 | if ((clock.source == source) && (clock.sampling_rate == rate)) | ||
313 | goto end; | ||
314 | |||
315 | /* set params */ | ||
316 | if ((source != UINT_MAX) && (clock.source != source)) | ||
317 | clock.source = source; | ||
318 | if ((rate != UINT_MAX) && (clock.sampling_rate != rate)) | ||
319 | clock.sampling_rate = rate; | ||
320 | clock.index = 0; | ||
321 | |||
322 | cpu_to_be32s(&clock.source); | ||
323 | cpu_to_be32s(&clock.sampling_rate); | ||
324 | cpu_to_be32s(&clock.index); | ||
325 | |||
326 | err = efw_transaction(efw, EFC_CAT_HWCTL, | ||
327 | EFC_CMD_HWCTL_SET_CLOCK, | ||
328 | (__be32 *)&clock, sizeof(struct efc_clock), | ||
329 | NULL, 0); | ||
330 | if (err < 0) | ||
331 | goto end; | ||
332 | |||
333 | /* | ||
334 | * With firmware version 5.8, just after changing clock state, these | ||
335 | * parameters are not immediately retrieved by get command. In my | ||
336 | * trial, there needs to be 100msec to get changed parameters. | ||
337 | */ | ||
338 | msleep(150); | ||
339 | end: | ||
340 | return err; | ||
341 | } | ||
342 | |||
343 | int snd_efw_command_get_clock_source(struct snd_efw *efw, | ||
344 | enum snd_efw_clock_source *source) | ||
345 | { | ||
346 | int err; | ||
347 | struct efc_clock clock = {0}; | ||
348 | |||
349 | err = command_get_clock(efw, &clock); | ||
350 | if (err >= 0) | ||
351 | *source = clock.source; | ||
352 | |||
353 | return err; | ||
354 | } | ||
355 | |||
356 | int snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate) | ||
357 | { | ||
358 | int err; | ||
359 | struct efc_clock clock = {0}; | ||
360 | |||
361 | err = command_get_clock(efw, &clock); | ||
362 | if (err >= 0) | ||
363 | *rate = clock.sampling_rate; | ||
364 | |||
365 | return err; | ||
366 | } | ||
367 | |||
368 | int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate) | ||
369 | { | ||
370 | return command_set_clock(efw, UINT_MAX, rate); | ||
371 | } | ||
372 | |||
diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c new file mode 100644 index 000000000000..4f8216fb6b62 --- /dev/null +++ b/sound/firewire/fireworks/fireworks_hwdep.c | |||
@@ -0,0 +1,298 @@ | |||
1 | /* | ||
2 | * fireworks_hwdep.c - a part of driver for Fireworks 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 | /* | ||
10 | * This codes have five functionalities. | ||
11 | * | ||
12 | * 1.get information about firewire node | ||
13 | * 2.get notification about starting/stopping stream | ||
14 | * 3.lock/unlock streaming | ||
15 | * 4.transmit command of EFW transaction | ||
16 | * 5.receive response of EFW transaction | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include "fireworks.h" | ||
21 | |||
22 | static long | ||
23 | hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained, | ||
24 | loff_t *offset) | ||
25 | { | ||
26 | unsigned int length, till_end, type; | ||
27 | struct snd_efw_transaction *t; | ||
28 | long count = 0; | ||
29 | |||
30 | if (remained < sizeof(type) + sizeof(struct snd_efw_transaction)) | ||
31 | return -ENOSPC; | ||
32 | |||
33 | /* data type is SNDRV_FIREWIRE_EVENT_EFW_RESPONSE */ | ||
34 | type = SNDRV_FIREWIRE_EVENT_EFW_RESPONSE; | ||
35 | if (copy_to_user(buf, &type, sizeof(type))) | ||
36 | return -EFAULT; | ||
37 | remained -= sizeof(type); | ||
38 | buf += sizeof(type); | ||
39 | |||
40 | /* write into buffer as many responses as possible */ | ||
41 | while (efw->resp_queues > 0) { | ||
42 | t = (struct snd_efw_transaction *)(efw->pull_ptr); | ||
43 | length = be32_to_cpu(t->length) * sizeof(__be32); | ||
44 | |||
45 | /* confirm enough space for this response */ | ||
46 | if (remained < length) | ||
47 | break; | ||
48 | |||
49 | /* copy from ring buffer to user buffer */ | ||
50 | while (length > 0) { | ||
51 | till_end = snd_efw_resp_buf_size - | ||
52 | (unsigned int)(efw->pull_ptr - efw->resp_buf); | ||
53 | till_end = min_t(unsigned int, length, till_end); | ||
54 | |||
55 | if (copy_to_user(buf, efw->pull_ptr, till_end)) | ||
56 | return -EFAULT; | ||
57 | |||
58 | efw->pull_ptr += till_end; | ||
59 | if (efw->pull_ptr >= efw->resp_buf + | ||
60 | snd_efw_resp_buf_size) | ||
61 | efw->pull_ptr = efw->resp_buf; | ||
62 | |||
63 | length -= till_end; | ||
64 | buf += till_end; | ||
65 | count += till_end; | ||
66 | remained -= till_end; | ||
67 | } | ||
68 | |||
69 | efw->resp_queues--; | ||
70 | } | ||
71 | |||
72 | return count; | ||
73 | } | ||
74 | |||
75 | static long | ||
76 | hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count, | ||
77 | loff_t *offset) | ||
78 | { | ||
79 | union snd_firewire_event event; | ||
80 | |||
81 | memset(&event, 0, sizeof(event)); | ||
82 | |||
83 | event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; | ||
84 | event.lock_status.status = (efw->dev_lock_count > 0); | ||
85 | efw->dev_lock_changed = false; | ||
86 | |||
87 | count = min_t(long, count, sizeof(event.lock_status)); | ||
88 | |||
89 | if (copy_to_user(buf, &event, count)) | ||
90 | return -EFAULT; | ||
91 | |||
92 | return count; | ||
93 | } | ||
94 | |||
95 | static long | ||
96 | hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, | ||
97 | loff_t *offset) | ||
98 | { | ||
99 | struct snd_efw *efw = hwdep->private_data; | ||
100 | DEFINE_WAIT(wait); | ||
101 | |||
102 | spin_lock_irq(&efw->lock); | ||
103 | |||
104 | while ((!efw->dev_lock_changed) && (efw->resp_queues == 0)) { | ||
105 | prepare_to_wait(&efw->hwdep_wait, &wait, TASK_INTERRUPTIBLE); | ||
106 | spin_unlock_irq(&efw->lock); | ||
107 | schedule(); | ||
108 | finish_wait(&efw->hwdep_wait, &wait); | ||
109 | if (signal_pending(current)) | ||
110 | return -ERESTARTSYS; | ||
111 | spin_lock_irq(&efw->lock); | ||
112 | } | ||
113 | |||
114 | if (efw->dev_lock_changed) | ||
115 | count = hwdep_read_locked(efw, buf, count, offset); | ||
116 | else if (efw->resp_queues > 0) | ||
117 | count = hwdep_read_resp_buf(efw, buf, count, offset); | ||
118 | |||
119 | spin_unlock_irq(&efw->lock); | ||
120 | |||
121 | return count; | ||
122 | } | ||
123 | |||
124 | static long | ||
125 | hwdep_write(struct snd_hwdep *hwdep, const char __user *data, long count, | ||
126 | loff_t *offset) | ||
127 | { | ||
128 | struct snd_efw *efw = hwdep->private_data; | ||
129 | u32 seqnum; | ||
130 | u8 *buf; | ||
131 | |||
132 | if (count < sizeof(struct snd_efw_transaction) || | ||
133 | SND_EFW_RESPONSE_MAXIMUM_BYTES < count) | ||
134 | return -EINVAL; | ||
135 | |||
136 | buf = memdup_user(data, count); | ||
137 | if (IS_ERR(buf)) | ||
138 | return PTR_ERR(buf); | ||
139 | |||
140 | /* check seqnum is not for kernel-land */ | ||
141 | seqnum = be32_to_cpu(((struct snd_efw_transaction *)buf)->seqnum); | ||
142 | if (seqnum > SND_EFW_TRANSACTION_USER_SEQNUM_MAX) { | ||
143 | count = -EINVAL; | ||
144 | goto end; | ||
145 | } | ||
146 | |||
147 | if (snd_efw_transaction_cmd(efw->unit, buf, count) < 0) | ||
148 | count = -EIO; | ||
149 | end: | ||
150 | kfree(buf); | ||
151 | return count; | ||
152 | } | ||
153 | |||
154 | static unsigned int | ||
155 | hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) | ||
156 | { | ||
157 | struct snd_efw *efw = hwdep->private_data; | ||
158 | unsigned int events; | ||
159 | |||
160 | poll_wait(file, &efw->hwdep_wait, wait); | ||
161 | |||
162 | spin_lock_irq(&efw->lock); | ||
163 | if (efw->dev_lock_changed || (efw->resp_queues > 0)) | ||
164 | events = POLLIN | POLLRDNORM; | ||
165 | else | ||
166 | events = 0; | ||
167 | spin_unlock_irq(&efw->lock); | ||
168 | |||
169 | return events | POLLOUT; | ||
170 | } | ||
171 | |||
172 | static int | ||
173 | hwdep_get_info(struct snd_efw *efw, void __user *arg) | ||
174 | { | ||
175 | struct fw_device *dev = fw_parent_device(efw->unit); | ||
176 | struct snd_firewire_get_info info; | ||
177 | |||
178 | memset(&info, 0, sizeof(info)); | ||
179 | info.type = SNDRV_FIREWIRE_TYPE_FIREWORKS; | ||
180 | info.card = dev->card->index; | ||
181 | *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); | ||
182 | *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); | ||
183 | strlcpy(info.device_name, dev_name(&dev->device), | ||
184 | sizeof(info.device_name)); | ||
185 | |||
186 | if (copy_to_user(arg, &info, sizeof(info))) | ||
187 | return -EFAULT; | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static int | ||
193 | hwdep_lock(struct snd_efw *efw) | ||
194 | { | ||
195 | int err; | ||
196 | |||
197 | spin_lock_irq(&efw->lock); | ||
198 | |||
199 | if (efw->dev_lock_count == 0) { | ||
200 | efw->dev_lock_count = -1; | ||
201 | err = 0; | ||
202 | } else { | ||
203 | err = -EBUSY; | ||
204 | } | ||
205 | |||
206 | spin_unlock_irq(&efw->lock); | ||
207 | |||
208 | return err; | ||
209 | } | ||
210 | |||
211 | static int | ||
212 | hwdep_unlock(struct snd_efw *efw) | ||
213 | { | ||
214 | int err; | ||
215 | |||
216 | spin_lock_irq(&efw->lock); | ||
217 | |||
218 | if (efw->dev_lock_count == -1) { | ||
219 | efw->dev_lock_count = 0; | ||
220 | err = 0; | ||
221 | } else { | ||
222 | err = -EBADFD; | ||
223 | } | ||
224 | |||
225 | spin_unlock_irq(&efw->lock); | ||
226 | |||
227 | return err; | ||
228 | } | ||
229 | |||
230 | static int | ||
231 | hwdep_release(struct snd_hwdep *hwdep, struct file *file) | ||
232 | { | ||
233 | struct snd_efw *efw = hwdep->private_data; | ||
234 | |||
235 | spin_lock_irq(&efw->lock); | ||
236 | if (efw->dev_lock_count == -1) | ||
237 | efw->dev_lock_count = 0; | ||
238 | spin_unlock_irq(&efw->lock); | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int | ||
244 | hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, | ||
245 | unsigned int cmd, unsigned long arg) | ||
246 | { | ||
247 | struct snd_efw *efw = hwdep->private_data; | ||
248 | |||
249 | switch (cmd) { | ||
250 | case SNDRV_FIREWIRE_IOCTL_GET_INFO: | ||
251 | return hwdep_get_info(efw, (void __user *)arg); | ||
252 | case SNDRV_FIREWIRE_IOCTL_LOCK: | ||
253 | return hwdep_lock(efw); | ||
254 | case SNDRV_FIREWIRE_IOCTL_UNLOCK: | ||
255 | return hwdep_unlock(efw); | ||
256 | default: | ||
257 | return -ENOIOCTLCMD; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | #ifdef CONFIG_COMPAT | ||
262 | static int | ||
263 | hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, | ||
264 | unsigned int cmd, unsigned long arg) | ||
265 | { | ||
266 | return hwdep_ioctl(hwdep, file, cmd, | ||
267 | (unsigned long)compat_ptr(arg)); | ||
268 | } | ||
269 | #else | ||
270 | #define hwdep_compat_ioctl NULL | ||
271 | #endif | ||
272 | |||
273 | static const struct snd_hwdep_ops hwdep_ops = { | ||
274 | .read = hwdep_read, | ||
275 | .write = hwdep_write, | ||
276 | .release = hwdep_release, | ||
277 | .poll = hwdep_poll, | ||
278 | .ioctl = hwdep_ioctl, | ||
279 | .ioctl_compat = hwdep_compat_ioctl, | ||
280 | }; | ||
281 | |||
282 | int snd_efw_create_hwdep_device(struct snd_efw *efw) | ||
283 | { | ||
284 | struct snd_hwdep *hwdep; | ||
285 | int err; | ||
286 | |||
287 | err = snd_hwdep_new(efw->card, "Fireworks", 0, &hwdep); | ||
288 | if (err < 0) | ||
289 | goto end; | ||
290 | strcpy(hwdep->name, "Fireworks"); | ||
291 | hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREWORKS; | ||
292 | hwdep->ops = hwdep_ops; | ||
293 | hwdep->private_data = efw; | ||
294 | hwdep->exclusive = true; | ||
295 | end: | ||
296 | return err; | ||
297 | } | ||
298 | |||
diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c new file mode 100644 index 000000000000..cf9c65260439 --- /dev/null +++ b/sound/firewire/fireworks/fireworks_midi.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * fireworks_midi.c - a part of driver for Fireworks based devices | ||
3 | * | ||
4 | * Copyright (c) 2009-2010 Clemens Ladisch | ||
5 | * Copyright (c) 2013-2014 Takashi Sakamoto | ||
6 | * | ||
7 | * Licensed under the terms of the GNU General Public License, version 2. | ||
8 | */ | ||
9 | #include "fireworks.h" | ||
10 | |||
11 | static int midi_capture_open(struct snd_rawmidi_substream *substream) | ||
12 | { | ||
13 | struct snd_efw *efw = substream->rmidi->private_data; | ||
14 | int err; | ||
15 | |||
16 | err = snd_efw_stream_lock_try(efw); | ||
17 | if (err < 0) | ||
18 | goto end; | ||
19 | |||
20 | atomic_inc(&efw->capture_substreams); | ||
21 | err = snd_efw_stream_start_duplex(efw, 0); | ||
22 | if (err < 0) | ||
23 | snd_efw_stream_lock_release(efw); | ||
24 | |||
25 | end: | ||
26 | return err; | ||
27 | } | ||
28 | |||
29 | static int midi_playback_open(struct snd_rawmidi_substream *substream) | ||
30 | { | ||
31 | struct snd_efw *efw = substream->rmidi->private_data; | ||
32 | int err; | ||
33 | |||
34 | err = snd_efw_stream_lock_try(efw); | ||
35 | if (err < 0) | ||
36 | goto end; | ||
37 | |||
38 | atomic_inc(&efw->playback_substreams); | ||
39 | err = snd_efw_stream_start_duplex(efw, 0); | ||
40 | if (err < 0) | ||
41 | snd_efw_stream_lock_release(efw); | ||
42 | end: | ||
43 | return err; | ||
44 | } | ||
45 | |||
46 | static int midi_capture_close(struct snd_rawmidi_substream *substream) | ||
47 | { | ||
48 | struct snd_efw *efw = substream->rmidi->private_data; | ||
49 | |||
50 | atomic_dec(&efw->capture_substreams); | ||
51 | snd_efw_stream_stop_duplex(efw); | ||
52 | |||
53 | snd_efw_stream_lock_release(efw); | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int midi_playback_close(struct snd_rawmidi_substream *substream) | ||
58 | { | ||
59 | struct snd_efw *efw = substream->rmidi->private_data; | ||
60 | |||
61 | atomic_dec(&efw->playback_substreams); | ||
62 | snd_efw_stream_stop_duplex(efw); | ||
63 | |||
64 | snd_efw_stream_lock_release(efw); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) | ||
69 | { | ||
70 | struct snd_efw *efw = substrm->rmidi->private_data; | ||
71 | unsigned long flags; | ||
72 | |||
73 | spin_lock_irqsave(&efw->lock, flags); | ||
74 | |||
75 | if (up) | ||
76 | amdtp_stream_midi_trigger(&efw->tx_stream, | ||
77 | substrm->number, substrm); | ||
78 | else | ||
79 | amdtp_stream_midi_trigger(&efw->tx_stream, | ||
80 | substrm->number, NULL); | ||
81 | |||
82 | spin_unlock_irqrestore(&efw->lock, flags); | ||
83 | } | ||
84 | |||
85 | static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) | ||
86 | { | ||
87 | struct snd_efw *efw = substrm->rmidi->private_data; | ||
88 | unsigned long flags; | ||
89 | |||
90 | spin_lock_irqsave(&efw->lock, flags); | ||
91 | |||
92 | if (up) | ||
93 | amdtp_stream_midi_trigger(&efw->rx_stream, | ||
94 | substrm->number, substrm); | ||
95 | else | ||
96 | amdtp_stream_midi_trigger(&efw->rx_stream, | ||
97 | substrm->number, NULL); | ||
98 | |||
99 | spin_unlock_irqrestore(&efw->lock, flags); | ||
100 | } | ||
101 | |||
102 | static struct snd_rawmidi_ops midi_capture_ops = { | ||
103 | .open = midi_capture_open, | ||
104 | .close = midi_capture_close, | ||
105 | .trigger = midi_capture_trigger, | ||
106 | }; | ||
107 | |||
108 | static struct snd_rawmidi_ops midi_playback_ops = { | ||
109 | .open = midi_playback_open, | ||
110 | .close = midi_playback_close, | ||
111 | .trigger = midi_playback_trigger, | ||
112 | }; | ||
113 | |||
114 | static void set_midi_substream_names(struct snd_efw *efw, | ||
115 | struct snd_rawmidi_str *str) | ||
116 | { | ||
117 | struct snd_rawmidi_substream *subs; | ||
118 | |||
119 | list_for_each_entry(subs, &str->substreams, list) { | ||
120 | snprintf(subs->name, sizeof(subs->name), | ||
121 | "%s MIDI %d", efw->card->shortname, subs->number + 1); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | int snd_efw_create_midi_devices(struct snd_efw *efw) | ||
126 | { | ||
127 | struct snd_rawmidi *rmidi; | ||
128 | struct snd_rawmidi_str *str; | ||
129 | int err; | ||
130 | |||
131 | /* create midi ports */ | ||
132 | err = snd_rawmidi_new(efw->card, efw->card->driver, 0, | ||
133 | efw->midi_out_ports, efw->midi_in_ports, | ||
134 | &rmidi); | ||
135 | if (err < 0) | ||
136 | return err; | ||
137 | |||
138 | snprintf(rmidi->name, sizeof(rmidi->name), | ||
139 | "%s MIDI", efw->card->shortname); | ||
140 | rmidi->private_data = efw; | ||
141 | |||
142 | if (efw->midi_in_ports > 0) { | ||
143 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; | ||
144 | |||
145 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
146 | &midi_capture_ops); | ||
147 | |||
148 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; | ||
149 | |||
150 | set_midi_substream_names(efw, str); | ||
151 | } | ||
152 | |||
153 | if (efw->midi_out_ports > 0) { | ||
154 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; | ||
155 | |||
156 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
157 | &midi_playback_ops); | ||
158 | |||
159 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; | ||
160 | |||
161 | set_midi_substream_names(efw, str); | ||
162 | } | ||
163 | |||
164 | if ((efw->midi_out_ports > 0) && (efw->midi_in_ports > 0)) | ||
165 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; | ||
166 | |||
167 | return 0; | ||
168 | } | ||
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c new file mode 100644 index 000000000000..8a34753de210 --- /dev/null +++ b/sound/firewire/fireworks/fireworks_pcm.c | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * fireworks_pcm.c - a part of driver for Fireworks based devices | ||
3 | * | ||
4 | * Copyright (c) 2009-2010 Clemens Ladisch | ||
5 | * Copyright (c) 2013-2014 Takashi Sakamoto | ||
6 | * | ||
7 | * Licensed under the terms of the GNU General Public License, version 2. | ||
8 | */ | ||
9 | #include "./fireworks.h" | ||
10 | |||
11 | /* | ||
12 | * NOTE: | ||
13 | * Fireworks changes its AMDTP channels for PCM data according to its sampling | ||
14 | * rate. There are three modes. Here _XX is either _rx or _tx. | ||
15 | * 0: 32.0- 48.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels applied | ||
16 | * 1: 88.2- 96.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels_2x applied | ||
17 | * 2: 176.4-192.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels_4x applied | ||
18 | * | ||
19 | * The number of PCM channels for analog input and output are always fixed but | ||
20 | * the number of PCM channels for digital input and output are differed. | ||
21 | * | ||
22 | * Additionally, according to "AudioFire Owner's Manual Version 2.2", in some | ||
23 | * model, the number of PCM channels for digital input has more restriction | ||
24 | * depending on which digital interface is selected. | ||
25 | * - S/PDIF coaxial and optical : use input 1-2 | ||
26 | * - ADAT optical at 32.0-48.0 kHz : use input 1-8 | ||
27 | * - ADAT optical at 88.2-96.0 kHz : use input 1-4 (S/MUX format) | ||
28 | * | ||
29 | * The data in AMDTP channels for blank PCM channels are zero. | ||
30 | */ | ||
31 | static const unsigned int freq_table[] = { | ||
32 | /* multiplier mode 0 */ | ||
33 | [0] = 32000, | ||
34 | [1] = 44100, | ||
35 | [2] = 48000, | ||
36 | /* multiplier mode 1 */ | ||
37 | [3] = 88200, | ||
38 | [4] = 96000, | ||
39 | /* multiplier mode 2 */ | ||
40 | [5] = 176400, | ||
41 | [6] = 192000, | ||
42 | }; | ||
43 | |||
44 | static inline unsigned int | ||
45 | get_multiplier_mode_with_index(unsigned int index) | ||
46 | { | ||
47 | return ((int)index - 1) / 2; | ||
48 | } | ||
49 | |||
50 | int snd_efw_get_multiplier_mode(unsigned int sampling_rate, unsigned int *mode) | ||
51 | { | ||
52 | unsigned int i; | ||
53 | |||
54 | for (i = 0; i < ARRAY_SIZE(freq_table); i++) { | ||
55 | if (freq_table[i] == sampling_rate) { | ||
56 | *mode = get_multiplier_mode_with_index(i); | ||
57 | return 0; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | return -EINVAL; | ||
62 | } | ||
63 | |||
64 | static int | ||
65 | hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) | ||
66 | { | ||
67 | unsigned int *pcm_channels = rule->private; | ||
68 | struct snd_interval *r = | ||
69 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
70 | const struct snd_interval *c = | ||
71 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
72 | struct snd_interval t = { | ||
73 | .min = UINT_MAX, .max = 0, .integer = 1 | ||
74 | }; | ||
75 | unsigned int i, mode; | ||
76 | |||
77 | for (i = 0; i < ARRAY_SIZE(freq_table); i++) { | ||
78 | mode = get_multiplier_mode_with_index(i); | ||
79 | if (!snd_interval_test(c, pcm_channels[mode])) | ||
80 | continue; | ||
81 | |||
82 | t.min = min(t.min, freq_table[i]); | ||
83 | t.max = max(t.max, freq_table[i]); | ||
84 | } | ||
85 | |||
86 | return snd_interval_refine(r, &t); | ||
87 | } | ||
88 | |||
89 | static int | ||
90 | hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) | ||
91 | { | ||
92 | unsigned int *pcm_channels = rule->private; | ||
93 | struct snd_interval *c = | ||
94 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
95 | const struct snd_interval *r = | ||
96 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); | ||
97 | struct snd_interval t = { | ||
98 | .min = UINT_MAX, .max = 0, .integer = 1 | ||
99 | }; | ||
100 | unsigned int i, mode; | ||
101 | |||
102 | for (i = 0; i < ARRAY_SIZE(freq_table); i++) { | ||
103 | mode = get_multiplier_mode_with_index(i); | ||
104 | if (!snd_interval_test(r, freq_table[i])) | ||
105 | continue; | ||
106 | |||
107 | t.min = min(t.min, pcm_channels[mode]); | ||
108 | t.max = max(t.max, pcm_channels[mode]); | ||
109 | } | ||
110 | |||
111 | return snd_interval_refine(c, &t); | ||
112 | } | ||
113 | |||
114 | static void | ||
115 | limit_channels(struct snd_pcm_hardware *hw, unsigned int *pcm_channels) | ||
116 | { | ||
117 | unsigned int i, mode; | ||
118 | |||
119 | hw->channels_min = UINT_MAX; | ||
120 | hw->channels_max = 0; | ||
121 | |||
122 | for (i = 0; i < ARRAY_SIZE(freq_table); i++) { | ||
123 | mode = get_multiplier_mode_with_index(i); | ||
124 | if (pcm_channels[mode] == 0) | ||
125 | continue; | ||
126 | |||
127 | hw->channels_min = min(hw->channels_min, pcm_channels[mode]); | ||
128 | hw->channels_max = max(hw->channels_max, pcm_channels[mode]); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | static void | ||
133 | limit_period_and_buffer(struct snd_pcm_hardware *hw) | ||
134 | { | ||
135 | hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ | ||
136 | hw->periods_max = UINT_MAX; | ||
137 | |||
138 | hw->period_bytes_min = 4 * hw->channels_max; /* bytes for a frame */ | ||
139 | |||
140 | /* Just to prevent from allocating much pages. */ | ||
141 | hw->period_bytes_max = hw->period_bytes_min * 2048; | ||
142 | hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; | ||
143 | } | ||
144 | |||
145 | static int | ||
146 | pcm_init_hw_params(struct snd_efw *efw, | ||
147 | struct snd_pcm_substream *substream) | ||
148 | { | ||
149 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
150 | struct amdtp_stream *s; | ||
151 | unsigned int *pcm_channels; | ||
152 | int err; | ||
153 | |||
154 | runtime->hw.info = SNDRV_PCM_INFO_BATCH | | ||
155 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
156 | SNDRV_PCM_INFO_INTERLEAVED | | ||
157 | SNDRV_PCM_INFO_JOINT_DUPLEX | | ||
158 | SNDRV_PCM_INFO_MMAP | | ||
159 | SNDRV_PCM_INFO_MMAP_VALID; | ||
160 | |||
161 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
162 | runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS; | ||
163 | s = &efw->tx_stream; | ||
164 | pcm_channels = efw->pcm_capture_channels; | ||
165 | } else { | ||
166 | runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS; | ||
167 | s = &efw->rx_stream; | ||
168 | pcm_channels = efw->pcm_playback_channels; | ||
169 | } | ||
170 | |||
171 | /* limit rates */ | ||
172 | runtime->hw.rates = efw->supported_sampling_rate, | ||
173 | snd_pcm_limit_hw_rates(runtime); | ||
174 | |||
175 | limit_channels(&runtime->hw, pcm_channels); | ||
176 | limit_period_and_buffer(&runtime->hw); | ||
177 | |||
178 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
179 | hw_rule_channels, pcm_channels, | ||
180 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
181 | if (err < 0) | ||
182 | goto end; | ||
183 | |||
184 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
185 | hw_rule_rate, pcm_channels, | ||
186 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
187 | if (err < 0) | ||
188 | goto end; | ||
189 | |||
190 | err = amdtp_stream_add_pcm_hw_constraints(s, runtime); | ||
191 | end: | ||
192 | return err; | ||
193 | } | ||
194 | |||
195 | static int pcm_open(struct snd_pcm_substream *substream) | ||
196 | { | ||
197 | struct snd_efw *efw = substream->private_data; | ||
198 | unsigned int sampling_rate; | ||
199 | enum snd_efw_clock_source clock_source; | ||
200 | int err; | ||
201 | |||
202 | err = snd_efw_stream_lock_try(efw); | ||
203 | if (err < 0) | ||
204 | goto end; | ||
205 | |||
206 | err = pcm_init_hw_params(efw, substream); | ||
207 | if (err < 0) | ||
208 | goto err_locked; | ||
209 | |||
210 | err = snd_efw_command_get_clock_source(efw, &clock_source); | ||
211 | if (err < 0) | ||
212 | goto err_locked; | ||
213 | |||
214 | /* | ||
215 | * When source of clock is not internal or any PCM streams are running, | ||
216 | * available sampling rate is limited at current sampling rate. | ||
217 | */ | ||
218 | if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) || | ||
219 | amdtp_stream_pcm_running(&efw->tx_stream) || | ||
220 | amdtp_stream_pcm_running(&efw->rx_stream)) { | ||
221 | err = snd_efw_command_get_sampling_rate(efw, &sampling_rate); | ||
222 | if (err < 0) | ||
223 | goto err_locked; | ||
224 | substream->runtime->hw.rate_min = sampling_rate; | ||
225 | substream->runtime->hw.rate_max = sampling_rate; | ||
226 | } | ||
227 | |||
228 | snd_pcm_set_sync(substream); | ||
229 | end: | ||
230 | return err; | ||
231 | err_locked: | ||
232 | snd_efw_stream_lock_release(efw); | ||
233 | return err; | ||
234 | } | ||
235 | |||
236 | static int pcm_close(struct snd_pcm_substream *substream) | ||
237 | { | ||
238 | struct snd_efw *efw = substream->private_data; | ||
239 | snd_efw_stream_lock_release(efw); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int pcm_capture_hw_params(struct snd_pcm_substream *substream, | ||
244 | struct snd_pcm_hw_params *hw_params) | ||
245 | { | ||
246 | struct snd_efw *efw = substream->private_data; | ||
247 | |||
248 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
249 | atomic_inc(&efw->capture_substreams); | ||
250 | amdtp_stream_set_pcm_format(&efw->tx_stream, params_format(hw_params)); | ||
251 | |||
252 | return snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
253 | params_buffer_bytes(hw_params)); | ||
254 | } | ||
255 | static int pcm_playback_hw_params(struct snd_pcm_substream *substream, | ||
256 | struct snd_pcm_hw_params *hw_params) | ||
257 | { | ||
258 | struct snd_efw *efw = substream->private_data; | ||
259 | |||
260 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
261 | atomic_inc(&efw->playback_substreams); | ||
262 | amdtp_stream_set_pcm_format(&efw->rx_stream, params_format(hw_params)); | ||
263 | |||
264 | return snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
265 | params_buffer_bytes(hw_params)); | ||
266 | } | ||
267 | |||
268 | static int pcm_capture_hw_free(struct snd_pcm_substream *substream) | ||
269 | { | ||
270 | struct snd_efw *efw = substream->private_data; | ||
271 | |||
272 | if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) | ||
273 | atomic_dec(&efw->capture_substreams); | ||
274 | |||
275 | snd_efw_stream_stop_duplex(efw); | ||
276 | |||
277 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
278 | } | ||
279 | static int pcm_playback_hw_free(struct snd_pcm_substream *substream) | ||
280 | { | ||
281 | struct snd_efw *efw = substream->private_data; | ||
282 | |||
283 | if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) | ||
284 | atomic_dec(&efw->playback_substreams); | ||
285 | |||
286 | snd_efw_stream_stop_duplex(efw); | ||
287 | |||
288 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
289 | } | ||
290 | |||
291 | static int pcm_capture_prepare(struct snd_pcm_substream *substream) | ||
292 | { | ||
293 | struct snd_efw *efw = substream->private_data; | ||
294 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
295 | int err; | ||
296 | |||
297 | err = snd_efw_stream_start_duplex(efw, runtime->rate); | ||
298 | if (err >= 0) | ||
299 | amdtp_stream_pcm_prepare(&efw->tx_stream); | ||
300 | |||
301 | return err; | ||
302 | } | ||
303 | static int pcm_playback_prepare(struct snd_pcm_substream *substream) | ||
304 | { | ||
305 | struct snd_efw *efw = substream->private_data; | ||
306 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
307 | int err; | ||
308 | |||
309 | err = snd_efw_stream_start_duplex(efw, runtime->rate); | ||
310 | if (err >= 0) | ||
311 | amdtp_stream_pcm_prepare(&efw->rx_stream); | ||
312 | |||
313 | return err; | ||
314 | } | ||
315 | |||
316 | static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
317 | { | ||
318 | struct snd_efw *efw = substream->private_data; | ||
319 | |||
320 | switch (cmd) { | ||
321 | case SNDRV_PCM_TRIGGER_START: | ||
322 | amdtp_stream_pcm_trigger(&efw->tx_stream, substream); | ||
323 | break; | ||
324 | case SNDRV_PCM_TRIGGER_STOP: | ||
325 | amdtp_stream_pcm_trigger(&efw->tx_stream, NULL); | ||
326 | break; | ||
327 | default: | ||
328 | return -EINVAL; | ||
329 | } | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
334 | { | ||
335 | struct snd_efw *efw = substream->private_data; | ||
336 | |||
337 | switch (cmd) { | ||
338 | case SNDRV_PCM_TRIGGER_START: | ||
339 | amdtp_stream_pcm_trigger(&efw->rx_stream, substream); | ||
340 | break; | ||
341 | case SNDRV_PCM_TRIGGER_STOP: | ||
342 | amdtp_stream_pcm_trigger(&efw->rx_stream, NULL); | ||
343 | break; | ||
344 | default: | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) | ||
352 | { | ||
353 | struct snd_efw *efw = sbstrm->private_data; | ||
354 | return amdtp_stream_pcm_pointer(&efw->tx_stream); | ||
355 | } | ||
356 | static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) | ||
357 | { | ||
358 | struct snd_efw *efw = sbstrm->private_data; | ||
359 | return amdtp_stream_pcm_pointer(&efw->rx_stream); | ||
360 | } | ||
361 | |||
362 | static const struct snd_pcm_ops pcm_capture_ops = { | ||
363 | .open = pcm_open, | ||
364 | .close = pcm_close, | ||
365 | .ioctl = snd_pcm_lib_ioctl, | ||
366 | .hw_params = pcm_capture_hw_params, | ||
367 | .hw_free = pcm_capture_hw_free, | ||
368 | .prepare = pcm_capture_prepare, | ||
369 | .trigger = pcm_capture_trigger, | ||
370 | .pointer = pcm_capture_pointer, | ||
371 | .page = snd_pcm_lib_get_vmalloc_page, | ||
372 | }; | ||
373 | |||
374 | static const struct snd_pcm_ops pcm_playback_ops = { | ||
375 | .open = pcm_open, | ||
376 | .close = pcm_close, | ||
377 | .ioctl = snd_pcm_lib_ioctl, | ||
378 | .hw_params = pcm_playback_hw_params, | ||
379 | .hw_free = pcm_playback_hw_free, | ||
380 | .prepare = pcm_playback_prepare, | ||
381 | .trigger = pcm_playback_trigger, | ||
382 | .pointer = pcm_playback_pointer, | ||
383 | .page = snd_pcm_lib_get_vmalloc_page, | ||
384 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
385 | }; | ||
386 | |||
387 | int snd_efw_create_pcm_devices(struct snd_efw *efw) | ||
388 | { | ||
389 | struct snd_pcm *pcm; | ||
390 | int err; | ||
391 | |||
392 | err = snd_pcm_new(efw->card, efw->card->driver, 0, 1, 1, &pcm); | ||
393 | if (err < 0) | ||
394 | goto end; | ||
395 | |||
396 | pcm->private_data = efw; | ||
397 | snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname); | ||
398 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops); | ||
399 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops); | ||
400 | end: | ||
401 | return err; | ||
402 | } | ||
403 | |||
diff --git a/sound/firewire/fireworks/fireworks_proc.c b/sound/firewire/fireworks/fireworks_proc.c new file mode 100644 index 000000000000..f29d4aaf56a1 --- /dev/null +++ b/sound/firewire/fireworks/fireworks_proc.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * fireworks_proc.c - a part of driver for Fireworks based devices | ||
3 | * | ||
4 | * Copyright (c) 2009-2010 Clemens Ladisch | ||
5 | * Copyright (c) 2013-2014 Takashi Sakamoto | ||
6 | * | ||
7 | * Licensed under the terms of the GNU General Public License, version 2. | ||
8 | */ | ||
9 | |||
10 | #include "./fireworks.h" | ||
11 | |||
12 | static inline const char* | ||
13 | get_phys_name(struct snd_efw_phys_grp *grp, bool input) | ||
14 | { | ||
15 | const char *const ch_type[] = { | ||
16 | "Analog", "S/PDIF", "ADAT", "S/PDIF or ADAT", "Mirroring", | ||
17 | "Headphones", "I2S", "Guitar", "Pirzo Guitar", "Guitar String", | ||
18 | }; | ||
19 | |||
20 | if (grp->type < ARRAY_SIZE(ch_type)) | ||
21 | return ch_type[grp->type]; | ||
22 | else if (input) | ||
23 | return "Input"; | ||
24 | else | ||
25 | return "Output"; | ||
26 | } | ||
27 | |||
28 | static void | ||
29 | proc_read_hwinfo(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | ||
30 | { | ||
31 | struct snd_efw *efw = entry->private_data; | ||
32 | unsigned short i; | ||
33 | struct snd_efw_hwinfo *hwinfo; | ||
34 | |||
35 | hwinfo = kmalloc(sizeof(struct snd_efw_hwinfo), GFP_KERNEL); | ||
36 | if (hwinfo == NULL) | ||
37 | return; | ||
38 | |||
39 | if (snd_efw_command_get_hwinfo(efw, hwinfo) < 0) | ||
40 | goto end; | ||
41 | |||
42 | snd_iprintf(buffer, "guid_hi: 0x%X\n", hwinfo->guid_hi); | ||
43 | snd_iprintf(buffer, "guid_lo: 0x%X\n", hwinfo->guid_lo); | ||
44 | snd_iprintf(buffer, "type: 0x%X\n", hwinfo->type); | ||
45 | snd_iprintf(buffer, "version: 0x%X\n", hwinfo->version); | ||
46 | snd_iprintf(buffer, "vendor_name: %s\n", hwinfo->vendor_name); | ||
47 | snd_iprintf(buffer, "model_name: %s\n", hwinfo->model_name); | ||
48 | |||
49 | snd_iprintf(buffer, "dsp_version: 0x%X\n", hwinfo->dsp_version); | ||
50 | snd_iprintf(buffer, "arm_version: 0x%X\n", hwinfo->arm_version); | ||
51 | snd_iprintf(buffer, "fpga_version: 0x%X\n", hwinfo->fpga_version); | ||
52 | |||
53 | snd_iprintf(buffer, "flags: 0x%X\n", hwinfo->flags); | ||
54 | |||
55 | snd_iprintf(buffer, "max_sample_rate: 0x%X\n", hwinfo->max_sample_rate); | ||
56 | snd_iprintf(buffer, "min_sample_rate: 0x%X\n", hwinfo->min_sample_rate); | ||
57 | snd_iprintf(buffer, "supported_clock: 0x%X\n", | ||
58 | hwinfo->supported_clocks); | ||
59 | |||
60 | snd_iprintf(buffer, "phys out: 0x%X\n", hwinfo->phys_out); | ||
61 | snd_iprintf(buffer, "phys in: 0x%X\n", hwinfo->phys_in); | ||
62 | |||
63 | snd_iprintf(buffer, "phys in grps: 0x%X\n", | ||
64 | hwinfo->phys_in_grp_count); | ||
65 | for (i = 0; i < hwinfo->phys_in_grp_count; i++) { | ||
66 | snd_iprintf(buffer, | ||
67 | "phys in grp[0x%d]: type 0x%d, count 0x%d\n", | ||
68 | i, hwinfo->phys_out_grps[i].type, | ||
69 | hwinfo->phys_out_grps[i].count); | ||
70 | } | ||
71 | |||
72 | snd_iprintf(buffer, "phys out grps: 0x%X\n", | ||
73 | hwinfo->phys_out_grp_count); | ||
74 | for (i = 0; i < hwinfo->phys_out_grp_count; i++) { | ||
75 | snd_iprintf(buffer, | ||
76 | "phys out grps[0x%d]: type 0x%d, count 0x%d\n", | ||
77 | i, hwinfo->phys_out_grps[i].type, | ||
78 | hwinfo->phys_out_grps[i].count); | ||
79 | } | ||
80 | |||
81 | snd_iprintf(buffer, "amdtp rx pcm channels 1x: 0x%X\n", | ||
82 | hwinfo->amdtp_rx_pcm_channels); | ||
83 | snd_iprintf(buffer, "amdtp tx pcm channels 1x: 0x%X\n", | ||
84 | hwinfo->amdtp_tx_pcm_channels); | ||
85 | snd_iprintf(buffer, "amdtp rx pcm channels 2x: 0x%X\n", | ||
86 | hwinfo->amdtp_rx_pcm_channels_2x); | ||
87 | snd_iprintf(buffer, "amdtp tx pcm channels 2x: 0x%X\n", | ||
88 | hwinfo->amdtp_tx_pcm_channels_2x); | ||
89 | snd_iprintf(buffer, "amdtp rx pcm channels 4x: 0x%X\n", | ||
90 | hwinfo->amdtp_rx_pcm_channels_4x); | ||
91 | snd_iprintf(buffer, "amdtp tx pcm channels 4x: 0x%X\n", | ||
92 | hwinfo->amdtp_tx_pcm_channels_4x); | ||
93 | |||
94 | snd_iprintf(buffer, "midi out ports: 0x%X\n", hwinfo->midi_out_ports); | ||
95 | snd_iprintf(buffer, "midi in ports: 0x%X\n", hwinfo->midi_in_ports); | ||
96 | |||
97 | snd_iprintf(buffer, "mixer playback channels: 0x%X\n", | ||
98 | hwinfo->mixer_playback_channels); | ||
99 | snd_iprintf(buffer, "mixer capture channels: 0x%X\n", | ||
100 | hwinfo->mixer_capture_channels); | ||
101 | end: | ||
102 | kfree(hwinfo); | ||
103 | } | ||
104 | |||
105 | static void | ||
106 | proc_read_clock(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | ||
107 | { | ||
108 | struct snd_efw *efw = entry->private_data; | ||
109 | enum snd_efw_clock_source clock_source; | ||
110 | unsigned int sampling_rate; | ||
111 | |||
112 | if (snd_efw_command_get_clock_source(efw, &clock_source) < 0) | ||
113 | return; | ||
114 | |||
115 | if (snd_efw_command_get_sampling_rate(efw, &sampling_rate) < 0) | ||
116 | return; | ||
117 | |||
118 | snd_iprintf(buffer, "Clock Source: %d\n", clock_source); | ||
119 | snd_iprintf(buffer, "Sampling Rate: %d\n", sampling_rate); | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * NOTE: | ||
124 | * dB = 20 * log10(linear / 0x01000000) | ||
125 | * -144.0 dB when linear is 0 | ||
126 | */ | ||
127 | static void | ||
128 | proc_read_phys_meters(struct snd_info_entry *entry, | ||
129 | struct snd_info_buffer *buffer) | ||
130 | { | ||
131 | struct snd_efw *efw = entry->private_data; | ||
132 | struct snd_efw_phys_meters *meters; | ||
133 | unsigned int g, c, m, max, size; | ||
134 | const char *name; | ||
135 | u32 *linear; | ||
136 | int err; | ||
137 | |||
138 | size = sizeof(struct snd_efw_phys_meters) + | ||
139 | (efw->phys_in + efw->phys_out) * sizeof(u32); | ||
140 | meters = kzalloc(size, GFP_KERNEL); | ||
141 | if (meters == NULL) | ||
142 | return; | ||
143 | |||
144 | err = snd_efw_command_get_phys_meters(efw, meters, size); | ||
145 | if (err < 0) | ||
146 | goto end; | ||
147 | |||
148 | snd_iprintf(buffer, "Physical Meters:\n"); | ||
149 | |||
150 | m = 0; | ||
151 | max = min(efw->phys_out, meters->out_meters); | ||
152 | linear = meters->values; | ||
153 | snd_iprintf(buffer, " %d Outputs:\n", max); | ||
154 | for (g = 0; g < efw->phys_out_grp_count; g++) { | ||
155 | name = get_phys_name(&efw->phys_out_grps[g], false); | ||
156 | for (c = 0; c < efw->phys_out_grps[g].count; c++) { | ||
157 | if (m < max) | ||
158 | snd_iprintf(buffer, "\t%s [%d]: %d\n", | ||
159 | name, c, linear[m++]); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | m = 0; | ||
164 | max = min(efw->phys_in, meters->in_meters); | ||
165 | linear = meters->values + meters->out_meters; | ||
166 | snd_iprintf(buffer, " %d Inputs:\n", max); | ||
167 | for (g = 0; g < efw->phys_in_grp_count; g++) { | ||
168 | name = get_phys_name(&efw->phys_in_grps[g], true); | ||
169 | for (c = 0; c < efw->phys_in_grps[g].count; c++) | ||
170 | if (m < max) | ||
171 | snd_iprintf(buffer, "\t%s [%d]: %d\n", | ||
172 | name, c, linear[m++]); | ||
173 | } | ||
174 | end: | ||
175 | kfree(meters); | ||
176 | } | ||
177 | |||
178 | static void | ||
179 | proc_read_queues_state(struct snd_info_entry *entry, | ||
180 | struct snd_info_buffer *buffer) | ||
181 | { | ||
182 | struct snd_efw *efw = entry->private_data; | ||
183 | unsigned int consumed; | ||
184 | |||
185 | if (efw->pull_ptr > efw->push_ptr) | ||
186 | consumed = snd_efw_resp_buf_size - | ||
187 | (unsigned int)(efw->pull_ptr - efw->push_ptr); | ||
188 | else | ||
189 | consumed = (unsigned int)(efw->push_ptr - efw->pull_ptr); | ||
190 | |||
191 | snd_iprintf(buffer, "%d %d/%d\n", | ||
192 | efw->resp_queues, consumed, snd_efw_resp_buf_size); | ||
193 | } | ||
194 | |||
195 | static void | ||
196 | add_node(struct snd_efw *efw, struct snd_info_entry *root, const char *name, | ||
197 | void (*op)(struct snd_info_entry *e, struct snd_info_buffer *b)) | ||
198 | { | ||
199 | struct snd_info_entry *entry; | ||
200 | |||
201 | entry = snd_info_create_card_entry(efw->card, name, root); | ||
202 | if (entry == NULL) | ||
203 | return; | ||
204 | |||
205 | snd_info_set_text_ops(entry, efw, op); | ||
206 | if (snd_info_register(entry) < 0) | ||
207 | snd_info_free_entry(entry); | ||
208 | } | ||
209 | |||
210 | void snd_efw_proc_init(struct snd_efw *efw) | ||
211 | { | ||
212 | struct snd_info_entry *root; | ||
213 | |||
214 | /* | ||
215 | * All nodes are automatically removed at snd_card_disconnect(), | ||
216 | * by following to link list. | ||
217 | */ | ||
218 | root = snd_info_create_card_entry(efw->card, "firewire", | ||
219 | efw->card->proc_root); | ||
220 | if (root == NULL) | ||
221 | return; | ||
222 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
223 | if (snd_info_register(root) < 0) { | ||
224 | snd_info_free_entry(root); | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | add_node(efw, root, "clock", proc_read_clock); | ||
229 | add_node(efw, root, "firmware", proc_read_hwinfo); | ||
230 | add_node(efw, root, "meters", proc_read_phys_meters); | ||
231 | add_node(efw, root, "queues", proc_read_queues_state); | ||
232 | } | ||
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c new file mode 100644 index 000000000000..541569022a7c --- /dev/null +++ b/sound/firewire/fireworks/fireworks_stream.c | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * fireworks_stream.c - a part of driver for Fireworks 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 | #include "./fireworks.h" | ||
9 | |||
10 | #define CALLBACK_TIMEOUT 100 | ||
11 | |||
12 | static int | ||
13 | init_stream(struct snd_efw *efw, struct amdtp_stream *stream) | ||
14 | { | ||
15 | struct cmp_connection *conn; | ||
16 | enum cmp_direction c_dir; | ||
17 | enum amdtp_stream_direction s_dir; | ||
18 | int err; | ||
19 | |||
20 | if (stream == &efw->tx_stream) { | ||
21 | conn = &efw->out_conn; | ||
22 | c_dir = CMP_OUTPUT; | ||
23 | s_dir = AMDTP_IN_STREAM; | ||
24 | } else { | ||
25 | conn = &efw->in_conn; | ||
26 | c_dir = CMP_INPUT; | ||
27 | s_dir = AMDTP_OUT_STREAM; | ||
28 | } | ||
29 | |||
30 | err = cmp_connection_init(conn, efw->unit, c_dir, 0); | ||
31 | if (err < 0) | ||
32 | goto end; | ||
33 | |||
34 | err = amdtp_stream_init(stream, efw->unit, s_dir, CIP_BLOCKING); | ||
35 | if (err < 0) { | ||
36 | amdtp_stream_destroy(stream); | ||
37 | cmp_connection_destroy(conn); | ||
38 | } | ||
39 | end: | ||
40 | return err; | ||
41 | } | ||
42 | |||
43 | static void | ||
44 | stop_stream(struct snd_efw *efw, struct amdtp_stream *stream) | ||
45 | { | ||
46 | amdtp_stream_pcm_abort(stream); | ||
47 | amdtp_stream_stop(stream); | ||
48 | |||
49 | if (stream == &efw->tx_stream) | ||
50 | cmp_connection_break(&efw->out_conn); | ||
51 | else | ||
52 | cmp_connection_break(&efw->in_conn); | ||
53 | } | ||
54 | |||
55 | static int | ||
56 | start_stream(struct snd_efw *efw, struct amdtp_stream *stream, | ||
57 | unsigned int sampling_rate) | ||
58 | { | ||
59 | struct cmp_connection *conn; | ||
60 | unsigned int mode, pcm_channels, midi_ports; | ||
61 | int err; | ||
62 | |||
63 | err = snd_efw_get_multiplier_mode(sampling_rate, &mode); | ||
64 | if (err < 0) | ||
65 | goto end; | ||
66 | if (stream == &efw->tx_stream) { | ||
67 | conn = &efw->out_conn; | ||
68 | pcm_channels = efw->pcm_capture_channels[mode]; | ||
69 | midi_ports = efw->midi_out_ports; | ||
70 | } else { | ||
71 | conn = &efw->in_conn; | ||
72 | pcm_channels = efw->pcm_playback_channels[mode]; | ||
73 | midi_ports = efw->midi_in_ports; | ||
74 | } | ||
75 | |||
76 | amdtp_stream_set_parameters(stream, sampling_rate, | ||
77 | pcm_channels, midi_ports); | ||
78 | |||
79 | /* establish connection via CMP */ | ||
80 | err = cmp_connection_establish(conn, | ||
81 | amdtp_stream_get_max_payload(stream)); | ||
82 | if (err < 0) | ||
83 | goto end; | ||
84 | |||
85 | /* start amdtp stream */ | ||
86 | err = amdtp_stream_start(stream, | ||
87 | conn->resources.channel, | ||
88 | conn->speed); | ||
89 | if (err < 0) { | ||
90 | stop_stream(efw, stream); | ||
91 | goto end; | ||
92 | } | ||
93 | |||
94 | /* wait first callback */ | ||
95 | if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { | ||
96 | stop_stream(efw, stream); | ||
97 | err = -ETIMEDOUT; | ||
98 | } | ||
99 | end: | ||
100 | return err; | ||
101 | } | ||
102 | |||
103 | static void | ||
104 | destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) | ||
105 | { | ||
106 | stop_stream(efw, stream); | ||
107 | |||
108 | amdtp_stream_destroy(stream); | ||
109 | |||
110 | if (stream == &efw->tx_stream) | ||
111 | cmp_connection_destroy(&efw->out_conn); | ||
112 | else | ||
113 | cmp_connection_destroy(&efw->in_conn); | ||
114 | } | ||
115 | |||
116 | static int | ||
117 | get_sync_mode(struct snd_efw *efw, enum cip_flags *sync_mode) | ||
118 | { | ||
119 | enum snd_efw_clock_source clock_source; | ||
120 | int err; | ||
121 | |||
122 | err = snd_efw_command_get_clock_source(efw, &clock_source); | ||
123 | if (err < 0) | ||
124 | return err; | ||
125 | |||
126 | if (clock_source == SND_EFW_CLOCK_SOURCE_SYTMATCH) | ||
127 | return -ENOSYS; | ||
128 | |||
129 | *sync_mode = CIP_SYNC_TO_DEVICE; | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int | ||
134 | check_connection_used_by_others(struct snd_efw *efw, struct amdtp_stream *s) | ||
135 | { | ||
136 | struct cmp_connection *conn; | ||
137 | bool used; | ||
138 | int err; | ||
139 | |||
140 | if (s == &efw->tx_stream) | ||
141 | conn = &efw->out_conn; | ||
142 | else | ||
143 | conn = &efw->in_conn; | ||
144 | |||
145 | err = cmp_connection_check_used(conn, &used); | ||
146 | if ((err >= 0) && used && !amdtp_stream_running(s)) { | ||
147 | dev_err(&efw->unit->device, | ||
148 | "Connection established by others: %cPCR[%d]\n", | ||
149 | (conn->direction == CMP_OUTPUT) ? 'o' : 'i', | ||
150 | conn->pcr_index); | ||
151 | err = -EBUSY; | ||
152 | } | ||
153 | |||
154 | return err; | ||
155 | } | ||
156 | |||
157 | int snd_efw_stream_init_duplex(struct snd_efw *efw) | ||
158 | { | ||
159 | int err; | ||
160 | |||
161 | err = init_stream(efw, &efw->tx_stream); | ||
162 | if (err < 0) | ||
163 | goto end; | ||
164 | /* Fireworks transmits NODATA packets with TAG0. */ | ||
165 | efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0; | ||
166 | /* Fireworks has its own meaning for dbc. */ | ||
167 | efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT; | ||
168 | /* Fireworks reset dbc at bus reset. */ | ||
169 | efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK; | ||
170 | /* AudioFire9 always reports wrong dbs. */ | ||
171 | if (efw->is_af9) | ||
172 | efw->tx_stream.flags |= CIP_WRONG_DBS; | ||
173 | /* Firmware version 5.5 reports fixed interval for dbc. */ | ||
174 | if (efw->firmware_version == 0x5050000) | ||
175 | efw->tx_stream.tx_dbc_interval = 8; | ||
176 | |||
177 | err = init_stream(efw, &efw->rx_stream); | ||
178 | if (err < 0) { | ||
179 | destroy_stream(efw, &efw->tx_stream); | ||
180 | goto end; | ||
181 | } | ||
182 | /* | ||
183 | * Fireworks ignores MIDI messages in more than first 8 data | ||
184 | * blocks of an received AMDTP packet. | ||
185 | */ | ||
186 | efw->rx_stream.rx_blocks_for_midi = 8; | ||
187 | |||
188 | /* set IEC61883 compliant mode (actually not fully compliant...) */ | ||
189 | err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883); | ||
190 | if (err < 0) { | ||
191 | destroy_stream(efw, &efw->tx_stream); | ||
192 | destroy_stream(efw, &efw->rx_stream); | ||
193 | } | ||
194 | end: | ||
195 | return err; | ||
196 | } | ||
197 | |||
198 | int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) | ||
199 | { | ||
200 | struct amdtp_stream *master, *slave; | ||
201 | atomic_t *slave_substreams; | ||
202 | enum cip_flags sync_mode; | ||
203 | unsigned int curr_rate; | ||
204 | int err = 0; | ||
205 | |||
206 | mutex_lock(&efw->mutex); | ||
207 | |||
208 | /* Need no substreams */ | ||
209 | if ((atomic_read(&efw->playback_substreams) == 0) && | ||
210 | (atomic_read(&efw->capture_substreams) == 0)) | ||
211 | goto end; | ||
212 | |||
213 | err = get_sync_mode(efw, &sync_mode); | ||
214 | if (err < 0) | ||
215 | goto end; | ||
216 | if (sync_mode == CIP_SYNC_TO_DEVICE) { | ||
217 | master = &efw->tx_stream; | ||
218 | slave = &efw->rx_stream; | ||
219 | slave_substreams = &efw->playback_substreams; | ||
220 | } else { | ||
221 | master = &efw->rx_stream; | ||
222 | slave = &efw->tx_stream; | ||
223 | slave_substreams = &efw->capture_substreams; | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * Considering JACK/FFADO streaming: | ||
228 | * TODO: This can be removed hwdep functionality becomes popular. | ||
229 | */ | ||
230 | err = check_connection_used_by_others(efw, master); | ||
231 | if (err < 0) | ||
232 | goto end; | ||
233 | |||
234 | /* packet queueing error */ | ||
235 | if (amdtp_streaming_error(slave)) | ||
236 | stop_stream(efw, slave); | ||
237 | if (amdtp_streaming_error(master)) | ||
238 | stop_stream(efw, master); | ||
239 | |||
240 | /* stop streams if rate is different */ | ||
241 | err = snd_efw_command_get_sampling_rate(efw, &curr_rate); | ||
242 | if (err < 0) | ||
243 | goto end; | ||
244 | if (rate == 0) | ||
245 | rate = curr_rate; | ||
246 | if (rate != curr_rate) { | ||
247 | stop_stream(efw, slave); | ||
248 | stop_stream(efw, master); | ||
249 | } | ||
250 | |||
251 | /* master should be always running */ | ||
252 | if (!amdtp_stream_running(master)) { | ||
253 | amdtp_stream_set_sync(sync_mode, master, slave); | ||
254 | efw->master = master; | ||
255 | |||
256 | err = snd_efw_command_set_sampling_rate(efw, rate); | ||
257 | if (err < 0) | ||
258 | goto end; | ||
259 | |||
260 | err = start_stream(efw, master, rate); | ||
261 | if (err < 0) { | ||
262 | dev_err(&efw->unit->device, | ||
263 | "fail to start AMDTP master stream:%d\n", err); | ||
264 | goto end; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | /* start slave if needed */ | ||
269 | if (atomic_read(slave_substreams) > 0 && !amdtp_stream_running(slave)) { | ||
270 | err = start_stream(efw, slave, rate); | ||
271 | if (err < 0) { | ||
272 | dev_err(&efw->unit->device, | ||
273 | "fail to start AMDTP slave stream:%d\n", err); | ||
274 | stop_stream(efw, master); | ||
275 | } | ||
276 | } | ||
277 | end: | ||
278 | mutex_unlock(&efw->mutex); | ||
279 | return err; | ||
280 | } | ||
281 | |||
282 | void snd_efw_stream_stop_duplex(struct snd_efw *efw) | ||
283 | { | ||
284 | struct amdtp_stream *master, *slave; | ||
285 | atomic_t *master_substreams, *slave_substreams; | ||
286 | |||
287 | mutex_lock(&efw->mutex); | ||
288 | |||
289 | if (efw->master == &efw->rx_stream) { | ||
290 | slave = &efw->tx_stream; | ||
291 | master = &efw->rx_stream; | ||
292 | slave_substreams = &efw->capture_substreams; | ||
293 | master_substreams = &efw->playback_substreams; | ||
294 | } else { | ||
295 | slave = &efw->rx_stream; | ||
296 | master = &efw->tx_stream; | ||
297 | slave_substreams = &efw->playback_substreams; | ||
298 | master_substreams = &efw->capture_substreams; | ||
299 | } | ||
300 | |||
301 | if (atomic_read(slave_substreams) == 0) { | ||
302 | stop_stream(efw, slave); | ||
303 | |||
304 | if (atomic_read(master_substreams) == 0) | ||
305 | stop_stream(efw, master); | ||
306 | } | ||
307 | |||
308 | mutex_unlock(&efw->mutex); | ||
309 | } | ||
310 | |||
311 | void snd_efw_stream_update_duplex(struct snd_efw *efw) | ||
312 | { | ||
313 | if ((cmp_connection_update(&efw->out_conn) < 0) || | ||
314 | (cmp_connection_update(&efw->in_conn) < 0)) { | ||
315 | mutex_lock(&efw->mutex); | ||
316 | stop_stream(efw, &efw->rx_stream); | ||
317 | stop_stream(efw, &efw->tx_stream); | ||
318 | mutex_unlock(&efw->mutex); | ||
319 | } else { | ||
320 | amdtp_stream_update(&efw->rx_stream); | ||
321 | amdtp_stream_update(&efw->tx_stream); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | void snd_efw_stream_destroy_duplex(struct snd_efw *efw) | ||
326 | { | ||
327 | mutex_lock(&efw->mutex); | ||
328 | |||
329 | destroy_stream(efw, &efw->rx_stream); | ||
330 | destroy_stream(efw, &efw->tx_stream); | ||
331 | |||
332 | mutex_unlock(&efw->mutex); | ||
333 | } | ||
334 | |||
335 | void snd_efw_stream_lock_changed(struct snd_efw *efw) | ||
336 | { | ||
337 | efw->dev_lock_changed = true; | ||
338 | wake_up(&efw->hwdep_wait); | ||
339 | } | ||
340 | |||
341 | int snd_efw_stream_lock_try(struct snd_efw *efw) | ||
342 | { | ||
343 | int err; | ||
344 | |||
345 | spin_lock_irq(&efw->lock); | ||
346 | |||
347 | /* user land lock this */ | ||
348 | if (efw->dev_lock_count < 0) { | ||
349 | err = -EBUSY; | ||
350 | goto end; | ||
351 | } | ||
352 | |||
353 | /* this is the first time */ | ||
354 | if (efw->dev_lock_count++ == 0) | ||
355 | snd_efw_stream_lock_changed(efw); | ||
356 | err = 0; | ||
357 | end: | ||
358 | spin_unlock_irq(&efw->lock); | ||
359 | return err; | ||
360 | } | ||
361 | |||
362 | void snd_efw_stream_lock_release(struct snd_efw *efw) | ||
363 | { | ||
364 | spin_lock_irq(&efw->lock); | ||
365 | |||
366 | if (WARN_ON(efw->dev_lock_count <= 0)) | ||
367 | goto end; | ||
368 | if (--efw->dev_lock_count == 0) | ||
369 | snd_efw_stream_lock_changed(efw); | ||
370 | end: | ||
371 | spin_unlock_irq(&efw->lock); | ||
372 | } | ||
diff --git a/sound/firewire/fireworks/fireworks_transaction.c b/sound/firewire/fireworks/fireworks_transaction.c new file mode 100644 index 000000000000..aa56b8ac537c --- /dev/null +++ b/sound/firewire/fireworks/fireworks_transaction.c | |||
@@ -0,0 +1,326 @@ | |||
1 | /* | ||
2 | * fireworks_transaction.c - a part of driver for Fireworks 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 | /* | ||
10 | * Fireworks have its own transaction. The transaction can be delivered by AV/C | ||
11 | * Vendor Specific command. But at least Windows driver and firmware version 5.5 | ||
12 | * or later don't use it. | ||
13 | * | ||
14 | * Transaction substance: | ||
15 | * At first, 6 data exist. Following to the 6 data, parameters for each | ||
16 | * commands exists. All of parameters are 32 bit alighed to big endian. | ||
17 | * data[0]: Length of transaction substance | ||
18 | * data[1]: Transaction version | ||
19 | * data[2]: Sequence number. This is incremented by the device | ||
20 | * data[3]: transaction category | ||
21 | * data[4]: transaction command | ||
22 | * data[5]: return value in response. | ||
23 | * data[6-]: parameters | ||
24 | * | ||
25 | * Transaction address: | ||
26 | * command: 0xecc000000000 | ||
27 | * response: 0xecc080000000 (default) | ||
28 | * | ||
29 | * I note that the address for response can be changed by command. But this | ||
30 | * module uses the default address. | ||
31 | */ | ||
32 | #include "./fireworks.h" | ||
33 | |||
34 | #define MEMORY_SPACE_EFW_COMMAND 0xecc000000000ULL | ||
35 | #define MEMORY_SPACE_EFW_RESPONSE 0xecc080000000ULL | ||
36 | |||
37 | #define ERROR_RETRIES 3 | ||
38 | #define ERROR_DELAY_MS 5 | ||
39 | #define EFC_TIMEOUT_MS 125 | ||
40 | |||
41 | static DEFINE_SPINLOCK(instances_lock); | ||
42 | static struct snd_efw *instances[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; | ||
43 | |||
44 | static DEFINE_SPINLOCK(transaction_queues_lock); | ||
45 | static LIST_HEAD(transaction_queues); | ||
46 | |||
47 | enum transaction_queue_state { | ||
48 | STATE_PENDING, | ||
49 | STATE_BUS_RESET, | ||
50 | STATE_COMPLETE | ||
51 | }; | ||
52 | |||
53 | struct transaction_queue { | ||
54 | struct list_head list; | ||
55 | struct fw_unit *unit; | ||
56 | void *buf; | ||
57 | unsigned int size; | ||
58 | u32 seqnum; | ||
59 | enum transaction_queue_state state; | ||
60 | wait_queue_head_t wait; | ||
61 | }; | ||
62 | |||
63 | int snd_efw_transaction_cmd(struct fw_unit *unit, | ||
64 | const void *cmd, unsigned int size) | ||
65 | { | ||
66 | return snd_fw_transaction(unit, TCODE_WRITE_BLOCK_REQUEST, | ||
67 | MEMORY_SPACE_EFW_COMMAND, | ||
68 | (void *)cmd, size, 0); | ||
69 | } | ||
70 | |||
71 | int snd_efw_transaction_run(struct fw_unit *unit, | ||
72 | const void *cmd, unsigned int cmd_size, | ||
73 | void *resp, unsigned int resp_size) | ||
74 | { | ||
75 | struct transaction_queue t; | ||
76 | unsigned int tries; | ||
77 | int ret; | ||
78 | |||
79 | t.unit = unit; | ||
80 | t.buf = resp; | ||
81 | t.size = resp_size; | ||
82 | t.seqnum = be32_to_cpu(((struct snd_efw_transaction *)cmd)->seqnum) + 1; | ||
83 | t.state = STATE_PENDING; | ||
84 | init_waitqueue_head(&t.wait); | ||
85 | |||
86 | spin_lock_irq(&transaction_queues_lock); | ||
87 | list_add_tail(&t.list, &transaction_queues); | ||
88 | spin_unlock_irq(&transaction_queues_lock); | ||
89 | |||
90 | tries = 0; | ||
91 | do { | ||
92 | ret = snd_efw_transaction_cmd(t.unit, (void *)cmd, cmd_size); | ||
93 | if (ret < 0) | ||
94 | break; | ||
95 | |||
96 | wait_event_timeout(t.wait, t.state != STATE_PENDING, | ||
97 | msecs_to_jiffies(EFC_TIMEOUT_MS)); | ||
98 | |||
99 | if (t.state == STATE_COMPLETE) { | ||
100 | ret = t.size; | ||
101 | break; | ||
102 | } else if (t.state == STATE_BUS_RESET) { | ||
103 | msleep(ERROR_DELAY_MS); | ||
104 | } else if (++tries >= ERROR_RETRIES) { | ||
105 | dev_err(&t.unit->device, "EFW transaction timed out\n"); | ||
106 | ret = -EIO; | ||
107 | break; | ||
108 | } | ||
109 | } while (1); | ||
110 | |||
111 | spin_lock_irq(&transaction_queues_lock); | ||
112 | list_del(&t.list); | ||
113 | spin_unlock_irq(&transaction_queues_lock); | ||
114 | |||
115 | return ret; | ||
116 | } | ||
117 | |||
118 | static void | ||
119 | copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode) | ||
120 | { | ||
121 | size_t capacity, till_end; | ||
122 | struct snd_efw_transaction *t; | ||
123 | |||
124 | spin_lock_irq(&efw->lock); | ||
125 | |||
126 | t = (struct snd_efw_transaction *)data; | ||
127 | length = min_t(size_t, t->length * sizeof(t->length), length); | ||
128 | |||
129 | if (efw->push_ptr < efw->pull_ptr) | ||
130 | capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr); | ||
131 | else | ||
132 | capacity = snd_efw_resp_buf_size - | ||
133 | (unsigned int)(efw->push_ptr - efw->pull_ptr); | ||
134 | |||
135 | /* confirm enough space for this response */ | ||
136 | if (capacity < length) { | ||
137 | *rcode = RCODE_CONFLICT_ERROR; | ||
138 | goto end; | ||
139 | } | ||
140 | |||
141 | /* copy to ring buffer */ | ||
142 | while (length > 0) { | ||
143 | till_end = snd_efw_resp_buf_size - | ||
144 | (unsigned int)(efw->push_ptr - efw->resp_buf); | ||
145 | till_end = min_t(unsigned int, length, till_end); | ||
146 | |||
147 | memcpy(efw->push_ptr, data, till_end); | ||
148 | |||
149 | efw->push_ptr += till_end; | ||
150 | if (efw->push_ptr >= efw->resp_buf + snd_efw_resp_buf_size) | ||
151 | efw->push_ptr = efw->resp_buf; | ||
152 | |||
153 | length -= till_end; | ||
154 | data += till_end; | ||
155 | } | ||
156 | |||
157 | /* for hwdep */ | ||
158 | efw->resp_queues++; | ||
159 | wake_up(&efw->hwdep_wait); | ||
160 | |||
161 | *rcode = RCODE_COMPLETE; | ||
162 | end: | ||
163 | spin_unlock_irq(&efw->lock); | ||
164 | } | ||
165 | |||
166 | static void | ||
167 | handle_resp_for_user(struct fw_card *card, int generation, int source, | ||
168 | void *data, size_t length, int *rcode) | ||
169 | { | ||
170 | struct fw_device *device; | ||
171 | struct snd_efw *efw; | ||
172 | unsigned int i; | ||
173 | |||
174 | spin_lock_irq(&instances_lock); | ||
175 | |||
176 | for (i = 0; i < SNDRV_CARDS; i++) { | ||
177 | efw = instances[i]; | ||
178 | if (efw == NULL) | ||
179 | continue; | ||
180 | device = fw_parent_device(efw->unit); | ||
181 | if ((device->card != card) || | ||
182 | (device->generation != generation)) | ||
183 | continue; | ||
184 | smp_rmb(); /* node id vs. generation */ | ||
185 | if (device->node_id != source) | ||
186 | continue; | ||
187 | |||
188 | break; | ||
189 | } | ||
190 | if (i == SNDRV_CARDS) | ||
191 | goto end; | ||
192 | |||
193 | copy_resp_to_buf(efw, data, length, rcode); | ||
194 | end: | ||
195 | spin_unlock_irq(&instances_lock); | ||
196 | } | ||
197 | |||
198 | static void | ||
199 | handle_resp_for_kernel(struct fw_card *card, int generation, int source, | ||
200 | void *data, size_t length, int *rcode, u32 seqnum) | ||
201 | { | ||
202 | struct fw_device *device; | ||
203 | struct transaction_queue *t; | ||
204 | unsigned long flags; | ||
205 | |||
206 | spin_lock_irqsave(&transaction_queues_lock, flags); | ||
207 | list_for_each_entry(t, &transaction_queues, list) { | ||
208 | device = fw_parent_device(t->unit); | ||
209 | if ((device->card != card) || | ||
210 | (device->generation != generation)) | ||
211 | continue; | ||
212 | smp_rmb(); /* node_id vs. generation */ | ||
213 | if (device->node_id != source) | ||
214 | continue; | ||
215 | |||
216 | if ((t->state == STATE_PENDING) && (t->seqnum == seqnum)) { | ||
217 | t->state = STATE_COMPLETE; | ||
218 | t->size = min_t(unsigned int, length, t->size); | ||
219 | memcpy(t->buf, data, t->size); | ||
220 | wake_up(&t->wait); | ||
221 | *rcode = RCODE_COMPLETE; | ||
222 | } | ||
223 | } | ||
224 | spin_unlock_irqrestore(&transaction_queues_lock, flags); | ||
225 | } | ||
226 | |||
227 | static void | ||
228 | efw_response(struct fw_card *card, struct fw_request *request, | ||
229 | int tcode, int destination, int source, | ||
230 | int generation, unsigned long long offset, | ||
231 | void *data, size_t length, void *callback_data) | ||
232 | { | ||
233 | int rcode, dummy; | ||
234 | u32 seqnum; | ||
235 | |||
236 | rcode = RCODE_TYPE_ERROR; | ||
237 | if (length < sizeof(struct snd_efw_transaction)) { | ||
238 | rcode = RCODE_DATA_ERROR; | ||
239 | goto end; | ||
240 | } else if (offset != MEMORY_SPACE_EFW_RESPONSE) { | ||
241 | rcode = RCODE_ADDRESS_ERROR; | ||
242 | goto end; | ||
243 | } | ||
244 | |||
245 | seqnum = be32_to_cpu(((struct snd_efw_transaction *)data)->seqnum); | ||
246 | if (seqnum > SND_EFW_TRANSACTION_USER_SEQNUM_MAX + 1) { | ||
247 | handle_resp_for_kernel(card, generation, source, | ||
248 | data, length, &rcode, seqnum); | ||
249 | if (snd_efw_resp_buf_debug) | ||
250 | handle_resp_for_user(card, generation, source, | ||
251 | data, length, &dummy); | ||
252 | } else { | ||
253 | handle_resp_for_user(card, generation, source, | ||
254 | data, length, &rcode); | ||
255 | } | ||
256 | end: | ||
257 | fw_send_response(card, request, rcode); | ||
258 | } | ||
259 | |||
260 | void snd_efw_transaction_add_instance(struct snd_efw *efw) | ||
261 | { | ||
262 | unsigned int i; | ||
263 | |||
264 | spin_lock_irq(&instances_lock); | ||
265 | |||
266 | for (i = 0; i < SNDRV_CARDS; i++) { | ||
267 | if (instances[i] != NULL) | ||
268 | continue; | ||
269 | instances[i] = efw; | ||
270 | break; | ||
271 | } | ||
272 | |||
273 | spin_unlock_irq(&instances_lock); | ||
274 | } | ||
275 | |||
276 | void snd_efw_transaction_remove_instance(struct snd_efw *efw) | ||
277 | { | ||
278 | unsigned int i; | ||
279 | |||
280 | spin_lock_irq(&instances_lock); | ||
281 | |||
282 | for (i = 0; i < SNDRV_CARDS; i++) { | ||
283 | if (instances[i] != efw) | ||
284 | continue; | ||
285 | instances[i] = NULL; | ||
286 | } | ||
287 | |||
288 | spin_unlock_irq(&instances_lock); | ||
289 | } | ||
290 | |||
291 | void snd_efw_transaction_bus_reset(struct fw_unit *unit) | ||
292 | { | ||
293 | struct transaction_queue *t; | ||
294 | |||
295 | spin_lock_irq(&transaction_queues_lock); | ||
296 | list_for_each_entry(t, &transaction_queues, list) { | ||
297 | if ((t->unit == unit) && | ||
298 | (t->state == STATE_PENDING)) { | ||
299 | t->state = STATE_BUS_RESET; | ||
300 | wake_up(&t->wait); | ||
301 | } | ||
302 | } | ||
303 | spin_unlock_irq(&transaction_queues_lock); | ||
304 | } | ||
305 | |||
306 | static struct fw_address_handler resp_register_handler = { | ||
307 | .length = SND_EFW_RESPONSE_MAXIMUM_BYTES, | ||
308 | .address_callback = efw_response | ||
309 | }; | ||
310 | |||
311 | int snd_efw_transaction_register(void) | ||
312 | { | ||
313 | static const struct fw_address_region resp_register_region = { | ||
314 | .start = MEMORY_SPACE_EFW_RESPONSE, | ||
315 | .end = MEMORY_SPACE_EFW_RESPONSE + | ||
316 | SND_EFW_RESPONSE_MAXIMUM_BYTES | ||
317 | }; | ||
318 | return fw_core_add_address_handler(&resp_register_handler, | ||
319 | &resp_register_region); | ||
320 | } | ||
321 | |||
322 | void snd_efw_transaction_unregister(void) | ||
323 | { | ||
324 | WARN_ON(!list_empty(&transaction_queues)); | ||
325 | fw_core_remove_address_handler(&resp_register_handler); | ||
326 | } | ||