drivers/media/cec/usb/rainshadow/rainshadow-cec.c

Source file repositories/reference/linux-study-clean/drivers/media/cec/usb/rainshadow/rainshadow-cec.c

File Facts

System
Linux kernel
Corpus path
drivers/media/cec/usb/rainshadow/rainshadow-cec.c
Extension
.c
Size
8582 bytes
Lines
383
Domain
Driver Families
Bucket
drivers/media
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 rain {
	struct device *dev;
	struct serio *serio;
	struct cec_adapter *adap;
	struct completion cmd_done;
	struct work_struct work;

	/* Low-level ringbuffer, collecting incoming characters */
	char buf[DATA_SIZE];
	unsigned int buf_rd_idx;
	unsigned int buf_wr_idx;
	unsigned int buf_len;
	spinlock_t buf_lock;

	/* command buffer */
	char cmd[DATA_SIZE];
	unsigned int cmd_idx;
	bool cmd_started;

	/* reply to a command, only used to store the firmware version */
	char cmd_reply[DATA_SIZE];

	struct mutex write_lock;
};

static void rain_process_msg(struct rain *rain)
{
	struct cec_msg msg = {};
	const char *cmd = rain->cmd + 3;
	int stat = -1;

	for (; *cmd; cmd++) {
		if (!isxdigit(*cmd))
			continue;
		if (isxdigit(cmd[0]) && isxdigit(cmd[1])) {
			if (msg.len == CEC_MAX_MSG_SIZE)
				break;
			if (hex2bin(msg.msg + msg.len, cmd, 1))
				continue;
			msg.len++;
			cmd++;
			continue;
		}
		if (!cmd[1])
			stat = hex_to_bin(cmd[0]);
		break;
	}

	if (rain->cmd[0] == 'R') {
		if (stat == 1 || stat == 2)
			cec_received_msg(rain->adap, &msg);
		return;
	}

	switch (stat) {
	case 1:
		cec_transmit_attempt_done(rain->adap, CEC_TX_STATUS_OK);
		break;
	case 2:
		cec_transmit_attempt_done(rain->adap, CEC_TX_STATUS_NACK);
		break;
	default:
		cec_transmit_attempt_done(rain->adap, CEC_TX_STATUS_LOW_DRIVE);
		break;
	}
}

static void rain_irq_work_handler(struct work_struct *work)
{
	struct rain *rain =
		container_of(work, struct rain, work);

	while (true) {
		unsigned long flags;
		char data;

		spin_lock_irqsave(&rain->buf_lock, flags);
		if (!rain->buf_len) {
			spin_unlock_irqrestore(&rain->buf_lock, flags);
			break;
		}

		data = rain->buf[rain->buf_rd_idx];
		rain->buf_len--;
		rain->buf_rd_idx = (rain->buf_rd_idx + 1) & 0xff;

		spin_unlock_irqrestore(&rain->buf_lock, flags);

		if (!rain->cmd_started && data != '?')
			continue;

Annotation

Implementation Notes