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