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 <linux/gfp.h>
55 #include "usbusx2yaudio.c"
57 #if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && \
60 #include <sound/hwdep.h>
63 static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream
*subs
)
65 struct urb
*urb
= subs
->completed_urb
;
66 struct snd_pcm_runtime
*runtime
= subs
->pcm_substream
->runtime
;
67 int i
, lens
= 0, hwptr_done
= subs
->hwptr_done
;
68 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
69 if (0 > usX2Y
->hwdep_pcm_shm
->capture_iso_start
) {
70 int head
= usX2Y
->hwdep_pcm_shm
->captured_iso_head
+ 1;
71 if (head
>= ARRAY_SIZE(usX2Y
->hwdep_pcm_shm
->captured_iso
))
73 usX2Y
->hwdep_pcm_shm
->capture_iso_start
= head
;
74 snd_printdd("cap start %i\n", head
);
76 for (i
= 0; i
< nr_of_packs(); i
++) {
77 if (urb
->iso_frame_desc
[i
].status
) { /* active? hmm, skip this */
78 snd_printk(KERN_ERR
"activ frame status %i. Most propably some hardware problem.\n", urb
->iso_frame_desc
[i
].status
);
79 return urb
->iso_frame_desc
[i
].status
;
81 lens
+= urb
->iso_frame_desc
[i
].actual_length
/ usX2Y
->stride
;
83 if ((hwptr_done
+= lens
) >= runtime
->buffer_size
)
84 hwptr_done
-= runtime
->buffer_size
;
85 subs
->hwptr_done
= hwptr_done
;
86 subs
->transfer_done
+= lens
;
87 /* update the pointer, call callback if necessary */
88 if (subs
->transfer_done
>= runtime
->period_size
) {
89 subs
->transfer_done
-= runtime
->period_size
;
90 snd_pcm_period_elapsed(subs
->pcm_substream
);
95 static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime
*runtime
,
96 struct usX2Ydev
* usX2Y
)
98 return (runtime
->buffer_size
* 1000) / usX2Y
->rate
+ 1;
102 * prepare urb for playback data pipe
104 * we copy the data directly from the pcm buffer.
105 * the current position to be copied is held in hwptr field.
106 * since a urb can handle only a single linear buffer, if the total
107 * transferred area overflows the buffer boundary, we cannot send
108 * it directly from the buffer. thus the data is once copied to
109 * a temporary buffer and urb points to that.
111 static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream
*subs
,
114 int count
, counts
, pack
;
115 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
116 struct snd_usX2Y_hwdep_pcm_shm
*shm
= usX2Y
->hwdep_pcm_shm
;
117 struct snd_pcm_runtime
*runtime
= subs
->pcm_substream
->runtime
;
119 if (0 > shm
->playback_iso_start
) {
120 shm
->playback_iso_start
= shm
->captured_iso_head
-
121 usX2Y_iso_frames_per_buffer(runtime
, usX2Y
);
122 if (0 > shm
->playback_iso_start
)
123 shm
->playback_iso_start
+= ARRAY_SIZE(shm
->captured_iso
);
124 shm
->playback_iso_head
= shm
->playback_iso_start
;
128 for (pack
= 0; pack
< nr_of_packs(); pack
++) {
129 /* calculate the size of a packet */
130 counts
= shm
->captured_iso
[shm
->playback_iso_head
].length
/ usX2Y
->stride
;
131 if (counts
< 43 || counts
> 50) {
132 snd_printk(KERN_ERR
"should not be here with counts=%i\n", counts
);
135 /* set up descriptor */
136 urb
->iso_frame_desc
[pack
].offset
= shm
->captured_iso
[shm
->playback_iso_head
].offset
;
137 urb
->iso_frame_desc
[pack
].length
= shm
->captured_iso
[shm
->playback_iso_head
].length
;
138 if (atomic_read(&subs
->state
) != state_RUNNING
)
139 memset((char *)urb
->transfer_buffer
+ urb
->iso_frame_desc
[pack
].offset
, 0,
140 urb
->iso_frame_desc
[pack
].length
);
141 if (++shm
->playback_iso_head
>= ARRAY_SIZE(shm
->captured_iso
))
142 shm
->playback_iso_head
= 0;
145 urb
->transfer_buffer_length
= count
* usX2Y
->stride
;
150 static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream
*subs
,
154 for (pack
= 0; pack
< nr_of_packs(); ++pack
) {
155 struct usb_iso_packet_descriptor
*desc
= urb
->iso_frame_desc
+ pack
;
157 struct snd_usX2Y_hwdep_pcm_shm
*shm
= subs
->usX2Y
->hwdep_pcm_shm
;
158 int head
= shm
->captured_iso_head
+ 1;
159 if (head
>= ARRAY_SIZE(shm
->captured_iso
))
161 shm
->captured_iso
[head
].frame
= urb
->start_frame
+ pack
;
162 shm
->captured_iso
[head
].offset
= desc
->offset
;
163 shm
->captured_iso
[head
].length
= desc
->actual_length
;
164 shm
->captured_iso_head
= head
;
165 shm
->captured_iso_frames
++;
167 if ((desc
->offset
+= desc
->length
* NRURBS
*nr_of_packs()) +
169 desc
->offset
-= (SSS
- desc
->length
);
173 static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream
*capsubs
,
174 struct snd_usX2Y_substream
*capsubs2
,
175 struct snd_usX2Y_substream
*playbacksubs
,
179 struct urb
*urb
= playbacksubs
->completed_urb
;
181 state
= atomic_read(&playbacksubs
->state
);
183 if (state
== state_RUNNING
)
184 usX2Y_urb_play_retire(playbacksubs
, urb
);
185 else if (state
>= state_PRERUNNING
)
186 atomic_inc(&playbacksubs
->state
);
189 case state_STARTING1
:
190 urb
= playbacksubs
->urb
[0];
191 atomic_inc(&playbacksubs
->state
);
193 case state_STARTING2
:
194 urb
= playbacksubs
->urb
[1];
195 atomic_inc(&playbacksubs
->state
);
200 if ((err
= usX2Y_hwdep_urb_play_prepare(playbacksubs
, urb
)) ||
201 (err
= usX2Y_urb_submit(playbacksubs
, urb
, frame
))) {
206 playbacksubs
->completed_urb
= NULL
;
208 state
= atomic_read(&capsubs
->state
);
209 if (state
>= state_PREPARED
) {
210 if (state
== state_RUNNING
) {
211 if ((err
= usX2Y_usbpcm_urb_capt_retire(capsubs
)))
213 } else if (state
>= state_PRERUNNING
)
214 atomic_inc(&capsubs
->state
);
215 usX2Y_usbpcm_urb_capt_iso_advance(capsubs
, capsubs
->completed_urb
);
216 if (NULL
!= capsubs2
)
217 usX2Y_usbpcm_urb_capt_iso_advance(NULL
, capsubs2
->completed_urb
);
218 if ((err
= usX2Y_urb_submit(capsubs
, capsubs
->completed_urb
, frame
)))
220 if (NULL
!= capsubs2
)
221 if ((err
= usX2Y_urb_submit(capsubs2
, capsubs2
->completed_urb
, frame
)))
224 capsubs
->completed_urb
= NULL
;
225 if (NULL
!= capsubs2
)
226 capsubs2
->completed_urb
= NULL
;
231 static void i_usX2Y_usbpcm_urb_complete(struct urb
*urb
)
233 struct snd_usX2Y_substream
*subs
= urb
->context
;
234 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
235 struct snd_usX2Y_substream
*capsubs
, *capsubs2
, *playbacksubs
;
237 if (unlikely(atomic_read(&subs
->state
) < state_PREPARED
)) {
238 snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
239 usb_get_current_frame_number(usX2Y
->dev
),
240 subs
->endpoint
, usb_pipein(urb
->pipe
) ? "in" : "out",
241 urb
->status
, urb
->start_frame
);
244 if (unlikely(urb
->status
)) {
245 usX2Y_error_urb_status(usX2Y
, subs
, urb
);
248 if (likely((urb
->start_frame
& 0xFFFF) == (usX2Y
->wait_iso_frame
& 0xFFFF)))
249 subs
->completed_urb
= urb
;
251 usX2Y_error_sequence(usX2Y
, subs
, urb
);
255 capsubs
= usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
];
256 capsubs2
= usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
+ 2];
257 playbacksubs
= usX2Y
->subs
[SNDRV_PCM_STREAM_PLAYBACK
];
258 if (capsubs
->completed_urb
&& atomic_read(&capsubs
->state
) >= state_PREPARED
&&
259 (NULL
== capsubs2
|| capsubs2
->completed_urb
) &&
260 (playbacksubs
->completed_urb
|| atomic_read(&playbacksubs
->state
) < state_PREPARED
)) {
261 if (!usX2Y_usbpcm_usbframe_complete(capsubs
, capsubs2
, playbacksubs
, urb
->start_frame
))
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(struct snd_usX2Y_substream
*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(struct usX2Ydev
* 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
)
297 struct snd_usX2Y_substream
*subs
= urb
->context
;
298 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
299 struct snd_usX2Y_substream
*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 struct snd_usX2Y_substream
*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
);
316 * initialize a substream's urbs
318 static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream
*subs
)
322 int is_playback
= subs
== subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_PLAYBACK
];
323 struct usb_device
*dev
= subs
->usX2Y
->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(struct snd_pcm_substream
*substream
)
364 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
365 struct snd_usX2Y_substream
*subs
= runtime
->private_data
,
366 *cap_subs2
= subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
+ 2];
367 mutex_lock(&subs
->usX2Y
->prepare_mutex
);
368 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream
);
370 if (SNDRV_PCM_STREAM_PLAYBACK
== substream
->stream
) {
371 struct snd_usX2Y_substream
*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 struct snd_usX2Y_substream
*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 mutex_unlock(&subs
->usX2Y
->prepare_mutex
);
397 return snd_pcm_lib_free_pages(substream
);
400 static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream
*subs
)
402 struct usX2Ydev
* usX2Y
= subs
->usX2Y
;
403 usX2Y
->prepare_subs
= subs
;
404 subs
->urb
[0]->start_frame
= -1;
405 smp_wmb(); // Make sure 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(struct snd_usX2Y_substream
*subs
)
412 stream
= subs
->pcm_substream
->stream
;
413 struct usX2Ydev
*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 struct snd_usX2Y_substream
*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 struct snd_usX2Y_substream
*subs
= usX2Y
->subs
[p
];
431 if (subs
!= NULL
&& atomic_read(&subs
->state
) >= state_PREPARED
)
436 usX2Y_usbpcm_subs_startup(subs
);
437 for (u
= 0; u
< NRURBS
; u
++) {
438 for (p
= 0; 3 >= (stream
+ p
); p
+= 2) {
439 struct snd_usX2Y_substream
*subs
= usX2Y
->subs
[stream
+ p
];
441 struct urb
*urb
= subs
->urb
[u
];
442 if (usb_pipein(urb
->pipe
)) {
445 atomic_set(&subs
->state
, state_STARTING3
);
446 urb
->dev
= usX2Y
->dev
;
447 urb
->transfer_flags
= URB_ISO_ASAP
;
448 for (pack
= 0; pack
< nr_of_packs(); pack
++) {
449 urb
->iso_frame_desc
[pack
].offset
= subs
->maxpacksize
* (pack
+ u
* nr_of_packs());
450 urb
->iso_frame_desc
[pack
].length
= subs
->maxpacksize
;
452 urb
->transfer_buffer_length
= subs
->maxpacksize
* nr_of_packs();
453 if ((err
= usb_submit_urb(urb
, GFP_KERNEL
)) < 0) {
454 snd_printk (KERN_ERR
"cannot usb_submit_urb() for urb %d, err = %d\n", u
, err
);
458 snd_printdd("%i\n", urb
->start_frame
);
460 usX2Y
->wait_iso_frame
= urb
->start_frame
;
462 urb
->transfer_flags
= 0;
464 atomic_set(&subs
->state
, state_STARTING1
);
471 wait_event(usX2Y
->prepare_wait_queue
, NULL
== usX2Y
->prepare_subs
);
472 if (atomic_read(&subs
->state
) != state_PREPARED
)
477 usX2Y_subs_startup_finish(usX2Y
); // Call it now
478 usX2Y_clients_stop(usX2Y
); // something is completely wroong > stop evrything
486 * set format and initialize urbs
488 static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream
*substream
)
490 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
491 struct snd_usX2Y_substream
*subs
= runtime
->private_data
;
492 struct usX2Ydev
*usX2Y
= subs
->usX2Y
;
493 struct snd_usX2Y_substream
*capsubs
= subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
];
495 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream
);
497 if (NULL
== usX2Y
->hwdep_pcm_shm
) {
498 if (NULL
== (usX2Y
->hwdep_pcm_shm
= snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm
), GFP_KERNEL
)))
500 memset(usX2Y
->hwdep_pcm_shm
, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm
));
503 mutex_lock(&usX2Y
->prepare_mutex
);
504 usX2Y_subs_prepare(subs
);
505 // Start hardware streams
506 // SyncStream first....
507 if (atomic_read(&capsubs
->state
) < state_PREPARED
) {
508 if (usX2Y
->format
!= runtime
->format
)
509 if ((err
= usX2Y_format_set(usX2Y
, runtime
->format
)) < 0)
510 goto up_prepare_mutex
;
511 if (usX2Y
->rate
!= runtime
->rate
)
512 if ((err
= usX2Y_rate_set(usX2Y
, runtime
->rate
)) < 0)
513 goto up_prepare_mutex
;
514 snd_printdd("starting capture pipe for %s\n", subs
== capsubs
?
515 "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
) >
524 usX2Y
->hwdep_pcm_shm
->captured_iso_frames
) {
525 snd_printdd("Wait: iso_frames_per_buffer=%i,"
526 "captured_iso_frames=%i\n",
527 usX2Y_iso_frames_per_buffer(runtime
, usX2Y
),
528 usX2Y
->hwdep_pcm_shm
->captured_iso_frames
);
529 if (msleep_interruptible(10)) {
531 goto up_prepare_mutex
;
534 if (0 > (err
= usX2Y_usbpcm_urbs_start(subs
)))
535 goto up_prepare_mutex
;
537 snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
538 usX2Y_iso_frames_per_buffer(runtime
, usX2Y
),
539 usX2Y
->hwdep_pcm_shm
->captured_iso_frames
);
541 usX2Y
->hwdep_pcm_shm
->capture_iso_start
= -1;
544 mutex_unlock(&usX2Y
->prepare_mutex
);
548 static struct snd_pcm_hardware snd_usX2Y_4c
=
550 .info
= (SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_INTERLEAVED
|
551 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
552 SNDRV_PCM_INFO_MMAP_VALID
),
553 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S24_3LE
,
554 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
,
559 .buffer_bytes_max
= (2*128*1024),
560 .period_bytes_min
= 64,
561 .period_bytes_max
= (128*1024),
569 static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream
*substream
)
571 struct snd_usX2Y_substream
*subs
= ((struct snd_usX2Y_substream
**)
572 snd_pcm_substream_chip(substream
))[substream
->stream
];
573 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
575 if (!(subs
->usX2Y
->chip_status
& USX2Y_STAT_CHIP_MMAP_PCM_URBS
))
578 runtime
->hw
= SNDRV_PCM_STREAM_PLAYBACK
== substream
->stream
? snd_usX2Y_2c
:
579 (subs
->usX2Y
->subs
[3] ? snd_usX2Y_4c
: snd_usX2Y_2c
);
580 runtime
->private_data
= subs
;
581 subs
->pcm_substream
= substream
;
582 snd_pcm_hw_constraint_minmax(runtime
, SNDRV_PCM_HW_PARAM_PERIOD_TIME
, 1000, 200000);
587 static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream
*substream
)
589 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
590 struct snd_usX2Y_substream
*subs
= runtime
->private_data
;
592 subs
->pcm_substream
= NULL
;
597 static struct snd_pcm_ops snd_usX2Y_usbpcm_ops
=
599 .open
= snd_usX2Y_usbpcm_open
,
600 .close
= snd_usX2Y_usbpcm_close
,
601 .ioctl
= snd_pcm_lib_ioctl
,
602 .hw_params
= snd_usX2Y_pcm_hw_params
,
603 .hw_free
= snd_usX2Y_usbpcm_hw_free
,
604 .prepare
= snd_usX2Y_usbpcm_prepare
,
605 .trigger
= snd_usX2Y_pcm_trigger
,
606 .pointer
= snd_usX2Y_pcm_pointer
,
610 static int usX2Y_pcms_lock_check(struct snd_card
*card
)
612 struct list_head
*list
;
613 struct snd_device
*dev
;
616 list_for_each(list
, &card
->devices
) {
617 dev
= snd_device(list
);
618 if (dev
->type
!= SNDRV_DEV_PCM
)
620 pcm
= dev
->device_data
;
621 mutex_lock(&pcm
->open_mutex
);
623 list_for_each(list
, &card
->devices
) {
625 dev
= snd_device(list
);
626 if (dev
->type
!= SNDRV_DEV_PCM
)
628 pcm
= dev
->device_data
;
629 for (s
= 0; s
< 2; ++s
) {
630 struct snd_pcm_substream
*substream
;
631 substream
= pcm
->streams
[s
].substream
;
632 if (substream
&& SUBSTREAM_BUSY(substream
))
640 static void usX2Y_pcms_unlock(struct snd_card
*card
)
642 struct list_head
*list
;
643 struct snd_device
*dev
;
645 list_for_each(list
, &card
->devices
) {
646 dev
= snd_device(list
);
647 if (dev
->type
!= SNDRV_DEV_PCM
)
649 pcm
= dev
->device_data
;
650 mutex_unlock(&pcm
->open_mutex
);
655 static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep
*hw
, struct file
*file
)
657 // we need to be the first
658 struct snd_card
*card
= hw
->card
;
659 int err
= usX2Y_pcms_lock_check(card
);
661 usX2Y(card
)->chip_status
|= USX2Y_STAT_CHIP_MMAP_PCM_URBS
;
662 usX2Y_pcms_unlock(card
);
667 static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep
*hw
, struct file
*file
)
669 struct snd_card
*card
= hw
->card
;
670 int err
= usX2Y_pcms_lock_check(card
);
672 usX2Y(hw
->card
)->chip_status
&= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS
;
673 usX2Y_pcms_unlock(card
);
678 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct
*area
)
683 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct
*area
)
688 static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct
*area
,
689 struct vm_fault
*vmf
)
691 unsigned long offset
;
694 offset
= vmf
->pgoff
<< PAGE_SHIFT
;
695 vaddr
= (char*)((struct usX2Ydev
*)area
->vm_private_data
)->hwdep_pcm_shm
+ offset
;
696 vmf
->page
= virt_to_page(vaddr
);
702 static const 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 .fault
= snd_usX2Y_hwdep_pcm_vm_fault
,
709 static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep
* hw
, struct file
*filp
, struct vm_area_struct
*area
)
711 unsigned long size
= (unsigned long)(area
->vm_end
- area
->vm_start
);
712 struct usX2Ydev
*usX2Y
= hw
->private_data
;
714 if (!(usX2Y
->chip_status
& USX2Y_STAT_CHIP_INIT
))
717 /* if userspace tries to mmap beyond end of our buffer, fail */
718 if (size
> PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm
))) {
719 snd_printd("%lu > %lu\n", size
, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm
));
723 if (!usX2Y
->hwdep_pcm_shm
) {
726 area
->vm_ops
= &snd_usX2Y_hwdep_pcm_vm_ops
;
727 area
->vm_flags
|= VM_RESERVED
| VM_DONTEXPAND
;
728 area
->vm_private_data
= hw
->private_data
;
733 static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep
*hwdep
)
735 struct usX2Ydev
*usX2Y
= hwdep
->private_data
;
736 if (NULL
!= usX2Y
->hwdep_pcm_shm
)
737 snd_free_pages(usX2Y
->hwdep_pcm_shm
, sizeof(struct snd_usX2Y_hwdep_pcm_shm
));
741 int usX2Y_hwdep_pcm_new(struct snd_card
*card
)
744 struct snd_hwdep
*hw
;
746 struct usb_device
*dev
= usX2Y(card
)->dev
;
747 if (1 != nr_of_packs())
750 if ((err
= snd_hwdep_new(card
, SND_USX2Y_USBPCM_ID
, 1, &hw
)) < 0)
753 hw
->iface
= SNDRV_HWDEP_IFACE_USX2Y_PCM
;
754 hw
->private_data
= usX2Y(card
);
755 hw
->private_free
= snd_usX2Y_hwdep_pcm_private_free
;
756 hw
->ops
.open
= snd_usX2Y_hwdep_pcm_open
;
757 hw
->ops
.release
= snd_usX2Y_hwdep_pcm_release
;
758 hw
->ops
.mmap
= snd_usX2Y_hwdep_pcm_mmap
;
760 sprintf(hw
->name
, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev
->bus
->busnum
, dev
->devnum
);
762 err
= snd_pcm_new(card
, NAME_ALLCAPS
" hwdep Audio", 2, 1, 1, &pcm
);
766 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_PLAYBACK
, &snd_usX2Y_usbpcm_ops
);
767 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
, &snd_usX2Y_usbpcm_ops
);
769 pcm
->private_data
= usX2Y(card
)->subs
;
772 sprintf(pcm
->name
, NAME_ALLCAPS
" hwdep Audio");
773 if (0 > (err
= snd_pcm_lib_preallocate_pages(pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
,
774 SNDRV_DMA_TYPE_CONTINUOUS
,
775 snd_dma_continuous_data(GFP_KERNEL
),
776 64*1024, 128*1024)) ||
777 0 > (err
= snd_pcm_lib_preallocate_pages(pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
,
778 SNDRV_DMA_TYPE_CONTINUOUS
,
779 snd_dma_continuous_data(GFP_KERNEL
),
780 64*1024, 128*1024))) {
790 int usX2Y_hwdep_pcm_new(struct snd_card
*card
)