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 <linux/gfp.h>
55#include "usbusx2yaudio.c"
56
57#if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
58
59#include <sound/hwdep.h>
60
61
62static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs)
63{
64 struct urb *urb = subs->completed_urb;
65 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
66 int i, lens = 0, hwptr_done = subs->hwptr_done;
67 struct usX2Ydev *usX2Y = subs->usX2Y;
68 if (0 > usX2Y->hwdep_pcm_shm->capture_iso_start) {
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) {
77 snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status);
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
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
94static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
95 struct usX2Ydev * usX2Y)
96{
97 return (runtime->buffer_size * 1000) / usX2Y->rate + 1;
98}
99
100
101
102
103
104
105
106
107
108
109
110static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs,
111 struct urb *urb)
112{
113 int count, counts, pack;
114 struct usX2Ydev *usX2Y = subs->usX2Y;
115 struct snd_usX2Y_hwdep_pcm_shm *shm = usX2Y->hwdep_pcm_shm;
116 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
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
129 counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride;
130 if (counts < 43 || counts > 50) {
131 snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
132 return -EPIPE;
133 }
134
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
149static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream *subs,
150 struct urb *urb)
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) {
156 struct snd_usX2Y_hwdep_pcm_shm *shm = subs->usX2Y->hwdep_pcm_shm;
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
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)
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);
184 else if (state >= state_PRERUNNING)
185 atomic_inc(&playbacksubs->state);
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;
212 } else if (state >= state_PRERUNNING)
213 atomic_inc(&capsubs->state);
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
230static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
231{
232 struct snd_usX2Y_substream *subs = urb->context;
233 struct usX2Ydev *usX2Y = subs->usX2Y;
234 struct snd_usX2Y_substream *capsubs, *capsubs2, *playbacksubs;
235
236 if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
237 snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
238 usb_get_current_frame_number(usX2Y->dev),
239 subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
240 urb->status, urb->start_frame);
241 return;
242 }
243 if (unlikely(urb->status)) {
244 usX2Y_error_urb_status(usX2Y, subs, urb);
245 return;
246 }
247 if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
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)) {
260 if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame))
261 usX2Y->wait_iso_frame += nr_of_packs();
262 else {
263 snd_printdd("\n");
264 usX2Y_clients_stop(usX2Y);
265 }
266 }
267}
268
269
270static void usX2Y_hwdep_urb_release(struct urb **urb)
271{
272 usb_kill_urb(*urb);
273 usb_free_urb(*urb);
274 *urb = NULL;
275}
276
277
278
279
280static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs)
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
288static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
289{
290 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
291 usX2Y->prepare_subs = NULL;
292}
293
294static void i_usX2Y_usbpcm_subs_startup(struct urb *urb)
295{
296 struct snd_usX2Y_substream *subs = urb->context;
297 struct usX2Ydev *usX2Y = subs->usX2Y;
298 struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs;
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]) {
303 struct snd_usX2Y_substream *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
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
311 i_usX2Y_usbpcm_urb_complete(urb);
312}
313
314
315
316
317static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
318{
319 int i;
320 unsigned int pipe;
321 int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
322 struct usb_device *dev = subs->usX2Y->dev;
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
331 for (i = 0; i < NRURBS; i++) {
332 struct urb **purb = subs->urb + i;
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
360
361static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
362{
363 struct snd_pcm_runtime *runtime = substream->runtime;
364 struct snd_usX2Y_substream *subs = runtime->private_data,
365 *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
366 mutex_lock(&subs->usX2Y->prepare_mutex);
367 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
368
369 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
370 struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
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 {
385 struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
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 }
395 mutex_unlock(&subs->usX2Y->prepare_mutex);
396 return snd_pcm_lib_free_pages(substream);
397}
398
399static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
400{
401 struct usX2Ydev * usX2Y = subs->usX2Y;
402 usX2Y->prepare_subs = subs;
403 subs->urb[0]->start_frame = -1;
404 smp_wmb();
405 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
406}
407
408static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
409{
410 int p, u, err,
411 stream = subs->pcm_substream->stream;
412 struct usX2Ydev *usX2Y = subs->usX2Y;
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) {
420 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
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++) {
429 struct snd_usX2Y_substream *subs = usX2Y->subs[p];
430 if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
431 goto start;
432 }
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) {
438 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
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);
445 urb->dev = usX2Y->dev;
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);
458 if (u == 0)
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);
477 usX2Y_clients_stop(usX2Y);
478 }
479 return err;
480}
481
482
483
484
485
486
487static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
488{
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];
493 int err = 0;
494 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
495
496 if (NULL == usX2Y->hwdep_pcm_shm) {
497 if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm), GFP_KERNEL)))
498 return -ENOMEM;
499 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
500 }
501
502 mutex_lock(&usX2Y->prepare_mutex);
503 usX2Y_subs_prepare(subs);
504
505
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;
513 snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
514 "self" : "playpipe");
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) {
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);
528 if (msleep_interruptible(10)) {
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 }
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);
539 } else
540 usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
541
542 up_prepare_mutex:
543 mutex_unlock(&usX2Y->prepare_mutex);
544 return err;
545}
546
547static struct snd_pcm_hardware snd_usX2Y_4c =
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
568static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
569{
570 struct snd_usX2Y_substream *subs = ((struct snd_usX2Y_substream **)
571 snd_pcm_substream_chip(substream))[substream->stream];
572 struct snd_pcm_runtime *runtime = substream->runtime;
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
586static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
587{
588 struct snd_pcm_runtime *runtime = substream->runtime;
589 struct snd_usX2Y_substream *subs = runtime->private_data;
590
591 subs->pcm_substream = NULL;
592 return 0;
593}
594
595
596static struct snd_pcm_ops snd_usX2Y_usbpcm_ops =
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
609static int usX2Y_pcms_lock_check(struct snd_card *card)
610{
611 struct list_head *list;
612 struct snd_device *dev;
613 struct snd_pcm *pcm;
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;
620 mutex_lock(&pcm->open_mutex);
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) {
629 struct snd_pcm_substream *substream;
630 substream = pcm->streams[s].substream;
631 if (substream && SUBSTREAM_BUSY(substream))
632 err = -EBUSY;
633 }
634 }
635 return err;
636}
637
638
639static void usX2Y_pcms_unlock(struct snd_card *card)
640{
641 struct list_head *list;
642 struct snd_device *dev;
643 struct snd_pcm *pcm;
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;
649 mutex_unlock(&pcm->open_mutex);
650 }
651}
652
653
654static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
655{
656
657 struct snd_card *card = hw->card;
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
666static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
667{
668 struct snd_card *card = hw->card;
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
687static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area,
688 struct vm_fault *vmf)
689{
690 unsigned long offset;
691 void *vaddr;
692
693 offset = vmf->pgoff << PAGE_SHIFT;
694 vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset;
695 vmf->page = virt_to_page(vaddr);
696 get_page(vmf->page);
697 return 0;
698}
699
700
701static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
702 .open = snd_usX2Y_hwdep_pcm_vm_open,
703 .close = snd_usX2Y_hwdep_pcm_vm_close,
704 .fault = snd_usX2Y_hwdep_pcm_vm_fault,
705};
706
707
708static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
709{
710 unsigned long size = (unsigned long)(area->vm_end - area->vm_start);
711 struct usX2Ydev *usX2Y = hw->private_data;
712
713 if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
714 return -EBUSY;
715
716
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));
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;
726 area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
727 area->vm_private_data = hw->private_data;
728 return 0;
729}
730
731
732static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
733{
734 struct usX2Ydev *usX2Y = hwdep->private_data;
735 if (NULL != usX2Y->hwdep_pcm_shm)
736 snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
737}
738
739
740int usX2Y_hwdep_pcm_new(struct snd_card *card)
741{
742 int err;
743 struct snd_hwdep *hw;
744 struct snd_pcm *pcm;
745 struct usb_device *dev = usX2Y(card)->dev;
746 if (1 != nr_of_packs())
747 return 0;
748
749 if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
750 return err;
751
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;
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))) {
780 return err;
781 }
782
783
784 return 0;
785}
786
787#else
788
789int usX2Y_hwdep_pcm_new(struct snd_card *card)
790{
791 return 0;
792}
793
794#endif
795