【Tiny6410 And Linux】—(2.4)—实现 input 模型按键驱动——

好了,白去修了趟电脑!

日了,FUCK!初步鉴定是宿舍的电源不稳定,导致的!

好了,赶紧的贴完代码,去趟自习室。

1、驱动程序

①、input_btn_dev.c

#include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/platform_device.h>#include <linux/interrupt.h>#include <linux/device.h>#define DEVICE_NAME     "tiny6410_buttons"/* 平台资源的定义 */static struct resource tiny6410_buttons_resource[] = {        [0] = {                .start = IRQ_EINT(0),                .end   = IRQ_EINT(0),                .flags = IORESOURCE_IRQ,        },        [1] = {                .start = IRQ_EINT(1),                .end   = IRQ_EINT(1),                .flags = IORESOURCE_IRQ,        },        [2] = {                .start = IRQ_EINT(2),                .end   = IRQ_EINT(2),                .flags = IORESOURCE_IRQ,        },        [3] = {                .start = IRQ_EINT(3),                .end   = IRQ_EINT(3),                .flags = IORESOURCE_IRQ,        },        [4] = {                .start = IRQ_EINT(4),                .end   = IRQ_EINT(4),                .flags = IORESOURCE_IRQ,        },        [5] = {                .start = IRQ_EINT(5),                .end   = IRQ_EINT(5),                .flags = IORESOURCE_IRQ,        },        [6] = {                .start = IRQ_EINT(19),                .end   = IRQ_EINT(19),                .flags = IORESOURCE_IRQ,        },        [7] = {                .start = IRQ_EINT(20),                .end   = IRQ_EINT(20),                .flags = IORESOURCE_IRQ,        }                                       /* 这里不需要加逗号 */};static struct platform_device *tiny6410_buttons_dev;static int __init platform_init(void){        printk("[Call platform_init!]\n");        /* 分配一个 platform_device 结构 */        tiny6410_buttons_dev = platform_device_alloc(DEVICE_NAME, -1);        /* 为平台设备添加平台设备资源 */        platform_device_add_resources(tiny6410_buttons_dev,                                        tiny6410_buttons_resource, 8);        /* 注册平台设备 */        platform_device_add(tiny6410_buttons_dev);        return 0;}static void __exit platform_exit(void){        printk("[Call platform_exit!]\n");        platform_device_unregister(tiny6410_buttons_dev);}module_init(platform_init);module_exit(platform_exit);MODULE_AUTHOR("_Justin");MODULE_LICENSE("GPL");

②、input_btn_drv.c

