295 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Line 6 Linux USB driver4 *5 * Copyright (C) 2004-2010 Markus Grabner (line6@grabner-graz.at)6 */7 8#include <linux/slab.h>9#include <sound/core.h>10#include <sound/pcm.h>11#include <sound/pcm_params.h>12 13#include "capture.h"14#include "driver.h"15#include "pcm.h"16 17/*18 Find a free URB and submit it.19 must be called in line6pcm->in.lock context20*/21static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)22{23 int index;24 int i, urb_size;25 int ret;26 struct urb *urb_in;27 28 index = find_first_zero_bit(&line6pcm->in.active_urbs,29 line6pcm->line6->iso_buffers);30 31 if (index < 0 || index >= line6pcm->line6->iso_buffers) {32 dev_err(line6pcm->line6->ifcdev, "no free URB found\n");33 return -EINVAL;34 }35 36 urb_in = line6pcm->in.urbs[index];37 urb_size = 0;38 39 for (i = 0; i < LINE6_ISO_PACKETS; ++i) {40 struct usb_iso_packet_descriptor *fin =41 &urb_in->iso_frame_desc[i];42 fin->offset = urb_size;43 fin->length = line6pcm->max_packet_size_in;44 urb_size += line6pcm->max_packet_size_in;45 }46 47 urb_in->transfer_buffer =48 line6pcm->in.buffer +49 index * LINE6_ISO_PACKETS * line6pcm->max_packet_size_in;50 urb_in->transfer_buffer_length = urb_size;51 urb_in->context = line6pcm;52 53 ret = usb_submit_urb(urb_in, GFP_ATOMIC);54 55 if (ret == 0)56 set_bit(index, &line6pcm->in.active_urbs);57 else58 dev_err(line6pcm->line6->ifcdev,59 "URB in #%d submission failed (%d)\n", index, ret);60 61 return 0;62}63 64/*65 Submit all currently available capture URBs.66 must be called in line6pcm->in.lock context67*/68int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)69{70 int ret = 0, i;71 72 for (i = 0; i < line6pcm->line6->iso_buffers; ++i) {73 ret = submit_audio_in_urb(line6pcm);74 if (ret < 0)75 break;76 }77 78 return ret;79}80 81/*82 Copy data into ALSA capture buffer.83*/84void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)85{86 struct snd_pcm_substream *substream =87 get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);88 struct snd_pcm_runtime *runtime = substream->runtime;89 const int bytes_per_frame =90 line6pcm->properties->bytes_per_channel *91 line6pcm->properties->capture_hw.channels_max;92 int frames = fsize / bytes_per_frame;93 94 if (runtime == NULL)95 return;96 97 if (line6pcm->in.pos_done + frames > runtime->buffer_size) {98 /*99 The transferred area goes over buffer boundary,100 copy two separate chunks.101 */102 int len;103 104 len = runtime->buffer_size - line6pcm->in.pos_done;105 106 if (len > 0) {107 memcpy(runtime->dma_area +108 line6pcm->in.pos_done * bytes_per_frame, fbuf,109 len * bytes_per_frame);110 memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,111 (frames - len) * bytes_per_frame);112 } else {113 /* this is somewhat paranoid */114 dev_err(line6pcm->line6->ifcdev,115 "driver bug: len = %d\n", len);116 }117 } else {118 /* copy single chunk */119 memcpy(runtime->dma_area +120 line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize);121 }122 123 line6pcm->in.pos_done += frames;124 if (line6pcm->in.pos_done >= runtime->buffer_size)125 line6pcm->in.pos_done -= runtime->buffer_size;126}127 128void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)129{130 struct snd_pcm_substream *substream =131 get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);132 133 line6pcm->in.bytes += length;134 if (line6pcm->in.bytes >= line6pcm->in.period) {135 line6pcm->in.bytes %= line6pcm->in.period;136 spin_unlock(&line6pcm->in.lock);137 snd_pcm_period_elapsed(substream);138 spin_lock(&line6pcm->in.lock);139 }140}141 142/*143 * Callback for completed capture URB.144 */145static void audio_in_callback(struct urb *urb)146{147 int i, index, length = 0, shutdown = 0;148 unsigned long flags;149 150 struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;151 152 line6pcm->in.last_frame = urb->start_frame;153 154 /* find index of URB */155 for (index = 0; index < line6pcm->line6->iso_buffers; ++index)156 if (urb == line6pcm->in.urbs[index])157 break;158 159 spin_lock_irqsave(&line6pcm->in.lock, flags);160 161 for (i = 0; i < LINE6_ISO_PACKETS; ++i) {162 char *fbuf;163 int fsize;164 struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];165 166 if (fin->status == -EXDEV) {167 shutdown = 1;168 break;169 }170 171 fbuf = urb->transfer_buffer + fin->offset;172 fsize = fin->actual_length;173 174 if (fsize > line6pcm->max_packet_size_in) {175 dev_err(line6pcm->line6->ifcdev,176 "driver and/or device bug: packet too large (%d > %d)\n",177 fsize, line6pcm->max_packet_size_in);178 }179 180 length += fsize;181 182 BUILD_BUG_ON_MSG(LINE6_ISO_PACKETS != 1,183 "The following code assumes LINE6_ISO_PACKETS == 1");184 /* TODO:185 * Also, if iso_buffers != 2, the prev frame is almost random at186 * playback side.187 * This needs to be redesigned. It should be "stable", but we may188 * experience sync problems on such high-speed configs.189 */190 191 line6pcm->prev_fbuf = fbuf;192 line6pcm->prev_fsize = fsize /193 (line6pcm->properties->bytes_per_channel *194 line6pcm->properties->capture_hw.channels_max);195 196 if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&197 test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) &&198 fsize > 0)199 line6_capture_copy(line6pcm, fbuf, fsize);200 }201 202 clear_bit(index, &line6pcm->in.active_urbs);203 204 if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs))205 shutdown = 1;206 207 if (!shutdown) {208 submit_audio_in_urb(line6pcm);209 210 if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&211 test_bit(LINE6_STREAM_PCM, &line6pcm->in.running))212 line6_capture_check_period(line6pcm, length);213 }214 215 spin_unlock_irqrestore(&line6pcm->in.lock, flags);216}217 218/* open capture callback */219static int snd_line6_capture_open(struct snd_pcm_substream *substream)220{221 int err;222 struct snd_pcm_runtime *runtime = substream->runtime;223 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);224 225 err = snd_pcm_hw_constraint_ratdens(runtime, 0,226 SNDRV_PCM_HW_PARAM_RATE,227 &line6pcm->properties->rates);228 if (err < 0)229 return err;230 231 line6_pcm_acquire(line6pcm, LINE6_STREAM_CAPTURE_HELPER, false);232 233 runtime->hw = line6pcm->properties->capture_hw;234 return 0;235}236 237/* close capture callback */238static int snd_line6_capture_close(struct snd_pcm_substream *substream)239{240 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);241 242 line6_pcm_release(line6pcm, LINE6_STREAM_CAPTURE_HELPER);243 return 0;244}245 246/* capture operators */247const struct snd_pcm_ops snd_line6_capture_ops = {248 .open = snd_line6_capture_open,249 .close = snd_line6_capture_close,250 .hw_params = snd_line6_hw_params,251 .hw_free = snd_line6_hw_free,252 .prepare = snd_line6_prepare,253 .trigger = snd_line6_trigger,254 .pointer = snd_line6_pointer,255};256 257int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)258{259 struct usb_line6 *line6 = line6pcm->line6;260 int i;261 262 line6pcm->in.urbs = kcalloc(line6->iso_buffers, sizeof(struct urb *),263 GFP_KERNEL);264 if (line6pcm->in.urbs == NULL)265 return -ENOMEM;266 267 /* create audio URBs and fill in constant values: */268 for (i = 0; i < line6->iso_buffers; ++i) {269 struct urb *urb;270 271 /* URB for audio in: */272 urb = line6pcm->in.urbs[i] =273 usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);274 275 if (urb == NULL)276 return -ENOMEM;277 278 urb->dev = line6->usbdev;279 urb->pipe =280 usb_rcvisocpipe(line6->usbdev,281 line6->properties->ep_audio_r &282 USB_ENDPOINT_NUMBER_MASK);283 urb->transfer_flags = URB_ISO_ASAP;284 urb->start_frame = -1;285 urb->number_of_packets = LINE6_ISO_PACKETS;286 urb->interval = LINE6_ISO_INTERVAL;287 urb->error_count = 0;288 urb->complete = audio_in_callback;289 if (usb_urb_ep_type_check(urb))290 return -EINVAL;291 }292 293 return 0;294}295