zoukankan      html  css  js  c++  java
  • 字符设备驱动(四)按键中断


    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!
      ");
      			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
    ",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/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
      
    3. 以前使用测试程序调用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
      
    4. 按键测试一下会打印中断号

      # 按键按下会打印
      # irq55
      irq55
      
    5. 可以查看下中断次数,这里因为有按下中断和弹起中断,所以中断次数为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
      
    6. 查看下进程ps,查看shpid,查看其打开的文件/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
      
      
    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
    ",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
    ",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");
    
    
    
  • 相关阅读:
    Js定义一个表单并提交
    jQuery插件3种类型
    Jquery.extend()和jQuery.fn.extend(object);
    maven 依赖调解
    DOS 查看端口占用,Kill线程
    git 笔记
    mongodb添加登陆验证
    react 使用fortawesome字体图标
    redux小结
    MDM-Object.fn 一些实践与理解
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/10009173.html
Copyright © 2011-2022 走看看