学习嵌入式Linux开发——韦东山升级版全系列嵌入式视频之总线设备驱动模型代码分析
文章目录
- 概述
- 函数关系图
- 模型分析
- 资源层->设备层
- 设备层->驱动层
概述
今天看了《韦东山升级版全系列嵌入式视频之总线设备驱动模型》这一节的视频,看完之后感觉有一种似懂非懂的感觉,因此我对改节视频对应源码进行分析,结果如下:
函数关系图
模型分析
该模型分三层:
一、驱动层
二、设备层
三、资源层
数据流向大致为资源层->设备层->驱动层
资源层->设备层
要用到的引脚、设备数量等定义在资源层的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; }
总结
总结的比较乱,但是目前我也只理解到这一步了,如果以后有了新的思路就再改吧,谢谢观看。
- 嵌入式学习-驱动开发-lesson5-总线设备驱动模型及平台总线驱动
- 嵌入式linux平台设备驱动(设备驱动模型)开发之linux内核中bus总线
- 嵌入式内核及驱动开发-07linux驱动之平台总线(设备驱动模型,sysfs文件系统,device的构建和注册,driver的构建和注册总线,bus匹配)
- 嵌入式学习-驱动开发-lesson3-混杂设备驱动模型与linux中断处理流程
- ldd3学习之十一(2):Linux设备模型---总线、设备、驱动
- 平台总线设备驱动模型—代码分析
- 平台总线设备驱动模型——代码分析
- 嵌入式linux平台设备驱动(设备驱动模型)开发之linux内核中的设备驱动
- 平台总线设备驱动模型——代码分析
- 学习笔记(01):嵌入式Linux驱动教程(韦东山2期)-块设备驱动程序的编写驱动之用内存模拟磁盘...
- linux 下块设备驱动开发学习笔记 2(sbull驱动分析)
- 嵌入式 linux下kernel代码中设备驱动模型之device-driver
- 【嵌入式linux驱动开发】第十节 LCD 背光驱动代码架构分析(1)
- 嵌入式linux之分离分层概念,总线驱动设备模型
- 嵌入式 linux下kernel代码中设备驱动模型之bus
- ldd3学习之十一(3):Linux设备模型---platform总线分析
- 韦东山Linux视频驱动第2期》学习总结之第17课(USB设备驱动程序)
- 嵌入式学习-驱动开发-lesson1-字符设备驱动模型
- 嵌入式 linux下kernel代码中设备驱动模型之device
- Linux设备驱动程式学习(13)-Linux设备模型(总线、设备、驱动程式和类)