华清远见上海中心22071班
三个按键实现按键中断,
key1->led1
key2->led2
key3->led3
按键按一下灯亮,再按一下灯灭
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#define CNAME "myled"
int major;
int minor = 0;
int count = 3;
int irqnum_key1;
int irqnum_key2;
int irqnum_key3;
struct cdev *cdev;
struct class *cls;
struct device *dvc;
struct device_node *lednode;
struct device_node *irqnode;
struct gpio_desc *topled1;
struct gpio_desc *topled2;
struct gpio_desc *topled3;
// myleds
// {
// topled1 = <&gpioe 10 0>;
// topled2 = <&gpiof 10 0>;
// topled3 = <&gpioe 8 0>;
// };
// myirq
// {
// interrupt-parent = <&gpiof>;
// interrupts = <7 0>, <8 0>, <9 0>; //第一个成员指的是gpio编号,第二个成员表示触发方式,0表示默认属性
// };
struct file_operations fops;
irqreturn_t irq_handler_key1(int irqno, void *dev)
{
gpiod_set_value(topled3, !gpiod_get_value(topled3));
return IRQ_HANDLED;
}
irqreturn_t irq_handler_key2(int irqno, void *dev)
{
gpiod_set_value(topled2, !gpiod_get_value(topled2));
return IRQ_HANDLED;
}
irqreturn_t irq_handler_key3(int irqno, void *dev)
{
gpiod_set_value(topled1, !gpiod_get_value(topled1));
return IRQ_HANDLED;
}
static int __init led_init(void)
{
int res, i;
dev_t devt;
//分配cdev结构
cdev = cdev_alloc();
if (NULL == cdev)
{
printk("申请空间失败\n");
res = -EIO;
goto ERR1;
}
//初始化cdev结构体
cdev_init(cdev, &fops);
//动态注册字符设备编号
res = alloc_chrdev_region(&devt, 0, count, CNAME);
if (res)
{
printk("动态注册字符设备编号失败(err %d)\n", -res);
goto ERR2;
}
major = MAJOR(devt);
minor = MINOR(devt);
//向系统中添加字符设备
res = cdev_add(cdev, devt, count);
if (res)
{
printk("系统添加字符设备失败(err %d)\n", -res);
goto ERR3;
}
//上传目录
cls = class_create(THIS_MODULE, CNAME);
if (IS_ERR(cls))
{
printk("上传目录失败 (err %ld)\n", PTR_ERR(cls));
res = PTR_ERR(cls);
goto ERR4;
}
//上传节点
for (i = 0; i < count; i++)
{
dvc = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
if (IS_ERR(dvc))
{
printk("节点上传失败 (err %ld)\n", PTR_ERR(dvc));
res = PTR_ERR(dvc);
goto ERR5;
}
}
lednode = of_find_node_by_path("/myleds");
if (NULL == lednode)
{
printk("寻找设备树节点失败\n");
res = -EFAULT;
goto ERR5;
}
//申请GPIO号
topled1 = gpiod_get_from_of_node(lednode, "topled1", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(topled1))
{
printk("topled1 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled1));
res = PTR_ERR(topled1);
goto ERR5;
}
topled2 = gpiod_get_from_of_node(lednode, "topled2", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(topled2))
{
printk("topled2 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled2));
res = PTR_ERR(topled2);
goto ERR5;
}
topled3 = gpiod_get_from_of_node(lednode, "topled3", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(topled3))
{
printk("topled3 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled3));
res = PTR_ERR(topled3);
goto ERR5;
}
//设置相对应的gpio引脚为输出模式
gpiod_direction_output(topled1, 0);
gpiod_direction_output(topled2, 0);
gpiod_direction_output(topled3, 0);
//获取中断设备树节点
irqnode = of_find_node_by_path("/myirq");
if (NULL == lednode)
{
printk("寻找设备树节点失败\n");
res = -EFAULT;
goto ERR5;
}
//从节点信息中获取KEY1软中断号
irqnum_key1 = irq_of_parse_and_map(irqnode, 2);
if (irqnum_key1 == 0)
{
printk("key1 获取软中断号失败\n");
res = -EINVAL;
goto ERR5;
}
//从节点信息中获取KEY2软中断号
irqnum_key2 = irq_of_parse_and_map(irqnode, 0);
if (irqnum_key2 == 0)
{
printk("key2 获取软中断号失败\n");
res = -EINVAL;
goto ERR5;
}
//从节点信息中获取KEY3软中断号
irqnum_key3 = irq_of_parse_and_map(irqnode, 1);
if (irqnum_key3 == 0)
{
printk("key3 获取软中断号失败\n");
res = -EINVAL;
goto ERR5;
}
//将需要使用的软中断号key1注册进内核
res = request_irq(irqnum_key1, irq_handler_key1, IRQF_TRIGGER_FALLING, "key1_inte", NULL);
if (res)
{
printk("key1 注册失败\n");
return -EINVAL;
}
//将需要使用的软中断号key2注册进内核
res = request_irq(irqnum_key2, irq_handler_key2, IRQF_TRIGGER_FALLING, "key2_inte", NULL);
if (res)
{
printk("key2 注册失败\n");
return -EINVAL;
}
//将需要使用的软中断号key3注册进内核
res = request_irq(irqnum_key3, irq_handler_key3, IRQF_TRIGGER_FALLING, "key3_inte", NULL);
if (res)
{
printk("key3 注册失败\n");
return -EINVAL;
}
return 0;
ERR5:
for (--i; i >= 0; i--)
{
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
ERR4:
cdev_del(cdev);
ERR3:
unregister_chrdev_region(devt, count);
ERR2:
kfree(cdev);
ERR1:
return res;
}
static void __exit led_exit(void)
{
int i;
gpiod_set_value(topled1, 0);
gpiod_set_value(topled2, 0);
gpiod_set_value(topled3, 0);
gpiod_put(topled1);
gpiod_put(topled2);
gpiod_put(topled3);
for (i = 0; i < count; i++)
{
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
cdev_del(cdev);
unregister_chrdev_region(MKDEV(major, minor), count);
kfree(cdev);
free_irq(irqnum_key1, NULL);
free_irq(irqnum_key2, NULL);
free_irq(irqnum_key3, NULL);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");