drivers/media/cec/platform/cros-ec/cros-ec-cec.c

Source file repositories/reference/linux-study-clean/drivers/media/cec/platform/cros-ec/cros-ec-cec.c

File Facts

System
Linux kernel
Corpus path
drivers/media/cec/platform/cros-ec/cros-ec-cec.c
Extension
.c
Size
16725 bytes
Lines
609
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 cros_ec_cec_port {
	int port_num;
	struct cec_adapter *adap;
	struct cec_notifier *notify;
	struct cec_msg rx_msg;
	struct cros_ec_cec *cros_ec_cec;
};

/**
 * struct cros_ec_cec - Driver data for EC CEC
 *
 * @cros_ec: Pointer to EC device
 * @notifier: Notifier info for responding to EC events
 * @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG.
 * @num_ports: Number of CEC ports
 * @ports: Array of ports
 */
struct cros_ec_cec {
	struct cros_ec_device *cros_ec;
	struct notifier_block notifier;
	int write_cmd_version;
	int num_ports;
	struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS];
};

static void cros_ec_cec_received_message(struct cros_ec_cec_port *port,
					 uint8_t *msg, uint8_t len)
{
	if (len > CEC_MAX_MSG_SIZE)
		len = CEC_MAX_MSG_SIZE;

	port->rx_msg.len = len;
	memcpy(port->rx_msg.msg, msg, len);

	cec_received_msg(port->adap, &port->rx_msg);
}

static void handle_cec_message(struct cros_ec_cec *cros_ec_cec)
{
	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
	uint8_t *cec_message = cros_ec->event_data.data.cec_message;
	unsigned int len = cros_ec->event_size;
	struct cros_ec_cec_port *port;
	/*
	 * There are two ways of receiving CEC messages:
	 * 1. Old EC firmware which only supports one port sends the data in a
	 *    cec_message MKBP event.
	 * 2. New EC firmware which supports multiple ports uses
	 *    EC_MKBP_CEC_HAVE_DATA to notify that data is ready and
	 *    EC_CMD_CEC_READ_MSG to read it.
	 * Check that the EC only has one CEC port, and then we can assume the
	 * message is from port 0.
	 */
	if (cros_ec_cec->num_ports != 1) {
		dev_err(cros_ec->dev,
			"received cec_message on device with %d ports\n",
			cros_ec_cec->num_ports);
		return;
	}
	port = cros_ec_cec->ports[0];

	cros_ec_cec_received_message(port, cec_message, len);
}

static void cros_ec_cec_read_message(struct cros_ec_cec_port *port)
{
	struct cros_ec_device *cros_ec = port->cros_ec_cec->cros_ec;
	struct ec_params_cec_read params = {
		.port = port->port_num,
	};
	struct ec_response_cec_read response;
	int ret;

	ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_READ_MSG, &params,
			  sizeof(params), &response, sizeof(response));
	if (ret < 0) {
		dev_err(cros_ec->dev,
			"error reading CEC message on EC: %d\n", ret);
		return;
	}

	cros_ec_cec_received_message(port, response.msg, response.msg_len);
}

static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)
{
	struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
	uint32_t cec_events = cros_ec->event_data.data.cec_events;
	uint32_t port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events);
	uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events);

Annotation

Implementation Notes