[NETFILTER]: xt_connmark: add compat conversion functions
[hh.org.git] / sound / usb / usx2y / usx2yhwdeppcm.c
blob88b72b52590f44c4566864577223720b2d5a7c98
1 /*
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.
24 Advantage achieved:
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,
35 2 periods.
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:
42 Userland:
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
45 conversation.
46 Currently the usx2y jack driver provides above 2 services.
47 Kernel:
48 - rawusb dma pcm buffer transport should go to snd-usb-lib, so also snd-usb-audio
49 devices can use it.
50 Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y.
53 #include <linux/delay.h>
54 #include "usbusx2yaudio.c"
56 #if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1)
58 #include <sound/hwdep.h>
61 static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs)
63 struct urb *urb = subs->completed_urb;
64 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
65 int i, lens = 0, hwptr_done = subs->hwptr_done;
66 struct usX2Ydev *usX2Y = subs->usX2Y;
67 if (0 > usX2Y->hwdep_pcm_shm->capture_iso_start) { //FIXME
68 int head = usX2Y->hwdep_pcm_shm->captured_iso_head + 1;
69 if (head >= ARRAY_SIZE(usX2Y->hwdep_pcm_shm->captured_iso))
70 head = 0;
71 usX2Y->hwdep_pcm_shm->capture_iso_start = head;
72 snd_printdd("cap start %i\n", head);
74 for (i = 0; i < nr_of_packs(); i++) {
75 if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
76 snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status);
77 return urb->iso_frame_desc[i].status;
79 lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;
81 if ((hwptr_done += lens) >= runtime->buffer_size)
82 hwptr_done -= runtime->buffer_size;
83 subs->hwptr_done = hwptr_done;
84 subs->transfer_done += lens;
85 /* update the pointer, call callback if necessary */
86 if (subs->transfer_done >= runtime->period_size) {
87 subs->transfer_done -= runtime->period_size;
88 snd_pcm_period_elapsed(subs->pcm_substream);
90 return 0;
93 static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
94 struct usX2Ydev * usX2Y)
96 return (runtime->buffer_size * 1000) / usX2Y->rate + 1; //FIXME: so far only correct period_size == 2^x ?
100 * prepare urb for playback data pipe
102 * we copy the data directly from the pcm buffer.
103 * the current position to be copied is held in hwptr field.
104 * since a urb can handle only a single linear buffer, if the total
105 * transferred area overflows the buffer boundary, we cannot send
106 * it directly from the buffer. thus the data is once copied to
107 * a temporary buffer and urb points to that.
109 static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs,
110 struct urb *urb)
112 int count, counts, pack;
113 struct usX2Ydev *usX2Y = subs->usX2Y;
114 struct snd_usX2Y_hwdep_pcm_shm *shm = usX2Y->hwdep_pcm_shm;
115 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
117 if (0 > shm->playback_iso_start) {
118 shm->playback_iso_start = shm->captured_iso_head -
119 usX2Y_iso_frames_per_buffer(runtime, usX2Y);
120 if (0 > shm->playback_iso_start)
121 shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
122 shm->playback_iso_head = shm->playback_iso_start;
125 count = 0;
126 for (pack = 0; pack < nr_of_packs(); pack++) {
127 /* calculate the size of a packet */
128 counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride;
129 if (counts < 43 || counts > 50) {
130 snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
131 return -EPIPE;
133 /* set up descriptor */
134 urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
135 urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
136 if (atomic_read(&subs->state) != state_RUNNING)
137 memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
138 urb->iso_frame_desc[pack].length);
139 if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
140 shm->playback_iso_head = 0;
141 count += counts;
143 urb->transfer_buffer_length = count * usX2Y->stride;
144 return 0;
148 static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream *subs,
149 struct urb *urb)
151 int pack;
152 for (pack = 0; pack < nr_of_packs(); ++pack) {
153 struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack;
154 if (NULL != subs) {
155 struct snd_usX2Y_hwdep_pcm_shm *shm = subs->usX2Y->hwdep_pcm_shm;
156 int head = shm->captured_iso_head + 1;
157 if (head >= ARRAY_SIZE(shm->captured_iso))
158 head = 0;
159 shm->captured_iso[head].frame = urb->start_frame + pack;
160 shm->captured_iso[head].offset = desc->offset;
161 shm->captured_iso[head].length = desc->actual_length;
162 shm->captured_iso_head = head;
163 shm->captured_iso_frames++;
165 if ((desc->offset += desc->length * NRURBS*nr_of_packs()) +
166 desc->length >= SSS)
167 desc->offset -= (SSS - desc->length);
171 static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream *capsubs,
172 struct snd_usX2Y_substream *capsubs2,
173 struct snd_usX2Y_substream *playbacksubs,
174 int frame)
176 int err, state;
177 struct urb *urb = playbacksubs->completed_urb;
179 state = atomic_read(&playbacksubs->state);
180 if (NULL != urb) {
181 if (state == state_RUNNING)
182 usX2Y_urb_play_retire(playbacksubs, urb);
183 else if (state >= state_PRERUNNING)
184 atomic_inc(&playbacksubs->state);
185 } else {
186 switch (state) {
187 case state_STARTING1:
188 urb = playbacksubs->urb[0];
189 atomic_inc(&playbacksubs->state);
190 break;
191 case state_STARTING2:
192 urb = playbacksubs->urb[1];
193 atomic_inc(&playbacksubs->state);
194 break;
197 if (urb) {
198 if ((err = usX2Y_hwdep_urb_play_prepare(playbacksubs, urb)) ||
199 (err = usX2Y_urb_submit(playbacksubs, urb, frame))) {
200 return err;
204 playbacksubs->completed_urb = NULL;
206 state = atomic_read(&capsubs->state);
207 if (state >= state_PREPARED) {
208 if (state == state_RUNNING) {
209 if ((err = usX2Y_usbpcm_urb_capt_retire(capsubs)))
210 return err;
211 } else if (state >= state_PRERUNNING)
212 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)))
217 return err;
218 if (NULL != capsubs2)
219 if ((err = usX2Y_urb_submit(capsubs2, capsubs2->completed_urb, frame)))
220 return err;
222 capsubs->completed_urb = NULL;
223 if (NULL != capsubs2)
224 capsubs2->completed_urb = NULL;
225 return 0;
229 static void i_usX2Y_usbpcm_urb_complete(struct urb *urb, struct pt_regs *regs)
231 struct snd_usX2Y_substream *subs = urb->context;
232 struct usX2Ydev *usX2Y = subs->usX2Y;
233 struct snd_usX2Y_substream *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",
237 usb_get_current_frame_number(usX2Y->chip.dev),
238 subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
239 urb->status, urb->start_frame);
240 return;
242 if (unlikely(urb->status)) {
243 usX2Y_error_urb_status(usX2Y, subs, urb);
244 return;
246 if (likely((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame))
247 subs->completed_urb = urb;
248 else {
249 usX2Y_error_sequence(usX2Y, subs, urb);
250 return;
253 capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
254 capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
255 playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
256 if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
257 (NULL == capsubs2 || capsubs2->completed_urb) &&
258 (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
259 if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) {
260 if (nr_of_packs() <= urb->start_frame &&
261 urb->start_frame <= (2 * nr_of_packs() - 1)) // uhci and ohci
262 usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs();
263 else
264 usX2Y->wait_iso_frame += nr_of_packs();
265 } else {
266 snd_printdd("\n");
267 usX2Y_clients_stop(usX2Y);
273 static void usX2Y_hwdep_urb_release(struct urb **urb)
275 usb_kill_urb(*urb);
276 usb_free_urb(*urb);
277 *urb = NULL;
281 * release a substream
283 static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs)
285 int i;
286 snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
287 for (i = 0; i < NRURBS; i++)
288 usX2Y_hwdep_urb_release(subs->urb + i);
291 static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
293 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
294 usX2Y->prepare_subs = NULL;
297 static void i_usX2Y_usbpcm_subs_startup(struct urb *urb, struct pt_regs *regs)
299 struct snd_usX2Y_substream *subs = urb->context;
300 struct usX2Ydev *usX2Y = subs->usX2Y;
301 struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs;
302 if (NULL != prepare_subs &&
303 urb->start_frame == prepare_subs->urb[0]->start_frame) {
304 atomic_inc(&prepare_subs->state);
305 if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
306 struct snd_usX2Y_substream *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
307 if (cap_subs2 != NULL)
308 atomic_inc(&cap_subs2->state);
310 usX2Y_usbpcm_subs_startup_finish(usX2Y);
311 wake_up(&usX2Y->prepare_wait_queue);
314 i_usX2Y_usbpcm_urb_complete(urb, regs);
318 * initialize a substream's urbs
320 static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
322 int i;
323 unsigned int pipe;
324 int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
325 struct usb_device *dev = subs->usX2Y->chip.dev;
327 pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
328 usb_rcvisocpipe(dev, subs->endpoint);
329 subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
330 if (!subs->maxpacksize)
331 return -EINVAL;
333 /* allocate and initialize data urbs */
334 for (i = 0; i < NRURBS; i++) {
335 struct urb **purb = subs->urb + i;
336 if (*purb) {
337 usb_kill_urb(*purb);
338 continue;
340 *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
341 if (NULL == *purb) {
342 usX2Y_usbpcm_urbs_release(subs);
343 return -ENOMEM;
345 (*purb)->transfer_buffer = is_playback ?
346 subs->usX2Y->hwdep_pcm_shm->playback : (
347 subs->endpoint == 0x8 ?
348 subs->usX2Y->hwdep_pcm_shm->capture0x8 :
349 subs->usX2Y->hwdep_pcm_shm->capture0xA);
351 (*purb)->dev = dev;
352 (*purb)->pipe = pipe;
353 (*purb)->number_of_packets = nr_of_packs();
354 (*purb)->context = subs;
355 (*purb)->interval = 1;
356 (*purb)->complete = i_usX2Y_usbpcm_subs_startup;
358 return 0;
362 * free the buffer
364 static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
366 struct snd_pcm_runtime *runtime = substream->runtime;
367 struct snd_usX2Y_substream *subs = runtime->private_data,
368 *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
369 mutex_lock(&subs->usX2Y->prepare_mutex);
370 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
372 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
373 struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
374 atomic_set(&subs->state, state_STOPPED);
375 usX2Y_usbpcm_urbs_release(subs);
376 if (!cap_subs->pcm_substream ||
377 !cap_subs->pcm_substream->runtime ||
378 !cap_subs->pcm_substream->runtime->status ||
379 cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
380 atomic_set(&cap_subs->state, state_STOPPED);
381 if (NULL != cap_subs2)
382 atomic_set(&cap_subs2->state, state_STOPPED);
383 usX2Y_usbpcm_urbs_release(cap_subs);
384 if (NULL != cap_subs2)
385 usX2Y_usbpcm_urbs_release(cap_subs2);
387 } else {
388 struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
389 if (atomic_read(&playback_subs->state) < state_PREPARED) {
390 atomic_set(&subs->state, state_STOPPED);
391 if (NULL != cap_subs2)
392 atomic_set(&cap_subs2->state, state_STOPPED);
393 usX2Y_usbpcm_urbs_release(subs);
394 if (NULL != cap_subs2)
395 usX2Y_usbpcm_urbs_release(cap_subs2);
398 mutex_unlock(&subs->usX2Y->prepare_mutex);
399 return snd_pcm_lib_free_pages(substream);
402 static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
404 struct usX2Ydev * usX2Y = subs->usX2Y;
405 usX2Y->prepare_subs = subs;
406 subs->urb[0]->start_frame = -1;
407 smp_wmb(); // Make sure above modifications are seen by i_usX2Y_subs_startup()
408 usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
411 static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
413 int p, u, err,
414 stream = subs->pcm_substream->stream;
415 struct usX2Ydev *usX2Y = subs->usX2Y;
417 if (SNDRV_PCM_STREAM_CAPTURE == stream) {
418 usX2Y->hwdep_pcm_shm->captured_iso_head = -1;
419 usX2Y->hwdep_pcm_shm->captured_iso_frames = 0;
422 for (p = 0; 3 >= (stream + p); p += 2) {
423 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
424 if (subs != NULL) {
425 if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
426 return err;
427 subs->completed_urb = NULL;
431 for (p = 0; p < 4; p++) {
432 struct snd_usX2Y_substream *subs = usX2Y->subs[p];
433 if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
434 goto start;
436 usX2Y->wait_iso_frame = -1;
438 start:
439 usX2Y_usbpcm_subs_startup(subs);
440 for (u = 0; u < NRURBS; u++) {
441 for (p = 0; 3 >= (stream + p); p += 2) {
442 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
443 if (subs != NULL) {
444 struct urb *urb = subs->urb[u];
445 if (usb_pipein(urb->pipe)) {
446 unsigned long pack;
447 if (0 == u)
448 atomic_set(&subs->state, state_STARTING3);
449 urb->dev = usX2Y->chip.dev;
450 urb->transfer_flags = URB_ISO_ASAP;
451 for (pack = 0; pack < nr_of_packs(); pack++) {
452 urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
453 urb->iso_frame_desc[pack].length = subs->maxpacksize;
455 urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
456 if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
457 snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
458 err = -EPIPE;
459 goto cleanup;
460 } else {
461 snd_printdd("%i\n", urb->start_frame);
462 if (0 > usX2Y->wait_iso_frame)
463 usX2Y->wait_iso_frame = urb->start_frame;
465 urb->transfer_flags = 0;
466 } else {
467 atomic_set(&subs->state, state_STARTING1);
468 break;
473 err = 0;
474 wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
475 if (atomic_read(&subs->state) != state_PREPARED)
476 err = -EPIPE;
478 cleanup:
479 if (err) {
480 usX2Y_subs_startup_finish(usX2Y); // Call it now
481 usX2Y_clients_stop(usX2Y); // something is completely wroong > stop evrything
483 return err;
487 * prepare callback
489 * set format and initialize urbs
491 static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
493 struct snd_pcm_runtime *runtime = substream->runtime;
494 struct snd_usX2Y_substream *subs = runtime->private_data;
495 struct usX2Ydev *usX2Y = subs->usX2Y;
496 struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
497 int err = 0;
498 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
500 if (NULL == usX2Y->hwdep_pcm_shm) {
501 if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm), GFP_KERNEL)))
502 return -ENOMEM;
503 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
506 mutex_lock(&usX2Y->prepare_mutex);
507 usX2Y_subs_prepare(subs);
508 // Start hardware streams
509 // SyncStream first....
510 if (atomic_read(&capsubs->state) < state_PREPARED) {
511 if (usX2Y->format != runtime->format)
512 if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
513 goto up_prepare_mutex;
514 if (usX2Y->rate != runtime->rate)
515 if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
516 goto up_prepare_mutex;
517 snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
518 "self" : "playpipe");
519 if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs)))
520 goto up_prepare_mutex;
523 if (subs != capsubs) {
524 usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
525 if (atomic_read(&subs->state) < state_PREPARED) {
526 while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) >
527 usX2Y->hwdep_pcm_shm->captured_iso_frames) {
528 snd_printdd("Wait: iso_frames_per_buffer=%i,"
529 "captured_iso_frames=%i\n",
530 usX2Y_iso_frames_per_buffer(runtime, usX2Y),
531 usX2Y->hwdep_pcm_shm->captured_iso_frames);
532 if (msleep_interruptible(10)) {
533 err = -ERESTARTSYS;
534 goto up_prepare_mutex;
537 if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
538 goto up_prepare_mutex;
540 snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
541 usX2Y_iso_frames_per_buffer(runtime, usX2Y),
542 usX2Y->hwdep_pcm_shm->captured_iso_frames);
543 } else
544 usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
546 up_prepare_mutex:
547 mutex_unlock(&usX2Y->prepare_mutex);
548 return err;
551 static struct snd_pcm_hardware snd_usX2Y_4c =
553 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
554 SNDRV_PCM_INFO_BLOCK_TRANSFER |
555 SNDRV_PCM_INFO_MMAP_VALID),
556 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
557 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
558 .rate_min = 44100,
559 .rate_max = 48000,
560 .channels_min = 2,
561 .channels_max = 4,
562 .buffer_bytes_max = (2*128*1024),
563 .period_bytes_min = 64,
564 .period_bytes_max = (128*1024),
565 .periods_min = 2,
566 .periods_max = 1024,
567 .fifo_size = 0
572 static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
574 struct snd_usX2Y_substream *subs = ((struct snd_usX2Y_substream **)
575 snd_pcm_substream_chip(substream))[substream->stream];
576 struct snd_pcm_runtime *runtime = substream->runtime;
578 if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
579 return -EBUSY;
581 runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
582 (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
583 runtime->private_data = subs;
584 subs->pcm_substream = substream;
585 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
586 return 0;
590 static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
592 struct snd_pcm_runtime *runtime = substream->runtime;
593 struct snd_usX2Y_substream *subs = runtime->private_data;
595 subs->pcm_substream = NULL;
596 return 0;
600 static struct snd_pcm_ops snd_usX2Y_usbpcm_ops =
602 .open = snd_usX2Y_usbpcm_open,
603 .close = snd_usX2Y_usbpcm_close,
604 .ioctl = snd_pcm_lib_ioctl,
605 .hw_params = snd_usX2Y_pcm_hw_params,
606 .hw_free = snd_usX2Y_usbpcm_hw_free,
607 .prepare = snd_usX2Y_usbpcm_prepare,
608 .trigger = snd_usX2Y_pcm_trigger,
609 .pointer = snd_usX2Y_pcm_pointer,
613 static int usX2Y_pcms_lock_check(struct snd_card *card)
615 struct list_head *list;
616 struct snd_device *dev;
617 struct snd_pcm *pcm;
618 int err = 0;
619 list_for_each(list, &card->devices) {
620 dev = snd_device(list);
621 if (dev->type != SNDRV_DEV_PCM)
622 continue;
623 pcm = dev->device_data;
624 mutex_lock(&pcm->open_mutex);
626 list_for_each(list, &card->devices) {
627 int s;
628 dev = snd_device(list);
629 if (dev->type != SNDRV_DEV_PCM)
630 continue;
631 pcm = dev->device_data;
632 for (s = 0; s < 2; ++s) {
633 struct snd_pcm_substream *substream;
634 substream = pcm->streams[s].substream;
635 if (SUBSTREAM_BUSY(substream))
636 err = -EBUSY;
639 return err;
643 static void usX2Y_pcms_unlock(struct snd_card *card)
645 struct list_head *list;
646 struct snd_device *dev;
647 struct snd_pcm *pcm;
648 list_for_each(list, &card->devices) {
649 dev = snd_device(list);
650 if (dev->type != SNDRV_DEV_PCM)
651 continue;
652 pcm = dev->device_data;
653 mutex_unlock(&pcm->open_mutex);
658 static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
660 // we need to be the first
661 struct snd_card *card = hw->card;
662 int err = usX2Y_pcms_lock_check(card);
663 if (0 == err)
664 usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
665 usX2Y_pcms_unlock(card);
666 return err;
670 static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
672 struct snd_card *card = hw->card;
673 int err = usX2Y_pcms_lock_check(card);
674 if (0 == err)
675 usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
676 usX2Y_pcms_unlock(card);
677 return err;
681 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
686 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
691 static struct page * snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type)
693 unsigned long offset;
694 struct page *page;
695 void *vaddr;
697 offset = area->vm_pgoff << PAGE_SHIFT;
698 offset += address - area->vm_start;
699 snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM);
700 vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset;
701 page = virt_to_page(vaddr);
702 get_page(page);
704 if (type)
705 *type = VM_FAULT_MINOR;
707 return page;
711 static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
712 .open = snd_usX2Y_hwdep_pcm_vm_open,
713 .close = snd_usX2Y_hwdep_pcm_vm_close,
714 .nopage = snd_usX2Y_hwdep_pcm_vm_nopage,
718 static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
720 unsigned long size = (unsigned long)(area->vm_end - area->vm_start);
721 struct usX2Ydev *usX2Y = hw->private_data;
723 if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
724 return -EBUSY;
726 /* if userspace tries to mmap beyond end of our buffer, fail */
727 if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) {
728 snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm));
729 return -EINVAL;
732 if (!usX2Y->hwdep_pcm_shm) {
733 return -ENODEV;
735 area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
736 area->vm_flags |= VM_RESERVED;
737 area->vm_private_data = hw->private_data;
738 return 0;
742 static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
744 struct usX2Ydev *usX2Y = hwdep->private_data;
745 if (NULL != usX2Y->hwdep_pcm_shm)
746 snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
750 int usX2Y_hwdep_pcm_new(struct snd_card *card)
752 int err;
753 struct snd_hwdep *hw;
754 struct snd_pcm *pcm;
755 struct usb_device *dev = usX2Y(card)->chip.dev;
756 if (1 != nr_of_packs())
757 return 0;
759 if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
760 return err;
762 hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
763 hw->private_data = usX2Y(card);
764 hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
765 hw->ops.open = snd_usX2Y_hwdep_pcm_open;
766 hw->ops.release = snd_usX2Y_hwdep_pcm_release;
767 hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
768 hw->exclusive = 1;
769 sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
771 err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
772 if (err < 0) {
773 return err;
775 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
776 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
778 pcm->private_data = usX2Y(card)->subs;
779 pcm->info_flags = 0;
781 sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
782 if (0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
783 SNDRV_DMA_TYPE_CONTINUOUS,
784 snd_dma_continuous_data(GFP_KERNEL),
785 64*1024, 128*1024)) ||
786 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
787 SNDRV_DMA_TYPE_CONTINUOUS,
788 snd_dma_continuous_data(GFP_KERNEL),
789 64*1024, 128*1024))) {
790 return err;
794 return 0;
797 #else
799 int usX2Y_hwdep_pcm_new(struct snd_card *card)
801 return 0;
804 #endif