zoukankan      html  css  js  c++  java
  • 驱动程序分层分离概念--总线驱动设备模型

    一、示意图

                      App
    --------------------------------------------------
                     input.c
    --------------------------------------------------
               /                 
              /                   
             /        分离          
    button.c       < ===== >   evdev.c
    硬件相关                    纯软件(稳定)

    -----------------------------------------------

    bus_drv_dev模型                             bus  drv链表    
    1.把device放入bus的dev链表      device_add  /.match 1.放入drv链表 2.从dv链表取出一一比较(match)
    2.从bus的drv链表取出每一个drv              /         driver_register
    用bus的match函数判断drv能否支持dev        /           3.若支持,调用probe
    3.若可以支持,调用drv的probe           device       driver
                                        硬件相关      .probe比较稳定的代码
                                                     .name


    -----------------------------------------------
                     usb_bus_type
                    /           
    usb_new_device /              usb_register
                  /               
    usb_interface                  usb_driver
                                   .id_table
                                   .probe
                                                        
    -----------------------------------------------
            platform_bus_type
          /       .match  
         /                  
        /            
    platform_device         platform_driver
                            .probe

    -----------------------------------------------

    二、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,
            .end   = 0x56000050 + 8 - 1,
            .flags = IORESOURCE_MEM,
        },
        [1] = {
            .start = 5,
            .end   = 5,
            .flags = IORESOURCE_IRQ,
        }

    };

    static void led_release(struct device * dev)
    {
    }


    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");

    三、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");

        class_device_create(cls, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
        
        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");

    四、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;
    }
    五、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

  • 相关阅读:
    sql server 中替换字符串
    查询sql server数据库中字段内容长度的方法
    解决 Iis7.5 中的“ISAPI 和 CGI 限制”错误
    C# MVC3 中实现网银在线支付功能心得
    正则表达式验证数字和小数
    使用arttemplate js模板引擎,直接用模板渲染,减少字符串拼接。
    复选框判断全选与否以及选中删除
    内存泄漏问题
    用js闭包,在ul 里点击 li,输出对应的下标
    css 文字竖直排列
  • 原文地址:https://www.cnblogs.com/liulipeng/p/3391309.html
Copyright © 2011-2022 走看看