drivers/platform/chrome/cros_ec_uart.c

Source file repositories/reference/linux-study-clean/drivers/platform/chrome/cros_ec_uart.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/chrome/cros_ec_uart.c
Extension
.c
Size
10026 bytes
Lines
358
Domain
Driver Families
Bucket
drivers/platform
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 response_info {
	void *data;
	size_t max_size;
	size_t size;
	size_t exp_len;
	int status;
	wait_queue_head_t wait_queue;
};

/**
 * struct cros_ec_uart - information about a uart-connected EC
 *
 * @serdev:		serdev uart device we are connected to.
 * @baudrate:		UART baudrate of attached EC device.
 * @flowcontrol:	UART flowcontrol of attached device.
 * @irq:		Linux IRQ number of associated serial device.
 * @response:		Response info passing between cros_ec_uart_pkt_xfer()
 *			and cros_ec_uart_rx_bytes()
 */
struct cros_ec_uart {
	struct serdev_device *serdev;
	u32 baudrate;
	u8 flowcontrol;
	u32 irq;
	struct response_info response;
};

static size_t cros_ec_uart_rx_bytes(struct serdev_device *serdev,
				    const u8 *data, size_t count)
{
	struct ec_host_response *host_response;
	struct cros_ec_device *ec_dev = serdev_device_get_drvdata(serdev);
	struct cros_ec_uart *ec_uart = ec_dev->priv;
	struct response_info *resp = &ec_uart->response;

	/* Check if bytes were sent out of band */
	if (!resp->data) {
		/* Discard all bytes */
		dev_warn(ec_dev->dev, "Bytes received out of band, dropping them.\n");
		return count;
	}

	/*
	 * Check if incoming bytes + resp->size is greater than allocated
	 * buffer in din by cros_ec. This will ensure that if EC sends more
	 * bytes than max_size, waiting process will be notified with an error.
	 */
	if (resp->size + count > resp->max_size) {
		resp->status = -EMSGSIZE;
		wake_up(&resp->wait_queue);
		return count;
	}

	memcpy(resp->data + resp->size, data, count);

	resp->size += count;

	/* Read data_len if we received response header and if exp_len was not read before. */
	if (resp->size >= sizeof(*host_response) && resp->exp_len == 0) {
		host_response = (struct ec_host_response *)resp->data;
		resp->exp_len = host_response->data_len + sizeof(*host_response);
	}

	/* If driver received response header and payload from EC, wake up the wait queue. */
	if (resp->size >= sizeof(*host_response) && resp->size == resp->exp_len) {
		resp->status = 1;
		wake_up(&resp->wait_queue);
	}

	return count;
}

static int cros_ec_uart_pkt_xfer(struct cros_ec_device *ec_dev,
				 struct cros_ec_command *ec_msg)
{
	struct cros_ec_uart *ec_uart = ec_dev->priv;
	struct serdev_device *serdev = ec_uart->serdev;
	struct response_info *resp = &ec_uart->response;
	struct ec_host_response *host_response;
	unsigned int len;
	int ret, i;
	u8 sum;

	len = cros_ec_prepare_tx(ec_dev, ec_msg);
	dev_dbg(ec_dev->dev, "Prepared len=%d\n", len);

	/* Setup for incoming response */
	resp->data = ec_dev->din;
	resp->max_size = ec_dev->din_size;
	resp->size = 0;

Annotation

Implementation Notes