您的位置:首页 > 运维架构 > Linux

学习嵌入式Linux开发——韦东山升级版全系列嵌入式视频之总线设备驱动模型代码分析

2020-05-03 07:20 1276 查看

文章目录

  • 概述
  • 函数关系图
  • 模型分析
  • 资源层->设备层
  • 设备层->驱动层
  • 总结
  • 概述

    今天看了《韦东山升级版全系列嵌入式视频之总线设备驱动模型》这一节的视频,看完之后感觉有一种似懂非懂的感觉,因此我对改节视频对应源码进行分析,结果如下:

    函数关系图

    模型分析

    该模型分三层:
    一、驱动层

    二、设备层

    三、资源层

    数据流向大致为资源层->设备层->驱动层

    资源层->设备层

    要用到的引脚、设备数量等定义在资源层的resource数组内:

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

    例:

    static struct resource resources[] = {
    {
    .start = GROUP_PIN(3,1),
    .flags = IORESOURCE_IRQ,
    .name = "100ask_led_pin",
    },
    {
    .start = GROUP_PIN(5,8),
    .flags = IORESOURCE_IRQ,
    .name = "100ask_led_pin",
    },
    };

    在设备层chip_demo_gpio.c中通过platform_get_resource()函数将resource中的数据传入设备层,并在.probe = chip_demo_gpio_probe函数中创建device,在.remove = chip_demo_gpio_remove函数中卸载device:

    static struct platform_driver chip_demo_gpio_driver = {
    .probe      = chip_demo_gpio_probe,
    .remove     = chip_demo_gpio_remove,
    .driver     = {
    .name   = "100ask_led",
    },
    };
    
    static int chip_demo_gpio_probe(struct platform_device *pdev)
    {
    struct resource *res;
    int i = 0;
    
    while (1)
    {
    res = platform_get_resource(pdev, IORESOURCE_IRQ, i++);
    if (!res)
    break;
    
    g_ledpins[g_ledcnt] = res->start;
    led_class_create_device(g_ledcnt);
    g_ledcnt++;
    }
    return 0;
    
    }
    
    static int chip_demo_gpio_remove(struct platform_device *pdev)
    {
    struct resource *res;
    int i = 0;
    
    while (1)
    {
    res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
    if (!res)
    break;
    
    led_class_destroy_device(i);
    i++;
    g_ledcnt--;
    }
    return 0;
    }

    设备层->驱动层

    创建device的函数定义在驱动层leddrv.c:led_class_create_device();led_class_destroy_device()定义在驱动层leddrv.c:

    static struct class *led_class;
    
    void led_class_create_device(int minor)
    {
    device_create(led_class, NULL, MKDEV(major, minor), NULL, "100ask_led%d", minor); /* /dev/100ask_led0,1,... */
    }
    void led_class_destroy_device(int minor)
    {
    device_destroy(led_class, MKDEV(major, minor));
    }

    设备层在board_demo_led_opr结构体中对硬件进行设置,并在chip_demo_gpio_drv_init()中使用register_led_operration(&board_demo_led_opr)函数将设备层中结构体led_operations board_demo_led_opr的内容传入驱动层。
    led_operations board_demo_led_opr结构体的内容:

    /* 在例程中没有对硬件进行操作,只写了一个框架 */
    static struct led_operations board_demo_led_opr = {
    .init = board_demo_led_init,	//在此函数中使能时钟、设置引脚工作模式、设置输入输出模式
    .ctl  = board_demo_led_ctl,		//在此函数中设置引脚电平
    };
    
    static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */
    {
    //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);
    
    printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
    switch(GROUP(g_ledpins[which]))
    {
    case 0:
    {
    printk("init pin of group 0 ...\n");
    break;
    }
    case 1:
    {
    printk("init pin of group 1 ...\n");
    break;
    }
    case 2:
    {
    printk("init pin of group 2 ...\n");
    break;
    }
    case 3:
    {
    printk("init pin of group 3 ...\n");
    break;
    }
    }
    
    return 0;
    }
    
    static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
    {
    //printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");
    printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
    
    switch(GROUP(g_ledpins[which]))
    {
    case 0:
    {
    printk("set pin of group 0 ...\n");
    break;
    }
    case 1:
    {
    printk("set pin of group 1 ...\n");
    break;
    }
    case 2:
    {
    printk("set pin of group 2 ...\n");
    break;
    }
    case 3:
    {
    printk("set pin of group 3 ...\n");
    break;
    }
    }
    
    return 0;
    }

    chip_demo_gpio_drv_init()函数:

    static int __init chip_demo_gpio_drv_init(void)
    {
    int err;
    
    err = platform_driver_register(&chip_demo_gpio_driver);
    
    /* 此函数定义在驱动层leddrv.c,在此处使用将board_demo_led_opr中的内容传入驱动层的p_led_opr */
    register_led_operations(&board_demo_led_opr);
    
    return 0;
    }

    设备层leddrv.c中register_led_operration()的定义

    struct led_operations *p_led_opr;
    void register_led_operations(struct led_operations *opr)
    {
    p_led_opr = opr;
    }

    然后通过p_led_opr ->init()p_led_opr ->ctl()在open和write函数中操作硬件

    /* 2. 定义自己的file_operations结构体                                              */
    static struct file_operations led_drv = {
    .owner	 = THIS_MODULE,
    .open    = led_drv_open,
    .read    = led_drv_read,
    .write   = led_drv_write,
    .release = led_drv_close,
    };
    
    /* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */
    /* write(fd, &val, 1); */
    static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
    {
    int err;
    char status;
    struct inode *inode = file_inode(file);
    int minor = iminor(inode);
    
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    err = copy_from_user(&status, buf, 1);
    
    /* 根据次设备号和status控制LED */
    p_led_opr->ctl(minor, status);
    
    return 1;
    }
    
    static int led_drv_open (struct inode *node, struct file *file)
    {
    int minor = iminor(node);
    
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    /* 根据次设备号初始化LED */
    p_led_opr->init(minor);
    
    return 0;
    }

    总结

    总结的比较乱,但是目前我也只理解到这一步了,如果以后有了新的思路就再改吧,谢谢观看。

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签:  linux
    相关文章推荐