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.
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.
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
17 /* USX2Y "rawusb" aka hwdep_pcm implementation
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.
23 The pair uses a hardware dependant alsa-device for mmaped pcm transport.
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,
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).
40 This is a first "proof of concept" implementation.
41 Later, funcionalities should migrate to more apropriate places:
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
46 Currently the usx2y jack driver provides above 2 services.
48 - rawusb dma pcm buffer transport should go to snd-usb-lib, so also snd-usb-audio
50 Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y.
53 #include <linux/delay.h>
54 #include "usbusx2yaudio.c"
56 #if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1)
58 #include <sound/hwdep.h>
61 static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs)
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) { //FIXME
68 int head = usX2Y->hwdep_pcm_shm->captured_iso_head + 1;
69 if (head >= ARRAY_SIZE(usX2Y->hwdep_pcm_shm->captured_iso))
71 usX2Y->hwdep_pcm_shm->capture_iso_start = head;
72 snd_printdd("cap start %i\n", head);
74 for (i = 0; i < nr_of_packs(); i++) {
75 if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
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;
79 lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;
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 /* update the pointer, call callback if necessary */
86 if (subs->transfer_done >= runtime->period_size) {
87 subs->transfer_done -= runtime->period_size;
88 snd_pcm_period_elapsed(subs->pcm_substream);
93 static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
94 struct usX2Ydev * usX2Y)
96 return (runtime->buffer_size * 1000) / usX2Y->rate + 1; //FIXME: so far only correct period_size == 2^x ?
100 * prepare urb for playback data pipe
102 * we copy the data directly from the pcm buffer.
103 * the current position to be copied is held in hwptr field.
104 * since a urb can handle only a single linear buffer, if the total
105 * transferred area overflows the buffer boundary, we cannot send
106 * it directly from the buffer. thus the data is once copied to
107 * a temporary buffer and urb points to that.
109 static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs,
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;
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;
126 for (pack = 0; pack < nr_of_packs(); pack++) {
127 /* calculate the size of a packet */
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);
133 /* set up descriptor */
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;
143 urb->transfer_buffer_length = count * usX2Y->stride;
148 static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream *subs,
152 for (pack = 0; pack < nr_of_packs(); ++pack) {
153 struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack;
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))
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++;
165 if ((desc->offset += desc->length * NRURBS*nr_of_packs()) +
167 desc->offset -= (SSS - desc->length);
171 static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream *capsubs,
172 struct snd_usX2Y_substream *capsubs2,
173 struct snd_usX2Y_substream *playbacksubs,
177 struct urb *urb = playbacksubs->completed_urb;
179 state = atomic_read(&playbacksubs->state);
181 if (state == state_RUNNING)
182 usX2Y_urb_play_retire(playbacksubs, urb);
183 else if (state >= state_PRERUNNING)
184 atomic_inc(&playbacksubs->state);
187 case state_STARTING1:
188 urb = playbacksubs->urb[0];
189 atomic_inc(&playbacksubs->state);
191 case state_STARTING2:
192 urb = playbacksubs->urb[1];
193 atomic_inc(&playbacksubs->state);
198 if ((err = usX2Y_hwdep_urb_play_prepare(playbacksubs, urb)) ||
199 (err = usX2Y_urb_submit(playbacksubs, urb, frame))) {
204 playbacksubs->completed_urb = NULL;
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)))
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)))
218 if (NULL != capsubs2)
219 if ((err = usX2Y_urb_submit(capsubs2, capsubs2->completed_urb, frame)))
222 capsubs->completed_urb = NULL;
223 if (NULL != capsubs2)
224 capsubs2->completed_urb = NULL;
229 static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
231 struct snd_usX2Y_substream *subs = urb->context;
232 struct usX2Ydev *usX2Y = subs->usX2Y;
233 struct snd_usX2Y_substream *capsubs, *capsubs2, *playbacksubs;
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);
242 if (unlikely(urb->status)) {
243 usX2Y_error_urb_status(usX2Y, subs, urb);
246 if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
247 subs->completed_urb = urb;
249 usX2Y_error_sequence(usX2Y, subs, urb);
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();
263 usX2Y_clients_stop(usX2Y);
269 static void usX2Y_hwdep_urb_release(struct urb **urb)
277 * release a substream
279 static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs)
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);
287 static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
289 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
290 usX2Y->prepare_subs = NULL;
293 static void i_usX2Y_usbpcm_subs_startup(struct urb *urb)
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);
306 usX2Y_usbpcm_subs_startup_finish(usX2Y);
307 wake_up(&usX2Y->prepare_wait_queue);
310 i_usX2Y_usbpcm_urb_complete(urb);
314 * initialize a substream's urbs
316 static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
320 int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
321 struct usb_device *dev = subs->usX2Y->chip.dev;
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)
329 /* allocate and initialize data urbs */
330 for (i = 0; i < NRURBS; i++) {
331 struct urb **purb = subs->urb + i;
336 *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
338 usX2Y_usbpcm_urbs_release(subs);
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);
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;
360 static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
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);
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);
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);
394 mutex_unlock(&subs->usX2Y->prepare_mutex);
395 return snd_pcm_lib_free_pages(substream);
398 static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
400 struct usX2Ydev * usX2Y = subs->usX2Y;
401 usX2Y->prepare_subs = subs;
402 subs->urb[0]->start_frame = -1;
403 smp_wmb(); // Make sure above modifications are seen by i_usX2Y_subs_startup()
404 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
407 static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
410 stream = subs->pcm_substream->stream;
411 struct usX2Ydev *usX2Y = subs->usX2Y;
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;
418 for (p = 0; 3 >= (stream + p); p += 2) {
419 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
421 if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
423 subs->completed_urb = NULL;
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)
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];
439 struct urb *urb = subs->urb[u];
440 if (usb_pipein(urb->pipe)) {
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;
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);
456 snd_printdd("%i\n", urb->start_frame);
458 usX2Y->wait_iso_frame = urb->start_frame;
460 urb->transfer_flags = 0;
462 atomic_set(&subs->state, state_STARTING1);
469 wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
470 if (atomic_read(&subs->state) != state_PREPARED)
475 usX2Y_subs_startup_finish(usX2Y); // Call it now
476 usX2Y_clients_stop(usX2Y); // something is completely wroong > stop evrything
484 * set format and initialize urbs
486 static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
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];
493 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
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)))
498 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
501 mutex_lock(&usX2Y->prepare_mutex);
502 usX2Y_subs_prepare(subs);
503 // Start hardware streams
504 // SyncStream first....
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;
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)) {
529 goto up_prepare_mutex;
532 if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
533 goto up_prepare_mutex;
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);
539 usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
542 mutex_unlock(&usX2Y->prepare_mutex);
546 static struct snd_pcm_hardware snd_usX2Y_4c =
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,
557 .buffer_bytes_max = (2*128*1024),
558 .period_bytes_min = 64,
559 .period_bytes_max = (128*1024),
567 static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
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;
573 if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
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);
585 static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
587 struct snd_pcm_runtime *runtime = substream->runtime;
588 struct snd_usX2Y_substream *subs = runtime->private_data;
590 subs->pcm_substream = NULL;
595 static struct snd_pcm_ops snd_usX2Y_usbpcm_ops =
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,
608 static int usX2Y_pcms_lock_check(struct snd_card *card)
610 struct list_head *list;
611 struct snd_device *dev;
614 list_for_each(list, &card->devices) {
615 dev = snd_device(list);
616 if (dev->type != SNDRV_DEV_PCM)
618 pcm = dev->device_data;
619 mutex_lock(&pcm->open_mutex);
621 list_for_each(list, &card->devices) {
623 dev = snd_device(list);
624 if (dev->type != SNDRV_DEV_PCM)
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))
638 static void usX2Y_pcms_unlock(struct snd_card *card)
640 struct list_head *list;
641 struct snd_device *dev;
643 list_for_each(list, &card->devices) {
644 dev = snd_device(list);
645 if (dev->type != SNDRV_DEV_PCM)
647 pcm = dev->device_data;
648 mutex_unlock(&pcm->open_mutex);
653 static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
655 // we need to be the first
656 struct snd_card *card = hw->card;
657 int err = usX2Y_pcms_lock_check(card);
659 usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
660 usX2Y_pcms_unlock(card);
665 static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
667 struct snd_card *card = hw->card;
668 int err = usX2Y_pcms_lock_check(card);
670 usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
671 usX2Y_pcms_unlock(card);
676 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
681 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
686 static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area,
687 struct vm_fault *vmf)
689 unsigned long offset;
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);
700 static 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,
707 static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
709 unsigned long size = (unsigned long)(area->vm_end - area->vm_start);
710 struct usX2Ydev *usX2Y = hw->private_data;
712 if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
715 /* if userspace tries to mmap beyond end of our buffer, fail */
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));
721 if (!usX2Y->hwdep_pcm_shm) {
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;
731 static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
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));
739 int usX2Y_hwdep_pcm_new(struct snd_card *card)
742 struct snd_hwdep *hw;
744 struct usb_device *dev = usX2Y(card)->chip.dev;
745 if (1 != nr_of_packs())
748 if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
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;
758 sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
760 err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
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);
767 pcm->private_data = usX2Y(card)->subs;
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))) {
788 int usX2Y_hwdep_pcm_new(struct snd_card *card)