编写使用中断的按键驱动程序

简介: 编写使用中断的按键驱动程序

编写使用中断的按键驱动程序

从头写按键驱动,特别是如何使用中断,是休眠-唤醒,POLL机制,异步通知,定时器,中断的线程化处理。

编程思路

1.编写设备树提供硬件信息;查看原理图确定按键使用的引脚,再在设备树中添加节点,在节点里指定中断信息。

gpio_keys_100ask {
compatible = "100ask,gpio_key";
gpios = <&gpio5 1 GPIO_ACTIVE_HIGH
&gpio4 14 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&key1_pinctrl
&key2_pinctrl>;
key1_100ask: key1_100ask {        /*!< Function assigned for the core: Cortex-A7[ca7] */
            fsl,pins = <
                MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01        0x000110A0
            >;
        };
};
key2_100ask: key2_100ask {                /*!< Function assigned for the core: Cortex-A7[ca7] */
            fsl,pins = <
                MX6UL_PAD_NAND_CE1_B__GPIO4_IO14           0x000010B0
            >;
        };

上面指定引脚信息

gpio_key_drv.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
struct gpio_key{
  int gpio;
  struct gpio_desc *gpiod;
  int flag;
  int irq;
} ;
static struct gpio_key *gpio_keys_100ask;
static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
  struct gpio_key *gpio_key = dev_id;
  int val;
  val = gpiod_get_value(gpio_key->gpiod);
  printk("key %d %d\n", gpio_key->gpio, val);
  return IRQ_HANDLED;
}
/* 1. 从platform_device获得GPIO
 * 2. gpio=>irq
 * 3. request_irq
 */
static int gpio_key_probe(struct platform_device *pdev)
{
  int err;
  struct device_node *node = pdev->dev.of_node;
  int count;
  int i;
  enum of_gpio_flags flag;
  unsigned flags = GPIOF_IN;
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  count = of_gpio_count(node);
  if (!count)
  {
    printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
    return -1;
  }
  gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);
  for (i = 0; i < count; i++)
  {
    gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag);
    if (gpio_keys_100ask[i].gpio < 0)
    {
      printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);
      return -1;
    }
    gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio);
    gpio_keys_100ask[i].flag = flag & OF_GPIO_ACTIVE_LOW;
    if (flag & OF_GPIO_ACTIVE_LOW)
      flags |= GPIOF_ACTIVE_LOW;
    err = devm_gpio_request_one(&pdev->dev, gpio_keys_100ask[i].gpio, flags, NULL);
    gpio_keys_100ask[i].irq  = gpio_to_irq(gpio_keys_100ask[i].gpio);
  }
  for (i = 0; i < count; i++)
  {
    err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_keys_100ask[i]);
  }
    return 0;
}
static int gpio_key_remove(struct platform_device *pdev)
{
  //int err;
  struct device_node *node = pdev->dev.of_node;
  int count;
  int i;
  count = of_gpio_count(node);
  for (i = 0; i < count; i++)
  {
    free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);
  }
  kfree(gpio_keys_100ask);
    return 0;
}
static const struct of_device_id ask100_keys[] = {
    { .compatible = "100ask,gpio_key" },
    { },
};
/* 1. 定义platform_driver */
static struct platform_driver gpio_keys_driver = {
    .probe      = gpio_key_probe,
    .remove     = gpio_key_remove,
    .driver     = {
        .name   = "100ask_gpio_key",
        .of_match_table = ask100_keys,
    },
};
/* 2. 在入口函数注册platform_driver */
static int __init gpio_key_init(void)
{
    int err;
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    err = platform_driver_register(&gpio_keys_driver); 
  return err;
}
/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
 *     卸载platform_driver
 */
static void __exit gpio_key_exit(void)
{
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    platform_driver_unregister(&gpio_keys_driver);
}
/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
module_init(gpio_key_init);
module_exit(gpio_key_exit);
MODULE_LICENSE("GPL");

首先编写入口函数gpio_key_init()并在里面进行设备注册。出口函数在卸载驱动程序。在入口函数会注册platform_driver 名为gpio_keys_driver结构体,并声明probe和remove,driver函数在driver函数里面指明那个设备名。在probe函数里面*

1.从platform_device获得GPIO

2.gpio=>irq

3.request_irq

1.从设备树获得GPIO

count = of_gpio_count(node);
for (i = 0; i < count; i++)
 gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag);

2.从GPIO获得中断号

gpio_keys_100ask[i].irq = gpio_to_irq(gpio_keys_100ask[i].gpio);

3.申请中断

err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, \
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_keys_100ask
[i]);

4.中断函数

static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
struct gpio_key *gpio_key = dev_id;
int val;
val = gpiod_get_value(gpio_key->gpiod);
printk("key %d %d\n", gpio_key->gpio, val);
return IRQ_HANDLED;
}
目录
相关文章
|
7月前
|
开发者
STM32中断详解及其编程实践
STM32中断详解及其编程实践
447 1
|
5月前
|
存储 索引
8086 汇编笔记(十一):内中断
8086 汇编笔记(十一):内中断
|
Java Linux API
中断-处理程序架构
中断-处理程序架构
154 0
|
Linux 调度
Linux驱动中断下半部的三种方法
Linux驱动中断下半部的三种方法
|
存储
TM4C123库函数学习(3)---串口中断
TM4C123库函数学习(3)---串口中断
221 0
西门子S7-1200基本位逻辑指令编程实例,如何编写起保停控制程序
今天我们来学习一个西门子S7-1200基本位逻辑指令的编程实例,给大家介绍一下如何编写起保停控制程序。
西门子S7-1200基本位逻辑指令编程实例,如何编写起保停控制程序
|
Linux 芯片
LED驱动程序--可拓展的LED驱动程序
LED驱动程序--可拓展的LED驱动程序
122 0
|
程序员 Linux 芯片
按键驱动编写
按键驱动编写
115 0
按键驱动编写
|
编解码
什么是中断?西门子S7-200 SMART如何编写中断程序
中断就是中止当前正在运行的程序,去执行为立刻响应的信号而编写的中断服务程序,执行完毕后再返回原来中止的程序并继续执行。
什么是中断?西门子S7-200 SMART如何编写中断程序
|
C语言
【嵌入式实训】STM32中断处理机制及外部中断使用方法
理论知识 STM32系列处理器外部中断/事件控制器的原理 共19个外部中断线,其中GPIO端口以下图的方式连接到16个外部中断/事件线上: 另外三种其他的外部中断/事件控制器的连接如下:EXTI 线 
642 0