drivers/input/joystick/iforce/iforce-serio.c

Source file repositories/reference/linux-study-clean/drivers/input/joystick/iforce/iforce-serio.c

File Facts

System
Linux kernel
Corpus path
drivers/input/joystick/iforce/iforce-serio.c
Extension
.c
Size
5924 bytes
Lines
252
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 iforce_serio {
	struct iforce iforce;

	struct serio *serio;
	int idx, pkt, len, id;
	u8 csum;
	u8 expect_packet;
	u8 cmd_response[IFORCE_MAX_LENGTH];
	u8 cmd_response_len;
	u8 data_in[IFORCE_MAX_LENGTH];
};

static void iforce_serio_xmit(struct iforce *iforce)
{
	struct iforce_serio *iforce_serio = container_of(iforce,
							 struct iforce_serio,
							 iforce);
	unsigned char cs;
	int i;

	if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
		set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags);
		return;
	}

	guard(spinlock_irqsave)(&iforce->xmit_lock);

	do {
		if (iforce->xmit.head == iforce->xmit.tail)
			break;

		cs = 0x2b;

		serio_write(iforce_serio->serio, 0x2b);

		serio_write(iforce_serio->serio,
			    iforce->xmit.buf[iforce->xmit.tail]);
		cs ^= iforce->xmit.buf[iforce->xmit.tail];
		XMIT_INC(iforce->xmit.tail, 1);

		for (i = iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
			serio_write(iforce_serio->serio,
				    iforce->xmit.buf[iforce->xmit.tail]);
			cs ^= iforce->xmit.buf[iforce->xmit.tail];
			XMIT_INC(iforce->xmit.tail, 1);
		}

		serio_write(iforce_serio->serio, cs);

	} while (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags));

	iforce_clear_xmit_and_wake(iforce);
}

static int iforce_serio_get_id(struct iforce *iforce, u8 id,
			       u8 *response_data, size_t *response_len)
{
	struct iforce_serio *iforce_serio = container_of(iforce,
							 struct iforce_serio,
							 iforce);

	iforce_serio->expect_packet = HI(FF_CMD_QUERY);
	iforce_serio->cmd_response_len = 0;

	iforce_send_packet(iforce, FF_CMD_QUERY, &id);

	wait_event_interruptible_timeout(iforce->wait,
					 !iforce_serio->expect_packet, HZ);

	if (iforce_serio->expect_packet) {
		iforce_serio->expect_packet = 0;
		return -ETIMEDOUT;
	}

	if (iforce_serio->cmd_response[0] != id)
		return -EIO;

	memcpy(response_data, iforce_serio->cmd_response,
	       iforce_serio->cmd_response_len);
	*response_len = iforce_serio->cmd_response_len;

	return 0;
}

static int iforce_serio_start_io(struct iforce *iforce)
{
	/* No special handling required */
	return 0;
}

Annotation

Implementation Notes