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, struct pt_regs *regs)
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((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame))
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 if (nr_of_packs() <= urb->start_frame &&
261 urb->start_frame <= (2 * nr_of_packs() - 1)) // uhci and ohci
262 usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs();
264 usX2Y->wait_iso_frame += nr_of_packs();
267 usX2Y_clients_stop(usX2Y);
273 static void usX2Y_hwdep_urb_release(struct urb **urb)
281 * release a substream
283 static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs)
286 snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
287 for (i = 0; i < NRURBS; i++)
288 usX2Y_hwdep_urb_release(subs->urb + i);
291 static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
293 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
294 usX2Y->prepare_subs = NULL;
297 static void i_usX2Y_usbpcm_subs_startup(struct urb *urb, struct pt_regs *regs)
299 struct snd_usX2Y_substream *subs = urb->context;
300 struct usX2Ydev *usX2Y = subs->usX2Y;
301 struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs;
302 if (NULL != prepare_subs &&
303 urb->start_frame == prepare_subs->urb[0]->start_frame) {
304 atomic_inc(&prepare_subs->state);
305 if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
306 struct snd_usX2Y_substream *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
307 if (cap_subs2 != NULL)
308 atomic_inc(&cap_subs2->state);
310 usX2Y_usbpcm_subs_startup_finish(usX2Y);
311 wake_up(&usX2Y->prepare_wait_queue);
314 i_usX2Y_usbpcm_urb_complete(urb, regs);
318 * initialize a substream's urbs
320 static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
324 int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
325 struct usb_device *dev = subs->usX2Y->chip.dev;
327 pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
328 usb_rcvisocpipe(dev, subs->endpoint);
329 subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
330 if (!subs->maxpacksize)
333 /* allocate and initialize data urbs */
334 for (i = 0; i < NRURBS; i++) {
335 struct urb **purb = subs->urb + i;
340 *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
342 usX2Y_usbpcm_urbs_release(subs);
345 (*purb)->transfer_buffer = is_playback ?
346 subs->usX2Y->hwdep_pcm_shm->playback : (
347 subs->endpoint == 0x8 ?
348 subs->usX2Y->hwdep_pcm_shm->capture0x8 :
349 subs->usX2Y->hwdep_pcm_shm->capture0xA);
352 (*purb)->pipe = pipe;
353 (*purb)->number_of_packets = nr_of_packs();
354 (*purb)->context = subs;
355 (*purb)->interval = 1;
356 (*purb)->complete = i_usX2Y_usbpcm_subs_startup;
364 static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
366 struct snd_pcm_runtime *runtime = substream->runtime;
367 struct snd_usX2Y_substream *subs = runtime->private_data,
368 *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
369 down(&subs->usX2Y->prepare_mutex);
370 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
372 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
373 struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
374 atomic_set(&subs->state, state_STOPPED);
375 usX2Y_usbpcm_urbs_release(subs);
376 if (!cap_subs->pcm_substream ||
377 !cap_subs->pcm_substream->runtime ||
378 !cap_subs->pcm_substream->runtime->status ||
379 cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
380 atomic_set(&cap_subs->state, state_STOPPED);
381 if (NULL != cap_subs2)
382 atomic_set(&cap_subs2->state, state_STOPPED);
383 usX2Y_usbpcm_urbs_release(cap_subs);
384 if (NULL != cap_subs2)
385 usX2Y_usbpcm_urbs_release(cap_subs2);
388 struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
389 if (atomic_read(&playback_subs->state) < state_PREPARED) {
390 atomic_set(&subs->state, state_STOPPED);
391 if (NULL != cap_subs2)
392 atomic_set(&cap_subs2->state, state_STOPPED);
393 usX2Y_usbpcm_urbs_release(subs);
394 if (NULL != cap_subs2)
395 usX2Y_usbpcm_urbs_release(cap_subs2);
398 up(&subs->usX2Y->prepare_mutex);
399 return snd_pcm_lib_free_pages(substream);
402 static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
404 struct usX2Ydev * usX2Y = subs->usX2Y;
405 usX2Y->prepare_subs = subs;
406 subs->urb[0]->start_frame = -1;
407 smp_wmb(); // Make shure above modifications are seen by i_usX2Y_subs_startup()
408 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
411 static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
414 stream = subs->pcm_substream->stream;
415 struct usX2Ydev *usX2Y = subs->usX2Y;
417 if (SNDRV_PCM_STREAM_CAPTURE == stream) {
418 usX2Y->hwdep_pcm_shm->captured_iso_head = -1;
419 usX2Y->hwdep_pcm_shm->captured_iso_frames = 0;
422 for (p = 0; 3 >= (stream + p); p += 2) {
423 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
425 if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
427 subs->completed_urb = NULL;
431 for (p = 0; p < 4; p++) {
432 struct snd_usX2Y_substream *subs = usX2Y->subs[p];
433 if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
436 usX2Y->wait_iso_frame = -1;
439 usX2Y_usbpcm_subs_startup(subs);
440 for (u = 0; u < NRURBS; u++) {
441 for (p = 0; 3 >= (stream + p); p += 2) {
442 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
444 struct urb *urb = subs->urb[u];
445 if (usb_pipein(urb->pipe)) {
448 atomic_set(&subs->state, state_STARTING3);
449 urb->dev = usX2Y->chip.dev;
450 urb->transfer_flags = URB_ISO_ASAP;
451 for (pack = 0; pack < nr_of_packs(); pack++) {
452 urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
453 urb->iso_frame_desc[pack].length = subs->maxpacksize;
455 urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
456 if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
457 snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
461 snd_printdd("%i\n", urb->start_frame);
462 if (0 > usX2Y->wait_iso_frame)
463 usX2Y->wait_iso_frame = urb->start_frame;
465 urb->transfer_flags = 0;
467 atomic_set(&subs->state, state_STARTING1);
474 wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
475 if (atomic_read(&subs->state) != state_PREPARED)
480 usX2Y_subs_startup_finish(usX2Y); // Call it now
481 usX2Y_clients_stop(usX2Y); // something is completely wroong > stop evrything
489 * set format and initialize urbs
491 static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
493 struct snd_pcm_runtime *runtime = substream->runtime;
494 struct snd_usX2Y_substream *subs = runtime->private_data;
495 struct usX2Ydev *usX2Y = subs->usX2Y;
496 struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
498 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
500 if (NULL == usX2Y->hwdep_pcm_shm) {
501 if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm), GFP_KERNEL)))
503 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
506 down(&usX2Y->prepare_mutex);
507 usX2Y_subs_prepare(subs);
508 // Start hardware streams
509 // SyncStream first....
510 if (atomic_read(&capsubs->state) < state_PREPARED) {
511 if (usX2Y->format != runtime->format)
512 if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
513 goto up_prepare_mutex;
514 if (usX2Y->rate != runtime->rate)
515 if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
516 goto up_prepare_mutex;
517 snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
518 "self" : "playpipe");
519 if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs)))
520 goto up_prepare_mutex;
523 if (subs != capsubs) {
524 usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
525 if (atomic_read(&subs->state) < state_PREPARED) {
526 while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) >
527 usX2Y->hwdep_pcm_shm->captured_iso_frames) {
528 snd_printdd("Wait: iso_frames_per_buffer=%i,"
529 "captured_iso_frames=%i\n",
530 usX2Y_iso_frames_per_buffer(runtime, usX2Y),
531 usX2Y->hwdep_pcm_shm->captured_iso_frames);
532 if (msleep_interruptible(10)) {
534 goto up_prepare_mutex;
537 if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
538 goto up_prepare_mutex;
540 snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
541 usX2Y_iso_frames_per_buffer(runtime, usX2Y),
542 usX2Y->hwdep_pcm_shm->captured_iso_frames);
544 usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
547 up(&usX2Y->prepare_mutex);
551 static struct snd_pcm_hardware snd_usX2Y_4c =
553 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
554 SNDRV_PCM_INFO_BLOCK_TRANSFER |
555 SNDRV_PCM_INFO_MMAP_VALID),
556 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
557 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
562 .buffer_bytes_max = (2*128*1024),
563 .period_bytes_min = 64,
564 .period_bytes_max = (128*1024),
572 static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
574 struct snd_usX2Y_substream *subs = ((struct snd_usX2Y_substream **)
575 snd_pcm_substream_chip(substream))[substream->stream];
576 struct snd_pcm_runtime *runtime = substream->runtime;
578 if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
581 runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
582 (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
583 runtime->private_data = subs;
584 subs->pcm_substream = substream;
585 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
590 static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
592 struct snd_pcm_runtime *runtime = substream->runtime;
593 struct snd_usX2Y_substream *subs = runtime->private_data;
595 subs->pcm_substream = NULL;
600 static struct snd_pcm_ops snd_usX2Y_usbpcm_ops =
602 .open = snd_usX2Y_usbpcm_open,
603 .close = snd_usX2Y_usbpcm_close,
604 .ioctl = snd_pcm_lib_ioctl,
605 .hw_params = snd_usX2Y_pcm_hw_params,
606 .hw_free = snd_usX2Y_usbpcm_hw_free,
607 .prepare = snd_usX2Y_usbpcm_prepare,
608 .trigger = snd_usX2Y_pcm_trigger,
609 .pointer = snd_usX2Y_pcm_pointer,
613 static int usX2Y_pcms_lock_check(struct snd_card *card)
615 struct list_head *list;
616 struct snd_device *dev;
619 list_for_each(list, &card->devices) {
620 dev = snd_device(list);
621 if (dev->type != SNDRV_DEV_PCM)
623 pcm = dev->device_data;
624 down(&pcm->open_mutex);
626 list_for_each(list, &card->devices) {
628 dev = snd_device(list);
629 if (dev->type != SNDRV_DEV_PCM)
631 pcm = dev->device_data;
632 for (s = 0; s < 2; ++s) {
633 struct snd_pcm_substream *substream;
634 substream = pcm->streams[s].substream;
635 if (substream && substream->ffile != NULL)
643 static void usX2Y_pcms_unlock(struct snd_card *card)
645 struct list_head *list;
646 struct snd_device *dev;
648 list_for_each(list, &card->devices) {
649 dev = snd_device(list);
650 if (dev->type != SNDRV_DEV_PCM)
652 pcm = dev->device_data;
653 up(&pcm->open_mutex);
658 static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
660 // we need to be the first
661 struct snd_card *card = hw->card;
662 int err = usX2Y_pcms_lock_check(card);
664 usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
665 usX2Y_pcms_unlock(card);
670 static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
672 struct snd_card *card = hw->card;
673 int err = usX2Y_pcms_lock_check(card);
675 usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
676 usX2Y_pcms_unlock(card);
681 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
686 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
691 static struct page * snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type)
693 unsigned long offset;
697 offset = area->vm_pgoff << PAGE_SHIFT;
698 offset += address - area->vm_start;
699 snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM);
700 vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset;
701 page = virt_to_page(vaddr);
705 *type = VM_FAULT_MINOR;
711 static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
712 .open = snd_usX2Y_hwdep_pcm_vm_open,
713 .close = snd_usX2Y_hwdep_pcm_vm_close,
714 .nopage = snd_usX2Y_hwdep_pcm_vm_nopage,
718 static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
720 unsigned long size = (unsigned long)(area->vm_end - area->vm_start);
721 struct usX2Ydev *usX2Y = hw->private_data;
723 if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
726 /* if userspace tries to mmap beyond end of our buffer, fail */
727 if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) {
728 snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm));
732 if (!usX2Y->hwdep_pcm_shm) {
735 area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
736 area->vm_flags |= VM_RESERVED;
737 area->vm_private_data = hw->private_data;
742 static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
744 struct usX2Ydev *usX2Y = hwdep->private_data;
745 if (NULL != usX2Y->hwdep_pcm_shm)
746 snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
750 int usX2Y_hwdep_pcm_new(struct snd_card *card)
753 struct snd_hwdep *hw;
755 struct usb_device *dev = usX2Y(card)->chip.dev;
756 if (1 != nr_of_packs())
759 if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
762 hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
763 hw->private_data = usX2Y(card);
764 hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
765 hw->ops.open = snd_usX2Y_hwdep_pcm_open;
766 hw->ops.release = snd_usX2Y_hwdep_pcm_release;
767 hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
769 sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
771 err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
775 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
776 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
778 pcm->private_data = usX2Y(card)->subs;
781 sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
782 if (0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
783 SNDRV_DMA_TYPE_CONTINUOUS,
784 snd_dma_continuous_data(GFP_KERNEL),
785 64*1024, 128*1024)) ||
786 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
787 SNDRV_DMA_TYPE_CONTINUOUS,
788 snd_dma_continuous_data(GFP_KERNEL),
789 64*1024, 128*1024))) {
799 int usX2Y_hwdep_pcm_new(struct snd_card *card)