drivers/input/joystick/adc-joystick.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/joystick/adc-joystick.c
Extension
.c
Size
7796 bytes
Lines
332
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 adc_joystick_axis {
	u32 code;
	bool inverted;
};

struct adc_joystick {
	struct input_dev *input;
	struct iio_cb_buffer *buffer;
	struct iio_channel *chans;
	unsigned int num_chans;
	struct adc_joystick_axis axes[] __counted_by(num_chans);
};

static int adc_joystick_invert(struct input_dev *dev,
			       unsigned int axis, int val)
{
	int min = input_abs_get_min(dev, axis);
	int max = input_abs_get_max(dev, axis);

	return (max + min) - val;
}

static void adc_joystick_poll(struct input_dev *input)
{
	struct adc_joystick *joy = input_get_drvdata(input);
	int i, val, ret;

	for (i = 0; i < joy->num_chans; i++) {
		ret = iio_read_channel_raw(&joy->chans[i], &val);
		if (ret < 0)
			return;
		if (joy->axes[i].inverted)
			val = adc_joystick_invert(input, i, val);
		input_report_abs(input, joy->axes[i].code, val);
	}
	input_sync(input);
}

static int adc_joystick_handle(const void *data, void *private)
{
	struct adc_joystick *joy = private;
	enum iio_endian endianness;
	int bytes, msb, val, idx, i;
	const u16 *data_u16;
	bool sign;

	bytes = joy->chans[0].channel->scan_type.storagebits >> 3;

	for (i = 0; i < joy->num_chans; ++i) {
		idx = joy->chans[i].channel->scan_index;
		endianness = joy->chans[i].channel->scan_type.endianness;
		msb = joy->chans[i].channel->scan_type.realbits - 1;
		sign = tolower(joy->chans[i].channel->scan_type.sign) == 's';

		switch (bytes) {
		case 1:
			val = ((const u8 *)data)[idx];
			break;
		case 2:
			data_u16 = (const u16 *)data + idx;

			/*
			 * Data is aligned to the sample size by IIO core.
			 * Call `get_unaligned_xe16` to hide type casting.
			 */
			if (endianness == IIO_BE)
				val = get_unaligned_be16(data_u16);
			else if (endianness == IIO_LE)
				val = get_unaligned_le16(data_u16);
			else /* IIO_CPU */
				val = *data_u16;
			break;
		default:
			return -EINVAL;
		}

		val >>= joy->chans[i].channel->scan_type.shift;
		if (sign)
			val = sign_extend32(val, msb);
		else
			val &= GENMASK(msb, 0);
		if (joy->axes[i].inverted)
			val = adc_joystick_invert(joy->input, i, val);
		input_report_abs(joy->input, joy->axes[i].code, val);
	}

	input_sync(joy->input);

	return 0;
}

Annotation

Implementation Notes