drivers/input/joystick/zhenhua.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/joystick/zhenhua.c
Extension
.c
Size
4973 bytes
Lines
203
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 zhenhua {
	struct input_dev *dev;
	int idx;
	unsigned char data[ZHENHUA_MAX_LENGTH];
	char phys[32];
};

/*
 * zhenhua_process_packet() decodes packets the driver receives from the
 * RC transmitter. It updates the data accordingly.
 */

static void zhenhua_process_packet(struct zhenhua *zhenhua)
{
	struct input_dev *dev = zhenhua->dev;
	unsigned char *data = zhenhua->data;

	input_report_abs(dev, ABS_Y, data[1]);
	input_report_abs(dev, ABS_X, data[2]);
	input_report_abs(dev, ABS_RZ, data[3]);
	input_report_abs(dev, ABS_Z, data[4]);

	input_sync(dev);
}

/*
 * zhenhua_interrupt() is called by the low level driver when characters
 * are ready for us. We then buffer them for further processing, or call the
 * packet processing routine.
 */

static irqreturn_t zhenhua_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
{
	struct zhenhua *zhenhua = serio_get_drvdata(serio);

	/* All Zhen Hua packets are 5 bytes. The fact that the first byte
	 * is allways 0xf7 and all others are in range 0x32 - 0xc8 (50-200)
	 * can be used to check and regain sync. */

	if (data == 0xef)
		zhenhua->idx = 0;	/* this byte starts a new packet */
	else if (zhenhua->idx == 0)
		return IRQ_HANDLED;	/* wrong MSB -- ignore this byte */

	if (zhenhua->idx < ZHENHUA_MAX_LENGTH)
		zhenhua->data[zhenhua->idx++] = bitrev8(data);

	if (zhenhua->idx == ZHENHUA_MAX_LENGTH) {
		zhenhua_process_packet(zhenhua);
		zhenhua->idx = 0;
	}

	return IRQ_HANDLED;
}

/*
 * zhenhua_disconnect() is the opposite of zhenhua_connect()
 */

static void zhenhua_disconnect(struct serio *serio)
{
	struct zhenhua *zhenhua = serio_get_drvdata(serio);

	serio_close(serio);
	serio_set_drvdata(serio, NULL);
	input_unregister_device(zhenhua->dev);
	kfree(zhenhua);
}

/*
 * zhenhua_connect() is the routine that is called when someone adds a
 * new serio device. It looks for the Twiddler, and if found, registers
 * it as an input device.
 */

static int zhenhua_connect(struct serio *serio, struct serio_driver *drv)
{
	struct zhenhua *zhenhua;
	struct input_dev *input_dev;
	int err = -ENOMEM;

	zhenhua = kzalloc_obj(*zhenhua);
	input_dev = input_allocate_device();
	if (!zhenhua || !input_dev)
		goto fail1;

	zhenhua->dev = input_dev;
	snprintf(zhenhua->phys, sizeof(zhenhua->phys), "%s/input0", serio->phys);

	input_dev->name = "Zhen Hua 5-byte device";

Annotation

Implementation Notes