查看: 1103|回复: 0

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

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

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2014-11-30 23:13:49 | 显示全部楼层 |阅读模式
    分享到:
    基于前面提到的最精简的框架,中断程序只是多了一个irq注册和响应的代码。
    需要增加的函数有:
    request_irq //请求注册irq
    free_irq //释放请求
    和一个自定义的irq响应函数。
    当然,为了程序能够真正完成工作,还需要一个阻塞响应机制,以便用户程序能够等到中断的到达。
    这里同样使用了最简单的方式,增加的函数:
    DECLARE_COMPLETION(MSG); //linux内核定义好的宏,给一个变量名称即可
    init_completion(&MSG); //初始化
    wait_for_completion(&MSG); //阻塞函数
    complete(&MSG); //打断阻塞的函数
    下面上代码,对照之前的GPIO框架,可以很清晰地看出区别:

    • #include <linux/init.h>
    • #include <linux/module.h>
    • #include <linux/fs.h>
    • #include <linux/cdev.h>
    • #include <linux/device.h>
    • #include <linux/wait.h>
    • #include <linux/delay.h>
    • #include <asm/io.h>
    • #include <asm/uaccess.h>
    • #include <linux/interrupt.h>
    • #include "../A10.h"
    • /**********************************************************************/
    •         #define KEY_IRQ                28

    •         #define KEY_BACK                17
    •         #define KEY_HOME                19
    •         #define KEY_MENU                18

    •         #define KEY_BACK_BIT                        0x20000        //(0x1 << 17)
    •         #define KEY_MENU_BIT                        0x40000        //(0x1 << 18)
    •         #define KEY_HOME_BIT                        0x80000        //(0x1 << 19)

    •         #define KEY_DOWN                0
    •         #define KEY_UP                                1
    •         volatile static unsigned long* REG_PH_CFG2;
    •         volatile static unsigned long* REG_PH_PULL1;
    •         volatile static unsigned long* REG_PIO_INT_CFG2;
    •         volatile static unsigned long* REG_PIO_INT_CTL;
    •         volatile static unsigned long* REG_PIO_INT_STATUS;
    •         volatile static unsigned long* REG_PH_DAT;

    •         /*volatile static unsigned long* REG_INTC_IRQ_PEND_REG0;
    •         volatile static unsigned long* REG_INTC_IRQ_TYPE_SEL0;
    •         volatile static unsigned long* REG_INTC_EN_REG0;
    •         volatile static unsigned long* REG_INTC_MASK_REG0;*/

    •         static int Inited = 0;
    •         DECLARE_COMPLETION(MSG);
    •         static unsigned char KeyFlag = 0;
    •         static unsigned char KeyHL = 255;

    • static irqreturn_t KEY_ISR(int irq, void* dev_id)
    • {
    •         unsigned int State, Data;
    •         State = *REG_PIO_INT_STATUS;
    •         *REG_PIO_INT_STATUS |= (KEY_HOME_BIT + KEY_MENU_BIT + KEY_BACK_BIT); //Clear INT Pending
    •         mdelay(1);
    •         *REG_PH_CFG2 &= ~((0x7 << 12) + (0x7 << 8) + (0x7 << 4)); //Input
    •         Data = *REG_PH_DAT;
    •         *REG_PH_CFG2 |= ((0x6 << 12) + (0x6 << 8) + (0x6 << 4)); //EINT
    •         //printk("IRQ State - %u ___ IRQ Data - %u\n", State, Data);

    •         if ((State & KEY_BACK_BIT) == KEY_BACK_BIT )
    •         {
    •                 KeyFlag = KEY_BACK;
    •                 if ((Data & KEY_BACK_BIT) == KEY_BACK_BIT) KeyHL = KEY_UP; else KeyHL = KEY_DOWN;
    •         }
    •         else
    •                 if ((State & KEY_MENU_BIT) == KEY_MENU_BIT)
    •                 {
    •                         KeyFlag = KEY_MENU;
    •                         if ((Data & KEY_MENU_BIT) == KEY_MENU_BIT) KeyHL = KEY_UP; else KeyHL = KEY_DOWN;
    •                 }
    •                 else
    •                         if ((State & KEY_HOME_BIT) == KEY_HOME_BIT)
    •                         {
    •                                 KeyFlag = KEY_HOME;
    •                                 if ((Data & KEY_HOME_BIT) == KEY_HOME_BIT) KeyHL = KEY_UP; else KeyHL = KEY_DOWN;
    •                         }

    •         if ((KeyFlag != 0) && (KeyHL != 255)) complete(&MSG);
    •         return IRQ_HANDLED;
    • }
    • static int KEY_open(struct inode* n, struct file* f)
    • {
    •         int Result = 0;
    •         Inited++;
    •         if (Inited > 1)
    •         {
    •                 return 0;
    •         }
    •         REG_PH_CFG2 = (volatile unsigned long*) ioremap(PH_CFG2, 4);
    •         REG_PH_PULL1 = (volatile unsigned long*) ioremap(PH_PULL1, 4);
    •         REG_PIO_INT_CFG2 = (volatile unsigned long*) ioremap(PIO_INT_CFG2, 4);
    •         REG_PIO_INT_CTL= (volatile unsigned long*) ioremap(PIO_INT_CTL, 4);
    •         REG_PIO_INT_STATUS = (volatile unsigned long*) ioremap(PIO_INT_STATUS, 4);
    •         REG_PH_DAT = (volatile unsigned long*) ioremap(PH_DAT, 4);

    •         /*REG_INTC_IRQ_PEND_REG0 = (volatile unsigned long*) ioremap(INTC_IRQ_PEND_REG0, 4);
    •         REG_INTC_IRQ_TYPE_SEL0 = (volatile unsigned long*) ioremap(INTC_IRQ_TYPE_SEL0, 4);
    •         REG_INTC_EN_REG0 = (volatile unsigned long*) ioremap(INTC_EN_REG0, 4);
    •         REG_INTC_MASK_REG0 = (volatile unsigned long*) ioremap(INTC_MASK_REG0, 4);*/

    •         *REG_PH_CFG2 &= ~((0x7 << 12) + (0x7 << 8) + (0x7 << 4));
    •         *REG_PH_CFG2 |= ((0x6 << 12) + (0x6 << 8) + (0x6 << 4)); //EINT
    •         *REG_PH_PULL1 &= ~((0x3 << 6) + (0x3 << 4) + (0x3 << 2));
    •         *REG_PH_PULL1 |= ((0x1 << 6) + (0x1 << 4) + (0x1 << 2)); //Pull_UP
    •         *REG_PIO_INT_CFG2 &= ~((0xF << 12) + (0xF << 8) + (0xF << 4));
    •         *REG_PIO_INT_CFG2 |= ((0x4 << 12) + (0x4 << 8) + (0x4<< 4)); //Double Edge
    •         //*REG_PH_DAT |= KEY_HOME_BIT + KEY_MENU_BIT + KEY_BACK_BIT;

    •         //*REG_INTC_IRQ_TYPE_SEL0 &= ~((0x1 << KEY_MENU) + (0x1 << KEY_HOME) + (0x1 << KEY_BACK)); //Is IRQ, not FIQ
    •         //*REG_INTC_EN_REG0 |= ((0x1 << KEY_MENU) + (0x1 << KEY_HOME) + (0x1 << KEY_BACK)); //Enable INT

    •         *REG_PIO_INT_CTL |= ((0x1 << KEY_MENU) + (0x1 << KEY_HOME) + (0x1 << KEY_BACK)); //Enable INT
    •         Result = request_irq(KEY_IRQ, KEY_ISR, IRQF_DISABLED, "KEY", NULL);
    •         if (Result != 0)
    •         {
    •                 //printk("Request IRQ file! ErrorCode: %d\n", Result);
    •                 free_irq(KEY_IRQ, NULL);
    •                 return Result;
    •         }
    •         init_completion(&MSG);
    •         //printk("Open Finished!\n");
    •         return Result;
    • }
    • static ssize_t KEY_write(struct file* f, const char __user* buf, size_t len, loff_t* l)
    • {
    •         unsigned char Buf[2];

    •         if (copy_from_user(&Buf, buf, len)) return -1;
    •         //printk("Write Finished!\n");
    •         return len;
    • }
    • static ssize_t KEY_read(struct file* f, char __user* buf, size_t len, loff_t* l)
    • {
    •         unsigned char Buf[2];
    •         int Len = sizeof(Buf);
    •         wait_for_completion(&MSG);
    •         Buf[0] = KeyFlag;
    •         Buf[1] = KeyHL;
    •         if (copy_to_user(buf, &Buf, sizeof(Buf))) return 0;
    •         KeyFlag = 0;
    •         KeyHL = 255;

    •         //printk("Read Finished!\n");
    •         return Len;
    • }
    • static int KEY_close(struct inode* n, struct file* f)
    • {
    •         Inited--;
    •         if (Inited > 0)
    •         {
    •                 return 0;
    •         }

    •         free_irq(KEY_IRQ, NULL);
    •         //remove_wait_queue(&MSG);

    •         iounmap(REG_PH_CFG2);
    •         iounmap(REG_PH_PULL1);
    •         iounmap(REG_PIO_INT_CFG2);
    •         iounmap(REG_PIO_INT_STATUS);
    •         iounmap(REG_PH_DAT);

    •         /*iounmap(REG_INTC_IRQ_PEND_REG0);
    •         iounmap(REG_INTC_IRQ_TYPE_SEL0);
    •         iounmap(REG_INTC_EN_REG0);
    •         iounmap(REG_INTC_MASK_REG0);*/
    •         //printk("Close Finished!\n");
    •         return 0;
    • }
    • /**********************************************************************/
    •         #define DEV_NAME        "KEY"
    •         #define DEV_COUNT        1
    •         static struct class* pClass;
    •         int major;

    •         static struct file_operations fops =
    •         {
    •                 .owner = THIS_MODULE,
    •                 .open = KEY_open,
    •                 .write = KEY_write,
    •                 .read = KEY_read,
    •                 .release = KEY_close,
    •         };
    • static int __init KEY_init(void)
    • {
    •         major = register_chrdev(0, DEV_NAME, &fops);
    •         pClass = class_create(THIS_MODULE, DEV_NAME);
    •         if (pClass == NULL)
    •         {
    •                 unregister_chrdev(major, DEV_NAME);
    •                 return -1;
    •         }
    •         device_create(pClass, NULL, MKDEV(major, 0), NULL, DEV_NAME);
    •         //printk("Init Finished!\n");
    •         return 0;
    • }
    • static void __exit KEY_exit(void)
    • {
    •         unregister_chrdev(major, DEV_NAME);
    •         if (pClass)
    •         {
    •                 device_destroy(pClass, MKDEV(major, 0));
    •                 class_destroy(pClass);
    •         }
    •         //printk("Exit Finished!\n");
    • }
    • MODULE_LICENSE("GPL");
    • MODULE_AUTHOR("LiuYang");
    • module_init(KEY_init);
    • module_exit(KEY_exit);
    复制代码
    Makefile文件同前,改一下文件名.o即可。
    测试程序:

    • #include <stdio.h>
    • #include <unistd.h>
    • #include <fcntl.h>
    • int main(int argc, char **argv)
    • {
    •         int f;
    •         int I;
    •         int Len;
    •         unsigned char Buf[2];

    •         f = open("/dev/KEY", O_RDWR);
    •         printf("File Handle: %d\n", f);
    •         if (f < 0)
    •         {
    •                 printf("Open KEY fail!\n");
    •                 return -1;
    •         }
    • for (I = 0; I < 6; I++)
    •         {
    •                 Len = read(f, &Buf, 2);
    •                 printf("Len: %d -- Key: %d -- HL: %d\n", Len, Buf[0], Buf[1]);
    •         }

    •         close(f);
    •         return 0;
    • }
    复制代码
    这样,测试程序在调用了read之后会阻塞在那里,等待驱动程序中中断的达到。每次按下按键后,程序就继续执行了。wait_for_completion有很多种,可以增加超时之类的来完成自己的要求。
    顺便说一下,pcDuino已经占用了这个中断,测试的话,在启动后需要先rmmod sw_interrupt,以保证本程序的运行。
    回复

    使用道具 举报

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

    本版积分规则

    关闭

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

    手机版|小黑屋|与非网

    GMT+8, 2024-12-19 01:20 , Processed in 0.120488 second(s), 18 queries , MemCache On.

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

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.