drivers/input/touchscreen/sis_i2c.c

Source file repositories/reference/linux-study-clean/drivers/input/touchscreen/sis_i2c.c

File Facts

System
Linux kernel
Corpus path
drivers/input/touchscreen/sis_i2c.c
Extension
.c
Size
9872 bytes
Lines
396
Domain
Driver Families
Bucket
drivers/input
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 sis_ts_data {
	struct i2c_client *client;
	struct input_dev *input;

	struct gpio_desc *attn_gpio;
	struct gpio_desc *reset_gpio;

	u8 packet[SIS_MAX_PACKET_SIZE];
};

static int sis_read_packet(struct i2c_client *client, u8 *buf,
			   unsigned int *num_contacts,
			   unsigned int *contact_size)
{
	int count_idx;
	int ret;
	u16 len;
	u16 crc, pkg_crc;
	u8 report_id;

	ret = i2c_master_recv(client, buf, SIS_MAX_PACKET_SIZE);
	if (ret <= 0)
		return -EIO;

	len = get_unaligned_le16(&buf[SIS_PKT_LEN_OFFSET]);
	if (len > SIS_MAX_PACKET_SIZE) {
		dev_err(&client->dev,
			"%s: invalid packet length (%d vs %d)\n",
			__func__, len, SIS_MAX_PACKET_SIZE);
		return -E2BIG;
	}

	if (len < 10)
		return -EINVAL;

	report_id = buf[SIS_PKT_REPORT_OFFSET];
	count_idx  = len - 1;
	*contact_size = SIS_BASE_LEN_PER_CONTACT;

	if (report_id != SIS_ALL_IN_ONE_PACKAGE) {
		if (SIS_PKT_IS_TOUCH(report_id)) {
			/*
			 * Calculate CRC ignoring packet length
			 * in the beginning and CRC transmitted
			 * at the end of the packet.
			 */
			crc = crc_itu_t(0, buf + 2, len - 2 - 2);
			pkg_crc = get_unaligned_le16(&buf[len - 2]);

			if (crc != pkg_crc) {
				dev_err(&client->dev,
					"%s: CRC Error (%d vs %d)\n",
					__func__, crc, pkg_crc);
				return -EINVAL;
			}

			count_idx -= 2;

		} else if (!SIS_PKT_IS_HIDI2C(report_id)) {
			dev_err(&client->dev,
				"%s: invalid packet ID %#02x\n",
				__func__, report_id);
			return -EINVAL;
		}

		if (SIS_PKT_HAS_SCANTIME(report_id))
			count_idx -= SIS_SCAN_TIME_LEN;

		if (SIS_PKT_HAS_AREA(report_id))
			*contact_size += SIS_AREA_LEN_PER_CONTACT;
		if (SIS_PKT_HAS_PRESSURE(report_id))
			*contact_size += SIS_PRESSURE_LEN_PER_CONTACT;
	}

	*num_contacts = buf[count_idx];
	return 0;
}

static int sis_ts_report_contact(struct sis_ts_data *ts, const u8 *data, u8 id)
{
	struct input_dev *input = ts->input;
	int slot;
	u8 status = data[SIS_CONTACT_STATUS_OFFSET];
	u8 pressure;
	u8 height, width;
	u16 x, y;

	if (status != SIS_STATUS_DOWN && status != SIS_STATUS_UP) {
		dev_err(&ts->client->dev, "Unexpected touch status: %#02x\n",
			data[SIS_CONTACT_STATUS_OFFSET]);

Annotation

Implementation Notes