diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/firewire | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'sound/firewire')
-rw-r--r-- | sound/firewire/Kconfig | 36 | ||||
-rw-r--r-- | sound/firewire/Makefile | 8 | ||||
-rw-r--r-- | sound/firewire/amdtp.c | 563 | ||||
-rw-r--r-- | sound/firewire/amdtp.h | 169 | ||||
-rw-r--r-- | sound/firewire/cmp.c | 307 | ||||
-rw-r--r-- | sound/firewire/cmp.h | 41 | ||||
-rw-r--r-- | sound/firewire/fcp.c | 224 | ||||
-rw-r--r-- | sound/firewire/fcp.h | 12 | ||||
-rw-r--r-- | sound/firewire/isight.c | 756 | ||||
-rw-r--r-- | sound/firewire/iso-resources.c | 231 | ||||
-rw-r--r-- | sound/firewire/iso-resources.h | 38 | ||||
-rw-r--r-- | sound/firewire/lib.c | 85 | ||||
-rw-r--r-- | sound/firewire/lib.h | 19 | ||||
-rw-r--r-- | sound/firewire/packets-buffer.c | 76 | ||||
-rw-r--r-- | sound/firewire/packets-buffer.h | 26 | ||||
-rw-r--r-- | sound/firewire/speakers.c | 857 |
16 files changed, 3448 insertions, 0 deletions
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig new file mode 100644 index 000000000000..26071489970b --- /dev/null +++ b/sound/firewire/Kconfig | |||
@@ -0,0 +1,36 @@ | |||
1 | menuconfig SND_FIREWIRE | ||
2 | bool "FireWire sound devices" | ||
3 | depends on FIREWIRE | ||
4 | default y | ||
5 | help | ||
6 | Support for IEEE-1394/FireWire/iLink sound devices. | ||
7 | |||
8 | if SND_FIREWIRE && FIREWIRE | ||
9 | |||
10 | config SND_FIREWIRE_LIB | ||
11 | tristate | ||
12 | depends on SND_PCM | ||
13 | |||
14 | config SND_FIREWIRE_SPEAKERS | ||
15 | tristate "FireWire speakers" | ||
16 | select SND_PCM | ||
17 | select SND_FIREWIRE_LIB | ||
18 | help | ||
19 | Say Y here to include support for the Griffin FireWave Surround | ||
20 | and the LaCie FireWire Speakers. | ||
21 | |||
22 | To compile this driver as a module, choose M here: the module | ||
23 | will be called snd-firewire-speakers. | ||
24 | |||
25 | config SND_ISIGHT | ||
26 | tristate "Apple iSight microphone" | ||
27 | select SND_PCM | ||
28 | select SND_FIREWIRE_LIB | ||
29 | help | ||
30 | Say Y here to include support for the front and rear microphones | ||
31 | of the Apple iSight web camera. | ||
32 | |||
33 | To compile this driver as a module, choose M here: the module | ||
34 | will be called snd-isight. | ||
35 | |||
36 | endif # SND_FIREWIRE | ||
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile new file mode 100644 index 000000000000..d71ed8935f76 --- /dev/null +++ b/sound/firewire/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ | ||
2 | fcp.o cmp.o amdtp.o | ||
3 | snd-firewire-speakers-objs := speakers.o | ||
4 | snd-isight-objs := isight.o | ||
5 | |||
6 | obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o | ||
7 | obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o | ||
8 | obj-$(CONFIG_SND_ISIGHT) += snd-isight.o | ||
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c new file mode 100644 index 000000000000..87657dd7714c --- /dev/null +++ b/sound/firewire/amdtp.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /* | ||
2 | * Audio and Music Data Transmission Protocol (IEC 61883-6) streams | ||
3 | * with Common Isochronous Packet (IEC 61883-1) headers | ||
4 | * | ||
5 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/device.h> | ||
10 | #include <linux/err.h> | ||
11 | #include <linux/firewire.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <sound/pcm.h> | ||
15 | #include "amdtp.h" | ||
16 | |||
17 | #define TICKS_PER_CYCLE 3072 | ||
18 | #define CYCLES_PER_SECOND 8000 | ||
19 | #define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND) | ||
20 | |||
21 | #define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 µs */ | ||
22 | |||
23 | #define TAG_CIP 1 | ||
24 | |||
25 | #define CIP_EOH (1u << 31) | ||
26 | #define CIP_FMT_AM (0x10 << 24) | ||
27 | #define AMDTP_FDF_AM824 (0 << 19) | ||
28 | #define AMDTP_FDF_SFC_SHIFT 16 | ||
29 | |||
30 | /* TODO: make these configurable */ | ||
31 | #define INTERRUPT_INTERVAL 16 | ||
32 | #define QUEUE_LENGTH 48 | ||
33 | |||
34 | /** | ||
35 | * amdtp_out_stream_init - initialize an AMDTP output stream structure | ||
36 | * @s: the AMDTP output stream to initialize | ||
37 | * @unit: the target of the stream | ||
38 | * @flags: the packet transmission method to use | ||
39 | */ | ||
40 | int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, | ||
41 | enum cip_out_flags flags) | ||
42 | { | ||
43 | if (flags != CIP_NONBLOCKING) | ||
44 | return -EINVAL; | ||
45 | |||
46 | s->unit = fw_unit_get(unit); | ||
47 | s->flags = flags; | ||
48 | s->context = ERR_PTR(-1); | ||
49 | mutex_init(&s->mutex); | ||
50 | s->packet_index = 0; | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | EXPORT_SYMBOL(amdtp_out_stream_init); | ||
55 | |||
56 | /** | ||
57 | * amdtp_out_stream_destroy - free stream resources | ||
58 | * @s: the AMDTP output stream to destroy | ||
59 | */ | ||
60 | void amdtp_out_stream_destroy(struct amdtp_out_stream *s) | ||
61 | { | ||
62 | WARN_ON(!IS_ERR(s->context)); | ||
63 | mutex_destroy(&s->mutex); | ||
64 | fw_unit_put(s->unit); | ||
65 | } | ||
66 | EXPORT_SYMBOL(amdtp_out_stream_destroy); | ||
67 | |||
68 | /** | ||
69 | * amdtp_out_stream_set_rate - set the sample rate | ||
70 | * @s: the AMDTP output stream to configure | ||
71 | * @rate: the sample rate | ||
72 | * | ||
73 | * The sample rate must be set before the stream is started, and must not be | ||
74 | * changed while the stream is running. | ||
75 | */ | ||
76 | void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate) | ||
77 | { | ||
78 | static const struct { | ||
79 | unsigned int rate; | ||
80 | unsigned int syt_interval; | ||
81 | } rate_info[] = { | ||
82 | [CIP_SFC_32000] = { 32000, 8, }, | ||
83 | [CIP_SFC_44100] = { 44100, 8, }, | ||
84 | [CIP_SFC_48000] = { 48000, 8, }, | ||
85 | [CIP_SFC_88200] = { 88200, 16, }, | ||
86 | [CIP_SFC_96000] = { 96000, 16, }, | ||
87 | [CIP_SFC_176400] = { 176400, 32, }, | ||
88 | [CIP_SFC_192000] = { 192000, 32, }, | ||
89 | }; | ||
90 | unsigned int sfc; | ||
91 | |||
92 | if (WARN_ON(!IS_ERR(s->context))) | ||
93 | return; | ||
94 | |||
95 | for (sfc = 0; sfc < ARRAY_SIZE(rate_info); ++sfc) | ||
96 | if (rate_info[sfc].rate == rate) { | ||
97 | s->sfc = sfc; | ||
98 | s->syt_interval = rate_info[sfc].syt_interval; | ||
99 | return; | ||
100 | } | ||
101 | WARN_ON(1); | ||
102 | } | ||
103 | EXPORT_SYMBOL(amdtp_out_stream_set_rate); | ||
104 | |||
105 | /** | ||
106 | * amdtp_out_stream_get_max_payload - get the stream's packet size | ||
107 | * @s: the AMDTP output stream | ||
108 | * | ||
109 | * This function must not be called before the stream has been configured | ||
110 | * with amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and | ||
111 | * amdtp_out_stream_set_midi(). | ||
112 | */ | ||
113 | unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s) | ||
114 | { | ||
115 | static const unsigned int max_data_blocks[] = { | ||
116 | [CIP_SFC_32000] = 4, | ||
117 | [CIP_SFC_44100] = 6, | ||
118 | [CIP_SFC_48000] = 6, | ||
119 | [CIP_SFC_88200] = 12, | ||
120 | [CIP_SFC_96000] = 12, | ||
121 | [CIP_SFC_176400] = 23, | ||
122 | [CIP_SFC_192000] = 24, | ||
123 | }; | ||
124 | |||
125 | s->data_block_quadlets = s->pcm_channels; | ||
126 | s->data_block_quadlets += DIV_ROUND_UP(s->midi_ports, 8); | ||
127 | |||
128 | return 8 + max_data_blocks[s->sfc] * 4 * s->data_block_quadlets; | ||
129 | } | ||
130 | EXPORT_SYMBOL(amdtp_out_stream_get_max_payload); | ||
131 | |||
132 | static void amdtp_write_s16(struct amdtp_out_stream *s, | ||
133 | struct snd_pcm_substream *pcm, | ||
134 | __be32 *buffer, unsigned int frames); | ||
135 | static void amdtp_write_s32(struct amdtp_out_stream *s, | ||
136 | struct snd_pcm_substream *pcm, | ||
137 | __be32 *buffer, unsigned int frames); | ||
138 | |||
139 | /** | ||
140 | * amdtp_out_stream_set_pcm_format - set the PCM format | ||
141 | * @s: the AMDTP output stream to configure | ||
142 | * @format: the format of the ALSA PCM device | ||
143 | * | ||
144 | * The sample format must be set before the stream is started, and must not be | ||
145 | * changed while the stream is running. | ||
146 | */ | ||
147 | void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, | ||
148 | snd_pcm_format_t format) | ||
149 | { | ||
150 | if (WARN_ON(!IS_ERR(s->context))) | ||
151 | return; | ||
152 | |||
153 | switch (format) { | ||
154 | default: | ||
155 | WARN_ON(1); | ||
156 | /* fall through */ | ||
157 | case SNDRV_PCM_FORMAT_S16: | ||
158 | s->transfer_samples = amdtp_write_s16; | ||
159 | break; | ||
160 | case SNDRV_PCM_FORMAT_S32: | ||
161 | s->transfer_samples = amdtp_write_s32; | ||
162 | break; | ||
163 | } | ||
164 | } | ||
165 | EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format); | ||
166 | |||
167 | static unsigned int calculate_data_blocks(struct amdtp_out_stream *s) | ||
168 | { | ||
169 | unsigned int phase, data_blocks; | ||
170 | |||
171 | if (!cip_sfc_is_base_44100(s->sfc)) { | ||
172 | /* Sample_rate / 8000 is an integer, and precomputed. */ | ||
173 | data_blocks = s->data_block_state; | ||
174 | } else { | ||
175 | phase = s->data_block_state; | ||
176 | |||
177 | /* | ||
178 | * This calculates the number of data blocks per packet so that | ||
179 | * 1) the overall rate is correct and exactly synchronized to | ||
180 | * the bus clock, and | ||
181 | * 2) packets with a rounded-up number of blocks occur as early | ||
182 | * as possible in the sequence (to prevent underruns of the | ||
183 | * device's buffer). | ||
184 | */ | ||
185 | if (s->sfc == CIP_SFC_44100) | ||
186 | /* 6 6 5 6 5 6 5 ... */ | ||
187 | data_blocks = 5 + ((phase & 1) ^ | ||
188 | (phase == 0 || phase >= 40)); | ||
189 | else | ||
190 | /* 12 11 11 11 11 ... or 23 22 22 22 22 ... */ | ||
191 | data_blocks = 11 * (s->sfc >> 1) + (phase == 0); | ||
192 | if (++phase >= (80 >> (s->sfc >> 1))) | ||
193 | phase = 0; | ||
194 | s->data_block_state = phase; | ||
195 | } | ||
196 | |||
197 | return data_blocks; | ||
198 | } | ||
199 | |||
200 | static unsigned int calculate_syt(struct amdtp_out_stream *s, | ||
201 | unsigned int cycle) | ||
202 | { | ||
203 | unsigned int syt_offset, phase, index, syt; | ||
204 | |||
205 | if (s->last_syt_offset < TICKS_PER_CYCLE) { | ||
206 | if (!cip_sfc_is_base_44100(s->sfc)) | ||
207 | syt_offset = s->last_syt_offset + s->syt_offset_state; | ||
208 | else { | ||
209 | /* | ||
210 | * The time, in ticks, of the n'th SYT_INTERVAL sample is: | ||
211 | * n * SYT_INTERVAL * 24576000 / sample_rate | ||
212 | * Modulo TICKS_PER_CYCLE, the difference between successive | ||
213 | * elements is about 1386.23. Rounding the results of this | ||
214 | * formula to the SYT precision results in a sequence of | ||
215 | * differences that begins with: | ||
216 | * 1386 1386 1387 1386 1386 1386 1387 1386 1386 1386 1387 ... | ||
217 | * This code generates _exactly_ the same sequence. | ||
218 | */ | ||
219 | phase = s->syt_offset_state; | ||
220 | index = phase % 13; | ||
221 | syt_offset = s->last_syt_offset; | ||
222 | syt_offset += 1386 + ((index && !(index & 3)) || | ||
223 | phase == 146); | ||
224 | if (++phase >= 147) | ||
225 | phase = 0; | ||
226 | s->syt_offset_state = phase; | ||
227 | } | ||
228 | } else | ||
229 | syt_offset = s->last_syt_offset - TICKS_PER_CYCLE; | ||
230 | s->last_syt_offset = syt_offset; | ||
231 | |||
232 | if (syt_offset < TICKS_PER_CYCLE) { | ||
233 | syt_offset += TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE; | ||
234 | syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12; | ||
235 | syt += syt_offset % TICKS_PER_CYCLE; | ||
236 | |||
237 | return syt & 0xffff; | ||
238 | } else { | ||
239 | return 0xffff; /* no info */ | ||
240 | } | ||
241 | } | ||
242 | |||
243 | static void amdtp_write_s32(struct amdtp_out_stream *s, | ||
244 | struct snd_pcm_substream *pcm, | ||
245 | __be32 *buffer, unsigned int frames) | ||
246 | { | ||
247 | struct snd_pcm_runtime *runtime = pcm->runtime; | ||
248 | unsigned int channels, remaining_frames, frame_step, i, c; | ||
249 | const u32 *src; | ||
250 | |||
251 | channels = s->pcm_channels; | ||
252 | src = (void *)runtime->dma_area + | ||
253 | s->pcm_buffer_pointer * (runtime->frame_bits / 8); | ||
254 | remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; | ||
255 | frame_step = s->data_block_quadlets - channels; | ||
256 | |||
257 | for (i = 0; i < frames; ++i) { | ||
258 | for (c = 0; c < channels; ++c) { | ||
259 | *buffer = cpu_to_be32((*src >> 8) | 0x40000000); | ||
260 | src++; | ||
261 | buffer++; | ||
262 | } | ||
263 | buffer += frame_step; | ||
264 | if (--remaining_frames == 0) | ||
265 | src = (void *)runtime->dma_area; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | static void amdtp_write_s16(struct amdtp_out_stream *s, | ||
270 | struct snd_pcm_substream *pcm, | ||
271 | __be32 *buffer, unsigned int frames) | ||
272 | { | ||
273 | struct snd_pcm_runtime *runtime = pcm->runtime; | ||
274 | unsigned int channels, remaining_frames, frame_step, i, c; | ||
275 | const u16 *src; | ||
276 | |||
277 | channels = s->pcm_channels; | ||
278 | src = (void *)runtime->dma_area + | ||
279 | s->pcm_buffer_pointer * (runtime->frame_bits / 8); | ||
280 | remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; | ||
281 | frame_step = s->data_block_quadlets - channels; | ||
282 | |||
283 | for (i = 0; i < frames; ++i) { | ||
284 | for (c = 0; c < channels; ++c) { | ||
285 | *buffer = cpu_to_be32((*src << 8) | 0x40000000); | ||
286 | src++; | ||
287 | buffer++; | ||
288 | } | ||
289 | buffer += frame_step; | ||
290 | if (--remaining_frames == 0) | ||
291 | src = (void *)runtime->dma_area; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | static void amdtp_fill_pcm_silence(struct amdtp_out_stream *s, | ||
296 | __be32 *buffer, unsigned int frames) | ||
297 | { | ||
298 | unsigned int i, c; | ||
299 | |||
300 | for (i = 0; i < frames; ++i) { | ||
301 | for (c = 0; c < s->pcm_channels; ++c) | ||
302 | buffer[c] = cpu_to_be32(0x40000000); | ||
303 | buffer += s->data_block_quadlets; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static void amdtp_fill_midi(struct amdtp_out_stream *s, | ||
308 | __be32 *buffer, unsigned int frames) | ||
309 | { | ||
310 | unsigned int i; | ||
311 | |||
312 | for (i = 0; i < frames; ++i) | ||
313 | buffer[s->pcm_channels + i * s->data_block_quadlets] = | ||
314 | cpu_to_be32(0x80000000); | ||
315 | } | ||
316 | |||
317 | static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) | ||
318 | { | ||
319 | __be32 *buffer; | ||
320 | unsigned int index, data_blocks, syt, ptr; | ||
321 | struct snd_pcm_substream *pcm; | ||
322 | struct fw_iso_packet packet; | ||
323 | int err; | ||
324 | |||
325 | if (s->packet_index < 0) | ||
326 | return; | ||
327 | index = s->packet_index; | ||
328 | |||
329 | data_blocks = calculate_data_blocks(s); | ||
330 | syt = calculate_syt(s, cycle); | ||
331 | |||
332 | buffer = s->buffer.packets[index].buffer; | ||
333 | buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | | ||
334 | (s->data_block_quadlets << 16) | | ||
335 | s->data_block_counter); | ||
336 | buffer[1] = cpu_to_be32(CIP_EOH | CIP_FMT_AM | AMDTP_FDF_AM824 | | ||
337 | (s->sfc << AMDTP_FDF_SFC_SHIFT) | syt); | ||
338 | buffer += 2; | ||
339 | |||
340 | pcm = ACCESS_ONCE(s->pcm); | ||
341 | if (pcm) | ||
342 | s->transfer_samples(s, pcm, buffer, data_blocks); | ||
343 | else | ||
344 | amdtp_fill_pcm_silence(s, buffer, data_blocks); | ||
345 | if (s->midi_ports) | ||
346 | amdtp_fill_midi(s, buffer, data_blocks); | ||
347 | |||
348 | s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; | ||
349 | |||
350 | packet.payload_length = 8 + data_blocks * 4 * s->data_block_quadlets; | ||
351 | packet.interrupt = IS_ALIGNED(index + 1, INTERRUPT_INTERVAL); | ||
352 | packet.skip = 0; | ||
353 | packet.tag = TAG_CIP; | ||
354 | packet.sy = 0; | ||
355 | packet.header_length = 0; | ||
356 | |||
357 | err = fw_iso_context_queue(s->context, &packet, &s->buffer.iso_buffer, | ||
358 | s->buffer.packets[index].offset); | ||
359 | if (err < 0) { | ||
360 | dev_err(&s->unit->device, "queueing error: %d\n", err); | ||
361 | s->packet_index = -1; | ||
362 | amdtp_out_stream_pcm_abort(s); | ||
363 | return; | ||
364 | } | ||
365 | |||
366 | if (++index >= QUEUE_LENGTH) | ||
367 | index = 0; | ||
368 | s->packet_index = index; | ||
369 | |||
370 | if (pcm) { | ||
371 | ptr = s->pcm_buffer_pointer + data_blocks; | ||
372 | if (ptr >= pcm->runtime->buffer_size) | ||
373 | ptr -= pcm->runtime->buffer_size; | ||
374 | ACCESS_ONCE(s->pcm_buffer_pointer) = ptr; | ||
375 | |||
376 | s->pcm_period_pointer += data_blocks; | ||
377 | if (s->pcm_period_pointer >= pcm->runtime->period_size) { | ||
378 | s->pcm_period_pointer -= pcm->runtime->period_size; | ||
379 | snd_pcm_period_elapsed(pcm); | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | |||
384 | static void out_packet_callback(struct fw_iso_context *context, u32 cycle, | ||
385 | size_t header_length, void *header, void *data) | ||
386 | { | ||
387 | struct amdtp_out_stream *s = data; | ||
388 | unsigned int i, packets = header_length / 4; | ||
389 | |||
390 | /* | ||
391 | * Compute the cycle of the last queued packet. | ||
392 | * (We need only the four lowest bits for the SYT, so we can ignore | ||
393 | * that bits 0-11 must wrap around at 3072.) | ||
394 | */ | ||
395 | cycle += QUEUE_LENGTH - packets; | ||
396 | |||
397 | for (i = 0; i < packets; ++i) | ||
398 | queue_out_packet(s, ++cycle); | ||
399 | fw_iso_context_queue_flush(s->context); | ||
400 | } | ||
401 | |||
402 | static int queue_initial_skip_packets(struct amdtp_out_stream *s) | ||
403 | { | ||
404 | struct fw_iso_packet skip_packet = { | ||
405 | .skip = 1, | ||
406 | }; | ||
407 | unsigned int i; | ||
408 | int err; | ||
409 | |||
410 | for (i = 0; i < QUEUE_LENGTH; ++i) { | ||
411 | skip_packet.interrupt = IS_ALIGNED(s->packet_index + 1, | ||
412 | INTERRUPT_INTERVAL); | ||
413 | err = fw_iso_context_queue(s->context, &skip_packet, NULL, 0); | ||
414 | if (err < 0) | ||
415 | return err; | ||
416 | if (++s->packet_index >= QUEUE_LENGTH) | ||
417 | s->packet_index = 0; | ||
418 | } | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | /** | ||
424 | * amdtp_out_stream_start - start sending packets | ||
425 | * @s: the AMDTP output stream to start | ||
426 | * @channel: the isochronous channel on the bus | ||
427 | * @speed: firewire speed code | ||
428 | * | ||
429 | * The stream cannot be started until it has been configured with | ||
430 | * amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and | ||
431 | * amdtp_out_stream_set_midi(); and it must be started before any | ||
432 | * PCM or MIDI device can be started. | ||
433 | */ | ||
434 | int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed) | ||
435 | { | ||
436 | static const struct { | ||
437 | unsigned int data_block; | ||
438 | unsigned int syt_offset; | ||
439 | } initial_state[] = { | ||
440 | [CIP_SFC_32000] = { 4, 3072 }, | ||
441 | [CIP_SFC_48000] = { 6, 1024 }, | ||
442 | [CIP_SFC_96000] = { 12, 1024 }, | ||
443 | [CIP_SFC_192000] = { 24, 1024 }, | ||
444 | [CIP_SFC_44100] = { 0, 67 }, | ||
445 | [CIP_SFC_88200] = { 0, 67 }, | ||
446 | [CIP_SFC_176400] = { 0, 67 }, | ||
447 | }; | ||
448 | int err; | ||
449 | |||
450 | mutex_lock(&s->mutex); | ||
451 | |||
452 | if (WARN_ON(!IS_ERR(s->context) || | ||
453 | (!s->pcm_channels && !s->midi_ports))) { | ||
454 | err = -EBADFD; | ||
455 | goto err_unlock; | ||
456 | } | ||
457 | |||
458 | s->data_block_state = initial_state[s->sfc].data_block; | ||
459 | s->syt_offset_state = initial_state[s->sfc].syt_offset; | ||
460 | s->last_syt_offset = TICKS_PER_CYCLE; | ||
461 | |||
462 | err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH, | ||
463 | amdtp_out_stream_get_max_payload(s), | ||
464 | DMA_TO_DEVICE); | ||
465 | if (err < 0) | ||
466 | goto err_unlock; | ||
467 | |||
468 | s->context = fw_iso_context_create(fw_parent_device(s->unit)->card, | ||
469 | FW_ISO_CONTEXT_TRANSMIT, | ||
470 | channel, speed, 0, | ||
471 | out_packet_callback, s); | ||
472 | if (IS_ERR(s->context)) { | ||
473 | err = PTR_ERR(s->context); | ||
474 | if (err == -EBUSY) | ||
475 | dev_err(&s->unit->device, | ||
476 | "no free output stream on this controller\n"); | ||
477 | goto err_buffer; | ||
478 | } | ||
479 | |||
480 | amdtp_out_stream_update(s); | ||
481 | |||
482 | s->packet_index = 0; | ||
483 | s->data_block_counter = 0; | ||
484 | err = queue_initial_skip_packets(s); | ||
485 | if (err < 0) | ||
486 | goto err_context; | ||
487 | |||
488 | err = fw_iso_context_start(s->context, -1, 0, 0); | ||
489 | if (err < 0) | ||
490 | goto err_context; | ||
491 | |||
492 | mutex_unlock(&s->mutex); | ||
493 | |||
494 | return 0; | ||
495 | |||
496 | err_context: | ||
497 | fw_iso_context_destroy(s->context); | ||
498 | s->context = ERR_PTR(-1); | ||
499 | err_buffer: | ||
500 | iso_packets_buffer_destroy(&s->buffer, s->unit); | ||
501 | err_unlock: | ||
502 | mutex_unlock(&s->mutex); | ||
503 | |||
504 | return err; | ||
505 | } | ||
506 | EXPORT_SYMBOL(amdtp_out_stream_start); | ||
507 | |||
508 | /** | ||
509 | * amdtp_out_stream_update - update the stream after a bus reset | ||
510 | * @s: the AMDTP output stream | ||
511 | */ | ||
512 | void amdtp_out_stream_update(struct amdtp_out_stream *s) | ||
513 | { | ||
514 | ACCESS_ONCE(s->source_node_id_field) = | ||
515 | (fw_parent_device(s->unit)->card->node_id & 0x3f) << 24; | ||
516 | } | ||
517 | EXPORT_SYMBOL(amdtp_out_stream_update); | ||
518 | |||
519 | /** | ||
520 | * amdtp_out_stream_stop - stop sending packets | ||
521 | * @s: the AMDTP output stream to stop | ||
522 | * | ||
523 | * All PCM and MIDI devices of the stream must be stopped before the stream | ||
524 | * itself can be stopped. | ||
525 | */ | ||
526 | void amdtp_out_stream_stop(struct amdtp_out_stream *s) | ||
527 | { | ||
528 | mutex_lock(&s->mutex); | ||
529 | |||
530 | if (IS_ERR(s->context)) { | ||
531 | mutex_unlock(&s->mutex); | ||
532 | return; | ||
533 | } | ||
534 | |||
535 | fw_iso_context_stop(s->context); | ||
536 | fw_iso_context_destroy(s->context); | ||
537 | s->context = ERR_PTR(-1); | ||
538 | iso_packets_buffer_destroy(&s->buffer, s->unit); | ||
539 | |||
540 | mutex_unlock(&s->mutex); | ||
541 | } | ||
542 | EXPORT_SYMBOL(amdtp_out_stream_stop); | ||
543 | |||
544 | /** | ||
545 | * amdtp_out_stream_pcm_abort - abort the running PCM device | ||
546 | * @s: the AMDTP stream about to be stopped | ||
547 | * | ||
548 | * If the isochronous stream needs to be stopped asynchronously, call this | ||
549 | * function first to stop the PCM device. | ||
550 | */ | ||
551 | void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s) | ||
552 | { | ||
553 | struct snd_pcm_substream *pcm; | ||
554 | |||
555 | pcm = ACCESS_ONCE(s->pcm); | ||
556 | if (pcm) { | ||
557 | snd_pcm_stream_lock_irq(pcm); | ||
558 | if (snd_pcm_running(pcm)) | ||
559 | snd_pcm_stop(pcm, SNDRV_PCM_STATE_XRUN); | ||
560 | snd_pcm_stream_unlock_irq(pcm); | ||
561 | } | ||
562 | } | ||
563 | EXPORT_SYMBOL(amdtp_out_stream_pcm_abort); | ||
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h new file mode 100644 index 000000000000..537a9cb83581 --- /dev/null +++ b/sound/firewire/amdtp.h | |||
@@ -0,0 +1,169 @@ | |||
1 | #ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED | ||
2 | #define SOUND_FIREWIRE_AMDTP_H_INCLUDED | ||
3 | |||
4 | #include <linux/mutex.h> | ||
5 | #include <linux/spinlock.h> | ||
6 | #include "packets-buffer.h" | ||
7 | |||
8 | /** | ||
9 | * enum cip_out_flags - describes details of the streaming protocol | ||
10 | * @CIP_NONBLOCKING: In non-blocking mode, each packet contains | ||
11 | * sample_rate/8000 samples, with rounding up or down to adjust | ||
12 | * for clock skew and left-over fractional samples. This should | ||
13 | * be used if supported by the device. | ||
14 | */ | ||
15 | enum cip_out_flags { | ||
16 | CIP_NONBLOCKING = 0, | ||
17 | }; | ||
18 | |||
19 | /** | ||
20 | * enum cip_sfc - a stream's sample rate | ||
21 | */ | ||
22 | enum cip_sfc { | ||
23 | CIP_SFC_32000 = 0, | ||
24 | CIP_SFC_44100 = 1, | ||
25 | CIP_SFC_48000 = 2, | ||
26 | CIP_SFC_88200 = 3, | ||
27 | CIP_SFC_96000 = 4, | ||
28 | CIP_SFC_176400 = 5, | ||
29 | CIP_SFC_192000 = 6, | ||
30 | }; | ||
31 | |||
32 | #define AMDTP_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \ | ||
33 | SNDRV_PCM_FMTBIT_S32) | ||
34 | |||
35 | struct fw_unit; | ||
36 | struct fw_iso_context; | ||
37 | struct snd_pcm_substream; | ||
38 | |||
39 | struct amdtp_out_stream { | ||
40 | struct fw_unit *unit; | ||
41 | enum cip_out_flags flags; | ||
42 | struct fw_iso_context *context; | ||
43 | struct mutex mutex; | ||
44 | |||
45 | enum cip_sfc sfc; | ||
46 | unsigned int data_block_quadlets; | ||
47 | unsigned int pcm_channels; | ||
48 | unsigned int midi_ports; | ||
49 | void (*transfer_samples)(struct amdtp_out_stream *s, | ||
50 | struct snd_pcm_substream *pcm, | ||
51 | __be32 *buffer, unsigned int frames); | ||
52 | |||
53 | unsigned int syt_interval; | ||
54 | unsigned int source_node_id_field; | ||
55 | struct iso_packets_buffer buffer; | ||
56 | |||
57 | struct snd_pcm_substream *pcm; | ||
58 | |||
59 | int packet_index; | ||
60 | unsigned int data_block_counter; | ||
61 | |||
62 | unsigned int data_block_state; | ||
63 | |||
64 | unsigned int last_syt_offset; | ||
65 | unsigned int syt_offset_state; | ||
66 | |||
67 | unsigned int pcm_buffer_pointer; | ||
68 | unsigned int pcm_period_pointer; | ||
69 | }; | ||
70 | |||
71 | int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, | ||
72 | enum cip_out_flags flags); | ||
73 | void amdtp_out_stream_destroy(struct amdtp_out_stream *s); | ||
74 | |||
75 | void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate); | ||
76 | unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s); | ||
77 | |||
78 | int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed); | ||
79 | void amdtp_out_stream_update(struct amdtp_out_stream *s); | ||
80 | void amdtp_out_stream_stop(struct amdtp_out_stream *s); | ||
81 | |||
82 | void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, | ||
83 | snd_pcm_format_t format); | ||
84 | void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s); | ||
85 | |||
86 | /** | ||
87 | * amdtp_out_stream_set_pcm - configure format of PCM samples | ||
88 | * @s: the AMDTP output stream to be configured | ||
89 | * @pcm_channels: the number of PCM samples in each data block, to be encoded | ||
90 | * as AM824 multi-bit linear audio | ||
91 | * | ||
92 | * This function must not be called while the stream is running. | ||
93 | */ | ||
94 | static inline void amdtp_out_stream_set_pcm(struct amdtp_out_stream *s, | ||
95 | unsigned int pcm_channels) | ||
96 | { | ||
97 | s->pcm_channels = pcm_channels; | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * amdtp_out_stream_set_midi - configure format of MIDI data | ||
102 | * @s: the AMDTP output stream to be configured | ||
103 | * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels) | ||
104 | * | ||
105 | * This function must not be called while the stream is running. | ||
106 | */ | ||
107 | static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s, | ||
108 | unsigned int midi_ports) | ||
109 | { | ||
110 | s->midi_ports = midi_ports; | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * amdtp_out_streaming_error - check for streaming error | ||
115 | * @s: the AMDTP output stream | ||
116 | * | ||
117 | * If this function returns true, the stream's packet queue has stopped due to | ||
118 | * an asynchronous error. | ||
119 | */ | ||
120 | static inline bool amdtp_out_streaming_error(struct amdtp_out_stream *s) | ||
121 | { | ||
122 | return s->packet_index < 0; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * amdtp_out_stream_pcm_prepare - prepare PCM device for running | ||
127 | * @s: the AMDTP output stream | ||
128 | * | ||
129 | * This function should be called from the PCM device's .prepare callback. | ||
130 | */ | ||
131 | static inline void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s) | ||
132 | { | ||
133 | s->pcm_buffer_pointer = 0; | ||
134 | s->pcm_period_pointer = 0; | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * amdtp_out_stream_pcm_trigger - start/stop playback from a PCM device | ||
139 | * @s: the AMDTP output stream | ||
140 | * @pcm: the PCM device to be started, or %NULL to stop the current device | ||
141 | * | ||
142 | * Call this function on a running isochronous stream to enable the actual | ||
143 | * transmission of PCM data. This function should be called from the PCM | ||
144 | * device's .trigger callback. | ||
145 | */ | ||
146 | static inline void amdtp_out_stream_pcm_trigger(struct amdtp_out_stream *s, | ||
147 | struct snd_pcm_substream *pcm) | ||
148 | { | ||
149 | ACCESS_ONCE(s->pcm) = pcm; | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * amdtp_out_stream_pcm_pointer - get the PCM buffer position | ||
154 | * @s: the AMDTP output stream that transports the PCM data | ||
155 | * | ||
156 | * Returns the current buffer position, in frames. | ||
157 | */ | ||
158 | static inline unsigned long | ||
159 | amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s) | ||
160 | { | ||
161 | return ACCESS_ONCE(s->pcm_buffer_pointer); | ||
162 | } | ||
163 | |||
164 | static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc) | ||
165 | { | ||
166 | return sfc & 1; | ||
167 | } | ||
168 | |||
169 | #endif | ||
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c new file mode 100644 index 000000000000..14cacbc655dd --- /dev/null +++ b/sound/firewire/cmp.c | |||
@@ -0,0 +1,307 @@ | |||
1 | /* | ||
2 | * Connection Management Procedures (IEC 61883-1) helper functions | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
6 | */ | ||
7 | |||
8 | #include <linux/device.h> | ||
9 | #include <linux/firewire.h> | ||
10 | #include <linux/firewire-constants.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include "lib.h" | ||
14 | #include "iso-resources.h" | ||
15 | #include "cmp.h" | ||
16 | |||
17 | #define IMPR_SPEED_MASK 0xc0000000 | ||
18 | #define IMPR_SPEED_SHIFT 30 | ||
19 | #define IMPR_XSPEED_MASK 0x00000060 | ||
20 | #define IMPR_XSPEED_SHIFT 5 | ||
21 | #define IMPR_PLUGS_MASK 0x0000001f | ||
22 | |||
23 | #define IPCR_ONLINE 0x80000000 | ||
24 | #define IPCR_BCAST_CONN 0x40000000 | ||
25 | #define IPCR_P2P_CONN_MASK 0x3f000000 | ||
26 | #define IPCR_P2P_CONN_SHIFT 24 | ||
27 | #define IPCR_CHANNEL_MASK 0x003f0000 | ||
28 | #define IPCR_CHANNEL_SHIFT 16 | ||
29 | |||
30 | enum bus_reset_handling { | ||
31 | ABORT_ON_BUS_RESET, | ||
32 | SUCCEED_ON_BUS_RESET, | ||
33 | }; | ||
34 | |||
35 | static __attribute__((format(printf, 2, 3))) | ||
36 | void cmp_error(struct cmp_connection *c, const char *fmt, ...) | ||
37 | { | ||
38 | va_list va; | ||
39 | |||
40 | va_start(va, fmt); | ||
41 | dev_err(&c->resources.unit->device, "%cPCR%u: %pV", | ||
42 | 'i', c->pcr_index, &(struct va_format){ fmt, &va }); | ||
43 | va_end(va); | ||
44 | } | ||
45 | |||
46 | static int pcr_modify(struct cmp_connection *c, | ||
47 | __be32 (*modify)(struct cmp_connection *c, __be32 old), | ||
48 | int (*check)(struct cmp_connection *c, __be32 pcr), | ||
49 | enum bus_reset_handling bus_reset_handling) | ||
50 | { | ||
51 | struct fw_device *device = fw_parent_device(c->resources.unit); | ||
52 | int generation = c->resources.generation; | ||
53 | int rcode, errors = 0; | ||
54 | __be32 old_arg, buffer[2]; | ||
55 | int err; | ||
56 | |||
57 | buffer[0] = c->last_pcr_value; | ||
58 | for (;;) { | ||
59 | old_arg = buffer[0]; | ||
60 | buffer[1] = modify(c, buffer[0]); | ||
61 | |||
62 | rcode = fw_run_transaction( | ||
63 | device->card, TCODE_LOCK_COMPARE_SWAP, | ||
64 | device->node_id, generation, device->max_speed, | ||
65 | CSR_REGISTER_BASE + CSR_IPCR(c->pcr_index), | ||
66 | buffer, 8); | ||
67 | |||
68 | if (rcode == RCODE_COMPLETE) { | ||
69 | if (buffer[0] == old_arg) /* success? */ | ||
70 | break; | ||
71 | |||
72 | if (check) { | ||
73 | err = check(c, buffer[0]); | ||
74 | if (err < 0) | ||
75 | return err; | ||
76 | } | ||
77 | } else if (rcode == RCODE_GENERATION) | ||
78 | goto bus_reset; | ||
79 | else if (rcode_is_permanent_error(rcode) || ++errors >= 3) | ||
80 | goto io_error; | ||
81 | } | ||
82 | c->last_pcr_value = buffer[1]; | ||
83 | |||
84 | return 0; | ||
85 | |||
86 | io_error: | ||
87 | cmp_error(c, "transaction failed: %s\n", rcode_string(rcode)); | ||
88 | return -EIO; | ||
89 | |||
90 | bus_reset: | ||
91 | return bus_reset_handling == ABORT_ON_BUS_RESET ? -EAGAIN : 0; | ||
92 | } | ||
93 | |||
94 | |||
95 | /** | ||
96 | * cmp_connection_init - initializes a connection manager | ||
97 | * @c: the connection manager to initialize | ||
98 | * @unit: a unit of the target device | ||
99 | * @ipcr_index: the index of the iPCR on the target device | ||
100 | */ | ||
101 | int cmp_connection_init(struct cmp_connection *c, | ||
102 | struct fw_unit *unit, | ||
103 | unsigned int ipcr_index) | ||
104 | { | ||
105 | __be32 impr_be; | ||
106 | u32 impr; | ||
107 | int err; | ||
108 | |||
109 | err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, | ||
110 | CSR_REGISTER_BASE + CSR_IMPR, | ||
111 | &impr_be, 4); | ||
112 | if (err < 0) | ||
113 | return err; | ||
114 | impr = be32_to_cpu(impr_be); | ||
115 | |||
116 | if (ipcr_index >= (impr & IMPR_PLUGS_MASK)) | ||
117 | return -EINVAL; | ||
118 | |||
119 | err = fw_iso_resources_init(&c->resources, unit); | ||
120 | if (err < 0) | ||
121 | return err; | ||
122 | |||
123 | c->connected = false; | ||
124 | mutex_init(&c->mutex); | ||
125 | c->last_pcr_value = cpu_to_be32(0x80000000); | ||
126 | c->pcr_index = ipcr_index; | ||
127 | c->max_speed = (impr & IMPR_SPEED_MASK) >> IMPR_SPEED_SHIFT; | ||
128 | if (c->max_speed == SCODE_BETA) | ||
129 | c->max_speed += (impr & IMPR_XSPEED_MASK) >> IMPR_XSPEED_SHIFT; | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | EXPORT_SYMBOL(cmp_connection_init); | ||
134 | |||
135 | /** | ||
136 | * cmp_connection_destroy - free connection manager resources | ||
137 | * @c: the connection manager | ||
138 | */ | ||
139 | void cmp_connection_destroy(struct cmp_connection *c) | ||
140 | { | ||
141 | WARN_ON(c->connected); | ||
142 | mutex_destroy(&c->mutex); | ||
143 | fw_iso_resources_destroy(&c->resources); | ||
144 | } | ||
145 | EXPORT_SYMBOL(cmp_connection_destroy); | ||
146 | |||
147 | |||
148 | static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr) | ||
149 | { | ||
150 | ipcr &= ~cpu_to_be32(IPCR_BCAST_CONN | | ||
151 | IPCR_P2P_CONN_MASK | | ||
152 | IPCR_CHANNEL_MASK); | ||
153 | ipcr |= cpu_to_be32(1 << IPCR_P2P_CONN_SHIFT); | ||
154 | ipcr |= cpu_to_be32(c->resources.channel << IPCR_CHANNEL_SHIFT); | ||
155 | |||
156 | return ipcr; | ||
157 | } | ||
158 | |||
159 | static int ipcr_set_check(struct cmp_connection *c, __be32 ipcr) | ||
160 | { | ||
161 | if (ipcr & cpu_to_be32(IPCR_BCAST_CONN | | ||
162 | IPCR_P2P_CONN_MASK)) { | ||
163 | cmp_error(c, "plug is already in use\n"); | ||
164 | return -EBUSY; | ||
165 | } | ||
166 | if (!(ipcr & cpu_to_be32(IPCR_ONLINE))) { | ||
167 | cmp_error(c, "plug is not on-line\n"); | ||
168 | return -ECONNREFUSED; | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * cmp_connection_establish - establish a connection to the target | ||
176 | * @c: the connection manager | ||
177 | * @max_payload_bytes: the amount of data (including CIP headers) per packet | ||
178 | * | ||
179 | * This function establishes a point-to-point connection from the local | ||
180 | * computer to the target by allocating isochronous resources (channel and | ||
181 | * bandwidth) and setting the target's input plug control register. When this | ||
182 | * function succeeds, the caller is responsible for starting transmitting | ||
183 | * packets. | ||
184 | */ | ||
185 | int cmp_connection_establish(struct cmp_connection *c, | ||
186 | unsigned int max_payload_bytes) | ||
187 | { | ||
188 | int err; | ||
189 | |||
190 | if (WARN_ON(c->connected)) | ||
191 | return -EISCONN; | ||
192 | |||
193 | c->speed = min(c->max_speed, | ||
194 | fw_parent_device(c->resources.unit)->max_speed); | ||
195 | |||
196 | mutex_lock(&c->mutex); | ||
197 | |||
198 | retry_after_bus_reset: | ||
199 | err = fw_iso_resources_allocate(&c->resources, | ||
200 | max_payload_bytes, c->speed); | ||
201 | if (err < 0) | ||
202 | goto err_mutex; | ||
203 | |||
204 | err = pcr_modify(c, ipcr_set_modify, ipcr_set_check, | ||
205 | ABORT_ON_BUS_RESET); | ||
206 | if (err == -EAGAIN) { | ||
207 | fw_iso_resources_free(&c->resources); | ||
208 | goto retry_after_bus_reset; | ||
209 | } | ||
210 | if (err < 0) | ||
211 | goto err_resources; | ||
212 | |||
213 | c->connected = true; | ||
214 | |||
215 | mutex_unlock(&c->mutex); | ||
216 | |||
217 | return 0; | ||
218 | |||
219 | err_resources: | ||
220 | fw_iso_resources_free(&c->resources); | ||
221 | err_mutex: | ||
222 | mutex_unlock(&c->mutex); | ||
223 | |||
224 | return err; | ||
225 | } | ||
226 | EXPORT_SYMBOL(cmp_connection_establish); | ||
227 | |||
228 | /** | ||
229 | * cmp_connection_update - update the connection after a bus reset | ||
230 | * @c: the connection manager | ||
231 | * | ||
232 | * This function must be called from the driver's .update handler to reestablish | ||
233 | * any connection that might have been active. | ||
234 | * | ||
235 | * Returns zero on success, or a negative error code. On an error, the | ||
236 | * connection is broken and the caller must stop transmitting iso packets. | ||
237 | */ | ||
238 | int cmp_connection_update(struct cmp_connection *c) | ||
239 | { | ||
240 | int err; | ||
241 | |||
242 | mutex_lock(&c->mutex); | ||
243 | |||
244 | if (!c->connected) { | ||
245 | mutex_unlock(&c->mutex); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | err = fw_iso_resources_update(&c->resources); | ||
250 | if (err < 0) | ||
251 | goto err_unconnect; | ||
252 | |||
253 | err = pcr_modify(c, ipcr_set_modify, ipcr_set_check, | ||
254 | SUCCEED_ON_BUS_RESET); | ||
255 | if (err < 0) | ||
256 | goto err_resources; | ||
257 | |||
258 | mutex_unlock(&c->mutex); | ||
259 | |||
260 | return 0; | ||
261 | |||
262 | err_resources: | ||
263 | fw_iso_resources_free(&c->resources); | ||
264 | err_unconnect: | ||
265 | c->connected = false; | ||
266 | mutex_unlock(&c->mutex); | ||
267 | |||
268 | return err; | ||
269 | } | ||
270 | EXPORT_SYMBOL(cmp_connection_update); | ||
271 | |||
272 | |||
273 | static __be32 ipcr_break_modify(struct cmp_connection *c, __be32 ipcr) | ||
274 | { | ||
275 | return ipcr & ~cpu_to_be32(IPCR_BCAST_CONN | IPCR_P2P_CONN_MASK); | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * cmp_connection_break - break the connection to the target | ||
280 | * @c: the connection manager | ||
281 | * | ||
282 | * This function deactives the connection in the target's input plug control | ||
283 | * register, and frees the isochronous resources of the connection. Before | ||
284 | * calling this function, the caller should cease transmitting packets. | ||
285 | */ | ||
286 | void cmp_connection_break(struct cmp_connection *c) | ||
287 | { | ||
288 | int err; | ||
289 | |||
290 | mutex_lock(&c->mutex); | ||
291 | |||
292 | if (!c->connected) { | ||
293 | mutex_unlock(&c->mutex); | ||
294 | return; | ||
295 | } | ||
296 | |||
297 | err = pcr_modify(c, ipcr_break_modify, NULL, SUCCEED_ON_BUS_RESET); | ||
298 | if (err < 0) | ||
299 | cmp_error(c, "plug is still connected\n"); | ||
300 | |||
301 | fw_iso_resources_free(&c->resources); | ||
302 | |||
303 | c->connected = false; | ||
304 | |||
305 | mutex_unlock(&c->mutex); | ||
306 | } | ||
307 | EXPORT_SYMBOL(cmp_connection_break); | ||
diff --git a/sound/firewire/cmp.h b/sound/firewire/cmp.h new file mode 100644 index 000000000000..f47de08feb12 --- /dev/null +++ b/sound/firewire/cmp.h | |||
@@ -0,0 +1,41 @@ | |||
1 | #ifndef SOUND_FIREWIRE_CMP_H_INCLUDED | ||
2 | #define SOUND_FIREWIRE_CMP_H_INCLUDED | ||
3 | |||
4 | #include <linux/mutex.h> | ||
5 | #include <linux/types.h> | ||
6 | #include "iso-resources.h" | ||
7 | |||
8 | struct fw_unit; | ||
9 | |||
10 | /** | ||
11 | * struct cmp_connection - manages an isochronous connection to a device | ||
12 | * @speed: the connection's actual speed | ||
13 | * | ||
14 | * This structure manages (using CMP) an isochronous stream from the local | ||
15 | * computer to a device's input plug (iPCR). | ||
16 | * | ||
17 | * There is no corresponding oPCR created on the local computer, so it is not | ||
18 | * possible to overlay connections on top of this one. | ||
19 | */ | ||
20 | struct cmp_connection { | ||
21 | int speed; | ||
22 | /* private: */ | ||
23 | bool connected; | ||
24 | struct mutex mutex; | ||
25 | struct fw_iso_resources resources; | ||
26 | __be32 last_pcr_value; | ||
27 | unsigned int pcr_index; | ||
28 | unsigned int max_speed; | ||
29 | }; | ||
30 | |||
31 | int cmp_connection_init(struct cmp_connection *connection, | ||
32 | struct fw_unit *unit, | ||
33 | unsigned int ipcr_index); | ||
34 | void cmp_connection_destroy(struct cmp_connection *connection); | ||
35 | |||
36 | int cmp_connection_establish(struct cmp_connection *connection, | ||
37 | unsigned int max_payload); | ||
38 | int cmp_connection_update(struct cmp_connection *connection); | ||
39 | void cmp_connection_break(struct cmp_connection *connection); | ||
40 | |||
41 | #endif | ||
diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c new file mode 100644 index 000000000000..ec578b5ad8da --- /dev/null +++ b/sound/firewire/fcp.c | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * Function Control Protocol (IEC 61883-1) helper functions | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
6 | */ | ||
7 | |||
8 | #include <linux/device.h> | ||
9 | #include <linux/firewire.h> | ||
10 | #include <linux/firewire-constants.h> | ||
11 | #include <linux/list.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/wait.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include "fcp.h" | ||
18 | #include "lib.h" | ||
19 | |||
20 | #define CTS_AVC 0x00 | ||
21 | |||
22 | #define ERROR_RETRIES 3 | ||
23 | #define ERROR_DELAY_MS 5 | ||
24 | #define FCP_TIMEOUT_MS 125 | ||
25 | |||
26 | static DEFINE_SPINLOCK(transactions_lock); | ||
27 | static LIST_HEAD(transactions); | ||
28 | |||
29 | enum fcp_state { | ||
30 | STATE_PENDING, | ||
31 | STATE_BUS_RESET, | ||
32 | STATE_COMPLETE, | ||
33 | }; | ||
34 | |||
35 | struct fcp_transaction { | ||
36 | struct list_head list; | ||
37 | struct fw_unit *unit; | ||
38 | void *response_buffer; | ||
39 | unsigned int response_size; | ||
40 | unsigned int response_match_bytes; | ||
41 | enum fcp_state state; | ||
42 | wait_queue_head_t wait; | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * fcp_avc_transaction - send an AV/C command and wait for its response | ||
47 | * @unit: a unit on the target device | ||
48 | * @command: a buffer containing the command frame; must be DMA-able | ||
49 | * @command_size: the size of @command | ||
50 | * @response: a buffer for the response frame | ||
51 | * @response_size: the maximum size of @response | ||
52 | * @response_match_bytes: a bitmap specifying the bytes used to detect the | ||
53 | * correct response frame | ||
54 | * | ||
55 | * This function sends a FCP command frame to the target and waits for the | ||
56 | * corresponding response frame to be returned. | ||
57 | * | ||
58 | * Because it is possible for multiple FCP transactions to be active at the | ||
59 | * same time, the correct response frame is detected by the value of certain | ||
60 | * bytes. These bytes must be set in @response before calling this function, | ||
61 | * and the corresponding bits must be set in @response_match_bytes. | ||
62 | * | ||
63 | * @command and @response can point to the same buffer. | ||
64 | * | ||
65 | * Asynchronous operation (INTERIM, NOTIFY) is not supported at the moment. | ||
66 | * | ||
67 | * Returns the actual size of the response frame, or a negative error code. | ||
68 | */ | ||
69 | int fcp_avc_transaction(struct fw_unit *unit, | ||
70 | const void *command, unsigned int command_size, | ||
71 | void *response, unsigned int response_size, | ||
72 | unsigned int response_match_bytes) | ||
73 | { | ||
74 | struct fcp_transaction t; | ||
75 | int tcode, ret, tries = 0; | ||
76 | |||
77 | t.unit = unit; | ||
78 | t.response_buffer = response; | ||
79 | t.response_size = response_size; | ||
80 | t.response_match_bytes = response_match_bytes; | ||
81 | t.state = STATE_PENDING; | ||
82 | init_waitqueue_head(&t.wait); | ||
83 | |||
84 | spin_lock_irq(&transactions_lock); | ||
85 | list_add_tail(&t.list, &transactions); | ||
86 | spin_unlock_irq(&transactions_lock); | ||
87 | |||
88 | for (;;) { | ||
89 | tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST | ||
90 | : TCODE_WRITE_BLOCK_REQUEST; | ||
91 | ret = snd_fw_transaction(t.unit, tcode, | ||
92 | CSR_REGISTER_BASE + CSR_FCP_COMMAND, | ||
93 | (void *)command, command_size); | ||
94 | if (ret < 0) | ||
95 | break; | ||
96 | |||
97 | wait_event_timeout(t.wait, t.state != STATE_PENDING, | ||
98 | msecs_to_jiffies(FCP_TIMEOUT_MS)); | ||
99 | |||
100 | if (t.state == STATE_COMPLETE) { | ||
101 | ret = t.response_size; | ||
102 | break; | ||
103 | } else if (t.state == STATE_BUS_RESET) { | ||
104 | msleep(ERROR_DELAY_MS); | ||
105 | } else if (++tries >= ERROR_RETRIES) { | ||
106 | dev_err(&t.unit->device, "FCP command timed out\n"); | ||
107 | ret = -EIO; | ||
108 | break; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | spin_lock_irq(&transactions_lock); | ||
113 | list_del(&t.list); | ||
114 | spin_unlock_irq(&transactions_lock); | ||
115 | |||
116 | return ret; | ||
117 | } | ||
118 | EXPORT_SYMBOL(fcp_avc_transaction); | ||
119 | |||
120 | /** | ||
121 | * fcp_bus_reset - inform the target handler about a bus reset | ||
122 | * @unit: the unit that might be used by fcp_avc_transaction() | ||
123 | * | ||
124 | * This function must be called from the driver's .update handler to inform | ||
125 | * the FCP transaction handler that a bus reset has happened. Any pending FCP | ||
126 | * transactions are retried. | ||
127 | */ | ||
128 | void fcp_bus_reset(struct fw_unit *unit) | ||
129 | { | ||
130 | struct fcp_transaction *t; | ||
131 | |||
132 | spin_lock_irq(&transactions_lock); | ||
133 | list_for_each_entry(t, &transactions, list) { | ||
134 | if (t->unit == unit && | ||
135 | t->state == STATE_PENDING) { | ||
136 | t->state = STATE_BUS_RESET; | ||
137 | wake_up(&t->wait); | ||
138 | } | ||
139 | } | ||
140 | spin_unlock_irq(&transactions_lock); | ||
141 | } | ||
142 | EXPORT_SYMBOL(fcp_bus_reset); | ||
143 | |||
144 | /* checks whether the response matches the masked bytes in response_buffer */ | ||
145 | static bool is_matching_response(struct fcp_transaction *transaction, | ||
146 | const void *response, size_t length) | ||
147 | { | ||
148 | const u8 *p1, *p2; | ||
149 | unsigned int mask, i; | ||
150 | |||
151 | p1 = response; | ||
152 | p2 = transaction->response_buffer; | ||
153 | mask = transaction->response_match_bytes; | ||
154 | |||
155 | for (i = 0; ; ++i) { | ||
156 | if ((mask & 1) && p1[i] != p2[i]) | ||
157 | return false; | ||
158 | mask >>= 1; | ||
159 | if (!mask) | ||
160 | return true; | ||
161 | if (--length == 0) | ||
162 | return false; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | static void fcp_response(struct fw_card *card, struct fw_request *request, | ||
167 | int tcode, int destination, int source, | ||
168 | int generation, unsigned long long offset, | ||
169 | void *data, size_t length, void *callback_data) | ||
170 | { | ||
171 | struct fcp_transaction *t; | ||
172 | unsigned long flags; | ||
173 | |||
174 | if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC) | ||
175 | return; | ||
176 | |||
177 | spin_lock_irqsave(&transactions_lock, flags); | ||
178 | list_for_each_entry(t, &transactions, list) { | ||
179 | struct fw_device *device = fw_parent_device(t->unit); | ||
180 | if (device->card != card || | ||
181 | device->generation != generation) | ||
182 | continue; | ||
183 | smp_rmb(); /* node_id vs. generation */ | ||
184 | if (device->node_id != source) | ||
185 | continue; | ||
186 | |||
187 | if (t->state == STATE_PENDING && | ||
188 | is_matching_response(t, data, length)) { | ||
189 | t->state = STATE_COMPLETE; | ||
190 | t->response_size = min((unsigned int)length, | ||
191 | t->response_size); | ||
192 | memcpy(t->response_buffer, data, t->response_size); | ||
193 | wake_up(&t->wait); | ||
194 | } | ||
195 | } | ||
196 | spin_unlock_irqrestore(&transactions_lock, flags); | ||
197 | } | ||
198 | |||
199 | static struct fw_address_handler response_register_handler = { | ||
200 | .length = 0x200, | ||
201 | .address_callback = fcp_response, | ||
202 | }; | ||
203 | |||
204 | static int __init fcp_module_init(void) | ||
205 | { | ||
206 | static const struct fw_address_region response_register_region = { | ||
207 | .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE, | ||
208 | .end = CSR_REGISTER_BASE + CSR_FCP_END, | ||
209 | }; | ||
210 | |||
211 | fw_core_add_address_handler(&response_register_handler, | ||
212 | &response_register_region); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static void __exit fcp_module_exit(void) | ||
218 | { | ||
219 | WARN_ON(!list_empty(&transactions)); | ||
220 | fw_core_remove_address_handler(&response_register_handler); | ||
221 | } | ||
222 | |||
223 | module_init(fcp_module_init); | ||
224 | module_exit(fcp_module_exit); | ||
diff --git a/sound/firewire/fcp.h b/sound/firewire/fcp.h new file mode 100644 index 000000000000..86595688bd91 --- /dev/null +++ b/sound/firewire/fcp.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef SOUND_FIREWIRE_FCP_H_INCLUDED | ||
2 | #define SOUND_FIREWIRE_FCP_H_INCLUDED | ||
3 | |||
4 | struct fw_unit; | ||
5 | |||
6 | int fcp_avc_transaction(struct fw_unit *unit, | ||
7 | const void *command, unsigned int command_size, | ||
8 | void *response, unsigned int response_size, | ||
9 | unsigned int response_match_bytes); | ||
10 | void fcp_bus_reset(struct fw_unit *unit); | ||
11 | |||
12 | #endif | ||
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c new file mode 100644 index 000000000000..440030818db7 --- /dev/null +++ b/sound/firewire/isight.c | |||
@@ -0,0 +1,756 @@ | |||
1 | /* | ||
2 | * Apple iSight audio driver | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
6 | */ | ||
7 | |||
8 | #include <asm/byteorder.h> | ||
9 | #include <linux/delay.h> | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/firewire.h> | ||
12 | #include <linux/firewire-constants.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/mod_devicetable.h> | ||
15 | #include <linux/mutex.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <sound/control.h> | ||
18 | #include <sound/core.h> | ||
19 | #include <sound/initval.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/tlv.h> | ||
22 | #include "lib.h" | ||
23 | #include "iso-resources.h" | ||
24 | #include "packets-buffer.h" | ||
25 | |||
26 | #define OUI_APPLE 0x000a27 | ||
27 | #define MODEL_APPLE_ISIGHT 0x000008 | ||
28 | #define SW_ISIGHT_AUDIO 0x000010 | ||
29 | |||
30 | #define REG_AUDIO_ENABLE 0x000 | ||
31 | #define AUDIO_ENABLE 0x80000000 | ||
32 | #define REG_DEF_AUDIO_GAIN 0x204 | ||
33 | #define REG_GAIN_RAW_START 0x210 | ||
34 | #define REG_GAIN_RAW_END 0x214 | ||
35 | #define REG_GAIN_DB_START 0x218 | ||
36 | #define REG_GAIN_DB_END 0x21c | ||
37 | #define REG_SAMPLE_RATE_INQUIRY 0x280 | ||
38 | #define REG_ISO_TX_CONFIG 0x300 | ||
39 | #define SPEED_SHIFT 16 | ||
40 | #define REG_SAMPLE_RATE 0x400 | ||
41 | #define RATE_48000 0x80000000 | ||
42 | #define REG_GAIN 0x500 | ||
43 | #define REG_MUTE 0x504 | ||
44 | |||
45 | #define MAX_FRAMES_PER_PACKET 475 | ||
46 | |||
47 | #define QUEUE_LENGTH 20 | ||
48 | |||
49 | struct isight { | ||
50 | struct snd_card *card; | ||
51 | struct fw_unit *unit; | ||
52 | struct fw_device *device; | ||
53 | u64 audio_base; | ||
54 | struct fw_address_handler iris_handler; | ||
55 | struct snd_pcm_substream *pcm; | ||
56 | struct mutex mutex; | ||
57 | struct iso_packets_buffer buffer; | ||
58 | struct fw_iso_resources resources; | ||
59 | struct fw_iso_context *context; | ||
60 | bool pcm_active; | ||
61 | bool pcm_running; | ||
62 | bool first_packet; | ||
63 | int packet_index; | ||
64 | u32 total_samples; | ||
65 | unsigned int buffer_pointer; | ||
66 | unsigned int period_counter; | ||
67 | s32 gain_min, gain_max; | ||
68 | unsigned int gain_tlv[4]; | ||
69 | }; | ||
70 | |||
71 | struct audio_payload { | ||
72 | __be32 sample_count; | ||
73 | __be32 signature; | ||
74 | __be32 sample_total; | ||
75 | __be32 reserved; | ||
76 | __be16 samples[2 * MAX_FRAMES_PER_PACKET]; | ||
77 | }; | ||
78 | |||
79 | MODULE_DESCRIPTION("iSight audio driver"); | ||
80 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
81 | MODULE_LICENSE("GPL v2"); | ||
82 | |||
83 | static struct fw_iso_packet audio_packet = { | ||
84 | .payload_length = sizeof(struct audio_payload), | ||
85 | .interrupt = 1, | ||
86 | .header_length = 4, | ||
87 | }; | ||
88 | |||
89 | static void isight_update_pointers(struct isight *isight, unsigned int count) | ||
90 | { | ||
91 | struct snd_pcm_runtime *runtime = isight->pcm->runtime; | ||
92 | unsigned int ptr; | ||
93 | |||
94 | smp_wmb(); /* update buffer data before buffer pointer */ | ||
95 | |||
96 | ptr = isight->buffer_pointer; | ||
97 | ptr += count; | ||
98 | if (ptr >= runtime->buffer_size) | ||
99 | ptr -= runtime->buffer_size; | ||
100 | ACCESS_ONCE(isight->buffer_pointer) = ptr; | ||
101 | |||
102 | isight->period_counter += count; | ||
103 | if (isight->period_counter >= runtime->period_size) { | ||
104 | isight->period_counter -= runtime->period_size; | ||
105 | snd_pcm_period_elapsed(isight->pcm); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static void isight_samples(struct isight *isight, | ||
110 | const __be16 *samples, unsigned int count) | ||
111 | { | ||
112 | struct snd_pcm_runtime *runtime; | ||
113 | unsigned int count1; | ||
114 | |||
115 | if (!ACCESS_ONCE(isight->pcm_running)) | ||
116 | return; | ||
117 | |||
118 | runtime = isight->pcm->runtime; | ||
119 | if (isight->buffer_pointer + count <= runtime->buffer_size) { | ||
120 | memcpy(runtime->dma_area + isight->buffer_pointer * 4, | ||
121 | samples, count * 4); | ||
122 | } else { | ||
123 | count1 = runtime->buffer_size - isight->buffer_pointer; | ||
124 | memcpy(runtime->dma_area + isight->buffer_pointer * 4, | ||
125 | samples, count1 * 4); | ||
126 | samples += count1 * 2; | ||
127 | memcpy(runtime->dma_area, samples, (count - count1) * 4); | ||
128 | } | ||
129 | |||
130 | isight_update_pointers(isight, count); | ||
131 | } | ||
132 | |||
133 | static void isight_pcm_abort(struct isight *isight) | ||
134 | { | ||
135 | unsigned long flags; | ||
136 | |||
137 | if (ACCESS_ONCE(isight->pcm_active)) { | ||
138 | snd_pcm_stream_lock_irqsave(isight->pcm, flags); | ||
139 | if (snd_pcm_running(isight->pcm)) | ||
140 | snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN); | ||
141 | snd_pcm_stream_unlock_irqrestore(isight->pcm, flags); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void isight_dropped_samples(struct isight *isight, unsigned int total) | ||
146 | { | ||
147 | struct snd_pcm_runtime *runtime; | ||
148 | u32 dropped; | ||
149 | unsigned int count1; | ||
150 | |||
151 | if (!ACCESS_ONCE(isight->pcm_running)) | ||
152 | return; | ||
153 | |||
154 | runtime = isight->pcm->runtime; | ||
155 | dropped = total - isight->total_samples; | ||
156 | if (dropped < runtime->buffer_size) { | ||
157 | if (isight->buffer_pointer + dropped <= runtime->buffer_size) { | ||
158 | memset(runtime->dma_area + isight->buffer_pointer * 4, | ||
159 | 0, dropped * 4); | ||
160 | } else { | ||
161 | count1 = runtime->buffer_size - isight->buffer_pointer; | ||
162 | memset(runtime->dma_area + isight->buffer_pointer * 4, | ||
163 | 0, count1 * 4); | ||
164 | memset(runtime->dma_area, 0, (dropped - count1) * 4); | ||
165 | } | ||
166 | isight_update_pointers(isight, dropped); | ||
167 | } else { | ||
168 | isight_pcm_abort(isight); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | static void isight_packet(struct fw_iso_context *context, u32 cycle, | ||
173 | size_t header_length, void *header, void *data) | ||
174 | { | ||
175 | struct isight *isight = data; | ||
176 | const struct audio_payload *payload; | ||
177 | unsigned int index, length, count, total; | ||
178 | int err; | ||
179 | |||
180 | if (isight->packet_index < 0) | ||
181 | return; | ||
182 | index = isight->packet_index; | ||
183 | payload = isight->buffer.packets[index].buffer; | ||
184 | length = be32_to_cpup(header) >> 16; | ||
185 | |||
186 | if (likely(length >= 16 && | ||
187 | payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) { | ||
188 | count = be32_to_cpu(payload->sample_count); | ||
189 | if (likely(count <= (length - 16) / 4)) { | ||
190 | total = be32_to_cpu(payload->sample_total); | ||
191 | if (unlikely(total != isight->total_samples)) { | ||
192 | if (!isight->first_packet) | ||
193 | isight_dropped_samples(isight, total); | ||
194 | isight->first_packet = false; | ||
195 | isight->total_samples = total; | ||
196 | } | ||
197 | |||
198 | isight_samples(isight, payload->samples, count); | ||
199 | isight->total_samples += count; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | err = fw_iso_context_queue(isight->context, &audio_packet, | ||
204 | &isight->buffer.iso_buffer, | ||
205 | isight->buffer.packets[index].offset); | ||
206 | if (err < 0) { | ||
207 | dev_err(&isight->unit->device, "queueing error: %d\n", err); | ||
208 | isight_pcm_abort(isight); | ||
209 | isight->packet_index = -1; | ||
210 | return; | ||
211 | } | ||
212 | fw_iso_context_queue_flush(isight->context); | ||
213 | |||
214 | if (++index >= QUEUE_LENGTH) | ||
215 | index = 0; | ||
216 | isight->packet_index = index; | ||
217 | } | ||
218 | |||
219 | static int isight_connect(struct isight *isight) | ||
220 | { | ||
221 | int ch, err, rcode, errors = 0; | ||
222 | __be32 value; | ||
223 | |||
224 | retry_after_bus_reset: | ||
225 | ch = fw_iso_resources_allocate(&isight->resources, | ||
226 | sizeof(struct audio_payload), | ||
227 | isight->device->max_speed); | ||
228 | if (ch < 0) { | ||
229 | err = ch; | ||
230 | goto error; | ||
231 | } | ||
232 | |||
233 | value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT)); | ||
234 | for (;;) { | ||
235 | rcode = fw_run_transaction( | ||
236 | isight->device->card, | ||
237 | TCODE_WRITE_QUADLET_REQUEST, | ||
238 | isight->device->node_id, | ||
239 | isight->resources.generation, | ||
240 | isight->device->max_speed, | ||
241 | isight->audio_base + REG_ISO_TX_CONFIG, | ||
242 | &value, 4); | ||
243 | if (rcode == RCODE_COMPLETE) { | ||
244 | return 0; | ||
245 | } else if (rcode == RCODE_GENERATION) { | ||
246 | fw_iso_resources_free(&isight->resources); | ||
247 | goto retry_after_bus_reset; | ||
248 | } else if (rcode_is_permanent_error(rcode) || ++errors >= 3) { | ||
249 | err = -EIO; | ||
250 | goto err_resources; | ||
251 | } | ||
252 | msleep(5); | ||
253 | } | ||
254 | |||
255 | err_resources: | ||
256 | fw_iso_resources_free(&isight->resources); | ||
257 | error: | ||
258 | return err; | ||
259 | } | ||
260 | |||
261 | static int isight_open(struct snd_pcm_substream *substream) | ||
262 | { | ||
263 | static const struct snd_pcm_hardware hardware = { | ||
264 | .info = SNDRV_PCM_INFO_MMAP | | ||
265 | SNDRV_PCM_INFO_MMAP_VALID | | ||
266 | SNDRV_PCM_INFO_BATCH | | ||
267 | SNDRV_PCM_INFO_INTERLEAVED | | ||
268 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | ||
269 | .formats = SNDRV_PCM_FMTBIT_S16_BE, | ||
270 | .rates = SNDRV_PCM_RATE_48000, | ||
271 | .rate_min = 48000, | ||
272 | .rate_max = 48000, | ||
273 | .channels_min = 2, | ||
274 | .channels_max = 2, | ||
275 | .buffer_bytes_max = 4 * 1024 * 1024, | ||
276 | .period_bytes_min = MAX_FRAMES_PER_PACKET * 4, | ||
277 | .period_bytes_max = 1024 * 1024, | ||
278 | .periods_min = 2, | ||
279 | .periods_max = UINT_MAX, | ||
280 | }; | ||
281 | struct isight *isight = substream->private_data; | ||
282 | |||
283 | substream->runtime->hw = hardware; | ||
284 | |||
285 | return iso_packets_buffer_init(&isight->buffer, isight->unit, | ||
286 | QUEUE_LENGTH, | ||
287 | sizeof(struct audio_payload), | ||
288 | DMA_FROM_DEVICE); | ||
289 | } | ||
290 | |||
291 | static int isight_close(struct snd_pcm_substream *substream) | ||
292 | { | ||
293 | struct isight *isight = substream->private_data; | ||
294 | |||
295 | iso_packets_buffer_destroy(&isight->buffer, isight->unit); | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int isight_hw_params(struct snd_pcm_substream *substream, | ||
301 | struct snd_pcm_hw_params *hw_params) | ||
302 | { | ||
303 | struct isight *isight = substream->private_data; | ||
304 | int err; | ||
305 | |||
306 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
307 | params_buffer_bytes(hw_params)); | ||
308 | if (err < 0) | ||
309 | return err; | ||
310 | |||
311 | ACCESS_ONCE(isight->pcm_active) = true; | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int reg_read(struct isight *isight, int offset, __be32 *value) | ||
317 | { | ||
318 | return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST, | ||
319 | isight->audio_base + offset, value, 4); | ||
320 | } | ||
321 | |||
322 | static int reg_write(struct isight *isight, int offset, __be32 value) | ||
323 | { | ||
324 | return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST, | ||
325 | isight->audio_base + offset, &value, 4); | ||
326 | } | ||
327 | |||
328 | static void isight_stop_streaming(struct isight *isight) | ||
329 | { | ||
330 | if (!isight->context) | ||
331 | return; | ||
332 | |||
333 | fw_iso_context_stop(isight->context); | ||
334 | fw_iso_context_destroy(isight->context); | ||
335 | isight->context = NULL; | ||
336 | fw_iso_resources_free(&isight->resources); | ||
337 | reg_write(isight, REG_AUDIO_ENABLE, 0); | ||
338 | } | ||
339 | |||
340 | static int isight_hw_free(struct snd_pcm_substream *substream) | ||
341 | { | ||
342 | struct isight *isight = substream->private_data; | ||
343 | |||
344 | ACCESS_ONCE(isight->pcm_active) = false; | ||
345 | |||
346 | mutex_lock(&isight->mutex); | ||
347 | isight_stop_streaming(isight); | ||
348 | mutex_unlock(&isight->mutex); | ||
349 | |||
350 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
351 | } | ||
352 | |||
353 | static int isight_start_streaming(struct isight *isight) | ||
354 | { | ||
355 | unsigned int i; | ||
356 | int err; | ||
357 | |||
358 | if (isight->context) { | ||
359 | if (isight->packet_index < 0) | ||
360 | isight_stop_streaming(isight); | ||
361 | else | ||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000)); | ||
366 | if (err < 0) | ||
367 | goto error; | ||
368 | |||
369 | err = isight_connect(isight); | ||
370 | if (err < 0) | ||
371 | goto error; | ||
372 | |||
373 | err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE)); | ||
374 | if (err < 0) | ||
375 | goto err_resources; | ||
376 | |||
377 | isight->context = fw_iso_context_create(isight->device->card, | ||
378 | FW_ISO_CONTEXT_RECEIVE, | ||
379 | isight->resources.channel, | ||
380 | isight->device->max_speed, | ||
381 | 4, isight_packet, isight); | ||
382 | if (IS_ERR(isight->context)) { | ||
383 | err = PTR_ERR(isight->context); | ||
384 | isight->context = NULL; | ||
385 | goto err_resources; | ||
386 | } | ||
387 | |||
388 | for (i = 0; i < QUEUE_LENGTH; ++i) { | ||
389 | err = fw_iso_context_queue(isight->context, &audio_packet, | ||
390 | &isight->buffer.iso_buffer, | ||
391 | isight->buffer.packets[i].offset); | ||
392 | if (err < 0) | ||
393 | goto err_context; | ||
394 | } | ||
395 | |||
396 | isight->first_packet = true; | ||
397 | isight->packet_index = 0; | ||
398 | |||
399 | err = fw_iso_context_start(isight->context, -1, 0, | ||
400 | FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/); | ||
401 | if (err < 0) | ||
402 | goto err_context; | ||
403 | |||
404 | return 0; | ||
405 | |||
406 | err_context: | ||
407 | fw_iso_context_destroy(isight->context); | ||
408 | isight->context = NULL; | ||
409 | err_resources: | ||
410 | fw_iso_resources_free(&isight->resources); | ||
411 | reg_write(isight, REG_AUDIO_ENABLE, 0); | ||
412 | error: | ||
413 | return err; | ||
414 | } | ||
415 | |||
416 | static int isight_prepare(struct snd_pcm_substream *substream) | ||
417 | { | ||
418 | struct isight *isight = substream->private_data; | ||
419 | int err; | ||
420 | |||
421 | isight->buffer_pointer = 0; | ||
422 | isight->period_counter = 0; | ||
423 | |||
424 | mutex_lock(&isight->mutex); | ||
425 | err = isight_start_streaming(isight); | ||
426 | mutex_unlock(&isight->mutex); | ||
427 | |||
428 | return err; | ||
429 | } | ||
430 | |||
431 | static int isight_trigger(struct snd_pcm_substream *substream, int cmd) | ||
432 | { | ||
433 | struct isight *isight = substream->private_data; | ||
434 | |||
435 | switch (cmd) { | ||
436 | case SNDRV_PCM_TRIGGER_START: | ||
437 | ACCESS_ONCE(isight->pcm_running) = true; | ||
438 | break; | ||
439 | case SNDRV_PCM_TRIGGER_STOP: | ||
440 | ACCESS_ONCE(isight->pcm_running) = false; | ||
441 | break; | ||
442 | default: | ||
443 | return -EINVAL; | ||
444 | } | ||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream) | ||
449 | { | ||
450 | struct isight *isight = substream->private_data; | ||
451 | |||
452 | return ACCESS_ONCE(isight->buffer_pointer); | ||
453 | } | ||
454 | |||
455 | static int isight_create_pcm(struct isight *isight) | ||
456 | { | ||
457 | static struct snd_pcm_ops ops = { | ||
458 | .open = isight_open, | ||
459 | .close = isight_close, | ||
460 | .ioctl = snd_pcm_lib_ioctl, | ||
461 | .hw_params = isight_hw_params, | ||
462 | .hw_free = isight_hw_free, | ||
463 | .prepare = isight_prepare, | ||
464 | .trigger = isight_trigger, | ||
465 | .pointer = isight_pointer, | ||
466 | .page = snd_pcm_lib_get_vmalloc_page, | ||
467 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
468 | }; | ||
469 | struct snd_pcm *pcm; | ||
470 | int err; | ||
471 | |||
472 | err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm); | ||
473 | if (err < 0) | ||
474 | return err; | ||
475 | pcm->private_data = isight; | ||
476 | strcpy(pcm->name, "iSight"); | ||
477 | isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; | ||
478 | isight->pcm->ops = &ops; | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int isight_gain_info(struct snd_kcontrol *ctl, | ||
484 | struct snd_ctl_elem_info *info) | ||
485 | { | ||
486 | struct isight *isight = ctl->private_data; | ||
487 | |||
488 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
489 | info->count = 1; | ||
490 | info->value.integer.min = isight->gain_min; | ||
491 | info->value.integer.max = isight->gain_max; | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static int isight_gain_get(struct snd_kcontrol *ctl, | ||
497 | struct snd_ctl_elem_value *value) | ||
498 | { | ||
499 | struct isight *isight = ctl->private_data; | ||
500 | __be32 gain; | ||
501 | int err; | ||
502 | |||
503 | err = reg_read(isight, REG_GAIN, &gain); | ||
504 | if (err < 0) | ||
505 | return err; | ||
506 | |||
507 | value->value.integer.value[0] = (s32)be32_to_cpu(gain); | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static int isight_gain_put(struct snd_kcontrol *ctl, | ||
513 | struct snd_ctl_elem_value *value) | ||
514 | { | ||
515 | struct isight *isight = ctl->private_data; | ||
516 | |||
517 | if (value->value.integer.value[0] < isight->gain_min || | ||
518 | value->value.integer.value[0] > isight->gain_max) | ||
519 | return -EINVAL; | ||
520 | |||
521 | return reg_write(isight, REG_GAIN, | ||
522 | cpu_to_be32(value->value.integer.value[0])); | ||
523 | } | ||
524 | |||
525 | static int isight_mute_get(struct snd_kcontrol *ctl, | ||
526 | struct snd_ctl_elem_value *value) | ||
527 | { | ||
528 | struct isight *isight = ctl->private_data; | ||
529 | __be32 mute; | ||
530 | int err; | ||
531 | |||
532 | err = reg_read(isight, REG_MUTE, &mute); | ||
533 | if (err < 0) | ||
534 | return err; | ||
535 | |||
536 | value->value.integer.value[0] = !mute; | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int isight_mute_put(struct snd_kcontrol *ctl, | ||
542 | struct snd_ctl_elem_value *value) | ||
543 | { | ||
544 | struct isight *isight = ctl->private_data; | ||
545 | |||
546 | return reg_write(isight, REG_MUTE, | ||
547 | (__force __be32)!value->value.integer.value[0]); | ||
548 | } | ||
549 | |||
550 | static int isight_create_mixer(struct isight *isight) | ||
551 | { | ||
552 | static const struct snd_kcontrol_new gain_control = { | ||
553 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
554 | .name = "Mic Capture Volume", | ||
555 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
556 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
557 | .info = isight_gain_info, | ||
558 | .get = isight_gain_get, | ||
559 | .put = isight_gain_put, | ||
560 | }; | ||
561 | static const struct snd_kcontrol_new mute_control = { | ||
562 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
563 | .name = "Mic Capture Switch", | ||
564 | .info = snd_ctl_boolean_mono_info, | ||
565 | .get = isight_mute_get, | ||
566 | .put = isight_mute_put, | ||
567 | }; | ||
568 | __be32 value; | ||
569 | struct snd_kcontrol *ctl; | ||
570 | int err; | ||
571 | |||
572 | err = reg_read(isight, REG_GAIN_RAW_START, &value); | ||
573 | if (err < 0) | ||
574 | return err; | ||
575 | isight->gain_min = be32_to_cpu(value); | ||
576 | |||
577 | err = reg_read(isight, REG_GAIN_RAW_END, &value); | ||
578 | if (err < 0) | ||
579 | return err; | ||
580 | isight->gain_max = be32_to_cpu(value); | ||
581 | |||
582 | isight->gain_tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX; | ||
583 | isight->gain_tlv[1] = 2 * sizeof(unsigned int); | ||
584 | |||
585 | err = reg_read(isight, REG_GAIN_DB_START, &value); | ||
586 | if (err < 0) | ||
587 | return err; | ||
588 | isight->gain_tlv[2] = (s32)be32_to_cpu(value) * 100; | ||
589 | |||
590 | err = reg_read(isight, REG_GAIN_DB_END, &value); | ||
591 | if (err < 0) | ||
592 | return err; | ||
593 | isight->gain_tlv[3] = (s32)be32_to_cpu(value) * 100; | ||
594 | |||
595 | ctl = snd_ctl_new1(&gain_control, isight); | ||
596 | if (ctl) | ||
597 | ctl->tlv.p = isight->gain_tlv; | ||
598 | err = snd_ctl_add(isight->card, ctl); | ||
599 | if (err < 0) | ||
600 | return err; | ||
601 | |||
602 | err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight)); | ||
603 | if (err < 0) | ||
604 | return err; | ||
605 | |||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | static void isight_card_free(struct snd_card *card) | ||
610 | { | ||
611 | struct isight *isight = card->private_data; | ||
612 | |||
613 | fw_iso_resources_destroy(&isight->resources); | ||
614 | fw_unit_put(isight->unit); | ||
615 | fw_device_put(isight->device); | ||
616 | mutex_destroy(&isight->mutex); | ||
617 | } | ||
618 | |||
619 | static u64 get_unit_base(struct fw_unit *unit) | ||
620 | { | ||
621 | struct fw_csr_iterator i; | ||
622 | int key, value; | ||
623 | |||
624 | fw_csr_iterator_init(&i, unit->directory); | ||
625 | while (fw_csr_iterator_next(&i, &key, &value)) | ||
626 | if (key == CSR_OFFSET) | ||
627 | return CSR_REGISTER_BASE + value * 4; | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static int isight_probe(struct device *unit_dev) | ||
632 | { | ||
633 | struct fw_unit *unit = fw_unit(unit_dev); | ||
634 | struct fw_device *fw_dev = fw_parent_device(unit); | ||
635 | struct snd_card *card; | ||
636 | struct isight *isight; | ||
637 | int err; | ||
638 | |||
639 | err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card); | ||
640 | if (err < 0) | ||
641 | return err; | ||
642 | snd_card_set_dev(card, unit_dev); | ||
643 | |||
644 | isight = card->private_data; | ||
645 | isight->card = card; | ||
646 | mutex_init(&isight->mutex); | ||
647 | isight->unit = fw_unit_get(unit); | ||
648 | isight->device = fw_device_get(fw_dev); | ||
649 | isight->audio_base = get_unit_base(unit); | ||
650 | if (!isight->audio_base) { | ||
651 | dev_err(&unit->device, "audio unit base not found\n"); | ||
652 | err = -ENXIO; | ||
653 | goto err_unit; | ||
654 | } | ||
655 | fw_iso_resources_init(&isight->resources, unit); | ||
656 | |||
657 | card->private_free = isight_card_free; | ||
658 | |||
659 | strcpy(card->driver, "iSight"); | ||
660 | strcpy(card->shortname, "Apple iSight"); | ||
661 | snprintf(card->longname, sizeof(card->longname), | ||
662 | "Apple iSight (GUID %08x%08x) at %s, S%d", | ||
663 | fw_dev->config_rom[3], fw_dev->config_rom[4], | ||
664 | dev_name(&unit->device), 100 << fw_dev->max_speed); | ||
665 | strcpy(card->mixername, "iSight"); | ||
666 | |||
667 | err = isight_create_pcm(isight); | ||
668 | if (err < 0) | ||
669 | goto error; | ||
670 | |||
671 | err = isight_create_mixer(isight); | ||
672 | if (err < 0) | ||
673 | goto error; | ||
674 | |||
675 | err = snd_card_register(card); | ||
676 | if (err < 0) | ||
677 | goto error; | ||
678 | |||
679 | dev_set_drvdata(unit_dev, isight); | ||
680 | |||
681 | return 0; | ||
682 | |||
683 | err_unit: | ||
684 | fw_unit_put(isight->unit); | ||
685 | fw_device_put(isight->device); | ||
686 | mutex_destroy(&isight->mutex); | ||
687 | error: | ||
688 | snd_card_free(card); | ||
689 | return err; | ||
690 | } | ||
691 | |||
692 | static int isight_remove(struct device *dev) | ||
693 | { | ||
694 | struct isight *isight = dev_get_drvdata(dev); | ||
695 | |||
696 | isight_pcm_abort(isight); | ||
697 | |||
698 | snd_card_disconnect(isight->card); | ||
699 | |||
700 | mutex_lock(&isight->mutex); | ||
701 | isight_stop_streaming(isight); | ||
702 | mutex_unlock(&isight->mutex); | ||
703 | |||
704 | snd_card_free_when_closed(isight->card); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static void isight_bus_reset(struct fw_unit *unit) | ||
710 | { | ||
711 | struct isight *isight = dev_get_drvdata(&unit->device); | ||
712 | |||
713 | if (fw_iso_resources_update(&isight->resources) < 0) { | ||
714 | isight_pcm_abort(isight); | ||
715 | |||
716 | mutex_lock(&isight->mutex); | ||
717 | isight_stop_streaming(isight); | ||
718 | mutex_unlock(&isight->mutex); | ||
719 | } | ||
720 | } | ||
721 | |||
722 | static const struct ieee1394_device_id isight_id_table[] = { | ||
723 | { | ||
724 | .match_flags = IEEE1394_MATCH_SPECIFIER_ID | | ||
725 | IEEE1394_MATCH_VERSION, | ||
726 | .specifier_id = OUI_APPLE, | ||
727 | .version = SW_ISIGHT_AUDIO, | ||
728 | }, | ||
729 | { } | ||
730 | }; | ||
731 | MODULE_DEVICE_TABLE(ieee1394, isight_id_table); | ||
732 | |||
733 | static struct fw_driver isight_driver = { | ||
734 | .driver = { | ||
735 | .owner = THIS_MODULE, | ||
736 | .name = KBUILD_MODNAME, | ||
737 | .bus = &fw_bus_type, | ||
738 | .probe = isight_probe, | ||
739 | .remove = isight_remove, | ||
740 | }, | ||
741 | .update = isight_bus_reset, | ||
742 | .id_table = isight_id_table, | ||
743 | }; | ||
744 | |||
745 | static int __init alsa_isight_init(void) | ||
746 | { | ||
747 | return driver_register(&isight_driver.driver); | ||
748 | } | ||
749 | |||
750 | static void __exit alsa_isight_exit(void) | ||
751 | { | ||
752 | driver_unregister(&isight_driver.driver); | ||
753 | } | ||
754 | |||
755 | module_init(alsa_isight_init); | ||
756 | module_exit(alsa_isight_exit); | ||
diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c new file mode 100644 index 000000000000..ffe20b877e9f --- /dev/null +++ b/sound/firewire/iso-resources.c | |||
@@ -0,0 +1,231 @@ | |||
1 | /* | ||
2 | * isochronous resources helper functions | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
6 | */ | ||
7 | |||
8 | #include <linux/device.h> | ||
9 | #include <linux/firewire.h> | ||
10 | #include <linux/firewire-constants.h> | ||
11 | #include <linux/jiffies.h> | ||
12 | #include <linux/mutex.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include "iso-resources.h" | ||
16 | |||
17 | /** | ||
18 | * fw_iso_resources_init - initializes a &struct fw_iso_resources | ||
19 | * @r: the resource manager to initialize | ||
20 | * @unit: the device unit for which the resources will be needed | ||
21 | * | ||
22 | * If the device does not support all channel numbers, change @r->channels_mask | ||
23 | * after calling this function. | ||
24 | */ | ||
25 | int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) | ||
26 | { | ||
27 | r->channels_mask = ~0uLL; | ||
28 | r->unit = fw_unit_get(unit); | ||
29 | mutex_init(&r->mutex); | ||
30 | r->allocated = false; | ||
31 | |||
32 | return 0; | ||
33 | } | ||
34 | EXPORT_SYMBOL(fw_iso_resources_init); | ||
35 | |||
36 | /** | ||
37 | * fw_iso_resources_destroy - destroy a resource manager | ||
38 | * @r: the resource manager that is no longer needed | ||
39 | */ | ||
40 | void fw_iso_resources_destroy(struct fw_iso_resources *r) | ||
41 | { | ||
42 | WARN_ON(r->allocated); | ||
43 | mutex_destroy(&r->mutex); | ||
44 | fw_unit_put(r->unit); | ||
45 | } | ||
46 | EXPORT_SYMBOL(fw_iso_resources_destroy); | ||
47 | |||
48 | static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed) | ||
49 | { | ||
50 | unsigned int bytes, s400_bytes; | ||
51 | |||
52 | /* iso packets have three header quadlets and quadlet-aligned payload */ | ||
53 | bytes = 3 * 4 + ALIGN(max_payload_bytes, 4); | ||
54 | |||
55 | /* convert to bandwidth units (quadlets at S1600 = bytes at S400) */ | ||
56 | if (speed <= SCODE_400) | ||
57 | s400_bytes = bytes * (1 << (SCODE_400 - speed)); | ||
58 | else | ||
59 | s400_bytes = DIV_ROUND_UP(bytes, 1 << (speed - SCODE_400)); | ||
60 | |||
61 | return s400_bytes; | ||
62 | } | ||
63 | |||
64 | static int current_bandwidth_overhead(struct fw_card *card) | ||
65 | { | ||
66 | /* | ||
67 | * Under the usual pessimistic assumption (cable length 4.5 m), the | ||
68 | * isochronous overhead for N cables is 1.797 µs + N * 0.494 µs, or | ||
69 | * 88.3 + N * 24.3 in bandwidth units. | ||
70 | * | ||
71 | * The calculation below tries to deduce N from the current gap count. | ||
72 | * If the gap count has been optimized by measuring the actual packet | ||
73 | * transmission time, this derived overhead should be near the actual | ||
74 | * overhead as well. | ||
75 | */ | ||
76 | return card->gap_count < 63 ? card->gap_count * 97 / 10 + 89 : 512; | ||
77 | } | ||
78 | |||
79 | static int wait_isoch_resource_delay_after_bus_reset(struct fw_card *card) | ||
80 | { | ||
81 | for (;;) { | ||
82 | s64 delay = (card->reset_jiffies + HZ) - get_jiffies_64(); | ||
83 | if (delay <= 0) | ||
84 | return 0; | ||
85 | if (schedule_timeout_interruptible(delay) > 0) | ||
86 | return -ERESTARTSYS; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * fw_iso_resources_allocate - allocate isochronous channel and bandwidth | ||
92 | * @r: the resource manager | ||
93 | * @max_payload_bytes: the amount of data (including CIP headers) per packet | ||
94 | * @speed: the speed (e.g., SCODE_400) at which the packets will be sent | ||
95 | * | ||
96 | * This function allocates one isochronous channel and enough bandwidth for the | ||
97 | * specified packet size. | ||
98 | * | ||
99 | * Returns the channel number that the caller must use for streaming, or | ||
100 | * a negative error code. Due to potentionally long delays, this function is | ||
101 | * interruptible and can return -ERESTARTSYS. On success, the caller is | ||
102 | * responsible for calling fw_iso_resources_update() on bus resets, and | ||
103 | * fw_iso_resources_free() when the resources are not longer needed. | ||
104 | */ | ||
105 | int fw_iso_resources_allocate(struct fw_iso_resources *r, | ||
106 | unsigned int max_payload_bytes, int speed) | ||
107 | { | ||
108 | struct fw_card *card = fw_parent_device(r->unit)->card; | ||
109 | int bandwidth, channel, err; | ||
110 | |||
111 | if (WARN_ON(r->allocated)) | ||
112 | return -EBADFD; | ||
113 | |||
114 | r->bandwidth = packet_bandwidth(max_payload_bytes, speed); | ||
115 | |||
116 | retry_after_bus_reset: | ||
117 | spin_lock_irq(&card->lock); | ||
118 | r->generation = card->generation; | ||
119 | r->bandwidth_overhead = current_bandwidth_overhead(card); | ||
120 | spin_unlock_irq(&card->lock); | ||
121 | |||
122 | err = wait_isoch_resource_delay_after_bus_reset(card); | ||
123 | if (err < 0) | ||
124 | return err; | ||
125 | |||
126 | mutex_lock(&r->mutex); | ||
127 | |||
128 | bandwidth = r->bandwidth + r->bandwidth_overhead; | ||
129 | fw_iso_resource_manage(card, r->generation, r->channels_mask, | ||
130 | &channel, &bandwidth, true); | ||
131 | if (channel == -EAGAIN) { | ||
132 | mutex_unlock(&r->mutex); | ||
133 | goto retry_after_bus_reset; | ||
134 | } | ||
135 | if (channel >= 0) { | ||
136 | r->channel = channel; | ||
137 | r->allocated = true; | ||
138 | } else { | ||
139 | if (channel == -EBUSY) | ||
140 | dev_err(&r->unit->device, | ||
141 | "isochronous resources exhausted\n"); | ||
142 | else | ||
143 | dev_err(&r->unit->device, | ||
144 | "isochronous resource allocation failed\n"); | ||
145 | } | ||
146 | |||
147 | mutex_unlock(&r->mutex); | ||
148 | |||
149 | return channel; | ||
150 | } | ||
151 | EXPORT_SYMBOL(fw_iso_resources_allocate); | ||
152 | |||
153 | /** | ||
154 | * fw_iso_resources_update - update resource allocations after a bus reset | ||
155 | * @r: the resource manager | ||
156 | * | ||
157 | * This function must be called from the driver's .update handler to reallocate | ||
158 | * any resources that were allocated before the bus reset. It is safe to call | ||
159 | * this function if no resources are currently allocated. | ||
160 | * | ||
161 | * Returns a negative error code on failure. If this happens, the caller must | ||
162 | * stop streaming. | ||
163 | */ | ||
164 | int fw_iso_resources_update(struct fw_iso_resources *r) | ||
165 | { | ||
166 | struct fw_card *card = fw_parent_device(r->unit)->card; | ||
167 | int bandwidth, channel; | ||
168 | |||
169 | mutex_lock(&r->mutex); | ||
170 | |||
171 | if (!r->allocated) { | ||
172 | mutex_unlock(&r->mutex); | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | spin_lock_irq(&card->lock); | ||
177 | r->generation = card->generation; | ||
178 | r->bandwidth_overhead = current_bandwidth_overhead(card); | ||
179 | spin_unlock_irq(&card->lock); | ||
180 | |||
181 | bandwidth = r->bandwidth + r->bandwidth_overhead; | ||
182 | |||
183 | fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, | ||
184 | &channel, &bandwidth, true); | ||
185 | /* | ||
186 | * When another bus reset happens, pretend that the allocation | ||
187 | * succeeded; we will try again for the new generation later. | ||
188 | */ | ||
189 | if (channel < 0 && channel != -EAGAIN) { | ||
190 | r->allocated = false; | ||
191 | if (channel == -EBUSY) | ||
192 | dev_err(&r->unit->device, | ||
193 | "isochronous resources exhausted\n"); | ||
194 | else | ||
195 | dev_err(&r->unit->device, | ||
196 | "isochronous resource allocation failed\n"); | ||
197 | } | ||
198 | |||
199 | mutex_unlock(&r->mutex); | ||
200 | |||
201 | return channel; | ||
202 | } | ||
203 | EXPORT_SYMBOL(fw_iso_resources_update); | ||
204 | |||
205 | /** | ||
206 | * fw_iso_resources_free - frees allocated resources | ||
207 | * @r: the resource manager | ||
208 | * | ||
209 | * This function deallocates the channel and bandwidth, if allocated. | ||
210 | */ | ||
211 | void fw_iso_resources_free(struct fw_iso_resources *r) | ||
212 | { | ||
213 | struct fw_card *card = fw_parent_device(r->unit)->card; | ||
214 | int bandwidth, channel; | ||
215 | |||
216 | mutex_lock(&r->mutex); | ||
217 | |||
218 | if (r->allocated) { | ||
219 | bandwidth = r->bandwidth + r->bandwidth_overhead; | ||
220 | fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, | ||
221 | &channel, &bandwidth, false); | ||
222 | if (channel < 0) | ||
223 | dev_err(&r->unit->device, | ||
224 | "isochronous resource deallocation failed\n"); | ||
225 | |||
226 | r->allocated = false; | ||
227 | } | ||
228 | |||
229 | mutex_unlock(&r->mutex); | ||
230 | } | ||
231 | EXPORT_SYMBOL(fw_iso_resources_free); | ||
diff --git a/sound/firewire/iso-resources.h b/sound/firewire/iso-resources.h new file mode 100644 index 000000000000..5a9af7c61657 --- /dev/null +++ b/sound/firewire/iso-resources.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef SOUND_FIREWIRE_ISO_RESOURCES_H_INCLUDED | ||
2 | #define SOUND_FIREWIRE_ISO_RESOURCES_H_INCLUDED | ||
3 | |||
4 | #include <linux/mutex.h> | ||
5 | #include <linux/types.h> | ||
6 | |||
7 | struct fw_unit; | ||
8 | |||
9 | /** | ||
10 | * struct fw_iso_resources - manages channel/bandwidth allocation | ||
11 | * @channels_mask: if the device does not support all channel numbers, set this | ||
12 | * bit mask to something else than the default (all ones) | ||
13 | * | ||
14 | * This structure manages (de)allocation of isochronous resources (channel and | ||
15 | * bandwidth) for one isochronous stream. | ||
16 | */ | ||
17 | struct fw_iso_resources { | ||
18 | u64 channels_mask; | ||
19 | /* private: */ | ||
20 | struct fw_unit *unit; | ||
21 | struct mutex mutex; | ||
22 | unsigned int channel; | ||
23 | unsigned int bandwidth; /* in bandwidth units, without overhead */ | ||
24 | unsigned int bandwidth_overhead; | ||
25 | int generation; /* in which allocation is valid */ | ||
26 | bool allocated; | ||
27 | }; | ||
28 | |||
29 | int fw_iso_resources_init(struct fw_iso_resources *r, | ||
30 | struct fw_unit *unit); | ||
31 | void fw_iso_resources_destroy(struct fw_iso_resources *r); | ||
32 | |||
33 | int fw_iso_resources_allocate(struct fw_iso_resources *r, | ||
34 | unsigned int max_payload_bytes, int speed); | ||
35 | int fw_iso_resources_update(struct fw_iso_resources *r); | ||
36 | void fw_iso_resources_free(struct fw_iso_resources *r); | ||
37 | |||
38 | #endif | ||
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c new file mode 100644 index 000000000000..4750cea2210e --- /dev/null +++ b/sound/firewire/lib.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * miscellaneous helper functions | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
6 | */ | ||
7 | |||
8 | #include <linux/delay.h> | ||
9 | #include <linux/device.h> | ||
10 | #include <linux/firewire.h> | ||
11 | #include <linux/module.h> | ||
12 | #include "lib.h" | ||
13 | |||
14 | #define ERROR_RETRY_DELAY_MS 5 | ||
15 | |||
16 | /** | ||
17 | * rcode_string - convert a firewire result code to a string | ||
18 | * @rcode: the result | ||
19 | */ | ||
20 | const char *rcode_string(unsigned int rcode) | ||
21 | { | ||
22 | static const char *const names[] = { | ||
23 | [RCODE_COMPLETE] = "complete", | ||
24 | [RCODE_CONFLICT_ERROR] = "conflict error", | ||
25 | [RCODE_DATA_ERROR] = "data error", | ||
26 | [RCODE_TYPE_ERROR] = "type error", | ||
27 | [RCODE_ADDRESS_ERROR] = "address error", | ||
28 | [RCODE_SEND_ERROR] = "send error", | ||
29 | [RCODE_CANCELLED] = "cancelled", | ||
30 | [RCODE_BUSY] = "busy", | ||
31 | [RCODE_GENERATION] = "generation", | ||
32 | [RCODE_NO_ACK] = "no ack", | ||
33 | }; | ||
34 | |||
35 | if (rcode < ARRAY_SIZE(names) && names[rcode]) | ||
36 | return names[rcode]; | ||
37 | else | ||
38 | return "unknown"; | ||
39 | } | ||
40 | EXPORT_SYMBOL(rcode_string); | ||
41 | |||
42 | /** | ||
43 | * snd_fw_transaction - send a request and wait for its completion | ||
44 | * @unit: the driver's unit on the target device | ||
45 | * @tcode: the transaction code | ||
46 | * @offset: the address in the target's address space | ||
47 | * @buffer: input/output data | ||
48 | * @length: length of @buffer | ||
49 | * | ||
50 | * Submits an asynchronous request to the target device, and waits for the | ||
51 | * response. The node ID and the current generation are derived from @unit. | ||
52 | * On a bus reset or an error, the transaction is retried a few times. | ||
53 | * Returns zero on success, or a negative error code. | ||
54 | */ | ||
55 | int snd_fw_transaction(struct fw_unit *unit, int tcode, | ||
56 | u64 offset, void *buffer, size_t length) | ||
57 | { | ||
58 | struct fw_device *device = fw_parent_device(unit); | ||
59 | int generation, rcode, tries = 0; | ||
60 | |||
61 | for (;;) { | ||
62 | generation = device->generation; | ||
63 | smp_rmb(); /* node_id vs. generation */ | ||
64 | rcode = fw_run_transaction(device->card, tcode, | ||
65 | device->node_id, generation, | ||
66 | device->max_speed, offset, | ||
67 | buffer, length); | ||
68 | |||
69 | if (rcode == RCODE_COMPLETE) | ||
70 | return 0; | ||
71 | |||
72 | if (rcode_is_permanent_error(rcode) || ++tries >= 3) { | ||
73 | dev_err(&unit->device, "transaction failed: %s\n", | ||
74 | rcode_string(rcode)); | ||
75 | return -EIO; | ||
76 | } | ||
77 | |||
78 | msleep(ERROR_RETRY_DELAY_MS); | ||
79 | } | ||
80 | } | ||
81 | EXPORT_SYMBOL(snd_fw_transaction); | ||
82 | |||
83 | MODULE_DESCRIPTION("FireWire audio helper functions"); | ||
84 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
85 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h new file mode 100644 index 000000000000..064f3fd9ab06 --- /dev/null +++ b/sound/firewire/lib.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef SOUND_FIREWIRE_LIB_H_INCLUDED | ||
2 | #define SOUND_FIREWIRE_LIB_H_INCLUDED | ||
3 | |||
4 | #include <linux/firewire-constants.h> | ||
5 | #include <linux/types.h> | ||
6 | |||
7 | struct fw_unit; | ||
8 | |||
9 | int snd_fw_transaction(struct fw_unit *unit, int tcode, | ||
10 | u64 offset, void *buffer, size_t length); | ||
11 | const char *rcode_string(unsigned int rcode); | ||
12 | |||
13 | /* returns true if retrying the transaction would not make sense */ | ||
14 | static inline bool rcode_is_permanent_error(int rcode) | ||
15 | { | ||
16 | return rcode == RCODE_TYPE_ERROR || rcode == RCODE_ADDRESS_ERROR; | ||
17 | } | ||
18 | |||
19 | #endif | ||
diff --git a/sound/firewire/packets-buffer.c b/sound/firewire/packets-buffer.c new file mode 100644 index 000000000000..3c61ca2e6152 --- /dev/null +++ b/sound/firewire/packets-buffer.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * helpers for managing a buffer for many packets | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
6 | */ | ||
7 | |||
8 | #include <linux/firewire.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include "packets-buffer.h" | ||
11 | |||
12 | /** | ||
13 | * iso_packets_buffer_init - allocates the memory for packets | ||
14 | * @b: the buffer structure to initialize | ||
15 | * @unit: the device at the other end of the stream | ||
16 | * @count: the number of packets | ||
17 | * @packet_size: the (maximum) size of a packet, in bytes | ||
18 | * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE | ||
19 | */ | ||
20 | int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, | ||
21 | unsigned int count, unsigned int packet_size, | ||
22 | enum dma_data_direction direction) | ||
23 | { | ||
24 | unsigned int packets_per_page, pages; | ||
25 | unsigned int i, page_index, offset_in_page; | ||
26 | void *p; | ||
27 | int err; | ||
28 | |||
29 | b->packets = kmalloc(count * sizeof(*b->packets), GFP_KERNEL); | ||
30 | if (!b->packets) { | ||
31 | err = -ENOMEM; | ||
32 | goto error; | ||
33 | } | ||
34 | |||
35 | packet_size = L1_CACHE_ALIGN(packet_size); | ||
36 | packets_per_page = PAGE_SIZE / packet_size; | ||
37 | if (WARN_ON(!packets_per_page)) { | ||
38 | err = -EINVAL; | ||
39 | goto error; | ||
40 | } | ||
41 | pages = DIV_ROUND_UP(count, packets_per_page); | ||
42 | |||
43 | err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card, | ||
44 | pages, direction); | ||
45 | if (err < 0) | ||
46 | goto err_packets; | ||
47 | |||
48 | for (i = 0; i < count; ++i) { | ||
49 | page_index = i / packets_per_page; | ||
50 | p = page_address(b->iso_buffer.pages[page_index]); | ||
51 | offset_in_page = (i % packets_per_page) * packet_size; | ||
52 | b->packets[i].buffer = p + offset_in_page; | ||
53 | b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page; | ||
54 | } | ||
55 | |||
56 | return 0; | ||
57 | |||
58 | err_packets: | ||
59 | kfree(b->packets); | ||
60 | error: | ||
61 | return err; | ||
62 | } | ||
63 | EXPORT_SYMBOL(iso_packets_buffer_init); | ||
64 | |||
65 | /** | ||
66 | * iso_packets_buffer_destroy - frees packet buffer resources | ||
67 | * @b: the buffer structure to free | ||
68 | * @unit: the device at the other end of the stream | ||
69 | */ | ||
70 | void iso_packets_buffer_destroy(struct iso_packets_buffer *b, | ||
71 | struct fw_unit *unit) | ||
72 | { | ||
73 | fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card); | ||
74 | kfree(b->packets); | ||
75 | } | ||
76 | EXPORT_SYMBOL(iso_packets_buffer_destroy); | ||
diff --git a/sound/firewire/packets-buffer.h b/sound/firewire/packets-buffer.h new file mode 100644 index 000000000000..6513c5cb6ea9 --- /dev/null +++ b/sound/firewire/packets-buffer.h | |||
@@ -0,0 +1,26 @@ | |||
1 | #ifndef SOUND_FIREWIRE_PACKETS_BUFFER_H_INCLUDED | ||
2 | #define SOUND_FIREWIRE_PACKETS_BUFFER_H_INCLUDED | ||
3 | |||
4 | #include <linux/dma-mapping.h> | ||
5 | #include <linux/firewire.h> | ||
6 | |||
7 | /** | ||
8 | * struct iso_packets_buffer - manages a buffer for many packets | ||
9 | * @iso_buffer: the memory containing the packets | ||
10 | * @packets: an array, with each element pointing to one packet | ||
11 | */ | ||
12 | struct iso_packets_buffer { | ||
13 | struct fw_iso_buffer iso_buffer; | ||
14 | struct { | ||
15 | void *buffer; | ||
16 | unsigned int offset; | ||
17 | } *packets; | ||
18 | }; | ||
19 | |||
20 | int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, | ||
21 | unsigned int count, unsigned int packet_size, | ||
22 | enum dma_data_direction direction); | ||
23 | void iso_packets_buffer_destroy(struct iso_packets_buffer *b, | ||
24 | struct fw_unit *unit); | ||
25 | |||
26 | #endif | ||
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c new file mode 100644 index 000000000000..5466de8527bd --- /dev/null +++ b/sound/firewire/speakers.c | |||
@@ -0,0 +1,857 @@ | |||
1 | /* | ||
2 | * OXFW970-based speakers driver | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
6 | */ | ||
7 | |||
8 | #include <linux/device.h> | ||
9 | #include <linux/firewire.h> | ||
10 | #include <linux/firewire-constants.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/mod_devicetable.h> | ||
13 | #include <linux/mutex.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <sound/control.h> | ||
16 | #include <sound/core.h> | ||
17 | #include <sound/initval.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/pcm_params.h> | ||
20 | #include "cmp.h" | ||
21 | #include "fcp.h" | ||
22 | #include "amdtp.h" | ||
23 | #include "lib.h" | ||
24 | |||
25 | #define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000) | ||
26 | /* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */ | ||
27 | |||
28 | #define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020) | ||
29 | #define OXFORD_HARDWARE_ID_OXFW970 0x39443841 | ||
30 | #define OXFORD_HARDWARE_ID_OXFW971 0x39373100 | ||
31 | |||
32 | #define VENDOR_GRIFFIN 0x001292 | ||
33 | #define VENDOR_LACIE 0x00d04b | ||
34 | |||
35 | #define SPECIFIER_1394TA 0x00a02d | ||
36 | #define VERSION_AVC 0x010001 | ||
37 | |||
38 | struct device_info { | ||
39 | const char *driver_name; | ||
40 | const char *short_name; | ||
41 | const char *long_name; | ||
42 | int (*pcm_constraints)(struct snd_pcm_runtime *runtime); | ||
43 | unsigned int mixer_channels; | ||
44 | u8 mute_fb_id; | ||
45 | u8 volume_fb_id; | ||
46 | }; | ||
47 | |||
48 | struct fwspk { | ||
49 | struct snd_card *card; | ||
50 | struct fw_unit *unit; | ||
51 | const struct device_info *device_info; | ||
52 | struct snd_pcm_substream *pcm; | ||
53 | struct mutex mutex; | ||
54 | struct cmp_connection connection; | ||
55 | struct amdtp_out_stream stream; | ||
56 | bool stream_running; | ||
57 | bool mute; | ||
58 | s16 volume[6]; | ||
59 | s16 volume_min; | ||
60 | s16 volume_max; | ||
61 | }; | ||
62 | |||
63 | MODULE_DESCRIPTION("FireWire speakers driver"); | ||
64 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
65 | MODULE_LICENSE("GPL v2"); | ||
66 | |||
67 | static int firewave_rate_constraint(struct snd_pcm_hw_params *params, | ||
68 | struct snd_pcm_hw_rule *rule) | ||
69 | { | ||
70 | static unsigned int stereo_rates[] = { 48000, 96000 }; | ||
71 | struct snd_interval *channels = | ||
72 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
73 | struct snd_interval *rate = | ||
74 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
75 | |||
76 | /* two channels work only at 48/96 kHz */ | ||
77 | if (snd_interval_max(channels) < 6) | ||
78 | return snd_interval_list(rate, 2, stereo_rates, 0); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int firewave_channels_constraint(struct snd_pcm_hw_params *params, | ||
83 | struct snd_pcm_hw_rule *rule) | ||
84 | { | ||
85 | static const struct snd_interval all_channels = { .min = 6, .max = 6 }; | ||
86 | struct snd_interval *rate = | ||
87 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
88 | struct snd_interval *channels = | ||
89 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
90 | |||
91 | /* 32/44.1 kHz work only with all six channels */ | ||
92 | if (snd_interval_max(rate) < 48000) | ||
93 | return snd_interval_refine(channels, &all_channels); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int firewave_constraints(struct snd_pcm_runtime *runtime) | ||
98 | { | ||
99 | static unsigned int channels_list[] = { 2, 6 }; | ||
100 | static struct snd_pcm_hw_constraint_list channels_list_constraint = { | ||
101 | .count = 2, | ||
102 | .list = channels_list, | ||
103 | }; | ||
104 | int err; | ||
105 | |||
106 | runtime->hw.rates = SNDRV_PCM_RATE_32000 | | ||
107 | SNDRV_PCM_RATE_44100 | | ||
108 | SNDRV_PCM_RATE_48000 | | ||
109 | SNDRV_PCM_RATE_96000; | ||
110 | runtime->hw.channels_max = 6; | ||
111 | |||
112 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
113 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
114 | &channels_list_constraint); | ||
115 | if (err < 0) | ||
116 | return err; | ||
117 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
118 | firewave_rate_constraint, NULL, | ||
119 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
120 | if (err < 0) | ||
121 | return err; | ||
122 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
123 | firewave_channels_constraint, NULL, | ||
124 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
125 | if (err < 0) | ||
126 | return err; | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) | ||
132 | { | ||
133 | runtime->hw.rates = SNDRV_PCM_RATE_32000 | | ||
134 | SNDRV_PCM_RATE_44100 | | ||
135 | SNDRV_PCM_RATE_48000 | | ||
136 | SNDRV_PCM_RATE_88200 | | ||
137 | SNDRV_PCM_RATE_96000; | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int fwspk_open(struct snd_pcm_substream *substream) | ||
143 | { | ||
144 | static const struct snd_pcm_hardware hardware = { | ||
145 | .info = SNDRV_PCM_INFO_MMAP | | ||
146 | SNDRV_PCM_INFO_MMAP_VALID | | ||
147 | SNDRV_PCM_INFO_BATCH | | ||
148 | SNDRV_PCM_INFO_INTERLEAVED | | ||
149 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | ||
150 | .formats = AMDTP_OUT_PCM_FORMAT_BITS, | ||
151 | .channels_min = 2, | ||
152 | .channels_max = 2, | ||
153 | .buffer_bytes_max = 4 * 1024 * 1024, | ||
154 | .period_bytes_min = 1, | ||
155 | .period_bytes_max = UINT_MAX, | ||
156 | .periods_min = 1, | ||
157 | .periods_max = UINT_MAX, | ||
158 | }; | ||
159 | struct fwspk *fwspk = substream->private_data; | ||
160 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
161 | int err; | ||
162 | |||
163 | runtime->hw = hardware; | ||
164 | |||
165 | err = fwspk->device_info->pcm_constraints(runtime); | ||
166 | if (err < 0) | ||
167 | return err; | ||
168 | err = snd_pcm_limit_hw_rates(runtime); | ||
169 | if (err < 0) | ||
170 | return err; | ||
171 | |||
172 | err = snd_pcm_hw_constraint_minmax(runtime, | ||
173 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | ||
174 | 5000, 8192000); | ||
175 | if (err < 0) | ||
176 | return err; | ||
177 | |||
178 | err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | ||
179 | if (err < 0) | ||
180 | return err; | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static int fwspk_close(struct snd_pcm_substream *substream) | ||
186 | { | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static void fwspk_stop_stream(struct fwspk *fwspk) | ||
191 | { | ||
192 | if (fwspk->stream_running) { | ||
193 | amdtp_out_stream_stop(&fwspk->stream); | ||
194 | cmp_connection_break(&fwspk->connection); | ||
195 | fwspk->stream_running = false; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | static int fwspk_set_rate(struct fwspk *fwspk, unsigned int sfc) | ||
200 | { | ||
201 | u8 *buf; | ||
202 | int err; | ||
203 | |||
204 | buf = kmalloc(8, GFP_KERNEL); | ||
205 | if (!buf) | ||
206 | return -ENOMEM; | ||
207 | |||
208 | buf[0] = 0x00; /* AV/C, CONTROL */ | ||
209 | buf[1] = 0xff; /* unit */ | ||
210 | buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */ | ||
211 | buf[3] = 0x00; /* plug 0 */ | ||
212 | buf[4] = 0x90; /* format: audio */ | ||
213 | buf[5] = 0x00 | sfc; /* AM824, frequency */ | ||
214 | buf[6] = 0xff; /* SYT (not used) */ | ||
215 | buf[7] = 0xff; | ||
216 | |||
217 | err = fcp_avc_transaction(fwspk->unit, buf, 8, buf, 8, | ||
218 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5)); | ||
219 | if (err < 0) | ||
220 | goto error; | ||
221 | if (err < 6 || buf[0] != 0x09 /* ACCEPTED */) { | ||
222 | dev_err(&fwspk->unit->device, "failed to set sample rate\n"); | ||
223 | err = -EIO; | ||
224 | goto error; | ||
225 | } | ||
226 | |||
227 | err = 0; | ||
228 | |||
229 | error: | ||
230 | kfree(buf); | ||
231 | |||
232 | return err; | ||
233 | } | ||
234 | |||
235 | static int fwspk_hw_params(struct snd_pcm_substream *substream, | ||
236 | struct snd_pcm_hw_params *hw_params) | ||
237 | { | ||
238 | struct fwspk *fwspk = substream->private_data; | ||
239 | int err; | ||
240 | |||
241 | mutex_lock(&fwspk->mutex); | ||
242 | fwspk_stop_stream(fwspk); | ||
243 | mutex_unlock(&fwspk->mutex); | ||
244 | |||
245 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
246 | params_buffer_bytes(hw_params)); | ||
247 | if (err < 0) | ||
248 | goto error; | ||
249 | |||
250 | amdtp_out_stream_set_rate(&fwspk->stream, params_rate(hw_params)); | ||
251 | amdtp_out_stream_set_pcm(&fwspk->stream, params_channels(hw_params)); | ||
252 | |||
253 | amdtp_out_stream_set_pcm_format(&fwspk->stream, | ||
254 | params_format(hw_params)); | ||
255 | |||
256 | err = fwspk_set_rate(fwspk, fwspk->stream.sfc); | ||
257 | if (err < 0) | ||
258 | goto err_buffer; | ||
259 | |||
260 | return 0; | ||
261 | |||
262 | err_buffer: | ||
263 | snd_pcm_lib_free_vmalloc_buffer(substream); | ||
264 | error: | ||
265 | return err; | ||
266 | } | ||
267 | |||
268 | static int fwspk_hw_free(struct snd_pcm_substream *substream) | ||
269 | { | ||
270 | struct fwspk *fwspk = substream->private_data; | ||
271 | |||
272 | mutex_lock(&fwspk->mutex); | ||
273 | fwspk_stop_stream(fwspk); | ||
274 | mutex_unlock(&fwspk->mutex); | ||
275 | |||
276 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
277 | } | ||
278 | |||
279 | static int fwspk_prepare(struct snd_pcm_substream *substream) | ||
280 | { | ||
281 | struct fwspk *fwspk = substream->private_data; | ||
282 | int err; | ||
283 | |||
284 | mutex_lock(&fwspk->mutex); | ||
285 | |||
286 | if (amdtp_out_streaming_error(&fwspk->stream)) | ||
287 | fwspk_stop_stream(fwspk); | ||
288 | |||
289 | if (!fwspk->stream_running) { | ||
290 | err = cmp_connection_establish(&fwspk->connection, | ||
291 | amdtp_out_stream_get_max_payload(&fwspk->stream)); | ||
292 | if (err < 0) | ||
293 | goto err_mutex; | ||
294 | |||
295 | err = amdtp_out_stream_start(&fwspk->stream, | ||
296 | fwspk->connection.resources.channel, | ||
297 | fwspk->connection.speed); | ||
298 | if (err < 0) | ||
299 | goto err_connection; | ||
300 | |||
301 | fwspk->stream_running = true; | ||
302 | } | ||
303 | |||
304 | mutex_unlock(&fwspk->mutex); | ||
305 | |||
306 | amdtp_out_stream_pcm_prepare(&fwspk->stream); | ||
307 | |||
308 | return 0; | ||
309 | |||
310 | err_connection: | ||
311 | cmp_connection_break(&fwspk->connection); | ||
312 | err_mutex: | ||
313 | mutex_unlock(&fwspk->mutex); | ||
314 | |||
315 | return err; | ||
316 | } | ||
317 | |||
318 | static int fwspk_trigger(struct snd_pcm_substream *substream, int cmd) | ||
319 | { | ||
320 | struct fwspk *fwspk = substream->private_data; | ||
321 | struct snd_pcm_substream *pcm; | ||
322 | |||
323 | switch (cmd) { | ||
324 | case SNDRV_PCM_TRIGGER_START: | ||
325 | pcm = substream; | ||
326 | break; | ||
327 | case SNDRV_PCM_TRIGGER_STOP: | ||
328 | pcm = NULL; | ||
329 | break; | ||
330 | default: | ||
331 | return -EINVAL; | ||
332 | } | ||
333 | amdtp_out_stream_pcm_trigger(&fwspk->stream, pcm); | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static snd_pcm_uframes_t fwspk_pointer(struct snd_pcm_substream *substream) | ||
338 | { | ||
339 | struct fwspk *fwspk = substream->private_data; | ||
340 | |||
341 | return amdtp_out_stream_pcm_pointer(&fwspk->stream); | ||
342 | } | ||
343 | |||
344 | static int fwspk_create_pcm(struct fwspk *fwspk) | ||
345 | { | ||
346 | static struct snd_pcm_ops ops = { | ||
347 | .open = fwspk_open, | ||
348 | .close = fwspk_close, | ||
349 | .ioctl = snd_pcm_lib_ioctl, | ||
350 | .hw_params = fwspk_hw_params, | ||
351 | .hw_free = fwspk_hw_free, | ||
352 | .prepare = fwspk_prepare, | ||
353 | .trigger = fwspk_trigger, | ||
354 | .pointer = fwspk_pointer, | ||
355 | .page = snd_pcm_lib_get_vmalloc_page, | ||
356 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
357 | }; | ||
358 | struct snd_pcm *pcm; | ||
359 | int err; | ||
360 | |||
361 | err = snd_pcm_new(fwspk->card, "OXFW970", 0, 1, 0, &pcm); | ||
362 | if (err < 0) | ||
363 | return err; | ||
364 | pcm->private_data = fwspk; | ||
365 | strcpy(pcm->name, fwspk->device_info->short_name); | ||
366 | fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | ||
367 | fwspk->pcm->ops = &ops; | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | enum control_action { CTL_READ, CTL_WRITE }; | ||
372 | enum control_attribute { | ||
373 | CTL_MIN = 0x02, | ||
374 | CTL_MAX = 0x03, | ||
375 | CTL_CURRENT = 0x10, | ||
376 | }; | ||
377 | |||
378 | static int fwspk_mute_command(struct fwspk *fwspk, bool *value, | ||
379 | enum control_action action) | ||
380 | { | ||
381 | u8 *buf; | ||
382 | u8 response_ok; | ||
383 | int err; | ||
384 | |||
385 | buf = kmalloc(11, GFP_KERNEL); | ||
386 | if (!buf) | ||
387 | return -ENOMEM; | ||
388 | |||
389 | if (action == CTL_READ) { | ||
390 | buf[0] = 0x01; /* AV/C, STATUS */ | ||
391 | response_ok = 0x0c; /* STABLE */ | ||
392 | } else { | ||
393 | buf[0] = 0x00; /* AV/C, CONTROL */ | ||
394 | response_ok = 0x09; /* ACCEPTED */ | ||
395 | } | ||
396 | buf[1] = 0x08; /* audio unit 0 */ | ||
397 | buf[2] = 0xb8; /* FUNCTION BLOCK */ | ||
398 | buf[3] = 0x81; /* function block type: feature */ | ||
399 | buf[4] = fwspk->device_info->mute_fb_id; /* function block ID */ | ||
400 | buf[5] = 0x10; /* control attribute: current */ | ||
401 | buf[6] = 0x02; /* selector length */ | ||
402 | buf[7] = 0x00; /* audio channel number */ | ||
403 | buf[8] = 0x01; /* control selector: mute */ | ||
404 | buf[9] = 0x01; /* control data length */ | ||
405 | if (action == CTL_READ) | ||
406 | buf[10] = 0xff; | ||
407 | else | ||
408 | buf[10] = *value ? 0x70 : 0x60; | ||
409 | |||
410 | err = fcp_avc_transaction(fwspk->unit, buf, 11, buf, 11, 0x3fe); | ||
411 | if (err < 0) | ||
412 | goto error; | ||
413 | if (err < 11) { | ||
414 | dev_err(&fwspk->unit->device, "short FCP response\n"); | ||
415 | err = -EIO; | ||
416 | goto error; | ||
417 | } | ||
418 | if (buf[0] != response_ok) { | ||
419 | dev_err(&fwspk->unit->device, "mute command failed\n"); | ||
420 | err = -EIO; | ||
421 | goto error; | ||
422 | } | ||
423 | if (action == CTL_READ) | ||
424 | *value = buf[10] == 0x70; | ||
425 | |||
426 | err = 0; | ||
427 | |||
428 | error: | ||
429 | kfree(buf); | ||
430 | |||
431 | return err; | ||
432 | } | ||
433 | |||
434 | static int fwspk_volume_command(struct fwspk *fwspk, s16 *value, | ||
435 | unsigned int channel, | ||
436 | enum control_attribute attribute, | ||
437 | enum control_action action) | ||
438 | { | ||
439 | u8 *buf; | ||
440 | u8 response_ok; | ||
441 | int err; | ||
442 | |||
443 | buf = kmalloc(12, GFP_KERNEL); | ||
444 | if (!buf) | ||
445 | return -ENOMEM; | ||
446 | |||
447 | if (action == CTL_READ) { | ||
448 | buf[0] = 0x01; /* AV/C, STATUS */ | ||
449 | response_ok = 0x0c; /* STABLE */ | ||
450 | } else { | ||
451 | buf[0] = 0x00; /* AV/C, CONTROL */ | ||
452 | response_ok = 0x09; /* ACCEPTED */ | ||
453 | } | ||
454 | buf[1] = 0x08; /* audio unit 0 */ | ||
455 | buf[2] = 0xb8; /* FUNCTION BLOCK */ | ||
456 | buf[3] = 0x81; /* function block type: feature */ | ||
457 | buf[4] = fwspk->device_info->volume_fb_id; /* function block ID */ | ||
458 | buf[5] = attribute; /* control attribute */ | ||
459 | buf[6] = 0x02; /* selector length */ | ||
460 | buf[7] = channel; /* audio channel number */ | ||
461 | buf[8] = 0x02; /* control selector: volume */ | ||
462 | buf[9] = 0x02; /* control data length */ | ||
463 | if (action == CTL_READ) { | ||
464 | buf[10] = 0xff; | ||
465 | buf[11] = 0xff; | ||
466 | } else { | ||
467 | buf[10] = *value >> 8; | ||
468 | buf[11] = *value; | ||
469 | } | ||
470 | |||
471 | err = fcp_avc_transaction(fwspk->unit, buf, 12, buf, 12, 0x3fe); | ||
472 | if (err < 0) | ||
473 | goto error; | ||
474 | if (err < 12) { | ||
475 | dev_err(&fwspk->unit->device, "short FCP response\n"); | ||
476 | err = -EIO; | ||
477 | goto error; | ||
478 | } | ||
479 | if (buf[0] != response_ok) { | ||
480 | dev_err(&fwspk->unit->device, "volume command failed\n"); | ||
481 | err = -EIO; | ||
482 | goto error; | ||
483 | } | ||
484 | if (action == CTL_READ) | ||
485 | *value = (buf[10] << 8) | buf[11]; | ||
486 | |||
487 | err = 0; | ||
488 | |||
489 | error: | ||
490 | kfree(buf); | ||
491 | |||
492 | return err; | ||
493 | } | ||
494 | |||
495 | static int fwspk_mute_get(struct snd_kcontrol *control, | ||
496 | struct snd_ctl_elem_value *value) | ||
497 | { | ||
498 | struct fwspk *fwspk = control->private_data; | ||
499 | |||
500 | value->value.integer.value[0] = !fwspk->mute; | ||
501 | |||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static int fwspk_mute_put(struct snd_kcontrol *control, | ||
506 | struct snd_ctl_elem_value *value) | ||
507 | { | ||
508 | struct fwspk *fwspk = control->private_data; | ||
509 | bool mute; | ||
510 | int err; | ||
511 | |||
512 | mute = !value->value.integer.value[0]; | ||
513 | |||
514 | if (mute == fwspk->mute) | ||
515 | return 0; | ||
516 | |||
517 | err = fwspk_mute_command(fwspk, &mute, CTL_WRITE); | ||
518 | if (err < 0) | ||
519 | return err; | ||
520 | fwspk->mute = mute; | ||
521 | |||
522 | return 1; | ||
523 | } | ||
524 | |||
525 | static int fwspk_volume_info(struct snd_kcontrol *control, | ||
526 | struct snd_ctl_elem_info *info) | ||
527 | { | ||
528 | struct fwspk *fwspk = control->private_data; | ||
529 | |||
530 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
531 | info->count = fwspk->device_info->mixer_channels; | ||
532 | info->value.integer.min = fwspk->volume_min; | ||
533 | info->value.integer.max = fwspk->volume_max; | ||
534 | |||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; | ||
539 | |||
540 | static int fwspk_volume_get(struct snd_kcontrol *control, | ||
541 | struct snd_ctl_elem_value *value) | ||
542 | { | ||
543 | struct fwspk *fwspk = control->private_data; | ||
544 | unsigned int i; | ||
545 | |||
546 | for (i = 0; i < fwspk->device_info->mixer_channels; ++i) | ||
547 | value->value.integer.value[channel_map[i]] = fwspk->volume[i]; | ||
548 | |||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | static int fwspk_volume_put(struct snd_kcontrol *control, | ||
553 | struct snd_ctl_elem_value *value) | ||
554 | { | ||
555 | struct fwspk *fwspk = control->private_data; | ||
556 | unsigned int i, changed_channels; | ||
557 | bool equal_values = true; | ||
558 | s16 volume; | ||
559 | int err; | ||
560 | |||
561 | for (i = 0; i < fwspk->device_info->mixer_channels; ++i) { | ||
562 | if (value->value.integer.value[i] < fwspk->volume_min || | ||
563 | value->value.integer.value[i] > fwspk->volume_max) | ||
564 | return -EINVAL; | ||
565 | if (value->value.integer.value[i] != | ||
566 | value->value.integer.value[0]) | ||
567 | equal_values = false; | ||
568 | } | ||
569 | |||
570 | changed_channels = 0; | ||
571 | for (i = 0; i < fwspk->device_info->mixer_channels; ++i) | ||
572 | if (value->value.integer.value[channel_map[i]] != | ||
573 | fwspk->volume[i]) | ||
574 | changed_channels |= 1 << (i + 1); | ||
575 | |||
576 | if (equal_values && changed_channels != 0) | ||
577 | changed_channels = 1 << 0; | ||
578 | |||
579 | for (i = 0; i <= fwspk->device_info->mixer_channels; ++i) { | ||
580 | volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; | ||
581 | if (changed_channels & (1 << i)) { | ||
582 | err = fwspk_volume_command(fwspk, &volume, i, | ||
583 | CTL_CURRENT, CTL_WRITE); | ||
584 | if (err < 0) | ||
585 | return err; | ||
586 | } | ||
587 | if (i > 0) | ||
588 | fwspk->volume[i - 1] = volume; | ||
589 | } | ||
590 | |||
591 | return changed_channels != 0; | ||
592 | } | ||
593 | |||
594 | static int fwspk_create_mixer(struct fwspk *fwspk) | ||
595 | { | ||
596 | static const struct snd_kcontrol_new controls[] = { | ||
597 | { | ||
598 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
599 | .name = "PCM Playback Switch", | ||
600 | .info = snd_ctl_boolean_mono_info, | ||
601 | .get = fwspk_mute_get, | ||
602 | .put = fwspk_mute_put, | ||
603 | }, | ||
604 | { | ||
605 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
606 | .name = "PCM Playback Volume", | ||
607 | .info = fwspk_volume_info, | ||
608 | .get = fwspk_volume_get, | ||
609 | .put = fwspk_volume_put, | ||
610 | }, | ||
611 | }; | ||
612 | unsigned int i, first_ch; | ||
613 | int err; | ||
614 | |||
615 | err = fwspk_volume_command(fwspk, &fwspk->volume_min, | ||
616 | 0, CTL_MIN, CTL_READ); | ||
617 | if (err < 0) | ||
618 | return err; | ||
619 | err = fwspk_volume_command(fwspk, &fwspk->volume_max, | ||
620 | 0, CTL_MAX, CTL_READ); | ||
621 | if (err < 0) | ||
622 | return err; | ||
623 | |||
624 | err = fwspk_mute_command(fwspk, &fwspk->mute, CTL_READ); | ||
625 | if (err < 0) | ||
626 | return err; | ||
627 | |||
628 | first_ch = fwspk->device_info->mixer_channels == 1 ? 0 : 1; | ||
629 | for (i = 0; i < fwspk->device_info->mixer_channels; ++i) { | ||
630 | err = fwspk_volume_command(fwspk, &fwspk->volume[i], | ||
631 | first_ch + i, CTL_CURRENT, CTL_READ); | ||
632 | if (err < 0) | ||
633 | return err; | ||
634 | } | ||
635 | |||
636 | for (i = 0; i < ARRAY_SIZE(controls); ++i) { | ||
637 | err = snd_ctl_add(fwspk->card, | ||
638 | snd_ctl_new1(&controls[i], fwspk)); | ||
639 | if (err < 0) | ||
640 | return err; | ||
641 | } | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static u32 fwspk_read_firmware_version(struct fw_unit *unit) | ||
647 | { | ||
648 | __be32 data; | ||
649 | int err; | ||
650 | |||
651 | err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, | ||
652 | OXFORD_FIRMWARE_ID_ADDRESS, &data, 4); | ||
653 | return err >= 0 ? be32_to_cpu(data) : 0; | ||
654 | } | ||
655 | |||
656 | static void fwspk_card_free(struct snd_card *card) | ||
657 | { | ||
658 | struct fwspk *fwspk = card->private_data; | ||
659 | struct fw_device *dev = fw_parent_device(fwspk->unit); | ||
660 | |||
661 | amdtp_out_stream_destroy(&fwspk->stream); | ||
662 | cmp_connection_destroy(&fwspk->connection); | ||
663 | fw_unit_put(fwspk->unit); | ||
664 | fw_device_put(dev); | ||
665 | mutex_destroy(&fwspk->mutex); | ||
666 | } | ||
667 | |||
668 | static const struct device_info *__devinit fwspk_detect(struct fw_device *dev) | ||
669 | { | ||
670 | static const struct device_info griffin_firewave = { | ||
671 | .driver_name = "FireWave", | ||
672 | .short_name = "FireWave", | ||
673 | .long_name = "Griffin FireWave Surround", | ||
674 | .pcm_constraints = firewave_constraints, | ||
675 | .mixer_channels = 6, | ||
676 | .mute_fb_id = 0x01, | ||
677 | .volume_fb_id = 0x02, | ||
678 | }; | ||
679 | static const struct device_info lacie_speakers = { | ||
680 | .driver_name = "FWSpeakers", | ||
681 | .short_name = "FireWire Speakers", | ||
682 | .long_name = "LaCie FireWire Speakers", | ||
683 | .pcm_constraints = lacie_speakers_constraints, | ||
684 | .mixer_channels = 1, | ||
685 | .mute_fb_id = 0x01, | ||
686 | .volume_fb_id = 0x01, | ||
687 | }; | ||
688 | struct fw_csr_iterator i; | ||
689 | int key, value; | ||
690 | |||
691 | fw_csr_iterator_init(&i, dev->config_rom); | ||
692 | while (fw_csr_iterator_next(&i, &key, &value)) | ||
693 | if (key == CSR_VENDOR) | ||
694 | switch (value) { | ||
695 | case VENDOR_GRIFFIN: | ||
696 | return &griffin_firewave; | ||
697 | case VENDOR_LACIE: | ||
698 | return &lacie_speakers; | ||
699 | } | ||
700 | |||
701 | return NULL; | ||
702 | } | ||
703 | |||
704 | static int __devinit fwspk_probe(struct device *unit_dev) | ||
705 | { | ||
706 | struct fw_unit *unit = fw_unit(unit_dev); | ||
707 | struct fw_device *fw_dev = fw_parent_device(unit); | ||
708 | struct snd_card *card; | ||
709 | struct fwspk *fwspk; | ||
710 | u32 firmware; | ||
711 | int err; | ||
712 | |||
713 | err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*fwspk), &card); | ||
714 | if (err < 0) | ||
715 | return err; | ||
716 | snd_card_set_dev(card, unit_dev); | ||
717 | |||
718 | fwspk = card->private_data; | ||
719 | fwspk->card = card; | ||
720 | mutex_init(&fwspk->mutex); | ||
721 | fw_device_get(fw_dev); | ||
722 | fwspk->unit = fw_unit_get(unit); | ||
723 | fwspk->device_info = fwspk_detect(fw_dev); | ||
724 | if (!fwspk->device_info) { | ||
725 | err = -ENODEV; | ||
726 | goto err_unit; | ||
727 | } | ||
728 | |||
729 | err = cmp_connection_init(&fwspk->connection, unit, 0); | ||
730 | if (err < 0) | ||
731 | goto err_unit; | ||
732 | |||
733 | err = amdtp_out_stream_init(&fwspk->stream, unit, CIP_NONBLOCKING); | ||
734 | if (err < 0) | ||
735 | goto err_connection; | ||
736 | |||
737 | card->private_free = fwspk_card_free; | ||
738 | |||
739 | strcpy(card->driver, fwspk->device_info->driver_name); | ||
740 | strcpy(card->shortname, fwspk->device_info->short_name); | ||
741 | firmware = fwspk_read_firmware_version(unit); | ||
742 | snprintf(card->longname, sizeof(card->longname), | ||
743 | "%s (OXFW%x %04x), GUID %08x%08x at %s, S%d", | ||
744 | fwspk->device_info->long_name, | ||
745 | firmware >> 20, firmware & 0xffff, | ||
746 | fw_dev->config_rom[3], fw_dev->config_rom[4], | ||
747 | dev_name(&unit->device), 100 << fw_dev->max_speed); | ||
748 | strcpy(card->mixername, "OXFW970"); | ||
749 | |||
750 | err = fwspk_create_pcm(fwspk); | ||
751 | if (err < 0) | ||
752 | goto error; | ||
753 | |||
754 | err = fwspk_create_mixer(fwspk); | ||
755 | if (err < 0) | ||
756 | goto error; | ||
757 | |||
758 | err = snd_card_register(card); | ||
759 | if (err < 0) | ||
760 | goto error; | ||
761 | |||
762 | dev_set_drvdata(unit_dev, fwspk); | ||
763 | |||
764 | return 0; | ||
765 | |||
766 | err_connection: | ||
767 | cmp_connection_destroy(&fwspk->connection); | ||
768 | err_unit: | ||
769 | fw_unit_put(fwspk->unit); | ||
770 | fw_device_put(fw_dev); | ||
771 | mutex_destroy(&fwspk->mutex); | ||
772 | error: | ||
773 | snd_card_free(card); | ||
774 | return err; | ||
775 | } | ||
776 | |||
777 | static int __devexit fwspk_remove(struct device *dev) | ||
778 | { | ||
779 | struct fwspk *fwspk = dev_get_drvdata(dev); | ||
780 | |||
781 | mutex_lock(&fwspk->mutex); | ||
782 | amdtp_out_stream_pcm_abort(&fwspk->stream); | ||
783 | snd_card_disconnect(fwspk->card); | ||
784 | fwspk_stop_stream(fwspk); | ||
785 | mutex_unlock(&fwspk->mutex); | ||
786 | |||
787 | snd_card_free_when_closed(fwspk->card); | ||
788 | |||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static void fwspk_bus_reset(struct fw_unit *unit) | ||
793 | { | ||
794 | struct fwspk *fwspk = dev_get_drvdata(&unit->device); | ||
795 | |||
796 | fcp_bus_reset(fwspk->unit); | ||
797 | |||
798 | if (cmp_connection_update(&fwspk->connection) < 0) { | ||
799 | mutex_lock(&fwspk->mutex); | ||
800 | amdtp_out_stream_pcm_abort(&fwspk->stream); | ||
801 | fwspk_stop_stream(fwspk); | ||
802 | mutex_unlock(&fwspk->mutex); | ||
803 | return; | ||
804 | } | ||
805 | |||
806 | amdtp_out_stream_update(&fwspk->stream); | ||
807 | } | ||
808 | |||
809 | static const struct ieee1394_device_id fwspk_id_table[] = { | ||
810 | { | ||
811 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
812 | IEEE1394_MATCH_MODEL_ID | | ||
813 | IEEE1394_MATCH_SPECIFIER_ID | | ||
814 | IEEE1394_MATCH_VERSION, | ||
815 | .vendor_id = VENDOR_GRIFFIN, | ||
816 | .model_id = 0x00f970, | ||
817 | .specifier_id = SPECIFIER_1394TA, | ||
818 | .version = VERSION_AVC, | ||
819 | }, | ||
820 | { | ||
821 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
822 | IEEE1394_MATCH_MODEL_ID | | ||
823 | IEEE1394_MATCH_SPECIFIER_ID | | ||
824 | IEEE1394_MATCH_VERSION, | ||
825 | .vendor_id = VENDOR_LACIE, | ||
826 | .model_id = 0x00f970, | ||
827 | .specifier_id = SPECIFIER_1394TA, | ||
828 | .version = VERSION_AVC, | ||
829 | }, | ||
830 | { } | ||
831 | }; | ||
832 | MODULE_DEVICE_TABLE(ieee1394, fwspk_id_table); | ||
833 | |||
834 | static struct fw_driver fwspk_driver = { | ||
835 | .driver = { | ||
836 | .owner = THIS_MODULE, | ||
837 | .name = KBUILD_MODNAME, | ||
838 | .bus = &fw_bus_type, | ||
839 | .probe = fwspk_probe, | ||
840 | .remove = __devexit_p(fwspk_remove), | ||
841 | }, | ||
842 | .update = fwspk_bus_reset, | ||
843 | .id_table = fwspk_id_table, | ||
844 | }; | ||
845 | |||
846 | static int __init alsa_fwspk_init(void) | ||
847 | { | ||
848 | return driver_register(&fwspk_driver.driver); | ||
849 | } | ||
850 | |||
851 | static void __exit alsa_fwspk_exit(void) | ||
852 | { | ||
853 | driver_unregister(&fwspk_driver.driver); | ||
854 | } | ||
855 | |||
856 | module_init(alsa_fwspk_init); | ||
857 | module_exit(alsa_fwspk_exit); | ||