zoukankan      html  css  js  c++  java
  • 13. linux 中断式驱动编程

    1. 根据硬件工程生成设备数文件 dts

    / {
        amba_pl: amba_pl {
            #address-cells = <1>;
            #size-cells = <1>;
            compatible = "simple-bus";
            ranges ;
            axi_timer_0: timer@42800000 {
                clock-frequency = <100000000>;
                clock-names = "ref_clk";
                clocks = <&clkc 0>;
                compatible = "ricky,xps-timer-1.00.a";
                interrupt-parent = <&intc>;
                interrupts = <0 29 4>;
                reg = <0x42800000 0x10000>;
                xlnx,count-width = <0x20>;
                xlnx,gen0-assert = <0x1>;
                xlnx,gen1-assert = <0x1>;
                xlnx,one-timer-only = <0x0>;
                xlnx,trig0-assert = <0x1>;
                xlnx,trig1-assert = <0x1>;
            };
        };
    };
    
    

    2. 驱动程序

    *  intr_example.c - The simplest kernel module.
     */
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/slab.h>
    #include <linux/io.h>
    #include <linux/interrupt.h>
    
    
    #include <linux/of_address.h>
    #include <linux/of_device.h>
    #include <linux/of_platform.h>
    
    
    /* Standard module information, edit as appropriate */
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR
        ("Xilinx Inc.");
    MODULE_DESCRIPTION
        ("intr_example - loadable module template generated by petalinux-create -t modules");
    
    
    #define DRIVER_NAME "intr_example"
    
    
    #define XIL_AXI_TIMER_BASEADDR 0x42800000
    #define XIL_AXI_TIMER_HIGHADDR 0x4280FFFF
    
    
    #define XIL_AXI_TIMER_TCSR_OFFSET        0x0
    #define XIL_AXI_TIMER_TLR_OFFSET        0x4
    #define XIL_AXI_TIMER_TCR_OFFSET        0x8
    #define XIL_AXI_TIMER_CSR_INT_OCCURED_MASK    0x00000100
    
    
    #define XIL_AXI_TIMER_CSR_CASC_MASK        0x00000800
    #define XIL_AXI_TIMER_CSR_ENABLE_ALL_MASK    0x00000400
    #define XIL_AXI_TIMER_CSR_ENABLE_PWM_MASK    0x00000200
    #define XIL_AXI_TIMER_CSR_INT_OCCURED_MASK    0x00000100
    #define XIL_AXI_TIMER_CSR_ENABLE_TMR_MASK    0x00000080
    #define XIL_AXI_TIMER_CSR_ENABLE_INT_MASK    0x00000040
    #define XIL_AXI_TIMER_CSR_LOAD_MASK        0x00000020
    #define XIL_AXI_TIMER_CSR_AUTO_RELOAD_MASK    0x00000010
    #define XIL_AXI_TIMER_CSR_EXT_CAPTURE_MASK    0x00000008
    #define XIL_AXI_TIMER_CSR_EXT_GENERATE_MASK    0x00000004
    #define XIL_AXI_TIMER_CSR_DOWN_COUNT_MASK    0x00000002
    #define XIL_AXI_TIMER_CSR_CAPTURE_MODE_MASK    0x00000001
    
    
    #define TIMER_CNT    0xF8000000
    
    
    /* Simple example of how to receive command line parameters to your module.
       Delete if you don't need them */
    unsigned myint = 0xdeadbeef;
    char *mystr = "default";
    
    
    module_param(myint, int, S_IRUGO);
    module_param(mystr, charp, S_IRUGO);
    
    
    struct intr_example_local {
        int irq;
        unsigned long mem_start;
        unsigned long mem_end;
        void __iomem *base_addr;
    };
    
    
    static int int_cnt;
    
    
    static irqreturn_t intr_example_irq(int irq, struct intr_example_local *lp)
    {
        unsigned int data;
    
    
    
    
        /* 
        * Clear Interrupt
        */
        data = ioread32(lp->base_addr + XIL_AXI_TIMER_TCSR_OFFSET);
        iowrite32(data | XIL_AXI_TIMER_CSR_INT_OCCURED_MASK,
        lp->base_addr + XIL_AXI_TIMER_TCSR_OFFSET);
    
    
    
    
        return IRQ_HANDLED;
    }
    
    
    static int intr_example_probe(struct platform_device *pdev)
    {
        struct resource *r_irq; /* Interrupt resources */
        struct resource *r_mem; /* IO mem resources */
        struct device *dev = &pdev->dev;
        struct intr_example_local *lp = NULL;
    
        unsigned int data = 0;
        int rc = 0;
    
        dev_info(dev, "Device Tree Probing
    ");
    
    
        /* Get iospace for the device */
        r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r_mem) {
            dev_err(dev, "invalid address
    ");
            return -ENODEV;
        }
    
        lp = (struct intr_example_local *) kmalloc(sizeof(struct intr_example_local), GFP_KERNEL);
        if (!lp) {
            dev_err(dev, "Cound not allocate intr_example device
    ");
            return -ENOMEM;
        }
    
        dev_set_drvdata(dev, lp);
    
        lp->mem_start = r_mem->start;
        lp->mem_end = r_mem->end;
    
    
        if (!request_mem_region(lp->mem_start,
                    lp->mem_end - lp->mem_start + 1,
                    DRIVER_NAME)) {
            dev_err(dev, "Couldn't lock memory region at %p
    ",
                (void *)lp->mem_start);
            rc = -EBUSY;
            goto error1;
        }
    
    
        lp->base_addr = ioremap_nocache(lp->mem_start, lp->mem_end - lp->mem_start + 1);
        if (!lp->base_addr) {
            dev_err(dev, "intr_example: Could not allocate iomem
    ");
            rc = -EIO;
            goto error2;
        }
    
    
        /* Get IRQ for the device */
        r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!r_irq) {
            dev_info(dev, "no IRQ found
    ");
            dev_info(dev, "intr_example at 0x%08x mapped to 0x%08x
    ",
                (unsigned int __force)lp->mem_start,
                (unsigned int __force)lp->base_addr);
            return 0;
        }
        lp->irq = r_irq->start;
    
    
        rc = request_irq(lp->irq, &intr_example_irq, 0, DRIVER_NAME, lp);
        if (rc) {
            dev_err(dev, "testmodule: Could not allocate interrupt %d.
    ",
                lp->irq);
            goto error3;
        }
    
    
        dev_info(dev,"intr_example at 0x%08x mapped to 0x%08x, irq=%d
    ",
            (unsigned int __force)lp->mem_start,
            (unsigned int __force)lp->base_addr,
            lp->irq);
    
    
    
    
        return 0;
    error3:
        free_irq(lp->irq, lp);
    error2:
        release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
    error1:
        kfree(lp);
        dev_set_drvdata(dev, NULL);
        return rc;
    }
    
    
    static int intr_example_remove(struct platform_device *pdev)
    {
        struct device *dev = &pdev->dev;
        struct intr_example_local *lp = dev_get_drvdata(dev);
        free_irq(lp->irq, lp);
        release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
        kfree(lp);
        dev_set_drvdata(dev, NULL);
        return 0;
    }
    
    
    #ifdef CONFIG_OF
    static struct of_device_id intr_example_of_match[] = {
        { .compatible = "ricky,xps-timer-1.00.a", },
        { /* end of list */ },
    };
    MODULE_DEVICE_TABLE(of, intr_example_of_match);
    #else
    # define intr_example_of_match
    #endif
    
    
    
    
    static struct platform_driver intr_example_driver = {
        .driver = {
            .name = DRIVER_NAME,
            .owner = THIS_MODULE,
            .of_match_table    = intr_example_of_match,
        },
        .probe        = intr_example_probe,
        .remove        = intr_example_remove,
    };
    
    
    static int __init intr_example_init(void)
    {
        printk("<1>Hello module world.
    ");
        printk("<1>Module parameters were (0x%08x) and "%s"
    ", myint,
               mystr);
    
    
        return platform_driver_register(&intr_example_driver);
    }
    
    
    
    
    static void __exit intr_example_exit(void)
    {
        platform_driver_unregister(&intr_example_driver);
        printk(KERN_ALERT "Goodbye module world.
    ");
    }
    
    
    module_init(intr_example_init);
    module_exit(intr_example_exit);
    
    
  • 相关阅读:
    主流浏览器的内核私有属性css前缀
    判断一个js对象是否是Array,最准确的方法
    JavaScript的void运算符
    js闭包面试题
    请问何为混合应用 (Hybrid APP) ,与原生 Native 应用相比它的优劣势
    将闭包返回赋值给两个变量,执行这两个闭包变量
    js操作符“+”前后的类型转换
    js基本类型和基本包装类型的区别
    只能输入零和非零开头的数字的正则表达式
    将一个非匿名函数赋值给变量再执行这个非匿名函数会如何
  • 原文地址:https://www.cnblogs.com/standardzero/p/12551162.html
Copyright © 2011-2022 走看看