Linux设备驱动模型分析

合集下载

linux内核部件分析-设备驱动模型之driver

linux内核部件分析-设备驱动模型之driver

上节我们分析设备驱动模型中的device,主要是drivers/base/core.c,可以说是代码量最大的一个文件。

本节要分析的驱动driver,就要相对简单很多。

原因也很简单,对于driver,我们能定义的公共部分实在不多,能再sysfs中表达的也很少。

本节的分析将围绕drivers/base/driver.c,但头文件仍然是include/linux/device.h和drivers/base/base.h。

先让我们来看看driver的结构。

[cpp]view plaincopyprint?1.struct device_driver {2.const char *name;3.struct bus_type *bus;4.5.struct module *owner;6.const char *mod_name; /* used for built-in modules */7.8.bool suppress_bind_attrs; /* disables bind/unbind via sysfs */9.10.int (*probe) (struct device *dev);11.int (*remove) (struct device *dev);12.void (*shutdown) (struct device *dev);13.int (*suspend) (struct device *dev, pm_message_t state);14.int (*resume) (struct device *dev);15.const struct attribute_group **groups;16.17.const struct dev_pm_ops *pm;18.19.struct driver_private *p;20.};struct device_driver就是模型定义的通用驱动结构。

LINUX设备驱动程序(4)

LINUX设备驱动程序(4)

协议简介
对于网络的正式介绍一般都采用 OSI (Open Systems Interconnection)模型, 但是Linux 中网络栈的介绍一般分为四层的 Internet 模型。
协议栈层次对比
OSI七层网络模型 应用层 表示层 会话层 传输层 网络层
数据链路层 物理层
Linux TCP/IP 四层概念模型
网络协议
网络协议层用于实现各种具体的网络协议, 如: TCP、UDP 等。
设备无关接口
设备无关接口将协议与各种网络设备驱动连接在一起。 这一层提供一组通用函数供底层网络设备驱动程序使用,让 它们可以对高层协议栈进行操作。
首先,设备驱动程序可能会通过调用 register_netdevice 或 unregister_netdevice 在内核中 进行注册或注销。调用者首先填写 net_device 结构,然后 传递这个结构进行注册。内核调用它的 init 函数(如果定义 了这种函数),然后执行一组健全性检查,并将新设备添加 到设备列表中(内核中的活动设备链表)。
驱动程序
网络栈底部是负责 管理物理网络设备 的设备驱动程序。
第二节 网卡驱动程序设计
设备注册
设备描述:
每个网络接口都由一个 net_device结构来描述
注册: 网络接口驱动的注册方式与字符驱动不同之处在于 它没有主次设备号,并使用如下函数注册。
int register_netdev(struct net_device *dev)
Linux网络子系统架构
Linux协议架构
Linux 网络子系统的顶部是系统调用接口。它为用 户空间的应用程序提供了一种访问内核网络子系统 的方法。位于其下面的是一个协议无关层,它提供 了一种通用方法来使用传输层协议。然后是具体协 议的实现,在 Linux 中包括内嵌的协议 TCP、 UDP,当然还有 IP。然后是设备无关层,它提供了 协议与设备驱动通信的通用接口,最下面是设备驱 动程序。

Linux设备模型 热插拔、mdev 与 firmware

Linux设备模型 热插拔、mdev 与 firmware

Linux设备驱动程序学习(15)-Linux设备模型(热插拔、mdev 与firmware)热插拔有2 个不同角度来看待热插拔:从内核角度看,热插拔是在硬件、内核和内核驱动之间的交互。

从用户角度看,热插拔是内核和用户空间之间,通过调用用户空间程序(如hotplug、udev 和mdev)的交互。

当需要通知用户内核发生了某种热插拔事件时,内核才调用这个用户空间程序。

现在的计算机系统,要求Linux 内核能够在硬件从系统中增删时,可靠稳定地运行。

这就对设备驱动作者增加了压力,因为在他们必须处理一个毫无征兆地突然出现或消失的设备。

热插拔工具当用户向系统添加或删除设备时,内核会产生一个热插拔事件,并在/proc/sys/kernel/hotplug文件里查找处理设备连接的用户空间程序。

这个用户空间程序主要有hotplug:这个程序是一个典型的bash 脚本,只传递执行权给一系列位于/etc/hot-plug.d/ 目录树的程序。

hotplug 脚本搜索所有的有 .hotplug 后缀的可能对这个事件进行处理的程序并调用它们, 并传递给它们许多不同的已经被内核设置的环境变量。

