如何实现Linux设备驱动模型

合集下载

Linuxlinux硬件驱动架构

Linuxlinux硬件驱动架构

Linuxlinux硬件驱动架构linux硬件驱动(usb)模块:模块用来装载到内核中,用来实现设备驱动程序。

linux对于一个硬件的驱动,使用两种方式加载:  1.   直接加载到内核代码中,启动内核时就会驱动此硬件设备  2.   以模块方式加载,编译生成一个.o的文件,当应用程序需要时加载进内核空间运行   so (通常说的硬件驱动其实就是一个硬件驱动模块及.o文件)设备文件(设备节点):设备文件(设备节点)指定(主设备号)&& (次设备号)主设备号:对应着确定的驱动程序。

(声明设备所使用的驱动程序,设备号相当于硬件驱动程序的一个标识)次设备号:区分不同属性,不同使用方法,不同位置,不同操作设备号从/proc/drives中获取,so 先有驱动程序在内核中,才有设备节点在目录中。

SCSI(并口):通常使用的的usb存储设备,是模拟scsi硬盘而进行设计的。

Linux硬件驱动架构:.o驱动模块文件--(如果需要使用这个驱动程序,首先要加载运行它)-->insmod *.o--(驱动程序根据字符设备类型或块设备类型(鼠标属于字符设备,硬盘属于块设备))向系统注册-->注册成功之后系统返回一个主设备号---(根据主设备号创建一个放置在/dev目录下的设备文件)-->(mknod 用来创建设备文件需要用到设备号这个参数)----->我们访问硬件时,就可以对设备文件通过open,read,write等命令进行,而驱动就会接收到相应的read,write 操作而根据自己模块中的相应函数进行。

上层调用api.o 驱动drive.o与模块相关的一些东西:1. /lib/modules/2.6.**目录,下面是针对当前内核版本的模块。

Linux的总线设备驱动模型

Linux的总线设备驱动模型

Linux的总线设备驱动模型裸机编写驱动⽐较⾃由,按照⼿册实现其功能即可,每个⼈写出来都有很⼤不同;⽽Linux中还需要按照Linux的驱动模型来编写,也就是需要按照“模板”来写,写出来的驱动就⽐较统⼀。

⼀、 Linux采⽤总线设备驱动模型。

主要包含总线、设备、驱动三个部分。

总线:最先注册,有⼏个重要的回调函数,例如match函数⽤于匹配device和driver。

设备:设备的物理信息,例如设备名、物理地址、中断号等;驱动:设备的驱动程序和设备名等信息,例如初始化函数、波特率设置函数、启动停⽌函数、中断函数等。

现实中,很多设备都是接在总线上的,例如SPI Flash接在SPI总线上,EEPROM接在I2C总线上。

但也有很多芯⽚内部设备没有挂在总线上,例如UART、SPI控制器。

为了统⼀使⽤Linux总线设备驱动模型,内核中定义了⼀个虚拟总线platform_bus_type,将这些设备(叫做平台设备)注册到该虚拟总线上统⼀管理。

⼆、Linux驱动注册顺序(总线、设备、驱动三者关系)1、注册总线 xxx_bus_type:在系统初始化阶段,会⾸先向内核注册各种常⽤的总线类型,⽐如pci, usb, spi, i2c, platform等等。

有两个重要的链表挂在bus上,⼀个是设备device链表,⼀个是驱动driver链表。

它包含的最关键的函数:match()⽤于匹配device和driver。

//例⼦:static int __init spi_init(void){int status;printk("@@ spi_init :spi_bus_type\n");buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);if (!buf) {status = -ENOMEM;goto err0;}status = bus_register(&spi_bus_type);if (status < 0)goto err1;status = class_register(&spi_master_class);if (status < 0)goto err2;return 0;err2:bus_unregister(&spi_bus_type);err1:kfree(buf);buf = NULL;err0:return status;}2、注册设备:将系统设备注册进内核的对应总线上,⼤多是调⽤xxx_device_regisger注册。

linux驱动模型

linux驱动模型

我们将详细的介绍Linux的设备驱动模型。

Linux设备驱动模型是一个相当复杂的系统,对于初学者来说真有些无从入手。

而且更加困难的是,随着新的Linux Kernel的release,Linux 的设备驱动模型总会有或大或小的变化,我们将尽量展现Linux Kernel 的这种变化。

早期的Linux内核(版本2.4之前)并没有实现一个统一的设备模型,设备节点的创建一般是mknod命令手动创建或利用devfs文件系统创建。

早期的Linux发行版一般会采用手动创建的方式预先把通常用到的节点都创建出来,而嵌入式系统则会采用devfs的方式。

起初Linux 2.6 内核还支持devfs,但从2.6.18开始,内核完全移除了devfs系统而采用的udev的方式动态的创建设备节点。

因此,新的Linux发行版都采用udev的方式管理设备节点文件。

