capture.c (7579B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Line 6 Linux USB driver 4 * 5 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.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 context 20*/ 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 else 58 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 context 67*/ 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 at 186 * playback side. 187 * This needs to be redesigned. It should be "stable", but we may 188 * 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}