linux驱动时就是从char设备开始的,然后接着又把那个char设备改写为input设备了,从中也开始对于linux设备驱动编程入了个小门了接着就把那个代码贴一下,用以以后可以记起。

 

具体的代码含义都加了注释了:

 



#include <linux/slab.h>

#include <linux/irq.h>

#include <linux/interrupt.h>

#include <linux/poll.h>

#include <asm/io.h>

#include <linux/delay.h>

#include <linux/module.h>

#include <linux/time.h>

#include <linux/gpio.h>

#include <linux/wait.h>

#include <linux/input.h>

#include <linux/init.h>



static gpio_base = 96; //gpio的基址,看不同的平台而定的。

static pow_btn = 18; //按键的中断号,也是依赖于平台的



struct input_dev *btn_dev; //input设备的结构体,这里定义了btn_dev

struct delayed_work btn_work; //这个是工作队列,用于让中断处理程序在中断后半部分



static irqreturn_t power_isr(int irq, void *dev_id); //中断入口函数



static int __init button_init(void);

static void __exit button_exit(void);



static void power_work_fn(struct work_struct *work) //中断下半部分处理,即工作队列中处理

{

struct timeval tm_p, tm_n;

unsigned char flag = 1;

unsigned int width = 0;



if(gpio_get_value(power)) return;



do_gettimeofday(&tm_p); //取当前的时间

while(!gpio_get_value(pow_btn)) //判断按键是否弹起

{

if(!flag) continue;



do_gettimeofday(&tm_n); //再取间

width = 1000000 * (tm_n.tv_sec - tm_p.tv_sec) //计算两次的时间差,就是按键一直没弹起

+ tm_n.tv_usec - tm_p.tv_usec;

if(width >= 1500000) //自己定义的超过了1.5s就上报一次,

{

input_report_key(btn_dev, KEY_POWER, 0); //上报按键值

input_report_key(btn_dev, KEY_POWER, 1);

input_sync(btn_dev);

flag =0;

}

}



if(flag)

{

input_report_key(btn_dev, KEY_POWER, 1);

input_report_key(btn_dev, KEY_POWER, 0);

input_sync(btn_dev);

}

}



static irqreturn_t power_isr(int irq, void *dev_id) //中断处理函数

{

schedule_delayed_work(&power_work, 0); //把中断函数放在工作队列里去做了

return IRQ_HANDLED;

}



static int __init button_init(void)

{

int error;

gpio_request(pow_btn, "power-gpio"); //初始化申请gpio

gpio_direction_input(pow_btn); //设置gpio口为输入



//申请中断

if(reques_irq(gpio_base+pow_btn, power_isr, IRQ_DISABLED, "my_power", NULL) != 0)

{

printk(KERN_ERR "my_power: can't allocate irq %d\n", pow_btn);

return (-EIO);

}



//分配input设备

btn_dev = input_allocate_device();

if(!btn_dev)

{

printk(KERN_ERR "button: not enough memory\n");

error = -ENOMEM;

goto err_free_irq;

}



//把相应的按键给置上

btn_dev->evbit[0] = BIT_MASK(EV_KEY);

btn_dev->keybit[BIT_WORK(KEY_POWER)] |= BIT_MASK(KEY_POWER);



//注册input设备

error = input_register_device(btn_dev);

if(error)

{

printk(KERN_ERR "button: failed to register device\n");

goto err_free_dev;

}



//初始化工作队列

INIT_DELAYED_WORK(&power_work, power_work_fn);



printk("$$$$$$$my_power button register ok\n");

return 0;



err_free_dev:

input_free_device(btn_dev);



err_free_irq:

free_irq(gpio_base+pow_btn, power_isr);



return error;

}



static void __exit button_exit(void)

{

input_free_device(btn_dev);

free_irq(gpio_base+pow_btn, power_isr);

}



module_init(button_init);

module_exit(button_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("eastmoon");

 

 

input设备啊,工作队列啊,时间的获取啊。GPIO的使用啊。分析好了这个驱动,下面贴个应用层的调用。总不能只有个驱动,而没法测试吧。

 

 

 



#include <stdio.h>

#include <sys/ioctl.h>

#include <unistd.h>

#include <fcntl.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <sys/select.h>

#include <sys/time.h>

#include <linux/input.h>



#define DEVICE "/dev/event0"



int main(int argc, char *argv[])

{

struct input_event btn;

int fd, rev;

unsigned short type;

unsigned short code;

int value;



fd = open(DEVICE, O_RDWR);

if(fd < 0)

{

printf("Open file %s failed!\n", DEVICE);

return -1;

}



while(1)

{

rev = read(fd, &btn, sizeof(struct input_event));

if(rev > 0)

{

type = btn.type;

code = btn.code;

value = btn.value;

printf("type = %d, code = %d, value = %d\n", type, code ,value);

}

}

close(fd);



return 0;

}

    相比知道了上面的驱动程序,应用程序肯定显得那么简单了。就不多做分析了。

    这个就是最最简单的input的基本模型了,相信以这个为基础,其他的input设备也是大同小异的了。