请选择 进入手机版 | 继续访问电脑版

环信

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: mmap uikit gcc
查看: 343|回复: 1

16. 中断处理

[复制链接]

42

主题

68

帖子

229

积分

中级会员

Rank: 3Rank: 3

积分
229
发表于 2015-10-3 10:21:49 | 显示全部楼层 |阅读模式
本帖最后由 master 于 2015-12-23 16:59 编辑

为设备实现一个中断包含两个步骤:
    1.向内核注册中断
    2.实现中断处理函数
   
    中断注册
    int request_irq(unsigned int irq, void (*handler)(int, void*, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id)
    返回0表示成功,或者返回一个错误码   
            
        unsigned int irq
        中断号。
        void (*handler)(int,void *,struct pt_regs *)
        中断处理函数。
        unsigned long flags
        与中断管理有关的各种选项。
        const char * devname
        设备名
        void *dev_id
        共享中断时使用。   
        
        flags中断标志
        在flags参数中,可以选择一些与中断管理有关的选项,如:
        IRQF_DISABLED(SA_INTERRUPT)
            如果设置该位,表示是一个“快速”中断处理程序;如果没有设置这位,那么是一个“慢速”中断处理程序。
        IRQF_SHARED(SA_SHIRQ)
            该位表明中断可以在设备间共享。
            
        快速/慢速这两种类型的中断处理程序的主要区别在于:
        快速中断保证中断处理的原子性(不被打断),而慢速中断则不保证。换句话说,也就是“开启中断”标志位(处理器IF)在运行快速中断处理程序时是关闭的,
        因此在服务该中断时,不会被其他类型的中断打断;而调用慢速中断处理时,其它类型的中断仍可以得到服务。                    
            
        共享中断就是将不同的设备挂到同一个中断信号线上。Linux对共享的支持主要是为PCI设备服务。   

        共享中断也是通过request_irq函数来注册的,但有三个特别之处:
            1.申请共享中断时,必须在flags参数中指定IRQF_SHARED位
            2. dev_id参数必须是唯一的。
            3.共享中断的处理程序中,不能使用disable_irq(unsigned int irq)
                为什么? -> 如果使用了这个函数,共享中断信号线的其它设备将同样无法使用中断,也就无法正常工作了。        
               
    中断处理程序   
    特别之处在于中断处理程序是在中断上下文中运行的,它的行为受到某些限制:
        1.不能向用户空间发送或接受数据
        2.不能使用可能引起阻塞的函数
        3.不能使用可能引起调度的函数   
        
        中断处理函数流程   
            void short_sh_interrupt(int irq, void *dev_id, struct pt_regs *regs)
            {
                /* 判断是否是本设备产生了中断(为什么要做这样的检测?) */
                value = inb(short_base);
                if (!(value & 0x80)) return;
                /* 清除中断位(如果设备支持自动清除,则不需要这步) */
                outb(value & 0x7F, short_base);
                /* 中断处理,通常是数据接收*/
                。。。。。。。。。
                /* 唤醒等待数据的进程*/
                wake_up_interruptible(&short_queue);
               
        当设备不再需要使用中断时(通常在驱动卸载时), 应当把它们返还给系统,使用:
            void free_irq(unsigned int irq, void *dev_id)   

回复

使用道具 举报

42

主题

68

帖子

229

积分

中级会员

Rank: 3Rank: 3

积分
229
 楼主| 发表于 2015-12-23 17:24:38 | 显示全部楼层
button.c
  1. #include <linux/module.h>
  2. #include <linux/types.h>
  3. #include <linux/miscdevice.h>
  4. #include <linux/fs.h>
  5. #include <linux/init.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/interrupt.h>
  8. #include <linux/clk.h>
  9. #include <linux/uaccess.h>
  10. #include <linux/io.h>
  11. #include <mach/map.h>
  12. #include <mach/regs-gpio.h>
  13. #include <linux/poll.h>
  14. #include <linux/irq.h>
  15. #include <asm/unistd.h>
  16. #include <linux/device.h>


  17. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

  18. static volatile int ev_press = 0;


  19. static int key_value;
  20. static struct device     *buttons_dev;    /* platform device attached to */
  21. static struct resource    *buttons_mem;
  22. static struct resource   *buttons_irq;
  23. static void __iomem        *buttons_base;


  24. static int button_irqs[6];

  25. /*
  26. 2.实现中断处理函数
  27.     中断处理程序是在中断上下文中运行的,它的行为受到某些限制:
  28.         1.不能向用户空间发送或接受数据
  29.         2.不能使用可能引起阻塞的函数
  30.         3.不能使用可能引起调度的函数
  31. */
  32. static irqreturn_t buttons_interrupt(int irq, void *dev_id)
  33. {
  34.     /*
  35.     中断处理函数流程   
  36.     判断是否是本设备产生了中断
  37.                 value = inb(short_base);
  38.                 if (!(value & 0x80)) return;
  39.          清除中断位(如果设备支持自动清除,则不需要这步)
  40.                 outb(value & 0x7F, short_base);
  41.          中断处理,通常是数据接收
  42.     */
  43.     int i;
  44.     for(i=0; i<6; i++)
  45.     {
  46.         if(irq == button_irqs[i])
  47.         {
  48.             //printk("==>interrput number:%d\n",irq);  
  49.             key_value = i;
  50.             ev_press =1;
  51.             
  52.             /* 唤醒等待数据的进程*/
  53.             wake_up_interruptible(&button_waitq);        
  54.         }
  55.     }
  56.    
  57.     return IRQ_RETVAL(IRQ_HANDLED);
  58.    
  59. }

  60. static int s3c24xx_buttons_open(struct inode *inode, struct file *file)
  61. {
  62.     /*
  63.     为设备实现一个中断包含两个步骤:
  64.         1.向内核注册中断
  65.         2.实现中断处理函数
  66.         */
  67.     int i;
  68.     int err = 0;
  69.     /*注册中断*/
  70.     for(i=0; i<6; i++)
  71.     {
  72.         if (button_irqs[i] < 0)
  73.             continue;
  74.                            
  75.     /*1.向内核注册中断
  76.     中断触发方式:上升沿触发
  77.             int request_irq(unsigned int irq, void (*handler)(int, void*, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id)
  78.             返回0表示成功,或者返回一个错误码   
  79.                 unsigned int irq
  80.                 中断号。
  81.                 void (*handler)(int,void *,struct pt_regs *)
  82.                 中断处理函数。
  83.                 unsigned long flags
  84.                 与中断管理有关的各种选项。
  85.                 const char * devname
  86.                 设备名
  87.                 void *dev_id
  88.                 共享中断时使用。   
  89.                
  90.                 flags中断标志
  91.                 在flags参数中,可以选择一些与中断管理有关的选项,如:
  92.                 IRQF_DISABLED(SA_INTERRUPT)
  93.                     如果设置该位,表示是一个“快速”中断处理程序;如果没有设置这位,那么是一个“慢速”中断处理程序。
  94.                 IRQF_SHARED(SA_SHIRQ)
  95.                     该位表明中断可以在设备间共享。
  96.                 IRQ_TYPE_EDGE_RISING
  97.                     .......
  98.     */
  99.         err = request_irq(button_irqs[i],buttons_interrupt,IRQ_TYPE_EDGE_RISING,NULL,NULL);
  100.         if(err)
  101.             break;
  102.         
  103.     }

  104.     if (err) {
  105.         i--;
  106.         for (; i >= 0; i--)
  107.         {
  108.             if (button_irqs[i] < 0)
  109.             {
  110.                 continue;
  111.             }
  112.             disable_irq(button_irqs[i]);
  113.             
  114.             //当设备不再需要使用中断时(通常在驱动卸载时), 应当把它们返还给系统
  115.             free_irq(button_irqs[i], NULL);
  116.         }
  117.         return -EBUSY;
  118.     }

  119.     ev_press = 0;   
  120.     return 0;
  121. }

  122. static int s3c24xx_buttons_close(struct inode *inode, struct file *file)
  123. {
  124.     int i;   
  125.     for (i=0; i<6; i++)
  126.     {
  127.         if (button_irqs[i] < 0)
  128.         {
  129.             continue;
  130.         }
  131.         
  132.         //当设备不再需要使用中断时(通常在驱动卸载时), 应当把它们返还给系统
  133.         free_irq(button_irqs[i],NULL);
  134.     }
  135.     return 0;
  136. }

  137. static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
  138. {
  139.     unsigned long err;
  140.     if (!ev_press)
  141.     {
  142.         if (filp->f_flags & O_NONBLOCK)
  143.             return -EAGAIN;
  144.         else
  145.             wait_event_interruptible(button_waitq, ev_press);
  146.     }   
  147.     ev_press = 0;
  148.     err = copy_to_user(buff, &key_value, sizeof(key_value));
  149.     return sizeof(key_value);
  150. }

  151. static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)
  152. {
  153.     unsigned int mask = 0;
  154.     poll_wait(file, &button_waitq, wait);
  155.     if (ev_press){
  156.         mask |= POLLIN | POLLRDNORM;
  157.     }
  158.     return mask;
  159. }



  160. static struct file_operations mini2440buttons_fops = {
  161.     .owner   =   THIS_MODULE,
  162.     .open    =   s3c24xx_buttons_open,
  163.     .release =   s3c24xx_buttons_close,
  164.     .read    =   s3c24xx_buttons_read,
  165.     .poll    =   s3c24xx_buttons_poll,
  166. };

  167. static struct miscdevice mini2440_miscdev = {
  168.    
  169.     .minor = MISC_DYNAMIC_MINOR,
  170.     .name ="buttons",
  171.     .fops = &mini2440buttons_fops,
  172. };

  173. /* device interface */
  174. static int mini2440_buttons_probe(struct platform_device *pdev)
  175. {
  176.     struct resource *res;
  177.     struct device *dev;
  178.     int ret;
  179.     int size;
  180.     int i;
  181.    
  182.     printk("probe:%s\n", __func__);
  183.     dev = &pdev->dev;
  184.     buttons_dev = &pdev->dev;
  185.    
  186.     /*平台资源获取
  187.         获取平台设备资源
  188.             struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)
  189.              参数:
  190.             dev: 资源所属的设备
  191.             type: 获取的资源类型
  192.             num: 获取的资源数
  193.     */
  194.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  195.     if (res == NULL)
  196.     {
  197.         dev_err(dev, "no memory resource specified\n");
  198.         return -ENOENT;
  199.     }
  200.    
  201.     size = (res->end - res->start) + 1;
  202.     buttons_mem = request_mem_region(res->start, size, pdev->name);
  203.     if (buttons_mem == NULL)
  204.     {
  205.         dev_err(dev, "failed to get memory region\n");
  206.         ret = -ENOENT;
  207.         goto err_req;
  208.     }
  209.    
  210.     buttons_base = ioremap(res->start, size);
  211.     if (buttons_base == NULL)
  212.     {
  213.         dev_err(dev, "failed to ioremap() region\n");
  214.         ret = -EINVAL;
  215.         goto err_req;
  216.     }
  217.     printk(KERN_DEBUG"probe: mapped buttons_base=%p\n", buttons_base);

  218.     /*get irq number*/
  219.     for(i=0; i<6; i++)
  220.     {
  221.         buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i);
  222.         if(buttons_irq == NULL)
  223.         {
  224.             dev_err(dev,"no irq resource specified\n");
  225.             ret = -ENOENT;
  226.             goto err_map;
  227.         }
  228.         button_irqs[i] = buttons_irq->start;
  229.         //printk("button_irqs[%d]=%d\n",i,button_irqs[i]);  
  230.     }
  231.     ret = misc_register(&mini2440_miscdev);
  232.         
  233.     return 0;

  234. err_map:
  235.     iounmap(buttons_base);

  236. err_req:
  237.     release_resource(buttons_mem);
  238.     kfree(buttons_mem);

  239.     return ret;
  240. }

  241. static int mini2440_buttons_remove(struct platform_device *dev)
  242. {
  243.     release_resource(buttons_mem);
  244.     kfree(buttons_mem);
  245.     buttons_mem = NULL;

  246.     iounmap(buttons_base);
  247.     misc_deregister(&mini2440_miscdev);
  248.     return 0;
  249. }

  250. /*平台驱动定义
  251.     使用struct platform_driver 描述:
  252.         struct platform_driver {
  253.         int (*probe)(struct platform_device *);
  254.         int (*remove)(struct platform_device *);
  255.         void (*shutdown)(struct platform_device *);
  256.         int (*suspend)(struct platform_device *, pm_message_t state);
  257.         int (*suspend_late)(struct platform_device *, pm_message_t state);
  258.         int (*resume_early)(struct platform_device *);
  259.         int (*resume)(struct platform_device *);
  260.         struct device_driver driver;
  261.     }
  262. */
  263. static struct platform_driver mini2440buttons_driver = {
  264.     .probe        = mini2440_buttons_probe,
  265.     .remove        = mini2440_buttons_remove,
  266.     .driver        = {
  267.         .owner    = THIS_MODULE,
  268.         .name    = "mini2440-buttons",
  269.     },
  270. };

  271. static char banner[] __initdata =
  272.      "Buttons Driver\n";

  273. static int __init buttons_init(void)
  274. {
  275.     printk(banner);
  276.    
  277.     /*平台驱动注册*/
  278.     platform_driver_register(&mini2440buttons_driver);
  279.     return 0;
  280. }

  281. static void __exit buttons_exit(void)
  282. {
  283.     platform_driver_unregister(&mini2440buttons_driver);
  284. }

  285. module_init(buttons_init);
  286. module_exit(buttons_exit);

  287. MODULE_AUTHOR("Dick");
  288. MODULE_DESCRIPTION("Buttons Driver");
  289. MODULE_LICENSE("GPL");


复制代码
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|环信 Glofty.com ( 粤ICP备15084637号 )

GMT+8, 2017-1-23 04:21 , Processed in 0.218768 second(s), 21 queries .

快速回复 返回顶部 返回列表