sound/usb/line6/capture.c

Source file repositories/reference/linux-study-clean/sound/usb/line6/capture.c

File Facts

System
Linux kernel
Corpus path
sound/usb/line6/capture.c
Extension
.c
Size
7479 bytes
Lines
290
Domain
Driver Families
Bucket
sound/usb
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (len > 0) {
			memcpy(runtime->dma_area +
			       line6pcm->in.pos_done * bytes_per_frame, fbuf,
			       len * bytes_per_frame);
			memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
			       (frames - len) * bytes_per_frame);
		} else {
			/* this is somewhat paranoid */
			dev_err(line6pcm->line6->ifcdev,
				"driver bug: len = %d\n", len);
		}
	} else {
		/* copy single chunk */
		memcpy(runtime->dma_area +
		       line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize);
	}

	line6pcm->in.pos_done += frames;
	if (line6pcm->in.pos_done >= runtime->buffer_size)
		line6pcm->in.pos_done -= runtime->buffer_size;
}

void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
{
	struct snd_pcm_substream *substream =
	    get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);

	line6pcm->in.bytes += length;
	if (line6pcm->in.bytes >= line6pcm->in.period) {
		line6pcm->in.bytes %= line6pcm->in.period;
		spin_unlock(&line6pcm->in.lock);
		snd_pcm_period_elapsed(substream);
		spin_lock(&line6pcm->in.lock);
	}
}

/*
 * Callback for completed capture URB.
 */
static void audio_in_callback(struct urb *urb)
{
	int i, index, length = 0, shutdown = 0;
	struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;

	line6pcm->in.last_frame = urb->start_frame;

	/* find index of URB */
	for (index = 0; index < line6pcm->line6->iso_buffers; ++index)
		if (urb == line6pcm->in.urbs[index])
			break;

	guard(spinlock_irqsave)(&line6pcm->in.lock);

	for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
		char *fbuf;
		int fsize;
		struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];

		if (fin->status == -EXDEV) {
			shutdown = 1;
			break;
		}

		fbuf = urb->transfer_buffer + fin->offset;
		fsize = fin->actual_length;

		if (fsize > line6pcm->max_packet_size_in) {
			dev_err(line6pcm->line6->ifcdev,
				"driver and/or device bug: packet too large (%d > %d)\n",
				fsize, line6pcm->max_packet_size_in);
		}

		length += fsize;

		BUILD_BUG_ON_MSG(LINE6_ISO_PACKETS != 1,
			"The following code assumes LINE6_ISO_PACKETS == 1");
		/* TODO:
		 * Also, if iso_buffers != 2, the prev frame is almost random at
		 * playback side.
		 * This needs to be redesigned. It should be "stable", but we may
		 * experience sync problems on such high-speed configs.
		 */

		line6pcm->prev_fbuf = fbuf;
		line6pcm->prev_fsize = fsize /
			(line6pcm->properties->bytes_per_channel *
			line6pcm->properties->capture_hw.channels_max);

		if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
		    test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) &&

Annotation

Implementation Notes