驱动之字符设备----按键中断写驱动流程:
传参时: 将字符串转换成整数; 按键 驱动:
open函数中:注册中断 request_irq(irq, ) release 函数:释放中断 free_irq(unsigned int irq, void *dev_id); 中断处理函数(中断号, , ,)。。。。。。(第一步,打印键值----à将键值保存在一个变量中,传递给驱动???如何通过缓存,将快速的按键都保存下来)
按键驱动:(呵呵,虽然挺简单的,但是初学的我,还是搞了一天半,查了不少书。。。。。) ① 设备驱动模块的加载:(MKDEV生成主设备号、注册设备号、ioremap虚拟地址的映射、读改写、)
1 /*设备驱动模块的加载*/ ② 设备驱动的卸载模块:(包括取消映射、注销设备、释放申请的设备号) View Code 1 static void __exit my_key_exit(void)
③ 设备注册 (cdev_init建立cdev和file_operations之间的联系、cdev_add向系统添加一个设备) 1 /*设备的注册*/ ④ file_operations结构体,成员函数实现字符设备和内核的接口
1 struct file_operations key_fops = { ⑤ open函数中:注册中断 request_irq(irq,hander,irqflags,name, dev_id )其中添加了一种驱动程序的出错处理。。。goto 函数实现 1 static int my_key_open(struct inode *inodep, struct file *filep) ⑥ release函数:(释放中断)
View Code 1 static int my_key_release(struct inode *inodep,struct file *filep)
⑦ 最后的中断处理函数(irqreturn_t 可能有两种返回值,IRQ_NONE和IRQ_HANDLED;当中断处理函数程序检测到一个中断时,但该中断对应的设备并不是在注册处理函数期间指定的产生源时,返回IRQ_NONE;当中断处理程序被正确调用,且确实是他所对应设备产生了中断时,返回IRQ_HANDLED;)
1 irqreturn_t hander(unsigned int irq, void *dev_id)
驱动程序的出错处理 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 |
|