drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c

Source file repositories/reference/linux-study-clean/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c

File Facts

System
Linux kernel
Corpus path
drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c
Extension
.c
Size
7251 bytes
Lines
266
Domain
Driver Families
Bucket
drivers/hid
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

if (append_data_reg) {
			memcpy(write_buf + offset, &qcdev->dev_desc.data_reg, HIDI2C_REG_LEN);
			offset += HIDI2C_REG_LEN;
		}
	} else {
		memcpy(write_buf, &qcdev->dev_desc.output_reg, HIDI2C_REG_LEN);
		offset += HIDI2C_REG_LEN;
	}

	if (data && data_len) {
		put_unaligned_le16(data_len + HIDI2C_LENGTH_LEN, write_buf + offset);
		offset += HIDI2C_LENGTH_LEN;
		memcpy(write_buf + offset, data, data_len);
	}

	return buf_len;
}

static size_t quicki2c_encode_cmd(struct quicki2c_device *qcdev, u32 *cmd_buf,
				  u8 opcode, u8 report_type, u8 report_id)
{
	size_t cmd_len;

	*cmd_buf = FIELD_PREP(HIDI2C_CMD_OPCODE, opcode) |
		   FIELD_PREP(HIDI2C_CMD_REPORT_TYPE, report_type);

	if (report_id < HIDI2C_CMD_MAX_RI) {
		*cmd_buf |= FIELD_PREP(HIDI2C_CMD_REPORT_ID, report_id);
		cmd_len = HIDI2C_CMD_LEN;
	} else {
		*cmd_buf |= FIELD_PREP(HIDI2C_CMD_REPORT_ID, HIDI2C_CMD_MAX_RI) |
			    FIELD_PREP(HIDI2C_CMD_3RD_BYTE, report_id);
		cmd_len = HIDI2C_CMD_LEN_OPT;
	}

	return cmd_len;
}

static int write_cmd_to_txdma(struct quicki2c_device *qcdev, int opcode,
			      int report_type, int report_id, u8 *buf, size_t buf_len)
{
	size_t cmd_len;
	ssize_t len;
	u32 cmd;

	cmd_len = quicki2c_encode_cmd(qcdev, &cmd, opcode, report_type, report_id);

	len = quicki2c_init_write_buf(qcdev, cmd, cmd_len, buf ? true : false, buf,
				      buf_len, qcdev->report_buf, qcdev->report_len);
	if (len < 0)
		return len;

	return thc_dma_write(qcdev->thc_hw, qcdev->report_buf, len);
}

int quicki2c_set_power(struct quicki2c_device *qcdev, enum hidi2c_power_state power_state)
{
	return write_cmd_to_txdma(qcdev, HIDI2C_SET_POWER, HIDI2C_RESERVED, power_state, NULL, 0);
}

int quicki2c_get_device_descriptor(struct quicki2c_device *qcdev)
{
	u32 read_len = 0;
	int ret;

	ret = thc_tic_pio_write_and_read(qcdev->thc_hw, qcdev->hid_desc_addr,
					 HIDI2C_REG_LEN, NULL, HIDI2C_DEV_DESC_LEN,
					 &read_len, (u32 *)&qcdev->dev_desc);
	if (ret || HIDI2C_DEV_DESC_LEN != read_len) {
		dev_err_once(qcdev->dev, "Get device descriptor failed, ret %d, read len %u\n",
			     ret, read_len);
		return -EIO;
	}

	if (le16_to_cpu(qcdev->dev_desc.bcd_ver) != HIDI2C_HID_DESC_BCDVERSION)
		return -EOPNOTSUPP;

	return 0;
}

int quicki2c_get_report_descriptor(struct quicki2c_device *qcdev)
{
	u16 desc_reg = le16_to_cpu(qcdev->dev_desc.report_desc_reg);
	size_t read_len = le16_to_cpu(qcdev->dev_desc.report_desc_len);
	u32 prd_len = read_len;

	return thc_swdma_read(qcdev->thc_hw, (u8 *)&desc_reg, HIDI2C_REG_LEN,
			      &prd_len, qcdev->report_descriptor, &read_len);
}

Annotation

Implementation Notes