#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/sysfs.h>
#include <linux/atomic.h>
#define GPIO_KEY 5 // 按键连接的GPIO编号
#define DEV_NAME "key_device" // 设备名
#define CLASS_NAME "key_drv" // 设备类名
// 设备结构体
struct key_dev {
int gpio; // GPIO编号
int irq; // 中断号
atomic_t count; // 按键次数(原子变量)
struct device *dev; // 设备对象
};
static struct key_dev *key_device;
static struct class *key_class;
// sysfs的show方法:向应用层返回按键次数
static ssize_t count_show(struct device *dev, struct device_attribute *attr, char *buf) {
struct key_dev *kdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", atomic_read(&kdev->count));
}
// 定义sysfs属性
static DEVICE_ATTR(count, S_IRUGO, count_show, NULL);
// 中断处理函数:按键按下时调用
static irqreturn_t key_irq_handler(int irq, void *dev_id) {
struct key_dev *kdev = (struct key_dev *)dev_id;
atomic_inc(&kdev->count); // 按键次数+1
return IRQ_HANDLED;
}
// 驱动初始化函数
static int __init key_drv_init(void) {
int ret;
// 分配设备结构体内存
key_device = kmalloc(sizeof(struct key_dev), GFP_KERNEL);
if (!key_device) {
return -ENOMEM;
}
// 初始化设备结构体
key_device->gpio = GPIO_KEY;
atomic_set(&key_device->count, 0); // 初始次数为0
// 申请GPIO
ret = gpio_request(key_device->gpio, DEV_NAME);
if (ret) {
printk("gpio_request failed: %d\n", ret);
kfree(key_device);
return ret;
}
// 设置GPIO为输入
gpio_direction_input(key_device->gpio);
// 获取中断号
key_device->irq = gpio_to_irq(key_device->gpio);
if (key_device->irq < 0) {
printk("gpio_to_irq failed: %d\n", key_device->irq);
gpio_free(key_device->gpio);
kfree(key_device);
return key_device->irq;
}
// 注册中断(下降沿触发,传递设备结构体作为参数)
ret = request_irq(key_device->irq, key_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_SHARED,
DEV_NAME, key_device);
if (ret) {
printk("request_irq failed: %d\n", ret);
gpio_free(key_device->gpio);
kfree(key_device);
return ret;
}
// 创建设备类
key_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(key_class)) {
printk("class_create failed\n");
free_irq(key_device->irq, key_device);
gpio_free(key_device->gpio);
kfree(key_device);
return PTR_ERR(key_class);
}
// 创建设备节点
key_device->dev = device_create(key_class, NULL, MKDEV(0, 0), key_device, DEV_NAME);
if (IS_ERR(key_device->dev)) {
printk("device_create failed\n");
class_destroy(key_class);
free_irq(key_device->irq, key_device);
gpio_free(key_device->gpio);
kfree(key_device);
return PTR_ERR(key_device->dev);
}
// 创建sysfs属性文件
ret = device_create_file(key_device->dev, &dev_attr_count);
if (ret) {
printk("device_create_file failed: %d\n", ret);
device_destroy(key_class, MKDEV(0, 0));
class_destroy(key_class);
free_irq(key_device->irq, key_device);
gpio_free(key_device->gpio);
kfree(key_device);
return ret;
}
printk("key driver init success\n");
return 0;
}
// 驱动卸载函数
static void __exit key_drv_exit(void) {
// 移除sysfs文件
device_remove_file(key_device->dev, &dev_attr_count);
// 销毁设备
device_destroy(key_class, MKDEV(0, 0));
// 销毁设备类
class_destroy(key_class);
// 释放中断
free_irq(key_device->irq, key_device);
// 释放GPIO
gpio_free(key_device->gpio);
// 释放设备结构体内存
kfree(key_device);
printk("key driver exit success\n");
}
module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("牛马程序员");
MODULE_DESCRIPTION("GPIO Key Interrupt Driver");