(基本已被淘汰,具体内容请参阅《LDD3》)udev :用于linux2.6.13或更高版本的内核上,为用户空间提供使用固定设备名的动态/dev目录的解决方案。

它通过在sysfs 的/class/ 和/block/ 目录树中查找一个称为dev 的文件,以确定所创建的设备节点文件的主次设备号。

所以要使用udev,驱动必须为设备在sysfs中创建类接口及其dev属性文件,方法和sculld模块中创建dev属性相同。

udev的资料网上十分丰富,我就不在这废话了,给出以下链接有兴趣的自己研究:mdev:一个简化版的udev,是busybox所带的程序,十分适合嵌入式系统。

因为hotplug现在也在被慢慢地淘汰,udev不再依赖hotplug了,所以这里不再介绍;udev较mdev复杂,不太适合嵌入式使用。

linux驱动21页PPT

linux驱动21页PPT
内核和网络驱动程序间的通讯完全不同于内核和字符设备以及 块设备驱动程序之间的通信,内核调用一套和数据包传输相关 的函数。
设备文件和设备驱动
设备文件和设备驱动
设备文件是文件系统上的一个 节点,是一种特殊的文件,叫 做设备文件。每个设备文件在 用户空间代表了一个设备。
设备文件一般存在/dev目录下, 用mknod命令创建。
/proc/ioports:查看设备的IO端口。 /proc/interrupts:查看正在使用的中断号。
构造和运行模块
Kernel Module的特点
模块只是预先注册自己以便服务于将来的某个请求,然后就立即 结束。
模块可以是实现驱动程序,文件系统,或者其他功能。 加载模块后,模块运行在内核空间,和内核链接为一体。
#include <linux/module.h>
int init_module(void) {
printk("<1>Hello, world\n"); return 0; } void cleanup_module(void) { printk("<1>Goodbye world\n"); }
简单的内核模块例子(2)
SUMMER TEMPLATE
linux驱动
Linux Kernel 系统架构图
设备驱动程序简介
驱动程序的特点
是应用和硬件设备之间的一个软件层 。
这个软件层一般在内核中实现
设备驱动程序的作用在于提供机制,而不是提供策略, 编写访问硬件的内核代码时不要给用户强加任何策略
○ 机制:驱动程序能实现什么功能。
1version>/modules.dep文件,其中<kernel version>

LINUX设备驱动开发详解

LINUX设备驱动开发详解

LINUX设备驱动开发详解概述LINUX设备驱动开发是一项非常重要的任务,它使得硬件设备能够与操作系统进行有效地交互。

本文将详细介绍LINUX设备驱动开发的基本概念、流程和常用工具,帮助读者了解设备驱动开发的要点和技巧。

设备驱动的基本概念设备驱动是连接硬件设备和操作系统的桥梁,它负责处理硬件设备的输入和输出,并提供相应的接口供操作系统调用。

设备驱动一般由设备驱动程序和设备配置信息组成。

设备驱动程序是编写解决设备驱动的代码,它负责完成设备初始化、IO操作、中断处理、设备状态管理等任务。

设备驱动程序一般由C语言编写,使用Linux内核提供的API函数进行开发。

设备配置信息是定义硬件设备的相关参数和寄存器配置的文件,它告诉操作系统如何与硬件设备进行交互。

设备配置信息一般以设备树或者直接编码在设备驱动程序中。

设备驱动的开发流程设备驱动的开发流程包括设备初始化、设备注册、设备操作函数编写和设备驱动注册等几个主要步骤。

下面将详细介绍这些步骤。

设备初始化设备初始化是设备驱动开发的第一步,它包括硬件初始化和内存分配两个主要任务。

硬件初始化是对硬件设备进行基本的初始化工作,包括寄存器配置、中断初始化等。

通过操作设备的寄存器,将设备设置为所需的状态。

内存分配是为设备驱动程序分配内存空间以便于执行。

在设备初始化阶段,通常需要为设备驱动程序分配一块连续的物理内存空间。

设备注册设备注册是将设备驱动程序与设备对象进行关联的过程,它使得操作系统能够正确地管理设备。

设备注册包括设备号分配、设备文件创建等操作。

设备号是设备在系统中的唯一标识符,通过设备号可以找到设备对象对应的设备驱动程序。

设备号分配通常由操作系统负责,设备驱动程序通过注册函数来获取设备号。

设备文件是用户通过应用程序访问设备的接口,它是操作系统中的一个特殊文件。

设备文件的创建需要通过设备号和驱动程序的注册函数来完成。

