1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Linux driver for TerraTec DMX 6Fire USB |
4 | * |
5 | * PCM driver |
6 | * |
7 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
8 | * Created: Jan 01, 2011 |
9 | * Copyright: (C) Torsten Schenk |
10 | */ |
11 | |
12 | #include "pcm.h" |
13 | #include "chip.h" |
14 | #include "comm.h" |
15 | #include "control.h" |
16 | |
17 | enum { |
18 | OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4 |
19 | }; |
20 | |
21 | /* keep next two synced with |
22 | * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE |
23 | * and CONTROL_RATE_XXX in control.h */ |
24 | static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 }; |
25 | static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 }; |
26 | static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; |
27 | static const int rates_alsaid[] = { |
28 | SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000, |
29 | SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000, |
30 | SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 }; |
31 | |
32 | enum { /* settings for pcm */ |
33 | OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024 |
34 | }; |
35 | |
36 | enum { /* pcm streaming states */ |
37 | STREAM_DISABLED, /* no pcm streaming */ |
38 | STREAM_STARTING, /* pcm streaming requested, waiting to become ready */ |
39 | STREAM_RUNNING, /* pcm streaming running */ |
40 | STREAM_STOPPING |
41 | }; |
42 | |
43 | static const struct snd_pcm_hardware pcm_hw = { |
44 | .info = SNDRV_PCM_INFO_MMAP | |
45 | SNDRV_PCM_INFO_INTERLEAVED | |
46 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
47 | SNDRV_PCM_INFO_MMAP_VALID | |
48 | SNDRV_PCM_INFO_BATCH, |
49 | |
50 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, |
51 | |
52 | .rates = SNDRV_PCM_RATE_44100 | |
53 | SNDRV_PCM_RATE_48000 | |
54 | SNDRV_PCM_RATE_88200 | |
55 | SNDRV_PCM_RATE_96000 | |
56 | SNDRV_PCM_RATE_176400 | |
57 | SNDRV_PCM_RATE_192000, |
58 | |
59 | .rate_min = 44100, |
60 | .rate_max = 192000, |
61 | .channels_min = 1, |
62 | .channels_max = 0, /* set in pcm_open, depending on capture/playback */ |
63 | .buffer_bytes_max = MAX_BUFSIZE, |
64 | .period_bytes_min = PCM_N_PACKETS_PER_URB * (PCM_MAX_PACKET_SIZE - 4), |
65 | .period_bytes_max = MAX_BUFSIZE, |
66 | .periods_min = 2, |
67 | .periods_max = 1024 |
68 | }; |
69 | |
70 | static int usb6fire_pcm_set_rate(struct pcm_runtime *rt) |
71 | { |
72 | int ret; |
73 | struct control_runtime *ctrl_rt = rt->chip->control; |
74 | |
75 | ctrl_rt->usb_streaming = false; |
76 | ret = ctrl_rt->update_streaming(ctrl_rt); |
77 | if (ret < 0) { |
78 | dev_err(&rt->chip->dev->dev, |
79 | "error stopping streaming while setting samplerate %d.\n" , |
80 | rates[rt->rate]); |
81 | return ret; |
82 | } |
83 | |
84 | ret = ctrl_rt->set_rate(ctrl_rt, rt->rate); |
85 | if (ret < 0) { |
86 | dev_err(&rt->chip->dev->dev, |
87 | "error setting samplerate %d.\n" , |
88 | rates[rt->rate]); |
89 | return ret; |
90 | } |
91 | |
92 | ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS, |
93 | false, false); |
94 | if (ret < 0) { |
95 | dev_err(&rt->chip->dev->dev, |
96 | "error initializing channels while setting samplerate %d.\n" , |
97 | rates[rt->rate]); |
98 | return ret; |
99 | } |
100 | |
101 | ctrl_rt->usb_streaming = true; |
102 | ret = ctrl_rt->update_streaming(ctrl_rt); |
103 | if (ret < 0) { |
104 | dev_err(&rt->chip->dev->dev, |
105 | "error starting streaming while setting samplerate %d.\n" , |
106 | rates[rt->rate]); |
107 | return ret; |
108 | } |
109 | |
110 | rt->in_n_analog = IN_N_CHANNELS; |
111 | rt->out_n_analog = OUT_N_CHANNELS; |
112 | rt->in_packet_size = rates_in_packet_size[rt->rate]; |
113 | rt->out_packet_size = rates_out_packet_size[rt->rate]; |
114 | return 0; |
115 | } |
116 | |
117 | static struct pcm_substream *usb6fire_pcm_get_substream( |
118 | struct snd_pcm_substream *alsa_sub) |
119 | { |
120 | struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); |
121 | |
122 | if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) |
123 | return &rt->playback; |
124 | else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) |
125 | return &rt->capture; |
126 | dev_err(&rt->chip->dev->dev, "error getting pcm substream slot.\n" ); |
127 | return NULL; |
128 | } |
129 | |
130 | /* call with stream_mutex locked */ |
131 | static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) |
132 | { |
133 | int i; |
134 | struct control_runtime *ctrl_rt = rt->chip->control; |
135 | |
136 | if (rt->stream_state != STREAM_DISABLED) { |
137 | |
138 | rt->stream_state = STREAM_STOPPING; |
139 | |
140 | for (i = 0; i < PCM_N_URBS; i++) { |
141 | usb_kill_urb(urb: &rt->in_urbs[i].instance); |
142 | usb_kill_urb(urb: &rt->out_urbs[i].instance); |
143 | } |
144 | ctrl_rt->usb_streaming = false; |
145 | ctrl_rt->update_streaming(ctrl_rt); |
146 | rt->stream_state = STREAM_DISABLED; |
147 | } |
148 | } |
149 | |
150 | /* call with stream_mutex locked */ |
151 | static int usb6fire_pcm_stream_start(struct pcm_runtime *rt) |
152 | { |
153 | int ret; |
154 | int i; |
155 | int k; |
156 | struct usb_iso_packet_descriptor *packet; |
157 | |
158 | if (rt->stream_state == STREAM_DISABLED) { |
159 | /* submit our in urbs */ |
160 | rt->stream_wait_cond = false; |
161 | rt->stream_state = STREAM_STARTING; |
162 | for (i = 0; i < PCM_N_URBS; i++) { |
163 | for (k = 0; k < PCM_N_PACKETS_PER_URB; k++) { |
164 | packet = &rt->in_urbs[i].packets[k]; |
165 | packet->offset = k * rt->in_packet_size; |
166 | packet->length = rt->in_packet_size; |
167 | packet->actual_length = 0; |
168 | packet->status = 0; |
169 | } |
170 | ret = usb_submit_urb(urb: &rt->in_urbs[i].instance, |
171 | GFP_ATOMIC); |
172 | if (ret) { |
173 | usb6fire_pcm_stream_stop(rt); |
174 | return ret; |
175 | } |
176 | } |
177 | |
178 | /* wait for first out urb to return (sent in urb handler) */ |
179 | wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond, |
180 | HZ); |
181 | if (rt->stream_wait_cond) |
182 | rt->stream_state = STREAM_RUNNING; |
183 | else { |
184 | usb6fire_pcm_stream_stop(rt); |
185 | return -EIO; |
186 | } |
187 | } |
188 | return 0; |
189 | } |
190 | |
191 | /* call with substream locked */ |
192 | static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) |
193 | { |
194 | int i; |
195 | int frame; |
196 | int frame_count; |
197 | unsigned int total_length = 0; |
198 | struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); |
199 | struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; |
200 | u32 *src = NULL; |
201 | u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off |
202 | * (alsa_rt->frame_bits >> 3)); |
203 | u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size |
204 | * (alsa_rt->frame_bits >> 3)); |
205 | int bytes_per_frame = alsa_rt->channels << 2; |
206 | |
207 | for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { |
208 | /* at least 4 header bytes for valid packet. |
209 | * after that: 32 bits per sample for analog channels */ |
210 | if (urb->packets[i].actual_length > 4) |
211 | frame_count = (urb->packets[i].actual_length - 4) |
212 | / (rt->in_n_analog << 2); |
213 | else |
214 | frame_count = 0; |
215 | |
216 | if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) |
217 | src = (u32 *) (urb->buffer + total_length); |
218 | else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) |
219 | src = (u32 *) (urb->buffer - 1 + total_length); |
220 | else |
221 | return; |
222 | src++; /* skip leading 4 bytes of every packet */ |
223 | total_length += urb->packets[i].length; |
224 | for (frame = 0; frame < frame_count; frame++) { |
225 | memcpy(dest, src, bytes_per_frame); |
226 | dest += alsa_rt->channels; |
227 | src += rt->in_n_analog; |
228 | sub->dma_off++; |
229 | sub->period_off++; |
230 | if (dest == dest_end) { |
231 | sub->dma_off = 0; |
232 | dest = (u32 *) alsa_rt->dma_area; |
233 | } |
234 | } |
235 | } |
236 | } |
237 | |
238 | /* call with substream locked */ |
239 | static void usb6fire_pcm_playback(struct pcm_substream *sub, |
240 | struct pcm_urb *urb) |
241 | { |
242 | int i; |
243 | int frame; |
244 | int frame_count; |
245 | struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); |
246 | struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; |
247 | u32 *src = (u32 *) (alsa_rt->dma_area + sub->dma_off |
248 | * (alsa_rt->frame_bits >> 3)); |
249 | u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size |
250 | * (alsa_rt->frame_bits >> 3)); |
251 | u32 *dest; |
252 | int bytes_per_frame = alsa_rt->channels << 2; |
253 | |
254 | if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) |
255 | dest = (u32 *) (urb->buffer - 1); |
256 | else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) |
257 | dest = (u32 *) (urb->buffer); |
258 | else { |
259 | dev_err(&rt->chip->dev->dev, "Unknown sample format." ); |
260 | return; |
261 | } |
262 | |
263 | for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { |
264 | /* at least 4 header bytes for valid packet. |
265 | * after that: 32 bits per sample for analog channels */ |
266 | if (urb->packets[i].length > 4) |
267 | frame_count = (urb->packets[i].length - 4) |
268 | / (rt->out_n_analog << 2); |
269 | else |
270 | frame_count = 0; |
271 | dest++; /* skip leading 4 bytes of every frame */ |
272 | for (frame = 0; frame < frame_count; frame++) { |
273 | memcpy(dest, src, bytes_per_frame); |
274 | src += alsa_rt->channels; |
275 | dest += rt->out_n_analog; |
276 | sub->dma_off++; |
277 | sub->period_off++; |
278 | if (src == src_end) { |
279 | src = (u32 *) alsa_rt->dma_area; |
280 | sub->dma_off = 0; |
281 | } |
282 | } |
283 | } |
284 | } |
285 | |
286 | static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) |
287 | { |
288 | struct pcm_urb *in_urb = usb_urb->context; |
289 | struct pcm_urb *out_urb = in_urb->peer; |
290 | struct pcm_runtime *rt = in_urb->chip->pcm; |
291 | struct pcm_substream *sub; |
292 | unsigned long flags; |
293 | int total_length = 0; |
294 | int frame_count; |
295 | int frame; |
296 | int channel; |
297 | int i; |
298 | u8 *dest; |
299 | |
300 | if (usb_urb->status || rt->panic || rt->stream_state == STREAM_STOPPING) |
301 | return; |
302 | for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) |
303 | if (in_urb->packets[i].status) { |
304 | rt->panic = true; |
305 | return; |
306 | } |
307 | |
308 | if (rt->stream_state == STREAM_DISABLED) { |
309 | dev_err(&rt->chip->dev->dev, |
310 | "internal error: stream disabled in in-urb handler.\n" ); |
311 | return; |
312 | } |
313 | |
314 | /* receive our capture data */ |
315 | sub = &rt->capture; |
316 | spin_lock_irqsave(&sub->lock, flags); |
317 | if (sub->active) { |
318 | usb6fire_pcm_capture(sub, urb: in_urb); |
319 | if (sub->period_off >= sub->instance->runtime->period_size) { |
320 | sub->period_off %= sub->instance->runtime->period_size; |
321 | spin_unlock_irqrestore(lock: &sub->lock, flags); |
322 | snd_pcm_period_elapsed(substream: sub->instance); |
323 | } else |
324 | spin_unlock_irqrestore(lock: &sub->lock, flags); |
325 | } else |
326 | spin_unlock_irqrestore(lock: &sub->lock, flags); |
327 | |
328 | /* setup out urb structure */ |
329 | for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { |
330 | out_urb->packets[i].offset = total_length; |
331 | out_urb->packets[i].length = (in_urb->packets[i].actual_length |
332 | - 4) / (rt->in_n_analog << 2) |
333 | * (rt->out_n_analog << 2) + 4; |
334 | out_urb->packets[i].status = 0; |
335 | total_length += out_urb->packets[i].length; |
336 | } |
337 | memset(out_urb->buffer, 0, total_length); |
338 | |
339 | /* now send our playback data (if a free out urb was found) */ |
340 | sub = &rt->playback; |
341 | spin_lock_irqsave(&sub->lock, flags); |
342 | if (sub->active) { |
343 | usb6fire_pcm_playback(sub, urb: out_urb); |
344 | if (sub->period_off >= sub->instance->runtime->period_size) { |
345 | sub->period_off %= sub->instance->runtime->period_size; |
346 | spin_unlock_irqrestore(lock: &sub->lock, flags); |
347 | snd_pcm_period_elapsed(substream: sub->instance); |
348 | } else |
349 | spin_unlock_irqrestore(lock: &sub->lock, flags); |
350 | } else |
351 | spin_unlock_irqrestore(lock: &sub->lock, flags); |
352 | |
353 | /* setup the 4th byte of each sample (0x40 for analog channels) */ |
354 | dest = out_urb->buffer; |
355 | for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) |
356 | if (out_urb->packets[i].length >= 4) { |
357 | frame_count = (out_urb->packets[i].length - 4) |
358 | / (rt->out_n_analog << 2); |
359 | *(dest++) = 0xaa; |
360 | *(dest++) = 0xaa; |
361 | *(dest++) = frame_count; |
362 | *(dest++) = 0x00; |
363 | for (frame = 0; frame < frame_count; frame++) |
364 | for (channel = 0; |
365 | channel < rt->out_n_analog; |
366 | channel++) { |
367 | dest += 3; /* skip sample data */ |
368 | *(dest++) = 0x40; |
369 | } |
370 | } |
371 | usb_submit_urb(urb: &out_urb->instance, GFP_ATOMIC); |
372 | usb_submit_urb(urb: &in_urb->instance, GFP_ATOMIC); |
373 | } |
374 | |
375 | static void usb6fire_pcm_out_urb_handler(struct urb *usb_urb) |
376 | { |
377 | struct pcm_urb *urb = usb_urb->context; |
378 | struct pcm_runtime *rt = urb->chip->pcm; |
379 | |
380 | if (rt->stream_state == STREAM_STARTING) { |
381 | rt->stream_wait_cond = true; |
382 | wake_up(&rt->stream_wait_queue); |
383 | } |
384 | } |
385 | |
386 | static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub) |
387 | { |
388 | struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); |
389 | struct pcm_substream *sub = NULL; |
390 | struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; |
391 | |
392 | if (rt->panic) |
393 | return -EPIPE; |
394 | |
395 | mutex_lock(&rt->stream_mutex); |
396 | alsa_rt->hw = pcm_hw; |
397 | |
398 | if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
399 | if (rt->rate < ARRAY_SIZE(rates)) |
400 | alsa_rt->hw.rates = rates_alsaid[rt->rate]; |
401 | alsa_rt->hw.channels_max = OUT_N_CHANNELS; |
402 | sub = &rt->playback; |
403 | } else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) { |
404 | if (rt->rate < ARRAY_SIZE(rates)) |
405 | alsa_rt->hw.rates = rates_alsaid[rt->rate]; |
406 | alsa_rt->hw.channels_max = IN_N_CHANNELS; |
407 | sub = &rt->capture; |
408 | } |
409 | |
410 | if (!sub) { |
411 | mutex_unlock(lock: &rt->stream_mutex); |
412 | dev_err(&rt->chip->dev->dev, "invalid stream type.\n" ); |
413 | return -EINVAL; |
414 | } |
415 | |
416 | sub->instance = alsa_sub; |
417 | sub->active = false; |
418 | mutex_unlock(lock: &rt->stream_mutex); |
419 | return 0; |
420 | } |
421 | |
422 | static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) |
423 | { |
424 | struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); |
425 | struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); |
426 | unsigned long flags; |
427 | |
428 | if (rt->panic) |
429 | return 0; |
430 | |
431 | mutex_lock(&rt->stream_mutex); |
432 | if (sub) { |
433 | /* deactivate substream */ |
434 | spin_lock_irqsave(&sub->lock, flags); |
435 | sub->instance = NULL; |
436 | sub->active = false; |
437 | spin_unlock_irqrestore(lock: &sub->lock, flags); |
438 | |
439 | /* all substreams closed? if so, stop streaming */ |
440 | if (!rt->playback.instance && !rt->capture.instance) { |
441 | usb6fire_pcm_stream_stop(rt); |
442 | rt->rate = ARRAY_SIZE(rates); |
443 | } |
444 | } |
445 | mutex_unlock(lock: &rt->stream_mutex); |
446 | return 0; |
447 | } |
448 | |
449 | static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) |
450 | { |
451 | struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); |
452 | struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); |
453 | struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; |
454 | int ret; |
455 | |
456 | if (rt->panic) |
457 | return -EPIPE; |
458 | if (!sub) |
459 | return -ENODEV; |
460 | |
461 | mutex_lock(&rt->stream_mutex); |
462 | sub->dma_off = 0; |
463 | sub->period_off = 0; |
464 | |
465 | if (rt->stream_state == STREAM_DISABLED) { |
466 | for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++) |
467 | if (alsa_rt->rate == rates[rt->rate]) |
468 | break; |
469 | if (rt->rate == ARRAY_SIZE(rates)) { |
470 | mutex_unlock(lock: &rt->stream_mutex); |
471 | dev_err(&rt->chip->dev->dev, |
472 | "invalid rate %d in prepare.\n" , |
473 | alsa_rt->rate); |
474 | return -EINVAL; |
475 | } |
476 | |
477 | ret = usb6fire_pcm_set_rate(rt); |
478 | if (ret) { |
479 | mutex_unlock(lock: &rt->stream_mutex); |
480 | return ret; |
481 | } |
482 | ret = usb6fire_pcm_stream_start(rt); |
483 | if (ret) { |
484 | mutex_unlock(lock: &rt->stream_mutex); |
485 | dev_err(&rt->chip->dev->dev, |
486 | "could not start pcm stream.\n" ); |
487 | return ret; |
488 | } |
489 | } |
490 | mutex_unlock(lock: &rt->stream_mutex); |
491 | return 0; |
492 | } |
493 | |
494 | static int usb6fire_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd) |
495 | { |
496 | struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); |
497 | struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); |
498 | unsigned long flags; |
499 | |
500 | if (rt->panic) |
501 | return -EPIPE; |
502 | if (!sub) |
503 | return -ENODEV; |
504 | |
505 | switch (cmd) { |
506 | case SNDRV_PCM_TRIGGER_START: |
507 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
508 | spin_lock_irqsave(&sub->lock, flags); |
509 | sub->active = true; |
510 | spin_unlock_irqrestore(lock: &sub->lock, flags); |
511 | return 0; |
512 | |
513 | case SNDRV_PCM_TRIGGER_STOP: |
514 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
515 | spin_lock_irqsave(&sub->lock, flags); |
516 | sub->active = false; |
517 | spin_unlock_irqrestore(lock: &sub->lock, flags); |
518 | return 0; |
519 | |
520 | default: |
521 | return -EINVAL; |
522 | } |
523 | } |
524 | |
525 | static snd_pcm_uframes_t usb6fire_pcm_pointer( |
526 | struct snd_pcm_substream *alsa_sub) |
527 | { |
528 | struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); |
529 | struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); |
530 | unsigned long flags; |
531 | snd_pcm_uframes_t ret; |
532 | |
533 | if (rt->panic || !sub) |
534 | return SNDRV_PCM_POS_XRUN; |
535 | |
536 | spin_lock_irqsave(&sub->lock, flags); |
537 | ret = sub->dma_off; |
538 | spin_unlock_irqrestore(lock: &sub->lock, flags); |
539 | return ret; |
540 | } |
541 | |
542 | static const struct snd_pcm_ops pcm_ops = { |
543 | .open = usb6fire_pcm_open, |
544 | .close = usb6fire_pcm_close, |
545 | .prepare = usb6fire_pcm_prepare, |
546 | .trigger = usb6fire_pcm_trigger, |
547 | .pointer = usb6fire_pcm_pointer, |
548 | }; |
549 | |
550 | static void usb6fire_pcm_init_urb(struct pcm_urb *urb, |
551 | struct sfire_chip *chip, bool in, int ep, |
552 | void (*handler)(struct urb *)) |
553 | { |
554 | urb->chip = chip; |
555 | usb_init_urb(urb: &urb->instance); |
556 | urb->instance.transfer_buffer = urb->buffer; |
557 | urb->instance.transfer_buffer_length = |
558 | PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE; |
559 | urb->instance.dev = chip->dev; |
560 | urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep) |
561 | : usb_sndisocpipe(chip->dev, ep); |
562 | urb->instance.interval = 1; |
563 | urb->instance.complete = handler; |
564 | urb->instance.context = urb; |
565 | urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB; |
566 | } |
567 | |
568 | static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt) |
569 | { |
570 | int i; |
571 | |
572 | for (i = 0; i < PCM_N_URBS; i++) { |
573 | rt->out_urbs[i].buffer = kcalloc(n: PCM_MAX_PACKET_SIZE, |
574 | size: PCM_N_PACKETS_PER_URB, |
575 | GFP_KERNEL); |
576 | if (!rt->out_urbs[i].buffer) |
577 | return -ENOMEM; |
578 | rt->in_urbs[i].buffer = kcalloc(n: PCM_MAX_PACKET_SIZE, |
579 | size: PCM_N_PACKETS_PER_URB, |
580 | GFP_KERNEL); |
581 | if (!rt->in_urbs[i].buffer) |
582 | return -ENOMEM; |
583 | } |
584 | return 0; |
585 | } |
586 | |
587 | static void usb6fire_pcm_buffers_destroy(struct pcm_runtime *rt) |
588 | { |
589 | int i; |
590 | |
591 | for (i = 0; i < PCM_N_URBS; i++) { |
592 | kfree(objp: rt->out_urbs[i].buffer); |
593 | kfree(objp: rt->in_urbs[i].buffer); |
594 | } |
595 | } |
596 | |
597 | int usb6fire_pcm_init(struct sfire_chip *chip) |
598 | { |
599 | int i; |
600 | int ret; |
601 | struct snd_pcm *pcm; |
602 | struct pcm_runtime *rt = |
603 | kzalloc(size: sizeof(struct pcm_runtime), GFP_KERNEL); |
604 | |
605 | if (!rt) |
606 | return -ENOMEM; |
607 | |
608 | ret = usb6fire_pcm_buffers_init(rt); |
609 | if (ret) { |
610 | usb6fire_pcm_buffers_destroy(rt); |
611 | kfree(objp: rt); |
612 | return ret; |
613 | } |
614 | |
615 | rt->chip = chip; |
616 | rt->stream_state = STREAM_DISABLED; |
617 | rt->rate = ARRAY_SIZE(rates); |
618 | init_waitqueue_head(&rt->stream_wait_queue); |
619 | mutex_init(&rt->stream_mutex); |
620 | |
621 | spin_lock_init(&rt->playback.lock); |
622 | spin_lock_init(&rt->capture.lock); |
623 | |
624 | for (i = 0; i < PCM_N_URBS; i++) { |
625 | usb6fire_pcm_init_urb(urb: &rt->in_urbs[i], chip, in: true, ep: IN_EP, |
626 | handler: usb6fire_pcm_in_urb_handler); |
627 | usb6fire_pcm_init_urb(urb: &rt->out_urbs[i], chip, in: false, ep: OUT_EP, |
628 | handler: usb6fire_pcm_out_urb_handler); |
629 | |
630 | rt->in_urbs[i].peer = &rt->out_urbs[i]; |
631 | rt->out_urbs[i].peer = &rt->in_urbs[i]; |
632 | } |
633 | |
634 | ret = snd_pcm_new(card: chip->card, id: "DMX6FireUSB" , device: 0, playback_count: 1, capture_count: 1, rpcm: &pcm); |
635 | if (ret < 0) { |
636 | usb6fire_pcm_buffers_destroy(rt); |
637 | kfree(objp: rt); |
638 | dev_err(&chip->dev->dev, "cannot create pcm instance.\n" ); |
639 | return ret; |
640 | } |
641 | |
642 | pcm->private_data = rt; |
643 | strcpy(p: pcm->name, q: "DMX 6Fire USB" ); |
644 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_PLAYBACK, ops: &pcm_ops); |
645 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_CAPTURE, ops: &pcm_ops); |
646 | snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, size: 0, max: 0); |
647 | |
648 | rt->instance = pcm; |
649 | |
650 | chip->pcm = rt; |
651 | return 0; |
652 | } |
653 | |
654 | void usb6fire_pcm_abort(struct sfire_chip *chip) |
655 | { |
656 | struct pcm_runtime *rt = chip->pcm; |
657 | int i; |
658 | |
659 | if (rt) { |
660 | rt->panic = true; |
661 | |
662 | if (rt->playback.instance) |
663 | snd_pcm_stop_xrun(substream: rt->playback.instance); |
664 | |
665 | if (rt->capture.instance) |
666 | snd_pcm_stop_xrun(substream: rt->capture.instance); |
667 | |
668 | for (i = 0; i < PCM_N_URBS; i++) { |
669 | usb_poison_urb(urb: &rt->in_urbs[i].instance); |
670 | usb_poison_urb(urb: &rt->out_urbs[i].instance); |
671 | } |
672 | |
673 | } |
674 | } |
675 | |
676 | void usb6fire_pcm_destroy(struct sfire_chip *chip) |
677 | { |
678 | struct pcm_runtime *rt = chip->pcm; |
679 | |
680 | usb6fire_pcm_buffers_destroy(rt); |
681 | kfree(objp: rt); |
682 | chip->pcm = NULL; |
683 | } |
684 | |