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