设备操作函数编写设备操作函数是设备驱动程序的核心部分,它包括设备打开、设备关闭、读和写等操作。

Linux摄像头驱动学习之:(四)UVC-摄像头驱动框架分析

Linux摄像头驱动学习之:(四)UVC-摄像头驱动框架分析

Linux摄像头驱动学习之:(四)UVC-摄像头驱动框架分析UVC: USB Video ClassUVC驱动:drivers\media\video\uvc\uvc_driver.c分析:1. usb_register(&uvc_driver.driver);2. uvc_probeuvc_register_videovdev = video_device_alloc();vdev->fops = &uvc_fops;video_register_device在下载 uvc specification,UVC 1.5 Class specification.pdf : 有详细描述USB_Video_Example 1.5.pdf : 有⽰例通过VideoControl Interface来控制,通过VideoStreaming Interface来读视频数据,VC⾥含有多个Unit/Terminal等功能模块,可以通过访问这些模块进⾏控制,⽐如调亮度分析UVC驱动调⽤过程:const struct v4l2_file_operations uvc_fops = {.owner = THIS_MODULE,.open = uvc_v4l2_open,.release = uvc_v4l2_release,.ioctl = uvc_v4l2_ioctl,.read = uvc_v4l2_read,.mmap = uvc_v4l2_mmap,.poll = uvc_v4l2_poll,};1. open:uvc_v4l2_open2. VIDIOC_QUERYCAP // video->streaming->type 应该是在设备被枚举时分析描述符时设置的if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)cap->capabilities = V4L2_CAP_VIDEO_CAPTURE| V4L2_CAP_STREAMING;elsecap->capabilities = V4L2_CAP_VIDEO_OUTPUT| V4L2_CAP_STREAMING;3. VIDIOC_ENUM_FMT // format数组应是在设备被枚举时设置的format = &video->streaming->format[fmt->index];4. VIDIOC_G_FMTuvc_v4l2_get_format // USB摄像头⽀持多种格式fromat, 每种格式下有多种frame(⽐如分辨率)struct uvc_format *format = video->streaming->cur_format;struct uvc_frame *frame = video->streaming->cur_frame;5. VIDIOC_TRY_FMTuvc_v4l2_try_format/* Check if the hardware supports the requested format. *//* Find the closest image size. The distance between image sizes is* the size in pixels of the non-overlapping regions between the* requested size and the frame-specified size.*/6. VIDIOC_S_FMT // 只是把参数保存起来,还没有发给USB摄像头uvc_v4l2_set_formatuvc_v4l2_try_formatvideo->streaming->cur_format = format;video->streaming->cur_frame = frame;7. VIDIOC_REQBUFSuvc_alloc_buffersfor (; nbuffers > 0; --nbuffers) {mem = vmalloc_32(nbuffers * bufsize);if (mem != NULL)break;}8. VIDIOC_QUERYBUFuvc_query_buffer__uvc_query_buffermemcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf); // 复制参数9. mmapuvc_v4l2_mmap10. VIDIOC_QBUFuvc_queue_bufferlist_add_tail(&buf->stream, &queue->mainqueue);list_add_tail(&buf->queue, &queue->irqqueue);11. VIDIOC_STREAMONuvc_video_enable(video, 1) // 把所设置的参数发给硬件,然后启动摄像头/* Commit the streaming parameters. */uvc_commit_videouvc_set_video_ctrl /* 设置格式fromat, frame */ret = __uvc_query_ctrl(video->dev /* 哪⼀个USB设备 */, SET_CUR, 0,video->streaming->intfnum /* 哪⼀个接⼝: VS */,probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,uvc_timeout_param);/* 启动:Initialize isochronous/bulk URBs and allocate transfer buffers. */uvc_init_video(video, GFP_KERNEL);uvc_init_video_isoc / uvc_init_video_bulkurb->complete = uvc_video_complete; (收到数据后此函数被调⽤,它⼜调⽤video->decode(urb, video, buf); ==>uvc_video_decode_isoc/uvc_video_encode_bulk => uvc_queue_next_buffer => wake_up(&buf->wait);)usb_submit_urb12. polluvc_v4l2_polluvc_queue_pollpoll_wait(file, &buf->wait, wait); // 休眠等待有数据13. VIDIOC_DQBUFuvc_dequeue_bufferlist_del(&buf->stream);14. VIDIOC_STREAMOFFuvc_video_enable(video, 0);usb_kill_urb(urb);usb_free_urb(urb);分析设置亮度过程:ioctl: VIDIOC_S_CTRLuvc_ctrl_setuvc_ctrl_commit__uvc_ctrl_commit(video, 0);uvc_ctrl_commit_entity(video->dev, entity, rollback);ret = uvc_query_ctrl(dev /* 哪⼀个USB设备 */, SET_CUR, ctrl->entity->id /* 哪⼀个unit/terminal */,dev->intfnum /* 哪⼀个接⼝: VC interface */, ctrl->info->selector,uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),ctrl->info->size);总结:1. UVC设备有2个interface: VideoControl Interface, VideoStreaming Interface2. VideoControl Interface⽤于控制,⽐如设置亮度。