#include <linux/module.h>#include <linux/types.h>#include <linux/miscdevice.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/platform_device.h>#include <linux/interrupt.h>#include <linux/uaccess.h>#include <linux/io.h>#include <mach/map.h>#include <mach/regs-gpio.h>#include <linux/poll.h>#include <linux/irq.h>#include <asm/unistd.h>#include <linux/device.h>#include <linux/workqueue.h>#include <linux/input.h>#include <mach/gpio-bank-n.h>#include <mach/gpio-bank-l.h>#define DRIVER_NAME     "tiny6410_buttons"#define DEVICE_NAME     "tiny6410_buttons"/* 注意: * 在一个较规范的驱动程序中,通常不会将设备资源在平台驱动程序中 * 以全局变量的形式给出(这里是为了简化操作,将部分设备资源以全局变量形式 * 给出),一个更好的办法是,将这些资源都添加到对应的平台设备中,以平台 * 设备资源或者平台设备似有数据的形式管理。 *//* 记录按键中断号 */typedef struct{        int irq;                        /* 中断号,初始化为 0,将在                                         * probe 获取资源 */        int num;                        /* 对应的按键编号 */        char *name;                     /* 中断所属的名字 */} button_irq_t;/* 按键数据结构 */typedef struct {struct delayed_work dwork;/* 用于按键中断下半部分的延迟工作 */struct input_dev *dev;/* 按键的输入设备结构 */button_irq_t *birqs;/* 指向记录按键中断资源数组 */int nirqs;/* 设备支持的按键中断数 */int val;/* 记录键值 */volatile int cnum;/* 记录产生中断的按键编号 */} buttons_data_t;button_irq_t  button_irqs[] ={        {0, 0, "KEY1"},        {0, 1, "KEY2"},        {0, 2, "KEY3"},        {0, 3, "KEY4"},        {0, 4, "KEY5"},        {0, 5, "KEY6"},        {0, 6, "KEY7"},        {0, 7, "KEY8"},};/* 按键驱动数据全局变量 g_bd */static buttons_data_t g_bd ={.birqs= button_irqs,.nirqs= sizeof(button_irqs) / sizeof(button_irqs[0]),};/*  * buttons_work_func 函数 * 延迟工作的回调函数则负责完成中断处理程序中未完成的工作  */static void buttons_work_func(struct work_struct *w){int down;unsigned tmp;int num = g_bd.cnum;        switch(num)         {                case 0: case 1: case 2: case 3: case 4: case 5:                        tmp = readl(S3C64XX_GPNDAT);                        down = !(tmp & (1 << num));                        break;                                        case 6: case 7:                        tmp = readl(S3C64XX_GPLDAT);                        down = !(tmp & (1 << (num + 5)));                        break;                default:                        down = 0;        }g_bd.val = down ? 1 : 0;if(num == 0)input_report_key(g_bd.dev,KEY_1,g_bd.val);else if(num == 1)input_report_key(g_bd.dev,KEY_2,g_bd.val);else if(num == 2)input_report_key(g_bd.dev,KEY_3,g_bd.val);else if(num == 3)input_report_key(g_bd.dev,KEY_4,g_bd.val);else if(num == 4)input_report_key(g_bd.dev,KEY_5,g_bd.val);else if(num == 5)input_report_key(g_bd.dev,KEY_6,g_bd.val);else if(num == 6)input_report_key(g_bd.dev,KEY_7,g_bd.val);else if(num == 7)input_report_key(g_bd.dev,KEY_8,g_bd.val);printk("[num = %d,g_bd.val = %d]\n",num,g_bd.val);input_sync(g_bd.dev);}/* * buttons_interrupt * 使用一个整形变量 key_value 的 0~7 位来记录键值,0~7 * 位分别对应 KEY0~KEY7 的抬起或者按下情况( 1 表示按下)。 */static irqreturn_t buttons_interrupt(int irq,void *dev_id){        /* 定义一个指针,指向所对应的中断号 */        button_irq_t *birq = (button_irq_t *)dev_id;g_bd.cnum = birq->num;/* 延迟 20ms,用作按键消抖 */schedule_delayed_work(&g_bd.dwork,HZ/50);return IRQ_RETVAL(IRQ_HANDLED);}/* * buttons_request_irq */static int buttons_request_irqs(void){        int i;        int err = 0;        for(i = 0;i < g_bd.nirqs;i ++ )        {                if (button_irqs[i].irq < 0)                        continue;                /* 申请中断 */                 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;        }//ev_press = 1;        return 0;} /*  * probe 实现函数 */static int tiny6410_buttons_probe(struct platform_device *pdev){        int ret;        int i;          static struct resource   *buttons_irq;          printk("[call %s]\n", __func__);/* 初始化 delay_work 结构,来使用延迟调度工作 */INIT_DELAYED_WORK(&g_bd.dwork,buttons_work_func);           /* 获取设备资源 */        for(i = 0;i < 8;i ++ )        {                buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i);                button_irqs[i].irq = buttons_irq->start;        }/* 注册按键中断 */ret = buttons_request_irqs();printk("[irq-request ret = %d]\n",ret);/* input 设备结构填充 */g_bd.dev = input_allocate_device();g_bd.dev->phys = NULL;g_bd.dev->name = DEVICE_NAME;/* 设置设备支持的事件 *//* 首先填充 evbit */set_bit(EV_KEY,g_bd.dev->evbit);set_bit(EV_SYN,g_bd.dev->evbit);/* 填充 keybit */set_bit(KEY_1,g_bd.dev->keybit);set_bit(KEY_2,g_bd.dev->keybit);set_bit(KEY_3,g_bd.dev->keybit);set_bit(KEY_4,g_bd.dev->keybit);set_bit(KEY_5,g_bd.dev->keybit);set_bit(KEY_6,g_bd.dev->keybit);set_bit(KEY_7,g_bd.dev->keybit);set_bit(KEY_8,g_bd.dev->keybit);/* 注册 input 设备 */ret = input_register_device(g_bd.dev);        return ret;}/* * remove 实现函数 */static int tiny6410_buttons_remove(struct platform_device *dev){printk("[Call %s]\n",__func__);input_unregister_device(g_bd.dev);return 0;}/* 平台设备驱动结构 */static struct platform_driver tiny6410_buttons_driver = {        .probe  = tiny6410_buttons_probe,        .remove = tiny6410_buttons_remove,        .driver =        {                .owner  = THIS_MODULE,                .name   = DRIVER_NAME,        },};static int __init buttons_init(void){        printk("[Call buttons_init!]\n");               /* 注册驱动 */        platform_driver_register(&tiny6410_buttons_driver);        return 0;}static void __exit buttons_exit(void){        printk("[Call buttons_exit!]\n");        platform_driver_unregister(&tiny6410_buttons_driver);}module_init(buttons_init);module_exit(buttons_exit);MODULE_AUTHOR("_Justin");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Tiny6410 Buttons Driver");

③、Makefile

ifneq ($(KERNELRELEASE),)obj-m := input_btn_dev.o input_btn_drv.oelseKDIR := /home/_Jana/linux-2.6.38all:make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-clean:rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.orderendif

2、测试程序

app_input.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.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/input/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, count:%d",                                ev_key.type,ev_key.code,ev_key.value,count);                        if(EV_SYN == ev_key.type)                                printf(" ... syn event!\n");        }        close(buttons_fd);        return 0;}

3、测试结果

天不负;卧薪尝胆,三千越甲可吞吴。

【Tiny6410 And Linux】—(2.4)—实现 input 模型按键驱动——

相关文章:

你感兴趣的文章:

标签云: