sound/virtio/virtio_pcm_msg.c

Source file repositories/reference/linux-study-clean/sound/virtio/virtio_pcm_msg.c

File Facts

System
Linux kernel
Corpus path
sound/virtio/virtio_pcm_msg.c
Extension
.c
Size
10948 bytes
Lines
416
Domain
Driver Families
Bucket
sound/virtio
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

struct virtio_pcm_msg {
	struct virtio_pcm_substream *substream;
	struct virtio_snd_pcm_xfer xfer;
	struct virtio_snd_pcm_status status;
	size_t length;
	struct scatterlist sgs[];
};

/**
 * enum pcm_msg_sg_index - Index values for the virtio_pcm_msg->sgs field in
 *                         an I/O message.
 * @PCM_MSG_SG_XFER: Element containing a virtio_snd_pcm_xfer structure.
 * @PCM_MSG_SG_STATUS: Element containing a virtio_snd_pcm_status structure.
 * @PCM_MSG_SG_DATA: The first element containing a data buffer.
 */
enum pcm_msg_sg_index {
	PCM_MSG_SG_XFER = 0,
	PCM_MSG_SG_STATUS,
	PCM_MSG_SG_DATA
};

/**
 * virtsnd_pcm_sg_num() - Count the number of sg-elements required to represent
 *                        vmalloc'ed buffer.
 * @data: Pointer to vmalloc'ed buffer.
 * @length: Buffer size.
 *
 * Context: Any context.
 * Return: Number of physically contiguous parts in the @data.
 */
static int virtsnd_pcm_sg_num(u8 *data, unsigned int length)
{
	phys_addr_t sg_address;
	unsigned int sg_length;
	int num = 0;

	while (length) {
		struct page *pg = vmalloc_to_page(data);
		phys_addr_t pg_address = page_to_phys(pg);
		size_t pg_length;

		pg_length = PAGE_SIZE - offset_in_page(data);
		if (pg_length > length)
			pg_length = length;

		if (!num || sg_address + sg_length != pg_address) {
			sg_address = pg_address;
			sg_length = pg_length;
			num++;
		} else {
			sg_length += pg_length;
		}

		data += pg_length;
		length -= pg_length;
	}

	return num;
}

/**
 * virtsnd_pcm_sg_from() - Build sg-list from vmalloc'ed buffer.
 * @sgs: Preallocated sg-list to populate.
 * @nsgs: The maximum number of elements in the @sgs.
 * @data: Pointer to vmalloc'ed buffer.
 * @length: Buffer size.
 *
 * Splits the buffer into physically contiguous parts and makes an sg-list of
 * such parts.
 *
 * Context: Any context.
 */
static void virtsnd_pcm_sg_from(struct scatterlist *sgs, int nsgs, u8 *data,
				unsigned int length)
{
	int idx = -1;

	while (length) {
		struct page *pg = vmalloc_to_page(data);
		size_t pg_length;

		pg_length = PAGE_SIZE - offset_in_page(data);
		if (pg_length > length)
			pg_length = length;

		if (idx == -1 ||
		    sg_phys(&sgs[idx]) + sgs[idx].length != page_to_phys(pg)) {
			if (idx + 1 == nsgs)
				break;
			sg_set_page(&sgs[++idx], pg, pg_length,

Annotation

Implementation Notes