drivers/media/usb/usbtv/usbtv-audio.c

Source file repositories/reference/linux-study-clean/drivers/media/usb/usbtv/usbtv-audio.c

File Facts

System
Linux kernel
Corpus path
drivers/media/usb/usbtv/usbtv-audio.c
Extension
.c
Size
9962 bytes
Lines
378
Domain
Driver Families
Bucket
drivers/media
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 (buffer_pos + chunk_length >= runtime->buffer_size) {
			size_t cnt = (runtime->buffer_size - buffer_pos) *
				frame_bytes;
			memcpy(runtime->dma_area + buffer_pos * frame_bytes,
				urb_current, cnt);
			memcpy(runtime->dma_area, urb_current + cnt,
				chunk_length * frame_bytes - cnt);
		} else {
			memcpy(runtime->dma_area + buffer_pos * frame_bytes,
				urb_current, chunk_length * frame_bytes);
		}

		buffer_pos += chunk_length;
		period_pos += chunk_length;

		if (buffer_pos >= runtime->buffer_size)
			buffer_pos -= runtime->buffer_size;

		if (period_pos >= runtime->period_size) {
			period_pos -= runtime->period_size;
			period_elapsed = 1;
		}
	}

	snd_pcm_stream_lock_irqsave(substream, flags);

	chip->snd_buffer_pos = buffer_pos;
	chip->snd_period_pos = period_pos;

	snd_pcm_stream_unlock_irqrestore(substream, flags);

	if (period_elapsed)
		snd_pcm_period_elapsed(substream);

	usb_submit_urb(urb, GFP_ATOMIC);
}

static int usbtv_audio_start(struct usbtv *chip)
{
	unsigned int pipe;
	static const u16 setup[][2] = {
		/* These seem to enable the device. */
		{ USBTV_BASE + 0x0008, 0x0001 },
		{ USBTV_BASE + 0x01d0, 0x00ff },
		{ USBTV_BASE + 0x01d9, 0x0002 },

		{ USBTV_BASE + 0x01da, 0x0013 },
		{ USBTV_BASE + 0x01db, 0x0012 },
		{ USBTV_BASE + 0x01e9, 0x0002 },
		{ USBTV_BASE + 0x01ec, 0x006c },
		{ USBTV_BASE + 0x0294, 0x0020 },
		{ USBTV_BASE + 0x0255, 0x00cf },
		{ USBTV_BASE + 0x0256, 0x0020 },
		{ USBTV_BASE + 0x01eb, 0x0030 },
		{ USBTV_BASE + 0x027d, 0x00a6 },
		{ USBTV_BASE + 0x0280, 0x0011 },
		{ USBTV_BASE + 0x0281, 0x0040 },
		{ USBTV_BASE + 0x0282, 0x0011 },
		{ USBTV_BASE + 0x0283, 0x0040 },
		{ 0xf891, 0x0010 },

		/* this sets the input from composite */
		{ USBTV_BASE + 0x0284, 0x00aa },
	};

	chip->snd_bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (chip->snd_bulk_urb == NULL)
		goto err_alloc_urb;

	pipe = usb_rcvbulkpipe(chip->udev, USBTV_AUDIO_ENDP);

	chip->snd_bulk_urb->transfer_buffer = kzalloc(
		USBTV_AUDIO_URBSIZE, GFP_KERNEL);
	if (chip->snd_bulk_urb->transfer_buffer == NULL)
		goto err_transfer_buffer;

	usb_fill_bulk_urb(chip->snd_bulk_urb, chip->udev, pipe,
		chip->snd_bulk_urb->transfer_buffer, USBTV_AUDIO_URBSIZE,
		usbtv_audio_urb_received, chip);

	/* starting the stream */
	usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));

	usb_clear_halt(chip->udev, pipe);
	usb_submit_urb(chip->snd_bulk_urb, GFP_ATOMIC);

	return 0;

err_transfer_buffer:
	usb_free_urb(chip->snd_bulk_urb);

Annotation

Implementation Notes