sound/usb/6fire/pcm.c

Source file repositories/reference/linux-study-clean/sound/usb/6fire/pcm.c

File Facts

System
Linux kernel
Corpus path
sound/usb/6fire/pcm.c
Extension
.c
Size
17426 bytes
Lines
671
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 (ret) {
				usb6fire_pcm_stream_stop(rt);
				return ret;
			}
		}

		/* wait for first out urb to return (sent in urb handler) */
		wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond,
				HZ);
		if (rt->stream_wait_cond)
			rt->stream_state = STREAM_RUNNING;
		else {
			usb6fire_pcm_stream_stop(rt);
			return -EIO;
		}
	}
	return 0;
}

/* call with substream locked */
static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)
{
	int i;
	int frame;
	int frame_count;
	unsigned int total_length = 0;
	struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
	struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
	u32 *src = NULL;
	u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off
			* (alsa_rt->frame_bits >> 3));
	u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
			* (alsa_rt->frame_bits >> 3));
	int bytes_per_frame = alsa_rt->channels << 2;

	for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
		/* at least 4 header bytes for valid packet.
		 * after that: 32 bits per sample for analog channels */
		if (urb->packets[i].actual_length > 4)
			frame_count = (urb->packets[i].actual_length - 4)
					/ (rt->in_n_analog << 2);
		else
			frame_count = 0;

		if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
			src = (u32 *) (urb->buffer + total_length);
		else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
			src = (u32 *) (urb->buffer - 1 + total_length);
		else
			return;
		src++; /* skip leading 4 bytes of every packet */
		total_length += urb->packets[i].length;
		for (frame = 0; frame < frame_count; frame++) {
			memcpy(dest, src, bytes_per_frame);
			dest += alsa_rt->channels;
			src += rt->in_n_analog;
			sub->dma_off++;
			sub->period_off++;
			if (dest == dest_end) {
				sub->dma_off = 0;
				dest = (u32 *) alsa_rt->dma_area;
			}
		}
	}
}

/* call with substream locked */
static void usb6fire_pcm_playback(struct pcm_substream *sub,
		struct pcm_urb *urb)
{
	int i;
	int frame;
	int frame_count;
	struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
	struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
	u32 *src = (u32 *) (alsa_rt->dma_area + sub->dma_off
			* (alsa_rt->frame_bits >> 3));
	u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
			* (alsa_rt->frame_bits >> 3));
	u32 *dest;
	int bytes_per_frame = alsa_rt->channels << 2;

	if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
		dest = (u32 *) (urb->buffer - 1);
	else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
		dest = (u32 *) (urb->buffer);
	else {
		dev_err(&rt->chip->dev->dev, "Unknown sample format.");
		return;
	}

Annotation

Implementation Notes