11-S3C2440驱动学习(七)嵌入式linux-字符设备的另一种写法及RTC驱动程序分析和字符设备驱动框架总结
来源:互联网 发布:下载汉王识别软件 编辑:程序博客网 时间:2024/06/10 15:14
一、字符设备驱动程序的另一种写法
1.1、之前
major = register_chrdev(0, "hello", &hello_fops); /* (major, 0), (major, 1), ..., (major, 255)都对应hello_fops */缺点:一个主设备号,占据了0-255个次设备号,由主设备号确定file_operations结构体
1.2、现在
将register_chrdev:拆分为三部分
优点:指定次设备号范围,由主设备+次设备号确定file_operations结构体,且同一主设备号可以由多个file_operations结构体。
分析register_chrdev_region:
if (major) {devid = MKDEV(major, 0);//从0开始register_chrdev_region(devid, HELLO_CNT, "hello"); /* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */}如果指定了主设备号major,MKDEV将主设备号转换为dev_t类型。
参数1:dev_t类型类型主设备号,且初始化了次设备号的起始值
参数2:设备节点的数量
参数3:驱动名字
分析alloc_chrdev_region:
else {alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello"); /* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */major = MAJOR(devid); }如果没有指定住设备号,用次函数。
参数1:主设备号
参数2:此设备号起始值
参数3:设备节点数量
参数4:驱动名字
分析cdev_init:
cdev_init(&hello_cdev, &hello_fops);关联cdev设备与file_operations结构体
参数1:cdev设备
参数2:file_operations结构体
分析cdev_add:
cdev_add(&hello_cdev, devid, HELLO_CNT);注册信息
参数1:cdev设备
参数2:主设备号信息
参数3:设备节点数量
1.3、hello world例子代码
#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/irq.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/arch/regs-gpio.h>#include <asm/hardware.h>#include <linux/poll.h>#include <linux/cdev.h>/* 1. 确定主设备号 */static int major;static int hello_open(struct inode *inode, struct file *file){printk("hello_open\n");return 0;}/* 2. 构造file_operations */static struct file_operations hello_fops = {.owner = THIS_MODULE,.open = hello_open,};#define HELLO_CNT 2static struct cdev hello_cdev;static struct class *cls;static int hello_init(void){dev_t devid;/* 3. 告诉内核 */#if 0major = register_chrdev(0, "hello", &hello_fops); /* (major, 0), (major, 1), ..., (major, 255)都对应hello_fops */#elseif (major) {devid = MKDEV(major, 0);//从0开始register_chrdev_region(devid, HELLO_CNT, "hello"); /* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */} else {alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello"); /* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */major = MAJOR(devid); }cdev_init(&hello_cdev, &hello_fops);cdev_add(&hello_cdev, devid, HELLO_CNT);#endifcls = class_create(THIS_MODULE, "hello");class_device_create(cls, NULL, MKDEV(major, 0), NULL, "hello0"); /* /dev/hello0 */class_device_create(cls, NULL, MKDEV(major, 1), NULL, "hello1"); /* /dev/hello1 */class_device_create(cls, NULL, MKDEV(major, 2), NULL, "hello2"); /* /dev/hello2 */return 0;}static void hello_exit(void){class_device_destroy(cls, MKDEV(major, 0));class_device_destroy(cls, MKDEV(major, 1));class_device_destroy(cls, MKDEV(major, 2));class_destroy(cls);cdev_del(&hello_cdev);unregister_chrdev_region(MKDEV(major, 0), HELLO_CNT);}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("GPL");
1.4、测试程序#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>/* * hello_test /dev/hello0 */void print_usage(char *file){printf("%s <dev>\n", file);}int main(int argc, char **argv){int fd;if (argc != 2){print_usage(argv[0]);return 0;}fd = open(argv[1], O_RDWR);if (fd < 0)printf("can't open %s\n", argv[1]);elseprintf("can open %s\n", argv[1]);return 0;}
2、RTC驱动程序分析
系统:linux-3.4.2
2.1、框架分析
(1)内核驱动地址:内核中RTC驱动程序:Rtc-s3c.c(linux-3.4.2\drivers\rtc)
(2)入口函数:
module_platform_driver(s3c_rtc_driver);
展开后是:static int __init gpio_pmodoled_driver_init(void){ return platform_driver_register(&xxx);}module_init(xxx);static void __exit gpio_pmodoled_driver_init(void){ return platform_driver_unregister(&xx);}module_exit(xxx);(3)platform_driver总线驱动模型
RTC驱动程序采用platform_driver的方式,内核注册了s3c-rtc设备,设备配置文件里初始化该平台设备。当加载RTC驱动程序的时候,发现内核中有名为“s3c2410-rtc”设备,因此调用platform_driver s3c_rtc_driver的probe函数。
static struct platform_driver s3c_rtc_driver = {.probe= s3c_rtc_probe,.remove= __devexit_p(s3c_rtc_remove),.suspend= s3c_rtc_suspend,.resume= s3c_rtc_resume,.id_table= s3c_rtc_driver_ids,.driver= {.name= "s3c-rtc",.owner= THIS_MODULE,.of_match_table= s3c_rtc_dt_match,},};
内核在Devs.c (linux-3.4.2\arch\arm\plat-samsung)定义了RTC平台设备及其资源
#ifdef CONFIG_PLAT_S3C24XXstatic struct resource s3c_rtc_resource[] = {[0] = DEFINE_RES_MEM(S3C24XX_PA_RTC, SZ_256),[1] = DEFINE_RES_IRQ(IRQ_RTC),[2] = DEFINE_RES_IRQ(IRQ_TICK),};struct platform_device s3c_device_rtc = {.name= "s3c2410-rtc",.id= -1,.num_resources= ARRAY_SIZE(s3c_rtc_resource),.resource= s3c_rtc_resource,};#endif /* CONFIG_PLAT_S3C24XX */
在Common-smdk.c (linux-3.4.2\arch\arm\mach-s3c24xx)里初始化platform_device,并添加相应设备
(4)s3c_rtc_probe函数中向上注册
s3c_rtc_probe{ rtc= rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,THIS_MODULE);}
(5)上层核心文件:
Class.c (linux-3.4.2\drivers\rtc) rtc_device_register、rtc_init
Rtc-dev.c(linux-3.4.2\drivers\rtc) rtc_init—》rtc_dev_init();
(6)上层驱动入口函数:
rtc_dev_init();{err =alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");}注册设备
(7)rtc_device_register注册rtc_device设备。
并分配、设置、注册rtc_device,并注册设备节点。
rtc_device_register// Class.c{rtc_dev_prepare(rtc); //Rtc-dev.c{ cdev_init(&rtc->char_dev, &rtc_dev_fops);}rtc_dev_add_device(rtc); //Rtc-dev.c{ cdev_add(&rtc->char_dev, rtc->dev.devt, 1)}}(8)file_operations结构体:
设备对应的file_operations结构体
//Rtc-dev.cstatic const struct file_operations rtc_dev_fops = {.owner= THIS_MODULE,.llseek= no_llseek,.read= rtc_dev_read,.poll= rtc_dev_poll,.unlocked_ioctl= rtc_dev_ioctl,.open= rtc_dev_open,.release= rtc_dev_release,.fasync= rtc_dev_fasync,};rtc_device对应的ops结构体。
static const struct rtc_class_ops s3c_rtcops = {.read_time= s3c_rtc_gettime,.set_time= s3c_rtc_settime,.read_alarm= s3c_rtc_getalarm,.set_alarm= s3c_rtc_setalarm,.proc= s3c_rtc_proc,.alarm_irq_enable = s3c_rtc_setaie,};
2.2、调用过程分析
-------------------------------------------
kernel: sys_open
rtc_dev_fops.open
rtc_dev_open
// 根据次设备号找到以前用"rtc_device_register"注册的rtc_device
struct rtc_device *rtc = container_of(inode->i_cdev,struct rtc_device, char_dev);
const struct rtc_class_ops *ops = rtc->ops;
err = ops->open ? ops->open(rtc->dev.parent) : 0;
s3c_rtc_open
app: ioctl(fd, RTC_RD_TIME,...)
-------------------------------------------
kernel: sys_ioctl
rtc_dev_fops.ioctl
rtc_dev_ioctl
struct rtc_device *rtc = file->private_data;
rtc_read_time(rtc, &tm);
err = rtc->ops->read_time(rtc->dev.parent, tm);
s3c_rtc_gettime
分析:
(1)应用程序调用open函数:open("/dev/rtc0");
(2)设备节点对应的上层file_operations结构体的open函数被调用,即rtc_dev_fops的rtc_device被调用。
(3)rtc_device函数中,通过次设备号,找到对用的rtc_device设备。
struct rtc_device *rtc = container_of(inode->i_cdev,struct rtc_device, char_dev);
(4)如果rtc_device设备由open函数,则调用open函数(这个open函数是rtc_device设备的open函数,即rtc_class_ops结构体里的s3c_rtc_open函数被调用)。
同理app:ioctl(fd, RTC_RD_TIME,...)
3、字符设备驱动框架总结
3.1、字符设备驱动
(1)头文件
(2)入口函数:module_init
a、register_chrdev b、register_chrdev_region/alloc_chrdev_region cdev_init cdev_add class_create class_device_create
(3)出口函数:module_exit
(4)修饰:MODULE_LICENSE("GPL");
3.2、复杂字符设备驱动
内核中的很多驱动程序采用了分层的结构,如RTC、Lcd、V4L2等等。
所谓分层,可以理解为一个驱动程序有多部分组成,内核中帮我们完成并加载了上层驱动部分,并提供了API接口,我们通过API接口完成硬件相关的驱动。其中一种典型的应用就是platform_driver与分层结构的组合。比如在RTC驱动程序中,内核初始化了一个名为s3c-rtc平台设备,在配置在单板的配置初始化文件中完成平台设备的加载。当我们注册一个名为s3c-rtc平台设备的时候,这个平台设备的probe函数被调用,往往在probe函数中会创建一个字符设备。并注册rtc_device。应用程序open时,调用字符设备file_operations里的open函数,这个open函数首先会通过次设备号获取rtc_device,并判断是否有open函数,有的话则调用里面的open函数,同理其他函数。
- 11-S3C2440驱动学习(七)嵌入式linux-字符设备的另一种写法及RTC驱动程序分析和字符设备驱动框架总结
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-LED字符设备驱动
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-查询+中断+引入poll机制的按键驱动程序
- 基于mini6410的linux驱动学习总结(五 字符设备驱动程序实例分析(虚拟设备驱动))
- 字符设备驱动之RTC驱动分析
- s3c2440基于linux的button和led字符设备驱动
- 基于mini6410的linux驱动学习总结(四 设计字符设备驱动程序)
- 嵌入式linux字符设备驱动
- 嵌入式linux字符设备驱动
- Linux设备驱动--简单字符设备驱动程序
- Linux设备驱动--字符设备驱动程序1
- Linux设备驱动--字符设备驱动程序2
- 11-S3C2440驱动学习(八)嵌入式linux-块设备驱动程序
- Linux字符设备驱动程序的框架(新写法)
- linux设备驱动学习(3) 字符设备驱动程序
- Linux设备驱动程序学习(1)--字符设备驱动
- 【原创】《Linux设备驱动程序》学习之循序渐进 --- 字符设备驱动
- 字符设备驱动框架学习总结
- 常见排序算法的python实现
- Activity免注册跳转
- 监控摄像头进行网页直播和微信直播的技术方案
- 基于docker的caffe环境搭建与使用示例
- Ref 与 Out 的区别
- 11-S3C2440驱动学习(七)嵌入式linux-字符设备的另一种写法及RTC驱动程序分析和字符设备驱动框架总结
- 非平稳时间序列季节效应分析
- 定义自己异常
- Spring Security 系列教程(2)
- SEO之HTML优化:让你的网站HTML代码更符合SEO规范
- 数据挖掘领域十大经典算法
- Binder机制开启篇
- CSS之Responsive网页设计的三个特性
- 图像处理中的线性和非线性滤波器(上)