drivers/mfd/qnap-mcu.c

Source file repositories/reference/linux-study-clean/drivers/mfd/qnap-mcu.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/qnap-mcu.c
Extension
.c
Size
11056 bytes
Lines
427
Domain
Driver Families
Bucket
drivers/mfd
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 qnap_mcu_reply {
	u8 *data;
	size_t length;
	size_t received;
	struct completion done;
};

/**
 * struct qnap_mcu - QNAP NAS embedded controller
 *
 * @serdev:	Pointer to underlying serdev
 * @bus_lock:	Lock to serialize access to the device
 * @reply:	Reply data structure
 * @variant:	Device variant specific information
 * @version:	MCU firmware version
 */
struct qnap_mcu {
	struct serdev_device *serdev;
	struct mutex bus_lock;
	struct qnap_mcu_reply reply;
	const struct qnap_mcu_variant *variant;
	u8 version[QNAP_MCU_VERSION_LEN];
};

/*
 * The QNAP-MCU uses a basic XOR checksum.
 * It is always the last byte and XORs the whole previous message.
 */
static u8 qnap_mcu_csum(const u8 *buf, size_t size)
{
	u8 csum = 0;

	while (size--)
		csum ^= *buf++;

	return csum;
}

static bool qnap_mcu_verify_checksum(const u8 *buf, size_t size)
{
	u8 crc = qnap_mcu_csum(buf, size - QNAP_MCU_CHECKSUM_SIZE);

	return crc == buf[size - QNAP_MCU_CHECKSUM_SIZE];
}

static int qnap_mcu_write(struct qnap_mcu *mcu, const u8 *data, u8 data_size)
{
	unsigned char tx[QNAP_MCU_TX_BUFFER_SIZE];
	size_t length = data_size + QNAP_MCU_CHECKSUM_SIZE;

	if (length > sizeof(tx)) {
		dev_err(&mcu->serdev->dev, "data too big for transmit buffer");
		return -EINVAL;
	}

	memcpy(tx, data, data_size);
	tx[data_size] = qnap_mcu_csum(data, data_size);

	serdev_device_write_flush(mcu->serdev);

	return serdev_device_write(mcu->serdev, tx, length, HZ);
}

static bool qnap_mcu_is_error_msg(size_t size)
{
	return (size == QNAP_MCU_ERROR_SIZE + QNAP_MCU_CHECKSUM_SIZE);
}

static bool qnap_mcu_reply_is_generic_error(unsigned char *buf, size_t size)
{
	if (!qnap_mcu_is_error_msg(size))
		return false;

	if (buf[0] == '@' && buf[1] == '9')
		return true;

	return false;
}

static bool qnap_mcu_reply_is_checksum_error(unsigned char *buf, size_t size)
{
	if (!qnap_mcu_is_error_msg(size))
		return false;

	if (buf[0] == '@' && buf[1] == '8')
		return true;

	return false;
}

Annotation

Implementation Notes