From 7e57df0d3b39fb64fb278f433292a378e1fd0515 Mon Sep 17 00:00:00 2001 From: Nick Mello Date: Sat, 7 Feb 2026 00:21:31 -0600 Subject: [PATCH] initial commit --- Kconfig | 4 ++ Makefile | 13 +++++ gpio-keyboard-driver.c | 128 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 Kconfig create mode 100644 Makefile create mode 100644 gpio-keyboard-driver.c diff --git a/Kconfig b/Kconfig new file mode 100644 index 0000000..655c166 --- /dev/null +++ b/Kconfig @@ -0,0 +1,4 @@ +config GPIO_KEYBOARD_DRIVER + tristate "gpio-keyboard-driver" + help + TODO write this diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2672b4a --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +# Makefile for building my_driver kernel module + +KERNEL_DIR ?= $(PWD) +KERNEL_BUILD ?= $(KERNEL_DIR)/build + +obj-m += gpio-keyboard-driver.o + +# The default target +all: + $(MAKE) -C $(KERNEL_BUILD) M=$(PWD) modules + +clean: + $(MAKE) -C $(KERNEL_BUILD) M=$(PWD) clean diff --git a/gpio-keyboard-driver.c b/gpio-keyboard-driver.c new file mode 100644 index 0000000..ca3fd05 --- /dev/null +++ b/gpio-keyboard-driver.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct input_dev *kbd_dev; +static int gpio_num; +static int irq_num; + +static irqreturn_t gpio_irq_handler(int irq, void *dev_id) +{ + int state = gpio_get_value(gpio_num); + + /* Active low button */ + if (state == 0) { + input_report_key(kbd_dev, KEY_A, 1); + input_sync(kbd_dev); + } else { + input_report_key(kbd_dev, KEY_A, 0); + input_sync(kbd_dev); + } + + return IRQ_HANDLED; +} + +static int gpio_kbd_probe(struct platform_device *pdev) +{ + int ret; + + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + if (!np) + return -EINVAL; + + /* Read GPIO from DT */ + gpio_num = of_get_named_gpio(np, "gpios", 0); + if (gpio_num < 0) { + dev_err(dev, "Failed to get GPIO from DT\n"); + return gpio_num; + } + + ret = gpio_request(gpio_num, "gpio_kbd_button"); + if (ret) { + dev_err(dev, "Failed to request GPIO\n"); + return ret; + } + + gpio_direction_input(gpio_num); + + /* Allocate input device */ + kbd_dev = input_allocate_device(); + if (!kbd_dev) { + dev_err(dev, "Failed to allocate input device\n"); + gpio_free(gpio_num); + return -ENOMEM; + } + + kbd_dev->name = "GPIO Keyboard Device"; + kbd_dev->evbit[0] = BIT_MASK(EV_KEY); + set_bit(KEY_A, kbd_dev->keybit); + + ret = input_register_device(kbd_dev); + if (ret) { + dev_err(dev, "Failed to register input device\n"); + input_free_device(kbd_dev); + gpio_free(gpio_num); + return ret; + } + + /* Get IRQ from DT */ + irq_num = of_irq_get(np, 0); + if (irq_num < 0) { + dev_err(dev, "Failed to get IRQ from DT\n"); + input_unregister_device(kbd_dev); + gpio_free(gpio_num); + return irq_num; + } + + ret = request_irq(irq_num, + gpio_irq_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "gpio_kbd_irq", + NULL); + + if (ret) { + dev_err(dev, "Failed to request IRQ\n"); + input_unregister_device(kbd_dev); + gpio_free(gpio_num); + return ret; + } + + dev_info(dev, "GPIO keyboard driver loaded\n"); + return 0; +} + +static void gpio_kbd_remove(struct platform_device *pdev) +{ + free_irq(irq_num, NULL); + input_unregister_device(kbd_dev); + gpio_free(gpio_num); +} + +static const struct of_device_id gpio_kbd_of_match[] = { + { .compatible = "arcade,gpio-keyboard" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpio_kbd_of_match); + +static struct platform_driver gpio_kbd_driver = { + .probe = gpio_kbd_probe, + .remove = gpio_kbd_remove, + .driver = { + .name = "gpio-keyboard", + .of_match_table = gpio_kbd_of_match, + }, +}; + +module_platform_driver(gpio_kbd_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nicholas Mello"); +MODULE_DESCRIPTION("GPIO-based virtual keyboard driver using Device Tree");