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