xref: /linux/sound/usb/usx2y/us144mkii_capture.c (revision 05a54fa773284d1a7923cdfdd8f0c8dabb98bd26)
15c8c1079SŠerif Rami // SPDX-License-Identifier: GPL-2.0-only
25c8c1079SŠerif Rami // Copyright (c) 2025 Šerif Rami <ramiserifpersia@gmail.com>
35c8c1079SŠerif Rami 
45c8c1079SŠerif Rami #include "us144mkii.h"
55c8c1079SŠerif Rami 
65c8c1079SŠerif Rami /**
75c8c1079SŠerif Rami  * tascam_capture_open() - Opens the PCM capture substream.
85c8c1079SŠerif Rami  * @substream: The ALSA PCM substream to open.
95c8c1079SŠerif Rami  *
105c8c1079SŠerif Rami  * This function sets the hardware parameters for the capture substream
115c8c1079SŠerif Rami  * and stores a reference to the substream in the driver's private data.
125c8c1079SŠerif Rami  *
135c8c1079SŠerif Rami  * Return: 0 on success.
145c8c1079SŠerif Rami  */
155c8c1079SŠerif Rami static int tascam_capture_open(struct snd_pcm_substream *substream)
165c8c1079SŠerif Rami {
175c8c1079SŠerif Rami 	struct tascam_card *tascam = snd_pcm_substream_chip(substream);
185c8c1079SŠerif Rami 
195c8c1079SŠerif Rami 	substream->runtime->hw = tascam_pcm_hw;
205c8c1079SŠerif Rami 	tascam->capture_substream = substream;
215c8c1079SŠerif Rami 	atomic_set(&tascam->capture_active, 0);
225c8c1079SŠerif Rami 
235c8c1079SŠerif Rami 	return 0;
245c8c1079SŠerif Rami }
255c8c1079SŠerif Rami 
265c8c1079SŠerif Rami /**
275c8c1079SŠerif Rami  * tascam_capture_close() - Closes the PCM capture substream.
285c8c1079SŠerif Rami  * @substream: The ALSA PCM substream to close.
295c8c1079SŠerif Rami  *
305c8c1079SŠerif Rami  * This function clears the reference to the capture substream in the
315c8c1079SŠerif Rami  * driver's private data.
325c8c1079SŠerif Rami  *
335c8c1079SŠerif Rami  * Return: 0 on success.
345c8c1079SŠerif Rami  */
355c8c1079SŠerif Rami static int tascam_capture_close(struct snd_pcm_substream *substream)
365c8c1079SŠerif Rami {
375c8c1079SŠerif Rami 	struct tascam_card *tascam = snd_pcm_substream_chip(substream);
385c8c1079SŠerif Rami 
395c8c1079SŠerif Rami 	tascam->capture_substream = NULL;
405c8c1079SŠerif Rami 
415c8c1079SŠerif Rami 	return 0;
425c8c1079SŠerif Rami }
435c8c1079SŠerif Rami 
445c8c1079SŠerif Rami /**
455c8c1079SŠerif Rami  * tascam_capture_prepare() - Prepares the PCM capture substream for use.
465c8c1079SŠerif Rami  * @substream: The ALSA PCM substream to prepare.
475c8c1079SŠerif Rami  *
48*c1bb0c13SŠerif Rami  * This function initializes capture-related counters and ring buffer pointers.
495c8c1079SŠerif Rami  *
505c8c1079SŠerif Rami  * Return: 0 on success.
515c8c1079SŠerif Rami  */
525c8c1079SŠerif Rami static int tascam_capture_prepare(struct snd_pcm_substream *substream)
535c8c1079SŠerif Rami {
545c8c1079SŠerif Rami 	struct tascam_card *tascam = snd_pcm_substream_chip(substream);
555c8c1079SŠerif Rami 
565c8c1079SŠerif Rami 	tascam->driver_capture_pos = 0;
575c8c1079SŠerif Rami 	tascam->capture_frames_processed = 0;
58a2a2210fSŠerif Rami 	tascam->last_capture_period_pos = 0;
59*c1bb0c13SŠerif Rami 	tascam->capture_ring_buffer_read_ptr = 0;
60*c1bb0c13SŠerif Rami 	tascam->capture_ring_buffer_write_ptr = 0;
615c8c1079SŠerif Rami 
625c8c1079SŠerif Rami 	return 0;
635c8c1079SŠerif Rami }
645c8c1079SŠerif Rami 
655c8c1079SŠerif Rami /**
665c8c1079SŠerif Rami  * tascam_capture_pointer() - Returns the current capture pointer position.
675c8c1079SŠerif Rami  * @substream: The ALSA PCM substream.
685c8c1079SŠerif Rami  *
695c8c1079SŠerif Rami  * This function returns the current position of the capture pointer within
705c8c1079SŠerif Rami  * the ALSA ring buffer, in frames.
715c8c1079SŠerif Rami  *
725c8c1079SŠerif Rami  * Return: The current capture pointer position in frames.
735c8c1079SŠerif Rami  */
745c8c1079SŠerif Rami static snd_pcm_uframes_t
755c8c1079SŠerif Rami tascam_capture_pointer(struct snd_pcm_substream *substream)
765c8c1079SŠerif Rami {
775c8c1079SŠerif Rami 	struct tascam_card *tascam = snd_pcm_substream_chip(substream);
785c8c1079SŠerif Rami 	struct snd_pcm_runtime *runtime = substream->runtime;
795c8c1079SŠerif Rami 	u64 pos;
805c8c1079SŠerif Rami 
815c8c1079SŠerif Rami 	if (!atomic_read(&tascam->capture_active))
825c8c1079SŠerif Rami 		return 0;
835c8c1079SŠerif Rami 
845c8c1079SŠerif Rami 	scoped_guard(spinlock_irqsave, &tascam->lock) {
855c8c1079SŠerif Rami 		pos = tascam->capture_frames_processed;
865c8c1079SŠerif Rami 	}
875c8c1079SŠerif Rami 
885c8c1079SŠerif Rami 	if (runtime->buffer_size == 0)
895c8c1079SŠerif Rami 		return 0;
905c8c1079SŠerif Rami 
915c8c1079SŠerif Rami 	return do_div(pos, runtime->buffer_size);
925c8c1079SŠerif Rami }
935c8c1079SŠerif Rami 
945c8c1079SŠerif Rami /**
955c8c1079SŠerif Rami  * tascam_capture_ops - ALSA PCM operations for capture.
965c8c1079SŠerif Rami  *
975c8c1079SŠerif Rami  * This structure defines the callback functions for capture stream operations,
985c8c1079SŠerif Rami  * including open, close, ioctl, hardware parameters, hardware free, prepare,
995c8c1079SŠerif Rami  * trigger, and pointer.
1005c8c1079SŠerif Rami  */
1015c8c1079SŠerif Rami const struct snd_pcm_ops tascam_capture_ops = {
1025c8c1079SŠerif Rami 	.open = tascam_capture_open,
1035c8c1079SŠerif Rami 	.close = tascam_capture_close,
1045c8c1079SŠerif Rami 	.ioctl = snd_pcm_lib_ioctl,
1055c8c1079SŠerif Rami 	.hw_params = tascam_pcm_hw_params,
1065c8c1079SŠerif Rami 	.hw_free = tascam_pcm_hw_free,
1075c8c1079SŠerif Rami 	.prepare = tascam_capture_prepare,
1085c8c1079SŠerif Rami 	.trigger = tascam_pcm_trigger,
1095c8c1079SŠerif Rami 	.pointer = tascam_capture_pointer,
1105c8c1079SŠerif Rami };
111*c1bb0c13SŠerif Rami 
112*c1bb0c13SŠerif Rami /**
113*c1bb0c13SŠerif Rami  * decode_tascam_capture_block() - Decodes a raw 512-byte block from the device.
114*c1bb0c13SŠerif Rami  * @src_block: Pointer to the 512-byte raw source block.
115*c1bb0c13SŠerif Rami  * @dst_block: Pointer to the destination buffer for decoded audio frames.
116*c1bb0c13SŠerif Rami  *
117*c1bb0c13SŠerif Rami  * The device sends audio data in a complex, multiplexed format. This function
118*c1bb0c13SŠerif Rami  * demultiplexes the bits from the raw block into 8 frames of 4-channel,
119*c1bb0c13SŠerif Rami  * 24-bit audio (stored in 32-bit containers).
120*c1bb0c13SŠerif Rami  */
121*c1bb0c13SŠerif Rami static void decode_tascam_capture_block(const u8 *src_block, s32 *dst_block)
122*c1bb0c13SŠerif Rami {
123*c1bb0c13SŠerif Rami 	int frame, bit;
124*c1bb0c13SŠerif Rami 
125*c1bb0c13SŠerif Rami 	memset(dst_block, 0,
126*c1bb0c13SŠerif Rami 	       FRAMES_PER_DECODE_BLOCK * DECODED_CHANNELS_PER_FRAME *
127*c1bb0c13SŠerif Rami 		       DECODED_SAMPLE_SIZE);
128*c1bb0c13SŠerif Rami 
129*c1bb0c13SŠerif Rami 	for (frame = 0; frame < FRAMES_PER_DECODE_BLOCK; ++frame) {
130*c1bb0c13SŠerif Rami 		const u8 *p_src_frame_base = src_block + frame * 64;
131*c1bb0c13SŠerif Rami 		s32 *p_dst_frame = dst_block + frame * 4;
132*c1bb0c13SŠerif Rami 
133*c1bb0c13SŠerif Rami 		s32 ch[4] = { 0 };
134*c1bb0c13SŠerif Rami 
135*c1bb0c13SŠerif Rami 		for (bit = 0; bit < 24; ++bit) {
136*c1bb0c13SŠerif Rami 			u8 byte1 = p_src_frame_base[bit];
137*c1bb0c13SŠerif Rami 			u8 byte2 = p_src_frame_base[bit + 32];
138*c1bb0c13SŠerif Rami 
139*c1bb0c13SŠerif Rami 			ch[0] = (ch[0] << 1) | (byte1 & 1);
140*c1bb0c13SŠerif Rami 			ch[2] = (ch[2] << 1) | ((byte1 >> 1) & 1);
141*c1bb0c13SŠerif Rami 
142*c1bb0c13SŠerif Rami 			ch[1] = (ch[1] << 1) | (byte2 & 1);
143*c1bb0c13SŠerif Rami 			ch[3] = (ch[3] << 1) | ((byte2 >> 1) & 1);
144*c1bb0c13SŠerif Rami 		}
145*c1bb0c13SŠerif Rami 
146*c1bb0c13SŠerif Rami 		/*
147*c1bb0c13SŠerif Rami 		 * The result is a 24-bit sample. Shift left by 8 to align it to
148*c1bb0c13SŠerif Rami 		 * the most significant bits of a 32-bit integer (S32_LE format).
149*c1bb0c13SŠerif Rami 		 */
150*c1bb0c13SŠerif Rami 		p_dst_frame[0] = ch[0] << 8;
151*c1bb0c13SŠerif Rami 		p_dst_frame[1] = ch[1] << 8;
152*c1bb0c13SŠerif Rami 		p_dst_frame[2] = ch[2] << 8;
153*c1bb0c13SŠerif Rami 		p_dst_frame[3] = ch[3] << 8;
154*c1bb0c13SŠerif Rami 	}
155*c1bb0c13SŠerif Rami }
156*c1bb0c13SŠerif Rami 
157*c1bb0c13SŠerif Rami void tascam_capture_work_handler(struct work_struct *work)
158*c1bb0c13SŠerif Rami {
159*c1bb0c13SŠerif Rami 	struct tascam_card *tascam =
160*c1bb0c13SŠerif Rami 		container_of(work, struct tascam_card, capture_work);
161*c1bb0c13SŠerif Rami 	struct snd_pcm_substream *substream = tascam->capture_substream;
162*c1bb0c13SŠerif Rami 	struct snd_pcm_runtime *runtime;
163*c1bb0c13SŠerif Rami 	u8 *raw_block = tascam->capture_decode_raw_block;
164*c1bb0c13SŠerif Rami 	s32 *decoded_block = tascam->capture_decode_dst_block;
165*c1bb0c13SŠerif Rami 	s32 *routed_block = tascam->capture_routing_buffer;
166*c1bb0c13SŠerif Rami 
167*c1bb0c13SŠerif Rami 	if (!substream || !substream->runtime)
168*c1bb0c13SŠerif Rami 		return;
169*c1bb0c13SŠerif Rami 	runtime = substream->runtime;
170*c1bb0c13SŠerif Rami 
171*c1bb0c13SŠerif Rami 	if (!raw_block || !decoded_block || !routed_block) {
172*c1bb0c13SŠerif Rami 		dev_err(tascam->card->dev,
173*c1bb0c13SŠerif Rami 			"Capture decode/routing buffers not allocated!\n");
174*c1bb0c13SŠerif Rami 		return;
175*c1bb0c13SŠerif Rami 	}
176*c1bb0c13SŠerif Rami 
177*c1bb0c13SŠerif Rami 	while (atomic_read(&tascam->capture_active)) {
178*c1bb0c13SŠerif Rami 		size_t write_ptr, read_ptr, available_data;
179*c1bb0c13SŠerif Rami 		bool can_process;
180*c1bb0c13SŠerif Rami 
181*c1bb0c13SŠerif Rami 		scoped_guard(spinlock_irqsave, &tascam->lock) {
182*c1bb0c13SŠerif Rami 			write_ptr = tascam->capture_ring_buffer_write_ptr;
183*c1bb0c13SŠerif Rami 			read_ptr = tascam->capture_ring_buffer_read_ptr;
184*c1bb0c13SŠerif Rami 			available_data = (write_ptr >= read_ptr) ?
185*c1bb0c13SŠerif Rami 						 (write_ptr - read_ptr) :
186*c1bb0c13SŠerif Rami 						 (CAPTURE_RING_BUFFER_SIZE -
187*c1bb0c13SŠerif Rami 						  read_ptr + write_ptr);
188*c1bb0c13SŠerif Rami 			can_process =
189*c1bb0c13SŠerif Rami 				(available_data >= RAW_BYTES_PER_DECODE_BLOCK);
190*c1bb0c13SŠerif Rami 
191*c1bb0c13SŠerif Rami 			if (can_process) {
192*c1bb0c13SŠerif Rami 				size_t bytes_to_end =
193*c1bb0c13SŠerif Rami 					CAPTURE_RING_BUFFER_SIZE - read_ptr;
194*c1bb0c13SŠerif Rami 				if (bytes_to_end >=
195*c1bb0c13SŠerif Rami 				    RAW_BYTES_PER_DECODE_BLOCK) {
196*c1bb0c13SŠerif Rami 					memcpy(raw_block,
197*c1bb0c13SŠerif Rami 					       tascam->capture_ring_buffer +
198*c1bb0c13SŠerif Rami 						       read_ptr,
199*c1bb0c13SŠerif Rami 					       RAW_BYTES_PER_DECODE_BLOCK);
200*c1bb0c13SŠerif Rami 				} else {
201*c1bb0c13SŠerif Rami 					memcpy(raw_block,
202*c1bb0c13SŠerif Rami 					       tascam->capture_ring_buffer +
203*c1bb0c13SŠerif Rami 						       read_ptr,
204*c1bb0c13SŠerif Rami 					       bytes_to_end);
205*c1bb0c13SŠerif Rami 					memcpy(raw_block + bytes_to_end,
206*c1bb0c13SŠerif Rami 					       tascam->capture_ring_buffer,
207*c1bb0c13SŠerif Rami 					       RAW_BYTES_PER_DECODE_BLOCK -
208*c1bb0c13SŠerif Rami 						       bytes_to_end);
209*c1bb0c13SŠerif Rami 				}
210*c1bb0c13SŠerif Rami 				tascam->capture_ring_buffer_read_ptr =
211*c1bb0c13SŠerif Rami 					(read_ptr +
212*c1bb0c13SŠerif Rami 					 RAW_BYTES_PER_DECODE_BLOCK) %
213*c1bb0c13SŠerif Rami 					CAPTURE_RING_BUFFER_SIZE;
214*c1bb0c13SŠerif Rami 			}
215*c1bb0c13SŠerif Rami 		}
216*c1bb0c13SŠerif Rami 
217*c1bb0c13SŠerif Rami 		if (!can_process)
218*c1bb0c13SŠerif Rami 			break;
219*c1bb0c13SŠerif Rami 
220*c1bb0c13SŠerif Rami 		decode_tascam_capture_block(raw_block, decoded_block);
221*c1bb0c13SŠerif Rami 		process_capture_routing_us144mkii(tascam, decoded_block,
222*c1bb0c13SŠerif Rami 						  routed_block);
223*c1bb0c13SŠerif Rami 
224*c1bb0c13SŠerif Rami 		scoped_guard(spinlock_irqsave, &tascam->lock) {
225*c1bb0c13SŠerif Rami 			if (atomic_read(&tascam->capture_active)) {
226*c1bb0c13SŠerif Rami 				int f;
227*c1bb0c13SŠerif Rami 
228*c1bb0c13SŠerif Rami 				for (f = 0; f < FRAMES_PER_DECODE_BLOCK; ++f) {
229*c1bb0c13SŠerif Rami 					u8 *dst_frame_start =
230*c1bb0c13SŠerif Rami 						runtime->dma_area +
231*c1bb0c13SŠerif Rami 						frames_to_bytes(
232*c1bb0c13SŠerif Rami 							runtime,
233*c1bb0c13SŠerif Rami 							tascam->driver_capture_pos);
234*c1bb0c13SŠerif Rami 					s32 *routed_frame_start =
235*c1bb0c13SŠerif Rami 						routed_block +
236*c1bb0c13SŠerif Rami 						(f * NUM_CHANNELS);
237*c1bb0c13SŠerif Rami 					int c;
238*c1bb0c13SŠerif Rami 
239*c1bb0c13SŠerif Rami 					for (c = 0; c < NUM_CHANNELS; c++) {
240*c1bb0c13SŠerif Rami 						u8 *dst_channel =
241*c1bb0c13SŠerif Rami 							dst_frame_start +
242*c1bb0c13SŠerif Rami 							(c * BYTES_PER_SAMPLE);
243*c1bb0c13SŠerif Rami 						s32 *src_channel_s32 =
244*c1bb0c13SŠerif Rami 							routed_frame_start + c;
245*c1bb0c13SŠerif Rami 
246*c1bb0c13SŠerif Rami 						memcpy(dst_channel,
247*c1bb0c13SŠerif Rami 						       ((char *)src_channel_s32) +
248*c1bb0c13SŠerif Rami 							       1,
249*c1bb0c13SŠerif Rami 						       3);
250*c1bb0c13SŠerif Rami 					}
251*c1bb0c13SŠerif Rami 
252*c1bb0c13SŠerif Rami 					tascam->driver_capture_pos =
253*c1bb0c13SŠerif Rami 						(tascam->driver_capture_pos +
254*c1bb0c13SŠerif Rami 						 1) %
255*c1bb0c13SŠerif Rami 						runtime->buffer_size;
256*c1bb0c13SŠerif Rami 				}
257*c1bb0c13SŠerif Rami 			}
258*c1bb0c13SŠerif Rami 		}
259*c1bb0c13SŠerif Rami 	}
260*c1bb0c13SŠerif Rami }
261*c1bb0c13SŠerif Rami 
262*c1bb0c13SŠerif Rami void capture_urb_complete(struct urb *urb)
263*c1bb0c13SŠerif Rami {
264*c1bb0c13SŠerif Rami 	struct tascam_card *tascam = urb->context;
265*c1bb0c13SŠerif Rami 	int ret;
266*c1bb0c13SŠerif Rami 
267*c1bb0c13SŠerif Rami 	if (urb->status) {
268*c1bb0c13SŠerif Rami 		if (urb->status != -ENOENT && urb->status != -ECONNRESET &&
269*c1bb0c13SŠerif Rami 		    urb->status != -ESHUTDOWN && urb->status != -ENODEV &&
270*c1bb0c13SŠerif Rami 		    urb->status != -EPROTO)
271*c1bb0c13SŠerif Rami 			dev_err_ratelimited(tascam->card->dev,
272*c1bb0c13SŠerif Rami 					    "Capture URB failed: %d\n",
273*c1bb0c13SŠerif Rami 					    urb->status);
274*c1bb0c13SŠerif Rami 		goto out;
275*c1bb0c13SŠerif Rami 	}
276*c1bb0c13SŠerif Rami 	if (!tascam || !atomic_read(&tascam->capture_active))
277*c1bb0c13SŠerif Rami 		goto out;
278*c1bb0c13SŠerif Rami 
279*c1bb0c13SŠerif Rami 	if (urb->actual_length > 0) {
280*c1bb0c13SŠerif Rami 		scoped_guard(spinlock_irqsave, &tascam->lock) {
281*c1bb0c13SŠerif Rami 			size_t write_ptr = tascam->capture_ring_buffer_write_ptr;
282*c1bb0c13SŠerif Rami 			size_t bytes_to_end = CAPTURE_RING_BUFFER_SIZE - write_ptr;
283*c1bb0c13SŠerif Rami 
284*c1bb0c13SŠerif Rami 			if (urb->actual_length > bytes_to_end) {
285*c1bb0c13SŠerif Rami 				memcpy(tascam->capture_ring_buffer + write_ptr,
286*c1bb0c13SŠerif Rami 				       urb->transfer_buffer, bytes_to_end);
287*c1bb0c13SŠerif Rami 				memcpy(tascam->capture_ring_buffer,
288*c1bb0c13SŠerif Rami 				       urb->transfer_buffer + bytes_to_end,
289*c1bb0c13SŠerif Rami 				       urb->actual_length - bytes_to_end);
290*c1bb0c13SŠerif Rami 			} else {
291*c1bb0c13SŠerif Rami 				memcpy(tascam->capture_ring_buffer + write_ptr,
292*c1bb0c13SŠerif Rami 				       urb->transfer_buffer,
293*c1bb0c13SŠerif Rami 				       urb->actual_length);
294*c1bb0c13SŠerif Rami 			}
295*c1bb0c13SŠerif Rami 
296*c1bb0c13SŠerif Rami 			tascam->capture_ring_buffer_write_ptr =
297*c1bb0c13SŠerif Rami 				(write_ptr + urb->actual_length) %
298*c1bb0c13SŠerif Rami 				CAPTURE_RING_BUFFER_SIZE;
299*c1bb0c13SŠerif Rami 		}
300*c1bb0c13SŠerif Rami 
301*c1bb0c13SŠerif Rami 		schedule_work(&tascam->capture_work);
302*c1bb0c13SŠerif Rami 	}
303*c1bb0c13SŠerif Rami 
304*c1bb0c13SŠerif Rami 	usb_get_urb(urb);
305*c1bb0c13SŠerif Rami 	usb_anchor_urb(urb, &tascam->capture_anchor);
306*c1bb0c13SŠerif Rami 	ret = usb_submit_urb(urb, GFP_ATOMIC);
307*c1bb0c13SŠerif Rami 	if (ret < 0) {
308*c1bb0c13SŠerif Rami 		dev_err_ratelimited(tascam->card->dev,
309*c1bb0c13SŠerif Rami 				    "Failed to resubmit capture URB: %d\n",
310*c1bb0c13SŠerif Rami 				    ret);
311*c1bb0c13SŠerif Rami 		usb_unanchor_urb(urb);
312*c1bb0c13SŠerif Rami 		usb_put_urb(urb);
313*c1bb0c13SŠerif Rami 		atomic_dec(
314*c1bb0c13SŠerif Rami 			&tascam->active_urbs); /* Decrement on failed resubmission */
315*c1bb0c13SŠerif Rami 	}
316*c1bb0c13SŠerif Rami out:
317*c1bb0c13SŠerif Rami 	usb_put_urb(urb);
318*c1bb0c13SŠerif Rami }
319*c1bb0c13SŠerif Rami 
320