目录

  • 字符设备驱动(四)按键中断

    • 硬件IO
    • 程序设计
      • 中断配置
      • 中断关闭
      • 中断函数
      • 共享中断号
    • 测试
    • 完整的程序


title: 字符设备驱动(四)按键中断
tags: linux
date: 2018-11-23 17:26:57
toc: true
---

字符设备驱动(四)按键中断

硬件IO

 *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)

测试

  1. 加载驱动

    # insmod dri.ko
    # lsmod
    Module                  Size  Used by    Not tainted
    dri                     2748  2
  2. 验证驱动安装,查看并没有我们的中断

    # cat /proc/interruptsCPU030:      95434         s3c  S3C2410 Timer Tick32:          0         s3c  s3c2410-lcd33:          0         s3c  s3c-mci34:          0         s3c  I2SSDI35:          0         s3c  I2SSDO37:         12         s3c  s3c-mci42:          0         s3c  ohci_hcd:usb143:          0         s3c  s3c2440-i2c51:       1241     s3c-ext  eth060:          0     s3c-ext  s3c-mci70:         70   s3c-uart0  s3c2440-uart71:        121   s3c-uart0  s3c2440-uart79:          0     s3c-adc  s3c2410_action80:          0     s3c-adc  s3c2410_action83:          0           -  s3c2410-wdt
    Err:          0
  3. 以前使用测试程序调用open,这里可以使用 exec 5</dev/xyz0来打开设备,这个意思是打开这个设备到5去,接着就可以看到中断被打开了

    # ls /dev/xyz0
    /dev/xyz0# exec 5</dev/xyz0# cat /proc/interruptsCPU016:          0    s3c-ext0  S218:          0    s3c-ext0  S355:          0     s3c-ext  S463:          0     s3c-ext  S5
    Err:          0
  4. 按键测试一下会打印中断号

    # 按键按下会打印
    # irq55
    irq55
  5. 可以查看下中断次数,这里因为有按下中断和弹起中断,所以中断次数为2

    # cat /proc/interruptsCPU016:          0    s3c-ext0  S218:          0    s3c-ext0  S355:          2     s3c-ext  S463:          0     s3c-ext  S5
    Err:          0
  6. 查看下进程ps,查看shpid,查看其打开的文件/dev/xyz0

    # psPID  Uid        VSZ Stat Command770 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
    
  7. 关闭文件,可以发现文件已经关闭,中断也没有了

    #  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");

转载于:https://www.cnblogs.com/zongzi10010/p/10009173.html

字符设备驱动(四)按键中断相关推荐

  1. linux内核模块编程(六)----字符设备驱动中断开发

    先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题 一 why 字符设备驱动在我们 ...

  2. Linux 字符设备驱动结构(四)—— file_operations 结构体知识解析

    前面在 Linux 字符设备驱动开发基础 (三)-- 字符设备驱动结构(中) ,我们已经介绍了两种重要的数据结构 struct inode{...}与 struct file{...} ,下面来介绍另 ...

  3. linux内核创建字符节点,Tiny6410学习ing—(四)、嵌入式Linux内核驱动进阶—(7)、高级字符设备驱动(自动创建节点)—#931...

    按照国嵌的视频教程上来说的,最后就是-自动创建设备文件! 其实我感觉以前完全可以直接是手动创建了设备文件,然后就可以直接讲述自动创建设备文件,为啥非要拖到最后来讲述,我也就不清楚了!! 不管了,写完收 ...

  4. Linux字符设备驱动详解四(使用自属的xbus驱动总线)

    文章目录 系列文章目录 前言 驱动目录 正文 驱动总线 总线管理 总线注册 设备注册 驱动注册 代码示例 总结 系列文章目录 Linux字符设备驱动详解 Linux字符设备驱动详解二(使用设备驱动模型 ...

  5. linux major头文件_《Linux设备驱动程序》(四)——字符设备驱动(上)

    之前我们说过,Linux设备主要分为三类:字符设备.块设备和网络接口. 字符设备相对于另外两个设备更加容易理解,同时,这类设备也适合大多数简单的硬件设备,因此,接下来我们学习一下字符设备驱动. 字符驱 ...

  6. 一起分析Linux系统设计思想——05字符设备驱动框架剖析(四)

    在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习.我的使命就是过滤掉大量的垃圾信息,将知识体系化,以短平快的方式直 ...

  7. 深入浅出:Linux设备驱动之字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...

  8. 虚拟字符设备驱动开发步骤

    目录 前言 字符设备驱动简介 内核驱动操作函数集合(file_operations结构体) 字符设备驱动开发步骤 .ko驱动模块的加载和卸载(module_init驱动入口.insmod驱动加载) 字 ...

  9. Linux 字符设备驱动开发基础(一)—— 编写简单 LED 设备驱动

    现在,我们来编写自己第一个字符设备驱动 -- 点亮LED.(不完善,后面再完善) 硬件平台:Exynos4412(FS4412) 编写驱动分下面几步: a -- 查看原理图.数据手册,了解设备的操作方 ...

最新文章

  1. 给IIS添加CA证书以支持https
  2. sql2008r 收缩数据库日志log文件;删除errorlog文件的方法
  3. VS2010中如何更改项目名称【转】
  4. vue.js源码学习分享(一)
  5. linux c之通过管道实现兄弟间进程通信:
  6. 使用Linux版Redis
  7. 矩阵的Cholesky分解
  8. System verilog随机函数$urandom输出8bit随机数
  9. MATLAB中的柱面与球面
  10. Struts2.1.6 + Spring2.5+Hibernate3.2整合
  11. 荔枝服务器维护,手把手为你讲解win10系统自动维护功能管理的问题.
  12. 研究validation插件到现在的感受
  13. java 文件的删除一行_如何从java中的文件中删除一行文本?
  14. 通讯录管理系统JAVA版本
  15. 飞鸟尽,良弓藏;狡兔死,走狗烹。
  16. bzoj5369: [PKUSC2018]最大前缀和 (状压dp)
  17. 2018美团实习笔试
  18. 学术研讨会---Micheal Stonebraker的主题演讲【读后感】
  19. 3分钟带你了解微信小程序开发
  20. Bash 里设置退出conda环境

热门文章

  1. 微信小程序开始试点广告功能,一个新的广告竞价体系将要诞生
  2. Visio 画图去掉页边距(图形四周的空白区域)的解决办法
  3. 基于嵌入式操作系统VxWorks的多任务并发程序设计(3)――任务调度
  4. 苹果紧急修复已遭利用的两个0day
  5. 微软7月修复117个漏洞,其中9个为0day,2个是Pwn2Own 漏洞
  6. 微软3月补丁星期二最值得注意的是CVE-2020-0684和神秘0day CVE-2020-0796
  7. Python排序算法[二]:测试数据的迷雾散去
  8. Mongodb 与 MySQL对比
  9. ls命令 文件和目录属性
  10. 精品软件 推荐 DiskGenius专业版 磁盘管理软件 4.7 注册版本分享