http://huao429006.blog.163.com/blog/static/171819785201082883523701/
基于2.6.30.4
的内核
函数: int
request_irq(unsigned int irq, void (*handler)
(int irq,void dev_id), unsigned long flags, const char *devname,
void
*dev_id) 在<linux/sched.h>
中定义。调用成功时,返回0,失败时为负数。
irq:
中断信号线,头文件:<mach/irqs.h>
handler:
中断处理函数
(就是中断处理函数名,如:buttons_interrupt)
在<linux/interrupt.h>中定义为:
typedef irqreturn_t (*irq_handler_t)(int, void
*);
flags:
中断有关的位掩码,介绍如下:
devname:
设备名(如: "simpledkey")
dev_id:
dev_id作用主要有两点:一.在中断处理程序释放时使用到dev_id,void free_irq(unsigned int irq,
void *dev_id)。
二.将使用该中断处理程序的设备结构体传递给该中断处理程序
注意:键盘驱动程序中每个注册的中断信号线一定要使用唯一的 dev_id 否则就会出现在free_irq()
时出现Trying
to free already-free IRQ
的情况。
1. 中断类型: 在中使用flags:
下面这些宏定义在:<linux/interrupt.h> 中:
#define
SA_SHIRQ
共享中断(旧版本的,2.6.19之前的内核)
#define
IRQF_SHARED
共享中断(新版本的)
#define
SA_INTERRUPT
快速中断(旧版本的)
#define
IRQF_DISABLED
快速中断(新版本的)
#define
IRQF_SAMPLE_RANDOM 表示本中断源可以用作随机数生成器的熵池
2. 中断的触发类型:
在set_irq_type(irq, type)中使用
#define
IRQ_TYPE_NONE
0x00000000 未指明类型
#define
IRQ_TYPE_EDGE_RISING 0x00000001 上升沿触发
#define
IRQ_TYPE_EDGE_FALLING 0x00000002 下降沿触发
#define
IRQ_TYPE_EDGE_BOTH
(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define
IRQ_TYPE_LEVEL_HIGH
0x00000004
高电平触发
#define
IRQ_TYPE_LEVEL_LOW
0x00000008 低电平触发
#define
IRQ_TYPE_SENSE_MASK
0x0000000f
#define
IRQ_TYPE_PROBE
0x00000010
通常:
int __init
xxx_init(void)
int __exit
xxx_exit(void);
"void"
不能少,否则会有警告。
注意:disable_irq(int irq);
不能在中断服务程序中用使用:
disable_irq不但会禁止给定的中断,而且也会等待当前正在执行的中断处理例程完成。
下面的函数的头文件为:<asm/uaccess.h>
unsigned long
copy_to_user(void __user *to,
const void *from, unsigned long
count);
unsigned long
copy_from_user(void *to, const
__user *from, unsigned long count);
经验:
对等待对列的初始化一定要放在 kmalloc() 分配内存之后,否则会出现段错误
Kdev = kmalloc(sizeof(struct kscan_dev), GFP_KERNEL);
if(!Kdev){
result = -ENOMEM;
goto fail;
}
init_waitqueue_head(&Kdev->wq);
这是完全由本人自己编的键盘驱动程序:
#include<linux/fs.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/types.h>
#include<linux/cdev.h>
#include<linux/interrupt.h>
#include<asm/uaccess.h>
#include<mach/hardware.h>
#include<mach/irqs.h>
#include<mach/regs-irq.h>
#include<asm/io.h>
#include<linux/sched.h>
#include<linux/wait.h>
#include<asm/signal.h>
#include<mach/regs-gpio.h>
#define KMajor 111
int flag =0;
static int inc=0;
MODULE_AUTHOR("Huao");
MODULE_LICENSE("Dual BSD/GPL");
struct kscan_dev
{
struct semaphore sem;
struct cdev cdev;
int key;
};
struct kscan_dev *Kdev;
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int irqArray[4] = {
IRQ_EINT0,IRQ_EINT1,IRQ_EINT2,IRQ_EINT4
};
static int devid[4] = {
0,1,2,4
};
static irqreturn_t Key_Interrupt(int irq, void *dev_id)
{
Kdev->key = 2;
flag = 1;
wake_up_interruptible(&wq);
printk("get key
%d!\n",Kdev->key);
return IRQ_HANDLED;
}
static int kscan_open(struct inode *inode ,struct file
*filp)
{
if(inc > 0) return
-ERESTARTSYS;
inc ++;
printk("enter kscan_open()\n");
//璁块棶kscan_dev缁撴瀯
Kdev = container_of(inode->i_cdev,
struct kscan_dev, cdev);
filp->private_data = Kdev;
return 0;
}
static int kscan_close(struct inode *inode ,struct file
*filp)
{
inc --;
return 0;
}
ssize_t kscan_read(struct file *filp, char __user *buf, size_t
count,loff_t *f_pos)
{
//buf 涓虹敤鎴风紦鍐插尯锛宖_pos涓烘枃浠跺綋鍓嶅緱鍋忕Щ閲?
int sum;
struct kscan_dev *dev =
filp->private_data;
if (filp->f_flags
& O_NONBLOCK)
{
return -EAGAIN;
}else{
printk("read is
blocked!\n");
wait_event_interruptible(wq,
flag != 0);
flag = 0;
sum =1;
printk("read is woken
up!\n");
dev->key = 8;
if(copy_to_user(buf,
&dev->key, 1))
{
sum = -EFAULT;
}
}
return sum;
}
struct file_operations kscan_fops = {
.owner = THIS_MODULE,
.read = kscan_read,
.open = kscan_open,
.release = kscan_close,
};
static void __exit Kscan_exit(void)
{
dev_t dev_value;
int u;
dev_value = MKDEV(KMajor,0);
//閲婃斁涓柇淇″彿绾?
for(u = 0;u < 4;u ++){
disable_irq(irqArray[u]);
free_irq(irqArray[u], (void
*)&devid[u]);
}
if(Kdev)
{
cdev_del(&Kdev->cdev);
//鍒犻櫎璁惧
kfree(Kdev);
//閲婃斁鍐呭瓨
}
unregister_chrdev_region(dev_value,
1);
//dev_value琛ㄧず璧峰鍊?
printk(KERN_DEBUG "free irq
success\n");
printk("delete device success!\n");
}
static int __init Kscan_init(void)
{
int result,err;
dev_t dev = 0;
int i;
//涓柇瀵勫瓨鍣ㄧ殑鍒濆鍖?
writel((2<<0)|(2<<2)|(2<<4)|(2<<8),S3C2410_GPFCON); //璁剧疆绔彛涓轰腑鏂?
writel((2<<0)|(2<<4)|(2<<8)|(2<<16),S3C2410_EXTINT0); //涓嬮檷娌夸腑鏂?
writel(readl(S3C2410_EINTPEND)|1,S3C2410_EINTPEND); //缃?琛ㄧず宸茶姹?
writel(readl(S3C2410_EINTMASK)&0,S3C2410_EINTMASK); //娓呬腑鏂睆钄戒綅
//KMajor
涓轰富璁惧鍙凤紝MKdev()灏嗗叾杞崲鎴恉ev_t绫诲瀷
dev = MKDEV(KMajor,0);
printk(KERN_NOTICE "KScan:major is
%d\n",dev);
//鍔ㄦ?佸垎閰嶈澶囧彿dev锛?琛ㄧず绗竴涓璁惧鍙凤紝1涓鸿姹傜殑涓暟锛岃澶囧悕涓篕scan
result = register_chrdev_region(dev, 1,
"kscan"); //dev 鐢ㄤ簬杈撳嚭涓昏澶囧彿
if(result<0)
{
printk(KERN_WARNING
"KScan:can`t get major\n");
return result;
}
//涓簊truct kscan_dev 鍒嗛厤鍐呭瓨绌洪棿锛孏FP_KERNEL
琛ㄧず鍐呭瓨绌洪棿杩涚▼
Kdev = kmalloc(sizeof(struct kscan_dev),
GFP_KERNEL);
if(!Kdev){
result = -ENOMEM;
goto fail;
}
//娓呯┖kscan_dev缁撴瀯浣撳唴瀛?
memset(Kdev, 0, sizeof(struct
kscan_dev));
//鍒濆鍖栧凡鍒嗛厤鍒板緱缁撴瀯
cdev_init(&Kdev->cdev,
&kscan_fops);
Kdev->cdev.owner =
THIS_MODULE;
Kdev->cdev.ops =
&kscan_fops;
//鍦ㄥ唴鏍镐腑娉ㄥ唽璁惧缁撴瀯淇℃伅,濡傛灉澶辫触鍒欒繑鍥炶礋寰楅敊璇爜
err =
cdev_add(&Kdev->cdev, dev,
1);
if(err<0){
printk(KERN_NOTICE "adding
scull err is %d\n",err);
goto fail;
}
//鐢宠涓柇淇″彿绾?
for(i = 0;i < 4;i++){
if(request_irq(irqArray[i],
Key_Interrupt, 0, "kscan", (void
*)&devid[i]))
{
//鐢宠鎴愬姛鏃惰繑鍥?锛屽け璐ヨ繑鍥炶礋鏁?
printk("request
button irq failed\n");
return
-1;
}
}
//wait_queue_head_t wq;
printk(KERN_NOTICE"*** ***init
kscan successfully\n");
return 0;
fail:
Kscan_exit();
return result;
}
module_init(Kscan_init);
module_exit(Kscan_exit);
加载中,请稍候......