Linux中继学习--按键驱动(使用中断方式)


这里主要是仿照《嵌入式Linux开发完全手册》 上的例子写的,下载见 ,只是增加了别外两个按按键。在我的mini2440开发板上有6个按键。在上两篇文章中,主要分析了驱动中的整体的流程,现在来看一个具体的例子,是如何使用中断的。 1. 模块的初始化函数和卸载函数

/* 执行"insmod mini2440_buttons.ko"命令时就会调用这个函数*/
static int __init mini2440_buttons_init (void)
{
  int ret;
/*这里主要是注册设备驱动程序,参数为主设备号,如果BUTTON_MAJOR设为0,表示由内核自动分配主设备号,设备的名字,file_operations结构,操作主调和号为BUTTON_MAJOR的设备文件时,就会调用mini2440_buttons_fops中的相关成员函数*/
  ret = register_chrdev(BUTTON_MAJOR,DEVICE_NAME,&mini2440_buttons_fops);
  if(ret < 0)
  {
    printk(DEVICE_NAME "can't register major number\n");
    return ret ;
  }
  printk(DEVICE_NAME"initialized\n");
  return 0;
}
/* 执行 rmmod mini2440_buttons.ko0 命令时就会调用这个函数 */
static void __exit mini2440_buttons_exit(void)
{
//卸载驱动程序

  unregister_chrdev(BUTTON_MAJOR,DEVICE_NAME);
}
//指定驱动程序的初始化函数和卸载函数

module_init(mini2440_buttons_init);
module_exit(mini2440_buttons_exit);

   下面这个结构体是每一个字符驱动程序都是要用到的。这里定义了应用程序可以使用的设备操作函数,只有在这个结构体中的函数,在应用程序中才可以使用,在下面的驱动程序中要实现下面的函数。

/* 这个结构是字符设备驱动程序的核心,当应用程序操作设备文件时所调用的open,read,write等函数,最终会调用这个结构中的对应函数*/
static struct file_operations mini2440_buttons_fops =
  {
    .owner = THIS_MODULE,
//这是 个宏,指向编译模块时自动创建的_this_module变量

    .open = mini2440_buttons_open,
    .release = mini2440_buttons_close,
    .read = mini2440_buttons_read,
  };

2. mini2440_buttons_open函数
   在应用程序执行“open("/dev/buttons",..)"系统调用时,mini2440_buttons_open函数将被调用。这用来注册6个按键的中断处理程序

static int mini2440_buttons_open(struct inode *inode,struct file *file)
{
  int i;
  int err;
  for (i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
  { //注册中断处理函数 一共六个
    err = request_irq(button_irqs[i].irq,buttons_interrupt,button_irqs[i].flags,button_irqs[i].name,(void *)&press_cnt[i]);
    if (err)
      break;
  }
  if(err) //出错处理函数,如果出错释放已经注册的中断
  {
    i--;
    for(;i>=0;i--)
      free_irq(button_irqs[i].irq,(void *)&press_cnt[i]);
    return -EBUSY;
  }
  return 0;
}

requst_irq函数执行成功后,这6个按键所用的GPIO引脚的功能被设为外部中断,触发方式为下降沿触发,中断处理函数为buttons_interrupt.最后一个参数“(void *)&press_cnt[i]”将在buttons_interrupt函数中用到,它用来 存储按键被按下的次数。参数button_irqs的定义如下:

struct button_irq_desc
{
  int irq;//中断号
  unsigned long flags; //中断标志,用来定义中断的触发方式
  char *name; //中断名称
};

static struct button_irq_desc button_irqs[] =
  {  //下面是按键对应的外部的中断号,触发方式,名称
    {IRQ_EINT8,IRQF_TRIGGER_FALLING,"KEY0"},
    {IRQ_EINT11,IRQF_TRIGGER_FALLING,"KEY1"},
    {IRQ_EINT13,IRQF_TRIGGER_FALLING,"KEY2"},
    {IRQ_EINT14,IRQF_TRIGGER_FALLING,"KEY3"},
    {IRQ_EINT15,IRQF_TRIGGER_FALLING,"KEY4"},
    {IRQ_EINT19,IRQF_TRIGGER_FALLING,"KEY5"},
  };

3. mini2440_buttons_close函数
mini2440_buttons_close函数的作用是用来卸载6个按键的中断处理函数代码如下:

/* 应用程序对设备文件/dev/buttons执行close(...)时。就会调用mini2440_buttons_close函数*/
static int mini2440_buttons_close(struct inode *inode,struct file *file)
{
  int i;
  for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
  {
//释放已注册的函数

    free_irq(button_irqs[i].irq,(void *)&press_cnt[i]);
  }
  return 0;
}

4. mini2440_buttons_read函数
中断处理函数会在press_cnt数组中记录按键被按下的次数。mini_buttons_read函数,首先判断是否按键再次按下,如果没有则休眠;否则读取press_cnt数组的数据,

/*等待队列:
 当没有按键被按下时,如果有进程调用mini2440_buttons_read函数,它将休眠*/

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
/*中断事件标志,中断服务程序将它置1,mini2440_buttons_read将它清0*/
static volatile int ev_press = 0;
/*应用程序对设备文件/dev/buttons执行read(...)时,就会调用mini2440_buttons_read函数*/
static int mini2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
{
  unsigned long err;
 //如果ev_press等于0,休眠
  wait_event_interruptible(button_waitq,ev_press);
  ev_press = 0;// 执行到这里是ev_press肯定是1,将它清0
  //将按键状态复制给用户,并清0
  err = copy_to_user(buff,(const void *)press_cnt,min(sizeof(press_cnt),count));
  memset((void *)press_cnt,0,sizeof(press_cnt));

  return err ? -EFAULT:0;
}

   
  • 1
  • 2
  • 下一页

相关内容