这一节,我们来以输入子系统的框架来写一个按键驱动。
问:怎么写符合输入子系统框架的驱动程序?
答:
1. 分配一个input_dev结构体
2. 设置
3. 注册
4. 硬件相关的代码,比如在中断服务程序里上报事件
问:如何分配input_dev结构体?
答:使用input_allocate_device函数
input_dev结构体的重要成员
structinput_dev {
constchar*name;
constchar*phys;
constchar*uniq;
structinput_id id;
unsigned longevbit[NBITS(EV_MAX)];// 表示能产生哪类事件
unsigned longkeybit[NBITS(KEY_MAX)];// 表示能产生哪些按键
unsigned longrelbit[NBITS(REL_MAX)];// 表示能产生哪些相对位移事件, x,y,滚轮
unsigned longabsbit[NBITS(ABS_MAX)];// 表示能产生哪些绝对位移事件, x,y
unsigned longmscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned longledbit[BITS_TO_LONGS(LED_CNT)];
unsigned longsndbit[BITS_TO_LONGS(SND_CNT)];
unsigned longffbit[BITS_TO_LONGS(FF_CNT)];
...
}
问:第二步的设置,应该怎么设置,应该设置什么?
答:举例,在此按键驱动里
/* 2.设置 */
/* 2.1 设置按键能产生哪类事件 */
set_bit(EV_KEY,buttons_dev->evbit); //按键类事件
set_bit(EV_REP,buttons_dev->evbit); //重复类事件,比如按下按键L能重复打印L;按下后,能重复帮你上报事件(重复,说明肯定用到定时器)
/* 2.2 设置能产生这类操作的哪些事件 */
set_bit(KEY_L,buttons_dev->keybit);
set_bit(KEY_S,buttons_dev->keybit);
set_bit(KEY_ENTER,buttons_dev->keybit);
set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);
问:有哪些类呢?
答:在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)
问:如何注册?
答:使用input_register_device(struct input_dev *dev)函数来注册
问:此按键驱动的硬件操作包括哪些操作?
答:申请定时器、申请中断操作
驱动源码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include //class_create
#include //S3C2410_GPF1
//#include
#include
//#include
#include //wait_event_interruptible
#include //poll
#include
#include
staticstructpin_desc{
intirq;
unsigned char*name;
unsigned intpin;
unsigned intkey_val;
};
staticstructpin_desc pins_desc[4] = {
{IRQ_EINT1,"K1",S3C2410_GPF1,KEY_L},
{IRQ_EINT4,"K2",S3C2410_GPF4,KEY_S},
{IRQ_EINT2,"K3",S3C2410_GPF2,KEY_ENTER},
{IRQ_EINT0,"K4",S3C2410_GPF0,KEY_LEFTSHIFT},
};
staticstructpin_desc *irq_pd;
staticstructinput_dev *buttons_dev;
staticstructtimer_list buttons_timer;
/* 用户中断处理函数 */
staticirqreturn_t buttons_irq(intirq,void*dev_id)
{
irq_pd = (structpin_desc *)dev_id;
/* 修改定时器定时时间,定时10ms,即10秒后启动定时器
* HZ 表示100个jiffies,jiffies的单位为10ms,即HZ = 100*10ms = 1s
* 这里HZ/100即定时10ms
*/
mod_timer(&buttons_timer, jiffies + (HZ /100));
returnIRQ_HANDLED;
}
/* 定时器处理函数 */
staticvoidbuttons_timer_function(unsignedlongdata)
{
structpin_desc *pindesc = irq_pd;
unsigned intpinval;
pinval = s3c2410_gpio_getpin(pindesc->pin);
if(pinval)
{
/* 松开 最后一个参数: 0-松开, 1-按下 */
input_event(buttons_dev,EV_KEY,pindesc->key_val,0);
input_sync(buttons_dev);
}
else
{
/* 按下 */
input_event(buttons_dev,EV_KEY,pindesc->key_val,1);
input_sync(buttons_dev);
}
}
/* 驱动入口函数 */
staticintbuttons_input_init(void)
{
inti;
/* 1.分配一个input_dev结构体 */
buttons_dev = input_allocate_device();
/* 2.设置 */
/* 2.1 设置按键能产生哪类事件 */
set_bit(EV_KEY,buttons_dev->evbit);
set_bit(EV_REP,buttons_dev->evbit);
/* 2.2 设置能产生这类操作的哪些事件 */
set_bit(KEY_L,buttons_dev->keybit);
set_bit(KEY_S,buttons_dev->keybit);
set_bit(KEY_ENTER,buttons_dev->keybit);
set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);
/* 3.注册 */
input_register_device(buttons_dev);
/* 4.硬件相关的设置 */
/* 4.1 定时器相关的操作 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer);
/* 4.2 申请中断 */
for(i = 0;i
{
request_irq(pins_desc[i].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH, pins_desc[i].name, &pins_desc[i]);
}
return0;
}
/* 驱动出口函数 */
staticvoidbuttons_input_exit(void)
{
inti;
for(i = 0;i
{
free_irq(pins_desc[i].irq, &pins_desc[i]);
}
del_timer(&buttons_timer);
input_unregister_device(buttons_dev);
input_free_device(buttons_dev);
}
module_init(buttons_input_init); //用于修饰入口函数
module_exit(buttons_input_exit); //用于修饰出口函数
MODULE_AUTHOR("LWJ");
MODULE_DESCRIPTION("Just for Demon");
MODULE_LICENSE("GPL");//遵循GPL协议
测试步骤方法一:
[WJ2440]# ls
Qt first_test second_test
TQLedtest fourth_drv.ko sixth_drv.ko
app_test fourth_test sixth_test
bin home sixthdrvtest
buttons_all_drv.ko lib sys
buttons_all_test linuxrc third_drv.ko
buttons_input.ko mnt third_test
dev opt tmp
driver_test proc udisk
etc root usr
fifth_drv.ko sbin var
fifth_test sddisk web
first_drv.ko second_drv.ko
[WJ2440]# ls /dev/event* -l
crw-rw---- 1 root root 13, 64 Jan 2 06:04 /dev/event0
[WJ2440]# insmod buttons_input.ko
input: Unspecified device as /devices/virtual/input/input1
[WJ2440]# ls /dev/event* -l
crw-rw---- 1 root root 13, 64 Jan 2 06:04 /dev/event0
crw-rw---- 1 root root 13, 65 Jan 2 06:06 /dev/event1
[WJ2440]# cat /dev/tty1
[WJ2440]# cat /dev/tty1
ls
ls
输入cat /dev/tty1命令后,顺序按下K1,K2,K3则会显示ls
2. 如果没有启动QT:
cat /dev/tty1
按:s2,s3,s4
就可以得到ls
或者:
exec 0
然后可以使用按键来输入
3. 如果已经启动了QT: ( 因为启动了qt之后,串口返回的是乱码)
可以点开记事本
然后按:s2,s3,s4