drivers/input/tablet/pegasus_notetaker.c

Source file repositories/reference/linux-study-clean/drivers/input/tablet/pegasus_notetaker.c

File Facts

System
Linux kernel
Corpus path
drivers/input/tablet/pegasus_notetaker.c
Extension
.c
Size
11353 bytes
Lines
491
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 pegasus {
	unsigned char *data;
	u8 data_len;
	dma_addr_t data_dma;
	struct input_dev *dev;
	struct usb_device *usbdev;
	struct usb_interface *intf;
	struct urb *irq;

	/* serialize access to open/suspend */
	struct mutex pm_mutex;
	bool is_open;

	char name[128];
	char phys[64];
	struct work_struct init;
};

static int pegasus_control_msg(struct pegasus *pegasus, u8 *data, int len)
{
	const int sizeof_buf = len + 2;
	int result;
	int error;
	u8 *cmd_buf;

	cmd_buf = kmalloc(sizeof_buf, GFP_KERNEL);
	if (!cmd_buf)
		return -ENOMEM;

	cmd_buf[0] = NOTETAKER_REPORT_ID;
	cmd_buf[1] = len;
	memcpy(cmd_buf + 2, data, len);

	result = usb_control_msg(pegasus->usbdev,
				 usb_sndctrlpipe(pegasus->usbdev, 0),
				 HID_REQ_SET_REPORT,
				 USB_TYPE_VENDOR | USB_DIR_OUT,
				 0, 0, cmd_buf, sizeof_buf,
				 USB_CTRL_SET_TIMEOUT);

	kfree(cmd_buf);

	if (unlikely(result != sizeof_buf)) {
		error = result < 0 ? result : -EIO;
		dev_err(&pegasus->usbdev->dev, "control msg error: %d\n",
			error);
		return error;
	}

	return 0;
}

static int pegasus_set_mode(struct pegasus *pegasus, u8 mode, u8 led)
{
	u8 cmd[] = { NOTETAKER_SET_CMD, NOTETAKER_SET_MODE, led, mode };

	return pegasus_control_msg(pegasus, cmd, sizeof(cmd));
}

static void pegasus_parse_packet(struct pegasus *pegasus)
{
	unsigned char *data = pegasus->data;
	struct input_dev *dev = pegasus->dev;
	u16 x, y;

	switch (data[0]) {
	case SPECIAL_COMMAND:
		/* device button pressed */
		if (data[1] == BUTTON_PRESSED)
			schedule_work(&pegasus->init);

		break;

	/* xy data */
	case BATTERY_LOW:
		dev_warn_once(&dev->dev, "Pen battery low\n");
		fallthrough;

	case BATTERY_NO_REPORT:
	case BATTERY_GOOD:
		x = le16_to_cpup((__le16 *)&data[2]);
		y = le16_to_cpup((__le16 *)&data[4]);

		/* pen-up event */
		if (x == 0 && y == 0)
			break;

		input_report_key(dev, BTN_TOUCH, data[1] & PEN_TIP);
		input_report_key(dev, BTN_RIGHT, data[1] & PEN_BUTTON_PRESSED);
		input_report_key(dev, BTN_TOOL_PEN, 1);

Annotation

Implementation Notes