标签:选择 处理 gpio 自动 nod ons href pos \n
目录
title: 字符设备驱动(四)按键中断
tags: linux
date: 2018-11-23 17:26:57
toc: true
---
*S2 eint0 GPF0
*S3 eint2 GPF2
*S4 eint11 GPG3
*S5 eint19 GPG11
配置中断引脚,配置中断触发方式,这是在request_irq
中配置的,根据irqflags
去调用中断数组中的chip
结构成员进行芯片相关的操作设置desc->chip->set_type
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
irq:中断号
handler:处理函数
irqflags:上升沿触发,下降沿触发,边沿触发等。指定了快速中断或中断共享等中断处理属性.
*devname:中断名字。通常是设备驱动程序的名称。改值用在 /proc/interrupt 系统 (虚拟)
文件上,或内核发生中断错误时使用。
dev_id 可作为共享中断时的中断区别参数,也可以用来指定中断服务函数需要参考的数据地址。也用于卸载action
确定中断号,可以查看这个函数的调用s3c24xx_init_irq
很明显的看到能够使用的宏在include/asm-arm/arch/irqs.h
中定义
#define IRQ_EINT0 S3C2410_IRQ(0) /* 16 */
#define IRQ_EINT2 S3C2410_IRQ(2)
#define IRQ_EINT11 S3C2410_IRQ(39)
#define IRQ_EINT19 S3C2410_IRQ(47)
中断标志irqflags
,同样在s3c24xx_init_irq
找到相关的set_irq_chip
,找到对应的chip
//中断0
set_irq_chip(irqno, &s3c_irq_eint0t4);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
//中断4-23
set_irq_chip(irqno, &s3c_irqext_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
//0~3
static struct irq_chip s3c_irq_eint0t4 = {
.name = "s3c-ext0",
.ack = s3c_irq_ack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
.set_wake = s3c_irq_wake,
.set_type = s3c_irqext_type,
};
//4~23
static struct irq_chip s3c_irqext_chip = {
.name = "s3c-ext",
.mask = s3c_irqext_mask,
.unmask = s3c_irqext_unmask,
.ack = s3c_irqext_ack,
.set_type = s3c_irqext_type,
.set_wake = s3c_irqext_wake
};
深入分析下set_type
函数,可以找到对应的irqflags
使用者s3c_irqext_type
中的参数type
也就是标志irqflags
,定义在include/asm-arm/irq.h
#define IRQT_NOEDGE (0)
#define IRQT_RISING (__IRQT_RISEDGE)
#define IRQT_FALLING (__IRQT_FALEDGE)
#define IRQT_BOTHEDGE (__IRQT_RISEDGE|__IRQT_FALEDGE)
#define IRQT_LOW (__IRQT_LOWLVL)
#define IRQT_HIGH (__IRQT_HIGHLVL)
#define IRQT_PROBE IRQ_TYPE_PROBE
//s3c_irqext_type
switch (type)
{
case IRQT_NOEDGE:
printk(KERN_WARNING "No edge setting!\n");
break;
case IRQT_RISING:
newvalue = S3C2410_EXTINT_RISEEDGE;
break;
case IRQT_FALLING:
newvalue = S3C2410_EXTINT_FALLEDGE;
break;
case IRQT_BOTHEDGE:
newvalue = S3C2410_EXTINT_BOTHEDGE;
break;
case IRQT_LOW:
newvalue = S3C2410_EXTINT_LOWLEV;
break;
case IRQT_HIGH:
newvalue = S3C2410_EXTINT_HILEV;
break;
default:
printk(KERN_ERR "No such irq type %d", type);
return -1;
}
这里选择双边触发IRQT_BOTHEDGE
,
char *devname
中断名随便取名
dev_id
可用作释放中断函数中删除action
的标识,这里可以先写作1
综上,代码为
/* 配置GPF0,2为输入引脚 */
/* 配置GPG3,11为输入引脚 */
request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);
这里需要增加释放删除action
链表的函数
int drv_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT0, &pins_desc[0]);
free_irq(IRQ_EINT2, &pins_desc[1]);
free_irq(IRQ_EINT11, &pins_desc[2]);
free_irq(IRQ_EINT19, &pins_desc[3]);
return 0;
}
static struct file_operations drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = drv_open,
.read = drv_read,
.release = drv_close,
};
在request_irq
中会去注册中断函数到action
链表,查看使用request_irq
的地方参考定义形式.比如随便艘多一个static irqreturn_t aaci_irq(int irq, void *devid)
仿照定义,打印下中断号
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
printk("irq%d\r\n",irq);
return IRQ_RETVAL(IRQ_HANDLED);
}
这里按键不要使用共享中断号,取用单独的中断号区分好处理
#define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */
// 使用下面的
#define IRQ_EINT4 S3C2410_IRQ(32) /* 48 */
#define IRQ_EINT5 S3C2410_IRQ(33)
#define IRQ_EINT6 S3C2410_IRQ(34)
#define IRQ_EINT7 S3C2410_IRQ(35)
#define IRQ_EINT8 S3C2410_IRQ(36)
加载驱动
# insmod dri.ko
# lsmod
Module Size Used by Not tainted
dri 2748 2
验证驱动安装,查看并没有我们的中断
# cat /proc/interrupts
CPU0
30: 95434 s3c S3C2410 Timer Tick
32: 0 s3c s3c2410-lcd
33: 0 s3c s3c-mci
34: 0 s3c I2SSDI
35: 0 s3c I2SSDO
37: 12 s3c s3c-mci
42: 0 s3c ohci_hcd:usb1
43: 0 s3c s3c2440-i2c
51: 1241 s3c-ext eth0
60: 0 s3c-ext s3c-mci
70: 70 s3c-uart0 s3c2440-uart
71: 121 s3c-uart0 s3c2440-uart
79: 0 s3c-adc s3c2410_action
80: 0 s3c-adc s3c2410_action
83: 0 - s3c2410-wdt
Err: 0
以前使用测试程序调用open
,这里可以使用 exec 5</dev/xyz0
来打开设备,这个意思是打开这个设备到5去,接着就可以看到中断被打开了
# ls /dev/xyz0
/dev/xyz0
# exec 5</dev/xyz0
# cat /proc/interrupts
CPU0
16: 0 s3c-ext0 S2
18: 0 s3c-ext0 S3
55: 0 s3c-ext S4
63: 0 s3c-ext S5
Err: 0
按键测试一下会打印中断号
# 按键按下会打印
# irq55
irq55
可以查看下中断次数,这里因为有按下中断和弹起中断,所以中断次数为2
# cat /proc/interrupts
CPU0
16: 0 s3c-ext0 S2
18: 0 s3c-ext0 S3
55: 2 s3c-ext S4
63: 0 s3c-ext S5
Err: 0
查看下进程ps
,查看sh
的pid
,查看其打开的文件/dev/xyz0
# ps
PID Uid VSZ Stat Command
770 0 3096 S -sh
# ls -l /proc/770/fd
lrwx------ 1 0 0 64 Jan 1 00:07 0 -> /dev/console
lrwx------ 1 0 0 64 Jan 1 00:07 1 -> /dev/console
lrwx------ 1 0 0 64 Jan 1 00:07 10 -> /dev/tty
lrwx------ 1 0 0 64 Jan 1 00:07 2 -> /dev/console
lr-x------ 1 0 0 64 Jan 1 00:07 5 -> /dev/xyz0
关闭文件,可以发现文件已经关闭,中断也没有了
# exec 5<&-
# ls -l /proc/770/fd
lrwx------ 1 0 0 64 Jan 1 00:07 0 -> /dev/console
lrwx------ 1 0 0 64 Jan 1 00:07 1 -> /dev/console
lrwx------ 1 0 0 64 Jan 1 00:07 10 -> /dev/tty
lrwx------ 1 0 0 64 Jan 1 00:07 2 -> /dev/console
# cat /proc/interrupts
#无相关中断了
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
//#include <linux/interrupt.h>
volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;
volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;
static struct class *drv_class;
static struct class_device *drv_class_dev;
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
printk("irq%d\r\n",irq);
return IRQ_HANDLED;
}
static int drv_open(struct inode *inode, struct file *file)
{
/* 配置GPF0,2为输入引脚 */
/* 配置GPG3,11为输入引脚 */
request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", 1);
request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", 1);
request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", 1);
request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", 1);
return 0;
}
int drv_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT0, 1);
free_irq(IRQ_EINT2, 1);
free_irq(IRQ_EINT11,1);
free_irq(IRQ_EINT19,1);
return 0;
}
static ssize_t drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
//int minor = MINOR(file->f_dentry->d_inode->i_rdev);
//printk("drv_write=%d\n",minor);
return 0;
}
static ssize_t drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
return 0;
}
static struct file_operations drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = drv_open,
.write = drv_write,
.read = drv_read,
.release = drv_close,
};
static int major;
static int drv_init(void)
{
int minor=0;
major=register_chrdev(0, "drv", &drv_fops); // 注册, 告诉内核
drv_class = class_create(THIS_MODULE, "drv");
drv_class_dev = class_device_create(drv_class, NULL, MKDEV(major, 0), NULL, "xyz%d", minor);
gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
gpfdat = gpfcon + 1;
gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
gpgdat = gpgcon + 1;
return 0;
}
static void drv_exit(void)
{
unregister_chrdev(major, "drv"); // 卸载
class_device_unregister(drv_class_dev);
class_destroy(drv_class);
iounmap(gpfcon);
iounmap(gpgcon);
}
module_init(drv_init);
module_exit(drv_exit);
MODULE_LICENSE("GPL");
标签:选择 处理 gpio 自动 nod ons href pos \n
原文地址:https://www.cnblogs.com/zongzi10010/p/10009173.html