drivers/input/mouse/byd.c

Source file repositories/reference/linux-study-clean/drivers/input/mouse/byd.c

File Facts

System
Linux kernel
Corpus path
drivers/input/mouse/byd.c
Extension
.c
Size
12902 bytes
Lines
508
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 byd_data {
	struct timer_list timer;
	struct psmouse *psmouse;
	s32 abs_x;
	s32 abs_y;
	typeof(jiffies) last_touch_time;
	bool btn_left;
	bool btn_right;
	bool touch;
};

static void byd_report_input(struct psmouse *psmouse)
{
	struct byd_data *priv = psmouse->private;
	struct input_dev *dev = psmouse->dev;

	input_report_key(dev, BTN_TOUCH, priv->touch);
	input_report_key(dev, BTN_TOOL_FINGER, priv->touch);

	input_report_abs(dev, ABS_X, priv->abs_x);
	input_report_abs(dev, ABS_Y, priv->abs_y);
	input_report_key(dev, BTN_LEFT, priv->btn_left);
	input_report_key(dev, BTN_RIGHT, priv->btn_right);

	input_sync(dev);
}

static void byd_clear_touch(struct timer_list *t)
{
	struct byd_data *priv = timer_container_of(priv, t, timer);
	struct psmouse *psmouse = priv->psmouse;

	guard(serio_pause_rx)(psmouse->ps2dev.serio);

	priv->touch = false;

	byd_report_input(psmouse);

	/*
	 * Move cursor back to center of pad when we lose touch - this
	 * specifically improves user experience when moving cursor with one
	 * finger, and pressing a button with another.
	 */
	priv->abs_x = BYD_PAD_WIDTH / 2;
	priv->abs_y = BYD_PAD_HEIGHT / 2;
}

static psmouse_ret_t byd_process_byte(struct psmouse *psmouse)
{
	struct byd_data *priv = psmouse->private;
	u8 *pkt = psmouse->packet;

	if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) {
		psmouse_warn(psmouse, "Always_1 bit not 1. pkt[0] = %02x\n",
			     pkt[0]);
		return PSMOUSE_BAD_DATA;
	}

	if (psmouse->pktcnt < psmouse->pktsize)
		return PSMOUSE_GOOD_DATA;

	/* Otherwise, a full packet has been received */
	switch (pkt[3]) {
	case BYD_PACKET_ABSOLUTE:
		/* Only use absolute packets for the start of movement. */
		if (!priv->touch) {
			/* needed to detect tap */
			typeof(jiffies) tap_time =
				priv->last_touch_time + BYD_TOUCH_TIMEOUT;
			priv->touch = time_after(jiffies, tap_time);

			/* init abs position */
			priv->abs_x = pkt[1] * (BYD_PAD_WIDTH / 256);
			priv->abs_y = (255 - pkt[2]) * (BYD_PAD_HEIGHT / 256);
		}
		break;
	case BYD_PACKET_RELATIVE: {
		/* Standard packet */
		/* Sign-extend if a sign bit is set. */
		u32 signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0;
		u32 signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0;
		s32 dx = signx | (int) pkt[1];
		s32 dy = signy | (int) pkt[2];

		/* Update position based on velocity */
		priv->abs_x += dx * BYD_DT;
		priv->abs_y -= dy * BYD_DT;

		priv->touch = true;
		break;

Annotation

Implementation Notes