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 "usbusx2yaudio.c"
55 #if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1)
57 #include <sound/hwdep.h>
60 static int usX2Y_usbpcm_urb_capt_retire(snd_usX2Y_substream_t
*subs
)
62 struct urb
*urb
= subs
->completed_urb
;
63 snd_pcm_runtime_t
*runtime
= subs
->pcm_substream
->runtime
;
64 int i
, lens
= 0, hwptr_done
= subs
->hwptr_done
;
65 usX2Ydev_t
*usX2Y
= subs
->usX2Y
;
66 if (0 > usX2Y
->hwdep_pcm_shm
->capture_iso_start
) { //FIXME
67 int head
= usX2Y
->hwdep_pcm_shm
->captured_iso_head
+ 1;
68 if (head
>= ARRAY_SIZE(usX2Y
->hwdep_pcm_shm
->captured_iso
))
70 usX2Y
->hwdep_pcm_shm
->capture_iso_start
= head
;
71 snd_printdd("cap start %i\n", head
);
73 for (i
= 0; i
< nr_of_packs(); i
++) {
74 if (urb
->iso_frame_desc
[i
].status
) { /* active? hmm, skip this */
75 snd_printk("activ frame status %i. Most propably some hardware problem.\n", urb
->iso_frame_desc
[i
].status
);
76 return urb
->iso_frame_desc
[i
].status
;
78 lens
+= urb
->iso_frame_desc
[i
].actual_length
/ usX2Y
->stride
;
80 if ((hwptr_done
+= lens
) >= runtime
->buffer_size
)
81 hwptr_done
-= runtime
->buffer_size
;
82 subs
->hwptr_done
= hwptr_done
;
83 subs
->transfer_done
+= lens
;
84 /* update the pointer, call callback if necessary */
85 if (subs
->transfer_done
>= runtime
->period_size
) {
86 subs
->transfer_done
-= runtime
->period_size
;
87 snd_pcm_period_elapsed(subs
->pcm_substream
);
92 static inline int usX2Y_iso_frames_per_buffer(snd_pcm_runtime_t
*runtime
, usX2Ydev_t
* usX2Y
)
94 return (runtime
->buffer_size
* 1000) / usX2Y
->rate
+ 1; //FIXME: so far only correct period_size == 2^x ?
98 * prepare urb for playback data pipe
100 * we copy the data directly from the pcm buffer.
101 * the current position to be copied is held in hwptr field.
102 * since a urb can handle only a single linear buffer, if the total
103 * transferred area overflows the buffer boundary, we cannot send
104 * it directly from the buffer. thus the data is once copied to
105 * a temporary buffer and urb points to that.
107 static int usX2Y_hwdep_urb_play_prepare(snd_usX2Y_substream_t
*subs
,
110 int count
, counts
, pack
;
111 usX2Ydev_t
*usX2Y
= subs
->usX2Y
;
112 struct snd_usX2Y_hwdep_pcm_shm
*shm
= usX2Y
->hwdep_pcm_shm
;
113 snd_pcm_runtime_t
*runtime
= subs
->pcm_substream
->runtime
;
115 if (0 > shm
->playback_iso_start
) {
116 shm
->playback_iso_start
= shm
->captured_iso_head
-
117 usX2Y_iso_frames_per_buffer(runtime
, usX2Y
);
118 if (0 > shm
->playback_iso_start
)
119 shm
->playback_iso_start
+= ARRAY_SIZE(shm
->captured_iso
);
120 shm
->playback_iso_head
= shm
->playback_iso_start
;
124 for (pack
= 0; pack
< nr_of_packs(); pack
++) {
125 /* calculate the size of a packet */
126 counts
= shm
->captured_iso
[shm
->playback_iso_head
].length
/ usX2Y
->stride
;
127 if (counts
< 43 || counts
> 50) {
128 snd_printk("should not be here with counts=%i\n", counts
);
131 /* set up descriptor */
132 urb
->iso_frame_desc
[pack
].offset
= shm
->captured_iso
[shm
->playback_iso_head
].offset
;
133 urb
->iso_frame_desc
[pack
].length
= shm
->captured_iso
[shm
->playback_iso_head
].length
;
134 if (atomic_read(&subs
->state
) != state_RUNNING
)
135 memset((char *)urb
->transfer_buffer
+ urb
->iso_frame_desc
[pack
].offset
, 0,
136 urb
->iso_frame_desc
[pack
].length
);
137 if (++shm
->playback_iso_head
>= ARRAY_SIZE(shm
->captured_iso
))
138 shm
->playback_iso_head
= 0;
141 urb
->transfer_buffer_length
= count
* usX2Y
->stride
;
146 static inline void usX2Y_usbpcm_urb_capt_iso_advance(snd_usX2Y_substream_t
*subs
, struct urb
*urb
)
149 for (pack
= 0; pack
< nr_of_packs(); ++pack
) {
150 struct usb_iso_packet_descriptor
*desc
= urb
->iso_frame_desc
+ pack
;
152 snd_usX2Y_hwdep_pcm_shm_t
*shm
= subs
->usX2Y
->hwdep_pcm_shm
;
153 int head
= shm
->captured_iso_head
+ 1;
154 if (head
>= ARRAY_SIZE(shm
->captured_iso
))
156 shm
->captured_iso
[head
].frame
= urb
->start_frame
+ pack
;
157 shm
->captured_iso
[head
].offset
= desc
->offset
;
158 shm
->captured_iso
[head
].length
= desc
->actual_length
;
159 shm
->captured_iso_head
= head
;
160 shm
->captured_iso_frames
++;
162 if ((desc
->offset
+= desc
->length
* NRURBS
*nr_of_packs()) +
164 desc
->offset
-= (SSS
- desc
->length
);
168 static inline int usX2Y_usbpcm_usbframe_complete(snd_usX2Y_substream_t
*capsubs
,
169 snd_usX2Y_substream_t
*capsubs2
,
170 snd_usX2Y_substream_t
*playbacksubs
, int frame
)
173 struct urb
*urb
= playbacksubs
->completed_urb
;
175 state
= atomic_read(&playbacksubs
->state
);
177 if (state
== state_RUNNING
)
178 usX2Y_urb_play_retire(playbacksubs
, urb
);
180 if (state
>= state_PRERUNNING
) {
181 atomic_inc(&playbacksubs
->state
);
185 case state_STARTING1
:
186 urb
= playbacksubs
->urb
[0];
187 atomic_inc(&playbacksubs
->state
);
189 case state_STARTING2
:
190 urb
= playbacksubs
->urb
[1];
191 atomic_inc(&playbacksubs
->state
);
196 if ((err
= usX2Y_hwdep_urb_play_prepare(playbacksubs
, urb
)) ||
197 (err
= usX2Y_urb_submit(playbacksubs
, urb
, frame
))) {
202 playbacksubs
->completed_urb
= NULL
;
204 state
= atomic_read(&capsubs
->state
);
205 if (state
>= state_PREPARED
) {
206 if (state
== state_RUNNING
) {
207 if ((err
= usX2Y_usbpcm_urb_capt_retire(capsubs
)))
210 if (state
>= state_PRERUNNING
)
211 atomic_inc(&capsubs
->state
);
213 usX2Y_usbpcm_urb_capt_iso_advance(capsubs
, capsubs
->completed_urb
);
214 if (NULL
!= capsubs2
)
215 usX2Y_usbpcm_urb_capt_iso_advance(NULL
, capsubs2
->completed_urb
);
216 if ((err
= usX2Y_urb_submit(capsubs
, capsubs
->completed_urb
, frame
)))
218 if (NULL
!= capsubs2
)
219 if ((err
= usX2Y_urb_submit(capsubs2
, capsubs2
->completed_urb
, frame
)))
222 capsubs
->completed_urb
= NULL
;
223 if (NULL
!= capsubs2
)
224 capsubs2
->completed_urb
= NULL
;
229 static void i_usX2Y_usbpcm_urb_complete(struct urb
*urb
, struct pt_regs
*regs
)
231 snd_usX2Y_substream_t
*subs
= (snd_usX2Y_substream_t
*)urb
->context
;
232 usX2Ydev_t
*usX2Y
= subs
->usX2Y
;
233 snd_usX2Y_substream_t
*capsubs
, *capsubs2
, *playbacksubs
;
235 if (unlikely(atomic_read(&subs
->state
) < state_PREPARED
)) {
236 snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", usb_get_current_frame_number(usX2Y
->chip
.dev
), subs
->endpoint
, usb_pipein(urb
->pipe
) ? "in" : "out", urb
->status
, urb
->start_frame
);
239 if (unlikely(urb
->status
)) {
240 usX2Y_error_urb_status(usX2Y
, subs
, urb
);
243 if (likely((0xFFFF & urb
->start_frame
) == usX2Y
->wait_iso_frame
))
244 subs
->completed_urb
= urb
;
246 usX2Y_error_sequence(usX2Y
, subs
, urb
);
250 capsubs
= usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
];
251 capsubs2
= usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
+ 2];
252 playbacksubs
= usX2Y
->subs
[SNDRV_PCM_STREAM_PLAYBACK
];
253 if (capsubs
->completed_urb
&& atomic_read(&capsubs
->state
) >= state_PREPARED
&&
254 (NULL
== capsubs2
|| capsubs2
->completed_urb
) &&
255 (playbacksubs
->completed_urb
|| atomic_read(&playbacksubs
->state
) < state_PREPARED
)) {
256 if (!usX2Y_usbpcm_usbframe_complete(capsubs
, capsubs2
, playbacksubs
, urb
->start_frame
)) {
257 if (nr_of_packs() <= urb
->start_frame
&&
258 urb
->start_frame
<= (2 * nr_of_packs() - 1)) // uhci and ohci
259 usX2Y
->wait_iso_frame
= urb
->start_frame
- nr_of_packs();
261 usX2Y
->wait_iso_frame
+= nr_of_packs();
264 usX2Y_clients_stop(usX2Y
);
270 static void usX2Y_hwdep_urb_release(struct urb
** urb
)
278 * release a substream
280 static void usX2Y_usbpcm_urbs_release(snd_usX2Y_substream_t
*subs
)
283 snd_printdd("snd_usX2Y_urbs_release() %i\n", subs
->endpoint
);
284 for (i
= 0; i
< NRURBS
; i
++)
285 usX2Y_hwdep_urb_release(subs
->urb
+ i
);
288 static void usX2Y_usbpcm_subs_startup_finish(usX2Ydev_t
* usX2Y
)
290 usX2Y_urbs_set_complete(usX2Y
, i_usX2Y_usbpcm_urb_complete
);
291 usX2Y
->prepare_subs
= NULL
;
294 static void i_usX2Y_usbpcm_subs_startup(struct urb
*urb
, struct pt_regs
*regs
)
296 snd_usX2Y_substream_t
*subs
= (snd_usX2Y_substream_t
*)urb
->context
;
297 usX2Ydev_t
*usX2Y
= subs
->usX2Y
;
298 snd_usX2Y_substream_t
*prepare_subs
= usX2Y
->prepare_subs
;
299 if (NULL
!= prepare_subs
&&
300 urb
->start_frame
== prepare_subs
->urb
[0]->start_frame
) {
301 atomic_inc(&prepare_subs
->state
);
302 if (prepare_subs
== usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
]) {
303 snd_usX2Y_substream_t
*cap_subs2
= usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
+ 2];
304 if (cap_subs2
!= NULL
)
305 atomic_inc(&cap_subs2
->state
);
307 usX2Y_usbpcm_subs_startup_finish(usX2Y
);
308 wake_up(&usX2Y
->prepare_wait_queue
);
311 i_usX2Y_usbpcm_urb_complete(urb
, regs
);
315 * initialize a substream's urbs
317 static int usX2Y_usbpcm_urbs_allocate(snd_usX2Y_substream_t
*subs
)
321 int is_playback
= subs
== subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_PLAYBACK
];
322 struct usb_device
*dev
= subs
->usX2Y
->chip
.dev
;
324 pipe
= is_playback
? usb_sndisocpipe(dev
, subs
->endpoint
) :
325 usb_rcvisocpipe(dev
, subs
->endpoint
);
326 subs
->maxpacksize
= usb_maxpacket(dev
, pipe
, is_playback
);
327 if (!subs
->maxpacksize
)
330 /* allocate and initialize data urbs */
331 for (i
= 0; i
< NRURBS
; i
++) {
332 struct urb
** purb
= subs
->urb
+ i
;
337 *purb
= usb_alloc_urb(nr_of_packs(), GFP_KERNEL
);
339 usX2Y_usbpcm_urbs_release(subs
);
342 (*purb
)->transfer_buffer
= is_playback
?
343 subs
->usX2Y
->hwdep_pcm_shm
->playback
: (
344 subs
->endpoint
== 0x8 ?
345 subs
->usX2Y
->hwdep_pcm_shm
->capture0x8
:
346 subs
->usX2Y
->hwdep_pcm_shm
->capture0xA
);
349 (*purb
)->pipe
= pipe
;
350 (*purb
)->number_of_packets
= nr_of_packs();
351 (*purb
)->context
= subs
;
352 (*purb
)->interval
= 1;
353 (*purb
)->complete
= i_usX2Y_usbpcm_subs_startup
;
361 static int snd_usX2Y_usbpcm_hw_free(snd_pcm_substream_t
*substream
)
363 snd_pcm_runtime_t
*runtime
= substream
->runtime
;
364 snd_usX2Y_substream_t
*subs
= (snd_usX2Y_substream_t
*)runtime
->private_data
,
365 *cap_subs2
= subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
+ 2];
366 down(&subs
->usX2Y
->prepare_mutex
);
367 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream
);
369 if (SNDRV_PCM_STREAM_PLAYBACK
== substream
->stream
) {
370 snd_usX2Y_substream_t
*cap_subs
= subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_CAPTURE
];
371 atomic_set(&subs
->state
, state_STOPPED
);
372 usX2Y_usbpcm_urbs_release(subs
);
373 if (!cap_subs
->pcm_substream
||
374 !cap_subs
->pcm_substream
->runtime
||
375 !cap_subs
->pcm_substream
->runtime
->status
||
376 cap_subs
->pcm_substream
->runtime
->status
->state
< SNDRV_PCM_STATE_PREPARED
) {
377 atomic_set(&cap_subs
->state
, state_STOPPED
);
378 if (NULL
!= cap_subs2
)
379 atomic_set(&cap_subs2
->state
, state_STOPPED
);
380 usX2Y_usbpcm_urbs_release(cap_subs
);
381 if (NULL
!= cap_subs2
)
382 usX2Y_usbpcm_urbs_release(cap_subs2
);
385 snd_usX2Y_substream_t
*playback_subs
= subs
->usX2Y
->subs
[SNDRV_PCM_STREAM_PLAYBACK
];
386 if (atomic_read(&playback_subs
->state
) < state_PREPARED
) {
387 atomic_set(&subs
->state
, state_STOPPED
);
388 if (NULL
!= cap_subs2
)
389 atomic_set(&cap_subs2
->state
, state_STOPPED
);
390 usX2Y_usbpcm_urbs_release(subs
);
391 if (NULL
!= cap_subs2
)
392 usX2Y_usbpcm_urbs_release(cap_subs2
);
395 up(&subs
->usX2Y
->prepare_mutex
);
396 return snd_pcm_lib_free_pages(substream
);
399 static void usX2Y_usbpcm_subs_startup(snd_usX2Y_substream_t
*subs
)
401 usX2Ydev_t
* usX2Y
= subs
->usX2Y
;
402 usX2Y
->prepare_subs
= subs
;
403 subs
->urb
[0]->start_frame
= -1;
404 smp_wmb(); // Make shure above modifications are seen by i_usX2Y_subs_startup()
405 usX2Y_urbs_set_complete(usX2Y
, i_usX2Y_usbpcm_subs_startup
);
408 static int usX2Y_usbpcm_urbs_start(snd_usX2Y_substream_t
*subs
)
411 stream
= subs
->pcm_substream
->stream
;
412 usX2Ydev_t
*usX2Y
= subs
->usX2Y
;
414 if (SNDRV_PCM_STREAM_CAPTURE
== stream
) {
415 usX2Y
->hwdep_pcm_shm
->captured_iso_head
= -1;
416 usX2Y
->hwdep_pcm_shm
->captured_iso_frames
= 0;
419 for (p
= 0; 3 >= (stream
+ p
); p
+= 2) {
420 snd_usX2Y_substream_t
*subs
= usX2Y
->subs
[stream
+ p
];
422 if ((err
= usX2Y_usbpcm_urbs_allocate(subs
)) < 0)
424 subs
->completed_urb
= NULL
;
428 for (p
= 0; p
< 4; p
++) {
429 snd_usX2Y_substream_t
*subs
= usX2Y
->subs
[p
];
430 if (subs
!= NULL
&& atomic_read(&subs
->state
) >= state_PREPARED
)
433 usX2Y
->wait_iso_frame
= -1;
436 usX2Y_usbpcm_subs_startup(subs
);
437 for (u
= 0; u
< NRURBS
; u
++) {
438 for (p
= 0; 3 >= (stream
+ p
); p
+= 2) {
439 snd_usX2Y_substream_t
*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
->chip
.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
);
459 if (0 > usX2Y
->wait_iso_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(snd_pcm_substream_t
*substream
)
490 snd_pcm_runtime_t
*runtime
= substream
->runtime
;
491 snd_usX2Y_substream_t
*subs
= (snd_usX2Y_substream_t
*)runtime
->private_data
;
492 usX2Ydev_t
*usX2Y
= subs
->usX2Y
;
493 snd_usX2Y_substream_t
*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(snd_usX2Y_hwdep_pcm_shm_t
), GFP_KERNEL
)))
500 memset(usX2Y
->hwdep_pcm_shm
, 0, sizeof(snd_usX2Y_hwdep_pcm_shm_t
));
503 down(&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
? "self" : "playpipe");
515 if (0 > (err
= usX2Y_usbpcm_urbs_start(capsubs
)))
516 goto up_prepare_mutex
;
519 if (subs
!= capsubs
) {
520 usX2Y
->hwdep_pcm_shm
->playback_iso_start
= -1;
521 if (atomic_read(&subs
->state
) < state_PREPARED
) {
522 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 set_current_state(TASK_INTERRUPTIBLE
);
526 timeout
= schedule_timeout(HZ
/100 + 1);
527 if (signal_pending(current
)) {
529 goto up_prepare_mutex
;
532 if (0 > (err
= usX2Y_usbpcm_urbs_start(subs
)))
533 goto up_prepare_mutex
;
535 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
);
537 usX2Y
->hwdep_pcm_shm
->capture_iso_start
= -1;
540 up(&usX2Y
->prepare_mutex
);
544 static snd_pcm_hardware_t snd_usX2Y_4c
=
546 .info
= (SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_INTERLEAVED
|
547 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
548 SNDRV_PCM_INFO_MMAP_VALID
),
549 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S24_3LE
,
550 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
,
555 .buffer_bytes_max
= (2*128*1024),
556 .period_bytes_min
= 64,
557 .period_bytes_max
= (128*1024),
565 static int snd_usX2Y_usbpcm_open(snd_pcm_substream_t
*substream
)
567 snd_usX2Y_substream_t
*subs
= ((snd_usX2Y_substream_t
**)
568 snd_pcm_substream_chip(substream
))[substream
->stream
];
569 snd_pcm_runtime_t
*runtime
= substream
->runtime
;
571 if (!(subs
->usX2Y
->chip_status
& USX2Y_STAT_CHIP_MMAP_PCM_URBS
))
574 runtime
->hw
= SNDRV_PCM_STREAM_PLAYBACK
== substream
->stream
? snd_usX2Y_2c
:
575 (subs
->usX2Y
->subs
[3] ? snd_usX2Y_4c
: snd_usX2Y_2c
);
576 runtime
->private_data
= subs
;
577 subs
->pcm_substream
= substream
;
578 snd_pcm_hw_constraint_minmax(runtime
, SNDRV_PCM_HW_PARAM_PERIOD_TIME
, 1000, 200000);
583 static int snd_usX2Y_usbpcm_close(snd_pcm_substream_t
*substream
)
585 snd_pcm_runtime_t
*runtime
= substream
->runtime
;
586 snd_usX2Y_substream_t
*subs
= (snd_usX2Y_substream_t
*)runtime
->private_data
;
589 subs
->pcm_substream
= NULL
;
594 static snd_pcm_ops_t snd_usX2Y_usbpcm_ops
=
596 .open
= snd_usX2Y_usbpcm_open
,
597 .close
= snd_usX2Y_usbpcm_close
,
598 .ioctl
= snd_pcm_lib_ioctl
,
599 .hw_params
= snd_usX2Y_pcm_hw_params
,
600 .hw_free
= snd_usX2Y_usbpcm_hw_free
,
601 .prepare
= snd_usX2Y_usbpcm_prepare
,
602 .trigger
= snd_usX2Y_pcm_trigger
,
603 .pointer
= snd_usX2Y_pcm_pointer
,
607 static int usX2Y_pcms_lock_check(snd_card_t
*card
)
609 struct list_head
*list
;
613 list_for_each(list
, &card
->devices
) {
614 dev
= snd_device(list
);
615 if (dev
->type
!= SNDRV_DEV_PCM
)
617 pcm
= dev
->device_data
;
618 down(&pcm
->open_mutex
);
620 list_for_each(list
, &card
->devices
) {
622 dev
= snd_device(list
);
623 if (dev
->type
!= SNDRV_DEV_PCM
)
625 pcm
= dev
->device_data
;
626 for (s
= 0; s
< 2; ++s
) {
627 snd_pcm_substream_t
*substream
;
628 substream
= pcm
->streams
[s
].substream
;
629 if (substream
&& substream
->open_flag
)
637 static void usX2Y_pcms_unlock(snd_card_t
*card
)
639 struct list_head
*list
;
642 list_for_each(list
, &card
->devices
) {
643 dev
= snd_device(list
);
644 if (dev
->type
!= SNDRV_DEV_PCM
)
646 pcm
= dev
->device_data
;
647 up(&pcm
->open_mutex
);
652 static int snd_usX2Y_hwdep_pcm_open(snd_hwdep_t
*hw
, struct file
*file
)
654 // we need to be the first
655 snd_card_t
*card
= hw
->card
;
656 int err
= usX2Y_pcms_lock_check(card
);
658 usX2Y(card
)->chip_status
|= USX2Y_STAT_CHIP_MMAP_PCM_URBS
;
659 usX2Y_pcms_unlock(card
);
664 static int snd_usX2Y_hwdep_pcm_release(snd_hwdep_t
*hw
, struct file
*file
)
666 snd_card_t
*card
= hw
->card
;
667 int err
= usX2Y_pcms_lock_check(card
);
669 usX2Y(hw
->card
)->chip_status
&= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS
;
670 usX2Y_pcms_unlock(card
);
675 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct
*area
)
680 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct
*area
)
685 static struct page
* snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct
*area
, unsigned long address
, int *type
)
687 unsigned long offset
;
691 offset
= area
->vm_pgoff
<< PAGE_SHIFT
;
692 offset
+= address
- area
->vm_start
;
693 snd_assert((offset
% PAGE_SIZE
) == 0, return NOPAGE_OOM
);
694 vaddr
= (char*)((usX2Ydev_t
*)area
->vm_private_data
)->hwdep_pcm_shm
+ offset
;
695 page
= virt_to_page(vaddr
);
698 *type
= VM_FAULT_MINOR
;
704 static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops
= {
705 .open
= snd_usX2Y_hwdep_pcm_vm_open
,
706 .close
= snd_usX2Y_hwdep_pcm_vm_close
,
707 .nopage
= snd_usX2Y_hwdep_pcm_vm_nopage
,
711 static int snd_usX2Y_hwdep_pcm_mmap(snd_hwdep_t
* hw
, struct file
*filp
, struct vm_area_struct
*area
)
713 unsigned long size
= (unsigned long)(area
->vm_end
- area
->vm_start
);
714 usX2Ydev_t
*usX2Y
= (usX2Ydev_t
*)hw
->private_data
;
716 if (!(((usX2Ydev_t
*)hw
->private_data
)->chip_status
& USX2Y_STAT_CHIP_INIT
))
719 /* if userspace tries to mmap beyond end of our buffer, fail */
720 if (size
> PAGE_ALIGN(sizeof(snd_usX2Y_hwdep_pcm_shm_t
))) {
721 snd_printd("%lu > %lu\n", size
, (unsigned long)sizeof(snd_usX2Y_hwdep_pcm_shm_t
));
725 if (!usX2Y
->hwdep_pcm_shm
) {
728 area
->vm_ops
= &snd_usX2Y_hwdep_pcm_vm_ops
;
729 area
->vm_flags
|= VM_RESERVED
;
730 snd_printd("vm_flags=0x%lX\n", area
->vm_flags
);
731 area
->vm_private_data
= hw
->private_data
;
736 static void snd_usX2Y_hwdep_pcm_private_free(snd_hwdep_t
*hwdep
)
738 usX2Ydev_t
*usX2Y
= (usX2Ydev_t
*)hwdep
->private_data
;
739 if (NULL
!= usX2Y
->hwdep_pcm_shm
)
740 snd_free_pages(usX2Y
->hwdep_pcm_shm
, sizeof(snd_usX2Y_hwdep_pcm_shm_t
));
744 static void snd_usX2Y_usbpcm_private_free(snd_pcm_t
*pcm
)
746 snd_pcm_lib_preallocate_free_for_all(pcm
);
750 int usX2Y_hwdep_pcm_new(snd_card_t
* card
)
755 struct usb_device
*dev
= usX2Y(card
)->chip
.dev
;
756 if (1 != nr_of_packs())
759 if ((err
= snd_hwdep_new(card
, SND_USX2Y_USBPCM_ID
, 1, &hw
)) < 0) {
763 hw
->iface
= SNDRV_HWDEP_IFACE_USX2Y_PCM
;
764 hw
->private_data
= usX2Y(card
);
765 hw
->private_free
= snd_usX2Y_hwdep_pcm_private_free
;
766 hw
->ops
.open
= snd_usX2Y_hwdep_pcm_open
;
767 hw
->ops
.release
= snd_usX2Y_hwdep_pcm_release
;
768 hw
->ops
.mmap
= snd_usX2Y_hwdep_pcm_mmap
;
770 sprintf(hw
->name
, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev
->bus
->busnum
, dev
->devnum
);
772 err
= snd_pcm_new(card
, NAME_ALLCAPS
" hwdep Audio", 2, 1, 1, &pcm
);
776 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_PLAYBACK
, &snd_usX2Y_usbpcm_ops
);
777 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
, &snd_usX2Y_usbpcm_ops
);
779 pcm
->private_data
= usX2Y(card
)->subs
;
780 pcm
->private_free
= snd_usX2Y_usbpcm_private_free
;
783 sprintf(pcm
->name
, NAME_ALLCAPS
" hwdep Audio");
784 if (0 > (err
= snd_pcm_lib_preallocate_pages(pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
,
785 SNDRV_DMA_TYPE_CONTINUOUS
,
786 snd_dma_continuous_data(GFP_KERNEL
),
787 64*1024, 128*1024)) ||
788 0 > (err
= snd_pcm_lib_preallocate_pages(pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
,
789 SNDRV_DMA_TYPE_CONTINUOUS
,
790 snd_dma_continuous_data(GFP_KERNEL
),
791 64*1024, 128*1024))) {
792 snd_usX2Y_usbpcm_private_free(pcm
);
802 int usX2Y_hwdep_pcm_new(snd_card_t
* card
)