00_linux 设备驱动模型 2.6以后通用模型

背景:管中窥豹2.4的驱动模型,明白进程怎么调用驱动程序的
2.6以后不用去使用 mknode创建设备文件
设备还是在 /proc/devices中
设备文件都放在/sys/ 中
设备节点为 /dev/设备节点

https://blog.csdn.net/guet_kite/article/details/78368928

扫盲

结构体和对象扫盲

key_set : kset是同类型kobject对象的集合,可以说是一个容器。
Kobject是基本数据类型,每个Kobject都会在"/sys/“文件系统中以目录的形式出现。是总线、驱动、设备的三种对象的一个基类,实现公共接口。
ktype,记录了kobject对象的一些属性。比如直接设置led灯的亮度属性/sys/led_key_set/led_kobject/led_ktype
class对象 /sys/class/xxx
device对象 /sys/class/xxx/yyy
自定义总线 /sys/bus/xbus 自己生成的总线,和IIC这边匹配类似
自定义总线dev /sys/bus/xbus/device/zzz
自定义总线drv /sys/bus/xbus/drv/zzz
平台总线 sys/bus/plantform

目录位置

设备 /proc/devices
设备文件 /sys/
设备节点 /dev/

结构体
基础结构体,设备文件创建

struct kset // 继承kobj 创建keyset的时候 也会创建kset->kobj, 也用来帮kobj和用户空间沟通
struct kobject //基础结构体,创建目录
struct kobj_type //记录属性文件调用接口
struct kobj_attribute //属性对象,和ktype调用,变成一个属性文件

设备节点创建

struct class //记录创建的类
struct device//记录上面类里创建的设备,

设备创建

struct char_device_struct //proc/devices/xxx有关 看00文章
struct cdev //proc/devices/xxx有关 看00文章

自建总线相关

struct bus_type //自己建立总线结构体
struct device //用于匹配自定义device
struct device_driver //用于匹配自定义drv

plnatfrom总线相关

struct platform_device //plnatfrom平台设备
struct platform_driver // plnatfrom平台driver

设备树相关

struct device_node //设备树的每个节点用这个结构体表示
struct property //获取节点里的属性用这个结构体表示

代码大概流程

设备文件创建 操作
创建 /sys/kset_test/led_kobject 这样一个设备文件夹 里面有设备属性文件 foo和led
用户空间通过直接cat和echo 操作这两个属性 对应着控制驱动空间

/* __ATTR 定义在 include/linux/sysfs.h。
 * show成员 和 store成员 最终分别会被 kobject->ktype 下的 kobj_sys_ops 下的。
 * kobj_attr_show 和 kobj_attr_store 调用。
 * foo 对应属性文件名。
 */
static struct kobj_attribute foo_attribute =
	__ATTR(foo, 0664, foo_show, foo_store);
/* led 对应属性名 
led_show  对应open后的read 也对应cat
led_store 对应open后的write 也对应echo xx >/sys/kset_test/led_kobject/led
*/
static struct kobj_attribute led_attribute =
	__ATTR(led, 0664, led_show, led_store);

/* 下面是attr一维数组的指针
	每个attr对应一个文件夹中的一个文件*/
static struct attribute *attrs[] = {
	&foo_attribute.attr,   //对应 /sys/kset_test/led_kobject/foo
	&led_attribute.attr,   //对应 /sys/kset_test/led_kobject/led
	NULL,	/* need to NULL terminate the list of attributes */
};


static struct attribute_group attr_group = {
	.attrs = attrs,
};

static int __init led_init_test(void)  {
	/* kset_create_and_add()
	 * 1.创建了一个key_set对象my_kset  
	 * 2.同时创建了kobject对象 kset_test 存于my_kset->kobj 
	 * 3.映射kobject对象(my_kset->kobj )在文件目录 /sys/kset_test
	*/
	my_kset = kset_create_and_add("kset_test", NULL, NULL);  
	/*kobject_create_and_add()
	 * 1.创建kobject对象led_kobj 
	 * 2.指明父kobject节点为my_kset->kobj
	 * 3.文件目录映射在父节点目录下 ,此时创建led_kobj 的文件目录 /sys/kset_test/led_kobject
	*/
	led_kobj =kobject_create_and_add("led_kobject", &my_kset->kobj );
	/* 给这个kobj创建创建属性attr
	同时会在/sys/kset_test/led_kobject目录下生成属性文件
	attr_group结构体里有attrs的双重指针,给每个attrs创建操作文件
*/
	sysfs_create_group(led_kobj, &attr_group);
}
设备节点注册流程

