查看: 3713|回复: 2

pcDuino Linux驱动开发四 -- 最简单的中断驱动

[复制链接]
  • TA的每日心情
    奋斗
    2022-9-16 05:52
  • 签到天数: 1368 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2014-8-17 09:08:06 | 显示全部楼层 |阅读模式
    分享到:
    基于前面提到的最精简的框架,中断程序只是多了一个irq注册和响应的代码。
    需要增加的函数有:

    request_irq //请求注册irq
    free_irq //释放请求
    和一个自定义的irq响应函数。

    当然,为了程序能够真正完成工作,还需要一个阻塞响应机制,以便用户程序能够等到中断的到达。
    这里同样使用了最简单的方式,增加的函数:

    DECLARE_COMPLETION(MSG); //linux内核定义好的宏,给一个变量名称即可
    init_completion(&MSG); //初始化
    wait_for_completion(&MSG); //阻塞函数
    complete(&MSG); //打断阻塞的函数

    下面上代码,对照之前的GPIO框架,可以很清晰地看出区别:
    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/fs.h>
    4. #include <linux/cdev.h>
    5. #include <linux/device.h>
    6. #include <linux/wait.h>
    7. #include <linux/delay.h>
    8. #include <asm/io.h>
    9. #include <asm/uaccess.h>
    10. #include <linux/interrupt.h>

    11. #include "../A10.h"

    12. /**********************************************************************/
    13.         #define KEY_IRQ                28
    14.        
    15.         #define KEY_BACK                17
    16.         #define KEY_HOME                19
    17.         #define KEY_MENU                18
    18.        
    19.         #define KEY_BACK_BIT                        0x20000        //(0x1 << 17)
    20.         #define KEY_MENU_BIT                        0x40000        //(0x1 << 18)
    21.         #define KEY_HOME_BIT                        0x80000        //(0x1 << 19)
    22.        
    23.         #define KEY_DOWN                0
    24.         #define KEY_UP                                1

    25.         volatile static unsigned long* REG_PH_CFG2;
    26.         volatile static unsigned long* REG_PH_PULL1;
    27.         volatile static unsigned long* REG_PIO_INT_CFG2;
    28.         volatile static unsigned long* REG_PIO_INT_CTL;
    29.         volatile static unsigned long* REG_PIO_INT_STATUS;
    30.         volatile static unsigned long* REG_PH_DAT;
    31.        
    32.         /*volatile static unsigned long* REG_INTC_IRQ_PEND_REG0;
    33.         volatile static unsigned long* REG_INTC_IRQ_TYPE_SEL0;
    34.         volatile static unsigned long* REG_INTC_EN_REG0;
    35.         volatile static unsigned long* REG_INTC_MASK_REG0;*/
    36.        
    37.         static int Inited = 0;

    38.         DECLARE_COMPLETION(MSG);
    39.         static unsigned char KeyFlag = 0;
    40.         static unsigned char KeyHL = 255;
    41.        
    42. static irqreturn_t KEY_ISR(int irq, void* dev_id)
    43. {
    44.         unsigned int State, Data;

    45.         State = *REG_PIO_INT_STATUS;
    46.         *REG_PIO_INT_STATUS |= (KEY_HOME_BIT + KEY_MENU_BIT + KEY_BACK_BIT); //Clear INT Pending

    47.         mdelay(1);
    48.         *REG_PH_CFG2 &= ~((0x7 << 12) + (0x7 << 8) + (0x7 << 4)); //Input
    49.         Data = *REG_PH_DAT;
    50.         *REG_PH_CFG2 |= ((0x6 << 12) + (0x6 << 8) + (0x6 << 4)); //EINT

    51.         //printk("IRQ State - %u ___ IRQ Data - %u\n", State, Data);
    52.        
    53.         if ((State & KEY_BACK_BIT) == KEY_BACK_BIT )
    54.         {
    55.                 KeyFlag = KEY_BACK;
    56.                 if ((Data & KEY_BACK_BIT)  == KEY_BACK_BIT) KeyHL = KEY_UP; else KeyHL = KEY_DOWN;
    57.         }
    58.         else
    59.                 if ((State & KEY_MENU_BIT) == KEY_MENU_BIT)
    60.                 {
    61.                         KeyFlag = KEY_MENU;
    62.                         if ((Data & KEY_MENU_BIT)  == KEY_MENU_BIT) KeyHL = KEY_UP; else KeyHL = KEY_DOWN;
    63.                 }
    64.                 else
    65.                         if ((State & KEY_HOME_BIT) == KEY_HOME_BIT)
    66.                         {
    67.                                 KeyFlag = KEY_HOME;
    68.                                 if ((Data & KEY_HOME_BIT) == KEY_HOME_BIT) KeyHL = KEY_UP; else KeyHL = KEY_DOWN;
    69.                         }
    70.                        
    71.         if ((KeyFlag != 0) && (KeyHL != 255)) complete(&MSG);

    72.         return IRQ_HANDLED;
    73. }

    74. static int KEY_open(struct inode* n, struct file* f)
    75. {
    76.         int Result = 0;

    77.         Inited++;
    78.         if (Inited > 1)
    79.         {
    80.                 return 0;
    81.         }

    82.         REG_PH_CFG2 = (volatile unsigned long*) ioremap(PH_CFG2, 4);
    83.         REG_PH_PULL1 = (volatile unsigned long*) ioremap(PH_PULL1, 4);
    84.         REG_PIO_INT_CFG2 = (volatile unsigned long*) ioremap(PIO_INT_CFG2, 4);
    85.         REG_PIO_INT_CTL= (volatile unsigned long*) ioremap(PIO_INT_CTL, 4);
    86.         REG_PIO_INT_STATUS = (volatile unsigned long*) ioremap(PIO_INT_STATUS, 4);
    87.         REG_PH_DAT = (volatile unsigned long*) ioremap(PH_DAT, 4);
    88.        
    89.         /*REG_INTC_IRQ_PEND_REG0 = (volatile unsigned long*) ioremap(INTC_IRQ_PEND_REG0, 4);
    90.         REG_INTC_IRQ_TYPE_SEL0 = (volatile unsigned long*) ioremap(INTC_IRQ_TYPE_SEL0, 4);
    91.         REG_INTC_EN_REG0 = (volatile unsigned long*) ioremap(INTC_EN_REG0, 4);
    92.         REG_INTC_MASK_REG0 = (volatile unsigned long*) ioremap(INTC_MASK_REG0, 4);*/
    93.        
    94.         *REG_PH_CFG2 &= ~((0x7 << 12) + (0x7 << 8) + (0x7 << 4));
    95.         *REG_PH_CFG2 |= ((0x6 << 12) + (0x6 << 8) + (0x6 << 4)); //EINT
    96.         *REG_PH_PULL1 &= ~((0x3 << 6) + (0x3 << 4) + (0x3 << 2));
    97.         *REG_PH_PULL1 |= ((0x1 << 6) + (0x1 << 4) + (0x1 << 2)); //Pull_UP
    98.         *REG_PIO_INT_CFG2 &= ~((0xF << 12) + (0xF << 8) + (0xF << 4));
    99.         *REG_PIO_INT_CFG2 |= ((0x4 << 12) + (0x4 << 8) + (0x4<< 4)); //Double Edge
    100.         //*REG_PH_DAT |= KEY_HOME_BIT + KEY_MENU_BIT + KEY_BACK_BIT;
    101.        
    102.         //*REG_INTC_IRQ_TYPE_SEL0 &= ~((0x1 << KEY_MENU) + (0x1 << KEY_HOME) + (0x1 << KEY_BACK)); //Is IRQ, not FIQ
    103.         //*REG_INTC_EN_REG0 |= ((0x1 << KEY_MENU) + (0x1 << KEY_HOME) + (0x1 << KEY_BACK)); //Enable INT
    104.        
    105.         *REG_PIO_INT_CTL |= ((0x1 << KEY_MENU) + (0x1 << KEY_HOME) + (0x1 << KEY_BACK)); //Enable INT

    106.         Result = request_irq(KEY_IRQ, KEY_ISR, IRQF_DISABLED, "KEY", NULL);
    107.         if (Result != 0)
    108.         {
    109.                 //printk("Request IRQ file! ErrorCode: %d\n", Result);
    110.                 free_irq(KEY_IRQ, NULL);
    111.                 return Result;
    112.         }

    113.         init_completion(&MSG);
    114.         //printk("Open Finished!\n");
    115.         return Result;
    116. }

    117. static ssize_t KEY_write(struct file* f, const char __user* buf, size_t len, loff_t* l)
    118. {
    119.         unsigned char Buf[2];
    120.        
    121.         if (copy_from_user(&Buf, buf, len)) return -1;

    122.         //printk("Write Finished!\n");
    123.         return len;
    124. }

    125. static ssize_t KEY_read(struct file* f, char __user* buf, size_t len, loff_t* l)
    126. {
    127.         unsigned char Buf[2];
    128.         int Len = sizeof(Buf);

    129.         wait_for_completion(&MSG);

    130.         Buf[0] = KeyFlag;
    131.         Buf[1] = KeyHL;
    132.         if (copy_to_user(buf, &Buf, sizeof(Buf))) return 0;

    133.         KeyFlag = 0;
    134.         KeyHL = 255;
    135.        
    136.         //printk("Read Finished!\n");
    137.         return Len;
    138. }

    139. static int KEY_close(struct inode* n, struct file* f)
    140. {
    141.         Inited--;
    142.         if (Inited > 0)
    143.         {
    144.                 return 0;
    145.         }
    146.        
    147.         free_irq(KEY_IRQ, NULL);
    148.         //remove_wait_queue(&MSG);
    149.        
    150.         iounmap(REG_PH_CFG2);
    151.         iounmap(REG_PH_PULL1);
    152.         iounmap(REG_PIO_INT_CFG2);
    153.         iounmap(REG_PIO_INT_STATUS);
    154.         iounmap(REG_PH_DAT);
    155.        
    156.         /*iounmap(REG_INTC_IRQ_PEND_REG0);
    157.         iounmap(REG_INTC_IRQ_TYPE_SEL0);
    158.         iounmap(REG_INTC_EN_REG0);
    159.         iounmap(REG_INTC_MASK_REG0);*/

    160.         //printk("Close Finished!\n");
    161.         return 0;
    162. }

    163. /**********************************************************************/
    164.         #define DEV_NAME        "KEY"
    165.         #define DEV_COUNT        1

    166.         static struct class* pClass;
    167.         int major;
    168.        
    169.         static struct file_operations fops =
    170.         {
    171.                 .owner = THIS_MODULE,
    172.                 .open = KEY_open,
    173.                 .write = KEY_write,
    174.                 .read = KEY_read,
    175.                 .release = KEY_close,
    176.         };

    177. static int __init KEY_init(void)
    178. {
    179.         major = register_chrdev(0, DEV_NAME, &fops);
    180.         pClass = class_create(THIS_MODULE, DEV_NAME);
    181.         if (pClass == NULL)
    182.         {
    183.                 unregister_chrdev(major, DEV_NAME);
    184.                 return -1;
    185.         }
    186.         device_create(pClass, NULL, MKDEV(major, 0),  NULL, DEV_NAME);
    187.         //printk("Init Finished!\n");

    188.         return 0;
    189. }

    190. static void __exit KEY_exit(void)
    191. {
    192.         unregister_chrdev(major, DEV_NAME);
    193.         if (pClass)
    194.         {
    195.                 device_destroy(pClass, MKDEV(major, 0));
    196.                 class_destroy(pClass);
    197.         }
    198.         //printk("Exit Finished!\n");
    199. }

    200. MODULE_LICENSE("GPL");
    201. MODULE_AUTHOR("LiuYang");
    202. module_init(KEY_init);
    203. module_exit(KEY_exit);
    复制代码
    Makefile文件同前,改一下文件名.o即可。

    测试程序:
    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <fcntl.h>

    4. int main(int argc, char **argv)
    5. {
    6.         int f;
    7.         int I;
    8.         int Len;
    9.         unsigned char Buf[2];
    10.        
    11.         f = open("/dev/KEY", O_RDWR);
    12.         printf("File Handle: %d\n", f);
    13.         if (f < 0)
    14.         {
    15.                 printf("Open KEY fail!\n");
    16.                 return -1;
    17.         }

    18. for (I = 0; I < 6; I++)
    19.         {
    20.                 Len = read(f, &Buf, 2);
    21.                 printf("Len: %d -- Key: %d  -- HL: %d\n", Len, Buf[0], Buf[1]);
    22.         }
    23.        
    24.         close(f);

    25.         return 0;
    26. }
    复制代码
    这样,测试程序在调用了read之后会阻塞在那里,等待驱动程序中中断的达到。每次按下按键后,程序就继续执行了。wait_for_completion有很多种,可以增加超时之类的来完成自己的要求。

    顺便说一下,pcDuino已经占用了这个中断,测试的话,在启动后需要先rmmod sw_interrupt,以保证本程序的运行。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2014-8-14 10:11
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2014-8-18 11:16:18 | 显示全部楼层
    一如既往地支持
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2022-9-16 05:52
  • 签到天数: 1368 天

    连续签到: 1 天

    [LV.10]以坛为家III

     楼主| 发表于 2014-8-18 13:14:53 | 显示全部楼层
    jyq 发表于 2014-8-18 11:16
    一如既往地支持

    多谢,献丑了
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /5 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-12-22 20:48 , Processed in 0.130954 second(s), 19 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.