drivers/input/keyboard/charlieplex_keypad.c

Source file repositories/reference/linux-study-clean/drivers/input/keyboard/charlieplex_keypad.c

File Facts

System
Linux kernel
Corpus path
drivers/input/keyboard/charlieplex_keypad.c
Extension
.c
Size
6350 bytes
Lines
233
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 charlieplex_keypad {
	struct input_dev *input_dev;
	struct gpio_descs *line_gpios;
	unsigned int nlines;
	unsigned int settling_time_us;
	unsigned int debounce_threshold;
	unsigned int debounce_count;
	int debounce_code;
	int current_code;
};

static void charlieplex_keypad_report_key(struct input_dev *input)
{
	struct charlieplex_keypad *keypad = input_get_drvdata(input);
	const unsigned short *keycodes = input->keycode;

	if (keypad->current_code > 0) {
		input_event(input, EV_MSC, MSC_SCAN, keypad->current_code);
		input_report_key(input, keycodes[keypad->current_code], 0);
		input_sync(input);
	}

	if (keypad->debounce_code) {
		input_event(input, EV_MSC, MSC_SCAN, keypad->debounce_code);
		input_report_key(input, keycodes[keypad->debounce_code], 1);
		input_sync(input);
	}

	keypad->current_code = keypad->debounce_code;
}

static void charlieplex_keypad_check_switch_change(struct input_dev *input,
						   unsigned int code)
{
	struct charlieplex_keypad *keypad = input_get_drvdata(input);

	if (code != keypad->debounce_code) {
		keypad->debounce_count = 0;
		keypad->debounce_code = code;
	}

	if (keypad->debounce_code != keypad->current_code) {
		if (keypad->debounce_count++ >= keypad->debounce_threshold)
			charlieplex_keypad_report_key(input);
	}
}

static int charlieplex_keypad_scan_line(struct charlieplex_keypad *keypad,
					unsigned int oline)
{
	struct gpio_descs *line_gpios = keypad->line_gpios;
	DECLARE_BITMAP(values, MATRIX_MAX_ROWS);
	int err;

	/* Activate only one line as output at a time. */
	gpiod_direction_output(line_gpios->desc[oline], 1);

	if (keypad->settling_time_us)
		fsleep(keypad->settling_time_us);

	/* Read input on all other lines. */
	err = gpiod_get_array_value_cansleep(line_gpios->ndescs, line_gpios->desc,
					     line_gpios->info, values);

	gpiod_direction_input(line_gpios->desc[oline]);

	if (err)
		return err;

	for (unsigned int iline = 0; iline < keypad->nlines; iline++) {
		if (iline == oline)
			continue; /* Do not read active output line. */

		/* Check if GPIO is asserted. */
		if (test_bit(iline, values))
			return MATRIX_SCAN_CODE(oline, iline,
						get_count_order(keypad->nlines));
	}

	return 0;
}

static void charlieplex_keypad_poll(struct input_dev *input)
{
	struct charlieplex_keypad *keypad = input_get_drvdata(input);
	int code = 0;

	for (unsigned int oline = 0; oline < keypad->nlines; oline++) {
		code = charlieplex_keypad_scan_line(keypad, oline);
		if (code != 0)

Annotation

Implementation Notes