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(snd_usX2Y_substream_t *subs)
63 struct urb *urb = subs->completed_urb;
64 snd_pcm_runtime_t *runtime = subs->pcm_substream->runtime;
65 int i, lens = 0, hwptr_done = subs->hwptr_done;
66 usX2Ydev_t *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("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(snd_pcm_runtime_t *runtime, usX2Ydev_t * usX2Y)
95 return (runtime->buffer_size * 1000) / usX2Y->rate + 1; //FIXME: so far only correct period_size == 2^x ?
99 * prepare urb for playback data pipe
101 * we copy the data directly from the pcm buffer.
102 * the current position to be copied is held in hwptr field.
103 * since a urb can handle only a single linear buffer, if the total
104 * transferred area overflows the buffer boundary, we cannot send
105 * it directly from the buffer. thus the data is once copied to
106 * a temporary buffer and urb points to that.
108 static int usX2Y_hwdep_urb_play_prepare(snd_usX2Y_substream_t *subs,
111 int count, counts, pack;
112 usX2Ydev_t *usX2Y = subs->usX2Y;
113 struct snd_usX2Y_hwdep_pcm_shm *shm = usX2Y->hwdep_pcm_shm;
114 snd_pcm_runtime_t *runtime = subs->pcm_substream->runtime;
116 if (0 > shm->playback_iso_start) {
117 shm->playback_iso_start = shm->captured_iso_head -
118 usX2Y_iso_frames_per_buffer(runtime, usX2Y);
119 if (0 > shm->playback_iso_start)
120 shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
121 shm->playback_iso_head = shm->playback_iso_start;
125 for (pack = 0; pack < nr_of_packs(); pack++) {
126 /* calculate the size of a packet */
127 counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride;
128 if (counts < 43 || counts > 50) {
129 snd_printk("should not be here with counts=%i\n", counts);
132 /* set up descriptor */
133 urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
134 urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
135 if (atomic_read(&subs->state) != state_RUNNING)
136 memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
137 urb->iso_frame_desc[pack].length);
138 if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
139 shm->playback_iso_head = 0;
142 urb->transfer_buffer_length = count * usX2Y->stride;
147 static inline void usX2Y_usbpcm_urb_capt_iso_advance(snd_usX2Y_substream_t *subs, struct urb *urb)
150 for (pack = 0; pack < nr_of_packs(); ++pack) {
151 struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack;
153 snd_usX2Y_hwdep_pcm_shm_t *shm = subs->usX2Y->hwdep_pcm_shm;
154 int head = shm->captured_iso_head + 1;
155 if (head >= ARRAY_SIZE(shm->captured_iso))
157 shm->captured_iso[head].frame = urb->start_frame + pack;
158 shm->captured_iso[head].offset = desc->offset;
159 shm->captured_iso[head].length = desc->actual_length;
160 shm->captured_iso_head = head;
161 shm->captured_iso_frames++;
163 if ((desc->offset += desc->length * NRURBS*nr_of_packs()) +
165 desc->offset -= (SSS - desc->length);
169 static inline int usX2Y_usbpcm_usbframe_complete(snd_usX2Y_substream_t *capsubs,
170 snd_usX2Y_substream_t *capsubs2,
171 snd_usX2Y_substream_t *playbacksubs, int frame)
174 struct urb *urb = playbacksubs->completed_urb;
176 state = atomic_read(&playbacksubs->state);
178 if (state == state_RUNNING)
179 usX2Y_urb_play_retire(playbacksubs, urb);
181 if (state >= state_PRERUNNING) {
182 atomic_inc(&playbacksubs->state);
186 case state_STARTING1:
187 urb = playbacksubs->urb[0];
188 atomic_inc(&playbacksubs->state);
190 case state_STARTING2:
191 urb = playbacksubs->urb[1];
192 atomic_inc(&playbacksubs->state);
197 if ((err = usX2Y_hwdep_urb_play_prepare(playbacksubs, urb)) ||
198 (err = usX2Y_urb_submit(playbacksubs, urb, frame))) {
203 playbacksubs->completed_urb = NULL;
205 state = atomic_read(&capsubs->state);
206 if (state >= state_PREPARED) {
207 if (state == state_RUNNING) {
208 if ((err = usX2Y_usbpcm_urb_capt_retire(capsubs)))
211 if (state >= state_PRERUNNING)
212 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)))
219 if (NULL != capsubs2)
220 if ((err = usX2Y_urb_submit(capsubs2, capsubs2->completed_urb, frame)))
223 capsubs->completed_urb = NULL;
224 if (NULL != capsubs2)
225 capsubs2->completed_urb = NULL;
230 static void i_usX2Y_usbpcm_urb_complete(struct urb *urb, struct pt_regs *regs)
232 snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t*)urb->context;
233 usX2Ydev_t *usX2Y = subs->usX2Y;
234 snd_usX2Y_substream_t *capsubs, *capsubs2, *playbacksubs;
236 if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
237 snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", usb_get_current_frame_number(usX2Y->chip.dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame);
240 if (unlikely(urb->status)) {
241 usX2Y_error_urb_status(usX2Y, subs, urb);
244 if (likely((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame))
245 subs->completed_urb = urb;
247 usX2Y_error_sequence(usX2Y, subs, urb);
251 capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
252 capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
253 playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
254 if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
255 (NULL == capsubs2 || capsubs2->completed_urb) &&
256 (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
257 if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) {
258 if (nr_of_packs() <= urb->start_frame &&
259 urb->start_frame <= (2 * nr_of_packs() - 1)) // uhci and ohci
260 usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs();
262 usX2Y->wait_iso_frame += nr_of_packs();
265 usX2Y_clients_stop(usX2Y);
271 static void usX2Y_hwdep_urb_release(struct urb** urb)
279 * release a substream
281 static void usX2Y_usbpcm_urbs_release(snd_usX2Y_substream_t *subs)
284 snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
285 for (i = 0; i < NRURBS; i++)
286 usX2Y_hwdep_urb_release(subs->urb + i);
289 static void usX2Y_usbpcm_subs_startup_finish(usX2Ydev_t * usX2Y)
291 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
292 usX2Y->prepare_subs = NULL;
295 static void i_usX2Y_usbpcm_subs_startup(struct urb *urb, struct pt_regs *regs)
297 snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t*)urb->context;
298 usX2Ydev_t *usX2Y = subs->usX2Y;
299 snd_usX2Y_substream_t *prepare_subs = usX2Y->prepare_subs;
300 if (NULL != prepare_subs &&
301 urb->start_frame == prepare_subs->urb[0]->start_frame) {
302 atomic_inc(&prepare_subs->state);
303 if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
304 snd_usX2Y_substream_t *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
305 if (cap_subs2 != NULL)
306 atomic_inc(&cap_subs2->state);
308 usX2Y_usbpcm_subs_startup_finish(usX2Y);
309 wake_up(&usX2Y->prepare_wait_queue);
312 i_usX2Y_usbpcm_urb_complete(urb, regs);
316 * initialize a substream's urbs
318 static int usX2Y_usbpcm_urbs_allocate(snd_usX2Y_substream_t *subs)
322 int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
323 struct usb_device *dev = subs->usX2Y->chip.dev;
325 pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
326 usb_rcvisocpipe(dev, subs->endpoint);
327 subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
328 if (!subs->maxpacksize)
331 /* allocate and initialize data urbs */
332 for (i = 0; i < NRURBS; i++) {
333 struct urb** purb = subs->urb + i;
338 *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
340 usX2Y_usbpcm_urbs_release(subs);
343 (*purb)->transfer_buffer = is_playback ?
344 subs->usX2Y->hwdep_pcm_shm->playback : (
345 subs->endpoint == 0x8 ?
346 subs->usX2Y->hwdep_pcm_shm->capture0x8 :
347 subs->usX2Y->hwdep_pcm_shm->capture0xA);
350 (*purb)->pipe = pipe;
351 (*purb)->number_of_packets = nr_of_packs();
352 (*purb)->context = subs;
353 (*purb)->interval = 1;
354 (*purb)->complete = i_usX2Y_usbpcm_subs_startup;
362 static int snd_usX2Y_usbpcm_hw_free(snd_pcm_substream_t *substream)
364 snd_pcm_runtime_t *runtime = substream->runtime;
365 snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data,
366 *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
367 down(&subs->usX2Y->prepare_mutex);
368 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
370 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
371 snd_usX2Y_substream_t *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
372 atomic_set(&subs->state, state_STOPPED);
373 usX2Y_usbpcm_urbs_release(subs);
374 if (!cap_subs->pcm_substream ||
375 !cap_subs->pcm_substream->runtime ||
376 !cap_subs->pcm_substream->runtime->status ||
377 cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
378 atomic_set(&cap_subs->state, state_STOPPED);
379 if (NULL != cap_subs2)
380 atomic_set(&cap_subs2->state, state_STOPPED);
381 usX2Y_usbpcm_urbs_release(cap_subs);
382 if (NULL != cap_subs2)
383 usX2Y_usbpcm_urbs_release(cap_subs2);
386 snd_usX2Y_substream_t *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
387 if (atomic_read(&playback_subs->state) < state_PREPARED) {
388 atomic_set(&subs->state, state_STOPPED);
389 if (NULL != cap_subs2)
390 atomic_set(&cap_subs2->state, state_STOPPED);
391 usX2Y_usbpcm_urbs_release(subs);
392 if (NULL != cap_subs2)
393 usX2Y_usbpcm_urbs_release(cap_subs2);
396 up(&subs->usX2Y->prepare_mutex);
397 return snd_pcm_lib_free_pages(substream);
400 static void usX2Y_usbpcm_subs_startup(snd_usX2Y_substream_t *subs)
402 usX2Ydev_t * usX2Y = subs->usX2Y;
403 usX2Y->prepare_subs = subs;
404 subs->urb[0]->start_frame = -1;
405 smp_wmb(); // Make shure above modifications are seen by i_usX2Y_subs_startup()
406 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
409 static int usX2Y_usbpcm_urbs_start(snd_usX2Y_substream_t *subs)
412 stream = subs->pcm_substream->stream;
413 usX2Ydev_t *usX2Y = subs->usX2Y;
415 if (SNDRV_PCM_STREAM_CAPTURE == stream) {
416 usX2Y->hwdep_pcm_shm->captured_iso_head = -1;
417 usX2Y->hwdep_pcm_shm->captured_iso_frames = 0;
420 for (p = 0; 3 >= (stream + p); p += 2) {
421 snd_usX2Y_substream_t *subs = usX2Y->subs[stream + p];
423 if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
425 subs->completed_urb = NULL;
429 for (p = 0; p < 4; p++) {
430 snd_usX2Y_substream_t *subs = usX2Y->subs[p];
431 if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
434 usX2Y->wait_iso_frame = -1;
437 usX2Y_usbpcm_subs_startup(subs);
438 for (u = 0; u < NRURBS; u++) {
439 for (p = 0; 3 >= (stream + p); p += 2) {
440 snd_usX2Y_substream_t *subs = usX2Y->subs[stream + p];
442 struct urb *urb = subs->urb[u];
443 if (usb_pipein(urb->pipe)) {
446 atomic_set(&subs->state, state_STARTING3);
447 urb->dev = usX2Y->chip.dev;
448 urb->transfer_flags = URB_ISO_ASAP;
449 for (pack = 0; pack < nr_of_packs(); pack++) {
450 urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
451 urb->iso_frame_desc[pack].length = subs->maxpacksize;
453 urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
454 if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
455 snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
459 snd_printdd("%i\n", urb->start_frame);
460 if (0 > usX2Y->wait_iso_frame)
461 usX2Y->wait_iso_frame = urb->start_frame;
463 urb->transfer_flags = 0;
465 atomic_set(&subs->state, state_STARTING1);
472 wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
473 if (atomic_read(&subs->state) != state_PREPARED)
478 usX2Y_subs_startup_finish(usX2Y); // Call it now
479 usX2Y_clients_stop(usX2Y); // something is completely wroong > stop evrything
487 * set format and initialize urbs
489 static int snd_usX2Y_usbpcm_prepare(snd_pcm_substream_t *substream)
491 snd_pcm_runtime_t *runtime = substream->runtime;
492 snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data;
493 usX2Ydev_t *usX2Y = subs->usX2Y;
494 snd_usX2Y_substream_t *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
496 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
498 if (NULL == usX2Y->hwdep_pcm_shm) {
499 if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(snd_usX2Y_hwdep_pcm_shm_t), GFP_KERNEL)))
501 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(snd_usX2Y_hwdep_pcm_shm_t));
504 down(&usX2Y->prepare_mutex);
505 usX2Y_subs_prepare(subs);
506 // Start hardware streams
507 // SyncStream first....
508 if (atomic_read(&capsubs->state) < state_PREPARED) {
509 if (usX2Y->format != runtime->format)
510 if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
511 goto up_prepare_mutex;
512 if (usX2Y->rate != runtime->rate)
513 if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
514 goto up_prepare_mutex;
515 snd_printdd("starting capture pipe for %s\n", subs == capsubs ? "self" : "playpipe");
516 if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs)))
517 goto up_prepare_mutex;
520 if (subs != capsubs) {
521 usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
522 if (atomic_read(&subs->state) < state_PREPARED) {
523 while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) > usX2Y->hwdep_pcm_shm->captured_iso_frames) {
524 snd_printd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", usX2Y_iso_frames_per_buffer(runtime, usX2Y), usX2Y->hwdep_pcm_shm->captured_iso_frames);
525 if (msleep_interruptible(10)) {
527 goto up_prepare_mutex;
530 if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
531 goto up_prepare_mutex;
533 snd_printd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", usX2Y_iso_frames_per_buffer(runtime, usX2Y), usX2Y->hwdep_pcm_shm->captured_iso_frames);
535 usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
538 up(&usX2Y->prepare_mutex);
542 static snd_pcm_hardware_t snd_usX2Y_4c =
544 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
545 SNDRV_PCM_INFO_BLOCK_TRANSFER |
546 SNDRV_PCM_INFO_MMAP_VALID),
547 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
548 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
553 .buffer_bytes_max = (2*128*1024),
554 .period_bytes_min = 64,
555 .period_bytes_max = (128*1024),
563 static int snd_usX2Y_usbpcm_open(snd_pcm_substream_t *substream)
565 snd_usX2Y_substream_t *subs = ((snd_usX2Y_substream_t **)
566 snd_pcm_substream_chip(substream))[substream->stream];
567 snd_pcm_runtime_t *runtime = substream->runtime;
569 if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
572 runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
573 (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
574 runtime->private_data = subs;
575 subs->pcm_substream = substream;
576 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
581 static int snd_usX2Y_usbpcm_close(snd_pcm_substream_t *substream)
583 snd_pcm_runtime_t *runtime = substream->runtime;
584 snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data;
587 subs->pcm_substream = NULL;
592 static snd_pcm_ops_t snd_usX2Y_usbpcm_ops =
594 .open = snd_usX2Y_usbpcm_open,
595 .close = snd_usX2Y_usbpcm_close,
596 .ioctl = snd_pcm_lib_ioctl,
597 .hw_params = snd_usX2Y_pcm_hw_params,
598 .hw_free = snd_usX2Y_usbpcm_hw_free,
599 .prepare = snd_usX2Y_usbpcm_prepare,
600 .trigger = snd_usX2Y_pcm_trigger,
601 .pointer = snd_usX2Y_pcm_pointer,
605 static int usX2Y_pcms_lock_check(snd_card_t *card)
607 struct list_head *list;
611 list_for_each(list, &card->devices) {
612 dev = snd_device(list);
613 if (dev->type != SNDRV_DEV_PCM)
615 pcm = dev->device_data;
616 down(&pcm->open_mutex);
618 list_for_each(list, &card->devices) {
620 dev = snd_device(list);
621 if (dev->type != SNDRV_DEV_PCM)
623 pcm = dev->device_data;
624 for (s = 0; s < 2; ++s) {
625 snd_pcm_substream_t *substream;
626 substream = pcm->streams[s].substream;
627 if (substream && substream->ffile != NULL)
635 static void usX2Y_pcms_unlock(snd_card_t *card)
637 struct list_head *list;
640 list_for_each(list, &card->devices) {
641 dev = snd_device(list);
642 if (dev->type != SNDRV_DEV_PCM)
644 pcm = dev->device_data;
645 up(&pcm->open_mutex);
650 static int snd_usX2Y_hwdep_pcm_open(snd_hwdep_t *hw, struct file *file)
652 // we need to be the first
653 snd_card_t *card = hw->card;
654 int err = usX2Y_pcms_lock_check(card);
656 usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
657 usX2Y_pcms_unlock(card);
662 static int snd_usX2Y_hwdep_pcm_release(snd_hwdep_t *hw, struct file *file)
664 snd_card_t *card = hw->card;
665 int err = usX2Y_pcms_lock_check(card);
667 usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
668 usX2Y_pcms_unlock(card);
673 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
678 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
683 static struct page * snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type)
685 unsigned long offset;
689 offset = area->vm_pgoff << PAGE_SHIFT;
690 offset += address - area->vm_start;
691 snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM);
692 vaddr = (char*)((usX2Ydev_t*)area->vm_private_data)->hwdep_pcm_shm + offset;
693 page = virt_to_page(vaddr);
696 *type = VM_FAULT_MINOR;
702 static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
703 .open = snd_usX2Y_hwdep_pcm_vm_open,
704 .close = snd_usX2Y_hwdep_pcm_vm_close,
705 .nopage = snd_usX2Y_hwdep_pcm_vm_nopage,
709 static int snd_usX2Y_hwdep_pcm_mmap(snd_hwdep_t * hw, struct file *filp, struct vm_area_struct *area)
711 unsigned long size = (unsigned long)(area->vm_end - area->vm_start);
712 usX2Ydev_t *usX2Y = (usX2Ydev_t*)hw->private_data;
714 if (!(((usX2Ydev_t*)hw->private_data)->chip_status & USX2Y_STAT_CHIP_INIT))
717 /* if userspace tries to mmap beyond end of our buffer, fail */
718 if (size > PAGE_ALIGN(sizeof(snd_usX2Y_hwdep_pcm_shm_t))) {
719 snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(snd_usX2Y_hwdep_pcm_shm_t));
723 if (!usX2Y->hwdep_pcm_shm) {
726 area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
727 area->vm_flags |= VM_RESERVED;
728 snd_printd("vm_flags=0x%lX\n", area->vm_flags);
729 area->vm_private_data = hw->private_data;
734 static void snd_usX2Y_hwdep_pcm_private_free(snd_hwdep_t *hwdep)
736 usX2Ydev_t *usX2Y = (usX2Ydev_t *)hwdep->private_data;
737 if (NULL != usX2Y->hwdep_pcm_shm)
738 snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(snd_usX2Y_hwdep_pcm_shm_t));
742 static void snd_usX2Y_usbpcm_private_free(snd_pcm_t *pcm)
744 snd_pcm_lib_preallocate_free_for_all(pcm);
748 int usX2Y_hwdep_pcm_new(snd_card_t* card)
753 struct usb_device *dev = usX2Y(card)->chip.dev;
754 if (1 != nr_of_packs())
757 if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0) {
761 hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
762 hw->private_data = usX2Y(card);
763 hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
764 hw->ops.open = snd_usX2Y_hwdep_pcm_open;
765 hw->ops.release = snd_usX2Y_hwdep_pcm_release;
766 hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
768 sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
770 err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
774 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
775 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
777 pcm->private_data = usX2Y(card)->subs;
778 pcm->private_free = snd_usX2Y_usbpcm_private_free;
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))) {
790 snd_usX2Y_usbpcm_private_free(pcm);
800 int usX2Y_hwdep_pcm_new(snd_card_t* card)