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 dependent 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, functionalities should migrate to more appropriate 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 <linux/gfp.h>
55 #include "usbusx2yaudio.c"
57 #if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
59 #include <sound/hwdep.h>
62 static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream
*subs
)
64 struct urb
*urb
= subs
->completed_urb
;
65 struct snd_pcm_runtime
*runtime
= subs
->pcm_substream
->runtime
;
66 int i
, lens
= 0, hwptr_done
= subs
->hwptr_done
;
67 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
68 if (0 > usX2Y
->hwdep_pcm_shm
->capture_iso_start
) { //FIXME
69 int head
= usX2Y
->hwdep_pcm_shm
->captured_iso_head
+ 1;
70 if (head
>= ARRAY_SIZE(usX2Y
->hwdep_pcm_shm
->captured_iso
))
72 usX2Y
->hwdep_pcm_shm
->capture_iso_start
= head
;
73 snd_printdd("cap start %i\n", head
);
75 for (i
= 0; i
< nr_of_packs(); i
++) {
76 if (urb
->iso_frame_desc
[i
].status
) { /* active? hmm, skip this */
77 snd_printk(KERN_ERR
"active frame status %i. Most probably some hardware problem.\n", urb
->iso_frame_desc
[i
].status
);
78 return urb
->iso_frame_desc
[i
].status
;
80 lens
+= urb
->iso_frame_desc
[i
].actual_length
/ usX2Y
->stride
;
82 if ((hwptr_done
+= lens
) >= runtime
->buffer_size
)
83 hwptr_done
-= runtime
->buffer_size
;
84 subs
->hwptr_done
= hwptr_done
;
85 subs
->transfer_done
+= lens
;
86 /* update the pointer, call callback if necessary */
87 if (subs
->transfer_done
>= runtime
->period_size
) {
88 subs
->transfer_done
-= runtime
->period_size
;
89 snd_pcm_period_elapsed(subs
->pcm_substream
);
94 static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime
*runtime
,
95 struct usX2Ydev
* usX2Y
)
97 return (runtime
->buffer_size
* 1000) / usX2Y
->rate
+ 1; //FIXME: so far only correct period_size == 2^x ?
101 * prepare urb for playback data pipe
103 * we copy the data directly from the pcm buffer.
104 * the current position to be copied is held in hwptr field.
105 * since a urb can handle only a single linear buffer, if the total
106 * transferred area overflows the buffer boundary, we cannot send
107 * it directly from the buffer. thus the data is once copied to
108 * a temporary buffer and urb points to that.
110 static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream
*subs
,
113 int count
, counts
, pack
;
114 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
115 struct snd_usX2Y_hwdep_pcm_shm
*shm
= usX2Y
->hwdep_pcm_shm
;
116 struct snd_pcm_runtime
*runtime
= subs
->pcm_substream
->runtime
;
118 if (0 > shm
->playback_iso_start
) {
119 shm
->playback_iso_start
= shm
->captured_iso_head
-
120 usX2Y_iso_frames_per_buffer(runtime
, usX2Y
);
121 if (0 > shm
->playback_iso_start
)
122 shm
->playback_iso_start
+= ARRAY_SIZE(shm
->captured_iso
);
123 shm
->playback_iso_head
= shm
->playback_iso_start
;
127 for (pack
= 0; pack
< nr_of_packs(); pack
++) {
128 /* calculate the size of a packet */
129 counts
= shm
->captured_iso
[shm
->playback_iso_head
].length
/ usX2Y
->stride
;
130 if (counts
< 43 || counts
> 50) {
131 snd_printk(KERN_ERR
"should not be here with counts=%i\n", counts
);
134 /* set up descriptor */
135 urb
->iso_frame_desc
[pack
].offset
= shm
->captured_iso
[shm
->playback_iso_head
].offset
;
136 urb
->iso_frame_desc
[pack
].length
= shm
->captured_iso
[shm
->playback_iso_head
].length
;
137 if (atomic_read(&subs
->state
) != state_RUNNING
)
138 memset((char *)urb
->transfer_buffer
+ urb
->iso_frame_desc
[pack
].offset
, 0,
139 urb
->iso_frame_desc
[pack
].length
);
140 if (++shm
->playback_iso_head
>= ARRAY_SIZE(shm
->captured_iso
))
141 shm
->playback_iso_head
= 0;
144 urb
->transfer_buffer_length
= count
* usX2Y
->stride
;
149 static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream
*subs
,
153 for (pack
= 0; pack
< nr_of_packs(); ++pack
) {
154 struct usb_iso_packet_descriptor
*desc
= urb
->iso_frame_desc
+ pack
;
156 struct snd_usX2Y_hwdep_pcm_shm
*shm
= subs
->usX2Y
->hwdep_pcm_shm
;
157 int head
= shm
->captured_iso_head
+ 1;
158 if (head
>= ARRAY_SIZE(shm
->captured_iso
))
160 shm
->captured_iso
[head
].frame
= urb
->start_frame
+ pack
;
161 shm
->captured_iso
[head
].offset
= desc
->offset
;
162 shm
->captured_iso
[head
].length
= desc
->actual_length
;
163 shm
->captured_iso_head
= head
;
164 shm
->captured_iso_frames
++;
166 if ((desc
->offset
+= desc
->length
* NRURBS
*nr_of_packs()) +
168 desc
->offset
-= (SSS
- desc
->length
);
172 static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream
*capsubs
,
173 struct snd_usX2Y_substream
*capsubs2
,
174 struct snd_usX2Y_substream
*playbacksubs
,
178 struct urb
*urb
= playbacksubs
->completed_urb
;
180 state
= atomic_read(&playbacksubs
->state
);
182 if (state
== state_RUNNING
)
183 usX2Y_urb_play_retire(playbacksubs
, urb
);
184 else if (state
>= state_PRERUNNING
)
185 atomic_inc(&playbacksubs
->state
);
188 case state_STARTING1
:
189 urb
= playbacksubs
->urb
[0];
190 atomic_inc(&playbacksubs
->state
);
192 case state_STARTING2
:
193 urb
= playbacksubs
->urb
[1];
194 atomic_inc(&playbacksubs
->state
);
199 if ((err
= usX2Y_hwdep_urb_play_prepare(playbacksubs
, urb
)) ||
200 (err
= usX2Y_urb_submit(playbacksubs
, urb
, frame
))) {
205 playbacksubs
->completed_urb
= NULL
;
207 state
= atomic_read(&capsubs
->state
);
208 if (state
>= state_PREPARED
) {
209 if (state
== state_RUNNING
) {
210 if ((err
= usX2Y_usbpcm_urb_capt_retire(capsubs
)))
212 } else if (state
>= state_PRERUNNING
)
213 atomic_inc(&capsubs
->state
);
214 usX2Y_usbpcm_urb_capt_iso_advance(capsubs
, capsubs
->completed_urb
);
215 if (NULL
!= capsubs2
)
216 usX2Y_usbpcm_urb_capt_iso_advance(NULL
, capsubs2
->completed_urb
);
217 if ((err
= usX2Y_urb_submit(capsubs
, capsubs
->completed_urb
, frame
)))
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
)
232 struct snd_usX2Y_substream
*subs
= urb
->context
;
233 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
234 struct snd_usX2Y_substream
*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",
238 usb_get_current_frame_number(usX2Y
->dev
),
239 subs
->endpoint
, usb_pipein(urb
->pipe
) ? "in" : "out",
240 urb
->status
, urb
->start_frame
);
243 if (unlikely(urb
->status
)) {
244 usX2Y_error_urb_status(usX2Y
, subs
, urb
);
248 subs
->completed_urb
= urb
;
249 capsubs
= usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
];
250 capsubs2
= usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
+ 2];
251 playbacksubs
= usX2Y
->subs
[SNDRV_PCM_STREAM_PLAYBACK
];
252 if (capsubs
->completed_urb
&& atomic_read(&capsubs
->state
) >= state_PREPARED
&&
253 (NULL
== capsubs2
|| capsubs2
->completed_urb
) &&
254 (playbacksubs
->completed_urb
|| atomic_read(&playbacksubs
->state
) < state_PREPARED
)) {
255 if (!usX2Y_usbpcm_usbframe_complete(capsubs
, capsubs2
, playbacksubs
, urb
->start_frame
))
256 usX2Y
->wait_iso_frame
+= nr_of_packs();
259 usX2Y_clients_stop(usX2Y
);
265 static void usX2Y_hwdep_urb_release(struct urb
**urb
)
273 * release a substream
275 static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream
*subs
)
278 snd_printdd("snd_usX2Y_urbs_release() %i\n", subs
->endpoint
);
279 for (i
= 0; i
< NRURBS
; i
++)
280 usX2Y_hwdep_urb_release(subs
->urb
+ i
);
283 static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev
* usX2Y
)
285 usX2Y_urbs_set_complete(usX2Y
, i_usX2Y_usbpcm_urb_complete
);
286 usX2Y
->prepare_subs
= NULL
;
289 static void i_usX2Y_usbpcm_subs_startup(struct urb
*urb
)
291 struct snd_usX2Y_substream
*subs
= urb
->context
;
292 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
293 struct snd_usX2Y_substream
*prepare_subs
= usX2Y
->prepare_subs
;
294 if (NULL
!= prepare_subs
&&
295 urb
->start_frame
== prepare_subs
->urb
[0]->start_frame
) {
296 atomic_inc(&prepare_subs
->state
);
297 if (prepare_subs
== usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
]) {
298 struct snd_usX2Y_substream
*cap_subs2
= usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
+ 2];
299 if (cap_subs2
!= NULL
)
300 atomic_inc(&cap_subs2
->state
);
302 usX2Y_usbpcm_subs_startup_finish(usX2Y
);
303 wake_up(&usX2Y
->prepare_wait_queue
);
306 i_usX2Y_usbpcm_urb_complete(urb
);
310 * initialize a substream's urbs
312 static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream
*subs
)
316 int is_playback
= subs
== subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_PLAYBACK
];
317 struct usb_device
*dev
= subs
->usX2Y
->dev
;
319 pipe
= is_playback
? usb_sndisocpipe(dev
, subs
->endpoint
) :
320 usb_rcvisocpipe(dev
, subs
->endpoint
);
321 subs
->maxpacksize
= usb_maxpacket(dev
, pipe
, is_playback
);
322 if (!subs
->maxpacksize
)
325 /* allocate and initialize data urbs */
326 for (i
= 0; i
< NRURBS
; i
++) {
327 struct urb
**purb
= subs
->urb
+ i
;
332 *purb
= usb_alloc_urb(nr_of_packs(), GFP_KERNEL
);
334 usX2Y_usbpcm_urbs_release(subs
);
337 (*purb
)->transfer_buffer
= is_playback
?
338 subs
->usX2Y
->hwdep_pcm_shm
->playback
: (
339 subs
->endpoint
== 0x8 ?
340 subs
->usX2Y
->hwdep_pcm_shm
->capture0x8
:
341 subs
->usX2Y
->hwdep_pcm_shm
->capture0xA
);
344 (*purb
)->pipe
= pipe
;
345 (*purb
)->number_of_packets
= nr_of_packs();
346 (*purb
)->context
= subs
;
347 (*purb
)->interval
= 1;
348 (*purb
)->complete
= i_usX2Y_usbpcm_subs_startup
;
356 static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream
*substream
)
358 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
359 struct snd_usX2Y_substream
*subs
= runtime
->private_data
,
360 *cap_subs2
= subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
+ 2];
361 mutex_lock(&subs
->usX2Y
->pcm_mutex
);
362 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream
);
364 if (SNDRV_PCM_STREAM_PLAYBACK
== substream
->stream
) {
365 struct snd_usX2Y_substream
*cap_subs
= subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
];
366 atomic_set(&subs
->state
, state_STOPPED
);
367 usX2Y_usbpcm_urbs_release(subs
);
368 if (!cap_subs
->pcm_substream
||
369 !cap_subs
->pcm_substream
->runtime
||
370 !cap_subs
->pcm_substream
->runtime
->status
||
371 cap_subs
->pcm_substream
->runtime
->status
->state
< SNDRV_PCM_STATE_PREPARED
) {
372 atomic_set(&cap_subs
->state
, state_STOPPED
);
373 if (NULL
!= cap_subs2
)
374 atomic_set(&cap_subs2
->state
, state_STOPPED
);
375 usX2Y_usbpcm_urbs_release(cap_subs
);
376 if (NULL
!= cap_subs2
)
377 usX2Y_usbpcm_urbs_release(cap_subs2
);
380 struct snd_usX2Y_substream
*playback_subs
= subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_PLAYBACK
];
381 if (atomic_read(&playback_subs
->state
) < state_PREPARED
) {
382 atomic_set(&subs
->state
, state_STOPPED
);
383 if (NULL
!= cap_subs2
)
384 atomic_set(&cap_subs2
->state
, state_STOPPED
);
385 usX2Y_usbpcm_urbs_release(subs
);
386 if (NULL
!= cap_subs2
)
387 usX2Y_usbpcm_urbs_release(cap_subs2
);
390 mutex_unlock(&subs
->usX2Y
->pcm_mutex
);
391 return snd_pcm_lib_free_pages(substream
);
394 static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream
*subs
)
396 struct usX2Ydev
* usX2Y
= subs
->usX2Y
;
397 usX2Y
->prepare_subs
= subs
;
398 subs
->urb
[0]->start_frame
= -1;
399 smp_wmb(); // Make sure above modifications are seen by i_usX2Y_subs_startup()
400 usX2Y_urbs_set_complete(usX2Y
, i_usX2Y_usbpcm_subs_startup
);
403 static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream
*subs
)
406 stream
= subs
->pcm_substream
->stream
;
407 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
409 if (SNDRV_PCM_STREAM_CAPTURE
== stream
) {
410 usX2Y
->hwdep_pcm_shm
->captured_iso_head
= -1;
411 usX2Y
->hwdep_pcm_shm
->captured_iso_frames
= 0;
414 for (p
= 0; 3 >= (stream
+ p
); p
+= 2) {
415 struct snd_usX2Y_substream
*subs
= usX2Y
->subs
[stream
+ p
];
417 if ((err
= usX2Y_usbpcm_urbs_allocate(subs
)) < 0)
419 subs
->completed_urb
= NULL
;
423 for (p
= 0; p
< 4; p
++) {
424 struct snd_usX2Y_substream
*subs
= usX2Y
->subs
[p
];
425 if (subs
!= NULL
&& atomic_read(&subs
->state
) >= state_PREPARED
)
430 usX2Y_usbpcm_subs_startup(subs
);
431 for (u
= 0; u
< NRURBS
; u
++) {
432 for (p
= 0; 3 >= (stream
+ p
); p
+= 2) {
433 struct snd_usX2Y_substream
*subs
= usX2Y
->subs
[stream
+ p
];
435 struct urb
*urb
= subs
->urb
[u
];
436 if (usb_pipein(urb
->pipe
)) {
439 atomic_set(&subs
->state
, state_STARTING3
);
440 urb
->dev
= usX2Y
->dev
;
441 for (pack
= 0; pack
< nr_of_packs(); pack
++) {
442 urb
->iso_frame_desc
[pack
].offset
= subs
->maxpacksize
* (pack
+ u
* nr_of_packs());
443 urb
->iso_frame_desc
[pack
].length
= subs
->maxpacksize
;
445 urb
->transfer_buffer_length
= subs
->maxpacksize
* nr_of_packs();
446 if ((err
= usb_submit_urb(urb
, GFP_KERNEL
)) < 0) {
447 snd_printk (KERN_ERR
"cannot usb_submit_urb() for urb %d, err = %d\n", u
, err
);
451 snd_printdd("%i\n", urb
->start_frame
);
453 usX2Y
->wait_iso_frame
= urb
->start_frame
;
455 urb
->transfer_flags
= 0;
457 atomic_set(&subs
->state
, state_STARTING1
);
464 wait_event(usX2Y
->prepare_wait_queue
, NULL
== usX2Y
->prepare_subs
);
465 if (atomic_read(&subs
->state
) != state_PREPARED
)
470 usX2Y_subs_startup_finish(usX2Y
); // Call it now
471 usX2Y_clients_stop(usX2Y
); // something is completely wroong > stop evrything
479 * set format and initialize urbs
481 static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream
*substream
)
483 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
484 struct snd_usX2Y_substream
*subs
= runtime
->private_data
;
485 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
486 struct snd_usX2Y_substream
*capsubs
= subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
];
488 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream
);
490 if (NULL
== usX2Y
->hwdep_pcm_shm
) {
491 if (NULL
== (usX2Y
->hwdep_pcm_shm
= snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm
), GFP_KERNEL
)))
493 memset(usX2Y
->hwdep_pcm_shm
, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm
));
496 mutex_lock(&usX2Y
->pcm_mutex
);
497 usX2Y_subs_prepare(subs
);
498 // Start hardware streams
499 // SyncStream first....
500 if (atomic_read(&capsubs
->state
) < state_PREPARED
) {
501 if (usX2Y
->format
!= runtime
->format
)
502 if ((err
= usX2Y_format_set(usX2Y
, runtime
->format
)) < 0)
503 goto up_prepare_mutex
;
504 if (usX2Y
->rate
!= runtime
->rate
)
505 if ((err
= usX2Y_rate_set(usX2Y
, runtime
->rate
)) < 0)
506 goto up_prepare_mutex
;
507 snd_printdd("starting capture pipe for %s\n", subs
== capsubs
?
508 "self" : "playpipe");
509 if (0 > (err
= usX2Y_usbpcm_urbs_start(capsubs
)))
510 goto up_prepare_mutex
;
513 if (subs
!= capsubs
) {
514 usX2Y
->hwdep_pcm_shm
->playback_iso_start
= -1;
515 if (atomic_read(&subs
->state
) < state_PREPARED
) {
516 while (usX2Y_iso_frames_per_buffer(runtime
, usX2Y
) >
517 usX2Y
->hwdep_pcm_shm
->captured_iso_frames
) {
518 snd_printdd("Wait: iso_frames_per_buffer=%i,"
519 "captured_iso_frames=%i\n",
520 usX2Y_iso_frames_per_buffer(runtime
, usX2Y
),
521 usX2Y
->hwdep_pcm_shm
->captured_iso_frames
);
522 if (msleep_interruptible(10)) {
524 goto up_prepare_mutex
;
527 if (0 > (err
= usX2Y_usbpcm_urbs_start(subs
)))
528 goto up_prepare_mutex
;
530 snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
531 usX2Y_iso_frames_per_buffer(runtime
, usX2Y
),
532 usX2Y
->hwdep_pcm_shm
->captured_iso_frames
);
534 usX2Y
->hwdep_pcm_shm
->capture_iso_start
= -1;
537 mutex_unlock(&usX2Y
->pcm_mutex
);
541 static struct snd_pcm_hardware snd_usX2Y_4c
=
543 .info
= (SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_INTERLEAVED
|
544 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
545 SNDRV_PCM_INFO_MMAP_VALID
),
546 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S24_3LE
,
547 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
,
552 .buffer_bytes_max
= (2*128*1024),
553 .period_bytes_min
= 64,
554 .period_bytes_max
= (128*1024),
562 static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream
*substream
)
564 struct snd_usX2Y_substream
*subs
= ((struct snd_usX2Y_substream
**)
565 snd_pcm_substream_chip(substream
))[substream
->stream
];
566 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
568 if (!(subs
->usX2Y
->chip_status
& USX2Y_STAT_CHIP_MMAP_PCM_URBS
))
571 runtime
->hw
= SNDRV_PCM_STREAM_PLAYBACK
== substream
->stream
? snd_usX2Y_2c
:
572 (subs
->usX2Y
->subs
[3] ? snd_usX2Y_4c
: snd_usX2Y_2c
);
573 runtime
->private_data
= subs
;
574 subs
->pcm_substream
= substream
;
575 snd_pcm_hw_constraint_minmax(runtime
, SNDRV_PCM_HW_PARAM_PERIOD_TIME
, 1000, 200000);
580 static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream
*substream
)
582 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
583 struct snd_usX2Y_substream
*subs
= runtime
->private_data
;
585 subs
->pcm_substream
= NULL
;
590 static const struct snd_pcm_ops snd_usX2Y_usbpcm_ops
=
592 .open
= snd_usX2Y_usbpcm_open
,
593 .close
= snd_usX2Y_usbpcm_close
,
594 .ioctl
= snd_pcm_lib_ioctl
,
595 .hw_params
= snd_usX2Y_pcm_hw_params
,
596 .hw_free
= snd_usX2Y_usbpcm_hw_free
,
597 .prepare
= snd_usX2Y_usbpcm_prepare
,
598 .trigger
= snd_usX2Y_pcm_trigger
,
599 .pointer
= snd_usX2Y_pcm_pointer
,
603 static int usX2Y_pcms_busy_check(struct snd_card
*card
)
605 struct usX2Ydev
*dev
= usX2Y(card
);
608 for (i
= 0; i
< dev
->pcm_devs
* 2; i
++) {
609 struct snd_usX2Y_substream
*subs
= dev
->subs
[i
];
610 if (subs
&& subs
->pcm_substream
&&
611 SUBSTREAM_BUSY(subs
->pcm_substream
))
617 static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep
*hw
, struct file
*file
)
619 struct snd_card
*card
= hw
->card
;
622 mutex_lock(&usX2Y(card
)->pcm_mutex
);
623 err
= usX2Y_pcms_busy_check(card
);
625 usX2Y(card
)->chip_status
|= USX2Y_STAT_CHIP_MMAP_PCM_URBS
;
626 mutex_unlock(&usX2Y(card
)->pcm_mutex
);
631 static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep
*hw
, struct file
*file
)
633 struct snd_card
*card
= hw
->card
;
636 mutex_lock(&usX2Y(card
)->pcm_mutex
);
637 err
= usX2Y_pcms_busy_check(card
);
639 usX2Y(hw
->card
)->chip_status
&= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS
;
640 mutex_unlock(&usX2Y(card
)->pcm_mutex
);
645 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct
*area
)
650 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct
*area
)
655 static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_fault
*vmf
)
657 unsigned long offset
;
660 offset
= vmf
->pgoff
<< PAGE_SHIFT
;
661 vaddr
= (char *)((struct usX2Ydev
*)vmf
->vma
->vm_private_data
)->hwdep_pcm_shm
+ offset
;
662 vmf
->page
= virt_to_page(vaddr
);
668 static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops
= {
669 .open
= snd_usX2Y_hwdep_pcm_vm_open
,
670 .close
= snd_usX2Y_hwdep_pcm_vm_close
,
671 .fault
= snd_usX2Y_hwdep_pcm_vm_fault
,
675 static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep
* hw
, struct file
*filp
, struct vm_area_struct
*area
)
677 unsigned long size
= (unsigned long)(area
->vm_end
- area
->vm_start
);
678 struct usX2Ydev
*usX2Y
= hw
->private_data
;
680 if (!(usX2Y
->chip_status
& USX2Y_STAT_CHIP_INIT
))
683 /* if userspace tries to mmap beyond end of our buffer, fail */
684 if (size
> PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm
))) {
685 snd_printd("%lu > %lu\n", size
, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm
));
689 if (!usX2Y
->hwdep_pcm_shm
) {
692 area
->vm_ops
= &snd_usX2Y_hwdep_pcm_vm_ops
;
693 area
->vm_flags
|= VM_DONTEXPAND
| VM_DONTDUMP
;
694 area
->vm_private_data
= hw
->private_data
;
699 static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep
*hwdep
)
701 struct usX2Ydev
*usX2Y
= hwdep
->private_data
;
702 if (NULL
!= usX2Y
->hwdep_pcm_shm
)
703 snd_free_pages(usX2Y
->hwdep_pcm_shm
, sizeof(struct snd_usX2Y_hwdep_pcm_shm
));
707 int usX2Y_hwdep_pcm_new(struct snd_card
*card
)
710 struct snd_hwdep
*hw
;
712 struct usb_device
*dev
= usX2Y(card
)->dev
;
713 if (1 != nr_of_packs())
716 if ((err
= snd_hwdep_new(card
, SND_USX2Y_USBPCM_ID
, 1, &hw
)) < 0)
719 hw
->iface
= SNDRV_HWDEP_IFACE_USX2Y_PCM
;
720 hw
->private_data
= usX2Y(card
);
721 hw
->private_free
= snd_usX2Y_hwdep_pcm_private_free
;
722 hw
->ops
.open
= snd_usX2Y_hwdep_pcm_open
;
723 hw
->ops
.release
= snd_usX2Y_hwdep_pcm_release
;
724 hw
->ops
.mmap
= snd_usX2Y_hwdep_pcm_mmap
;
726 sprintf(hw
->name
, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev
->bus
->busnum
, dev
->devnum
);
728 err
= snd_pcm_new(card
, NAME_ALLCAPS
" hwdep Audio", 2, 1, 1, &pcm
);
732 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_PLAYBACK
, &snd_usX2Y_usbpcm_ops
);
733 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
, &snd_usX2Y_usbpcm_ops
);
735 pcm
->private_data
= usX2Y(card
)->subs
;
738 sprintf(pcm
->name
, NAME_ALLCAPS
" hwdep Audio");
739 if (0 > (err
= snd_pcm_lib_preallocate_pages(pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
,
740 SNDRV_DMA_TYPE_CONTINUOUS
,
741 snd_dma_continuous_data(GFP_KERNEL
),
742 64*1024, 128*1024)) ||
743 0 > (err
= snd_pcm_lib_preallocate_pages(pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
,
744 SNDRV_DMA_TYPE_CONTINUOUS
,
745 snd_dma_continuous_data(GFP_KERNEL
),
746 64*1024, 128*1024))) {
756 int usX2Y_hwdep_pcm_new(struct snd_card
*card
)