Linux2.6设备驱动模型的基本元素是Class、Bus、Device、Driver,下面我们分别介绍各个部分。

Class 和Class Device驱动模型最基本的概念是设备及其类别,Linux中使用struct class 和struct class_device来管理不同类别的设备。

由于设备驱动模型是一个复杂的系统,我们还是从一个简单的例子开始介绍,然后在逐步展开。

其实实现设备节点的动态创建是一个很简单的事情,并不需要太多的代码。

我们修改我们的驱动初始化函数如下:#include <linux/device.h>#define DEVNAME "hello"static dev_t dev;static struct class *hello_c lass;static struct cdev *hello_cdev;static int __init hello_init(void){int error;error = alloc_chrdev_region(&dev, 0, 2, "hello");if (error){printk("hello: alloc_chardev_region failed! ");goto out;}hello_cdev = cdev_alloc();if (hello_cdev == NULL){printk("hello: alloc cdev failed! ");error = -ENOMEM;goto out_chrdev;}hello_cdev->ops = &hello_fops;hello_cdev->owner = THIS_MODULE;error = cdev_add(hello_cdev, dev, 1);if (error){printk("hello: cdev_add failed! ");goto out_cdev;}hello_class = class_create(THIS_MODULE, DEVNAME);if (IS_ERR(hello_class)){error = PTR_ERR(hello_class);goto out_chrdev;}class_device_create(hello_class, NULL, dev, NULL, DEVNAME);memset (hello_buf, 0, sizeof(hello_buf));memcpy(hello_buf, DEFAULT_MSG, sizeof(DEFAULT_MSG));printk("hello: Hello World! ");return 0;out_cdev:cdev_del(hello_cdev);out_chrdev:unregister_chrdev_region(hello_cdev->dev, 2);out:return error;}static void __exit hello_exit(void){class_device_destroy(hello_class, dev);class_destroy(hello_class);unregister_chrdev_region(hello_cdev->dev, 2);cdev_del(hello_cdev);printk("hello: Goodbye World ");}重新编译这个驱动程序,当加载这个驱动到内核中时,系统(一般是hotplug和udev系统)就会自动的创建我们指定的设备名字:/dev/hello,同时,你也可以发现在sysfs系统中添加了新的文件:/sys/class/hello/hello/。

Linux设备驱动模型与sysfs---platform总线设备驱动

Linux设备驱动模型与sysfs---platform总线设备驱动

Linux在2.6版本引入了设备驱动模型,设备驱动模型负责统一实现和维护一些特性,诸如:热插拔、对象生命周期、用户空间和驱动空间的交互等基础设施1.设备驱动模型基本概念设备驱动模型主要包含:类(class)、总线(bus)、设备(device)、驱动(driver),它们的本质都是内核中的几种数据结构的“实例”∙类的本质是class结构体类型,各种不同的类其实就是class的各种实例∙总线的本质是bus_type结构体类型,各种不同的总线其实就是bus_type的各种实例∙设备的本质是device结构体类型,各种不同的设备其实就是device的各种实例∙驱动的本质是device_driver结构体类型,各种不同的驱动其实就是device_driver的各种实例2.sysfs基本概念sysfs其实就是/sys目录,其主要作用就是:展示设备驱动模型中各组件的层次关系,并将各组件的本体——内核中的数据结构以文件形式呈现,方便用户层查看及操作3./sys目录结构与设备驱动模型∙/sys目录结构很好的展示了驱动设备模型,如图:∙注意:同一个设备可能在/sys中存在多个设备文件,比如一颗led的设备文件可能在/sys/bus/platform/devices/led1,同时还有一个在/sys/class/leds/led1。

虽然他们都是同一颗led的设备文件,但是他们的来源、机制、原理都是不同的,不能混为一谈4.各组件的特性与联系∙kobject:设备驱动模型各实例的最基本单元,提供一些公用型服务如:提供该实例在sysfs中的操作方法(show和store);提供在sysfs中以文件形式存在的属性,其实就是应用接口;提供各个实例的层次架构,让sysfs中弄出目录结构。

设备驱动模型中每个实例内部都会包含一个kobject∙总线、设备、驱动,这三者有着密切的联系。

在内核中,设备和驱动是分开注册的,注册设备的时候,并不需要驱动已经存在,而驱动被注册的时候,也不需要对应的设备已经被注册。

【IT专家】linux设备驱动模型

【IT专家】linux设备驱动模型

本文由我司收集整编,推荐下载,如有疑问,请与我司联系linux设备驱动模型2012/06/05 0 最早在去年的时候学习MMC/SD/SDIO的时候就接触过设备驱动模型,但是当时也整天看书也是迷迷糊糊的,因此最终也没有将这部分知识很好的整理一下。

现在再次接触到这部分知识。

也算是完成一直以来的一个想法。

