1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2025 Šerif Rami <ramiserifpersia@gmail.com>
3
4 #include "us144mkii.h"
5
6 /*
7 * tascam_capture_open() - Opens the PCM capture substream.
8 * @substream: The ALSA PCM substream to open.
9 *
10 * This function sets the hardware parameters for the capture substream
11 * and stores a reference to the substream in the driver's private data.
12 *
13 * Return: 0 on success.
14 */
tascam_capture_open(struct snd_pcm_substream * substream)15 static int tascam_capture_open(struct snd_pcm_substream *substream)
16 {
17 struct tascam_card *tascam = snd_pcm_substream_chip(substream);
18
19 substream->runtime->hw = tascam_pcm_hw;
20 tascam->capture_substream = substream;
21 atomic_set(&tascam->capture_active, 0);
22
23 return 0;
24 }
25
26 /*
27 * tascam_capture_close() - Closes the PCM capture substream.
28 * @substream: The ALSA PCM substream to close.
29 *
30 * This function clears the reference to the capture substream in the
31 * driver's private data.
32 *
33 * Return: 0 on success.
34 */
tascam_capture_close(struct snd_pcm_substream * substream)35 static int tascam_capture_close(struct snd_pcm_substream *substream)
36 {
37 struct tascam_card *tascam = snd_pcm_substream_chip(substream);
38
39 tascam->capture_substream = NULL;
40
41 return 0;
42 }
43
44 /*
45 * tascam_capture_prepare() - Prepares the PCM capture substream for use.
46 * @substream: The ALSA PCM substream to prepare.
47 *
48 * This function initializes capture-related counters and ring buffer pointers.
49 *
50 * Return: 0 on success.
51 */
tascam_capture_prepare(struct snd_pcm_substream * substream)52 static int tascam_capture_prepare(struct snd_pcm_substream *substream)
53 {
54 struct tascam_card *tascam = snd_pcm_substream_chip(substream);
55
56 tascam->driver_capture_pos = 0;
57 tascam->capture_frames_processed = 0;
58 tascam->last_capture_period_pos = 0;
59 tascam->capture_ring_buffer_read_ptr = 0;
60 tascam->capture_ring_buffer_write_ptr = 0;
61
62 return 0;
63 }
64
65 /*
66 * tascam_capture_pointer() - Returns the current capture pointer position.
67 * @substream: The ALSA PCM substream.
68 *
69 * This function returns the current position of the capture pointer within
70 * the ALSA ring buffer, in frames.
71 *
72 * Return: The current capture pointer position in frames.
73 */
74 static snd_pcm_uframes_t
tascam_capture_pointer(struct snd_pcm_substream * substream)75 tascam_capture_pointer(struct snd_pcm_substream *substream)
76 {
77 struct tascam_card *tascam = snd_pcm_substream_chip(substream);
78 struct snd_pcm_runtime *runtime = substream->runtime;
79 u64 pos;
80
81 if (!atomic_read(&tascam->capture_active))
82 return 0;
83
84 scoped_guard(spinlock_irqsave, &tascam->lock) {
85 pos = tascam->capture_frames_processed;
86 }
87
88 if (runtime->buffer_size == 0)
89 return 0;
90
91 return do_div(pos, runtime->buffer_size);
92 }
93
94 /*
95 * tascam_capture_ops - ALSA PCM operations for capture.
96 *
97 * This structure defines the callback functions for capture stream operations,
98 * including open, close, ioctl, hardware parameters, hardware free, prepare,
99 * trigger, and pointer.
100 */
101 const struct snd_pcm_ops tascam_capture_ops = {
102 .open = tascam_capture_open,
103 .close = tascam_capture_close,
104 .ioctl = snd_pcm_lib_ioctl,
105 .hw_params = tascam_pcm_hw_params,
106 .hw_free = tascam_pcm_hw_free,
107 .prepare = tascam_capture_prepare,
108 .trigger = tascam_pcm_trigger,
109 .pointer = tascam_capture_pointer,
110 };
111
112 /*
113 * decode_tascam_capture_block() - Decodes a raw 512-byte block from the device.
114 * @src_block: Pointer to the 512-byte raw source block.
115 * @dst_block: Pointer to the destination buffer for decoded audio frames.
116 *
117 * The device sends audio data in a complex, multiplexed format. This function
118 * demultiplexes the bits from the raw block into 8 frames of 4-channel,
119 * 24-bit audio (stored in 32-bit containers).
120 */
decode_tascam_capture_block(const u8 * src_block,s32 * dst_block)121 static void decode_tascam_capture_block(const u8 *src_block, s32 *dst_block)
122 {
123 int frame, bit;
124
125 memset(dst_block, 0,
126 FRAMES_PER_DECODE_BLOCK * DECODED_CHANNELS_PER_FRAME *
127 DECODED_SAMPLE_SIZE);
128
129 for (frame = 0; frame < FRAMES_PER_DECODE_BLOCK; ++frame) {
130 const u8 *p_src_frame_base = src_block + frame * 64;
131 s32 *p_dst_frame = dst_block + frame * 4;
132
133 s32 ch[4] = { 0 };
134
135 for (bit = 0; bit < 24; ++bit) {
136 u8 byte1 = p_src_frame_base[bit];
137 u8 byte2 = p_src_frame_base[bit + 32];
138
139 ch[0] = (ch[0] << 1) | (byte1 & 1);
140 ch[2] = (ch[2] << 1) | ((byte1 >> 1) & 1);
141
142 ch[1] = (ch[1] << 1) | (byte2 & 1);
143 ch[3] = (ch[3] << 1) | ((byte2 >> 1) & 1);
144 }
145
146 /*
147 * The result is a 24-bit sample. Shift left by 8 to align it to
148 * the most significant bits of a 32-bit integer (S32_LE format).
149 */
150 p_dst_frame[0] = ch[0] << 8;
151 p_dst_frame[1] = ch[1] << 8;
152 p_dst_frame[2] = ch[2] << 8;
153 p_dst_frame[3] = ch[3] << 8;
154 }
155 }
156
tascam_capture_work_handler(struct work_struct * work)157 void tascam_capture_work_handler(struct work_struct *work)
158 {
159 struct tascam_card *tascam =
160 container_of(work, struct tascam_card, capture_work);
161 struct snd_pcm_substream *substream = tascam->capture_substream;
162 struct snd_pcm_runtime *runtime;
163 u8 *raw_block = tascam->capture_decode_raw_block;
164 s32 *decoded_block = tascam->capture_decode_dst_block;
165 s32 *routed_block = tascam->capture_routing_buffer;
166
167 if (!substream || !substream->runtime)
168 return;
169 runtime = substream->runtime;
170
171 if (!raw_block || !decoded_block || !routed_block) {
172 dev_err(tascam->card->dev,
173 "Capture decode/routing buffers not allocated!\n");
174 return;
175 }
176
177 while (atomic_read(&tascam->capture_active)) {
178 size_t write_ptr, read_ptr, available_data;
179 bool can_process;
180
181 scoped_guard(spinlock_irqsave, &tascam->lock) {
182 write_ptr = tascam->capture_ring_buffer_write_ptr;
183 read_ptr = tascam->capture_ring_buffer_read_ptr;
184 available_data = (write_ptr >= read_ptr) ?
185 (write_ptr - read_ptr) :
186 (CAPTURE_RING_BUFFER_SIZE -
187 read_ptr + write_ptr);
188 can_process =
189 (available_data >= RAW_BYTES_PER_DECODE_BLOCK);
190
191 if (can_process) {
192 size_t bytes_to_end =
193 CAPTURE_RING_BUFFER_SIZE - read_ptr;
194 if (bytes_to_end >=
195 RAW_BYTES_PER_DECODE_BLOCK) {
196 memcpy(raw_block,
197 tascam->capture_ring_buffer +
198 read_ptr,
199 RAW_BYTES_PER_DECODE_BLOCK);
200 } else {
201 memcpy(raw_block,
202 tascam->capture_ring_buffer +
203 read_ptr,
204 bytes_to_end);
205 memcpy(raw_block + bytes_to_end,
206 tascam->capture_ring_buffer,
207 RAW_BYTES_PER_DECODE_BLOCK -
208 bytes_to_end);
209 }
210 tascam->capture_ring_buffer_read_ptr =
211 (read_ptr +
212 RAW_BYTES_PER_DECODE_BLOCK) %
213 CAPTURE_RING_BUFFER_SIZE;
214 }
215 }
216
217 if (!can_process)
218 break;
219
220 decode_tascam_capture_block(raw_block, decoded_block);
221 process_capture_routing_us144mkii(tascam, decoded_block,
222 routed_block);
223
224 scoped_guard(spinlock_irqsave, &tascam->lock) {
225 if (atomic_read(&tascam->capture_active)) {
226 int f;
227
228 for (f = 0; f < FRAMES_PER_DECODE_BLOCK; ++f) {
229 u8 *dst_frame_start =
230 runtime->dma_area +
231 frames_to_bytes(
232 runtime,
233 tascam->driver_capture_pos);
234 s32 *routed_frame_start =
235 routed_block +
236 (f * NUM_CHANNELS);
237 int c;
238
239 for (c = 0; c < NUM_CHANNELS; c++) {
240 u8 *dst_channel =
241 dst_frame_start +
242 (c * BYTES_PER_SAMPLE);
243 s32 *src_channel_s32 =
244 routed_frame_start + c;
245
246 memcpy(dst_channel,
247 ((char *)src_channel_s32) +
248 1,
249 3);
250 }
251
252 tascam->driver_capture_pos =
253 (tascam->driver_capture_pos +
254 1) %
255 runtime->buffer_size;
256 }
257 }
258 }
259 }
260 }
261
capture_urb_complete(struct urb * urb)262 void capture_urb_complete(struct urb *urb)
263 {
264 struct tascam_card *tascam = urb->context;
265 int ret;
266
267 if (urb->status) {
268 if (urb->status != -ENOENT && urb->status != -ECONNRESET &&
269 urb->status != -ESHUTDOWN && urb->status != -ENODEV &&
270 urb->status != -EPROTO)
271 dev_err_ratelimited(tascam->card->dev,
272 "Capture URB failed: %d\n",
273 urb->status);
274 goto out;
275 }
276 if (!tascam || !atomic_read(&tascam->capture_active))
277 goto out;
278
279 if (urb->actual_length > 0) {
280 scoped_guard(spinlock_irqsave, &tascam->lock) {
281 size_t write_ptr = tascam->capture_ring_buffer_write_ptr;
282 size_t bytes_to_end = CAPTURE_RING_BUFFER_SIZE - write_ptr;
283
284 if (urb->actual_length > bytes_to_end) {
285 memcpy(tascam->capture_ring_buffer + write_ptr,
286 urb->transfer_buffer, bytes_to_end);
287 memcpy(tascam->capture_ring_buffer,
288 urb->transfer_buffer + bytes_to_end,
289 urb->actual_length - bytes_to_end);
290 } else {
291 memcpy(tascam->capture_ring_buffer + write_ptr,
292 urb->transfer_buffer,
293 urb->actual_length);
294 }
295
296 tascam->capture_ring_buffer_write_ptr =
297 (write_ptr + urb->actual_length) %
298 CAPTURE_RING_BUFFER_SIZE;
299 }
300
301 schedule_work(&tascam->capture_work);
302 }
303
304 usb_get_urb(urb);
305 usb_anchor_urb(urb, &tascam->capture_anchor);
306 ret = usb_submit_urb(urb, GFP_ATOMIC);
307 if (ret < 0) {
308 dev_err_ratelimited(tascam->card->dev,
309 "Failed to resubmit capture URB: %d\n",
310 ret);
311 usb_unanchor_urb(urb);
312 usb_put_urb(urb);
313 atomic_dec(
314 &tascam->active_urbs); /* Decrement on failed resubmission */
315 }
316 out:
317 usb_put_urb(urb);
318 }
319
320