sound/usb/usx2y/usx2yhwdeppcm.c

Source file repositories/reference/linux-study-clean/sound/usb/usx2y/usx2yhwdeppcm.c

File Facts

System
Linux kernel
Corpus path
sound/usb/usx2y/usx2yhwdeppcm.c
Extension
.c
Size
23261 bytes
Lines
773
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 (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
			dev_err(&usx2y->dev->dev,
				"active frame status %i. Most probably some hardware problem.\n",
				urb->iso_frame_desc[i].status);
			return urb->iso_frame_desc[i].status;
		}
		lens += urb->iso_frame_desc[i].actual_length / usx2y->stride;
	}
	hwptr_done += lens;
	if (hwptr_done >= runtime->buffer_size)
		hwptr_done -= runtime->buffer_size;
	subs->hwptr_done = hwptr_done;
	subs->transfer_done += lens;
	/* update the pointer, call callback if necessary */
	if (subs->transfer_done >= runtime->period_size) {
		subs->transfer_done -= runtime->period_size;
		snd_pcm_period_elapsed(subs->pcm_substream);
	}
	return 0;
}

static int usx2y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
					      struct usx2ydev *usx2y)
{
	return (runtime->buffer_size * 1000) / usx2y->rate + 1;	//FIXME: so far only correct period_size == 2^x ?
}

/*
 * prepare urb for playback data pipe
 *
 * we copy the data directly from the pcm buffer.
 * the current position to be copied is held in hwptr field.
 * since a urb can handle only a single linear buffer, if the total
 * transferred area overflows the buffer boundary, we cannot send
 * it directly from the buffer.  thus the data is once copied to
 * a temporary buffer and urb points to that.
 */
static int usx2y_hwdep_urb_play_prepare(struct snd_usx2y_substream *subs,
					struct urb *urb)
{
	int count, counts, pack;
	struct usx2ydev *usx2y = subs->usx2y;
	struct snd_usx2y_hwdep_pcm_shm *shm = usx2y->hwdep_pcm_shm;
	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;

	if (shm->playback_iso_start < 0) {
		shm->playback_iso_start = shm->captured_iso_head -
			usx2y_iso_frames_per_buffer(runtime, usx2y);
		if (shm->playback_iso_start < 0)
			shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
		shm->playback_iso_head = shm->playback_iso_start;
	}

	count = 0;
	for (pack = 0; pack < nr_of_packs(); pack++) {
		/* calculate the size of a packet */
		counts = shm->captured_iso[shm->playback_iso_head].length / usx2y->stride;
		if (counts < 43 || counts > 50) {
			dev_err(&usx2y->dev->dev, "should not be here with counts=%i\n", counts);
			return -EPIPE;
		}
		/* set up descriptor */
		urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
		urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
		if (atomic_read(&subs->state) != STATE_RUNNING)
			memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
			       urb->iso_frame_desc[pack].length);
		if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
			shm->playback_iso_head = 0;
		count += counts;
	}
	urb->transfer_buffer_length = count * usx2y->stride;
	return 0;
}

static void usx2y_usbpcm_urb_capt_iso_advance(struct snd_usx2y_substream *subs,
					      struct urb *urb)
{
	struct usb_iso_packet_descriptor *desc;
	struct snd_usx2y_hwdep_pcm_shm *shm;
	int pack, head;

	for (pack = 0; pack < nr_of_packs(); ++pack) {
		desc = urb->iso_frame_desc + pack;
		if (subs) {
			shm = subs->usx2y->hwdep_pcm_shm;
			head = shm->captured_iso_head + 1;
			if (head >= ARRAY_SIZE(shm->captured_iso))
				head = 0;
			shm->captured_iso[head].frame = urb->start_frame + pack;

Annotation

Implementation Notes