驱动之字符设备----按键中断
2012-03-04 11:14
344 查看
写驱动流程:
传参时: 将字符串转换成整数;
按键 驱动:
open函数中:注册中断 request_irq(irq, )
release 函数:释放中断 free_irq(unsigned int irq, void *dev_id);
中断处理函数(中断号, , ,)。。。。。。(第一步,打印键值----à将键值保存在一个变量中,传递给驱动???如何通过缓存,将快速的按键都保存下来)
按键驱动:(呵呵,虽然挺简单的,但是初学的我,还是搞了一天半,查了不少书。。。。。)
① 设备驱动模块的加载:(MKDEV生成主设备号、注册设备号、ioremap虚拟地址的映射、读改写、)
② 设备驱动的卸载模块:(包括取消映射、注销设备、释放申请的设备号)
View Code
⑦ 最后的中断处理函数(irqreturn_t 可能有两种返回值,IRQ_NONE和IRQ_HANDLED;当中断处理函数程序检测到一个中断时,但该中断对应的设备并不是在注册处理函数期间指定的产生源时,返回IRQ_NONE;当中断处理程序被正确调用,且确实是他所对应设备产生了中断时,返回IRQ_HANDLED;)
驱动程序的出错处理 goto
if (a)
goto a;
if (b)
goto b;
if (c)
goto c;
c: free_irq(b);
b: free_irq(a);
a: return 0;
首先注册一个中断处理程序:request_irq(irq , hander, irqflags,devname, dev_id );
有注册就有释放: free_irq(irqno, dev_id);
中断处理程序:static irqreturn_t hander (int irqno,void * dev_id, struct pt_regs *regs);
注意:函数的返回值是一个特殊的类型,irqreturn_t 可能有两种返回值,IRQ_NONE和IRQ_HANDLED;当中断处理函数程序检测到一个中断时,但该中断对应的设备并不是在注册处理函数期间指定的产生源时,返回IRQ_NONE;当中断处理程序被正确调用,且确实是他所对应设备产生了中断时,返回IRQ_HANDLED;利用这两个返回值,内核可以知道设备发出的是否是一种虚假的(为请求)的中断;
static :
中断处理程序通常会标记位static,因为它从来都不会被别的文件中的代码直接调用。另外,中断处理程序是无需重入的,当一个给定的中断处理程序正在执行时,相应的中断线在所有的处理器上都会被屏蔽掉,以防止在同一个中断上接收另外一个新的中断处理。
驱动程序:
测试程序:
Makefile文件:
1.原理图-à输出高电平 led亮 |
2.对应核心板的GPIO口 |
3.查看寄存器地址 |
4.了解管脚的功能 |
5.开始写驱动 ①许可证 ②加载函数 申请设备号 MKDEV Register_chrdev_region Alloc_chrdev_region 注册设备 Cdev File_oparetions---àopen/release Cdev_init Cdev_add 寄存器映射 Ioremap(PA,size) 配置寄存器(读改写的方式) Readll() Write() ③卸载函数 取消映射 注销设备 释放 |
按键 驱动:
1.原理图 |
2.外部中断,下降沿触发 Request_irq的第3个参数设置 |
3.GPH0 |
开始写驱动: 许可证 加载模块 ① 申请设备号 ② 注册设备 ③ IO的初始化为外部中断模式 卸载 ① 注销设备 ② 释放设备号 |
release 函数:释放中断 free_irq(unsigned int irq, void *dev_id);
中断处理函数(中断号, , ,)。。。。。。(第一步,打印键值----à将键值保存在一个变量中,传递给驱动???如何通过缓存,将快速的按键都保存下来)
按键驱动:(呵呵,虽然挺简单的,但是初学的我,还是搞了一天半,查了不少书。。。。。)
① 设备驱动模块的加载:(MKDEV生成主设备号、注册设备号、ioremap虚拟地址的映射、读改写、)
/*设备驱动模块的加载*/ static int __init my_key_init(void) { int error; dev = MKDEV(key_major,key_minor); #if 1 if (key_major) { register_chrdev_region(dev,1,"mykey"); } else { alloc_chrdev_region(dev,0,1,"my_key"); } #endif error = register_chrdev_region(dev,1,"mykey"); if (error < 0) { printk(KERN_WARNING "can't get major %d\n",key_major); return error; } char_reg_setup_cdev(); gph0con_va = ioremap(GPH0CON,4); if (gph0con_va == NULL) { printk(KERN_WARNING "ioremap error......\n"); return -ENOMEM; } writel((readl(gph0con_va)& ~0xff0ffff0) | 0x22022220, gph0con_va); //GPH0CON外部中断模式 printk(KERN_INFO "mykey driver is ok.....\n"); return 0; }
② 设备驱动的卸载模块:(包括取消映射、注销设备、释放申请的设备号)
View Code
static int my_key_release(struct inode *inodep,struct file *filep) { free_irq(IRQ_EINT(2),NULL); free_irq(IRQ_EINT(1),NULL); printk(KERN_INFO "devices closed.....\n"); return 0; }
⑦ 最后的中断处理函数(irqreturn_t 可能有两种返回值,IRQ_NONE和IRQ_HANDLED;当中断处理函数程序检测到一个中断时,但该中断对应的设备并不是在注册处理函数期间指定的产生源时,返回IRQ_NONE;当中断处理程序被正确调用,且确实是他所对应设备产生了中断时,返回IRQ_HANDLED;)
irqreturn_t hander(unsigned int irq, void *dev_id) { switch (irq) { case IRQ_EINT(1): printk(KERN_INFO "key 1 is pressed......\n"); break; case IRQ_EINT(2): printk(KERN_INFO "key 2 is pressed......\n"); break; default : break; } return IRQ_HANDLED;//当中断处理程序被正确调用,且确实是他所对应设备产生了中断时,返回IRQ_HANDLED }
驱动程序的出错处理 goto
if (a)
goto a;
if (b)
goto b;
if (c)
goto c;
c: free_irq(b);
b: free_irq(a);
a: return 0;
首先注册一个中断处理程序:request_irq(irq , hander, irqflags,devname, dev_id );
有注册就有释放: free_irq(irqno, dev_id);
中断处理程序:static irqreturn_t hander (int irqno,void * dev_id, struct pt_regs *regs);
注意:函数的返回值是一个特殊的类型,irqreturn_t 可能有两种返回值,IRQ_NONE和IRQ_HANDLED;当中断处理函数程序检测到一个中断时,但该中断对应的设备并不是在注册处理函数期间指定的产生源时,返回IRQ_NONE;当中断处理程序被正确调用,且确实是他所对应设备产生了中断时,返回IRQ_HANDLED;利用这两个返回值,内核可以知道设备发出的是否是一种虚假的(为请求)的中断;
static :
中断处理程序通常会标记位static,因为它从来都不会被别的文件中的代码直接调用。另外,中断处理程序是无需重入的,当一个给定的中断处理程序正在执行时,相应的中断线在所有的处理器上都会被屏蔽掉,以防止在同一个中断上接收另外一个新的中断处理。
驱动程序:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/uaccess.h> #include <linux/cdev.h> #include <asm/io.h> #include <mach/irqs.h> #include <linux/cdev.h> #define GPH0CON 0xE0300100 MODULE_LICENSE ("GPL"); int key_major = 250; int key_minor = 0; dev_t dev = 0; static struct cdev cdev; unsigned long *gph0con_va; irqreturn_t hander(unsigned int irq, void *dev_id) { switch (irq) { case IRQ_EINT(1): printk(KERN_INFO "key 1 is pressed......\n"); break; case IRQ_EINT(2): printk(KERN_INFO "key 2 is pressed......\n"); break; default : break; } return IRQ_HANDLED; } static int my_key_open(struct inode *inodep, struct file *filep) { if (request_irq(IRQ_EINT(1),hander,IRQF_DISABLED | IRQF_TRIGGER_FALLING,"key1",NULL)) { printk("key 1 request_irq error...\n"); goto key1; } if (request_irq(IRQ_EINT(2),hander,IRQF_DISABLED | IRQF_TRIGGER_FALLING,"key2",NULL)) { printk("key 2 request_irq error...\n"); goto key2; } printk(KERN_INFO "device opend success..\n"); return 0; key2: free_irq(IRQ_EINT(1),NULL); key1: return 0; } static int my_key_release(struct inode *inodep,struct file *filep) { free_irq(IRQ_EINT(2),NULL); free_irq(IRQ_EINT(1),NULL); printk(KERN_INFO "devices closed.....\n"); return 0; } struct file_operations key_fops = { .owner = THIS_MODULE, .open = my_key_open, .release = my_key_release, }; static void char_reg_setup_cdev(void) { int error; cdev_init(&cdev,&key_fops);
error = cdev_add(&cdev,dev,1); if (error) { printk(KERN_NOTICE "char_reg_setup_cdev errro.,....\n"); } return ; } static int __init my_key_init(void) { int error; dev = MKDEV(key_major,key_minor); #if 1 if (key_major) { register_chrdev_region(dev,1,"mykey"); } else { alloc_chrdev_region(dev,0,1,"my_key"); } #endif error = register_chrdev_region(dev,1,"mykey"); if (error < 0) { printk(KERN_WARNING "can't get major %d\n",key_major); return error; } char_reg_setup_cdev(); gph0con_va = ioremap(GPH0CON,4); if (gph0con_va == NULL) { printk(KERN_WARNING "ioremap error......\n"); return -ENOMEM; } writel((readl(gph0con_va)& ~0xff0ffff0) | 0x22022220, gph0con_va); printk(KERN_INFO "mykey driver is ok.....\n"); return 0; } static void __exit my_key_exit(void) { iounmap(gph0con_va); cdev_del(&cdev); unregister_chrdev_region(dev,1);
printk(KERN_INFO "myket clean up\n"); return ; } module_init(my_key_init); module_exit(my_key_exit);
测试程序:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main() { int fd; int ret; // int key_num; fd = open("/dev/my_key",O_RDWR); if (fd < 0) { printf("open error\n"); return -1; } /* while (1) { ret = read(fd,&key_num,sizeof(int)); printf("you press the key of %d\n",key_num); } */ while (1); close(fd); printf("devices close...\n"); return 0; }
Makefile文件:
$(warning KERNELRELEASE=$(KERNELRELEASE)) ifeq ($(KERNELRELEASE),) #KERNELDIR ?= /lib/modules/$(shell uname -r)/build KERNELDIR ?= /home/linux/linux-2.6.35/ #该目录是你的内核的目录 PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* module .PHONY:modules modules_install clean else # obj-m := hello.o obj-m += my_key.o # obj-m := char_reg.o endif
相关文章推荐
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-查询+中断+引入poll机制的按键驱动程序
- 字符设备驱动笔记——中断方式按键驱动之linux中断处理结构(五)
- 字符设备驱动之按键中断——FS2410
- 字符设备驱动之按键中断(阻塞机制)——FS2410
- 基于platform总线的中断(按键)字符设备驱动设计
- 嵌入式linux:字符设备驱动-----按键驱动(中断+poll机制)
- 字符设备驱动笔记——中断方式按键驱动之linux异常处理结构(四)
- 字符设备驱动之按键中断(POLL机制)——FS2410
- 基于platform总线的中断(按键)字符设备驱动设计
- Linux设备驱动开发基础---字符设备驱动程序开发之基于中断的按键驱动
- 基于platform总线的中断(按键)字符设备驱动设计
- 字符设备驱动-中断方式操控按键
- 基于platform总线的中断(按键)字符设备驱动设计
- 字符设备驱动程序按键驱动---中断方式
- 字符设备驱动--中断方式下的按键驱动
- 字符设备驱动程序之中断方式的按键驱动
- 字符设备驱动之中断按键驱动
- 字符设备驱动之按键处理二(中断处理的按键驱动程序)
- 字符设备驱动-----按键驱动(中断+poll机制)
- arm 驱动基础:字符设备之异步通信:按键中断,通知应用程序