嵌入式linux驱动-输入子系统笔记

一、开发环境

1、内核:Linux 2.6.22.6;

2、JZ2440

3、ubuntu 9.10


二、过程

1、分配input_dev结构体

   使用input_allocate_device函数,如:

先定义一个input_dev 结构体类型变量:static struct input_dev *key_dev;

使用input_allocate_device函数分配key_dev=input_allocate_device();

2、设置input_dev

 input_dev结构体成员有:

struct input_dev {  
    const char *name;  
    const char *phys;  
    const char *uniq;  
    struct input_id id;  
  
    unsigned long evbit[NBITS(EV_MAX)];   // 表示能产生哪类事件  
    unsigned long keybit[NBITS(KEY_MAX)]; // 表示能产生哪些按键  
    unsigned long relbit[NBITS(REL_MAX)]; // 表示能产生哪些相对位移事件, x,y,滚轮  
    unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y  
    unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];  
    unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];  
    unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];  
    unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];  
    ...  
 }

先设置哪类操作,再设置这类操作的哪些事件,如

/* 2.1 设置按键能产生哪类事件 */ 

set_bit(EV_KEY,key_dev->evbit);//EV_KEY表示按键操作
set_bit(EV_REP,key_dev->evbit);//EV_REP表示按键重复操作  
/* 2.2 设置能产生这类操作的哪些事件 */  

set_bit(KEY_L,key_dev->keybit);//KEY_L表示按了L键
set_bit(KEY_S,key_dev->keybit);//KEY_S表示按了S键
set_bit(KEY_ENTER,key_dev->keybit);//ENTER表示按了ENTER键
set_bit(KEY_LEFTSHIFT,key_dev->keybit);//KEY_LEFTSHIFT表示按了左边的SHIFT键

另外:

input.h里有以下类

#define EV_SYN          0x00    //同步类  
#define EV_KEY          0x01    //按键类  
#define EV_REL          0x02    //相对位移类  
#define EV_ABS          0x03    //绝对位移类  
#define EV_MSC          0x04      
#define EV_SW           0x05  
#define EV_LED          0x11  
#define EV_SND          0x12    //声音类  
#define EV_REP          0x14    //重复类  
#define EV_FF           0x15  
#define EV_PWR          0x16  
#define EV_FF_STATUS        0x17  
#define EV_MAX          0x1f  
#define EV_CNT          (EV_MAX+1) 

3、注册

使用input_register_device(struct input_dev *dev)函数来注册,如:input_register_device(key_dev);

4、硬件相关操作

具体应用具体写了。比如本实验中使用到定时器,初始化定时器,使用按键注册中断等。

5、程序

#include 
#include 


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#include 
#include 
#include 


struct key_desc{
 int irq;
 char *name;
 unsigned int pin;
 unsigned int key_val;
};


struct key_desc key_desc[4]={
 {IRQ_EINT0,"s2",S3C2410_GPF0,KEY_L},
 {IRQ_EINT2,"s3",S3C2410_GPF2,KEY_S},
 {IRQ_EINT11,"s4",S3C2410_GPG3,KEY_ENTER},
 {IRQ_EINT19,"s5",S3C2410_GPG11,KEY_LEFTSHIFT},
};


static struct input_dev *key_dev;
static struct key_desc *irq_tmp;
static struct timer_list key_timer;


static irqreturn_t key_irq(int irq, void *dev_id)
{ 
   // printk("key_irq!irq=%d \n",irq);
 
 irq_tmp=(struct key_desc*)dev_id;
 mod_timer(&key_timer, jiffies + HZ/100);
 
 return IRQ_RETVAL(IRQ_HANDLED);
}


static void key_timer_func(unsigned long __data)
{
 struct key_desc * keysdesc=irq_tmp;
 unsigned int keyval;


 //printk("key_timer_func! \n");


 
 if (!keysdesc)
 {
 //printk("keysdesc\n");
 return;
 
 }
 
 
 keyval=s3c2410_gpio_getpin(keysdesc->pin);
 if(keyval)
 {//松开


 
 input_event(key_dev,EV_KEY,keysdesc->key_val,0);
 input_sync(key_dev);
 // printk("input_event0! \n");
 }
 else
 {//按下
 
 input_event(key_dev,EV_KEY,keysdesc->key_val,1);
 input_sync(key_dev);
 // printk("input_event1! \n");
 }
}


static int  key_init(void)
{ 
 int i;
 printk("key_init! \n");


 //分配一个input_dev结构体
 key_dev=input_allocate_device();


 //设置
 set_bit(EV_KEY,key_dev->evbit);
 set_bit(EV_REP,key_dev->evbit);


 set_bit(KEY_L,key_dev->keybit);
 set_bit(KEY_S,key_dev->keybit);
 set_bit(KEY_ENTER,key_dev->keybit);
 set_bit(KEY_LEFTSHIFT,key_dev->keybit);
 //注册
 input_register_device(key_dev);
 //硬件相关操作
 
 //定时器初始化
 init_timer(&key_timer);
 key_timer.function = key_timer_func;
 add_timer(&key_timer);


 for(i=0;i<4;i++)
 {
 request_irq(key_desc[i].irq,key_irq ,IRQT_BOTHEDGE,key_desc[i].name,&key_desc[i]);
 }


 return 0;
}


static void key_exit(void)
{
 int i;


 printk("key_exit! \n");


 for(i=0;i<4;i++)
 {
 free_irq(key_desc[i].irq,&key_desc[i]);
 }
 del_timer(&key_timer);
 input_unregister_device(key_dev);
 input_free_device(key_dev);
}


module_init(key_init);
module_exit(key_exit);


MODULE_LICENSE("GPL");








三、架构相关

1、驱动中按键松开、按下时调用input_event()函数把keysdesc->key_val即结构体

struct key_desc key_desc[4]={
{IRQ_EINT0,"s1",S3C2410_GPF0,KEY_L},
{IRQ_EINT2,"s2",S3C2410_GPF2,KEY_S},
{IRQ_EINT11,"s3",S3C2410_GPG3,KEY_ENTER},
{IRQ_EINT19,"s4",S3C2410_GPG11,KEY_LEFTSHIFT},
};

中的KEY_L,KEY_S,KEY_ENTER,KEY_LEFTSHIFT,传递给内核。

input_event()函数中有:

list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle, type, code, value);


实现了从input_dev到input_handle到input_handler的调用。即从硬件层到两者的连接层到驱动层的调用。我们写的程序调用input_event()函数,input_event中通过dev->h_list找到input_handle,input_handle通过其成员handler找到event。

2、韦分层框架截图

嵌入式linux驱动-输入子系统笔记_第1张图片

四、命令

hexdump /dev/event1 hex显示/dev/event1

exec 0

五、问题

1、加载模块后,没有event,如下

# ls -l /dev/event*
ls: /dev/event*: No such file or directory

解决:配置内核时选上Device Drivers->Input device support->Event interface && Event debugging。下载新内核到板子上。再重新make下编写的输入子系统。

加载子系统后,结果如下

嵌入式linux驱动-输入子系统笔记_第2张图片

六、结果

嵌入式linux驱动-输入子系统笔记_第3张图片





你可能感兴趣的:(嵌入式linux驱动)