Linux的驱动开发分析

Linux的驱动开发分析

f o r ( 1 e f t= c o u n t :l e f t>O :l e f t 一 _ ) {
. .
p u t u s e r ( 1 ,b u r ,1 ) ;

2 驱 动程 序原 理
编写设备 驱动程序 的原 理即基于I / O 设备管理 采用的分层 模 型, l / 0 设备 管理 软件位于 内核 中的最底层 , 设备驱动程 序是

r e a ( V E R I F YW i f ( v e r i f ya R I T E , b u r , c o u n t ) ==
— —
E F A U L T)
r e t u r n — E F A U L T ;
性 能得到提高 。 许 多广泛应 用的嵌入 式L i n u x 系 统都 采用静态 链接 的设备驱动程序模块。
( 1 ) 工作原理 。 作为内核 的一部分, 设各驱动程 序完 成对 设
据、 读 取应用程序传 送给设备文件 的数 据和 回送应用程 序请求 的数据和 检测处理设备 出现 的错 误的功能。 L i n u x 设备主要分
s t a t i c i n t o p e n
{ i n t l e f t :
化, 尽可能地精简。 嵌入 式L i n u x 系统不能够像桌面L i n u x  ̄ g 样
灵活 地使 用i n s m o d / r m m o d 力 口 载卸载设备驱 动程序 。 从嵌 入式 系统 的整 体性能考虑 , 采用静态链接模块能够使得整 个系统 的
设计分析 ・
L i n u x 的驱动开发分析
姜远志 ( 太原师范 学院 , 山 西 太原 0 3 0 0 0 0 )

总线设备驱动

总线设备驱动

linux内核学习---总线,设备,驱动Linux 设备模型中三个很重要的概念就是总线,设备,驱动.即 bus,device,driver,而实际上内核中也定义了这么一些数据结构,他们是 struct bus_type,struct device,struct device_driver,这三个重要的数据结构都来自一个地方,include/linux/device.h.我们知道总线有很多种,pci总线,scsi 总线,usb 总线,所以我们会看到Linux 内核代码中出现pci_bus_type,scsi_bus_type,usb_bus_type,他们都是 struct bus_type 类型的变量.而struct bus_type 结构中两个非常重要的成员就是 struct kset drivers 和 struct kset devices。

kset 和另一个叫做 kobject 正是 Linux Kernel 2.6 中设备模型的基本元素。

这里我们只需要知道,drivers 和 devices 的存在,让struct bus_type 与两个链表联系了起来,一个是devices 的链表,一个是 drivers 的链表,也就是说,知道一条总线所对应的数据结构,就可以找到这条总线所关联的设备有哪些,又有哪些支持这类设备的驱动程序.而要实现这些,就要求每次出现一个设备就要向总线汇报,或者说注册,每次出现一个驱动,也要向总线汇报,或者说注册.比如系统初始化的时候,会扫描连接了哪些设备,并为每一个设备建立起一个 struct device 的变量,每一次有一个驱动程序,就要准备一个 struct device_driver 结构的变量.把这些变量统统加入相应的链表,device 插入 devices 链表,driver 插入 drivers 链表. 这样通过总线就能找到每一个设备,每一个驱动。

struct bus_type 中为 devices 和 drivers 准备了两个链表,而代表 device 的结构体 struct device 中又有两个成员,struct bus_type *bus 和 struct device_driver *driver。

【原创】LinuxPCI驱动框架分析(一)

【原创】LinuxPCI驱动框架分析(一)

【原创】LinuxPCI驱动框架分析(一)背景•Read the fucking source code! --By 鲁迅•A picture is worth a thousand words. --By 高尔基说明:1.Kernel版本:4.142.ARM64处理器3.使用工具:Source Insight 3.5, Visio1. 概述从本文开始,将会针对PCIe专题来展开,涉及的内容包括:1.PCI/PCIe总线硬件;2.Linux PCI驱动核心框架;3.Linux PCI Host控制器驱动;不排除会包含PCIe外设驱动模块,一切随缘。

作为专题的第一篇,当然会先从硬件总线入手。

进入主题前,先讲点背景知识。

在PC时代,随着处理器的发展,经历了几代I/O总线的发展,解决的问题都是CPU主频提升与外部设备访问速度的问题:1.第一代总线包含ISA、EISA、VESA和Micro Channel等;2.第二代总线包含PCI、AGP、PCI-X等;3.第三代总线包含PCIe、mPCIe、m.2等;PCIe(PCI Express)是目前PC和嵌入式系统中最常用的高速总线,PCIe在PCI的基础上发展而来,在软件上PCIe与PCI是后向兼容的,PCI的系统软件可以用在PCIe系统中。

本文会分两部分展开,先介绍PCI总线,然后再介绍PCIe总线,方便在理解上的过渡,开始旅程吧。

2. PCI Local Bus2.1 PCI总线组成•PCI总线(Peripheral Component Interconnect,外部设备互联),由Intel公司提出,其主要功能是连接外部设备;•PCI Local Bus,PCI局部总线,局部总线技术是PC体系结构发展的一次变革,是在ISA总线和CPU总线之间增加的一级总线或管理层,可将一些高速外设,如图形卡、硬盘控制器等从ISA总线上卸下,而通过局部总线直接挂接在CPU总线上,使之与高速CPU总线相匹配。

(转)Linux设备驱动之HID驱动源码分析

(转)Linux设备驱动之HID驱动源码分析

(转)Linux设备驱动之HID驱动源码分析//Linux设备驱动之HID驱动源码分析HID是Human Interface Devices的缩写.翻译成中⽂即为⼈机交互设备.这⾥的⼈机交互设备是⼀个宏观上⾯的概念,任何设备,只要符合HID spec,都可以称之为HID设备.常见的HID 设备有⿏标键盘,游戏操纵杆等等.在接下来的代码分析中,可以参考HID的spec.这份spec可以在上找到.分析的代码主要集中在linux-2.6.25/drivers/hid⽬录下.对此设备结点的处理有两种接⼝,⼀种是read(),另⼀种是ioctl();read(): This is the event interface. When the HID device performs an interrupt transfer, indicating a change of state, data will be made available at the associated hiddev device with the content of a struct hiddev_event:struct hiddev_event { unsigned hid; signed int value; };containing the HID usage identifier for the status that changed, and the value that it was changed to.ioctl(): This is the control interface. There are a number of controls:HIDIOCGVERSION int (read)Gets the version code out of the hiddev driver.HIDIOCAPPLICATION(none)This ioctl call returns the HID application usage associated with the hid device. The third argument to ioctl() specifies which application index to get. This is useful when the device has more than one application collection. If the index is invalid (greater or equal to the number of application collections this device has) the ioctl returns -1. You can find out beforehand how many application collections the device has from the num_applications field from the hiddev_devinfo structure.HIDIOCGDEVINFO struct hiddev_devinfo(read)Gets a hiddev_devinfo structure which describes the device.HIDIOCGSTRING struct structhiddev_string_descriptor(read/write)Gets a string descriptor from the device. The caller must fill in the "index" field to indicate which descriptor should bereturned.HIDIOCINITREPORT Instructs the kernel to retrieve all input and feature report values from the device. At this point, all the usage structures will contain current values for the device, and will maintain it as the device changes.HIDIOCGNAME string (variable length)Gets the device nameHIDIOCGREPORT struct hiddev_report_info(write)Instructs the kernel to get a feature or input report from the device, in order to selectively update the usage structures(in contrast to INITREPORT).HIDIOCSREPORT struct hiddev_report_info(write)Instructs the kernel to send a report to the device. This report can be filled in by the userthroughHIDIOCSUSAGE calls (below) to fill in individual usage values in the report before sending the report in full tothe device.HIDIOCGREPORTINFO struct hiddev_report_info(read/write)Fills in a hiddev_report_info structure for the user. The report is looked up by type (input, output or feature) and id, sothese fields must be filled in by the user. The ID can be absolute -- the actual report id as reported by the device -- orrelative -- HID_REPORT_ID_FIRST for the first report, and (HID_REPORT_ID_NEXT | report_id) for the next reportafter report_id. Without a-priori information about report ids, the right way to use this ioctl is to use the relative IDsabove to enumerate the valid IDs. The ioctl returns non-zero when there is no more next ID. The real report ID is filledinto the returned hiddev_report_info structure.HIDIOCGFIELDINFO struct hiddev_field_info(read/write)Returns the field information associated with a report in a hiddev_field_info structure. The user must fill in report_idand report_type in this structure, as above. The field_index should also be filled in, which should be a number from 0and maxfield-1, as returned from a previous HIDIOCGREPORTINFO call.HIDIOCGUCODE struct hiddev_usage_ref(read/write)Returns the usage_code in a hiddev_usage_ref structure, given that given its report type, report id, field index, andindex within the field have already been filled into the structure.HIDIOCGUSAGE struct hiddev_usage_ref(read/write)Returns the value of a usage in a hiddev_usage_ref structure. The usage to be retrieved can be specified as above,or the user can choose to fill in the report_type field and specify the report_id asHID_REPORT_ID_UNKNOWN. Inthis case, the hiddev_usage_ref will be filled in with the report and field infomation associated with this usage if it isfound.HIDIOCSUSAGE struct hiddev_usage_ref(write)Sets the value of a usage in an output report.//利⽤libusb 实现的hid 读写/topics/370027825写⼊⽤usb_interrupt_write读取⽤usb_interrupt_read/acf/article/details/5431488Linux 2.6内核中包含了HID驱动,能够⾃动把USB Key等HID外设识别成“/dev/hiddev0”之类的设备。

linux virtio原理

linux virtio原理

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驱动开发中字符设备模型研究
s 3 c 2 41 0 l e d S
一 — 一
— 一 —
S t a t i C i n t S 3 c 2 4 1 0 l e d 0 p e n( S t r u e t i n o d e * i n o d e ,
s t r u c t f i l e 术 f i 1 p ) {
关键 词 :嵌 入 式 L I NUX; 字符 设 备 模 型 ;设 备 驱 动 程 序
中图分类号 :T P 3 6 8

文献标识码 :A
文章 编号 :
# d e f i n e D E  ̄ I C EN A M E l e d s
_
L l N U X系统 设 备 驱 动 概 念 为 了将一些硬件细 节隐藏,设置 统一的编程接 口,L I N U X 系统采用 了设备驱动形式 ,该驱动形式能够在底层硬件不 同的 情况下 ,把具体 的设备转化为抽象的设备文件 。设备文件只是 驱动访 问的入 口点,不会 占用系统空间,通过设备文件 ,系统 程序可完成对相关设备的各项操作 。在 L I N d X系统中,主要有 三种设备: ( 1 )字符设备 ; ( 2 )块设备 ; ( 3 )网络设备。 二、设备驱动程序的组成 设备初始化 函数是 设备 驱动程序编 写的重点 内容 ,能够 实现 设备的初始化 ,因此可将 设备驱动程序 看作是一组 函数 集 合 。驱 动 加 载 时, 需用 到 入 口 函数 i n i t m o d u l e 0,主 要 负 责结构体赋值及 寄存器置位 等初始化工 作,设备注册是 其
{ s w i t c h( c m d ) {
ca se L ED O N:

s 3 c 2 4 1 0g pi o s e t p i n ( L E D 1 ,L E DO N ) ;

Linux设备模型浅析之设备篇

Linux设备模型浅析之设备篇

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 。

linux网络设备驱动

linux网络设备驱动


网络设备驱动
struct net_device 全局信息 结构 net_device 的第一部分是由下面成员组成: char name[IFNAMSIZ]; 设备名子. 如果名子由驱动设置, 包含一个 %d 格式串, register_netdev 用一个数替换它来形成一个唯一的名子; 分配的编 号从 0 开始. unsigned long state; 设备状态. 这个成员包括几个标志. 驱动正常情况下不直接操作这些 标志; 相反, 提供了一套实用函数. struct net_device *next; 全局列表中指向下一个设备的指针. 这个成员驱动不能动. int (*init)(struct net_device *dev); 一个初始化函数. 如果设置了这个指针, 这个函数被 register_netdev 调用来完成对 net_device 结构的初始化. 大部分现代的网络驱动不 再使用这个函数; 相反, 初始化在注册接口前进行.
网络设备驱动
struct net_device接口信息
unsigned char addr_len; unsigned char broadcast[MAX_ADDR_LEN]; unsigned char dev_addr[MAX_ADDR_LEN]; 硬件 (MAC) 地址长度和设备硬件地址. 以太网地址长度是 6 个字节( 我们指的是接口板的硬件 ID ), 广播地址由 6 个 0xff 字节组成; ether_setup 安排成正确的值. 设备地址, 另外, 必 须以特定于设备的方式从接口板读出, 驱动应当将它拷贝到 dev_addr. 硬件地址用来产生正确的以太网头
void *priv;
Байду номын сангаас

linux SPI 驱动框架源码分析

linux SPI 驱动框架源码分析

SPI协议是一种同步的串行数据连接标准,由摩托罗拉公司命名,可工作于全双工模式。

相关通讯设备可工作于m/s模式。

主设备发起数据帧,允许多个从设备的存在。

每个从设备有独立的片选信号,SPI一般来说是四线串行总线结构。

接口:SCLK——Serial Clock(output from master)时钟(主设备发出)MOSI/SIMO——Master Output, Slave Input(output from master)数据信号线mosi(主设备发出)MISO/SOMI——Master Input,Slave Outpu(output from slave)数据信号线(从设备) SS——Slave Select(active low;output from master)片选信号下面来看一下Linux中的SPI驱动。

在Linux设备驱动框架的设计中,有一个重要的主机,外设驱动框架分离的思想,如下图。

外设a,b,c的驱动与主机控制器A,B,C的驱动不相关,主机控制器驱动不关心外设,而外设驱动也不关心主机,外设只是访问核心层的通用的API进行数据的传输,主机和外设之间可以进行任意的组合。

如果我们不进行如图的主机和外设分离,外设a,b,c和主机A,B,C进行组合的时候,需要9种不同的驱动。

设想一共有个主机控制器,n个外设,分离的结构是需要m+n个驱动,不分离则需要m*n个驱动。

下面介绍spi子系统的数据结构:在Linux中,使用spi_master结构来描述一个SPI主机控制器的驱动。

view plain分配,注册和注销的SPI主机的API由SPI核心提供:view plain在Linux中用spi_driver来描述一个SPI外设驱动。

view plain可以看出,spi_driver结构体和platform_driver结构体有极大的相似性,都有probe(),remove(),suspend(),resume()这样的接口。

spi_driver

spi_driver

linux spi驱动分析整理1、SPI总线:SPI(同步外设接口)是由摩托罗拉公司开发的全双工同步串行总线,其接口由MISO(串行数据输入),MOSI(串行数据输出),SCK(串行移位时钟),SS/CS(从使能信号)四种信号构成(当然了,现在芯片技术日新月异,SPI 模块的结构也在变化中,象OMAP 系列中的SPI 模块还支持 5 线的一种模式),SS /CS决定了唯一的与主设备通信的从设备,主设备通过产生移位时钟来发起通讯。

通讯时,数据由MOSI 输出,MISO 输入,数据在时钟的上升或下降沿由MOSI 输出,在紧接着的下降或上升沿由MISO 读入,这样经过8/16 次时钟的改变,完成8/16 位数据的传输。

SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性(CPOL)和相位(CPHA)可以进行配置。

如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。

如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。

2、LINUX驱动的分层与分离:在面向对象的程序设计中,可以为某一类相似的事物定义一个基类,而具体的事物可以继承这个基类中的函数。

Linux 内核中频繁使用到面向对象的设计思想。

在设备驱动方面,往往为同类的设备设计了一个框架,而框架中的核心层则实现了该设备通用的一些功能。

而且具体的设备不想使用核心层的函数,它可以重载之。

这就是我们所说的在驱动设计中的分层思想。

此外,在驱动的设计中,我们还会使用分离的思想。

如果一个设备的驱动和host 的驱动休戚相关,那么,这就意味着这个普通的设备如果用在不同的host 上,会采用n 个版本的驱动。

如果产品单一,也许感觉不到不使用分离思想来设计驱动的危害,但是我们想一下,这个世上被人们称道的多是什么?精品,艺术品!精品如何打造?注重细节,不只考虑单一需求!大家开发个东西不容易,怎么能随随便便就让它茫然众码矣呢,所以,何时何地,我们都要以打造精品的思想来要求自己,让自己的劳动力不浪费。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
5/20
bus_register(&platform_bus_type) 在/sys/bus/目录下创建bus_name子目录 在/sys/bus/bus_name/目录下创建drivers子目录 在/sys/bus/bus_name/目录下创建devices子目录 在/sys/bus/bus_name/目录下创建uevent文件 在/sys/bus/bus_name/目录下创建drivers_probe文件 在/sys/bus/bus_name/目录下创建drivers_autoprobe文件
};
提醒:变量名字 platform_bus 实为 device{}
int device_add(struct device *dev) //dev:&platform_bus {
struct device *parent = NULL; parent = get_device(dev->parent); struct device_type *type = dev->type; ... ... ;
drivers_kset devices_kset
bus_register(&platform_bus_type):
int bus_register(struct bus_type *bus) //bus:platform_bus_type {
struct bus_type_private *priv; priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); priv->bus = bus; bus->p = priv; ... ... ;
... ... ; for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { //grp: &pm_attr_group; attrs: &power_attrs
sysfs_add_file_mode(... , *attr, SYSFS_KOBJ_ATTR, (*attr)->mode | mode); ... ... ; } }
sys文件系统注册挂载
start_kernel()→vfs_caches_init()→mnt_init()→sysfs_init()
int __init sysfs_init(void) {
register_filesystem(&sysfs_fs_type); kern_mount(&sysfs_fs_type); ... ...; }
};
//设置 priv->subsys.kobj 的名字为 platform
kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //name: "platform"
priv->subsys.kobj.kset = bus_kset; priv->subsys.kobj.ktype = &bus_ktype;
system_bus_init()
在/sys/目录下创建system子目录
system_kset
2/20
device_register(&platform_bus) 在/sys/devices/目录下创建platform子目录 在/sys/devices/platform/目录下创建uevent文件 在/sys/devices/platform/目录下创建power子目录 在/sys/devices/platform/目录下创建control、wakeup文件
struct bus_type platform_bus_type = { .name = "platform", .dev_attrs = platform_dev_attrs, .match = platform_match, .uevent = platform_uevent, ... ... ,
device_create_file(dev, &uevent_attr); static struct device_attribute uevent_attr =__ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
if (MAJOR(dev->devt)) //dev->devt 无,操作不执行 ... ... ;
3/20
//dev->class 无 且 dev->parent 无,在/sys/devices/目录下创建 platform 目录
kobject_add(&dev->kobj, dev->kobj.parent, NULL);
//在/sys/devices/platform/目录下创建 uevent 属性文件
//确定 device 在/sys/device/.../中所处位置的算法思想 设备:dev
① 设备组 父设备:dev->parent
名词定义: 设备类:dev->class
② 类组 父设备类:dev->parent->class
算法思想:dev 必有,利用 dev->parent、dev->class、dev->parent->class 来计算设备所处 sysfs 文件中的位置。
//创建/sys/bus/platform 目录
kset_register(&priv->subsys);
//创建/sys/bus/platform/uevent 属性文件
bus_create_file(bus, &bus_attr_uevent);
//创建/sys/bus/platform/devices 目录
};
static struct attribute * power_attrs[] = { &dev_attr_control.attr, &dev_attr_wakeup.attr,
};
int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp) {
create_files(... , kobj, grp, ...);
4/20
... ... ; } int sysfs_create_subdir(struct kobject *kobj, const char *name, ...) {
create_dir(kobj, ... , name, ...); } static int create_files(... , struct kobject *kobj, const struct attribute_group *grp, ...) {
在/sys/dev/目录下创建char子目录
sysfs_dev_char_kobj
buses_init()
在/sys/目录下创建bus子目录
bus_kset
classes_init()
在/sys/目录下创建class子目录
class_kset
firmware_init()
在/sys/目录下创建firmware子目录
//在/sys/devices/platform/目录下创建 power 目录,并在 power 目录下创建 power_attrs 属性文件,包括 control、wakeup
sysfs_create_group(&dev->kobj, &pm_attr_group);
... ... ;
} }
static struct attribute_group pm_attr_group = { .name = "power", .attrs = power_attrs,
device_register(&platform_bus):
int device_register(struct device *dev) {
device_initialize(dev); device_add(dev); }
struct device platform_bus = { .init_name = "platform",
driver_init()
devtmpfs_init()
创建devtmpfs文件系统
devices_init()
在/sys/目录下创建devices子目录
devices_kset
在/sys/目录下创建dev子目录
dev_kobj
在/sys/dev/目录下创建block子目录
sysfs_dev_block_kobj
internal_create_group(kobj, ... , grp); }
static int internal_create_group(struct kobject *kobj, int update, const struct attribute_group *grp) {
if (grp->name) //name: "power" sysfs_create_subdir(kobj, grp->name, ...);
LK 设备驱动模型之 Base 子系统架构及 sysfs 组织结构
2013 年 1 月 10 日
※要点区:
① Linux驱动下面的base子系统的架构 ② sysfs文件系统的组织结构
相关文档
最新文档