好了,白去修了趟电脑!
日了,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、测试结果
天不负;卧薪尝胆,三千越甲可吞吴。