📄 caiaq-audio.c
字号:
const struct urb *urb, const struct usb_iso_packet_descriptor *iso){ unsigned char *usb_buf = urb->transfer_buffer + iso->offset; unsigned char check_byte; struct snd_pcm_substream *sub; int stream, i; spin_lock(&dev->spinlock); for (i = 0; i < iso->actual_length;) { if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) { for (stream = 0; stream < dev->n_streams; stream++, i++) { if (dev->first_packet) continue; check_byte = MAKE_CHECKBYTE(dev, stream, i); if ((usb_buf[i] & 0x3f) != check_byte) dev->input_panic = 1; if (usb_buf[i] & 0x80) dev->output_panic = 1; } } dev->first_packet = 0; for (stream = 0; stream < dev->n_streams; stream++, i++) { sub = dev->sub_capture[stream]; if (sub) { struct snd_pcm_runtime *rt = sub->runtime; char *audio_buf = rt->dma_area; int sz = frames_to_bytes(rt, rt->buffer_size); audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i]; dev->period_in_count[stream]++; if (dev->audio_in_buf_pos[stream] == sz) dev->audio_in_buf_pos[stream] = 0; } } } spin_unlock(&dev->spinlock);}static void read_in_urb(struct snd_usb_caiaqdev *dev, const struct urb *urb, const struct usb_iso_packet_descriptor *iso){ if (!dev->streaming) return; switch (dev->spec.data_alignment) { case 0: read_in_urb_mode0(dev, urb, iso); break; case 2: read_in_urb_mode2(dev, urb, iso); break; } if (dev->input_panic || dev->output_panic) { debug("streaming error detected %s %s\n", dev->input_panic ? "(input)" : "", dev->output_panic ? "(output)" : ""); } check_for_elapsed_periods(dev, dev->sub_capture);}static void fill_out_urb(struct snd_usb_caiaqdev *dev, struct urb *urb, const struct usb_iso_packet_descriptor *iso){ unsigned char *usb_buf = urb->transfer_buffer + iso->offset; struct snd_pcm_substream *sub; int stream, i; spin_lock(&dev->spinlock); for (i = 0; i < iso->length;) { for (stream = 0; stream < dev->n_streams; stream++, i++) { sub = dev->sub_playback[stream]; if (sub) { struct snd_pcm_runtime *rt = sub->runtime; char *audio_buf = rt->dma_area; int sz = frames_to_bytes(rt, rt->buffer_size); usb_buf[i] = audio_buf[dev->audio_out_buf_pos[stream]]; dev->period_out_count[stream]++; dev->audio_out_buf_pos[stream]++; if (dev->audio_out_buf_pos[stream] == sz) dev->audio_out_buf_pos[stream] = 0; } else usb_buf[i] = 0; } /* fill in the check bytes */ if (dev->spec.data_alignment == 2 && i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == (dev->n_streams * CHANNELS_PER_STREAM)) for (stream = 0; stream < dev->n_streams; stream++, i++) usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); } spin_unlock(&dev->spinlock); check_for_elapsed_periods(dev, dev->sub_playback);}static void read_completed(struct urb *urb){ struct snd_usb_caiaq_cb_info *info = urb->context; struct snd_usb_caiaqdev *dev; struct urb *out; int frame, len, send_it = 0, outframe = 0; if (urb->status || !info) return; dev = info->dev; if (!dev->streaming) return; out = dev->data_urbs_out[info->index]; /* read the recently received packet and send back one which has * the same layout */ for (frame = 0; frame < FRAMES_PER_URB; frame++) { if (urb->iso_frame_desc[frame].status) continue; len = urb->iso_frame_desc[outframe].actual_length; out->iso_frame_desc[outframe].length = len; out->iso_frame_desc[outframe].actual_length = 0; out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame; if (len > 0) { fill_out_urb(dev, out, &out->iso_frame_desc[outframe]); read_in_urb(dev, urb, &urb->iso_frame_desc[frame]); send_it = 1; } outframe++; } if (send_it) { out->number_of_packets = FRAMES_PER_URB; out->transfer_flags = URB_ISO_ASAP; usb_submit_urb(out, GFP_ATOMIC); } /* re-submit inbound urb */ for (frame = 0; frame < FRAMES_PER_URB; frame++) { urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; urb->iso_frame_desc[frame].length = BYTES_PER_FRAME; urb->iso_frame_desc[frame].actual_length = 0; } urb->number_of_packets = FRAMES_PER_URB; urb->transfer_flags = URB_ISO_ASAP; usb_submit_urb(urb, GFP_ATOMIC);}static void write_completed(struct urb *urb){ struct snd_usb_caiaq_cb_info *info = urb->context; struct snd_usb_caiaqdev *dev = info->dev; if (!dev->output_running) { dev->output_running = 1; wake_up(&dev->prepare_wait_queue); }}static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret){ int i, frame; struct urb **urbs; struct usb_device *usb_dev = dev->chip.dev; unsigned int pipe; pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? usb_sndisocpipe(usb_dev, ENDPOINT_PLAYBACK) : usb_rcvisocpipe(usb_dev, ENDPOINT_CAPTURE); urbs = kmalloc(N_URBS * sizeof(*urbs), GFP_KERNEL); if (!urbs) { log("unable to kmalloc() urbs, OOM!?\n"); *ret = -ENOMEM; return NULL; } for (i = 0; i < N_URBS; i++) { urbs[i] = usb_alloc_urb(FRAMES_PER_URB, GFP_KERNEL); if (!urbs[i]) { log("unable to usb_alloc_urb(), OOM!?\n"); *ret = -ENOMEM; return urbs; } urbs[i]->transfer_buffer = kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL); if (!urbs[i]->transfer_buffer) { log("unable to kmalloc() transfer buffer, OOM!?\n"); *ret = -ENOMEM; return urbs; } for (frame = 0; frame < FRAMES_PER_URB; frame++) { struct usb_iso_packet_descriptor *iso = &urbs[i]->iso_frame_desc[frame]; iso->offset = BYTES_PER_FRAME * frame; iso->length = BYTES_PER_FRAME; } urbs[i]->dev = usb_dev; urbs[i]->pipe = pipe; urbs[i]->transfer_buffer_length = FRAMES_PER_URB * BYTES_PER_FRAME; urbs[i]->context = &dev->data_cb_info[i]; urbs[i]->interval = 1; urbs[i]->transfer_flags = URB_ISO_ASAP; urbs[i]->number_of_packets = FRAMES_PER_URB; urbs[i]->complete = (dir == SNDRV_PCM_STREAM_CAPTURE) ? read_completed : write_completed; } *ret = 0; return urbs;}static void free_urbs(struct urb **urbs){ int i; if (!urbs) return; for (i = 0; i < N_URBS; i++) { if (!urbs[i]) continue; usb_kill_urb(urbs[i]); kfree(urbs[i]->transfer_buffer); usb_free_urb(urbs[i]); } kfree(urbs);}int __devinit snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev){ int i, ret; dev->n_audio_in = max(dev->spec.num_analog_audio_in, dev->spec.num_digital_audio_in) / CHANNELS_PER_STREAM; dev->n_audio_out = max(dev->spec.num_analog_audio_out, dev->spec.num_digital_audio_out) / CHANNELS_PER_STREAM; dev->n_streams = max(dev->n_audio_in, dev->n_audio_out); debug("dev->n_audio_in = %d\n", dev->n_audio_in); debug("dev->n_audio_out = %d\n", dev->n_audio_out); debug("dev->n_streams = %d\n", dev->n_streams); if (dev->n_streams > MAX_STREAMS) { log("unable to initialize device, too many streams.\n"); return -EINVAL; } ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, dev->n_audio_out, dev->n_audio_in, &dev->pcm); if (ret < 0) { log("snd_pcm_new() returned %d\n", ret); return ret; } dev->pcm->private_data = dev; strcpy(dev->pcm->name, dev->product_name); memset(dev->sub_playback, 0, sizeof(dev->sub_playback)); memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware, sizeof(snd_usb_caiaq_pcm_hardware)); /* setup samplerates */ dev->samplerates = dev->pcm_info.rates; switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): dev->samplerates |= SNDRV_PCM_RATE_88200; dev->samplerates |= SNDRV_PCM_RATE_192000; break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): dev->samplerates |= SNDRV_PCM_RATE_88200; break; } snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_caiaq_ops); snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_caiaq_ops); snd_pcm_lib_preallocate_pages_for_all(dev->pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), MAX_BUFFER_SIZE, MAX_BUFFER_SIZE); dev->data_cb_info = kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, GFP_KERNEL); if (!dev->data_cb_info) return -ENOMEM; for (i = 0; i < N_URBS; i++) { dev->data_cb_info[i].dev = dev; dev->data_cb_info[i].index = i; } dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret); if (ret < 0) { kfree(dev->data_cb_info); free_urbs(dev->data_urbs_in); return ret; } dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret); if (ret < 0) { kfree(dev->data_cb_info); free_urbs(dev->data_urbs_in); free_urbs(dev->data_urbs_out); return ret; } return 0;}void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev){ debug("snd_usb_caiaq_audio_free (%p)\n", dev); stream_stop(dev); free_urbs(dev->data_urbs_in); free_urbs(dev->data_urbs_out); kfree(dev->data_cb_info);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -