Linux设备驱动模型之上层容器
Linux内核驱动:cdev、misc以及device三者之间的联系和区别
![Linux内核驱动:cdev、misc以及device三者之间的联系和区别](https://img.taocdn.com/s3/m/ed561824effdc8d376eeaeaad1f34693daef10d5.png)
Linux内核驱动:cdev、misc以及device三者之间的联系和区别Linux内核驱动:cdev、misc以及device三者之间的联系和区别背景我想在cdev中使⽤dev_err等log打印函数,但是跟踪了⼀下cdev中的原型,发现并不是我想要的。
常见的驱动是这样⼦使⽤dev_err的:// 某个驱动,这⾥是电池有关的static int32_t oz8806_read_byte(struct oz8806_data *data, uint8_t index, uint8_t *dat){struct i2c_client *client = data->myclient;// ...dev_err(&client->dev, "%s: err %d, %d times\n", __func__, ret, i);// ...}⽽i2c_client原型是这样⼦的,dev就是⼀个device:// include/linux/i2c.hstruct i2c_client {// ...struct device dev; /* the device structure */// ...};那么,我想只要找到cdev中的dev,也可以这样⼦⽤,对吧?但是:// include/linux/cdev.hstruct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;} __randomize_layout;⽽dev_t长这个样⼦:// include/linux/types.htypedef u32 __kernel_dev_t;typedef __kernel_dev_t dev_t;我在困惑dev_t是什么东西以后,找到了下⾯这篇⽂章。
linux网络基础知识
![linux网络基础知识](https://img.taocdn.com/s3/m/c4642ad4ce2f0066f5332277.png)
Linux网络基础知识TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。
这4层分别为:应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。
传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。
网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。
网络接口层(网络接口层例如以太网设备驱动程序):对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据。
网络接口层在发送端将上层的IP数据报封装成帧后发送到网络上;数据帧通过网络到达接收端时,该结点的网络接口层对数据帧拆封,并检查帧中包含的MAC地址。
如果该地址就是本机的MAC地址或者是广播地址,则上传到网络层,否则丢弃该帧。
网络接口层可细分为数据链路层和物理层,数据链路层实际上就是网卡的驱动程序,物理层实际上就是布线、光纤、网卡和其它用来把两台网络通信设备连接在一起的东西。
链路层,有时也称作数据链路层或网络接口层,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡。
它们一起处理与电缆(或其他任何传输媒介)的物理接口细节。
网卡驱动程序主要实现发送数据帧与接受数据帧的功能,发送数据帧采用内核函数hard_start_xmit();接收数据帧采用内核函数netif_rx();网卡驱动程序主要是分配设置及注册net_dev结构体;数据帧的载体采用sk-buff结构体。
用浏览网页为例:发送方:1.输入网址:,按了回车键,电脑使用应用层用IE浏览器将数据从80端口发出,给了下一层协议——传输层。
Linux设备驱动模型与sysfs---platform总线设备驱动
![Linux设备驱动模型与sysfs---platform总线设备驱动](https://img.taocdn.com/s3/m/614147d2e109581b6bd97f19227916888486b96e.png)
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∙总线、设备、驱动,这三者有着密切的联系。
在内核中,设备和驱动是分开注册的,注册设备的时候,并不需要驱动已经存在,而驱动被注册的时候,也不需要对应的设备已经被注册。
Linux设备模型浅析之uevent篇
![Linux设备模型浅析之uevent篇](https://img.taocdn.com/s3/m/57be811459eef8c75fbfb3e3.png)
/* 在本例中是 devices_kset 容器,详细介绍可参照《Linux 设备模型浅析之设备篇》,后 面将列出 devices_kset 的定义 */ kset = top_kobj->kset; uevent_ops = kset->uevent_ops; // 本例中 uevent_ops = &device_uevent_ops
struct sk_buff *skb; size_t len;
/* allocate message with the maximum possible size */ len = strlen(action_string) + strlen(devpath) + 2; skb = alloc_skb(len + env->buflen, GFP_KERNEL); if (skb) {
return 0; }
// 获得用于存放环境变量的 buffer /* environment buffer */ env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); if (!env)
return -ENOMEM;
/* 获取该 kobj 在 sysfs 的路径,通过遍历其父 kobj 来获得,本例是/sys/devices/platform/ s3c2410-rtc/rtc/rtc0 */ /* complete object path */
goto exit;
/* 如果配置了网络,那么就会通过 netlink socket 向用户空间发送环境标量,而用户空间 则通过 netlink socket 接收,然后采取一些列的动作。这种机制目前用在 udev 中,也就是 pc 机系统中,后面会分析*/ #if defined(CONFIG_NET) /* send netlink message */ /* 如果配置了 net,则会在 kobject_uevent_init()例程中将全局比昂俩 uevent_sock 初试化 为 NETLINK_KOBJECT_UEVENT 类型的 socket。*/ if (uevent_sock) {
Linux设备驱动编程模型之上层容器篇(DOCX 33页)
![Linux设备驱动编程模型之上层容器篇(DOCX 33页)](https://img.taocdn.com/s3/m/3a6a836808a1284ac9504369.png)
Linux设备驱动编程模型之上层容器篇(DOCX 33页)Linux设备驱动编程模型之上层容器篇分类:Linux 2012-10-06 17:18 245人阅读评论(0) 收藏举报linux编程struct数据结构listnull2.6内核增加了一个引人注目的新特性——统一设备模型(device model)。
设备模型提供了一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构,从而使得系统具有以下优点:●∙∙∙∙∙∙∙∙代码重复最小化。
●∙∙∙∙∙∙∙∙提供诸如引用计数这样的统一机制。
●∙∙∙∙∙∙∙∙可以列举系统中所有的设备,观察它们的状态,并且查看它们连接的总线。
●∙∙∙∙∙∙∙∙可以将系统中的全部设备结构以树的形式完整、有效的展现出来——包括所有的总线和内部连接。
●∙∙∙∙∙∙∙∙可以将设备和其对应的驱动联系起来,反之亦然。
●∙∙∙∙∙∙∙∙可以将设备按照类型加以归类,比如分类为输入设备,而无需理解物理设备的拓扑结构。
●∙∙∙∙∙∙∙∙可以沿设备树的叶子向其根的方向依次遍历,以保证能以正确顺序关闭各设备的电源。
最后一点是实现设备模型的最初动机。
若想在内核中实现智能的电源管理,就需要来建立表示系统中设备拓扑关系的树结构。
当在树上端的设备关闭电源时,内核必须首先关闭该设备节点以下的(处于叶子上的)设备电源。
比如内核需要先关闭一个USB鼠标,然后才可关闭USB控制器;同样内核也必须在关闭PCI总线前先关闭USB控制器。
简而言之,若要准确而又高效的完成上述电源管理目标,内核无疑需要一颗设备树。
一、原理虽然设备模型的初衷是为了方便电源管理而提供出的一种设备拓扑结构,但是,为了方便调试,设备模型的开发者决定将设备结构树导出为一个文件系统,这就是sysfs文件系统,它可以帮助用户能以一个简单文件系统的方式来观察系统中各种设备的拓扑结构。
这个举措很快被证明是非常明智的,首先sysfs代替了先前处于/proc下的设备相关文件;另外它为系统对象提供了一个很有效的视图。
深入解析LinuxPlatform_device及驱动
![深入解析LinuxPlatform_device及驱动](https://img.taocdn.com/s3/m/1f21e2f8846a561252d380eb6294dd88d0d23d46.png)
深⼊解析LinuxPlatform_device及驱动[导读] 前⽂分析了Linux设备驱动的驱动模型,本⽂来聊聊Platform_driver/Platform_device这个类。
做嵌⼊式Linux的驱动,这个也是绕不开的,所以来学习分析总结⼀下。
上⽂阅读:注:代码分析基于linux-5.4.31为什么有Platform_driver前⽂谈到的总线驱动模型(注这个图是照着bootlin的⽂档绘制的):同时,根据代码分析其基础数据结构框架关系如下(UML关系并不严谨,仅为理解⽅便):可见驱动程序的模型分层有⼀层总线基础层,那么对于嵌⼊式开发领域⽽⾔,有很多SOC芯⽚内置了各种外设,并⽐如LCD,UART、audio、摄像头⼝等等,并没有总线。
为了统⼀驱动架构抽象,所以引⼊了platform bus这个虚拟的总线模型。
做过嵌⼊式开发的⼈应该都有体会,这类设备在嵌⼊式系统中⾮常多,所以在研究具体某类设备的驱动开发之前,有必要研究platform 设备的驱动模型。
在强调⼀下这个是统⼀在总线驱动模型这个体系内的。
驱动模型的实现定义在./include/linux/platform_device.h中,来梳理⼀下这些数据结构间的关系:platform_device ⽤于抽象平台设备platform_driver ⽤于抽象匹配平台设备对应的驱动程序通过继承演化关系分析,platform_device/platform_driver 仍然统⼀于总线驱动模型,只是虚拟出来了⼀条platform bus这样⼀条虚拟总线。
platform_bus在哪⾥实现的呢?该模块的实现位于./driver/base/platform.c中struct device platform_bus = {.init_name = "platform",};platform.c导出了⼀系列内核全局操作接⼝集:EXPORT_SYMBOL_GPL(platform_bus);EXPORT_SYMBOL_GPL(__platform_driver_register);EXPORT_SYMBOL_GPL(__platform_driver_probe);EXPORT_SYMBOL_GPL(platform_get_resource_byname);EXPORT_SYMBOL_GPL(platform_get_irq_byname);....那么既然这条总线并不存在,往往并不能实现设备枚举、热插拔等功能。
Linux设备驱动之platform
![Linux设备驱动之platform](https://img.taocdn.com/s3/m/cc0dba5416fc700abb68fc8b.png)
Linux设备驱动之platform
根据Linux设备模型可知,一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC 内存空间的外设等却不依附于此类总线。
基于这一背景,Linux设计了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动称为platform_driver。
设计目的
兼容设备模型
使得设备被挂接在一个总线上,因此,符合Linux 2.6 的设备模型。
其结果是,配套的sysfs 结点、设备电源管理都成为可能。
BSP和驱动隔离
在BSP中定义platform设备和设备使用的资源、设备的具体配置信息。
而在驱动中,只需要通过通用API去获取资源和数据,做到了板相关代码和驱动代码的分离,使得驱动具有更好的可扩展性和跨平台性。
软件架构
内核中Platform设备有关的实现位于include/linux/platform_device.h和drivers/base/platform.c两个文件中,它的软件架构如下:
由图片可知,Platform设备在内核中的实现主要包括三个部分:
Platform Bus,基于底层bus模块,抽象出一个虚拟的Platform bus,用于挂载Platform设备;
Platform Device,基于底层device模块,抽象出Platform Device,用于表示Platform设备;Platform Driver,基于底层device_driver模块,抽象出Platform Driver,用于驱动Platform 设备。
kobject设备模型分析
![kobject设备模型分析](https://img.taocdn.com/s3/m/6df5662fe2bd960590c6771e.png)
sysfs是kobject的表达,所以这里翻译了Documention下的kobjct.txt,并加上了一些自己的注释,这样基本就对kobject 和sysfs有了一个比较深刻的理解,我们可以简单的将sysfs看成最bottom的操作,然后kobject的想关操作是架构在sysfs 之上,再然后kobject和attribute所嵌入的结构体再构成上一层结构来操作kobject,最后就实现了kernel内部各个portion 通过sysfs与userspace进行交互。
要想了解linux驱动模型,以及驱动模型之上的kobject抽象,有一个难点就是我们没有一个明确的入手点。
要想了解kobject 我们必须了解很多不同的类型,而这些类型之间又会交叉引用,所以为了让理解更容易我们从多方面入手,首先看一些可能模糊不清的概念,然后随着深入我们会加入细节,在最后我们会定义一些我们工作上需要使用的术语。
kobject是一个结构体,它包含name,reference count以及指向一个parent的指针(这个指针等于就是将kobject加入了一个体系结构中),一个特定的类型,以及在sysfs文件系统中的一个相关表达。
kobject一般不会单独使用,大部分的时候它会被嵌入其他的结构体,而这些结构体才是我们代码中真正需要的。
一个结构体最多只能嵌入一个kobject,不然reference count就会乱掉,出错。
(PS:实际上我们可以理解这个kobject实际上是我们与sysfs进行交互的一个接口,我们在设备驱动以及总线相关的结构体中嵌入这个kobject,那么我们的设备驱动就可以通过sysfs与userspace进行交互了。
虽然sysfs是kobject的表达,但我们可以近似的将kobject看成是架在sysfs上面的,在kobject上面封装的一系列操作实际上到底层都是调用的sysfs的公共接口)struct kobject {const char *name;struct list_head entry;struct kobejct *parent;struct kset *kset;struct kobj_type *ktype;struct sysfs_dirent *sd;struct kref kref;unsigned int state_initialized:1;unsigned int state_in_sysfs:1;unsigned int state_add_uevent_sent:1;unsigend int state_remove_uevent_sent:1;}ktype定义了嵌入了kobject的结构体的类型,每一个嵌入了kobject的结构体都必须有一个想对应的ktype,ktype定义了这个kobject创建和销毁时候需要做的事情。
Docker容器存储驱动的选择与比较
![Docker容器存储驱动的选择与比较](https://img.taocdn.com/s3/m/a5d74db1690203d8ce2f0066f5335a8102d26638.png)
Docker容器存储驱动的选择与比较在使用Docker进行容器化部署时,容器存储驱动的选择是一个重要的决策,它直接影响到整个应用的性能、可用性和稳定性。
本文将对常见的Docker容器存储驱动进行比较和分析,帮助读者了解不同存储驱动的优缺点,以便做出合适的选择。
1. 目前常见的容器存储驱动目前,在主流的Docker社区中,最常见的存储驱动有OverlayFS、aufs、Device Mapper和Btrfs。
每个驱动都有其独特的特点和适用场景。
2. OverlayFSOverlayFS是Linux内核中的一种联合文件系统,在Docker中作为默认的存储驱动。
它通过将文件系统的改动应用到顶层的只读文件系统上来实现。
OverlayFS的优点是性能高,并且支持快速的容器创建和启动。
然而,它对底层文件系统的要求较高,不适用于某些特定的环境,如使用了ZFS或XFS文件系统的机器。
3. aufsaufs也是一种联合文件系统,被广泛用于容器的存储。
它的优点是与大多数Linux发行版兼容,并且在大部分硬件和文件系统上都能正常工作。
然而,aufs相对于OverlayFS在性能上稍逊一筹,并且在大规模的容器集群中可能出现性能瓶颈。
4. Device MapperDevice Mapper是Linux内核中的一个子系统,它提供了逻辑卷管理(LVM)的功能。
在Docker中,Device Mapper主要用于创建逻辑卷,以提供更高级的存储功能,如快照和复制。
Device Mapper的优点是稳定性高,支持高级存储功能,但同时也带来了一些性能的损失。
5. BtrfsBtrfs是一种基于Copy-on-Write(写时复制)的文件系统,具有非常好的快照和数据保护能力。
在Docker中,Btrfs可以提供更高级的存储功能,并且对于大规模的容器集群来说,性能也较好。
然而,Btrfs的稳定性较差,且在某些Linux发行版中可能需要进行额外的配置和安装。
Linux驱动之总线驱动模型
![Linux驱动之总线驱动模型](https://img.taocdn.com/s3/m/7461edb104a1b0717fd5ddd8.png)
随着系统结构演化越来越复杂,Linux内核对设备描述衍生出一般性的抽象描述,形成一个分层体系结构,从而引入了设备驱动模型。
这样描述还是不够让人理解,来看一下这些需求就好理解些:•Linux内核可以在各种体系结构和硬件平台上运行,因此需要最大限度地提高代码在平台之间的可重用性。
•分层实现也实现了软件工程的高内聚-低耦合的设计思想。
低耦合体现在对外提供统一的抽象访问接口,高内聚将相关度紧密的集中抽象实现。
•Linux内核驱动程序模型是先前在内核中使用的所有不同驱动程序模型的统一。
它旨在通过将一组数据和操作整合到全局可访问的数据结构中,来扩展基于基础总线来桥接设备驱动程序。
传统的驱动模型为它们所控制的设备实现了某种类似于树的结构(有时只是一个列表)。
不同类型的总线之间没有任何一致性。
驱动模型抽象了啥当前驱动程序模型为描述总线和总线下可能出现的设备提供了一个通用的、统一的模型。
统一总线模型包括一组所有总线都具有的公共属性和一组公共回调,如总线探测期间的设备发现、总线关闭、总线电源管理等。
通用的设备和桥接接口反映了现代计算机的目标:即执行无缝设备“即插即用”,电源管理和热插拔的能力。
特别是,英特尔和微软规定的模型(即ACPI)可确保与x86兼容的系统上几乎任何总线上的几乎所有设备都可以在此范式下工作。
当然,虽然大多数总线都支持其中大多数操作,但并不是每条总线都能够支持所有此类操作。
那么哪些通用需求被抽象出来了呢?•电源系统和系统关机,对于电源管理与系统关机对于设备相关的操作进行抽象实现。
关机为什么要被抽象出来管理,比如设备操作正在进行此时系统收到关机指令,那么在设备模型层就会遍历系统设备硬件,确保系统正确关机。
•用户空间访问:sysfs虚拟文件系统实现与设备模型对外的访问抽象,这也是为什么说Linux 设备也是文件的由来。
实际从软件架构层面看,这其实是一个软件桥接模块,抽象出统一用户访问接口,桥接了设备驱动。
linux的驱动调用方法
![linux的驱动调用方法](https://img.taocdn.com/s3/m/86e4de4b6d85ec3a87c24028915f804d2a16874d.png)
linux的驱动调用方法Linux驱动调用方法Linux是一种广泛使用的开源操作系统,它具有稳定、安全、高效和可定制的特点。
作为开源系统,Linux支持各种硬件设备,但要让硬件设备能够正常工作,我们需要使用对应的设备驱动程序。
本文将详细介绍Linux 的驱动调用方法,从加载和安装驱动到使用驱动,一步一步回答你的问题。
第一步:了解设备驱动设备驱动程序是操作系统内的一类软件,它通过与硬件设备交互来实现操作系统与硬件之间的通信。
设备驱动程序为应用程序提供了一系列接口,使其可以访问和控制硬件设备。
Linux设备驱动程序通常包括两个部分:设备驱动模块和设备驱动文件。
设备驱动模块是驱动程序的实现代码,它以动态链接库的形式存在。
设备驱动模块可以被加载到内核中,从而成为内核的一部分。
设备驱动文件则是一些特殊的文件,它们代表了系统中的具体硬件设备。
第二步:加载设备驱动在使用设备驱动之前,我们需要将它加载到内核中。
在Linux系统中,可以使用modprobe命令或insmod命令来加载设备驱动模块。
modprobe 命令会自动解析依赖关系,并加载相关的模块。
例如,如果我们要加载名为"mydriver"的设备驱动模块,可以使用以下命令:sudo modprobe mydriver或者,如果设备驱动程序没有被自动加载,可以使用insmod命令来手动加载:sudo insmod /path/to/mydriver.ko需要注意的是,加载设备驱动需要系统管理员权限。
第三步:安装设备驱动在加载设备驱动之前,我们需要确定设备驱动文件的位置。
通常,设备驱动文件位于/sys/class目录下的一个子目录中。
例如,设备驱动文件可能位于/sys/class/mydriver目录中。
为了安装设备驱动,我们需要创建一个符号链接到设备驱动文件。
在Linux 系统中,可以使用udev服务来自动创建符号链接。
首先,我们需要创建一个udev规则文件。
LinuxPlatform驱动模型(二)_驱动方法
![LinuxPlatform驱动模型(二)_驱动方法](https://img.taocdn.com/s3/m/d9653d3e0166f5335a8102d276a20029bd64639e.png)
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设备驱动编程模型之上层容器篇](https://img.taocdn.com/s3/m/f1b3e7bc7d1cfad6195f312b3169a4517723e5f7.png)
Linux设备驱动编程模型之上层容器篇引言在Linux设备驱动编程中,上层容器是一个重要的概念。
它提供了一个抽象层,用于将不同类型的设备驱动程序封装在一起,使得用户可以方便地访问和操作设备。
本文将介绍Linux设备驱动编程模型中的上层容器,并说明其工作原理和常见用途。
上层容器概述在Linux设备驱动编程中,上层容器是一种将相似类型的设备驱动封装在一起的机制。
它提供了一组通用的接口和方法,使得用户可以通过统一的方式来访问不同类型的设备。
上层容器将底层设备驱动程序的复杂性隐藏在内部,让用户只需要关注上层容器提供的接口即可。
上层容器还提供了一些额外的功能,如设备发现、设备管理和事件处理等。
通过这些功能,用户可以更方便地操作设备,并处理设备可能出现的异常情况。
上层容器的工作原理上层容器的工作原理可以简单地分为以下几个步骤:1.注册设备驱动程序:用户首先需要注册自己的设备驱动程序,以便上层容器能够识别和加载相关的驱动代码。
通常,用户需要提供一个设备描述符和一组设备操作函数,用于定义设备的属性和行为。
2.创建设备:在设备驱动程序注册成功后,上层容器会根据设备描述符来创建一个对应的设备对象。
该设备对象包含了设备的所有属性和状态,以及与之相关的一些操作方法。
3.绑定设备和驱动:将设备对象与对应的驱动程序进行绑定,以建立它们之间的关联关系。
这样,当上层容器收到用户的操作请求时,它可以根据绑定关系找到对应的设备对象,并调用相应的设备操作函数来处理请求。
4.设备访问和操作:用户可以通过上层容器提供的接口来访问和操作设备。
上层容器会处理用户发送的操作请求,并通过驱动程序调用相应的设备操作函数来执行相应的操作。
5.设备管理和事件处理:上层容器还提供了一些管理和处理设备的功能。
例如,它可以监测设备的状态变化,并在发生异常情况时进行相应的处理。
另外,上层容器还可以为设备注册一些事件回调函数,以处理设备可能产生的事件。
上层容器的常见用途上层容器在Linux设备驱动编程中有着广泛的应用。
linux内核sysfs详解【转】
![linux内核sysfs详解【转】](https://img.taocdn.com/s3/m/e28a22210166f5335a8102d276a20029bd646330.png)
linux内核sysfs详解【转】转⾃:"sysfs is a ram-based filesystem initially based on ramfs. It provides a meansto export kernel data structures, their attributes, and the linkages between them touserspace.” --- documentation/filesystems/sysfs.txt可以先把documentation/filesystems/sysfs.txt读⼀遍。
⽂档这种东西,真正读起来就嫌少了。
Sysfs⽂件系统是⼀个类似于proc⽂件系统的特殊⽂件系统,⽤于将系统中的设备组织成层次结构,并向⽤户模式程序提供详细的内核数据结构信息。
去/sys看⼀看,localhost:/sys#ls /sys/block/ bus/ class/ devices/ firmware/ kernel/ module/ power/Block⽬录:包含所有的块设备Devices⽬录:包含系统所有的设备,并根据设备挂接的总线类型组织成层次结构Bus⽬录:包含系统中所有的总线类型Drivers⽬录:包括内核中所有已注册的设备驱动程序Class⽬录:系统中的设备类型(如⽹卡设备,声卡设备等)sys下⾯的⽬录和⽂件反映了整台机器的系统状况。
⽐如bus,localhost:/sys/bus#lsi2c/ ide/ pci/ pci express/ platform/ pnp/ scsi/ serio/ usb/⾥⾯就包含了系统⽤到的⼀系列总线,⽐如pci, ide, scsi, usb等等。
⽐如你可以在usb⽂件夹中发现你使⽤的U盘,USB⿏标的信息。
我们要讨论⼀个⽂件系统,⾸先要知道这个⽂件系统的信息来源在哪⾥。
所谓信息来源是指⽂件组织存放的地点。
Linux容器技术的基本原理与应用
![Linux容器技术的基本原理与应用](https://img.taocdn.com/s3/m/93e0c57766ec102de2bd960590c69ec3d5bbdbae.png)
Linux容器技术的基本原理与应用在计算机科学领域,容器化技术是一种通过虚拟化技术来实现操作系统层级的隔离的方法。
其中,Linux容器技术是目前应用最广泛的一种容器化技术,在本文中,我们将探讨Linux容器技术的基本原理与应用。
一、基本原理Linux容器技术的基本原理包括命名空间、控制组和联合文件系统。
1. 命名空间(Namespace)命名空间是Linux容器技术实现隔离的基础,它允许进程在一个隔离的环境中运行,这个环境与其他命名空间中的进程相互隔离。
Linux内核提供了多个不同类型的命名空间,例如进程命名空间、网络命名空间、文件系统命名空间等。
每个命名空间可以将进程和资源限制在自己的范围内,避免了进程之间的干扰和冲突。
2. 控制组(Cgroup)控制组是Linux容器技术用于分配和控制资源的机制,它能将进程组织成一个树状结构,并对其资源使用进行限制。
通过控制组,可以对CPU、内存、磁盘IO等资源进行精细化的控制和分配,确保容器所需的资源得到合理分配和使用。
3. 联合文件系统(UnionFS)联合文件系统是Linux容器技术中常用的文件系统,它通过将多个文件系统挂载到同一个目录下,使得这些文件系统的内容像透明地合并到了一起。
这样,每个容器就可以拥有自己的文件系统结构,而不必创建和维护完整的独立文件系统。
联合文件系统大大减小了容器的磁盘空间开销。
二、应用场景Linux容器技术由于其高效、轻量级和灵活的特性,被广泛应用于各个领域。
以下是几个常见的应用场景。
1. 云计算平台云计算平台需要隔离多个租户之间的资源,保证每个租户都能独立运行和管理自己的应用程序。
使用Linux容器技术可以实现虚拟化隔离,提供灵活的资源分配和管理机制,从而满足不同租户的需求。
2. 微服务架构微服务架构将复杂的应用程序拆分为多个独立的服务,每个服务负责一个特定的功能。
通过使用Linux容器技术,可以将每个服务部署在独立的容器中,实现服务之间的隔离,提高系统的可扩展性和可维护性。
linux virtio原理
![linux virtio原理](https://img.taocdn.com/s3/m/d01fbb40591b6bd97f192279168884868662b86e.png)
linux virtio原理Linux virtio是一种在虚拟化环境中使用的设备驱动模型,它旨在提供高性能和低延迟的I/O操作。
本文将详细介绍virtio的原理及其在Linux系统中的应用。
一、virtio的原理1. 设备模型:virtio将虚拟设备分为前端和后端两部分。
前端设备运行在虚拟机中,后端设备运行在宿主机上。
两者之间通过virtio驱动进行通信。
2. 驱动模型:virtio驱动是一个通用的设备驱动框架,它提供了一组标准的设备接口,包括设备初始化、I/O操作和中断处理等。
驱动程序通过这些接口与前端设备进行通信。
3. 通信机制:virtio使用共享内存和事件通知机制实现前后端设备之间的高效通信。
前端设备将数据写入共享内存缓冲区,并通过事件通知机制通知后端设备。
后端设备读取共享内存中的数据,并进行相应的处理。
4. I/O虚拟化:virtio支持多种设备类型的虚拟化,包括网络设备、磁盘设备和图形设备等。
通过虚拟化技术,virtio可以将物理设备的功能在虚拟机中进行模拟,实现对虚拟机的透明访问。
二、virtio在Linux系统中的应用1. 网络虚拟化:virtio-net是virtio的网络设备驱动,它提供了高性能的网络虚拟化功能。
通过virtio-net驱动,虚拟机可以直接访问物理网络,实现与宿主机的高速数据传输。
2. 块设备虚拟化:virtio-blk是virtio的块设备驱动,它可以将宿主机上的块设备映射到虚拟机中,实现对虚拟机的块设备访问。
通过virtio-blk驱动,虚拟机可以实现高性能的块设备I/O操作。
3. 图形虚拟化:virtio-gpu是virtio的图形设备驱动,它可以将宿主机上的图形设备映射到虚拟机中,实现对虚拟机的图形输出。
通过virtio-gpu驱动,虚拟机可以实现高性能的图形渲染和显示。
三、结语virtio作为一种高性能的设备驱动模型,在虚拟化环境中得到了广泛的应用。
Linux设备模型浅析之设备篇
![Linux设备模型浅析之设备篇](https://img.taocdn.com/s3/m/cbe7d263f5335a8102d220c8.png)
Linux设备模型浅析之设备篇本文属本人原创,欢转载,转载请注明出处。
由于个人的见识和能力有限,不可能面面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是yzq.seen@,博客是。
Linux设备模型,仅仅看理论介绍,比如LDD3的第十四章,会感觉太抽象不易理解,而通过阅读内核代码就更具体更易理解,所以结合理论介绍和内核代码阅读能够更快速的理解掌握linux设备模型。
这一序列的文章的目的就是在于此,看这些文章之前最好能够仔细阅读LDD3的第十四章。
大部分device和driver都被包含在一个特定bus中,platform_device和platform_driver就是如此,包含在platform_bus_type中。
这里就以对platform_bus_type的调用为主线,浅析platform_device的注册过程,从而理解linux设备模型。
platform_bus_type用于关联SOC的platform device和platform driver,比如在内核linux-2.6.29中所有S3C2410中的platform device都保存在devs.c中。
这里就以S3C2410 RTC为例。
在文章的最后贴有一张针对本例的device model图片,可在阅读本文章的时候作为参照。
一、S3C2410 RTC的platform device定义在arch/arm/plat-s3c24xx/devs.c中,如下:static struct resource s3c_rtc_resource[] = {[0] = {.start = S3C24XX_PA_RTC,.end = S3C24XX_PA_RTC + 0xff,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_RTC,.end = IRQ_RTC,.flags = IORESOURCE_IRQ,},[2] = {.start = IRQ_TICK,.end = IRQ_TICK,.flags = IORESOURCE_IRQ}};struct platform_device s3c_device_rtc = {.name = "s3c2410-rtc",.id = -1,.num_resources = ARRAY_SIZE(s3c_rtc_resource),.resource = s3c_rtc_resource,};把它们添加在arch/arm/mach-s3c2440/ mach- smdk2440.c中,如下:static struct platform_device *smdk2440_devices[] __initdata = {&s3c_device_usb,&s3c_device_lcd,&s3c_device_wdt,&s3c_device_i2c0,&s3c_device_iis,& s3c_device_rtc};系统初始化的时候会调用drivers/base/platform.c里的platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices))将其注册到platform_bus_type,最终被添加到device hierarchy 。
网络驱动程序
![网络驱动程序](https://img.taocdn.com/s3/m/15f5079733d4b14e852468c6.png)
网络设备与媒介层
网络设备与媒介层直接对应于实际的硬件设备,我们可以定义一组宏和 一组访问设备内部寄存器的函数,具体的宏和函数与特定的硬件紧密相 关。
/*寄存器定义*/ #define DATA_REG 0x0004 #define CMD_REG 0x0008 /*寄存器读写函数*/ static u16 xxx_readword(u32 base_addr,int portno) {
• 设备驱动功能层各函数是网络设备接口层net_device数据结构的具体成员, 是驱使网络设备硬件完成相应动作的程序,它通过hard_start_xmit()函数启 动发送操作,并通过网络设备上的中断触发接收操作。
•网络设备与媒介层是完成数据包发送和接收的物理实体,包括网络适配器和 具体的传输媒介。
假设以太网适配器收到一个UDP数据包,Linux从底层到应用层处理 这一数据包的流程如下:
网卡收到一个UDP包后,驱动程序需要创建一个sk_buff结构体 和数据缓冲区,将收到的数据全部复制到data指向的空间,此 时,有效数据的开始位置是一个链路层的以太网头。
Linux之容器命令
![Linux之容器命令](https://img.taocdn.com/s3/m/598af627cec789eb172ded630b1c59eef8c79ac9.png)
Linux之容器命令启动镜像
docker run [可选参数] image
# 参数说明
--name = "Name" 容器名称 tomcat01、tomcat02、再来区分容器
-d 后台运⾏⽅式
-it 使⽤交互⽅式运⾏,进⼊容器查看内容
-p 指定容器的端⼝, -p 8080:8080
-p ip:主机端⼝:容器端⼝
-p 主机端⼝:容器端⼝(常⽤)
-p 容器端⼝
容器端⼝
-P 随机指定端⼝
# 测试并进⼊容器
docker run -it centos /bin/bash
# 从容器内退出主机
exit
列出所有运⾏的容器
# docker ps 命令
# 列出当前正在运⾏的容器
-a # 列出当前正在运⾏的容器+历史运⾏的容器
-n=? # 显⽰最近创建的容器
-q # 只显⽰容器的编号
-aq # 所有所有容器的编号
退出容器
exit # 直接停⽌容器并退出
Ctrl+P+Q # 容器不停⽌退出
删除容器
docker rm 容器id # 删除指定的容器,不能删除正在运⾏的容器,如果要强制删除,使⽤rm -f docker rm -f $(docker ps -aq) # 删除所有的容器
docker ps -a -q|xargs docker rm # 删除所有的容器
启动/停⽌容器
docker start 容器id # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停⽌容器
docker kill 容器id # 强制停⽌当前容器。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、总线(bus)
总线是CPU与外设之间的通道。在设备模型中,所有的设备都通过总线相连。用bus_type结构表示总线( <linux/device.h> ):
struct bus_type {
const char *name;//总线名,显示在/sysfs/bus/目录下,如/sysfs/bus/i2c
初始化总线上的驱动链表,并且不提供通过总线引用和释放该链表上的驱动
klist_init(&priv->klist_drivers, NULL, NULL);
最后为总线添加属性,如果成功添加,则在/sysfs/bus/xxx/目录下创建相应的属性文件。如果bus->bus_attrs为空(如i2c_bus_type),则不进行任何操作
首先,分配bus_type对应的私有数据结构
struct bus_type_private *priv;
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
将私有数据结构和bus_type对应起来
priv->bus = bus;
int (*resume_early)(struct device *dev);
int (*resume)(struct device *dev);
struct dev_pm_ops *pm;//电源管理接口,这里不讨论
struct bus_type_private *p;//总线的私有数据,定义于driver/base/base.h
记得刚工作的时候,当时为了查证一个I2C的问题,硬着头皮跟了一下Linux下i2c总线的驱动代码,两个字:吐血。主要是跟着跟着就跟到了Linux设备驱动模型的核心里去了,这里面数据结构复杂,函数调用的关系跟着跟着就不知道哪对哪了。归根结底,没仔细阅读过Linux设备驱动模型的核心代码,我想只要理解了这部分内容,上层的一些总线驱动比如i2c、spi、platform等等都将会变得简单。于是,狠下心来好好研究一下Linux设备驱动的核心代码。虽然很困难,但是贵在尝试,贵在坚持。
void *data, int (*fn)(struct device_driver *, void *));
该函数和bus_for_each_dev类似,只不过它操作的对象是device_driver而已。总线上的所有设备均挂接在bus->p->klist_drivers链表。
static int __init i2c_init(void)
{
int retval;
retval = bus_register(&i2c_bus_type);
......
}
在调用bus_register(&i2c_bus_type)之后,将会在/sysfs/bus下看到i2c目录,在/sysfs/bus/i2c目录下看到devices和drivers目录。下面简单跟一下bus_register的源码(不考虑操作失败的情况):
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*suspend_late)(struct device *dev, pm_message_t state);
retval = bus_add_attrs(bus);
2、总线的方法
在bus_type结构中定义了许多方法,这些方法允许总线核心作为中间介质,在设备核心与驱动程序之间提供服务。目前,我们主要讨论其中的match方法,如果有需要,以后再添加其他方法的讨论:
int (*match)(struct device *dev, struct device_driver *drv);
priv->drivers_kset = kset_create_and_add("drivers", NULL,&priv->subsys.kobj);
初始化总线上的设备链表,并且把引用和释放该链表上的设备分别交由klist_devices_get和klist_devices_put函数负责
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
......
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *driver_data; /* data private to the driver */
struct bus_attribute *bus_attrs;//总线的缺省属性
struct device_attribute *dev_attrs;//总线上设备的缺省属性
struct driver_attribute *drv_attrs;//总线上挂接的驱动的缺省属性
//以下是总线的方法
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
......
}
不清楚将bus_kset当成/sysfs/bus目录,而priv->subsys当成/sysfs/bus/xxx(如/sysfs/bus/i2c)目录是否更容易理解其中的层次关系?
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);
下面代码段的成功执行将在/sysfs/bus/xxx/目录下增加drivers目录,挂在xxx总线上的所有驱动也应该都会在/sysfs/bus/xxx/drivers目录下出现?(符号链接?)
二、设备(device)
在底层,一个device结构代表一个设备:
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
struct bus_type *bus;//指向与之关联的bus_type
};
1、总线的注册
函数bus_register用来向系统注册一个总线:int bus_register(struct bus_type *bus);
以i2c总线为例,看看内核如何注册i2c总线的。首先,要准备名为“i2c”的bus_type结构:
/* drivers\i2c\i2c-core.c */
struct bus_type i2c_bus_type = {
.name = "i2c",
.dev_attrs = i2c_dev_attrs,
/* 以下暂时省略总线的方法 */
};
然后调用bus_register来注册i2c总线:
};
struct bus_type_private {
struct kset subsys;//代表该总线的kset
struct kset *drivers_kset;//挂接在该总线上的驱动的kset,如/sysfs/bus/i2c/drivers
struct kset *devices_kset;//挂载在该总线上的设备的kset,如/sysfs/bus/i2c/devices
当一个总线上的新设备或者新驱动被添加时,会一次或者多次调用这个函数,用来“匹配”总线上的设备和驱动。
3、总线上的一些基本操作
int bus_for_each_dev(struct bus_type *bus, struct device *start,void *data, int (*fn)(struct device *, void *));
该函数迭代了总线上的每个设备,将相关的device结构传递给函数fn,同时传递data值。如果start是NULL,将从总线上的第一个设备开始迭代;否则将从start后的第一个设备开始迭代。总线上的所有设备均挂接在bus->p->klist_devices链表。
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
......
retval = kset_register(&priv->subsys);
创建总线的属性文件,这些文件将显示在/sysfs/bus/xxx/目录下,有关热插拔的东东,我就先直接忽略了,以后再看吧
retval = bus_create_file(bus, &bus_attr_uevent);
下面代码段的成功执行将在/sysfs/bus/xxx/目录下增加devices目录,想象一下,挂在xxx总线上的所有设备应该都会在/sysfs/bus/xxx/devices目录下出现?(符号链接?)