Linux驱动开发之基于输入子系统按键驱动程序

1、驱动源代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/arch/regs-gpio.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/input.h>

struct input_dev *button_dev;
struct button_irq_desc {
    int irq;         //中断号
    int pin;         //对应的管脚
    int pin_setting; //GPIO控制寄存器的配置
    int number;      //按键的编号
    char *name;         //按键的名称
};


static struct button_irq_desc button_irqs [] = {
    {IRQ_EINT0 , S3C2410_GPF0 ,  S3C2410_GPF0_EINT0  , 0, "KEY0"},  
    {IRQ_EINT2,  S3C2410_GPF2 ,   S3C2410_GPF2_EINT2 ,   1, "KEY1"},
    {IRQ_EINT11, S3C2410_GPG3 ,  S3C2410_GPG3_EINT11 , 2, "KEY2"},
    {IRQ_EINT19, S3C2410_GPG11 ,  S3C2410_GPG11_EINT19 , 3, "KEY3"},
};

static int key_values = 0;

static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
    struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;//获得设备信息
    int down;
     udelay(0);
    down = !s3c2410_gpio_getpin(button_irqs->pin);   //读取GPIO端口的信息,down: 1(按下),0(弹起)
   if (!down) {   //按键弹起
    
    /*报告事件*/
    key_values = button_irqs->number;
    //printk("====>rising key_values=%d\n",key_values);
  if(key_values==0)
      input_report_key(button_dev, KEY_1, 0);
  if(key_values==1)
      input_report_key(button_dev, KEY_2, 0);
  if(key_values==2)
      input_report_key(button_dev, KEY_3, 0);
  if(key_values==3)
      input_report_key(button_dev, KEY_4, 0);
  
  input_sync(button_dev);      
        }
  
     else {    //按键按下
     
        key_values = button_irqs->number;  //获得是哪一个按键按下的
        //printk("====>falling key_values=%d\n",key_values);
  if(key_values==0)  //0号按键按下
        input_report_key(button_dev, KEY_1, 1); //提交按键按下事件
  if(key_values==1)//1号按键按下
        input_report_key(button_dev, KEY_2, 1);
  if(key_values==2)//2号按键按下
        input_report_key(button_dev, KEY_3, 1);
  if(key_values==3)//3号按键按下
        input_report_key(button_dev, KEY_4, 1);
  input_sync(button_dev);   //发送同步事件   

     }

  
    return IRQ_RETVAL(IRQ_HANDLED);//中断返回
}


static int s3c24xx_request_irq(void)
{
    int i;
    int err = 0;
    
    for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
    

                if (button_irqs[i].irq < 0) {  //中断号检查
                                continue;
                    }
     /* IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_BOTH */
        err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,   //中断为双边沿触发
                          button_irqs[i].name, (void *)&button_irqs[i]); //注册中断
        if (err)
            break;
    }

    if (err) {       //中断注册出错处理
        i--;
        for (; i >= 0; i--) {
        if (button_irqs[i].irq < 0) {
        continue;
        }
        disable_irq(button_irqs[i].irq);  
            free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);//注销中断
        }
        return -EBUSY;
    }

    
    return 0;
}


static int __init dev_init(void)
{

  
  /*request irq*/
  s3c24xx_request_irq(); //中断初始化函数
    /* Initialise input stuff */
    button_dev = input_allocate_device(); //分配输入设备
    if (!button_dev) {  
        printk(KERN_ERR "Unable to allocate the input device !!\n");
        return -ENOMEM;
    }
    button_dev->name = "s3c2440_button"; //设置输入设备的名称
    button_dev->id.bustype = BUS_RS232;  //设置输入设备的ID信息
        button_dev->id.vendor = 0xDEAD;
        button_dev->id.product = 0xBEEF;
        button_dev->id.version = 0x0100;

    button_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_SYN);//设置设备支持的事件
    //set_bit(EV_KEY, button_dev->evbit)//支持EV_KEY事件
    set_bit(KEY_1,   button_dev->keybit); //设置键盘的键值
    set_bit(KEY_2,   button_dev->keybit);
    set_bit(KEY_3,   button_dev->keybit);
    set_bit(KEY_4,   button_dev->keybit);
    //printk("KEY_RESERVED=%d ,KEY_1=%d",KEY_RESERVED,KEY_1);
    input_register_device(button_dev);   //注册input设备

    printk ("initialized\n");

    return 0;
}

static void __exit dev_exit(void)
{
        int i;
    
  for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
        if (button_irqs[i].irq < 0) {
            continue;
            }
        free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);//注销中断
   }

    input_unregister_device(button_dev);//注销输入设备
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");

2、Makefile

ifeq ($(KERNELRELEASE),)
KDIR := /home/source/linux-2.6.22.6/
PWD := $(shell pwd)
all:                               
        $(MAKE) -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:                                             
        $(MAKE) -C $(KDIR) M=$(PWD) clean
else
    obj-m := input_button.o
endif

3、应用程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>
int main(void)
{
    int buttons_fd;
    int key_value,i=0,count;

    struct input_event ev_key;
    buttons_fd = open("/dev/event1", O_RDWR); //阻塞方式打开设备
    if (buttons_fd < 0) {
        perror("open device buttons");
        exit(1);
    }

    for (;;) {
        count = read(buttons_fd,&ev_key,sizeof(struct input_event));
        for(i=0; i<(int)count/sizeof(struct input_event); i++)
            if(EV_KEY==ev_key.type)
                printf("type:%d,code:%d,value:%d\n", ev_key.type,ev_key.code-1,ev_key.value);
            if(EV_SYN==ev_key.type)
                printf("syn event\n\n");

    }

    close(buttons_fd);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xiezhi123456/article/details/81090205