zoukankan      html  css  js  c++  java
  • Linux平台总线设备驱动

    1. 平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备(没有挂到真实总线的设备)与驱动进行了管理,这样提高了程序的可移植性。

    2. 平台总线开发设备驱动流程

    (1)定义平台设备

    (2)注册平台设备

    (3)定义平台驱动

    (4)注册平台驱动

    3. 平台设备使用struct platform_device来描述

    struct platform_device {
        const char    * name;
        int        id;
        struct device    dev;
        u32        num_resources;
        struct resource    * resource;
    };

    ① name:设备名

    ② id:设备ID:配合设备名使用,以区分不同设备

    ③ dev:

    ④ num_resources:硬件资源个数

    ⑤ resource:硬件资源

    struct resource {
        resource_size_t start;
        resource_size_t end;
        const char *name;
        unsigned long flags;
        struct resource *parent, *sibling, *child;
    };


    (1) 注册平台设备:int platform_device_register(struct platform_device *pdev);

    (2) 注销平台设备:void platform_device_unregister(struct platform_device *pdev);

    4. 平台驱动使用struct platform_driver描述

    struct platform_driver {
        int (*probe)(struct platform_device *);
        int (*remove)(struct platform_device *);
        void (*shutdown)(struct platform_device *);
        int (*suspend)(struct platform_device *, pm_message_t state);
        int (*suspend_late)(struct platform_device *, pm_message_t state);
        int (*resume_early)(struct platform_device *);
        int (*resume)(struct platform_device *);
        struct device_driver driver;
    };


    (1)平台驱动注册: int platform_driver_register(struct platform_driver *)

    (2)平台驱动注销:void platform_driver_unregister(struct platform_driver *)

    5. 简单示例

    ① PlatformKeyDevice.c

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/interrupt.h>
    #include <linux/platform_device.h>
    
    MODULE_LICENSE("GPL");
    
    #define GPGCON 0x56000060
    
    void key_release(struct device *dev)
    {
        printk("dev->init_name = %s release!
    ", dev->init_name);
    }
    
    static struct resource key_resource[] = {
        [0] = {
            .start = GPGCON,
            .end   = GPGCON + 8,
            .flags = IORESOURCE_MEM,
        },
        [1] = {
            .start = IRQ_EINT8,
            .end   = IRQ_EINT11,
            .flags = IORESOURCE_IRQ,
        },
        [2] = {
            .start = IRQ_EINT13,
            .end   = IRQ_EINT14,
            .flags = IORESOURCE_IRQ,
        },
        [3] = {
            .start = IRQ_EINT15,
            .end   = IRQ_EINT19,
            .flags = IORESOURCE_IRQ,
        },
    };
    
    struct platform_device key_device = {
        .name = "my-key",
        .id = 0,
        .dev = {
            .init_name = "init_key",
            .release = key_release,
        },
        .num_resources = ARRAY_SIZE(key_resource),
        .resource = key_resource,
    };
    
    static int button_init(void)
    {
        platform_device_register(&key_device);
         
        return 0;
    }
    
    static void button_exit(void)
    {       
        platform_device_unregister(&key_device);
    }
    
    module_init(button_init);
    module_exit(button_exit);


    ② PlatformKeyDriver.c

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/miscdevice.h>
    #include <linux/interrupt.h>
    #include <linux/io.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h>
    #include <linux/platform_device.h>
    
    MODULE_LICENSE("GPL");
    
    struct timer_list buttons_timer;
    
    unsigned int key_num = 0;
    
    wait_queue_head_t key_wait_queue;
    
    unsigned int *key_base = NULL;
    
    
    void buttons_timer_function(unsigned long data)  
    {
        printk("keys_timer_function
    ");
        
        key_num = 0;
    
        printk("data = %lx
    ", data);
        
        switch(data)
        {
            case IRQ_EINT8:
                key_num = 1;
                break;
                
            case IRQ_EINT11:
                key_num = 2;
                break;
                
            case IRQ_EINT13:
                key_num = 3;
                break;
                
            case IRQ_EINT14:
                key_num = 4;
                break;
            
            case IRQ_EINT15:
                key_num = 5;
                break;
            
            case IRQ_EINT19:
                key_num = 6;
                break;            
            
            default:
                break;
        }
    
        printk("key_num = %d
    ", key_num);
        
        wake_up(&key_wait_queue);
    } 
    
    irqreturn_t key_int(int irq, void *dev_id)
    {
        //1. 检测是否发生了按键中断
        
        //2. 清除已经发生的按键中断
        
        //3. 提交下半部
        buttons_timer.data = irq;
        mod_timer(&buttons_timer, jiffies + (HZ /10));     
      
        //return 0;
        return IRQ_HANDLED;     
    }
    
    void key_hw_init(void)
    {
        unsigned int config_data;
        
        if(key_base != NULL)
        {
            config_data = readl(key_base);
            config_data &= 0b001111110000001100111100;
            config_data |= 0b100000001010100010000010;
    
            writel(config_data, key_base);
        }
    }
    
    int key_open(struct inode *node,struct file *filp)
    {
        return 0;    
    }
    
    ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
    { 
        wait_event(key_wait_queue, key_num);
            
        copy_to_user(buf, &key_num, 4);
        
        key_num = 0;
      
        return 4;
    }
    
    struct file_operations key_fops = 
    {
        .open = key_open,
        .read = key_read,    
    };
    
    struct miscdevice key_miscdev = {
        .minor = 200,
        .name = "key",
        .fops = &key_fops,    
    };
    
    int key_probe(struct platform_device *pdev)
    {
        int ret, size;
        
        struct resource *resources;
        struct resource *resources_irq;
        
        ret = misc_register(&key_miscdev);
        
        if (ret != 0)
            printk("register fail!
    ");
        
        //注册中断处理程序
        resources_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        
        request_irq(resources_irq->start, key_int, IRQF_TRIGGER_LOW, "key1", 0);
        request_irq(resources_irq->end, key_int, IRQF_TRIGGER_LOW, "key2", 0);
        
        resources_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
        
        request_irq(resources_irq->start, key_int, IRQF_TRIGGER_LOW, "key3", 0);
        request_irq(resources_irq->end, key_int, IRQF_TRIGGER_LOW, "key4", 0);
        
        resources_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
        
        request_irq(resources_irq->start, key_int,IRQF_TRIGGER_LOW, "key5", 0);
        request_irq(resources_irq->end, key_int,IRQF_TRIGGER_LOW, "key6", 0);
        
        
        //按键初始化
        resources = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        size = (resources->end - resources->start) + 1;
        key_base = ioremap(resources->start, size);
        
        key_hw_init();
        
        /* 初始化定时器 */  
        init_timer(&buttons_timer);   
        buttons_timer.function  = buttons_timer_function;  
        
        /* 向内核注册一个定时器 */  
        add_timer(&buttons_timer);  
        
        /*初始化等待队列*/
        init_waitqueue_head(&key_wait_queue);
        
        return 0;
    }
    
    int key_remove(struct platform_device *pdev)
    {
        struct resource *resources_irq;
        int i = 0;
        
        printk("PlatformKeyDriver: key_remove!
    ");
        
        for(i = 0; i <= 2; i++)
        {
            resources_irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
            
            free_irq(resources_irq->start, 0);
            free_irq(resources_irq->end, 0);
        }
        
        iounmap(key_base);
        misc_deregister(&key_miscdev);
        
        return 0;
    }
    
    static struct platform_driver key_driver = {
        .probe        = key_probe,
        .remove        = key_remove,
        .driver        = {
            .owner    = THIS_MODULE,
            .name    = "my-key",
        },
    };
    
    static int button_init(void)
    {
        return platform_driver_register(&key_driver);
    }
    
    static void button_exit(void)
    {       
        platform_driver_unregister(&key_driver);
    }
    
    module_init(button_init);
    module_exit(button_exit);
  • 相关阅读:
    add custom attribute to standard windows controls
    产生0到1之间均匀分布的一个随机数与随机数序列
    (HDOJ 1002)A + B Problem II
    递推问题系列1幂积序列
    杭电题目分类解答
    (HDOJ 1003)Max Sum
    快排序(递归算法)
    (HDOJ 1004)Let the Balloon Rise
    (HDOJ 1005)Number Sequence
    一个关于去除数组重复元素的问题(C语言实现)
  • 原文地址:https://www.cnblogs.com/wulei0630/p/9543394.html
Copyright © 2011-2022 走看看