1 // SPDX-License-Identifier: GPL-2.0-or-later
5 /* USX2Y "rawusb" aka hwdep_pcm implementation
7 Its usb's unableness to atomically handle power of 2 period sized data chuncs
8 at standard samplerates,
9 what led to this part of the usx2y module:
10 It provides the alsa kernel half of the usx2y-alsa-jack driver pair.
11 The pair uses a hardware dependent alsa-device for mmaped pcm transport.
13 The usb_hc moves pcm data from/into memory via DMA.
14 That memory is mmaped by jack's usx2y driver.
15 Jack's usx2y driver is the first/last to read/write pcm data.
16 Read/write is a combination of power of 2 period shaping and
17 float/int conversation.
18 Compared to mainline alsa/jack we leave out power of 2 period shaping inside
19 snd-usb-usx2y which needs memcpy() and additional buffers.
20 As a side effect possible unwanted pcm-data coruption resulting of
21 standard alsa's snd-usb-usx2y period shaping scheme falls away.
22 Result is sane jack operation at buffering schemes down to 128frames,
24 plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
25 cost of easier triggered i.e. aeolus xruns (128 or 256frames,
26 2periods works but is useless cause of crackling).
28 This is a first "proof of concept" implementation.
29 Later, functionalities should migrate to more appropriate places:
31 - The jackd could mmap its float-pcm buffers directly from alsa-lib.
32 - alsa-lib could provide power of 2 period sized shaping combined with int/float
34 Currently the usx2y jack driver provides above 2 services.
36 - rawusb dma pcm buffer transport should go to snd-usb-lib, so also snd-usb-audio
38 Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y.
41 #include <linux/delay.h>
42 #include <linux/gfp.h>
43 #include "usbusx2yaudio.c"
45 #if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
47 #include <sound/hwdep.h>
50 static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs)
52 struct urb *urb = subs->completed_urb;
53 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
54 int i, lens = 0, hwptr_done = subs->hwptr_done;
55 struct usX2Ydev *usX2Y = subs->usX2Y;
56 if (0 > usX2Y->hwdep_pcm_shm->capture_iso_start) { //FIXME
57 int head = usX2Y->hwdep_pcm_shm->captured_iso_head + 1;
58 if (head >= ARRAY_SIZE(usX2Y->hwdep_pcm_shm->captured_iso))
60 usX2Y->hwdep_pcm_shm->capture_iso_start = head;
61 snd_printdd("cap start %i\n", head);
63 for (i = 0; i < nr_of_packs(); i++) {
64 if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
65 snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status);
66 return urb->iso_frame_desc[i].status;
68 lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;
70 if ((hwptr_done += lens) >= runtime->buffer_size)
71 hwptr_done -= runtime->buffer_size;
72 subs->hwptr_done = hwptr_done;
73 subs->transfer_done += lens;
74 /* update the pointer, call callback if necessary */
75 if (subs->transfer_done >= runtime->period_size) {
76 subs->transfer_done -= runtime->period_size;
77 snd_pcm_period_elapsed(subs->pcm_substream);
82 static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
83 struct usX2Ydev * usX2Y)
85 return (runtime->buffer_size * 1000) / usX2Y->rate + 1; //FIXME: so far only correct period_size == 2^x ?
89 * prepare urb for playback data pipe
91 * we copy the data directly from the pcm buffer.
92 * the current position to be copied is held in hwptr field.
93 * since a urb can handle only a single linear buffer, if the total
94 * transferred area overflows the buffer boundary, we cannot send
95 * it directly from the buffer. thus the data is once copied to
96 * a temporary buffer and urb points to that.
98 static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs,
101 int count, counts, pack;
102 struct usX2Ydev *usX2Y = subs->usX2Y;
103 struct snd_usX2Y_hwdep_pcm_shm *shm = usX2Y->hwdep_pcm_shm;
104 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
106 if (0 > shm->playback_iso_start) {
107 shm->playback_iso_start = shm->captured_iso_head -
108 usX2Y_iso_frames_per_buffer(runtime, usX2Y);
109 if (0 > shm->playback_iso_start)
110 shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
111 shm->playback_iso_head = shm->playback_iso_start;
115 for (pack = 0; pack < nr_of_packs(); pack++) {
116 /* calculate the size of a packet */
117 counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride;
118 if (counts < 43 || counts > 50) {
119 snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
122 /* set up descriptor */
123 urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
124 urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
125 if (atomic_read(&subs->state) != state_RUNNING)
126 memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
127 urb->iso_frame_desc[pack].length);
128 if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
129 shm->playback_iso_head = 0;
132 urb->transfer_buffer_length = count * usX2Y->stride;
137 static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream *subs,
141 for (pack = 0; pack < nr_of_packs(); ++pack) {
142 struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack;
144 struct snd_usX2Y_hwdep_pcm_shm *shm = subs->usX2Y->hwdep_pcm_shm;
145 int head = shm->captured_iso_head + 1;
146 if (head >= ARRAY_SIZE(shm->captured_iso))
148 shm->captured_iso[head].frame = urb->start_frame + pack;
149 shm->captured_iso[head].offset = desc->offset;
150 shm->captured_iso[head].length = desc->actual_length;
151 shm->captured_iso_head = head;
152 shm->captured_iso_frames++;
154 if ((desc->offset += desc->length * NRURBS*nr_of_packs()) +
156 desc->offset -= (SSS - desc->length);
160 static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream *capsubs,
161 struct snd_usX2Y_substream *capsubs2,
162 struct snd_usX2Y_substream *playbacksubs,
166 struct urb *urb = playbacksubs->completed_urb;
168 state = atomic_read(&playbacksubs->state);
170 if (state == state_RUNNING)
171 usX2Y_urb_play_retire(playbacksubs, urb);
172 else if (state >= state_PRERUNNING)
173 atomic_inc(&playbacksubs->state);
176 case state_STARTING1:
177 urb = playbacksubs->urb[0];
178 atomic_inc(&playbacksubs->state);
180 case state_STARTING2:
181 urb = playbacksubs->urb[1];
182 atomic_inc(&playbacksubs->state);
187 if ((err = usX2Y_hwdep_urb_play_prepare(playbacksubs, urb)) ||
188 (err = usX2Y_urb_submit(playbacksubs, urb, frame))) {
193 playbacksubs->completed_urb = NULL;
195 state = atomic_read(&capsubs->state);
196 if (state >= state_PREPARED) {
197 if (state == state_RUNNING) {
198 if ((err = usX2Y_usbpcm_urb_capt_retire(capsubs)))
200 } else if (state >= state_PRERUNNING)
201 atomic_inc(&capsubs->state);
202 usX2Y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
203 if (NULL != capsubs2)
204 usX2Y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
205 if ((err = usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame)))
207 if (NULL != capsubs2)
208 if ((err = usX2Y_urb_submit(capsubs2, capsubs2->completed_urb, frame)))
211 capsubs->completed_urb = NULL;
212 if (NULL != capsubs2)
213 capsubs2->completed_urb = NULL;
218 static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
220 struct snd_usX2Y_substream *subs = urb->context;
221 struct usX2Ydev *usX2Y = subs->usX2Y;
222 struct snd_usX2Y_substream *capsubs, *capsubs2, *playbacksubs;
224 if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
225 snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
226 usb_get_current_frame_number(usX2Y->dev),
227 subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
228 urb->status, urb->start_frame);
231 if (unlikely(urb->status)) {
232 usX2Y_error_urb_status(usX2Y, subs, urb);
236 subs->completed_urb = urb;
237 capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
238 capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
239 playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
240 if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
241 (NULL == capsubs2 || capsubs2->completed_urb) &&
242 (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
243 if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame))
244 usX2Y->wait_iso_frame += nr_of_packs();
247 usX2Y_clients_stop(usX2Y);
253 static void usX2Y_hwdep_urb_release(struct urb **urb)
261 * release a substream
263 static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs)
266 snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
267 for (i = 0; i < NRURBS; i++)
268 usX2Y_hwdep_urb_release(subs->urb + i);
271 static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
273 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
274 usX2Y->prepare_subs = NULL;
277 static void i_usX2Y_usbpcm_subs_startup(struct urb *urb)
279 struct snd_usX2Y_substream *subs = urb->context;
280 struct usX2Ydev *usX2Y = subs->usX2Y;
281 struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs;
282 if (NULL != prepare_subs &&
283 urb->start_frame == prepare_subs->urb[0]->start_frame) {
284 atomic_inc(&prepare_subs->state);
285 if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
286 struct snd_usX2Y_substream *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
287 if (cap_subs2 != NULL)
288 atomic_inc(&cap_subs2->state);
290 usX2Y_usbpcm_subs_startup_finish(usX2Y);
291 wake_up(&usX2Y->prepare_wait_queue);
294 i_usX2Y_usbpcm_urb_complete(urb);
298 * initialize a substream's urbs
300 static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
304 int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
305 struct usb_device *dev = subs->usX2Y->dev;
307 pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
308 usb_rcvisocpipe(dev, subs->endpoint);
309 subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
310 if (!subs->maxpacksize)
313 /* allocate and initialize data urbs */
314 for (i = 0; i < NRURBS; i++) {
315 struct urb **purb = subs->urb + i;
320 *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
322 usX2Y_usbpcm_urbs_release(subs);
325 (*purb)->transfer_buffer = is_playback ?
326 subs->usX2Y->hwdep_pcm_shm->playback : (
327 subs->endpoint == 0x8 ?
328 subs->usX2Y->hwdep_pcm_shm->capture0x8 :
329 subs->usX2Y->hwdep_pcm_shm->capture0xA);
332 (*purb)->pipe = pipe;
333 (*purb)->number_of_packets = nr_of_packs();
334 (*purb)->context = subs;
335 (*purb)->interval = 1;
336 (*purb)->complete = i_usX2Y_usbpcm_subs_startup;
344 static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
346 struct snd_pcm_runtime *runtime = substream->runtime;
347 struct snd_usX2Y_substream *subs = runtime->private_data,
348 *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
349 mutex_lock(&subs->usX2Y->pcm_mutex);
350 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
352 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
353 struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
354 atomic_set(&subs->state, state_STOPPED);
355 usX2Y_usbpcm_urbs_release(subs);
356 if (!cap_subs->pcm_substream ||
357 !cap_subs->pcm_substream->runtime ||
358 !cap_subs->pcm_substream->runtime->status ||
359 cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
360 atomic_set(&cap_subs->state, state_STOPPED);
361 if (NULL != cap_subs2)
362 atomic_set(&cap_subs2->state, state_STOPPED);
363 usX2Y_usbpcm_urbs_release(cap_subs);
364 if (NULL != cap_subs2)
365 usX2Y_usbpcm_urbs_release(cap_subs2);
368 struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
369 if (atomic_read(&playback_subs->state) < state_PREPARED) {
370 atomic_set(&subs->state, state_STOPPED);
371 if (NULL != cap_subs2)
372 atomic_set(&cap_subs2->state, state_STOPPED);
373 usX2Y_usbpcm_urbs_release(subs);
374 if (NULL != cap_subs2)
375 usX2Y_usbpcm_urbs_release(cap_subs2);
378 mutex_unlock(&subs->usX2Y->pcm_mutex);
382 static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
384 struct usX2Ydev * usX2Y = subs->usX2Y;
385 usX2Y->prepare_subs = subs;
386 subs->urb[0]->start_frame = -1;
387 smp_wmb(); // Make sure above modifications are seen by i_usX2Y_subs_startup()
388 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
391 static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
394 stream = subs->pcm_substream->stream;
395 struct usX2Ydev *usX2Y = subs->usX2Y;
397 if (SNDRV_PCM_STREAM_CAPTURE == stream) {
398 usX2Y->hwdep_pcm_shm->captured_iso_head = -1;
399 usX2Y->hwdep_pcm_shm->captured_iso_frames = 0;
402 for (p = 0; 3 >= (stream + p); p += 2) {
403 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
405 if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
407 subs->completed_urb = NULL;
411 for (p = 0; p < 4; p++) {
412 struct snd_usX2Y_substream *subs = usX2Y->subs[p];
413 if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
418 usX2Y_usbpcm_subs_startup(subs);
419 for (u = 0; u < NRURBS; u++) {
420 for (p = 0; 3 >= (stream + p); p += 2) {
421 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
423 struct urb *urb = subs->urb[u];
424 if (usb_pipein(urb->pipe)) {
427 atomic_set(&subs->state, state_STARTING3);
428 urb->dev = usX2Y->dev;
429 for (pack = 0; pack < nr_of_packs(); pack++) {
430 urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
431 urb->iso_frame_desc[pack].length = subs->maxpacksize;
433 urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
434 if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
435 snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
439 snd_printdd("%i\n", urb->start_frame);
441 usX2Y->wait_iso_frame = urb->start_frame;
443 urb->transfer_flags = 0;
445 atomic_set(&subs->state, state_STARTING1);
452 wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
453 if (atomic_read(&subs->state) != state_PREPARED)
458 usX2Y_subs_startup_finish(usX2Y); // Call it now
459 usX2Y_clients_stop(usX2Y); // something is completely wroong > stop evrything
467 * set format and initialize urbs
469 static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
471 struct snd_pcm_runtime *runtime = substream->runtime;
472 struct snd_usX2Y_substream *subs = runtime->private_data;
473 struct usX2Ydev *usX2Y = subs->usX2Y;
474 struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
476 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
478 if (NULL == usX2Y->hwdep_pcm_shm) {
479 usX2Y->hwdep_pcm_shm = alloc_pages_exact(sizeof(struct snd_usX2Y_hwdep_pcm_shm),
481 if (!usX2Y->hwdep_pcm_shm)
483 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
486 mutex_lock(&usX2Y->pcm_mutex);
487 usX2Y_subs_prepare(subs);
488 // Start hardware streams
489 // SyncStream first....
490 if (atomic_read(&capsubs->state) < state_PREPARED) {
491 if (usX2Y->format != runtime->format)
492 if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
493 goto up_prepare_mutex;
494 if (usX2Y->rate != runtime->rate)
495 if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
496 goto up_prepare_mutex;
497 snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
498 "self" : "playpipe");
499 if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs)))
500 goto up_prepare_mutex;
503 if (subs != capsubs) {
504 usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
505 if (atomic_read(&subs->state) < state_PREPARED) {
506 while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) >
507 usX2Y->hwdep_pcm_shm->captured_iso_frames) {
508 snd_printdd("Wait: iso_frames_per_buffer=%i,"
509 "captured_iso_frames=%i\n",
510 usX2Y_iso_frames_per_buffer(runtime, usX2Y),
511 usX2Y->hwdep_pcm_shm->captured_iso_frames);
512 if (msleep_interruptible(10)) {
514 goto up_prepare_mutex;
517 if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
518 goto up_prepare_mutex;
520 snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
521 usX2Y_iso_frames_per_buffer(runtime, usX2Y),
522 usX2Y->hwdep_pcm_shm->captured_iso_frames);
524 usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
527 mutex_unlock(&usX2Y->pcm_mutex);
531 static const struct snd_pcm_hardware snd_usX2Y_4c =
533 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
534 SNDRV_PCM_INFO_BLOCK_TRANSFER |
535 SNDRV_PCM_INFO_MMAP_VALID),
536 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
537 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
542 .buffer_bytes_max = (2*128*1024),
543 .period_bytes_min = 64,
544 .period_bytes_max = (128*1024),
552 static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
554 struct snd_usX2Y_substream *subs = ((struct snd_usX2Y_substream **)
555 snd_pcm_substream_chip(substream))[substream->stream];
556 struct snd_pcm_runtime *runtime = substream->runtime;
558 if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
561 runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
562 (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
563 runtime->private_data = subs;
564 subs->pcm_substream = substream;
565 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
570 static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
572 struct snd_pcm_runtime *runtime = substream->runtime;
573 struct snd_usX2Y_substream *subs = runtime->private_data;
575 subs->pcm_substream = NULL;
580 static const struct snd_pcm_ops snd_usX2Y_usbpcm_ops =
582 .open = snd_usX2Y_usbpcm_open,
583 .close = snd_usX2Y_usbpcm_close,
584 .hw_params = snd_usX2Y_pcm_hw_params,
585 .hw_free = snd_usX2Y_usbpcm_hw_free,
586 .prepare = snd_usX2Y_usbpcm_prepare,
587 .trigger = snd_usX2Y_pcm_trigger,
588 .pointer = snd_usX2Y_pcm_pointer,
592 static int usX2Y_pcms_busy_check(struct snd_card *card)
594 struct usX2Ydev *dev = usX2Y(card);
597 for (i = 0; i < dev->pcm_devs * 2; i++) {
598 struct snd_usX2Y_substream *subs = dev->subs[i];
599 if (subs && subs->pcm_substream &&
600 SUBSTREAM_BUSY(subs->pcm_substream))
606 static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
608 struct snd_card *card = hw->card;
611 mutex_lock(&usX2Y(card)->pcm_mutex);
612 err = usX2Y_pcms_busy_check(card);
614 usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
615 mutex_unlock(&usX2Y(card)->pcm_mutex);
620 static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
622 struct snd_card *card = hw->card;
625 mutex_lock(&usX2Y(card)->pcm_mutex);
626 err = usX2Y_pcms_busy_check(card);
628 usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
629 mutex_unlock(&usX2Y(card)->pcm_mutex);
634 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
639 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
644 static vm_fault_t snd_usX2Y_hwdep_pcm_vm_fault(struct vm_fault *vmf)
646 unsigned long offset;
649 offset = vmf->pgoff << PAGE_SHIFT;
650 vaddr = (char *)((struct usX2Ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset;
651 vmf->page = virt_to_page(vaddr);
657 static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
658 .open = snd_usX2Y_hwdep_pcm_vm_open,
659 .close = snd_usX2Y_hwdep_pcm_vm_close,
660 .fault = snd_usX2Y_hwdep_pcm_vm_fault,
664 static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
666 unsigned long size = (unsigned long)(area->vm_end - area->vm_start);
667 struct usX2Ydev *usX2Y = hw->private_data;
669 if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
672 /* if userspace tries to mmap beyond end of our buffer, fail */
673 if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) {
674 snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm));
678 if (!usX2Y->hwdep_pcm_shm) {
681 area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
682 area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
683 area->vm_private_data = hw->private_data;
688 static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
690 struct usX2Ydev *usX2Y = hwdep->private_data;
691 if (NULL != usX2Y->hwdep_pcm_shm)
692 free_pages_exact(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
696 int usX2Y_hwdep_pcm_new(struct snd_card *card)
699 struct snd_hwdep *hw;
701 struct usb_device *dev = usX2Y(card)->dev;
702 if (1 != nr_of_packs())
705 if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
708 hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
709 hw->private_data = usX2Y(card);
710 hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
711 hw->ops.open = snd_usX2Y_hwdep_pcm_open;
712 hw->ops.release = snd_usX2Y_hwdep_pcm_release;
713 hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
715 sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
717 err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
721 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
722 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
724 pcm->private_data = usX2Y(card)->subs;
727 sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
728 snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
729 SNDRV_DMA_TYPE_CONTINUOUS,
732 snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
733 SNDRV_DMA_TYPE_CONTINUOUS,
742 int usX2Y_hwdep_pcm_new(struct snd_card *card)