ALSA: usb: Remove superfluous snd_dma_continuous_data()
[linux-2.6-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,
9 what led to this part of the usx2y module:
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.
38 Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y.
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
49
bbe85bbd 50static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs)
1da177e4
LT
51{
52 struct urb *urb = subs->completed_urb;
bbe85bbd 53 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
1da177e4 54 int i, lens = 0, hwptr_done = subs->hwptr_done;
bbe85bbd 55 struct usX2Ydev *usX2Y = subs->usX2Y;
1da177e4
LT
56 if (0 > usX2Y->hwdep_pcm_shm->capture_iso_start) { //FIXME
57 int head = usX2Y->hwdep_pcm_shm->captured_iso_head + 1;
58 if (head >= ARRAY_SIZE(usX2Y->hwdep_pcm_shm->captured_iso))
59 head = 0;
60 usX2Y->hwdep_pcm_shm->capture_iso_start = head;
61 snd_printdd("cap start %i\n", head);
62 }
63 for (i = 0; i < nr_of_packs(); i++) {
64 if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
6e8d5d2f 65 snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status);
1da177e4
LT
66 return urb->iso_frame_desc[i].status;
67 }
68 lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;
69 }
70 if ((hwptr_done += lens) >= runtime->buffer_size)
71 hwptr_done -= runtime->buffer_size;
72 subs->hwptr_done = hwptr_done;
73 subs->transfer_done += lens;
74 /* update the pointer, call callback if necessary */
75 if (subs->transfer_done >= runtime->period_size) {
76 subs->transfer_done -= runtime->period_size;
77 snd_pcm_period_elapsed(subs->pcm_substream);
78 }
79 return 0;
80}
81
bbe85bbd
TI
82static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
83 struct usX2Ydev * usX2Y)
1da177e4
LT
84{
85 return (runtime->buffer_size * 1000) / usX2Y->rate + 1; //FIXME: so far only correct period_size == 2^x ?
86}
87
88/*
89 * prepare urb for playback data pipe
90 *
91 * we copy the data directly from the pcm buffer.
92 * the current position to be copied is held in hwptr field.
93 * since a urb can handle only a single linear buffer, if the total
94 * transferred area overflows the buffer boundary, we cannot send
95 * it directly from the buffer. thus the data is once copied to
96 * a temporary buffer and urb points to that.
97 */
bbe85bbd
TI
98static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs,
99 struct urb *urb)
1da177e4
LT
100{
101 int count, counts, pack;
bbe85bbd 102 struct usX2Ydev *usX2Y = subs->usX2Y;
1da177e4 103 struct snd_usX2Y_hwdep_pcm_shm *shm = usX2Y->hwdep_pcm_shm;
bbe85bbd 104 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
1da177e4
LT
105
106 if (0 > shm->playback_iso_start) {
107 shm->playback_iso_start = shm->captured_iso_head -
108 usX2Y_iso_frames_per_buffer(runtime, usX2Y);
109 if (0 > shm->playback_iso_start)
110 shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
111 shm->playback_iso_head = shm->playback_iso_start;
112 }
113
114 count = 0;
115 for (pack = 0; pack < nr_of_packs(); pack++) {
116 /* calculate the size of a packet */
117 counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride;
118 if (counts < 43 || counts > 50) {
d3d579f8 119 snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
1da177e4
LT
120 return -EPIPE;
121 }
122 /* set up descriptor */
123 urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
124 urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
125 if (atomic_read(&subs->state) != state_RUNNING)
126 memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
127 urb->iso_frame_desc[pack].length);
128 if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
129 shm->playback_iso_head = 0;
130 count += counts;
131 }
132 urb->transfer_buffer_length = count * usX2Y->stride;
133 return 0;
134}
135
136
bbe85bbd
TI
137static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream *subs,
138 struct urb *urb)
1da177e4
LT
139{
140 int pack;
141 for (pack = 0; pack < nr_of_packs(); ++pack) {
142 struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack;
143 if (NULL != subs) {
bbe85bbd 144 struct snd_usX2Y_hwdep_pcm_shm *shm = subs->usX2Y->hwdep_pcm_shm;
1da177e4
LT
145 int head = shm->captured_iso_head + 1;
146 if (head >= ARRAY_SIZE(shm->captured_iso))
147 head = 0;
148 shm->captured_iso[head].frame = urb->start_frame + pack;
149 shm->captured_iso[head].offset = desc->offset;
150 shm->captured_iso[head].length = desc->actual_length;
151 shm->captured_iso_head = head;
152 shm->captured_iso_frames++;
153 }
154 if ((desc->offset += desc->length * NRURBS*nr_of_packs()) +
155 desc->length >= SSS)
156 desc->offset -= (SSS - desc->length);
157 }
158}
159
bbe85bbd
TI
160static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream *capsubs,
161 struct snd_usX2Y_substream *capsubs2,
162 struct snd_usX2Y_substream *playbacksubs,
163 int frame)
1da177e4
LT
164{
165 int err, state;
166 struct urb *urb = playbacksubs->completed_urb;
167
168 state = atomic_read(&playbacksubs->state);
169 if (NULL != urb) {
170 if (state == state_RUNNING)
171 usX2Y_urb_play_retire(playbacksubs, urb);
cb432379
TI
172 else if (state >= state_PRERUNNING)
173 atomic_inc(&playbacksubs->state);
1da177e4
LT
174 } else {
175 switch (state) {
176 case state_STARTING1:
177 urb = playbacksubs->urb[0];
178 atomic_inc(&playbacksubs->state);
179 break;
180 case state_STARTING2:
181 urb = playbacksubs->urb[1];
182 atomic_inc(&playbacksubs->state);
183 break;
184 }
185 }
186 if (urb) {
187 if ((err = usX2Y_hwdep_urb_play_prepare(playbacksubs, urb)) ||
188 (err = usX2Y_urb_submit(playbacksubs, urb, frame))) {
189 return err;
190 }
191 }
192
193 playbacksubs->completed_urb = NULL;
194
195 state = atomic_read(&capsubs->state);
196 if (state >= state_PREPARED) {
197 if (state == state_RUNNING) {
198 if ((err = usX2Y_usbpcm_urb_capt_retire(capsubs)))
199 return err;
cb432379
TI
200 } else if (state >= state_PRERUNNING)
201 atomic_inc(&capsubs->state);
1da177e4
LT
202 usX2Y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
203 if (NULL != capsubs2)
204 usX2Y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
205 if ((err = usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame)))
206 return err;
207 if (NULL != capsubs2)
208 if ((err = usX2Y_urb_submit(capsubs2, capsubs2->completed_urb, frame)))
209 return err;
210 }
211 capsubs->completed_urb = NULL;
212 if (NULL != capsubs2)
213 capsubs2->completed_urb = NULL;
214 return 0;
215}
216
217
7d12e780 218static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
1da177e4 219{
bbe85bbd
TI
220 struct snd_usX2Y_substream *subs = urb->context;
221 struct usX2Ydev *usX2Y = subs->usX2Y;
222 struct snd_usX2Y_substream *capsubs, *capsubs2, *playbacksubs;
1da177e4
LT
223
224 if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
bbe85bbd 225 snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
a014bbad 226 usb_get_current_frame_number(usX2Y->dev),
bbe85bbd
TI
227 subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
228 urb->status, urb->start_frame);
1da177e4
LT
229 return;
230 }
231 if (unlikely(urb->status)) {
232 usX2Y_error_urb_status(usX2Y, subs, urb);
233 return;
234 }
1da177e4 235
a9d14bc0 236 subs->completed_urb = urb;
1da177e4
LT
237 capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
238 capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
239 playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
240 if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
241 (NULL == capsubs2 || capsubs2->completed_urb) &&
242 (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
635bbb35
KW
243 if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame))
244 usX2Y->wait_iso_frame += nr_of_packs();
245 else {
1da177e4
LT
246 snd_printdd("\n");
247 usX2Y_clients_stop(usX2Y);
248 }
249 }
250}
251
252
bbe85bbd 253static void usX2Y_hwdep_urb_release(struct urb **urb)
1da177e4
LT
254{
255 usb_kill_urb(*urb);
256 usb_free_urb(*urb);
257 *urb = NULL;
258}
259
260/*
261 * release a substream
262 */
bbe85bbd 263static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs)
1da177e4
LT
264{
265 int i;
266 snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
267 for (i = 0; i < NRURBS; i++)
268 usX2Y_hwdep_urb_release(subs->urb + i);
269}
270
bbe85bbd 271static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
1da177e4
LT
272{
273 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
274 usX2Y->prepare_subs = NULL;
275}
276
7d12e780 277static void i_usX2Y_usbpcm_subs_startup(struct urb *urb)
1da177e4 278{
bbe85bbd
TI
279 struct snd_usX2Y_substream *subs = urb->context;
280 struct usX2Ydev *usX2Y = subs->usX2Y;
281 struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs;
1da177e4
LT
282 if (NULL != prepare_subs &&
283 urb->start_frame == prepare_subs->urb[0]->start_frame) {
284 atomic_inc(&prepare_subs->state);
285 if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
bbe85bbd 286 struct snd_usX2Y_substream *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
1da177e4
LT
287 if (cap_subs2 != NULL)
288 atomic_inc(&cap_subs2->state);
289 }
290 usX2Y_usbpcm_subs_startup_finish(usX2Y);
291 wake_up(&usX2Y->prepare_wait_queue);
292 }
293
7d12e780 294 i_usX2Y_usbpcm_urb_complete(urb);
1da177e4
LT
295}
296
297/*
298 * initialize a substream's urbs
299 */
bbe85bbd 300static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
1da177e4
LT
301{
302 int i;
303 unsigned int pipe;
304 int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
a014bbad 305 struct usb_device *dev = subs->usX2Y->dev;
1da177e4
LT
306
307 pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
308 usb_rcvisocpipe(dev, subs->endpoint);
309 subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
310 if (!subs->maxpacksize)
311 return -EINVAL;
312
313 /* allocate and initialize data urbs */
314 for (i = 0; i < NRURBS; i++) {
cb432379 315 struct urb **purb = subs->urb + i;
1da177e4
LT
316 if (*purb) {
317 usb_kill_urb(*purb);
318 continue;
319 }
320 *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
321 if (NULL == *purb) {
322 usX2Y_usbpcm_urbs_release(subs);
323 return -ENOMEM;
324 }
325 (*purb)->transfer_buffer = is_playback ?
326 subs->usX2Y->hwdep_pcm_shm->playback : (
327 subs->endpoint == 0x8 ?
328 subs->usX2Y->hwdep_pcm_shm->capture0x8 :
329 subs->usX2Y->hwdep_pcm_shm->capture0xA);
330
331 (*purb)->dev = dev;
332 (*purb)->pipe = pipe;
333 (*purb)->number_of_packets = nr_of_packs();
334 (*purb)->context = subs;
335 (*purb)->interval = 1;
336 (*purb)->complete = i_usX2Y_usbpcm_subs_startup;
337 }
338 return 0;
339}
340
341/*
342 * free the buffer
343 */
bbe85bbd 344static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
1da177e4 345{
bbe85bbd
TI
346 struct snd_pcm_runtime *runtime = substream->runtime;
347 struct snd_usX2Y_substream *subs = runtime->private_data,
1da177e4 348 *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
e2439a54 349 mutex_lock(&subs->usX2Y->pcm_mutex);
1da177e4
LT
350 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
351
352 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
bbe85bbd 353 struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
1da177e4
LT
354 atomic_set(&subs->state, state_STOPPED);
355 usX2Y_usbpcm_urbs_release(subs);
356 if (!cap_subs->pcm_substream ||
357 !cap_subs->pcm_substream->runtime ||
358 !cap_subs->pcm_substream->runtime->status ||
359 cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
360 atomic_set(&cap_subs->state, state_STOPPED);
361 if (NULL != cap_subs2)
362 atomic_set(&cap_subs2->state, state_STOPPED);
363 usX2Y_usbpcm_urbs_release(cap_subs);
364 if (NULL != cap_subs2)
365 usX2Y_usbpcm_urbs_release(cap_subs2);
366 }
367 } else {
bbe85bbd 368 struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
1da177e4
LT
369 if (atomic_read(&playback_subs->state) < state_PREPARED) {
370 atomic_set(&subs->state, state_STOPPED);
371 if (NULL != cap_subs2)
372 atomic_set(&cap_subs2->state, state_STOPPED);
373 usX2Y_usbpcm_urbs_release(subs);
374 if (NULL != cap_subs2)
375 usX2Y_usbpcm_urbs_release(cap_subs2);
376 }
377 }
e2439a54 378 mutex_unlock(&subs->usX2Y->pcm_mutex);
1da177e4
LT
379 return snd_pcm_lib_free_pages(substream);
380}
381
bbe85bbd 382static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
1da177e4 383{
bbe85bbd 384 struct usX2Ydev * usX2Y = subs->usX2Y;
1da177e4
LT
385 usX2Y->prepare_subs = subs;
386 subs->urb[0]->start_frame = -1;
7f927fcc 387 smp_wmb(); // Make sure above modifications are seen by i_usX2Y_subs_startup()
1da177e4
LT
388 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
389}
390
bbe85bbd 391static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
1da177e4
LT
392{
393 int p, u, err,
394 stream = subs->pcm_substream->stream;
bbe85bbd 395 struct usX2Ydev *usX2Y = subs->usX2Y;
1da177e4
LT
396
397 if (SNDRV_PCM_STREAM_CAPTURE == stream) {
398 usX2Y->hwdep_pcm_shm->captured_iso_head = -1;
399 usX2Y->hwdep_pcm_shm->captured_iso_frames = 0;
400 }
401
402 for (p = 0; 3 >= (stream + p); p += 2) {
bbe85bbd 403 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
1da177e4
LT
404 if (subs != NULL) {
405 if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
406 return err;
407 subs->completed_urb = NULL;
408 }
409 }
410
411 for (p = 0; p < 4; p++) {
bbe85bbd 412 struct snd_usX2Y_substream *subs = usX2Y->subs[p];
1da177e4
LT
413 if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
414 goto start;
415 }
1da177e4
LT
416
417 start:
418 usX2Y_usbpcm_subs_startup(subs);
419 for (u = 0; u < NRURBS; u++) {
420 for (p = 0; 3 >= (stream + p); p += 2) {
bbe85bbd 421 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
1da177e4
LT
422 if (subs != NULL) {
423 struct urb *urb = subs->urb[u];
424 if (usb_pipein(urb->pipe)) {
425 unsigned long pack;
426 if (0 == u)
427 atomic_set(&subs->state, state_STARTING3);
a014bbad 428 urb->dev = usX2Y->dev;
1da177e4
LT
429 for (pack = 0; pack < nr_of_packs(); pack++) {
430 urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
431 urb->iso_frame_desc[pack].length = subs->maxpacksize;
432 }
433 urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
434 if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
435 snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
436 err = -EPIPE;
437 goto cleanup;
438 } else {
439 snd_printdd("%i\n", urb->start_frame);
635bbb35 440 if (u == 0)
1da177e4
LT
441 usX2Y->wait_iso_frame = urb->start_frame;
442 }
443 urb->transfer_flags = 0;
444 } else {
445 atomic_set(&subs->state, state_STARTING1);
446 break;
447 }
448 }
449 }
450 }
451 err = 0;
452 wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
453 if (atomic_read(&subs->state) != state_PREPARED)
454 err = -EPIPE;
455
456 cleanup:
457 if (err) {
458 usX2Y_subs_startup_finish(usX2Y); // Call it now
459 usX2Y_clients_stop(usX2Y); // something is completely wroong > stop evrything
460 }
461 return err;
462}
463
464/*
465 * prepare callback
466 *
467 * set format and initialize urbs
468 */
bbe85bbd 469static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
1da177e4 470{
bbe85bbd
TI
471 struct snd_pcm_runtime *runtime = substream->runtime;
472 struct snd_usX2Y_substream *subs = runtime->private_data;
473 struct usX2Ydev *usX2Y = subs->usX2Y;
474 struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
1da177e4
LT
475 int err = 0;
476 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
477
478 if (NULL == usX2Y->hwdep_pcm_shm) {
734b5a0b
TI
479 usX2Y->hwdep_pcm_shm = alloc_pages_exact(sizeof(struct snd_usX2Y_hwdep_pcm_shm),
480 GFP_KERNEL);
481 if (!usX2Y->hwdep_pcm_shm)
1da177e4 482 return -ENOMEM;
bbe85bbd 483 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
1da177e4
LT
484 }
485
e2439a54 486 mutex_lock(&usX2Y->pcm_mutex);
1da177e4
LT
487 usX2Y_subs_prepare(subs);
488// Start hardware streams
489// SyncStream first....
490 if (atomic_read(&capsubs->state) < state_PREPARED) {
491 if (usX2Y->format != runtime->format)
492 if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
493 goto up_prepare_mutex;
494 if (usX2Y->rate != runtime->rate)
495 if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
496 goto up_prepare_mutex;
bbe85bbd
TI
497 snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
498 "self" : "playpipe");
1da177e4
LT
499 if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs)))
500 goto up_prepare_mutex;
501 }
502
503 if (subs != capsubs) {
504 usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
505 if (atomic_read(&subs->state) < state_PREPARED) {
bbe85bbd
TI
506 while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) >
507 usX2Y->hwdep_pcm_shm->captured_iso_frames) {
508 snd_printdd("Wait: iso_frames_per_buffer=%i,"
509 "captured_iso_frames=%i\n",
510 usX2Y_iso_frames_per_buffer(runtime, usX2Y),
511 usX2Y->hwdep_pcm_shm->captured_iso_frames);
b27c187f 512 if (msleep_interruptible(10)) {
1da177e4
LT
513 err = -ERESTARTSYS;
514 goto up_prepare_mutex;
515 }
516 }
517 if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
518 goto up_prepare_mutex;
519 }
bbe85bbd
TI
520 snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
521 usX2Y_iso_frames_per_buffer(runtime, usX2Y),
522 usX2Y->hwdep_pcm_shm->captured_iso_frames);
1da177e4
LT
523 } else
524 usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
525
526 up_prepare_mutex:
e2439a54 527 mutex_unlock(&usX2Y->pcm_mutex);
1da177e4
LT
528 return err;
529}
530
bbe85bbd 531static struct snd_pcm_hardware snd_usX2Y_4c =
1da177e4
LT
532{
533 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
534 SNDRV_PCM_INFO_BLOCK_TRANSFER |
535 SNDRV_PCM_INFO_MMAP_VALID),
536 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
537 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
538 .rate_min = 44100,
539 .rate_max = 48000,
540 .channels_min = 2,
541 .channels_max = 4,
542 .buffer_bytes_max = (2*128*1024),
543 .period_bytes_min = 64,
544 .period_bytes_max = (128*1024),
545 .periods_min = 2,
546 .periods_max = 1024,
547 .fifo_size = 0
548};
549
550
551
bbe85bbd 552static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
1da177e4 553{
bbe85bbd 554 struct snd_usX2Y_substream *subs = ((struct snd_usX2Y_substream **)
1da177e4 555 snd_pcm_substream_chip(substream))[substream->stream];
bbe85bbd 556 struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4
LT
557
558 if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
559 return -EBUSY;
560
561 runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
562 (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
563 runtime->private_data = subs;
564 subs->pcm_substream = substream;
565 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
566 return 0;
567}
568
569
bbe85bbd 570static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
1da177e4 571{
bbe85bbd
TI
572 struct snd_pcm_runtime *runtime = substream->runtime;
573 struct snd_usX2Y_substream *subs = runtime->private_data;
cb432379 574
1da177e4 575 subs->pcm_substream = NULL;
cb432379 576 return 0;
1da177e4
LT
577}
578
579
31cb1fb4 580static const struct snd_pcm_ops snd_usX2Y_usbpcm_ops =
1da177e4
LT
581{
582 .open = snd_usX2Y_usbpcm_open,
583 .close = snd_usX2Y_usbpcm_close,
584 .ioctl = snd_pcm_lib_ioctl,
585 .hw_params = snd_usX2Y_pcm_hw_params,
586 .hw_free = snd_usX2Y_usbpcm_hw_free,
587 .prepare = snd_usX2Y_usbpcm_prepare,
588 .trigger = snd_usX2Y_pcm_trigger,
589 .pointer = snd_usX2Y_pcm_pointer,
590};
591
592
e2439a54 593static int usX2Y_pcms_busy_check(struct snd_card *card)
1da177e4 594{
e2439a54
TI
595 struct usX2Ydev *dev = usX2Y(card);
596 int i;
1da177e4 597
e2439a54
TI
598 for (i = 0; i < dev->pcm_devs * 2; i++) {
599 struct snd_usX2Y_substream *subs = dev->subs[i];
600 if (subs && subs->pcm_substream &&
601 SUBSTREAM_BUSY(subs->pcm_substream))
602 return -EBUSY;
1da177e4 603 }
e2439a54 604 return 0;
1da177e4
LT
605}
606
bbe85bbd 607static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
1da177e4 608{
bbe85bbd 609 struct snd_card *card = hw->card;
e2439a54
TI
610 int err;
611
612 mutex_lock(&usX2Y(card)->pcm_mutex);
613 err = usX2Y_pcms_busy_check(card);
614 if (!err)
1da177e4 615 usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
e2439a54 616 mutex_unlock(&usX2Y(card)->pcm_mutex);
1da177e4
LT
617 return err;
618}
619
620
bbe85bbd 621static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
1da177e4 622{
bbe85bbd 623 struct snd_card *card = hw->card;
e2439a54
TI
624 int err;
625
626 mutex_lock(&usX2Y(card)->pcm_mutex);
627 err = usX2Y_pcms_busy_check(card);
628 if (!err)
1da177e4 629 usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
e2439a54 630 mutex_unlock(&usX2Y(card)->pcm_mutex);
1da177e4
LT
631 return err;
632}
633
634
635static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
636{
637}
638
639
640static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
641{
642}
643
644
29581051 645static vm_fault_t snd_usX2Y_hwdep_pcm_vm_fault(struct vm_fault *vmf)
1da177e4
LT
646{
647 unsigned long offset;
1da177e4
LT
648 void *vaddr;
649
eb415b8f 650 offset = vmf->pgoff << PAGE_SHIFT;
11bac800 651 vaddr = (char *)((struct usX2Ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset;
eb415b8f
NP
652 vmf->page = virt_to_page(vaddr);
653 get_page(vmf->page);
654 return 0;
1da177e4
LT
655}
656
657
f0f37e2f 658static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
1da177e4
LT
659 .open = snd_usX2Y_hwdep_pcm_vm_open,
660 .close = snd_usX2Y_hwdep_pcm_vm_close,
eb415b8f 661 .fault = snd_usX2Y_hwdep_pcm_vm_fault,
1da177e4
LT
662};
663
664
bbe85bbd 665static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
1da177e4
LT
666{
667 unsigned long size = (unsigned long)(area->vm_end - area->vm_start);
bbe85bbd 668 struct usX2Ydev *usX2Y = hw->private_data;
1da177e4 669
cb432379 670 if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
1da177e4
LT
671 return -EBUSY;
672
673 /* if userspace tries to mmap beyond end of our buffer, fail */
bbe85bbd
TI
674 if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) {
675 snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm));
1da177e4
LT
676 return -EINVAL;
677 }
678
679 if (!usX2Y->hwdep_pcm_shm) {
680 return -ENODEV;
681 }
682 area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
314e51b9 683 area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
1da177e4
LT
684 area->vm_private_data = hw->private_data;
685 return 0;
686}
687
688
bbe85bbd 689static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
1da177e4 690{
bbe85bbd 691 struct usX2Ydev *usX2Y = hwdep->private_data;
1da177e4 692 if (NULL != usX2Y->hwdep_pcm_shm)
734b5a0b 693 free_pages_exact(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
1da177e4
LT
694}
695
696
bbe85bbd 697int usX2Y_hwdep_pcm_new(struct snd_card *card)
1da177e4
LT
698{
699 int err;
bbe85bbd
TI
700 struct snd_hwdep *hw;
701 struct snd_pcm *pcm;
a014bbad 702 struct usb_device *dev = usX2Y(card)->dev;
1da177e4
LT
703 if (1 != nr_of_packs())
704 return 0;
705
cb432379 706 if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
1da177e4 707 return err;
cb432379 708
1da177e4
LT
709 hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
710 hw->private_data = usX2Y(card);
711 hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
712 hw->ops.open = snd_usX2Y_hwdep_pcm_open;
713 hw->ops.release = snd_usX2Y_hwdep_pcm_release;
714 hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
715 hw->exclusive = 1;
a5f8661d 716 sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
1da177e4
LT
717
718 err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
719 if (err < 0) {
720 return err;
721 }
722 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
723 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
724
725 pcm->private_data = usX2Y(card)->subs;
1da177e4
LT
726 pcm->info_flags = 0;
727
728 sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
4d1b5303
TI
729 snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
730 SNDRV_DMA_TYPE_CONTINUOUS,
0af0a4fe 731 NULL,
4d1b5303
TI
732 64*1024, 128*1024);
733 snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
734 SNDRV_DMA_TYPE_CONTINUOUS,
0af0a4fe 735 NULL,
4d1b5303 736 64*1024, 128*1024);
1da177e4
LT
737
738 return 0;
739}
740
741#else
742
bbe85bbd 743int usX2Y_hwdep_pcm_new(struct snd_card *card)
1da177e4
LT
744{
745 return 0;
746}
747
748#endif