把这部分知识简单的整理一下备忘。

 设备驱动模型最初是为了解决设备的电源管理而产生的,但是最后发展起来之后,作用就越来越大了,特别适合设备管理。

对于linux设备驱动工程师来说,掌握设备驱动模型非常重要。

 linux的设备驱动模型的底层机制主要包括:kobject,kobj_type,kset等几个结构。

这几个结构定义在include/linux/kobject.h中。

 kobject代表设备驱动模型中一个基本对象。

每个kobject都对应于sysfs中的一个目录。

上层结构例如device,device_driver,bus_type都嵌入了一个kobject,这相当于面向对象程序设计机制中的继承机制。

kobject的定义如下: 60 struct kobject { 61 const char *name;/*名称*/ 62 struct list_head entry;/*用于链入所属的kset的链表*/ 63 struct kobject *parent;/*父object*/ 64 struct kset *kset;/*所属kset*/ 65 struct kobj_type *ktype;/*所属ktype*/ 66 struct sysfs_dirent *sd;/*sysfs中的目录项*/ 67 struct kref kref;/*生命周期(引用计数)管理*/ 68 unsigned int state_initialized:1;/*标记:初始化*/ 69 unsigned int state_in_sysfs:1;/*标记:在sysfs 中*/ 70 unsigned int state_add_uevent_sent:1;/*标记:已发出KOBJ_ADD uevent*/ 71 unsigned int state_remove_uevent_sent:1;/*标记:已发出的KOBJ_REMOVE uevent*/ 72 unsigned int uevent_suppress:1;/*标记:禁止发出uevent*/ 73 };kobject的基本操作: 76 int kobject_set_name(struct kobject *kobj, const char *name, ...); 77 extern int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, 78 va_list vargs); 79 80 static inline const char *kobject_name(const struct kobject *kobj) 81 { 82 return kobj- name; 83 } 84 85 extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype);。

linux字符设备驱动框架流程

linux字符设备驱动框架流程

linux字符设备驱动框架流程Linux字符设备驱动框架流程一、引言字符设备驱动是Linux系统中的一种设备驱动类型,用于对字符设备的操作和管理。

本文将介绍Linux字符设备驱动框架的流程,包括驱动的注册、设备的初始化、文件操作接口的实现以及驱动的注销。

二、驱动的注册1. 驱动的初始化:驱动的初始化是在模块加载时进行的,通过定义init函数来进行初始化操作。

在初始化函数中,需要进行一些准备工作,如分配主设备号、创建设备类等。

2. 分配主设备号:主设备号是用来标识设备驱动的唯一标识符,通过调用函数alloc_chrdev_region来分配主设备号。

分配成功后,可以通过主设备号和次设备号来唯一标识一个设备。

3. 创建设备类:设备类用于将具有相同属性和行为的设备分为一组,通过调用函数class_create来创建设备类。

设备类的创建需要指定设备类的名字和设备的回调函数。

4. 注册字符设备驱动:注册字符设备驱动是通过调用函数cdev_init和cdev_add来实现的。

cdev_init用于初始化字符设备结构,cdev_add用于将字符设备添加到系统中。

三、设备的初始化1. 设备的创建:设备的创建是通过调用函数device_create来实现的。

设备的创建需要指定设备类、父设备、设备号和设备名。

2. 设备的初始化:设备的初始化是在设备创建后进行的,通过定义probe函数来进行初始化操作。

在probe函数中,需要进行一些设备的特定初始化工作,如申请资源、初始化设备寄存器等。

四、文件操作接口的实现1. 文件操作接口的定义:文件操作接口是用于对设备进行读写操作的接口,包括打开设备、关闭设备、读取设备和写入设备等操作。

文件操作接口需要定义在字符设备结构的file_operations成员中。

2. 文件操作接口的实现:文件操作接口的实现是通过定义对应的函数来实现的。

在函数中,需要进行一些设备操作的具体实现,如读取设备数据、写入设备数据等。

设备驱动模型实验报告(3篇)

设备驱动模型实验报告(3篇)

第1篇实验目的1. 理解Linux设备驱动模型的基本概念和结构。

2. 掌握设备驱动模型中总线、设备和驱动的交互方式。

3. 学习如何编写简单的字符设备驱动程序。

4. 熟悉Linux内核中与设备驱动模型相关的系统目录和文件。

实验环境- 操作系统:Linux- 编译器:GCC- 内核版本:Linux内核4.19- 开发工具:Makefile、内核模块编译脚本实验内容本实验主要围绕Linux设备驱动模型展开,通过实际编写一个简单的字符设备驱动程序来加深对设备驱动模型的理解。

一、实验原理Linux设备驱动模型是一种分层结构,主要包括以下几层:1. 硬件层:包括各种硬件设备。

2. 总线层:负责管理硬件设备和驱动程序之间的通信。

3. 设备层:包括各种物理设备,如硬盘、网络接口卡等。

4. 驱动层:负责与硬件设备交互,实现设备的初始化、操作等功能。

5. 用户层:通过系统调用与驱动程序交互,实现对硬件设备的操作。

在设备驱动模型中,总线、设备和驱动之间通过以下方式交互:1. 总线注册:驱动程序在初始化时,需要将自身注册到对应的总线上。

2. 设备绑定:驱动程序通过总线找到对应的设备,并将自身绑定到设备上。

3. 设备操作:用户通过系统调用与设备交互,驱动程序负责实现这些操作。

二、实验步骤1. 创建字符设备驱动程序:- 定义字符设备结构体`char_device`,包含设备名称、设备号等信息。

- 实现字符设备初始化函数`char_device_init`,负责初始化字符设备。

- 实现字符设备打开函数`char_device_open`,负责打开字符设备。

- 实现字符设备读写函数`char_device_read`和`char_device_write`,负责读写字符设备数据。

- 实现字符设备关闭函数`char_device_close`,负责关闭字符设备。

2. 注册字符设备驱动程序:- 在`init_module`函数中,注册字符设备驱动程序,包括设备名称、主设备号、次设备号等信息。

Linux设备驱动模型

Linux设备驱动模型

Linux设备驱动模型Udev先前所需的硬件文件节点都需要在/dev下静态创建,随2.4核而来的devfs,带来了动态设备节点创建。

Devfs虽然提供了in-memory filesystem创建节点的方法,但是节点命名依然取决于设备驱动。

命名管理和内核 Udev依赖于以下技术:(1)、内核sysfs支持,sysfs启动时挂载到/sys下(可查看/etc/fstab);(2)、一系列用户空间工具:udevd和udevinfo;(3)、定义在/etc/udev/rules.d/目录下的用户定义规则使用Udev:1、首先从sysfs的相关文件中获取文件属性。

假设DVD:/dev/sr0,CD-RW:/dev/sr1。

使用udevinfo来收集设备信息。

bash> udevinfo -a -p /sys/block/sr0Code View:bash> udevinfo -a -p /sys/block/sr0...looking at the device chain at'/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4':BUS=?usb?ID=?1-4?SYSFS{bConfigurationValue}=?1?...SYSFS{idProduct}=?0701?SYSFS{idVendor}=?05e3?SYSFS{manufacturer}=?Genesyslogic?SYSFS{maxchild}=?0?SYSFS{product}=?USB Mass Storage Device?...bash> udevinfo -a -p /sys/block/sr1...looking at the device chain at'/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-3':BUS=?usb?ID=?1-3?SYSFS{bConfigurationValue}=?2?...SYSFS{idProduct}=?0302?SYSFS{idVendor}=?0dbf?SYSFS{manufacturer}=?Addonics?SYSFS{maxchild}=?0?SYSFS{product}=?USB to IDE Cable?...2、使用收集的产品信息来辨别设备并加入udev命名规则,创建一个/etc/udev/rules.d/40-cdvd.rules并加入如下规则:BUS="usb", SYSFS{idProduct}="0701", SYSFS{idVendor}="05e3",KERNEL="sr[0-9]*", NAME="%k", SYMLINK="usbdvd"BUS="usb", SYSFS{idProduct}="0302", SYSFS{idVendor}="0dbf",KERNEL="sr[0-9]*", NAME="%k", SYMLINK="usbcdrw"规则1的意思是:无论何时它发现一个产品id为0x0701,vender ID是0x05e3,而且名字以sr开头的usb设备,都会在/dev下创建一个同名的节点,并produce一个命名为usbdvd的符号链接给那个节点。

Linux设备驱动模型

Linux设备驱动模型

简介作者:hjlin内核版本:2.6.29设备驱动模型框架是linux驱动编程的基础。

它通过kobject,kset,ktype等底层数据结构将bus_type, device, device_driver 等高层数据结构组织起来,形成一个层次、分类清晰的驱动模型。

优点如下:1.代码重用。

将对象抽象为总线、驱动、设备三种,各司其职。

同一总线的多个驱动使用相同的总线对象。

同一驱动可以关联驱动多个设备。

2.通过sysfs文件系统,清晰了展示内核驱动模型中的层次关系。

同时sysfs文件系统还提供了方便的同用户控件交互的接口。

框架数据结构KobjectKobject是代表驱动模型中的一个对象。

总线、驱动、设备都继承了它。

(在结构体中包含kobject)。

每个kobject在sysfs中表现为一个目录。

每个kobject都有一个parent kobject和所属的kset。

Kset就是kobject所属的kset,通过kset 的链表可以找到所有属于它的kobject。

这些kobject进行uevent操作时,都会调用所属的kset 的uevent_ops方法。

父kobj,用于表示kobject之间或者kobject和kset,kset之间的在sysfs 中的目录结构关系。

