2440 Linux按键驱动及测试程序
来源:互联网 发布:APP登录HTML源码 编辑:程序博客网 时间:2024/04/30 01:19
原文地址:http://www.cnblogs.com/nick123/archive/2010/03/26/1696966.html
以下是驱动程序:
- <p>/*本驱动程序运行于TQ2440开发板,内核版本2.6.31.6*/</p>#include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/init.h>
- #include <linux/delay.h>
- #include <linux/poll.h>
- #include <linux/irq.h>
- #include <asm/irq.h>
- #include <linux/io.h>
- #include <linux/interrupt.h>
- #include <asm/uaccess.h>
- #include <mach/regs-clock.h>
- #include <plat/regs-adc.h>
- #include <mach/hardware.h>
- #include <linux/platform_device.h>
- #include <linux/cdev.h>
- #include <linux/miscdevice.h>
- #define DEVICE_NAME "tq2440-buttons"
- #define DEV_COUNT 1
- #define BUTTON_MAJOR 0
- #define BUTTON_MINOR 0
- #define MIN(A,B) (A)>(B)?(B):(A)
- /*等待队列:
- *当没有按键被按下时,如果有进程调用tq2440_buttons_read函数
- *它将休眠*/
- static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
- /*中断事件标志,中断服务程序将它置1,tq2440_buttons_read将它清0 */
- static volatile int ev_press = 0;
- /* 按键被按下的次数(准确地说,是发生中断的次数) */
- static volatile int press_cnt[] = {0,0,0,0};
- static struct class *button_class;
- struct button_irqs_desc {
- int irq; //中断号
- unsigned long flags; //中断标志,用来定义中断的触发方式
- char *name; //中断名称
- };
- /*用来指定按键所用的外部中断引脚及中断触发方式,名字*/
- static struct button_irqs_desc button_irqs[] = {
- {IRQ_EINT0,IRQ_TYPE_EDGE_FALLING,"KEY1"}, //K1
- {IRQ_EINT1,IRQ_TYPE_EDGE_FALLING,"KEY2"}, //K2
- {IRQ_EINT2,IRQ_TYPE_EDGE_FALLING,"KEY3"}, //K3
- {IRQ_EINT4,IRQ_TYPE_EDGE_FALLING,"KEY4"}, //K4
- };
- dev_t dev_num;
- static struct cdev * buttons_cdev_p; //cdev结构体指针
- /*卸载驱动程序*/
- static void __exit tq2440_buttons_exit(void)
- {
- cdev_del(buttons_cdev_p);//注销cdev
- kfree(buttons_cdev_p);//释放设备结构体内存
- unregister_chrdev_region(dev_num,DEV_COUNT);//释放设备号
- }
- static irqreturn_t buttons_interrupt(int irq,void *dev_id)
- {
- volatile int *press_cnt = (volatile int *)dev_id;
- *press_cnt = *press_cnt + 1; /*按键计数器加1 */
- ev_press = 1; /*表示中断发生了*/
- wake_up_interruptible(&button_waitq); /*唤醒休眠的进程*/
- printk(" IRQ:%d\n",irq);
- return IRQ_RETVAL(IRQ_HANDLED);
- }
- /*应用程序执行open("/dev/buttons",...)系统调用时,tq2440_buttons_open函数将
- *被调用,它用来注册4个按键的中断处理程序*/
- static int tq2440_buttons_open(struct inode *inode,struct file *file)
- {
- int i;
- int err;
- for(i =0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++) {
- //注册中断处理函数
- err = request_irq(button_irqs[i].irq,buttons_interrupt,button_irqs[i].flags,
- button_irqs[i].name,(void *)&press_cnt[i]);
- if(err)
- break;
- }
- if(err) {
- //如果出错,释放已经注册的中断
- i--;
- for(;i>=0;i--)
- free_irq(button_irqs[i].irq,(void *)&press_cnt[i]);
- return -EBUSY;
- }
- return 0;
- }
- /*应用程序对设备文件/dev/buttons执行close(...)时,
- *就会调用tq2440_buttons_close函数*/
- static int tq2440_buttons_close(struct inode *inode,struct file *file)
- {
- int i;
- for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++) {
- //释放已经注册的中断
- free_irq(button_irqs[i].irq,(void *)&press_cnt[i]);
- }
- return 0;
- }
- /*应用程序对设备文件/dev/buttons执行read(...)时,
- *就会调用tq2440_buttons_read函数
- */
- static int tq2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
- {
- unsigned long err;
- /*如果ev_press等于0,休眠*/
- wait_event_interruptible(button_waitq,ev_press);
- /*执行到这里时ev_press肯定等于1,将它清0 */
- ev_press = 0;
- /*将按键状态复制给用户,并请0 */
- err = copy_to_user(buff,(const void *)press_cnt,MIN(sizeof(press_cnt),count));
- memset((void *)press_cnt,0,sizeof(press_cnt));
- return err? -EFAULT:0;
- }
- /*这个结构是字符驱动设备程序的核心
- *当应用程序操作设备文件时所调用的open,read,write等函数
- *最终会调用这个结构中的对应函数
- */
- static struct file_operations tq2440_buttons_fops = {
- .owner = THIS_MODULE,/*这是一个宏,指向编译模块时自动创建的__this_module变量*/
- .open = tq2440_buttons_open,
- .release = tq2440_buttons_close,
- .read = tq2440_buttons_read,
- };
- /* 初始化并注册cdev*/
- static void buttons_cdev_setup(void)
- {
- int err;
- cdev_init(buttons_cdev_p,&tq2440_buttons_fops);
- buttons_cdev_p->owner = THIS_MODULE;
- buttons_cdev_p->ops = &tq2440_buttons_fops;
- err = cdev_add(buttons_cdev_p,dev_num,1);
- if(IS_ERR(&err))
- printk(KERN_NOTICE "Error %d adding buttons",err);
- }
- static int __init tq2440_buttons_init(void)
- {
- int ret;
- /*注册字符设备驱动程序
- *参数为主设备号,设备名字,file_operations结构体
- *这样,主设备号就和具体的file_operations结构体联系起来了,
- *操作主设备号为BUTTON_MAJOR的设备文件时,就会调用
- *tq2440_buttons_fops中的相关成员函数,BUTTON_MAJOR可以设为0,
- *表示由内核自动分配主设备号
- */
- if(BUTTON_MAJOR) //手动分配设备号
- {
- dev_num=MKDEV(BUTTON_MAJOR, BUTTON_MINOR);
- ret=register_chrdev_region(dev_num,DEV_COUNT,DEVICE_NAME);
- }
- else { //动态分配设备号
- ret = alloc_chrdev_region(&dev_num,BUTTON_MINOR,DEV_COUNT,DEVICE_NAME);
- }
- if(ret<0) {
- printk(DEVICE_NAME " can't register major number \n");
- return ret;
- }
- /*动态申请cdev结构体的内存*/
- buttons_cdev_p = kmalloc(sizeof(struct cdev),GFP_KERNEL);
- if(!buttons_cdev_p) //申请失败
- {
- ret = -ENOMEM;
- goto fial_malloc;
- }
- memset(buttons_cdev_p,0,sizeof(struct cdev));
- buttons_cdev_setup();
- //注册一个类,使mdev可以在"/dev/"目录下面
- //建立设备节点
- button_class = class_create(THIS_MODULE,DEVICE_NAME);
- if(IS_ERR(button_class))
- {
- printk("Error:Failed to creat button_class \n");
- return -1;
- }
- //创建一个设备节点,节点名为DEVICE_NAME
- device_create(button_class,NULL,dev_num,NULL,DEVICE_NAME);
- printk(DEVICE_NAME " initialized \n");
- return 0;
- fial_malloc:unregister_chrdev_region(dev_num, 1);
- }
- /*这两行制定驱动程序的初始化函数和卸载函数*/
- module_init(tq2440_buttons_init);
- module_exit(tq2440_buttons_exit)
下面是测试程序:
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- int main(int argc,char **argv)
- {
- int i;
- int ret;
- int fd;
- int press_cnt[4];
- fd=open("/dev/tq2440-buttons",0);
- if(fd<0) {
- printf("Can't open /dev/tq2440-buttons \n");
- return -1;
- }
- //这是个无限循环,进程有可能在read函数中休眠,当有按键按下时,
- //它才返回
- while(1) {
- ret = read(fd,press_cnt,sizeof(press_cnt));
- if(ret<0) {
- printf("read err !\n");
- continue;
- }
- //如果被按下的次数不为0,打印出来
- for(i=0;i<sizeof(press_cnt)/sizeof(press_cnt[0]);i++) {
- if(press_cnt[i])
- printf("Key%d has been pressed %d times \n",i+1,press_cnt[i]);
- }
- }//while
- }
进入根文件系统dev目录,发现已经成功动分配设备,并自动创建文件节点
[nick@TQ2440 /dev]# ls -l tq*
crw-rw---- 1 0 0 232, 0 Jan 1 00:00 tq2440-adc
crw-rw---- 1 0 0 254, 0 Jan 1 00:00 tq2440-buttons
crw-rw---- 1 0 0 231, 0 Jan 1 00:00 tq2440-leds
crw-rw---- 1 0 0 204, 64 Jan 1 00:00 tq2440_serial0
crw-rw---- 1 0 0 204, 65 Jan 1 00:00 tq2440_serial1
crw-rw---- 1 0 0 204, 66 Jan 1 00:00 tq2440_serial2
下载内核后,运行测试程序
[nick@TQ2440 /app]# ./buttons_test &
查看中断已经注册成功
[nick@TQ2440 /proc]# cat interrupts
CPU0
16: 0 s3c-ext0 KEY1
17: 0 s3c-ext0 KEY2
18: 0 s3c-ext0 KEY3
30: 27496 s3c S3C2410 Timer Tick
32: 0 s3c s3c2410-lcd
43: 0 s3c s3c2440-i2c
48: 0 s3c-ext KEY4
51: 2587 s3c-ext eth0
70: 156 s3c-uart0 s3c2440-uart
71: 1839 s3c-uart0 s3c2440-uart
83: 0 - s3c2410-wdt
Err: 0
第一列表示中断号
第二列表示这个中断发生的次数
第三列表示这个中断的硬件访问结构“struct irq_chip *chip"的名字,它在初始化中断体系结构时指定
第四列表示中断的名称
这时按下按键,输出如下
IRQ:48
Key4 has been pressed 1 times
IRQ:16
Key1 has been pressed 1 times
IRQ:18
Key3 has been pressed 1 times
IRQ:48
Key4 has been pressed 1 times
IRQ:16
Key1 has been pressed 1 times
IRQ:17
Key2 has been pressed 1 times
- 2440 Linux按键驱动及测试程序
- linux按键驱动编写及测试程序
- 按键驱动测试程序
- Linux内核安装按键驱动步骤及测试
- platform_button 按键驱动的测试程序
- misc类型 按键驱动及应用- Linux
- linux下的spi驱动及测试程序移植开发
- Linux驱动---按键驱动
- linxu下244X的按键驱动,测试程序
- 基于中断的按键驱动以及其测试程序
- MINI2440 按键输入子系统 驱动及测试代码分析
- Linux触摸屏驱动测试程序
- linux按键驱动模块(中断方式) 程序和调试总结
- linux按键驱动示例
- linux按键驱动示例
- linux按键驱动
- linux 按键驱动
- Linux系统按键驱动
- 函数指针的一些小理解
- Provider-Defined Properties in DBPROPSET_JETOLEDB_DBINIT
- PPT单一对象设置多个动作、多个对象设置同一动作
- 第七章代码2
- J2ME的小飞机游戏
- 2440 Linux按键驱动及测试程序
- Cocos2D-x游戏开发之二:菜单事件响应
- Python字符编码详解
- 2012华为校园招聘机考试题总结(厦门大学) 渣渣的答案= =!
- 最全的IO操作知识总结
- SG函数模板
- 计科1111-1114班第二周讲义、课外作业(截止日期:2014年3月20日23点-周四晚,学委飞信通知同学)
- javaBean
- static