sound/soc/codecs/ntpfw.c

Source file repositories/reference/linux-study-clean/sound/soc/codecs/ntpfw.c

File Facts

System
Linux kernel
Corpus path
sound/soc/codecs/ntpfw.c
Extension
.c
Size
3063 bytes
Lines
138
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 ntpfw_chunk {
	__be16 length;
	u8 step;
	u8 data[];
} __packed;

struct ntpfw_header {
	__be32 magic;
} __packed;

static bool ntpfw_verify(struct device *dev, const u8 *buf, size_t buf_size, u32 magic)
{
	const struct ntpfw_header *header = (struct ntpfw_header *)buf;
	u32 buf_magic;

	if (buf_size <= sizeof(*header)) {
		dev_err(dev, "Failed to load firmware: image too small\n");
		return false;
	}

	buf_magic = be32_to_cpu(header->magic);
	if (buf_magic != magic) {
		dev_err(dev, "Failed to load firmware: invalid magic 0x%x:\n", buf_magic);
		return false;
	}

	return true;
}

static bool ntpfw_verify_chunk(struct device *dev, const struct ntpfw_chunk *chunk, size_t buf_size)
{
	size_t chunk_size;

	if (buf_size <= sizeof(*chunk)) {
		dev_err(dev, "Failed to load firmware: chunk size too big\n");
		return false;
	}

	if (chunk->step != 2 && chunk->step != 5) {
		dev_err(dev, "Failed to load firmware: invalid chunk step: %d\n", chunk->step);
		return false;
	}

	chunk_size = be16_to_cpu(chunk->length);
	if (chunk_size > buf_size) {
		dev_err(dev, "Failed to load firmware: invalid chunk length\n");
		return false;
	}

	if (chunk_size % chunk->step) {
		dev_err(dev, "Failed to load firmware: chunk length and step mismatch\n");
		return false;
	}

	return true;
}

static int ntpfw_send_chunk(struct i2c_client *i2c, const struct ntpfw_chunk *chunk)
{
	int ret;
	size_t i;
	size_t length = be16_to_cpu(chunk->length);

	for (i = 0; i < length; i += chunk->step) {
		ret = i2c_master_send(i2c, &chunk->data[i], chunk->step);
		if (ret != chunk->step) {
			dev_err(&i2c->dev, "I2C send failed: %d\n", ret);
			return ret < 0 ? ret : -EIO;
		}
	}

	return 0;
}

int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic)
{
	struct device *dev = &i2c->dev;
	const struct ntpfw_chunk *chunk;
	const struct firmware *fw;
	const u8 *data;
	size_t leftover;
	int ret;

	ret = request_firmware(&fw, name, dev);
	if (ret) {
		dev_warn(dev, "request_firmware '%s' failed with %d\n",
			 name, ret);
		return ret;
	}

Annotation

Implementation Notes