1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * US-X2Y AUDIO |
4 | * Copyright (c) 2002-2004 by Karsten Wiese |
5 | * |
6 | * based on |
7 | * |
8 | * (Tentative) USB Audio Driver for ALSA |
9 | * |
10 | * Main and PCM part |
11 | * |
12 | * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> |
13 | * |
14 | * Many codes borrowed from audio.c by |
15 | * Alan Cox (alan@lxorguk.ukuu.org.uk) |
16 | * Thomas Sailer (sailer@ife.ee.ethz.ch) |
17 | */ |
18 | |
19 | |
20 | #include <linux/interrupt.h> |
21 | #include <linux/slab.h> |
22 | #include <linux/usb.h> |
23 | #include <linux/moduleparam.h> |
24 | #include <sound/core.h> |
25 | #include <sound/info.h> |
26 | #include <sound/pcm.h> |
27 | #include <sound/pcm_params.h> |
28 | #include "usx2y.h" |
29 | #include "usbusx2y.h" |
30 | |
31 | /* Default value used for nr of packs per urb. |
32 | * 1 to 4 have been tested ok on uhci. |
33 | * To use 3 on ohci, you'd need a patch: |
34 | * look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on |
35 | * "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425" |
36 | * |
37 | * 1, 2 and 4 work out of the box on ohci, if I recall correctly. |
38 | * Bigger is safer operation, smaller gives lower latencies. |
39 | */ |
40 | #define USX2Y_NRPACKS 4 |
41 | |
42 | /* If your system works ok with this module's parameter |
43 | * nrpacks set to 1, you might as well comment |
44 | * this define out, and thereby produce smaller, faster code. |
45 | * You'd also set USX2Y_NRPACKS to 1 then. |
46 | */ |
47 | #define USX2Y_NRPACKS_VARIABLE 1 |
48 | |
49 | #ifdef USX2Y_NRPACKS_VARIABLE |
50 | static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */ |
51 | #define nr_of_packs() nrpacks |
52 | module_param(nrpacks, int, 0444); |
53 | MODULE_PARM_DESC(nrpacks, "Number of packets per URB." ); |
54 | #else |
55 | #define nr_of_packs() USX2Y_NRPACKS |
56 | #endif |
57 | |
58 | static int usx2y_urb_capt_retire(struct snd_usx2y_substream *subs) |
59 | { |
60 | struct urb *urb = subs->completed_urb; |
61 | struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; |
62 | unsigned char *cp; |
63 | int i, len, lens = 0, hwptr_done = subs->hwptr_done; |
64 | int cnt, blen; |
65 | struct usx2ydev *usx2y = subs->usx2y; |
66 | |
67 | for (i = 0; i < nr_of_packs(); i++) { |
68 | cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; |
69 | if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ |
70 | snd_printk(KERN_ERR |
71 | "active frame status %i. Most probably some hardware problem.\n" , |
72 | urb->iso_frame_desc[i].status); |
73 | return urb->iso_frame_desc[i].status; |
74 | } |
75 | len = urb->iso_frame_desc[i].actual_length / usx2y->stride; |
76 | if (!len) { |
77 | snd_printd("0 == len ERROR!\n" ); |
78 | continue; |
79 | } |
80 | |
81 | /* copy a data chunk */ |
82 | if ((hwptr_done + len) > runtime->buffer_size) { |
83 | cnt = runtime->buffer_size - hwptr_done; |
84 | blen = cnt * usx2y->stride; |
85 | memcpy(runtime->dma_area + hwptr_done * usx2y->stride, cp, blen); |
86 | memcpy(runtime->dma_area, cp + blen, len * usx2y->stride - blen); |
87 | } else { |
88 | memcpy(runtime->dma_area + hwptr_done * usx2y->stride, cp, |
89 | len * usx2y->stride); |
90 | } |
91 | lens += len; |
92 | hwptr_done += len; |
93 | if (hwptr_done >= runtime->buffer_size) |
94 | hwptr_done -= runtime->buffer_size; |
95 | } |
96 | |
97 | subs->hwptr_done = hwptr_done; |
98 | subs->transfer_done += lens; |
99 | /* update the pointer, call callback if necessary */ |
100 | if (subs->transfer_done >= runtime->period_size) { |
101 | subs->transfer_done -= runtime->period_size; |
102 | snd_pcm_period_elapsed(substream: subs->pcm_substream); |
103 | } |
104 | return 0; |
105 | } |
106 | |
107 | /* |
108 | * prepare urb for playback data pipe |
109 | * |
110 | * we copy the data directly from the pcm buffer. |
111 | * the current position to be copied is held in hwptr field. |
112 | * since a urb can handle only a single linear buffer, if the total |
113 | * transferred area overflows the buffer boundary, we cannot send |
114 | * it directly from the buffer. thus the data is once copied to |
115 | * a temporary buffer and urb points to that. |
116 | */ |
117 | static int usx2y_urb_play_prepare(struct snd_usx2y_substream *subs, |
118 | struct urb *cap_urb, |
119 | struct urb *urb) |
120 | { |
121 | struct usx2ydev *usx2y = subs->usx2y; |
122 | struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; |
123 | int count, counts, pack, len; |
124 | |
125 | count = 0; |
126 | for (pack = 0; pack < nr_of_packs(); pack++) { |
127 | /* calculate the size of a packet */ |
128 | counts = cap_urb->iso_frame_desc[pack].actual_length / usx2y->stride; |
129 | count += counts; |
130 | if (counts < 43 || counts > 50) { |
131 | snd_printk(KERN_ERR "should not be here with counts=%i\n" , counts); |
132 | return -EPIPE; |
133 | } |
134 | /* set up descriptor */ |
135 | urb->iso_frame_desc[pack].offset = pack ? |
136 | urb->iso_frame_desc[pack - 1].offset + |
137 | urb->iso_frame_desc[pack - 1].length : |
138 | 0; |
139 | urb->iso_frame_desc[pack].length = cap_urb->iso_frame_desc[pack].actual_length; |
140 | } |
141 | if (atomic_read(v: &subs->state) >= STATE_PRERUNNING) { |
142 | if (subs->hwptr + count > runtime->buffer_size) { |
143 | /* err, the transferred area goes over buffer boundary. |
144 | * copy the data to the temp buffer. |
145 | */ |
146 | len = runtime->buffer_size - subs->hwptr; |
147 | urb->transfer_buffer = subs->tmpbuf; |
148 | memcpy(subs->tmpbuf, runtime->dma_area + |
149 | subs->hwptr * usx2y->stride, len * usx2y->stride); |
150 | memcpy(subs->tmpbuf + len * usx2y->stride, |
151 | runtime->dma_area, (count - len) * usx2y->stride); |
152 | subs->hwptr += count; |
153 | subs->hwptr -= runtime->buffer_size; |
154 | } else { |
155 | /* set the buffer pointer */ |
156 | urb->transfer_buffer = runtime->dma_area + subs->hwptr * usx2y->stride; |
157 | subs->hwptr += count; |
158 | if (subs->hwptr >= runtime->buffer_size) |
159 | subs->hwptr -= runtime->buffer_size; |
160 | } |
161 | } else { |
162 | urb->transfer_buffer = subs->tmpbuf; |
163 | } |
164 | urb->transfer_buffer_length = count * usx2y->stride; |
165 | return 0; |
166 | } |
167 | |
168 | /* |
169 | * process after playback data complete |
170 | * |
171 | * update the current position and call callback if a period is processed. |
172 | */ |
173 | static void usx2y_urb_play_retire(struct snd_usx2y_substream *subs, struct urb *urb) |
174 | { |
175 | struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; |
176 | int len = urb->actual_length / subs->usx2y->stride; |
177 | |
178 | subs->transfer_done += len; |
179 | subs->hwptr_done += len; |
180 | if (subs->hwptr_done >= runtime->buffer_size) |
181 | subs->hwptr_done -= runtime->buffer_size; |
182 | if (subs->transfer_done >= runtime->period_size) { |
183 | subs->transfer_done -= runtime->period_size; |
184 | snd_pcm_period_elapsed(substream: subs->pcm_substream); |
185 | } |
186 | } |
187 | |
188 | static int usx2y_urb_submit(struct snd_usx2y_substream *subs, struct urb *urb, int frame) |
189 | { |
190 | int err; |
191 | |
192 | if (!urb) |
193 | return -ENODEV; |
194 | urb->start_frame = frame + NRURBS * nr_of_packs(); // let hcd do rollover sanity checks |
195 | urb->hcpriv = NULL; |
196 | urb->dev = subs->usx2y->dev; /* we need to set this at each time */ |
197 | err = usb_submit_urb(urb, GFP_ATOMIC); |
198 | if (err < 0) { |
199 | snd_printk(KERN_ERR "usb_submit_urb() returned %i\n" , err); |
200 | return err; |
201 | } |
202 | return 0; |
203 | } |
204 | |
205 | static int usx2y_usbframe_complete(struct snd_usx2y_substream *capsubs, |
206 | struct snd_usx2y_substream *playbacksubs, |
207 | int frame) |
208 | { |
209 | int err, state; |
210 | struct urb *urb = playbacksubs->completed_urb; |
211 | |
212 | state = atomic_read(v: &playbacksubs->state); |
213 | if (urb) { |
214 | if (state == STATE_RUNNING) |
215 | usx2y_urb_play_retire(subs: playbacksubs, urb); |
216 | else if (state >= STATE_PRERUNNING) |
217 | atomic_inc(v: &playbacksubs->state); |
218 | } else { |
219 | switch (state) { |
220 | case STATE_STARTING1: |
221 | urb = playbacksubs->urb[0]; |
222 | atomic_inc(v: &playbacksubs->state); |
223 | break; |
224 | case STATE_STARTING2: |
225 | urb = playbacksubs->urb[1]; |
226 | atomic_inc(v: &playbacksubs->state); |
227 | break; |
228 | } |
229 | } |
230 | if (urb) { |
231 | err = usx2y_urb_play_prepare(subs: playbacksubs, cap_urb: capsubs->completed_urb, urb); |
232 | if (err) |
233 | return err; |
234 | err = usx2y_urb_submit(subs: playbacksubs, urb, frame); |
235 | if (err) |
236 | return err; |
237 | } |
238 | |
239 | playbacksubs->completed_urb = NULL; |
240 | |
241 | state = atomic_read(v: &capsubs->state); |
242 | if (state >= STATE_PREPARED) { |
243 | if (state == STATE_RUNNING) { |
244 | err = usx2y_urb_capt_retire(subs: capsubs); |
245 | if (err) |
246 | return err; |
247 | } else if (state >= STATE_PRERUNNING) { |
248 | atomic_inc(v: &capsubs->state); |
249 | } |
250 | err = usx2y_urb_submit(subs: capsubs, urb: capsubs->completed_urb, frame); |
251 | if (err) |
252 | return err; |
253 | } |
254 | capsubs->completed_urb = NULL; |
255 | return 0; |
256 | } |
257 | |
258 | static void usx2y_clients_stop(struct usx2ydev *usx2y) |
259 | { |
260 | struct snd_usx2y_substream *subs; |
261 | struct urb *urb; |
262 | int s, u; |
263 | |
264 | for (s = 0; s < 4; s++) { |
265 | subs = usx2y->subs[s]; |
266 | if (subs) { |
267 | snd_printdd("%i %p state=%i\n" , s, subs, atomic_read(&subs->state)); |
268 | atomic_set(v: &subs->state, STATE_STOPPED); |
269 | } |
270 | } |
271 | for (s = 0; s < 4; s++) { |
272 | subs = usx2y->subs[s]; |
273 | if (subs) { |
274 | if (atomic_read(v: &subs->state) >= STATE_PRERUNNING) |
275 | snd_pcm_stop_xrun(substream: subs->pcm_substream); |
276 | for (u = 0; u < NRURBS; u++) { |
277 | urb = subs->urb[u]; |
278 | if (urb) |
279 | snd_printdd("%i status=%i start_frame=%i\n" , |
280 | u, urb->status, urb->start_frame); |
281 | } |
282 | } |
283 | } |
284 | usx2y->prepare_subs = NULL; |
285 | wake_up(&usx2y->prepare_wait_queue); |
286 | } |
287 | |
288 | static void usx2y_error_urb_status(struct usx2ydev *usx2y, |
289 | struct snd_usx2y_substream *subs, struct urb *urb) |
290 | { |
291 | snd_printk(KERN_ERR "ep=%i stalled with status=%i\n" , subs->endpoint, urb->status); |
292 | urb->status = 0; |
293 | usx2y_clients_stop(usx2y); |
294 | } |
295 | |
296 | static void i_usx2y_urb_complete(struct urb *urb) |
297 | { |
298 | struct snd_usx2y_substream *subs = urb->context; |
299 | struct usx2ydev *usx2y = subs->usx2y; |
300 | struct snd_usx2y_substream *capsubs, *playbacksubs; |
301 | |
302 | if (unlikely(atomic_read(&subs->state) < STATE_PREPARED)) { |
303 | snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n" , |
304 | usb_get_current_frame_number(usx2y->dev), |
305 | subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out" , |
306 | urb->status, urb->start_frame); |
307 | return; |
308 | } |
309 | if (unlikely(urb->status)) { |
310 | usx2y_error_urb_status(usx2y, subs, urb); |
311 | return; |
312 | } |
313 | |
314 | subs->completed_urb = urb; |
315 | |
316 | capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]; |
317 | playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]; |
318 | |
319 | if (capsubs->completed_urb && |
320 | atomic_read(v: &capsubs->state) >= STATE_PREPARED && |
321 | (playbacksubs->completed_urb || |
322 | atomic_read(v: &playbacksubs->state) < STATE_PREPARED)) { |
323 | if (!usx2y_usbframe_complete(capsubs, playbacksubs, frame: urb->start_frame)) { |
324 | usx2y->wait_iso_frame += nr_of_packs(); |
325 | } else { |
326 | snd_printdd("\n" ); |
327 | usx2y_clients_stop(usx2y); |
328 | } |
329 | } |
330 | } |
331 | |
332 | static void usx2y_urbs_set_complete(struct usx2ydev *usx2y, |
333 | void (*complete)(struct urb *)) |
334 | { |
335 | struct snd_usx2y_substream *subs; |
336 | struct urb *urb; |
337 | int s, u; |
338 | |
339 | for (s = 0; s < 4; s++) { |
340 | subs = usx2y->subs[s]; |
341 | if (subs) { |
342 | for (u = 0; u < NRURBS; u++) { |
343 | urb = subs->urb[u]; |
344 | if (urb) |
345 | urb->complete = complete; |
346 | } |
347 | } |
348 | } |
349 | } |
350 | |
351 | static void usx2y_subs_startup_finish(struct usx2ydev *usx2y) |
352 | { |
353 | usx2y_urbs_set_complete(usx2y, complete: i_usx2y_urb_complete); |
354 | usx2y->prepare_subs = NULL; |
355 | } |
356 | |
357 | static void i_usx2y_subs_startup(struct urb *urb) |
358 | { |
359 | struct snd_usx2y_substream *subs = urb->context; |
360 | struct usx2ydev *usx2y = subs->usx2y; |
361 | struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs; |
362 | |
363 | if (prepare_subs) { |
364 | if (urb->start_frame == prepare_subs->urb[0]->start_frame) { |
365 | usx2y_subs_startup_finish(usx2y); |
366 | atomic_inc(v: &prepare_subs->state); |
367 | wake_up(&usx2y->prepare_wait_queue); |
368 | } |
369 | } |
370 | |
371 | i_usx2y_urb_complete(urb); |
372 | } |
373 | |
374 | static void usx2y_subs_prepare(struct snd_usx2y_substream *subs) |
375 | { |
376 | snd_printdd("usx2y_substream_prepare(%p) ep=%i urb0=%p urb1=%p\n" , |
377 | subs, subs->endpoint, subs->urb[0], subs->urb[1]); |
378 | /* reset the pointer */ |
379 | subs->hwptr = 0; |
380 | subs->hwptr_done = 0; |
381 | subs->transfer_done = 0; |
382 | } |
383 | |
384 | static void usx2y_urb_release(struct urb **urb, int free_tb) |
385 | { |
386 | if (*urb) { |
387 | usb_kill_urb(urb: *urb); |
388 | if (free_tb) |
389 | kfree(objp: (*urb)->transfer_buffer); |
390 | usb_free_urb(urb: *urb); |
391 | *urb = NULL; |
392 | } |
393 | } |
394 | |
395 | /* |
396 | * release a substreams urbs |
397 | */ |
398 | static void usx2y_urbs_release(struct snd_usx2y_substream *subs) |
399 | { |
400 | int i; |
401 | |
402 | snd_printdd("%s %i\n" , __func__, subs->endpoint); |
403 | for (i = 0; i < NRURBS; i++) |
404 | usx2y_urb_release(urb: subs->urb + i, |
405 | free_tb: subs != subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]); |
406 | |
407 | kfree(objp: subs->tmpbuf); |
408 | subs->tmpbuf = NULL; |
409 | } |
410 | |
411 | /* |
412 | * initialize a substream's urbs |
413 | */ |
414 | static int usx2y_urbs_allocate(struct snd_usx2y_substream *subs) |
415 | { |
416 | int i; |
417 | unsigned int pipe; |
418 | int is_playback = subs == subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]; |
419 | struct usb_device *dev = subs->usx2y->dev; |
420 | struct urb **purb; |
421 | |
422 | pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : |
423 | usb_rcvisocpipe(dev, subs->endpoint); |
424 | subs->maxpacksize = usb_maxpacket(udev: dev, pipe); |
425 | if (!subs->maxpacksize) |
426 | return -EINVAL; |
427 | |
428 | if (is_playback && !subs->tmpbuf) { /* allocate a temporary buffer for playback */ |
429 | subs->tmpbuf = kcalloc(nr_of_packs(), size: subs->maxpacksize, GFP_KERNEL); |
430 | if (!subs->tmpbuf) |
431 | return -ENOMEM; |
432 | } |
433 | /* allocate and initialize data urbs */ |
434 | for (i = 0; i < NRURBS; i++) { |
435 | purb = subs->urb + i; |
436 | if (*purb) { |
437 | usb_kill_urb(urb: *purb); |
438 | continue; |
439 | } |
440 | *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL); |
441 | if (!*purb) { |
442 | usx2y_urbs_release(subs); |
443 | return -ENOMEM; |
444 | } |
445 | if (!is_playback && !(*purb)->transfer_buffer) { |
446 | /* allocate a capture buffer per urb */ |
447 | (*purb)->transfer_buffer = |
448 | kmalloc_array(n: subs->maxpacksize, |
449 | nr_of_packs(), GFP_KERNEL); |
450 | if (!(*purb)->transfer_buffer) { |
451 | usx2y_urbs_release(subs); |
452 | return -ENOMEM; |
453 | } |
454 | } |
455 | (*purb)->dev = dev; |
456 | (*purb)->pipe = pipe; |
457 | (*purb)->number_of_packets = nr_of_packs(); |
458 | (*purb)->context = subs; |
459 | (*purb)->interval = 1; |
460 | (*purb)->complete = i_usx2y_subs_startup; |
461 | } |
462 | return 0; |
463 | } |
464 | |
465 | static void usx2y_subs_startup(struct snd_usx2y_substream *subs) |
466 | { |
467 | struct usx2ydev *usx2y = subs->usx2y; |
468 | |
469 | usx2y->prepare_subs = subs; |
470 | subs->urb[0]->start_frame = -1; |
471 | wmb(); |
472 | usx2y_urbs_set_complete(usx2y, complete: i_usx2y_subs_startup); |
473 | } |
474 | |
475 | static int usx2y_urbs_start(struct snd_usx2y_substream *subs) |
476 | { |
477 | int i, err; |
478 | struct usx2ydev *usx2y = subs->usx2y; |
479 | struct urb *urb; |
480 | unsigned long pack; |
481 | |
482 | err = usx2y_urbs_allocate(subs); |
483 | if (err < 0) |
484 | return err; |
485 | subs->completed_urb = NULL; |
486 | for (i = 0; i < 4; i++) { |
487 | struct snd_usx2y_substream *subs = usx2y->subs[i]; |
488 | |
489 | if (subs && atomic_read(v: &subs->state) >= STATE_PREPARED) |
490 | goto start; |
491 | } |
492 | |
493 | start: |
494 | usx2y_subs_startup(subs); |
495 | for (i = 0; i < NRURBS; i++) { |
496 | urb = subs->urb[i]; |
497 | if (usb_pipein(urb->pipe)) { |
498 | if (!i) |
499 | atomic_set(v: &subs->state, STATE_STARTING3); |
500 | urb->dev = usx2y->dev; |
501 | for (pack = 0; pack < nr_of_packs(); pack++) { |
502 | urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack; |
503 | urb->iso_frame_desc[pack].length = subs->maxpacksize; |
504 | } |
505 | urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); |
506 | err = usb_submit_urb(urb, GFP_ATOMIC); |
507 | if (err < 0) { |
508 | snd_printk(KERN_ERR "cannot submit datapipe for urb %d, err = %d\n" , i, err); |
509 | err = -EPIPE; |
510 | goto cleanup; |
511 | } else { |
512 | if (!i) |
513 | usx2y->wait_iso_frame = urb->start_frame; |
514 | } |
515 | urb->transfer_flags = 0; |
516 | } else { |
517 | atomic_set(v: &subs->state, STATE_STARTING1); |
518 | break; |
519 | } |
520 | } |
521 | err = 0; |
522 | wait_event(usx2y->prepare_wait_queue, !usx2y->prepare_subs); |
523 | if (atomic_read(v: &subs->state) != STATE_PREPARED) |
524 | err = -EPIPE; |
525 | |
526 | cleanup: |
527 | if (err) { |
528 | usx2y_subs_startup_finish(usx2y); |
529 | usx2y_clients_stop(usx2y); // something is completely wrong > stop everything |
530 | } |
531 | return err; |
532 | } |
533 | |
534 | /* |
535 | * return the current pcm pointer. just return the hwptr_done value. |
536 | */ |
537 | static snd_pcm_uframes_t snd_usx2y_pcm_pointer(struct snd_pcm_substream *substream) |
538 | { |
539 | struct snd_usx2y_substream *subs = substream->runtime->private_data; |
540 | |
541 | return subs->hwptr_done; |
542 | } |
543 | |
544 | /* |
545 | * start/stop substream |
546 | */ |
547 | static int snd_usx2y_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
548 | { |
549 | struct snd_usx2y_substream *subs = substream->runtime->private_data; |
550 | |
551 | switch (cmd) { |
552 | case SNDRV_PCM_TRIGGER_START: |
553 | snd_printdd("%s(START)\n" , __func__); |
554 | if (atomic_read(v: &subs->state) == STATE_PREPARED && |
555 | atomic_read(v: &subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]->state) >= STATE_PREPARED) { |
556 | atomic_set(v: &subs->state, STATE_PRERUNNING); |
557 | } else { |
558 | snd_printdd("\n" ); |
559 | return -EPIPE; |
560 | } |
561 | break; |
562 | case SNDRV_PCM_TRIGGER_STOP: |
563 | snd_printdd("%s(STOP)\n" , __func__); |
564 | if (atomic_read(v: &subs->state) >= STATE_PRERUNNING) |
565 | atomic_set(v: &subs->state, STATE_PREPARED); |
566 | break; |
567 | default: |
568 | return -EINVAL; |
569 | } |
570 | return 0; |
571 | } |
572 | |
573 | /* |
574 | * allocate a buffer, setup samplerate |
575 | * |
576 | * so far we use a physically linear buffer although packetize transfer |
577 | * doesn't need a continuous area. |
578 | * if sg buffer is supported on the later version of alsa, we'll follow |
579 | * that. |
580 | */ |
581 | struct s_c2 { |
582 | char c1, c2; |
583 | }; |
584 | |
585 | static const struct s_c2 setrate_44100[] = { |
586 | { 0x14, 0x08}, // this line sets 44100, well actually a little less |
587 | { 0x18, 0x40}, // only tascam / frontier design knows the further lines ....... |
588 | { 0x18, 0x42}, |
589 | { 0x18, 0x45}, |
590 | { 0x18, 0x46}, |
591 | { 0x18, 0x48}, |
592 | { 0x18, 0x4A}, |
593 | { 0x18, 0x4C}, |
594 | { 0x18, 0x4E}, |
595 | { 0x18, 0x50}, |
596 | { 0x18, 0x52}, |
597 | { 0x18, 0x54}, |
598 | { 0x18, 0x56}, |
599 | { 0x18, 0x58}, |
600 | { 0x18, 0x5A}, |
601 | { 0x18, 0x5C}, |
602 | { 0x18, 0x5E}, |
603 | { 0x18, 0x60}, |
604 | { 0x18, 0x62}, |
605 | { 0x18, 0x64}, |
606 | { 0x18, 0x66}, |
607 | { 0x18, 0x68}, |
608 | { 0x18, 0x6A}, |
609 | { 0x18, 0x6C}, |
610 | { 0x18, 0x6E}, |
611 | { 0x18, 0x70}, |
612 | { 0x18, 0x72}, |
613 | { 0x18, 0x74}, |
614 | { 0x18, 0x76}, |
615 | { 0x18, 0x78}, |
616 | { 0x18, 0x7A}, |
617 | { 0x18, 0x7C}, |
618 | { 0x18, 0x7E} |
619 | }; |
620 | |
621 | static const struct s_c2 setrate_48000[] = { |
622 | { 0x14, 0x09}, // this line sets 48000, well actually a little less |
623 | { 0x18, 0x40}, // only tascam / frontier design knows the further lines ....... |
624 | { 0x18, 0x42}, |
625 | { 0x18, 0x45}, |
626 | { 0x18, 0x46}, |
627 | { 0x18, 0x48}, |
628 | { 0x18, 0x4A}, |
629 | { 0x18, 0x4C}, |
630 | { 0x18, 0x4E}, |
631 | { 0x18, 0x50}, |
632 | { 0x18, 0x52}, |
633 | { 0x18, 0x54}, |
634 | { 0x18, 0x56}, |
635 | { 0x18, 0x58}, |
636 | { 0x18, 0x5A}, |
637 | { 0x18, 0x5C}, |
638 | { 0x18, 0x5E}, |
639 | { 0x18, 0x60}, |
640 | { 0x18, 0x62}, |
641 | { 0x18, 0x64}, |
642 | { 0x18, 0x66}, |
643 | { 0x18, 0x68}, |
644 | { 0x18, 0x6A}, |
645 | { 0x18, 0x6C}, |
646 | { 0x18, 0x6E}, |
647 | { 0x18, 0x70}, |
648 | { 0x18, 0x73}, |
649 | { 0x18, 0x74}, |
650 | { 0x18, 0x76}, |
651 | { 0x18, 0x78}, |
652 | { 0x18, 0x7A}, |
653 | { 0x18, 0x7C}, |
654 | { 0x18, 0x7E} |
655 | }; |
656 | |
657 | #define NOOF_SETRATE_URBS ARRAY_SIZE(setrate_48000) |
658 | |
659 | static void i_usx2y_04int(struct urb *urb) |
660 | { |
661 | struct usx2ydev *usx2y = urb->context; |
662 | |
663 | if (urb->status) |
664 | snd_printk(KERN_ERR "snd_usx2y_04int() urb->status=%i\n" , urb->status); |
665 | if (!--usx2y->us04->len) |
666 | wake_up(&usx2y->in04_wait_queue); |
667 | } |
668 | |
669 | static int usx2y_rate_set(struct usx2ydev *usx2y, int rate) |
670 | { |
671 | int err = 0, i; |
672 | struct snd_usx2y_urb_seq *us = NULL; |
673 | int *usbdata = NULL; |
674 | const struct s_c2 *ra = rate == 48000 ? setrate_48000 : setrate_44100; |
675 | struct urb *urb; |
676 | |
677 | if (usx2y->rate != rate) { |
678 | us = kzalloc(struct_size(us, urb, NOOF_SETRATE_URBS), |
679 | GFP_KERNEL); |
680 | if (!us) { |
681 | err = -ENOMEM; |
682 | goto cleanup; |
683 | } |
684 | us->len = NOOF_SETRATE_URBS; |
685 | usbdata = kmalloc_array(NOOF_SETRATE_URBS, size: sizeof(int), |
686 | GFP_KERNEL); |
687 | if (!usbdata) { |
688 | err = -ENOMEM; |
689 | goto cleanup; |
690 | } |
691 | for (i = 0; i < NOOF_SETRATE_URBS; ++i) { |
692 | us->urb[i] = usb_alloc_urb(iso_packets: 0, GFP_KERNEL); |
693 | if (!us->urb[i]) { |
694 | err = -ENOMEM; |
695 | goto cleanup; |
696 | } |
697 | ((char *)(usbdata + i))[0] = ra[i].c1; |
698 | ((char *)(usbdata + i))[1] = ra[i].c2; |
699 | usb_fill_bulk_urb(urb: us->urb[i], dev: usx2y->dev, usb_sndbulkpipe(usx2y->dev, 4), |
700 | transfer_buffer: usbdata + i, buffer_length: 2, complete_fn: i_usx2y_04int, context: usx2y); |
701 | } |
702 | err = usb_urb_ep_type_check(urb: us->urb[0]); |
703 | if (err < 0) |
704 | goto cleanup; |
705 | us->submitted = 0; |
706 | usx2y->us04 = us; |
707 | wait_event_timeout(usx2y->in04_wait_queue, !us->len, HZ); |
708 | usx2y->us04 = NULL; |
709 | if (us->len) |
710 | err = -ENODEV; |
711 | cleanup: |
712 | if (us) { |
713 | us->submitted = 2*NOOF_SETRATE_URBS; |
714 | for (i = 0; i < NOOF_SETRATE_URBS; ++i) { |
715 | urb = us->urb[i]; |
716 | if (!urb) |
717 | continue; |
718 | if (urb->status) { |
719 | if (!err) |
720 | err = -ENODEV; |
721 | usb_kill_urb(urb); |
722 | } |
723 | usb_free_urb(urb); |
724 | } |
725 | usx2y->us04 = NULL; |
726 | kfree(objp: usbdata); |
727 | kfree(objp: us); |
728 | if (!err) |
729 | usx2y->rate = rate; |
730 | } |
731 | } |
732 | |
733 | return err; |
734 | } |
735 | |
736 | static int usx2y_format_set(struct usx2ydev *usx2y, snd_pcm_format_t format) |
737 | { |
738 | int alternate, err; |
739 | struct list_head *p; |
740 | |
741 | if (format == SNDRV_PCM_FORMAT_S24_3LE) { |
742 | alternate = 2; |
743 | usx2y->stride = 6; |
744 | } else { |
745 | alternate = 1; |
746 | usx2y->stride = 4; |
747 | } |
748 | list_for_each(p, &usx2y->midi_list) { |
749 | snd_usbmidi_input_stop(p); |
750 | } |
751 | usb_kill_urb(urb: usx2y->in04_urb); |
752 | err = usb_set_interface(dev: usx2y->dev, ifnum: 0, alternate); |
753 | if (err) { |
754 | snd_printk(KERN_ERR "usb_set_interface error\n" ); |
755 | return err; |
756 | } |
757 | usx2y->in04_urb->dev = usx2y->dev; |
758 | err = usb_submit_urb(urb: usx2y->in04_urb, GFP_KERNEL); |
759 | list_for_each(p, &usx2y->midi_list) { |
760 | snd_usbmidi_input_start(p); |
761 | } |
762 | usx2y->format = format; |
763 | usx2y->rate = 0; |
764 | return err; |
765 | } |
766 | |
767 | |
768 | static int snd_usx2y_pcm_hw_params(struct snd_pcm_substream *substream, |
769 | struct snd_pcm_hw_params *hw_params) |
770 | { |
771 | int err = 0; |
772 | unsigned int rate = params_rate(p: hw_params); |
773 | snd_pcm_format_t format = params_format(p: hw_params); |
774 | struct snd_card *card = substream->pstr->pcm->card; |
775 | struct usx2ydev *dev = usx2y(card); |
776 | struct snd_usx2y_substream *subs; |
777 | struct snd_pcm_substream *test_substream; |
778 | int i; |
779 | |
780 | mutex_lock(&usx2y(card)->pcm_mutex); |
781 | snd_printdd("snd_usx2y_hw_params(%p, %p)\n" , substream, hw_params); |
782 | /* all pcm substreams off one usx2y have to operate at the same |
783 | * rate & format |
784 | */ |
785 | for (i = 0; i < dev->pcm_devs * 2; i++) { |
786 | subs = dev->subs[i]; |
787 | if (!subs) |
788 | continue; |
789 | test_substream = subs->pcm_substream; |
790 | if (!test_substream || test_substream == substream || |
791 | !test_substream->runtime) |
792 | continue; |
793 | if ((test_substream->runtime->format && |
794 | test_substream->runtime->format != format) || |
795 | (test_substream->runtime->rate && |
796 | test_substream->runtime->rate != rate)) { |
797 | err = -EINVAL; |
798 | goto error; |
799 | } |
800 | } |
801 | |
802 | error: |
803 | mutex_unlock(lock: &usx2y(card)->pcm_mutex); |
804 | return err; |
805 | } |
806 | |
807 | /* |
808 | * free the buffer |
809 | */ |
810 | static int snd_usx2y_pcm_hw_free(struct snd_pcm_substream *substream) |
811 | { |
812 | struct snd_pcm_runtime *runtime = substream->runtime; |
813 | struct snd_usx2y_substream *subs = runtime->private_data; |
814 | struct snd_usx2y_substream *cap_subs, *playback_subs; |
815 | |
816 | mutex_lock(&subs->usx2y->pcm_mutex); |
817 | snd_printdd("snd_usx2y_hw_free(%p)\n" , substream); |
818 | |
819 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
820 | cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]; |
821 | atomic_set(v: &subs->state, STATE_STOPPED); |
822 | usx2y_urbs_release(subs); |
823 | if (!cap_subs->pcm_substream || |
824 | !cap_subs->pcm_substream->runtime || |
825 | cap_subs->pcm_substream->runtime->state < SNDRV_PCM_STATE_PREPARED) { |
826 | atomic_set(v: &cap_subs->state, STATE_STOPPED); |
827 | usx2y_urbs_release(subs: cap_subs); |
828 | } |
829 | } else { |
830 | playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]; |
831 | if (atomic_read(v: &playback_subs->state) < STATE_PREPARED) { |
832 | atomic_set(v: &subs->state, STATE_STOPPED); |
833 | usx2y_urbs_release(subs); |
834 | } |
835 | } |
836 | mutex_unlock(lock: &subs->usx2y->pcm_mutex); |
837 | return 0; |
838 | } |
839 | |
840 | /* |
841 | * prepare callback |
842 | * |
843 | * set format and initialize urbs |
844 | */ |
845 | static int snd_usx2y_pcm_prepare(struct snd_pcm_substream *substream) |
846 | { |
847 | struct snd_pcm_runtime *runtime = substream->runtime; |
848 | struct snd_usx2y_substream *subs = runtime->private_data; |
849 | struct usx2ydev *usx2y = subs->usx2y; |
850 | struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]; |
851 | int err = 0; |
852 | |
853 | snd_printdd("%s(%p)\n" , __func__, substream); |
854 | |
855 | mutex_lock(&usx2y->pcm_mutex); |
856 | usx2y_subs_prepare(subs); |
857 | // Start hardware streams |
858 | // SyncStream first.... |
859 | if (atomic_read(v: &capsubs->state) < STATE_PREPARED) { |
860 | if (usx2y->format != runtime->format) { |
861 | err = usx2y_format_set(usx2y, format: runtime->format); |
862 | if (err < 0) |
863 | goto up_prepare_mutex; |
864 | } |
865 | if (usx2y->rate != runtime->rate) { |
866 | err = usx2y_rate_set(usx2y, rate: runtime->rate); |
867 | if (err < 0) |
868 | goto up_prepare_mutex; |
869 | } |
870 | snd_printdd("starting capture pipe for %s\n" , subs == capsubs ? "self" : "playpipe" ); |
871 | err = usx2y_urbs_start(subs: capsubs); |
872 | if (err < 0) |
873 | goto up_prepare_mutex; |
874 | } |
875 | |
876 | if (subs != capsubs && atomic_read(v: &subs->state) < STATE_PREPARED) |
877 | err = usx2y_urbs_start(subs); |
878 | |
879 | up_prepare_mutex: |
880 | mutex_unlock(lock: &usx2y->pcm_mutex); |
881 | return err; |
882 | } |
883 | |
884 | static const struct snd_pcm_hardware snd_usx2y_2c = { |
885 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
886 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
887 | SNDRV_PCM_INFO_MMAP_VALID | |
888 | SNDRV_PCM_INFO_BATCH), |
889 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE, |
890 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, |
891 | .rate_min = 44100, |
892 | .rate_max = 48000, |
893 | .channels_min = 2, |
894 | .channels_max = 2, |
895 | .buffer_bytes_max = (2*128*1024), |
896 | .period_bytes_min = 64, |
897 | .period_bytes_max = (128*1024), |
898 | .periods_min = 2, |
899 | .periods_max = 1024, |
900 | .fifo_size = 0 |
901 | }; |
902 | |
903 | static int snd_usx2y_pcm_open(struct snd_pcm_substream *substream) |
904 | { |
905 | struct snd_usx2y_substream *subs = |
906 | ((struct snd_usx2y_substream **) |
907 | snd_pcm_substream_chip(substream))[substream->stream]; |
908 | struct snd_pcm_runtime *runtime = substream->runtime; |
909 | |
910 | if (subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS) |
911 | return -EBUSY; |
912 | |
913 | runtime->hw = snd_usx2y_2c; |
914 | runtime->private_data = subs; |
915 | subs->pcm_substream = substream; |
916 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, min: 1000, max: 200000); |
917 | return 0; |
918 | } |
919 | |
920 | static int snd_usx2y_pcm_close(struct snd_pcm_substream *substream) |
921 | { |
922 | struct snd_pcm_runtime *runtime = substream->runtime; |
923 | struct snd_usx2y_substream *subs = runtime->private_data; |
924 | |
925 | subs->pcm_substream = NULL; |
926 | |
927 | return 0; |
928 | } |
929 | |
930 | static const struct snd_pcm_ops snd_usx2y_pcm_ops = { |
931 | .open = snd_usx2y_pcm_open, |
932 | .close = snd_usx2y_pcm_close, |
933 | .hw_params = snd_usx2y_pcm_hw_params, |
934 | .hw_free = snd_usx2y_pcm_hw_free, |
935 | .prepare = snd_usx2y_pcm_prepare, |
936 | .trigger = snd_usx2y_pcm_trigger, |
937 | .pointer = snd_usx2y_pcm_pointer, |
938 | }; |
939 | |
940 | /* |
941 | * free a usb stream instance |
942 | */ |
943 | static void usx2y_audio_stream_free(struct snd_usx2y_substream **usx2y_substream) |
944 | { |
945 | int stream; |
946 | |
947 | for_each_pcm_streams(stream) { |
948 | kfree(objp: usx2y_substream[stream]); |
949 | usx2y_substream[stream] = NULL; |
950 | } |
951 | } |
952 | |
953 | static void snd_usx2y_pcm_private_free(struct snd_pcm *pcm) |
954 | { |
955 | struct snd_usx2y_substream **usx2y_stream = pcm->private_data; |
956 | |
957 | if (usx2y_stream) |
958 | usx2y_audio_stream_free(usx2y_substream: usx2y_stream); |
959 | } |
960 | |
961 | static int usx2y_audio_stream_new(struct snd_card *card, int playback_endpoint, int capture_endpoint) |
962 | { |
963 | struct snd_pcm *pcm; |
964 | int err, i; |
965 | struct snd_usx2y_substream **usx2y_substream = |
966 | usx2y(card)->subs + 2 * usx2y(card)->pcm_devs; |
967 | |
968 | for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; |
969 | i <= SNDRV_PCM_STREAM_CAPTURE; ++i) { |
970 | usx2y_substream[i] = kzalloc(size: sizeof(struct snd_usx2y_substream), GFP_KERNEL); |
971 | if (!usx2y_substream[i]) |
972 | return -ENOMEM; |
973 | |
974 | usx2y_substream[i]->usx2y = usx2y(card); |
975 | } |
976 | |
977 | if (playback_endpoint) |
978 | usx2y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint; |
979 | usx2y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint; |
980 | |
981 | err = snd_pcm_new(card, NAME_ALLCAPS" Audio" , usx2y(card)->pcm_devs, |
982 | playback_count: playback_endpoint ? 1 : 0, capture_count: 1, |
983 | rpcm: &pcm); |
984 | if (err < 0) { |
985 | usx2y_audio_stream_free(usx2y_substream); |
986 | return err; |
987 | } |
988 | |
989 | if (playback_endpoint) |
990 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_PLAYBACK, ops: &snd_usx2y_pcm_ops); |
991 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_CAPTURE, ops: &snd_usx2y_pcm_ops); |
992 | |
993 | pcm->private_data = usx2y_substream; |
994 | pcm->private_free = snd_usx2y_pcm_private_free; |
995 | pcm->info_flags = 0; |
996 | |
997 | sprintf(buf: pcm->name, NAME_ALLCAPS" Audio #%d" , usx2y(card)->pcm_devs); |
998 | |
999 | if (playback_endpoint) { |
1000 | snd_pcm_set_managed_buffer(substream: pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, |
1001 | SNDRV_DMA_TYPE_CONTINUOUS, |
1002 | NULL, |
1003 | size: 64*1024, max: 128*1024); |
1004 | } |
1005 | |
1006 | snd_pcm_set_managed_buffer(substream: pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, |
1007 | SNDRV_DMA_TYPE_CONTINUOUS, |
1008 | NULL, |
1009 | size: 64*1024, max: 128*1024); |
1010 | usx2y(card)->pcm_devs++; |
1011 | |
1012 | return 0; |
1013 | } |
1014 | |
1015 | /* |
1016 | * create a chip instance and set its names. |
1017 | */ |
1018 | int usx2y_audio_create(struct snd_card *card) |
1019 | { |
1020 | int err; |
1021 | |
1022 | err = usx2y_audio_stream_new(card, playback_endpoint: 0xA, capture_endpoint: 0x8); |
1023 | if (err < 0) |
1024 | return err; |
1025 | if (le16_to_cpu(usx2y(card)->dev->descriptor.idProduct) == USB_ID_US428) { |
1026 | err = usx2y_audio_stream_new(card, playback_endpoint: 0, capture_endpoint: 0xA); |
1027 | if (err < 0) |
1028 | return err; |
1029 | } |
1030 | if (le16_to_cpu(usx2y(card)->dev->descriptor.idProduct) != USB_ID_US122) |
1031 | err = usx2y_rate_set(usx2y(card), rate: 44100); // Lets us428 recognize output-volume settings, disturbs us122. |
1032 | return err; |
1033 | } |
1034 | |