diff options
Diffstat (limited to 'sound/usb/caiaq/audio.c')
-rw-r--r-- | sound/usb/caiaq/audio.c | 175 |
1 files changed, 160 insertions, 15 deletions
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 4328cad6c3a2..68b97477577b 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c | |||
@@ -111,7 +111,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev) | |||
111 | memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); | 111 | memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); |
112 | dev->input_panic = 0; | 112 | dev->input_panic = 0; |
113 | dev->output_panic = 0; | 113 | dev->output_panic = 0; |
114 | dev->first_packet = 1; | 114 | dev->first_packet = 4; |
115 | dev->streaming = 1; | 115 | dev->streaming = 1; |
116 | dev->warned = 0; | 116 | dev->warned = 0; |
117 | 117 | ||
@@ -169,7 +169,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) | |||
169 | } | 169 | } |
170 | 170 | ||
171 | static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, | 171 | static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, |
172 | struct snd_pcm_hw_params *hw_params) | 172 | struct snd_pcm_hw_params *hw_params) |
173 | { | 173 | { |
174 | debug("%s(%p)\n", __func__, sub); | 174 | debug("%s(%p)\n", __func__, sub); |
175 | return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); | 175 | return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); |
@@ -189,7 +189,7 @@ static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) | |||
189 | #endif | 189 | #endif |
190 | 190 | ||
191 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, | 191 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, |
192 | 48000, 64000, 88200, 96000, 176400, 192000 }; | 192 | 48000, 64000, 88200, 96000, 176400, 192000 }; |
193 | 193 | ||
194 | static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | 194 | static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) |
195 | { | 195 | { |
@@ -201,12 +201,39 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | |||
201 | debug("%s(%p)\n", __func__, substream); | 201 | debug("%s(%p)\n", __func__, substream); |
202 | 202 | ||
203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
204 | dev->period_out_count[index] = BYTES_PER_SAMPLE + 1; | 204 | int out_pos; |
205 | dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; | 205 | |
206 | switch (dev->spec.data_alignment) { | ||
207 | case 0: | ||
208 | case 2: | ||
209 | out_pos = BYTES_PER_SAMPLE + 1; | ||
210 | break; | ||
211 | case 3: | ||
212 | default: | ||
213 | out_pos = 0; | ||
214 | break; | ||
215 | } | ||
216 | |||
217 | dev->period_out_count[index] = out_pos; | ||
218 | dev->audio_out_buf_pos[index] = out_pos; | ||
206 | } else { | 219 | } else { |
207 | int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2; | 220 | int in_pos; |
208 | dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos; | 221 | |
209 | dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos; | 222 | switch (dev->spec.data_alignment) { |
223 | case 0: | ||
224 | in_pos = BYTES_PER_SAMPLE + 2; | ||
225 | break; | ||
226 | case 2: | ||
227 | in_pos = BYTES_PER_SAMPLE; | ||
228 | break; | ||
229 | case 3: | ||
230 | default: | ||
231 | in_pos = 0; | ||
232 | break; | ||
233 | } | ||
234 | |||
235 | dev->period_in_count[index] = in_pos; | ||
236 | dev->audio_in_buf_pos[index] = in_pos; | ||
210 | } | 237 | } |
211 | 238 | ||
212 | if (dev->streaming) | 239 | if (dev->streaming) |
@@ -221,7 +248,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | |||
221 | snd_pcm_limit_hw_rates(runtime); | 248 | snd_pcm_limit_hw_rates(runtime); |
222 | 249 | ||
223 | bytes_per_sample = BYTES_PER_SAMPLE; | 250 | bytes_per_sample = BYTES_PER_SAMPLE; |
224 | if (dev->spec.data_alignment == 2) | 251 | if (dev->spec.data_alignment >= 2) |
225 | bytes_per_sample++; | 252 | bytes_per_sample++; |
226 | 253 | ||
227 | bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) | 254 | bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) |
@@ -253,6 +280,8 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd) | |||
253 | { | 280 | { |
254 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); | 281 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); |
255 | 282 | ||
283 | debug("%s(%p) cmd %d\n", __func__, sub, cmd); | ||
284 | |||
256 | switch (cmd) { | 285 | switch (cmd) { |
257 | case SNDRV_PCM_TRIGGER_START: | 286 | case SNDRV_PCM_TRIGGER_START: |
258 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 287 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
@@ -402,6 +431,61 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, | |||
402 | } | 431 | } |
403 | } | 432 | } |
404 | 433 | ||
434 | static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev, | ||
435 | const struct urb *urb, | ||
436 | const struct usb_iso_packet_descriptor *iso) | ||
437 | { | ||
438 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | ||
439 | int stream, i; | ||
440 | |||
441 | /* paranoia check */ | ||
442 | if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM)) | ||
443 | return; | ||
444 | |||
445 | for (i = 0; i < iso->actual_length;) { | ||
446 | for (stream = 0; stream < dev->n_streams; stream++) { | ||
447 | struct snd_pcm_substream *sub = dev->sub_capture[stream]; | ||
448 | char *audio_buf = NULL; | ||
449 | int c, n, sz = 0; | ||
450 | |||
451 | if (sub && !dev->input_panic) { | ||
452 | struct snd_pcm_runtime *rt = sub->runtime; | ||
453 | audio_buf = rt->dma_area; | ||
454 | sz = frames_to_bytes(rt, rt->buffer_size); | ||
455 | } | ||
456 | |||
457 | for (c = 0; c < CHANNELS_PER_STREAM; c++) { | ||
458 | /* 3 audio data bytes, followed by 1 check byte */ | ||
459 | if (audio_buf) { | ||
460 | for (n = 0; n < BYTES_PER_SAMPLE; n++) { | ||
461 | audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n]; | ||
462 | |||
463 | if (dev->audio_in_buf_pos[stream] == sz) | ||
464 | dev->audio_in_buf_pos[stream] = 0; | ||
465 | } | ||
466 | |||
467 | dev->period_in_count[stream] += BYTES_PER_SAMPLE; | ||
468 | } | ||
469 | |||
470 | i += BYTES_PER_SAMPLE; | ||
471 | |||
472 | if (usb_buf[i] != ((stream << 1) | c) && | ||
473 | !dev->first_packet) { | ||
474 | if (!dev->input_panic) | ||
475 | printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n", | ||
476 | ((stream << 1) | c), usb_buf[i], c, stream, i); | ||
477 | dev->input_panic = 1; | ||
478 | } | ||
479 | |||
480 | i++; | ||
481 | } | ||
482 | } | ||
483 | } | ||
484 | |||
485 | if (dev->first_packet > 0) | ||
486 | dev->first_packet--; | ||
487 | } | ||
488 | |||
405 | static void read_in_urb(struct snd_usb_caiaqdev *dev, | 489 | static void read_in_urb(struct snd_usb_caiaqdev *dev, |
406 | const struct urb *urb, | 490 | const struct urb *urb, |
407 | const struct usb_iso_packet_descriptor *iso) | 491 | const struct usb_iso_packet_descriptor *iso) |
@@ -419,6 +503,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, | |||
419 | case 2: | 503 | case 2: |
420 | read_in_urb_mode2(dev, urb, iso); | 504 | read_in_urb_mode2(dev, urb, iso); |
421 | break; | 505 | break; |
506 | case 3: | ||
507 | read_in_urb_mode3(dev, urb, iso); | ||
508 | break; | ||
422 | } | 509 | } |
423 | 510 | ||
424 | if ((dev->input_panic || dev->output_panic) && !dev->warned) { | 511 | if ((dev->input_panic || dev->output_panic) && !dev->warned) { |
@@ -429,9 +516,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, | |||
429 | } | 516 | } |
430 | } | 517 | } |
431 | 518 | ||
432 | static void fill_out_urb(struct snd_usb_caiaqdev *dev, | 519 | static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev, |
433 | struct urb *urb, | 520 | struct urb *urb, |
434 | const struct usb_iso_packet_descriptor *iso) | 521 | const struct usb_iso_packet_descriptor *iso) |
435 | { | 522 | { |
436 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 523 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; |
437 | struct snd_pcm_substream *sub; | 524 | struct snd_pcm_substream *sub; |
@@ -457,9 +544,67 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev, | |||
457 | /* fill in the check bytes */ | 544 | /* fill in the check bytes */ |
458 | if (dev->spec.data_alignment == 2 && | 545 | if (dev->spec.data_alignment == 2 && |
459 | i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == | 546 | i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == |
460 | (dev->n_streams * CHANNELS_PER_STREAM)) | 547 | (dev->n_streams * CHANNELS_PER_STREAM)) |
461 | for (stream = 0; stream < dev->n_streams; stream++, i++) | 548 | for (stream = 0; stream < dev->n_streams; stream++, i++) |
462 | usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); | 549 | usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); |
550 | } | ||
551 | } | ||
552 | |||
553 | static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev, | ||
554 | struct urb *urb, | ||
555 | const struct usb_iso_packet_descriptor *iso) | ||
556 | { | ||
557 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | ||
558 | int stream, i; | ||
559 | |||
560 | for (i = 0; i < iso->length;) { | ||
561 | for (stream = 0; stream < dev->n_streams; stream++) { | ||
562 | struct snd_pcm_substream *sub = dev->sub_playback[stream]; | ||
563 | char *audio_buf = NULL; | ||
564 | int c, n, sz = 0; | ||
565 | |||
566 | if (sub) { | ||
567 | struct snd_pcm_runtime *rt = sub->runtime; | ||
568 | audio_buf = rt->dma_area; | ||
569 | sz = frames_to_bytes(rt, rt->buffer_size); | ||
570 | } | ||
571 | |||
572 | for (c = 0; c < CHANNELS_PER_STREAM; c++) { | ||
573 | for (n = 0; n < BYTES_PER_SAMPLE; n++) { | ||
574 | if (audio_buf) { | ||
575 | usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++]; | ||
576 | |||
577 | if (dev->audio_out_buf_pos[stream] == sz) | ||
578 | dev->audio_out_buf_pos[stream] = 0; | ||
579 | } else { | ||
580 | usb_buf[i+n] = 0; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | if (audio_buf) | ||
585 | dev->period_out_count[stream] += BYTES_PER_SAMPLE; | ||
586 | |||
587 | i += BYTES_PER_SAMPLE; | ||
588 | |||
589 | /* fill in the check byte pattern */ | ||
590 | usb_buf[i++] = (stream << 1) | c; | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | } | ||
595 | |||
596 | static inline void fill_out_urb(struct snd_usb_caiaqdev *dev, | ||
597 | struct urb *urb, | ||
598 | const struct usb_iso_packet_descriptor *iso) | ||
599 | { | ||
600 | switch (dev->spec.data_alignment) { | ||
601 | case 0: | ||
602 | case 2: | ||
603 | fill_out_urb_mode_0(dev, urb, iso); | ||
604 | break; | ||
605 | case 3: | ||
606 | fill_out_urb_mode_3(dev, urb, iso); | ||
607 | break; | ||
463 | } | 608 | } |
464 | } | 609 | } |
465 | 610 | ||