平时想用app调用驱动 都会进行操作设备节点/dev/NEWCHRLED_NAME
下面是一个设备节点怎么被创建的

#define NEWCHRLED_NAME "newchrled" /* 名字 */
static int __init led_init(void)
{
	//分配设备号
	alloc_chrdev_region(&newchrled.devid, 0, NEWCHRLED_CNT,NEWCHRLED_NAME);
	cdev_init(&newchrled.cdev, &newchrled_fops);
	cdev_add(&newchrled.cdev, newchrled.devid, NEWCHRLED_CNT);
	/*class_create()
	 * 1.创建kobj对象 名字NEWCHRLED_NAME
	 * 2.给kobj映射文件目录 /sys/class/NEWCHRLED_NAME/
	 * 3.返回class对象,class对象其实也间接继承kobj  也就是kobj
	*/
	newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME);
	/*device_create()
	 * 1.创建kobj对象 名字NEWCHRLED_NAME
	 * 2.kob_j的父konj对象设置为class
	 * 3.给kobj映射文件目录 /sys/class/NEWCHRLED_NAME/NEWCHRLED_NAME
	 * 4.返回device对象,device对象其实也间接继承kobj 也就是kobj
	 * 5.创建/sys/class/NEWCHRLED_NAME/NEWCHRLED_NAME/dev 属性文件 存放硬件设备号
	 * 6.使用kobject_uevent() 通知用户空间守护进程udev 读取/sys/class/NEWCHRLED_NAME/NEWCHRLED_NAME/dev 属性文件
	 * 7.udev通过读取属性文件 创建设备节点 /dev/NEWCHRLED_NAME
	*/
	newchrled.device = device_create(newchrled.class, NULL,newchrled.devid, NULL, NEWCHRLED_NAME);
}
//注册完设备节点 app通过open,read,write操作驱动的file_operation结构体
自定义总线操作

自定义一个总线 叫x-bus
在里面增加dev和drv 匹配成功后 调用drv的probe
进行基本的设备文件创作和设备节点创作
/sys/bus/xbus 自己生成的总线,和IIC这边匹配类似
自定义总线dev /sys/bus/xbus/device/zzz
自定义总线drv /sys/bus/xbus/drv/zzz

bus_register(struct bus_type *bus)  //添加新的总线类型 
device_register(struct device);
driver_register(struct device_driver);

匹配成功后 再执行创建设备节点

plantform平台总线操作

平台总线相对于自定义总线 最大的特点是封装了一层 而且linux自动帮你注册这个总线 /sys/bus/plantform
让drv 能更方便的获取 dev的硬件资源 并且linux帮你写好了 总线match函数 方便匹配设备树 或id表等
所以struct platform_device 继承上面 struct device
struct platform_driver 继承上面 struct device_driver

platform_device_register(struct platform_device);  /sys/bus/plantform/dev/xxx
platform_driver_register(struct platform_driver);  /sys/bus/plantform/drv/xxx

匹配成功后 再执行创建设备节点

设备树属性查看

文章写了 翻一下

ls /sys/firmware/devicetree/base

子系统介绍

pinctrl

前面写的驱动程序 控制硬件外设的时候 需要知道硬件外设有哪些gpio 要去看数据手册 看gpio有哪些寄存器 再去配置复用寄存器 这样效率就很低 pinctrl子系统驱动 根据设备树iomuxc节点选择状态进行配置
iomuxc节点(设备树节点)

  • 汇总所需引脚的配置信息
  • pinctrl子系统预存iomux节点信息
    -各种引脚组合的信息,比如串口三个引脚 直接打包为一组放在iomuxc

其他驱动程序需要信息 要去pinctr子系统 把iomuxc的引脚信息取出来
后面太多了 没有看!!! 就看了两节

gpio子系统

在驱动中 一个引脚复用为gpio
想直接控制这个引脚 用gpio子系统开发的接口就可以了
轻松做输入输出 获取当前值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值