如果父kobj不存在,并且所属的kset存在的话,则父kobj就是设置为所属的kset的内嵌kobj。

因此,注册设备、驱动或者总线的时候如果不指定parent kobj的话,父kobj则会设置为所属的kset的kobj。

(todo:最好画图表示关系)Kest通过kset可以将kobject组织成一颗层次树。

kobj_typebus_type代表一个总线。

对应/sys/bus下的一个目录。

管理相应总线下的所有驱动和设备。

struct bus_type {const char *name; //总线名称struct bus_attribute *bus_attrs; //该总线目录下的属性文件以及相应的访问方法struct device_attribute *dev_attrs; //该总线设备子目录下的属性文件以及相应的访问方法struct driver_attribute *drv_attrs; //该总线驱动子目录下的属性文件以及相应的访问方法int (*match)(struct device *dev, struct device_driver *drv); //驱动模型进行驱动和设备的匹配时调用int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //uevent方法int (*probe)(struct device *dev); //match成功之后会调用。

linux设备驱动程序的设计与实现

linux设备驱动程序的设计与实现

linux设备驱动程序的设计与实现
Linux设备驱动程序的设计与实现是一个涉及底层系统编程和硬件交互的复杂过程。

下面是一个简单的步骤指南,以帮助你开始设计和实现Linux设备驱动程序:
1. 了解硬件:首先,你需要熟悉你要驱动的硬件设备的规格和特性。

这包括硬件的内存空间、I/O端口、中断请求等。

2. 选择驱动程序模型:Linux支持多种设备驱动程序模型,包括字符设备、块设备、网络设备等。

根据你的硬件设备和需求,选择合适的驱动程序模型。

3. 编写Makefile:Makefile是一个文本文件,用于描述如何编译和链接你的设备驱动程序。

它告诉Linux内核构建系统如何找到并编译你的代码。

4. 编写设备驱动程序:在Linux内核源代码树中创建一个新的驱动程序模块,并编写相应的C代码。

这包括设备注册、初始化和卸载函数,以及支持读写和配置硬件的函数。

5. 测试和调试:编译你的设备驱动程序,并将其加载到运行中的Linux内核中。

使用各种测试工具和方法来验证驱动程序的正确性和稳定性。

6. 文档和发布:编写清晰的文档,描述你的设备驱动程序的用途、用法和已知问题。

发布你的代码以供其他人使
用和改进。

Linux的Platform驱动模型

Linux的Platform驱动模型

2.1 定义Platform总线
(1) bus_type总线的定义 // include\linux\device.h struct bus_type { //每个bus_type对象都对应/sys/bus目录下的一个子目录 const char *name; //总线名称 const char *dev_name; struct device *dev_root; struct bus_attribute *bus_attrs; //总线自身的属性,show,store struct device_attribute *dev_attrs; // 总线下设备共有的属性 struct driver_attribute *drv_attrs; // 总线下驱动共有的属性 int (*match)(struct device *dev, struct device_driver *drv); //匹配函数 int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //事件 int (*probe)(struct device *dev); //探测设备是否存在,或测试驱动是否正确 int (*remove)(struct device *dev); //删除设备 void (*shutdown)(struct device *dev); //关闭所有设备,断电 int (*suspend)(struct device *dev, pm_message_t state); //休眠设备 int (*resume)(struct device *dev); //恢复休眠的总线设备 struct dev_pm_ops *pm; //管理电源的函数 struct iommu_ops *iommu_ops; struct subsys_private *p; //管理设备与驱动的数据结构,私有变量指针 struct lock_class_key lock_key; };

LinuxPlatform驱动模型(二)_驱动方法

LinuxPlatform驱动模型(二)_驱动方法

LinuxPlatform驱动模型(⼆)_驱动⽅法在和中我们讨论了设备信息的写法,本⽂主要讨论平台总线中另外⼀部分-驱动⽅法,将试图回答下⾯⼏个问题:1. 如何填充platform_driver对象?2. 如何将驱动⽅法对象注册到平台总线中?正⽂前的⼀点罗嗦写驱动也有⼀段时间了,可以发现,其实驱动本质上只做了两件事:向上提供接⼝,向下控制硬件,当然,这⾥的向上并不是直接提供接⼝到应⽤层,⽽是提供接⼝给内核再由内核间接的将我们的接⼝提供给应⽤层。

⽽写驱动也是有⼀些套路可寻的,拿到⼀个硬件,我们⼤体可以按照下⾯的流程写⼀个驱动:1. 确定驱动架构:根据硬件连接⽅式结合分层/分离思想设计驱动的基本结构2. 确定驱动对象:内核中的⼀个驱动/设备就是⼀个对象,1.定义,2.初始化,3.注册,4.注销3. 向上提供接⼝:根据业务需要确定提供cdev/proc/sysfs哪种接⼝4. 向下控制硬件:1.查看原理图确定引脚和控制逻辑,2.查看芯⽚⼿册确定寄存器配置⽅式,3.进⾏内存映射,4.实现控制逻辑认识驱动⽅法对象内核⽤platform_driver结构来表⽰⼀个驱动⽅法对象//include/linux/device.h173 struct platform_driver {174 int (*probe)(struct platform_device *);175 int (*remove)(struct platform_device *);176 void (*shutdown)(struct platform_device *);177 int (*suspend)(struct platform_device *, pm_message_t state);178 int (*resume)(struct platform_device *);179 struct device_driver driver;180 const struct platform_device_id *id_table;181 bool prevent_deferred_probe;182 };在这个结构中,我们主要关⼼以下⼏个成员struct platform_driver--174-->探测函数,如果驱动匹配到了⽬标设备,总线会⾃动回调probe函数,必须实现,下⾯详细讨论。

Linux总线、设备、驱动模型与设备树

Linux总线、设备、驱动模型与设备树

Linux总线、设备、驱动模型与设备树
1.总线、设备、驱动模型
本着⾼内聚、低耦合的原则,Linux 把设备驱动模型分为了总线、设备和驱动三个实体,这三个实体在内核⾥的职责分别如下:
设备和驱动向总线进⾏注册,总线负责把设备和对应的驱动绑定起来。

驱动通过总线 API 接⼝platform_get_resource()取得板级设备信息,这样驱动和设备之间就实现了⾼内聚、低耦合的设计,
⽆论设备怎么换,驱动都可以岿然不动。

代码架构如下图所⽰:
2、设备树
引⼊设备树之前,关于硬件设备的描述信息⼀般放在⼀个个类似 arch/xxx/mach-xxx/board-xxx.c 的⽂件中,
这些代码中除了描述的设备信息不同,其代码逻辑都是⼀样的。

我们有理由,把这些设备端的信息,⽤⼀个⾮ C 的脚本语⾔来描述,这个脚本⽂件,就是 Device Tree(设备树)。

设备树是⼀种 dts ⽂件,它⽤简单的语法描述每个板⼦上的所有设备,以及这些设备的连接信息。

设备树⽂件存储在⽬录 arch/xxx/boot/dts 中,每⼀个 board 对应⼀个 dts ⽂件。

引⼊设备树之后,⼤量重复的 C 代码(arch/xxx/mach-xxx/board-xxx.c)被去除——驱动的归于驱动 C 代码,设备的归于设备树脚本⽂件。

arch/arm/mach-xxx/board-a.c 这样的⽂件永远地进⼊了历史的故纸堆,换个板⼦,只要换个 Device Tree ⽂件就好。

代码架构如下图所⽰:。

Linux网络设备驱动的实现

Linux网络设备驱动的实现

Linux⽹络设备驱动的实现结论:1、对⼀个设备驱动⽽⾔,主要从两个⽅⾯进⾏着⼿,⼀个是控制流,⼀个是数据流。

控制流就是如何控制⽹络设备,数据流则说的是报⽂的收发流程。

2、⽹络设备可以是Linux服务器的⽹卡,也可以是嵌⼊式设备的cpu或者交换芯⽚。

3、控制流分为低端的串⾏总线,如SMI、UART、SPI、USB等,也可以是⾼速总线,如PCI、PCIE总线等。

4、数据流则包含接收报⽂、发送报⽂,关键的内核数据结构是skb.⼀、⽹络设备注册与初始化1、⽹络设备的注册2、内核怎么知道调⽤驱动哪个发送函数呢?解答:在向内核注册⽹络设备时,会把驱动的实际发送函数挂接在ndo_start_xmit这个函数指针。

⼆、⽹络设备收包1、接收报⽂的流程如下:2、驱动收包任务的处理流程:三、⽹络设备发包1、驱动发包处理。

发包时,不⽤任务,⽽是在内核调⽤驱动的发包函数中直接发送。

实现思路是,将skb中的data字段和长度信息得到,然后挂在芯⽚的BD结构体上,然后启动发送,硬件就会发送出去。

四、⽹络设备性能提升⽅法1、总体思路:软硬件结合疗效好,再结合指令cache,优化收发流程处理、多核并发收发包(转发核直接使⽤轮询⽽不⽤中断收发包)。

五、skb常⽤操作⽅法1、增、删、改、查接⼝:分配skb: struct sk_buff *dev_alloc_skb(unsigned int length)释放skb: void dev_kfree_skb_any(struct sk_buff *skb)修改skb: 尾部增加内容:skb_put尾部减少内容:skb_trim头部增加内容:skb_push头部减少内容:skb_pull查找skb的头部空间:skb_headroom查找skb的尾部空间:skb_tailroom。

linux内核驱动模型和实现原理

linux内核驱动模型和实现原理

linux内核驱动模型和实现原理Linux内核驱动模型和实现原理:Linux内核是一个模块化的系统,它允许用户通过加载和卸载模块来扩展系统功能。

内核驱动程序是一种特殊类型的模块,它负责与硬件设备进行交互,控制设备的操作,并将设备的功能暴露给用户空间。

在Linux内核中,驱动程序的实现原理和模型是非常重要的。

首先,让我们来了解Linux内核驱动的模型。

Linux内核驱动模型主要由字符设备驱动、块设备驱动和网络设备驱动组成。

每种驱动类型都有自己的特点和工作方式。

字符设备驱动主要用于与字符设备进行交互,如终端设备、串口设备等。

字符设备驱动通常使用文件系统接口,通过文件描述符来访问设备,提供读写操作。

块设备驱动主要用于与块设备进行交互,如硬盘、闪存等。

块设备驱动负责管理设备的数据块,提供块设备的读写操作,支持文件系统的操作。

网络设备驱动主要用于与网络设备进行交互,如网卡、无线网卡等。

网络设备驱动负责管理网络设备的数据传输,实现网络协议栈的功能。

在Linux内核中,每种驱动类型都有对应的数据结构和函数接口,驱动程序通过这些接口与设备进行交互。

驱动程序的核心功能包括设备的注册、初始化、数据传输和中断处理等。

驱动程序的实现原理主要涉及以下几个方面:1.设备的注册和初始化:驱动程序在加载时需要将设备注册到内核中,以便内核能够识别设备并分配资源。

设备的初始化包括对设备的配置、内存的映射、中断的注册等操作。

2.数据传输和操作:驱动程序通过设备的接口进行数据的读写操作,如字符设备驱动可以使用read和write函数来进行数据传输,块设备驱动可以使用request和transfer函数来进行块的读写操作。

3.中断处理:设备通常会触发中断,驱动程序需要注册中断处理函数来处理设备的中断事件。

中断处理函数通常包括中断的处理、数据的传输、设备的复位等操作。

4.设备的管理和资源的释放:驱动程序需要负责设备的管理和资源的释放,包括设备的打开和关闭、内存的释放、中断的注销等操作。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

文库资料©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.如何实现Linux 设备驱动模型设备驱动模型,对系统的所有设备和驱动进行了抽象,形成了复杂的设备树型结构,采用面向对象的方法,抽象出了device 设备、driver 驱动、bus 总线和class 类等概念,所有已经注册的设备和驱动都挂在总线上,总线来完成设备和驱动之间的匹配。

总线、设备、驱动以及类之间的关系错综复杂,在Linux 内核中通过kobject 、kset 和subsys 来进行管理,驱动编写可以忽略这些管理机制的具体实现。

设备驱动模型的内部结构还在不停的发生改变,如device 、driver 、bus 等数据结构在不同版本都有差异,但是基于设备驱动模型编程的结构基本还是统一的。

Linux 设备驱动模型是Linux 驱动编程的高级内容,这一节只对device 、driver 等这些基本概念作介绍,便于阅读和理解内核中的代码。

实际上,具体驱动也不会孤立的使用这些概念,这些概念都融合在更高层的驱动子系统中。

对于大多数读者可以忽略这一节内容。

1.1.1 设备在Linux 设备驱动模型中,底层用device 结构来描述所管理的设备。

device 结构在文件<linux/device.h>中定义,如程序清单错误!文档中没有指定样式的文字。

.1所示。

程序清单错误!文档中没有指定样式的文字。

.1 device 数据结构定义struct device {struct device *parent; /* 父设备*/ struct device_private *p; /* 设备的私有数据 */ struct kobjectkobj; /* 设备的kobject 对象 */ const char *init_name; /*设备的初始名字 */ struct device_type *type;/* 设备类型*/ struct mutex mutex; /*同步驱动的互斥信号量 */ struct bus_type *bus; /*设备所在的总线类型 */ struct device_driver *driver; /*管理该设备的驱动程序*/ void*platform_data;/*平台相关的数据 */ struct dev_pm_infopower;/* 电源管理*/#ifdef CONFIG_NUMA int numa_node; /*设备接近的非一致性存储结构*/ #endifu64 *dma_mask; /* DMA 掩码*/ u64 coherent_dma_mask; /*设备一致性的DMA 掩码*/struct device_dma_parameters *dma_parms; /* DMA 参数*/ struct list_headdma_pools; /* DMA 缓冲池*/ struct dma_coherent_mem*dma_mem; /* DMA 一致性内存 */ /*体系结构相关的附加项*/ struct dev_archdata archdata;/* 体系结构相关的数据*/ #ifdef CONFIG_OF文库资料©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.注册和注销device 的函数分别是device_register()和device_unregister(),函数原型如下:int __must_check device_register(struct device *dev); void device_unregister(struct device *dev);大多数不会在驱动中单独使用device 结构,而是将device 结构嵌入到更高层的描述结构中。

例如,内核中用spi_device 来描述SPI 设备,spi_device 结构在<linux/spi/spi.h>文件中定义,是一个嵌入了device 结构的更高层的结构体,如程序清单错误!文档中没有指定样式的文字。

.2所示。

程序清单错误!文档中没有指定样式的文字。

.2 spi_device 数据结构struct spi_device {struct device dev;/* device 数据结构*/struct spi_master *master; u32 max_speed_hz; u8 chip_select; u8 mode; u8 bits_per_word; int irq;void *controller_state; void *controller_data; char modalias[SPI_NAME_SIZE];};系统提供了device_create()函数用于在sysfs/classs 中创建dev 文件,以供用户空间使用。

device_create()函数定义如下:struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);说明:● cls 是指向将要被注册的class 结构; ● parent 是设备的父指针; ● devt 是设备的设备编号;● drvdata 是被添加到设备回调的数据; ● fmt 是设备的名字。

文库资料©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.与device_create()函数相反的是device_destroy()函数,用于销毁sysfs/class 目录中的dev 文件。

device_destroy()函数原型如下:void device_destroy(struct class *cls, dev_t devt);1.1.2 驱动与设备相对应,Linux 设备驱动模型中,对管理的驱动也用device_driver 结构来描述,在<linux/device.h>中定义,如程序清单错误!文档中没有指定样式的文字。

.3所示。

程序清单错误!文档中没有指定样式的文字。

.3device_driver 结构定义struct device_driver {const char *name; /* 驱动的名称*/ struct bus_type *bus; /* 驱动所在的总线 */ struct module*owner;/* 驱动的所属模块*/ const char *mod_name; /*模块名称(静态编译的时候使用) */ bool suppress_bind_attrs;/*通过sysfs 禁止bind 或者unbind */ #if defined(CONFIG_OF)const struct of_device_id *of_match_table; /* 匹配设备的表 */ #endifint (*probe) (struct device *dev);/* probe 探测方法 */ int (*remove) (struct device *dev); /* remove 方法 */ void (*shutdown) (struct device *dev); /* shutdown 方法 */ int (*suspend) (struct device *dev, pm_message_t state);/* suspend 方法 */ int (*resume) (struct device *dev);/* resume 方法*/const struct attribute_group **groups; const struct dev_pm_ops *pm; /* 电源管理 */ struct driver_private *p;/* 驱动的私有数据*/};系统提供了driver_register()和driver_ungister()分别用于注册和注销device_driver ,函数原型分别如下:int __must_check driver_register(struct device_driver *drv); void driver_unregister(struct device_driver *drv);与device 结构类似,在驱动中一般也不会单独使用device_driver 结构,通常也是嵌入在更高层的描述结构中。

还是以SPI 为例,SPI 设备的驱动结构为spi_driver ,在<linux/spi/spi.h>文件中定义,是一个内嵌了device_driver 结构的更高层的结构体,原型如程序清单错误!文档中没有指定样式的文字。

.4所示。

程序清单错误!文档中没有指定样式的文字。

.4 spi_driver 数据结构struct spi_driver {const struct spi_device_id *id_table;int (*probe)(struct spi_device *spi);int(*remove)(struct spi_device *spi);文库资料©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.1.1.3 总线在设备驱动模型中,所有的设备都通过总线相连,总线既可以是实际的物理总线,也可以是内核虚拟的platform 总线。

驱动也挂在总线上,总线是设备和驱动之间的媒介,为它们提供服务。

当设备插入系统,总线将在所注册的驱动中寻找匹配的驱动,当驱动插入系统中,总线也会在所注册的设备中寻找匹配的设备。

在Linux 设备驱动模型中,总线用bus_type 结构来描述。

bus_type 结构在<linux/device.h>中定义,如程序清单错误!文档中没有指定样式的文字。

.5所示。

程序清单错误!文档中没有指定样式的文字。

.5bus_type 结构定义struct bus_type {const char *name;/* 总线名称 */ struct bus_attribute *bus_attrs; /* 总线属性 */ struct device_attribute *dev_attrs; /* 设备属性 */ struct driver_attribute *drv_attrs;/* 驱动属性*/int (*match)(struct device *dev, struct device_driver *drv); /* match 方法:匹配设备和驱动 */int (*uevent)(struct device *dev, struct kobj_uevent_env *env); /* uevent 方法,支持热插拔*/ int (*probe)(struct device *dev);/* probe 方法*/ int (*remove)(struct device *dev); /* remove 方法 */ void (*shutdown)(struct device *dev); /* shutdown 方法 * int (*suspend)(struct device *dev, pm_message_t state);/* suspend 方法 */ int (*resume)(struct device *dev); /* resume 方法*/const struct dev_pm_ops *pm; /* 电源管理*/ struct bus_type_private *p;/* 总线的私有数据结构*/};说明一下bus 总线的match 方法。

相关文档
最新文档