Merge tag 'cpufreq-arm-updates-6.3' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / sound / usb / line6 / capture.c
CommitLineData
a10e763b 1// SPDX-License-Identifier: GPL-2.0-only
705ececd 2/*
c078a4aa 3 * Line 6 Linux USB driver
705ececd 4 *
1027f476 5 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
705ececd
MG
6 */
7
140e28b8 8#include <linux/slab.h>
705ececd
MG
9#include <sound/core.h>
10#include <sound/pcm.h>
11#include <sound/pcm_params.h>
12
1027f476
MG
13#include "capture.h"
14#include "driver.h"
705ececd 15#include "pcm.h"
1027f476 16
705ececd
MG
17/*
18 Find a free URB and submit it.
3d3ae445 19 must be called in line6pcm->in.lock context
705ececd 20*/
1027f476 21static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
705ececd 22{
1027f476 23 int index;
705ececd 24 int i, urb_size;
e1a164d7 25 int ret;
705ececd
MG
26 struct urb *urb_in;
27
b2233d97
AK
28 index = find_first_zero_bit(&line6pcm->in.active_urbs,
29 line6pcm->line6->iso_buffers);
705ececd 30
b2233d97 31 if (index < 0 || index >= line6pcm->line6->iso_buffers) {
1027f476 32 dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
705ececd
MG
33 return -EINVAL;
34 }
35
ad0119ab 36 urb_in = line6pcm->in.urbs[index];
705ececd
MG
37 urb_size = 0;
38
6efc5667 39 for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
e0645d63
SB
40 struct usb_iso_packet_descriptor *fin =
41 &urb_in->iso_frame_desc[i];
705ececd 42 fin->offset = urb_size;
7a0f55ae
AK
43 fin->length = line6pcm->max_packet_size_in;
44 urb_size += line6pcm->max_packet_size_in;
705ececd
MG
45 }
46
e0645d63 47 urb_in->transfer_buffer =
ad0119ab 48 line6pcm->in.buffer +
7a0f55ae 49 index * LINE6_ISO_PACKETS * line6pcm->max_packet_size_in;
705ececd 50 urb_in->transfer_buffer_length = urb_size;
1027f476 51 urb_in->context = line6pcm;
705ececd 52
e1a164d7
MG
53 ret = usb_submit_urb(urb_in, GFP_ATOMIC);
54
55 if (ret == 0)
ad0119ab 56 set_bit(index, &line6pcm->in.active_urbs);
705ececd 57 else
1027f476 58 dev_err(line6pcm->line6->ifcdev,
e1a164d7 59 "URB in #%d submission failed (%d)\n", index, ret);
705ececd 60
705ececd
MG
61 return 0;
62}
63
64/*
65 Submit all currently available capture URBs.
63e20df1 66 must be called in line6pcm->in.lock context
705ececd 67*/
1027f476 68int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
705ececd 69{
3d3ae445 70 int ret = 0, i;
705ececd 71
b2233d97 72 for (i = 0; i < line6pcm->line6->iso_buffers; ++i) {
1027f476 73 ret = submit_audio_in_urb(line6pcm);
6efc5667 74 if (ret < 0)
3d3ae445 75 break;
6efc5667 76 }
705ececd 77
3d3ae445 78 return ret;
705ececd
MG
79}
80
705ececd 81/*
1027f476
MG
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;
97d78acf
AK
89 const int bytes_per_frame =
90 line6pcm->properties->bytes_per_channel *
91 line6pcm->properties->capture_hw.channels_max;
1027f476
MG
92 int frames = fsize / bytes_per_frame;
93
597a1e7c 94 if (runtime == NULL)
c7fcf255
MG
95 return;
96
ad0119ab 97 if (line6pcm->in.pos_done + frames > runtime->buffer_size) {
1027f476 98 /*
e1a164d7
MG
99 The transferred area goes over buffer boundary,
100 copy two separate chunks.
101 */
1027f476 102 int len;
b5f87cf9 103
ad0119ab 104 len = runtime->buffer_size - line6pcm->in.pos_done;
1027f476
MG
105
106 if (len > 0) {
107 memcpy(runtime->dma_area +
ad0119ab 108 line6pcm->in.pos_done * bytes_per_frame, fbuf,
1027f476
MG
109 len * bytes_per_frame);
110 memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
111 (frames - len) * bytes_per_frame);
027360c5
GKH
112 } else {
113 /* this is somewhat paranoid */
114 dev_err(line6pcm->line6->ifcdev,
115 "driver bug: len = %d\n", len);
116 }
1027f476
MG
117 } else {
118 /* copy single chunk */
119 memcpy(runtime->dma_area +
ad0119ab 120 line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize);
1027f476
MG
121 }
122
ad0119ab
TI
123 line6pcm->in.pos_done += frames;
124 if (line6pcm->in.pos_done >= runtime->buffer_size)
125 line6pcm->in.pos_done -= runtime->buffer_size;
1027f476
MG
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
ad0119ab
TI
133 line6pcm->in.bytes += length;
134 if (line6pcm->in.bytes >= line6pcm->in.period) {
135 line6pcm->in.bytes %= line6pcm->in.period;
3d3ae445 136 spin_unlock(&line6pcm->in.lock);
1027f476 137 snd_pcm_period_elapsed(substream);
3d3ae445 138 spin_lock(&line6pcm->in.lock);
1027f476
MG
139 }
140}
141
142/*
027360c5
GKH
143 * Callback for completed capture URB.
144 */
0c7ab158 145static void audio_in_callback(struct urb *urb)
705ececd
MG
146{
147 int i, index, length = 0, shutdown = 0;
705ececd
MG
148 unsigned long flags;
149
1027f476
MG
150 struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
151
ad0119ab 152 line6pcm->in.last_frame = urb->start_frame;
705ececd
MG
153
154 /* find index of URB */
b2233d97 155 for (index = 0; index < line6pcm->line6->iso_buffers; ++index)
ad0119ab 156 if (urb == line6pcm->in.urbs[index])
705ececd
MG
157 break;
158
ad0119ab 159 spin_lock_irqsave(&line6pcm->in.lock, flags);
705ececd 160
6efc5667 161 for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
705ececd
MG
162 char *fbuf;
163 int fsize;
164 struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
165
e1a164d7 166 if (fin->status == -EXDEV) {
705ececd
MG
167 shutdown = 1;
168 break;
169 }
170
171 fbuf = urb->transfer_buffer + fin->offset;
172 fsize = fin->actual_length;
1027f476 173
7a0f55ae 174 if (fsize > line6pcm->max_packet_size_in) {
1027f476
MG
175 dev_err(line6pcm->line6->ifcdev,
176 "driver and/or device bug: packet too large (%d > %d)\n",
7a0f55ae 177 fsize, line6pcm->max_packet_size_in);
1027f476
MG
178 }
179
705ececd
MG
180 length += fsize;
181
79faa2b0
AK
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
1027f476 191 line6pcm->prev_fbuf = fbuf;
97d78acf
AK
192 line6pcm->prev_fsize = fsize /
193 (line6pcm->properties->bytes_per_channel *
194 line6pcm->properties->capture_hw.channels_max);
705ececd 195
63e20df1
TI
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);
705ececd
MG
200 }
201
ad0119ab 202 clear_bit(index, &line6pcm->in.active_urbs);
705ececd 203
ad0119ab 204 if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs))
705ececd
MG
205 shutdown = 1;
206
6efc5667 207 if (!shutdown) {
1027f476 208 submit_audio_in_urb(line6pcm);
705ececd 209
63e20df1
TI
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);
705ececd 213 }
3d3ae445
TI
214
215 spin_unlock_irqrestore(&line6pcm->in.lock, flags);
705ececd
MG
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
6efc5667
GKH
225 err = snd_pcm_hw_constraint_ratdens(runtime, 0,
226 SNDRV_PCM_HW_PARAM_RATE,
1263f611 227 &line6pcm->properties->rates);
6efc5667 228 if (err < 0)
705ececd
MG
229 return err;
230
f56742cc
AK
231 line6_pcm_acquire(line6pcm, LINE6_STREAM_CAPTURE_HELPER, false);
232
1263f611 233 runtime->hw = line6pcm->properties->capture_hw;
705ececd
MG
234 return 0;
235}
236
237/* close capture callback */
238static int snd_line6_capture_close(struct snd_pcm_substream *substream)
239{
f56742cc
AK
240 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
241
242 line6_pcm_release(line6pcm, LINE6_STREAM_CAPTURE_HELPER);
705ececd
MG
243 return 0;
244}
245
705ececd 246/* capture operators */
e195a331 247const struct snd_pcm_ops snd_line6_capture_ops = {
e1a164d7
MG
248 .open = snd_line6_capture_open,
249 .close = snd_line6_capture_close,
63e20df1
TI
250 .hw_params = snd_line6_hw_params,
251 .hw_free = snd_line6_hw_free,
e1a164d7
MG
252 .prepare = snd_line6_prepare,
253 .trigger = snd_line6_trigger,
2954f914 254 .pointer = snd_line6_pointer,
705ececd
MG
255};
256
1027f476 257int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
705ececd 258{
16d603d3 259 struct usb_line6 *line6 = line6pcm->line6;
705ececd
MG
260 int i;
261
6396bb22
KC
262 line6pcm->in.urbs = kcalloc(line6->iso_buffers, sizeof(struct urb *),
263 GFP_KERNEL);
b2233d97
AK
264 if (line6pcm->in.urbs == NULL)
265 return -ENOMEM;
266
705ececd 267 /* create audio URBs and fill in constant values: */
b2233d97 268 for (i = 0; i < line6->iso_buffers; ++i) {
705ececd
MG
269 struct urb *urb;
270
271 /* URB for audio in: */
ad0119ab 272 urb = line6pcm->in.urbs[i] =
e0645d63 273 usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
705ececd 274
a019f5e8 275 if (urb == NULL)
705ececd 276 return -ENOMEM;
705ececd 277
16d603d3 278 urb->dev = line6->usbdev;
e0645d63 279 urb->pipe =
16d603d3
CR
280 usb_rcvisocpipe(line6->usbdev,
281 line6->properties->ep_audio_r &
e1a164d7 282 USB_ENDPOINT_NUMBER_MASK);
705ececd
MG
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;
6e8a914a
TI
289 if (usb_urb_ep_type_check(urb))
290 return -EINVAL;
705ececd
MG
291 }
292
293 return 0;
294}