zoukankan      html  css  js  c++  java
  • Linux学习 : 总线-设备-驱动模型

      platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。

      platform_match函数首先判断是否有id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数,其中对资源进行get、ioremap再注册驱动。

    LED总线设备驱动模型程序示例:

    1.device:主要设置硬件相关资源

    /*led_dev.c*/
    #include <linux/module.h>
    #include <linux/version.h>
    
    #include <linux/init.h>
    
    #include <linux/kernel.h>
    #include <linux/types.h>
    #include <linux/interrupt.h>
    #include <linux/list.h>
    #include <linux/timer.h>
    #include <linux/init.h>
    #include <linux/serial_core.h>
    #include <linux/platform_device.h>
    
    
    /* 分配/设置/注册一个platform_device */
    
    static struct resource led_resource[] = {
        [0] = {
            .start = 0x56000050,  //led控制寄存器地址
            .end   = 0x56000050 + 8 - 1,
            .flags = IORESOURCE_MEM, //内存资源
        },
        [1] = {
            .start = 5, //设置引脚号
            .end   = 5,
            .flags = IORESOURCE_IRQ, //中断资源
        }
    };
    
    static void led_release(struct device * dev)
    {
      //框架需求要设置一个release函数,不然会报错 }
    static struct platform_device led_dev = { .name = "myled", .id = -1, .num_resources = ARRAY_SIZE(led_resource), .resource = led_resource, .dev = { .release = led_release, }, }; static int led_dev_init(void) { platform_device_register(&led_dev); //注册平台设备 return 0; } static void led_dev_exit(void) { platform_device_unregister(&led_dev); } module_init(led_dev_init); module_exit(led_dev_exit); MODULE_LICENSE("GPL");

    2.driver:注册平台驱动,匹配上设备后调用probe函数:获取device资源,分配、设置、注册字符设备,实现对设备的操作函数(open,read,write)

    /*led_drv.c*/
    
    /* 分配/设置/注册一个platform_driver */
    
    #include <linux/module.h>
    #include <linux/version.h>
    
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    #include <linux/sched.h>
    #include <linux/pm.h>
    #include <linux/sysctl.h>
    #include <linux/proc_fs.h>
    #include <linux/delay.h>
    #include <linux/platform_device.h>
    #include <linux/input.h>
    #include <linux/irq.h>
    #include <asm/uaccess.h>
    #include <asm/io.h>
    
    static int major;
    
    
    static struct class *cls;
    static volatile unsigned long *gpio_con;
    static volatile unsigned long *gpio_dat;
    static int pin;
    
    static int led_open(struct inode *inode, struct file *file)
    {
        //printk("first_drv_open
    ");
        /* 配置为输出 */
        *gpio_con &= ~(0x3<<(pin*2));
        *gpio_con |= (0x1<<(pin*2));
        return 0;    
    }
    
    static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
    {
        int val;
    
        //printk("first_drv_write
    ");
    
        copy_from_user(&val, buf, count); //    copy_to_user();
    
        if (val == 1)
        {
            // 点灯
            *gpio_dat &= ~(1<<pin);
        }
        else
        {
            // 灭灯
            *gpio_dat |= (1<<pin);
        }
        
        return 0;
    }
    
    
    static struct file_operations led_fops = {
        .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
        .open   =   led_open,     
        .write    =    led_write,       
    };
    
    static int led_probe(struct platform_device *pdev)
    {
        struct resource        *res;
    
        /* 根据platform_device的资源进行ioremap */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        gpio_con = ioremap(res->start, res->end - res->start + 1);
        gpio_dat = gpio_con + 1;
    
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        pin = res->start;
    
        /* 注册字符设备驱动程序 */
    
        printk("led_probe, found led
    ");
    
        major = register_chrdev(0, "myled", &led_fops);
      //第一个参数指定类的所有者是哪个模块,第二个参数指定类名。
        cls = class_create(THIS_MODULE, "myled");
      //第一个参数指定所要创建的设备所从属的类,第二个参数是这个设备的父设备,如果没有就指定为NULL,第三个参数是设备号,第四个参数是供回调使用的数据,第五个参数是设备名字。
        class_device_create(cls, NULL, MKDEV(major, 0), NULL, "led"); /* 自动创建设备节点/dev/led(也可手动mknod),新版为device_create(...)*/
        
        return 0;
    }
    
    static int led_remove(struct platform_device *pdev)
    {
        /* 卸载字符设备驱动程序 */
        /* iounmap */
        printk("led_remove, remove led
    ");
    
        class_device_destroy(cls, MKDEV(major, 0));
        class_destroy(cls);
        unregister_chrdev(major, "myled");
        iounmap(gpio_con);
        
        return 0;
    }
    
    
    struct platform_driver led_drv = {
        .probe        = led_probe,
        .remove        = led_remove,
        .driver        = {
            .name    = "myled",
        }
    };
    
    
    static int led_drv_init(void)
    {
        platform_driver_register(&led_drv);
        return 0;
    }
    
    static void led_drv_exit(void)
    {
        platform_driver_unregister(&led_drv);
    }
    
    module_init(led_drv_init);
    module_exit(led_drv_exit);
    
    MODULE_LICENSE("GPL");

    3.测试应用程序:

    /*led_test.c*/
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    
    /* led_test on
     * led_test off
     */
    int main(int argc, char **argv)
    {
        int fd;
        int val = 1;
        fd = open("/dev/led", O_RDWR);
        if (fd < 0)
        {
            printf("can't open!
    ");
        }
        if (argc != 2)
        {
            printf("Usage :
    ");
            printf("%s <on|off>
    ", argv[0]);
            return 0;
        }
    
        if (strcmp(argv[1], "on") == 0)
        {
            val  = 1;
        }
        else
        {
            val = 0;
        }
        
        write(fd, &val, 4);
        return 0;
    }

    4.Makefile

    KERN_DIR = /work/system/linux-2.6.22.6
    
    all:
        make -C $(KERN_DIR) M=`pwd` modules 
    
    clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf modules.order
    
    obj-m    += led_drv.o
    obj-m    += led_dev.o
  • 相关阅读:
    PHP rsort() 函数
    PHP shuffle() 函数
    PHP sizeof() 函数
    PHP sort() 函数
    导入Orabbix_export_full.xml模板报错:主机群组 "Templates" 已存在.
    要让CLR挂掉的话……
    要让CLR挂掉的话……
    Windows 10 快捷键汇总表格
    Windows 10 快捷键汇总表格
    VisualStudio 合并代码文件
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/6443331.html
Copyright © 2011-2022 走看看