1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 */
4
5 /* USX2Y "rawusb" aka hwdep_pcm implementation
6
7 Its usb's unableness to atomically handle power of 2 period sized data chuncs
8 at standard samplerates,
9 what led to this part of the usx2y module:
10 It provides the alsa kernel half of the usx2y-alsa-jack driver pair.
11 The pair uses a hardware dependent alsa-device for mmaped pcm transport.
12 Advantage achieved:
13 The usb_hc moves pcm data from/into memory via DMA.
14 That memory is mmaped by jack's usx2y driver.
15 Jack's usx2y driver is the first/last to read/write pcm data.
16 Read/write is a combination of power of 2 period shaping and
17 float/int conversation.
18 Compared to mainline alsa/jack we leave out power of 2 period shaping inside
19 snd-usb-usx2y which needs memcpy() and additional buffers.
20 As a side effect possible unwanted pcm-data coruption resulting of
21 standard alsa's snd-usb-usx2y period shaping scheme falls away.
22 Result is sane jack operation at buffering schemes down to 128frames,
23 2 periods.
24 plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
25 cost of easier triggered i.e. aeolus xruns (128 or 256frames,
26 2periods works but is useless cause of crackling).
27
28 This is a first "proof of concept" implementation.
29 Later, functionalities should migrate to more appropriate places:
30 Userland:
31 - The jackd could mmap its float-pcm buffers directly from alsa-lib.
32 - alsa-lib could provide power of 2 period sized shaping combined with int/float
33 conversation.
34 Currently the usx2y jack driver provides above 2 services.
35 Kernel:
36 - rawusb dma pcm buffer transport should go to snd-usb-lib, so also snd-usb-audio
37 devices can use it.
38 Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y.
39 */
40
41 #include <linux/delay.h>
42 #include <linux/gfp.h>
43 #include "usbusx2yaudio.c"
44
45 #if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
46
47 #include <sound/hwdep.h>
48
usx2y_usbpcm_urb_capt_retire(struct snd_usx2y_substream * subs)49 static int usx2y_usbpcm_urb_capt_retire(struct snd_usx2y_substream *subs)
50 {
51 struct urb *urb = subs->completed_urb;
52 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
53 int i, lens = 0, hwptr_done = subs->hwptr_done;
54 struct usx2ydev *usx2y = subs->usx2y;
55 int head;
56
57 if (usx2y->hwdep_pcm_shm->capture_iso_start < 0) { //FIXME
58 head = usx2y->hwdep_pcm_shm->captured_iso_head + 1;
59 if (head >= ARRAY_SIZE(usx2y->hwdep_pcm_shm->captured_iso))
60 head = 0;
61 usx2y->hwdep_pcm_shm->capture_iso_start = head;
62 snd_printdd("cap start %i\n", head);
63 }
64 for (i = 0; i < nr_of_packs(); i++) {
65 if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
66 snd_printk(KERN_ERR
67 "active frame status %i. Most probably some hardware problem.\n",
68 urb->iso_frame_desc[i].status);
69 return urb->iso_frame_desc[i].status;
70 }
71 lens += urb->iso_frame_desc[i].actual_length / usx2y->stride;
72 }
73 hwptr_done += lens;
74 if (hwptr_done >= runtime->buffer_size)
75 hwptr_done -= runtime->buffer_size;
76 subs->hwptr_done = hwptr_done;
77 subs->transfer_done += lens;
78 /* update the pointer, call callback if necessary */
79 if (subs->transfer_done >= runtime->period_size) {
80 subs->transfer_done -= runtime->period_size;
81 snd_pcm_period_elapsed(subs->pcm_substream);
82 }
83 return 0;
84 }
85
usx2y_iso_frames_per_buffer(struct snd_pcm_runtime * runtime,struct usx2ydev * usx2y)86 static int usx2y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
87 struct usx2ydev *usx2y)
88 {
89 return (runtime->buffer_size * 1000) / usx2y->rate + 1; //FIXME: so far only correct period_size == 2^x ?
90 }
91
92 /*
93 * prepare urb for playback data pipe
94 *
95 * we copy the data directly from the pcm buffer.
96 * the current position to be copied is held in hwptr field.
97 * since a urb can handle only a single linear buffer, if the total
98 * transferred area overflows the buffer boundary, we cannot send
99 * it directly from the buffer. thus the data is once copied to
100 * a temporary buffer and urb points to that.
101 */
usx2y_hwdep_urb_play_prepare(struct snd_usx2y_substream * subs,struct urb * urb)102 static int usx2y_hwdep_urb_play_prepare(struct snd_usx2y_substream *subs,
103 struct urb *urb)
104 {
105 int count, counts, pack;
106 struct usx2ydev *usx2y = subs->usx2y;
107 struct snd_usx2y_hwdep_pcm_shm *shm = usx2y->hwdep_pcm_shm;
108 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
109
110 if (shm->playback_iso_start < 0) {
111 shm->playback_iso_start = shm->captured_iso_head -
112 usx2y_iso_frames_per_buffer(runtime, usx2y);
113 if (shm->playback_iso_start < 0)
114 shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
115 shm->playback_iso_head = shm->playback_iso_start;
116 }
117
118 count = 0;
119 for (pack = 0; pack < nr_of_packs(); pack++) {
120 /* calculate the size of a packet */
121 counts = shm->captured_iso[shm->playback_iso_head].length / usx2y->stride;
122 if (counts < 43 || counts > 50) {
123 snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
124 return -EPIPE;
125 }
126 /* set up descriptor */
127 urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
128 urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
129 if (atomic_read(&subs->state) != STATE_RUNNING)
130 memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
131 urb->iso_frame_desc[pack].length);
132 if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
133 shm->playback_iso_head = 0;
134 count += counts;
135 }
136 urb->transfer_buffer_length = count * usx2y->stride;
137 return 0;
138 }
139
usx2y_usbpcm_urb_capt_iso_advance(struct snd_usx2y_substream * subs,struct urb * urb)140 static void usx2y_usbpcm_urb_capt_iso_advance(struct snd_usx2y_substream *subs,
141 struct urb *urb)
142 {
143 struct usb_iso_packet_descriptor *desc;
144 struct snd_usx2y_hwdep_pcm_shm *shm;
145 int pack, head;
146
147 for (pack = 0; pack < nr_of_packs(); ++pack) {
148 desc = urb->iso_frame_desc + pack;
149 if (subs) {
150 shm = subs->usx2y->hwdep_pcm_shm;
151 head = shm->captured_iso_head + 1;
152 if (head >= ARRAY_SIZE(shm->captured_iso))
153 head = 0;
154 shm->captured_iso[head].frame = urb->start_frame + pack;
155 shm->captured_iso[head].offset = desc->offset;
156 shm->captured_iso[head].length = desc->actual_length;
157 shm->captured_iso_head = head;
158 shm->captured_iso_frames++;
159 }
160 desc->offset += desc->length * NRURBS * nr_of_packs();
161 if (desc->offset + desc->length >= SSS)
162 desc->offset -= (SSS - desc->length);
163 }
164 }
165
usx2y_usbpcm_usbframe_complete(struct snd_usx2y_substream * capsubs,struct snd_usx2y_substream * capsubs2,struct snd_usx2y_substream * playbacksubs,int frame)166 static int usx2y_usbpcm_usbframe_complete(struct snd_usx2y_substream *capsubs,
167 struct snd_usx2y_substream *capsubs2,
168 struct snd_usx2y_substream *playbacksubs,
169 int frame)
170 {
171 int err, state;
172 struct urb *urb = playbacksubs->completed_urb;
173
174 state = atomic_read(&playbacksubs->state);
175 if (urb) {
176 if (state == STATE_RUNNING)
177 usx2y_urb_play_retire(playbacksubs, urb);
178 else if (state >= STATE_PRERUNNING)
179 atomic_inc(&playbacksubs->state);
180 } else {
181 switch (state) {
182 case STATE_STARTING1:
183 urb = playbacksubs->urb[0];
184 atomic_inc(&playbacksubs->state);
185 break;
186 case STATE_STARTING2:
187 urb = playbacksubs->urb[1];
188 atomic_inc(&playbacksubs->state);
189 break;
190 }
191 }
192 if (urb) {
193 err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb);
194 if (err)
195 return err;
196 err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb);
197 if (err)
198 return err;
199 }
200
201 playbacksubs->completed_urb = NULL;
202
203 state = atomic_read(&capsubs->state);
204 if (state >= STATE_PREPARED) {
205 if (state == STATE_RUNNING) {
206 err = usx2y_usbpcm_urb_capt_retire(capsubs);
207 if (err)
208 return err;
209 } else if (state >= STATE_PRERUNNING) {
210 atomic_inc(&capsubs->state);
211 }
212 usx2y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
213 if (capsubs2)
214 usx2y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
215 err = usx2y_urb_submit(capsubs, capsubs->completed_urb, frame);
216 if (err)
217 return err;
218 if (capsubs2) {
219 err = usx2y_urb_submit(capsubs2, capsubs2->completed_urb, frame);
220 if (err)
221 return err;
222 }
223 }
224 capsubs->completed_urb = NULL;
225 if (capsubs2)
226 capsubs2->completed_urb = NULL;
227 return 0;
228 }
229
i_usx2y_usbpcm_urb_complete(struct urb * urb)230 static void i_usx2y_usbpcm_urb_complete(struct urb *urb)
231 {
232 struct snd_usx2y_substream *subs = urb->context;
233 struct usx2ydev *usx2y = subs->usx2y;
234 struct snd_usx2y_substream *capsubs, *capsubs2, *playbacksubs;
235
236 if (unlikely(atomic_read(&subs->state) < STATE_PREPARED)) {
237 snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
238 usb_get_current_frame_number(usx2y->dev),
239 subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
240 urb->status, urb->start_frame);
241 return;
242 }
243 if (unlikely(urb->status)) {
244 usx2y_error_urb_status(usx2y, subs, urb);
245 return;
246 }
247
248 subs->completed_urb = urb;
249 capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
250 capsubs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
251 playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
252 if (capsubs->completed_urb && atomic_read(&capsubs->state) >= STATE_PREPARED &&
253 (!capsubs2 || capsubs2->completed_urb) &&
254 (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < STATE_PREPARED)) {
255 if (!usx2y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) {
256 usx2y->wait_iso_frame += nr_of_packs();
257 } else {
258 snd_printdd("\n");
259 usx2y_clients_stop(usx2y);
260 }
261 }
262 }
263
usx2y_hwdep_urb_release(struct urb ** urb)264 static void usx2y_hwdep_urb_release(struct urb **urb)
265 {
266 usb_kill_urb(*urb);
267 usb_free_urb(*urb);
268 *urb = NULL;
269 }
270
271 /*
272 * release a substream
273 */
usx2y_usbpcm_urbs_release(struct snd_usx2y_substream * subs)274 static void usx2y_usbpcm_urbs_release(struct snd_usx2y_substream *subs)
275 {
276 int i;
277
278 snd_printdd("snd_usx2y_urbs_release() %i\n", subs->endpoint);
279 for (i = 0; i < NRURBS; i++)
280 usx2y_hwdep_urb_release(subs->urb + i);
281 }
282
usx2y_usbpcm_subs_startup_finish(struct usx2ydev * usx2y)283 static void usx2y_usbpcm_subs_startup_finish(struct usx2ydev *usx2y)
284 {
285 usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_urb_complete);
286 usx2y->prepare_subs = NULL;
287 }
288
i_usx2y_usbpcm_subs_startup(struct urb * urb)289 static void i_usx2y_usbpcm_subs_startup(struct urb *urb)
290 {
291 struct snd_usx2y_substream *subs = urb->context;
292 struct usx2ydev *usx2y = subs->usx2y;
293 struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs;
294 struct snd_usx2y_substream *cap_subs2;
295
296 if (prepare_subs &&
297 urb->start_frame == prepare_subs->urb[0]->start_frame) {
298 atomic_inc(&prepare_subs->state);
299 if (prepare_subs == usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
300 cap_subs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
301 if (cap_subs2)
302 atomic_inc(&cap_subs2->state);
303 }
304 usx2y_usbpcm_subs_startup_finish(usx2y);
305 wake_up(&usx2y->prepare_wait_queue);
306 }
307
308 i_usx2y_usbpcm_urb_complete(urb);
309 }
310
311 /*
312 * initialize a substream's urbs
313 */
usx2y_usbpcm_urbs_allocate(struct snd_usx2y_substream * subs)314 static int usx2y_usbpcm_urbs_allocate(struct snd_usx2y_substream *subs)
315 {
316 int i;
317 unsigned int pipe;
318 int is_playback = subs == subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
319 struct usb_device *dev = subs->usx2y->dev;
320 struct urb **purb;
321
322 pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
323 usb_rcvisocpipe(dev, subs->endpoint);
324 subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
325 if (!subs->maxpacksize)
326 return -EINVAL;
327
328 /* allocate and initialize data urbs */
329 for (i = 0; i < NRURBS; i++) {
330 purb = subs->urb + i;
331 if (*purb) {
332 usb_kill_urb(*purb);
333 continue;
334 }
335 *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
336 if (!*purb) {
337 usx2y_usbpcm_urbs_release(subs);
338 return -ENOMEM;
339 }
340 (*purb)->transfer_buffer = is_playback ?
341 subs->usx2y->hwdep_pcm_shm->playback : (
342 subs->endpoint == 0x8 ?
343 subs->usx2y->hwdep_pcm_shm->capture0x8 :
344 subs->usx2y->hwdep_pcm_shm->capture0xA);
345
346 (*purb)->dev = dev;
347 (*purb)->pipe = pipe;
348 (*purb)->number_of_packets = nr_of_packs();
349 (*purb)->context = subs;
350 (*purb)->interval = 1;
351 (*purb)->complete = i_usx2y_usbpcm_subs_startup;
352 }
353 return 0;
354 }
355
356 /*
357 * free the buffer
358 */
snd_usx2y_usbpcm_hw_free(struct snd_pcm_substream * substream)359 static int snd_usx2y_usbpcm_hw_free(struct snd_pcm_substream *substream)
360 {
361 struct snd_pcm_runtime *runtime = substream->runtime;
362 struct snd_usx2y_substream *subs = runtime->private_data;
363 struct snd_usx2y_substream *cap_subs;
364 struct snd_usx2y_substream *playback_subs;
365 struct snd_usx2y_substream *cap_subs2;
366
367 mutex_lock(&subs->usx2y->pcm_mutex);
368 snd_printdd("%s(%p)\n", __func__, substream);
369
370 cap_subs2 = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
371 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
372 cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
373 atomic_set(&subs->state, STATE_STOPPED);
374 usx2y_usbpcm_urbs_release(subs);
375 if (!cap_subs->pcm_substream ||
376 !cap_subs->pcm_substream->runtime ||
377 !cap_subs->pcm_substream->runtime->status ||
378 cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
379 atomic_set(&cap_subs->state, STATE_STOPPED);
380 if (cap_subs2)
381 atomic_set(&cap_subs2->state, STATE_STOPPED);
382 usx2y_usbpcm_urbs_release(cap_subs);
383 if (cap_subs2)
384 usx2y_usbpcm_urbs_release(cap_subs2);
385 }
386 } else {
387 playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
388 if (atomic_read(&playback_subs->state) < STATE_PREPARED) {
389 atomic_set(&subs->state, STATE_STOPPED);
390 if (cap_subs2)
391 atomic_set(&cap_subs2->state, STATE_STOPPED);
392 usx2y_usbpcm_urbs_release(subs);
393 if (cap_subs2)
394 usx2y_usbpcm_urbs_release(cap_subs2);
395 }
396 }
397 mutex_unlock(&subs->usx2y->pcm_mutex);
398 return 0;
399 }
400
usx2y_usbpcm_subs_startup(struct snd_usx2y_substream * subs)401 static void usx2y_usbpcm_subs_startup(struct snd_usx2y_substream *subs)
402 {
403 struct usx2ydev *usx2y = subs->usx2y;
404
405 usx2y->prepare_subs = subs;
406 subs->urb[0]->start_frame = -1;
407 smp_wmb(); // Make sure above modifications are seen by i_usx2y_subs_startup()
408 usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_subs_startup);
409 }
410
usx2y_usbpcm_urbs_start(struct snd_usx2y_substream * subs)411 static int usx2y_usbpcm_urbs_start(struct snd_usx2y_substream *subs)
412 {
413 int p, u, err, stream = subs->pcm_substream->stream;
414 struct usx2ydev *usx2y = subs->usx2y;
415 struct urb *urb;
416 unsigned long pack;
417
418 if (stream == SNDRV_PCM_STREAM_CAPTURE) {
419 usx2y->hwdep_pcm_shm->captured_iso_head = -1;
420 usx2y->hwdep_pcm_shm->captured_iso_frames = 0;
421 }
422
423 for (p = 0; 3 >= (stream + p); p += 2) {
424 struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
425 if (subs) {
426 err = usx2y_usbpcm_urbs_allocate(subs);
427 if (err < 0)
428 return err;
429 subs->completed_urb = NULL;
430 }
431 }
432
433 for (p = 0; p < 4; p++) {
434 struct snd_usx2y_substream *subs = usx2y->subs[p];
435
436 if (subs && atomic_read(&subs->state) >= STATE_PREPARED)
437 goto start;
438 }
439
440 start:
441 usx2y_usbpcm_subs_startup(subs);
442 for (u = 0; u < NRURBS; u++) {
443 for (p = 0; 3 >= (stream + p); p += 2) {
444 struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
445
446 if (!subs)
447 continue;
448 urb = subs->urb[u];
449 if (usb_pipein(urb->pipe)) {
450 if (!u)
451 atomic_set(&subs->state, STATE_STARTING3);
452 urb->dev = usx2y->dev;
453 for (pack = 0; pack < nr_of_packs(); pack++) {
454 urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
455 urb->iso_frame_desc[pack].length = subs->maxpacksize;
456 }
457 urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
458 err = usb_submit_urb(urb, GFP_KERNEL);
459 if (err < 0) {
460 snd_printk(KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
461 err = -EPIPE;
462 goto cleanup;
463 } else {
464 snd_printdd("%i\n", urb->start_frame);
465 if (!u)
466 usx2y->wait_iso_frame = urb->start_frame;
467 }
468 urb->transfer_flags = 0;
469 } else {
470 atomic_set(&subs->state, STATE_STARTING1);
471 break;
472 }
473 }
474 }
475 err = 0;
476 wait_event(usx2y->prepare_wait_queue, !usx2y->prepare_subs);
477 if (atomic_read(&subs->state) != STATE_PREPARED)
478 err = -EPIPE;
479
480 cleanup:
481 if (err) {
482 usx2y_subs_startup_finish(usx2y); // Call it now
483 usx2y_clients_stop(usx2y); // something is completely wrong > stop everything
484 }
485 return err;
486 }
487
488 #define USX2Y_HWDEP_PCM_PAGES \
489 PAGE_ALIGN(sizeof(struct snd_usx2y_hwdep_pcm_shm))
490
491 /*
492 * prepare callback
493 *
494 * set format and initialize urbs
495 */
snd_usx2y_usbpcm_prepare(struct snd_pcm_substream * substream)496 static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream)
497 {
498 struct snd_pcm_runtime *runtime = substream->runtime;
499 struct snd_usx2y_substream *subs = runtime->private_data;
500 struct usx2ydev *usx2y = subs->usx2y;
501 struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
502 int err = 0;
503
504 snd_printdd("snd_usx2y_pcm_prepare(%p)\n", substream);
505
506 mutex_lock(&usx2y->pcm_mutex);
507
508 if (!usx2y->hwdep_pcm_shm) {
509 usx2y->hwdep_pcm_shm = alloc_pages_exact(USX2Y_HWDEP_PCM_PAGES,
510 GFP_KERNEL);
511 if (!usx2y->hwdep_pcm_shm) {
512 err = -ENOMEM;
513 goto up_prepare_mutex;
514 }
515 memset(usx2y->hwdep_pcm_shm, 0, USX2Y_HWDEP_PCM_PAGES);
516 }
517
518 usx2y_subs_prepare(subs);
519 // Start hardware streams
520 // SyncStream first....
521 if (atomic_read(&capsubs->state) < STATE_PREPARED) {
522 if (usx2y->format != runtime->format) {
523 err = usx2y_format_set(usx2y, runtime->format);
524 if (err < 0)
525 goto up_prepare_mutex;
526 }
527 if (usx2y->rate != runtime->rate) {
528 err = usx2y_rate_set(usx2y, runtime->rate);
529 if (err < 0)
530 goto up_prepare_mutex;
531 }
532 snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
533 "self" : "playpipe");
534 err = usx2y_usbpcm_urbs_start(capsubs);
535 if (err < 0)
536 goto up_prepare_mutex;
537 }
538
539 if (subs != capsubs) {
540 usx2y->hwdep_pcm_shm->playback_iso_start = -1;
541 if (atomic_read(&subs->state) < STATE_PREPARED) {
542 while (usx2y_iso_frames_per_buffer(runtime, usx2y) >
543 usx2y->hwdep_pcm_shm->captured_iso_frames) {
544 snd_printdd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
545 usx2y_iso_frames_per_buffer(runtime, usx2y),
546 usx2y->hwdep_pcm_shm->captured_iso_frames);
547 if (msleep_interruptible(10)) {
548 err = -ERESTARTSYS;
549 goto up_prepare_mutex;
550 }
551 }
552 err = usx2y_usbpcm_urbs_start(subs);
553 if (err < 0)
554 goto up_prepare_mutex;
555 }
556 snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
557 usx2y_iso_frames_per_buffer(runtime, usx2y),
558 usx2y->hwdep_pcm_shm->captured_iso_frames);
559 } else {
560 usx2y->hwdep_pcm_shm->capture_iso_start = -1;
561 }
562
563 up_prepare_mutex:
564 mutex_unlock(&usx2y->pcm_mutex);
565 return err;
566 }
567
568 static const struct snd_pcm_hardware snd_usx2y_4c = {
569 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
570 SNDRV_PCM_INFO_BLOCK_TRANSFER |
571 SNDRV_PCM_INFO_MMAP_VALID),
572 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
573 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
574 .rate_min = 44100,
575 .rate_max = 48000,
576 .channels_min = 2,
577 .channels_max = 4,
578 .buffer_bytes_max = (2*128*1024),
579 .period_bytes_min = 64,
580 .period_bytes_max = (128*1024),
581 .periods_min = 2,
582 .periods_max = 1024,
583 .fifo_size = 0
584 };
585
snd_usx2y_usbpcm_open(struct snd_pcm_substream * substream)586 static int snd_usx2y_usbpcm_open(struct snd_pcm_substream *substream)
587 {
588 struct snd_usx2y_substream *subs =
589 ((struct snd_usx2y_substream **)
590 snd_pcm_substream_chip(substream))[substream->stream];
591 struct snd_pcm_runtime *runtime = substream->runtime;
592
593 if (!(subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
594 return -EBUSY;
595
596 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
597 runtime->hw = snd_usx2y_2c;
598 else
599 runtime->hw = (subs->usx2y->subs[3] ? snd_usx2y_4c : snd_usx2y_2c);
600 runtime->private_data = subs;
601 subs->pcm_substream = substream;
602 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
603 return 0;
604 }
605
snd_usx2y_usbpcm_close(struct snd_pcm_substream * substream)606 static int snd_usx2y_usbpcm_close(struct snd_pcm_substream *substream)
607 {
608 struct snd_pcm_runtime *runtime = substream->runtime;
609 struct snd_usx2y_substream *subs = runtime->private_data;
610
611 subs->pcm_substream = NULL;
612 return 0;
613 }
614
615 static const struct snd_pcm_ops snd_usx2y_usbpcm_ops = {
616 .open = snd_usx2y_usbpcm_open,
617 .close = snd_usx2y_usbpcm_close,
618 .hw_params = snd_usx2y_pcm_hw_params,
619 .hw_free = snd_usx2y_usbpcm_hw_free,
620 .prepare = snd_usx2y_usbpcm_prepare,
621 .trigger = snd_usx2y_pcm_trigger,
622 .pointer = snd_usx2y_pcm_pointer,
623 };
624
usx2y_pcms_busy_check(struct snd_card * card)625 static int usx2y_pcms_busy_check(struct snd_card *card)
626 {
627 struct usx2ydev *dev = usx2y(card);
628 struct snd_usx2y_substream *subs;
629 int i;
630
631 for (i = 0; i < dev->pcm_devs * 2; i++) {
632 subs = dev->subs[i];
633 if (subs && subs->pcm_substream &&
634 SUBSTREAM_BUSY(subs->pcm_substream))
635 return -EBUSY;
636 }
637 return 0;
638 }
639
snd_usx2y_hwdep_pcm_open(struct snd_hwdep * hw,struct file * file)640 static int snd_usx2y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
641 {
642 struct snd_card *card = hw->card;
643 int err;
644
645 mutex_lock(&usx2y(card)->pcm_mutex);
646 err = usx2y_pcms_busy_check(card);
647 if (!err)
648 usx2y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
649 mutex_unlock(&usx2y(card)->pcm_mutex);
650 return err;
651 }
652
snd_usx2y_hwdep_pcm_release(struct snd_hwdep * hw,struct file * file)653 static int snd_usx2y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
654 {
655 struct snd_card *card = hw->card;
656 int err;
657
658 mutex_lock(&usx2y(card)->pcm_mutex);
659 err = usx2y_pcms_busy_check(card);
660 if (!err)
661 usx2y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
662 mutex_unlock(&usx2y(card)->pcm_mutex);
663 return err;
664 }
665
snd_usx2y_hwdep_pcm_vm_open(struct vm_area_struct * area)666 static void snd_usx2y_hwdep_pcm_vm_open(struct vm_area_struct *area)
667 {
668 }
669
snd_usx2y_hwdep_pcm_vm_close(struct vm_area_struct * area)670 static void snd_usx2y_hwdep_pcm_vm_close(struct vm_area_struct *area)
671 {
672 }
673
snd_usx2y_hwdep_pcm_vm_fault(struct vm_fault * vmf)674 static vm_fault_t snd_usx2y_hwdep_pcm_vm_fault(struct vm_fault *vmf)
675 {
676 unsigned long offset;
677 void *vaddr;
678
679 offset = vmf->pgoff << PAGE_SHIFT;
680 vaddr = (char *)((struct usx2ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset;
681 vmf->page = virt_to_page(vaddr);
682 get_page(vmf->page);
683 return 0;
684 }
685
686 static const struct vm_operations_struct snd_usx2y_hwdep_pcm_vm_ops = {
687 .open = snd_usx2y_hwdep_pcm_vm_open,
688 .close = snd_usx2y_hwdep_pcm_vm_close,
689 .fault = snd_usx2y_hwdep_pcm_vm_fault,
690 };
691
snd_usx2y_hwdep_pcm_mmap(struct snd_hwdep * hw,struct file * filp,struct vm_area_struct * area)692 static int snd_usx2y_hwdep_pcm_mmap(struct snd_hwdep *hw, struct file *filp, struct vm_area_struct *area)
693 {
694 unsigned long size = (unsigned long)(area->vm_end - area->vm_start);
695 struct usx2ydev *usx2y = hw->private_data;
696
697 if (!(usx2y->chip_status & USX2Y_STAT_CHIP_INIT))
698 return -EBUSY;
699
700 /* if userspace tries to mmap beyond end of our buffer, fail */
701 if (size > USX2Y_HWDEP_PCM_PAGES) {
702 snd_printd("%lu > %lu\n", size, (unsigned long)USX2Y_HWDEP_PCM_PAGES);
703 return -EINVAL;
704 }
705
706 if (!usx2y->hwdep_pcm_shm)
707 return -ENODEV;
708
709 area->vm_ops = &snd_usx2y_hwdep_pcm_vm_ops;
710 area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
711 area->vm_private_data = hw->private_data;
712 return 0;
713 }
714
snd_usx2y_hwdep_pcm_private_free(struct snd_hwdep * hwdep)715 static void snd_usx2y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
716 {
717 struct usx2ydev *usx2y = hwdep->private_data;
718
719 if (usx2y->hwdep_pcm_shm)
720 free_pages_exact(usx2y->hwdep_pcm_shm, USX2Y_HWDEP_PCM_PAGES);
721 }
722
usx2y_hwdep_pcm_new(struct snd_card * card)723 int usx2y_hwdep_pcm_new(struct snd_card *card)
724 {
725 int err;
726 struct snd_hwdep *hw;
727 struct snd_pcm *pcm;
728 struct usb_device *dev = usx2y(card)->dev;
729
730 if (nr_of_packs() != 1)
731 return 0;
732
733 err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw);
734 if (err < 0)
735 return err;
736
737 hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
738 hw->private_data = usx2y(card);
739 hw->private_free = snd_usx2y_hwdep_pcm_private_free;
740 hw->ops.open = snd_usx2y_hwdep_pcm_open;
741 hw->ops.release = snd_usx2y_hwdep_pcm_release;
742 hw->ops.mmap = snd_usx2y_hwdep_pcm_mmap;
743 hw->exclusive = 1;
744 sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
745
746 err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
747 if (err < 0)
748 return err;
749
750 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usx2y_usbpcm_ops);
751 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usx2y_usbpcm_ops);
752
753 pcm->private_data = usx2y(card)->subs;
754 pcm->info_flags = 0;
755
756 sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
757 snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
758 SNDRV_DMA_TYPE_CONTINUOUS,
759 NULL,
760 64*1024, 128*1024);
761 snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
762 SNDRV_DMA_TYPE_CONTINUOUS,
763 NULL,
764 64*1024, 128*1024);
765
766 return 0;
767 }
768
769 #else
770
usx2y_hwdep_pcm_new(struct snd_card * card)771 int usx2y_hwdep_pcm_new(struct snd_card *card)
772 {
773 return 0;
774 }
775
776 #endif
777