Linux设备驱动模型分析
- 格式:pdf
- 大小:344.79 KB
- 文档页数:20
上节我们分析设备驱动模型中的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设备驱动程序学习(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设备驱动开发详解概述LINUX设备驱动开发是一项非常重要的任务,它使得硬件设备能够与操作系统进行有效地交互。
本文将详细介绍LINUX设备驱动开发的基本概念、流程和常用工具,帮助读者了解设备驱动开发的要点和技巧。
设备驱动的基本概念设备驱动是连接硬件设备和操作系统的桥梁,它负责处理硬件设备的输入和输出,并提供相应的接口供操作系统调用。
设备驱动一般由设备驱动程序和设备配置信息组成。
设备驱动程序是编写解决设备驱动的代码,它负责完成设备初始化、IO操作、中断处理、设备状态管理等任务。
设备驱动程序一般由C语言编写,使用Linux内核提供的API函数进行开发。
设备配置信息是定义硬件设备的相关参数和寄存器配置的文件,它告诉操作系统如何与硬件设备进行交互。
设备配置信息一般以设备树或者直接编码在设备驱动程序中。
设备驱动的开发流程设备驱动的开发流程包括设备初始化、设备注册、设备操作函数编写和设备驱动注册等几个主要步骤。
下面将详细介绍这些步骤。
设备初始化设备初始化是设备驱动开发的第一步,它包括硬件初始化和内存分配两个主要任务。
硬件初始化是对硬件设备进行基本的初始化工作,包括寄存器配置、中断初始化等。
通过操作设备的寄存器,将设备设置为所需的状态。
内存分配是为设备驱动程序分配内存空间以便于执行。
在设备初始化阶段,通常需要为设备驱动程序分配一块连续的物理内存空间。
设备注册设备注册是将设备驱动程序与设备对象进行关联的过程,它使得操作系统能够正确地管理设备。
设备注册包括设备号分配、设备文件创建等操作。
设备号是设备在系统中的唯一标识符,通过设备号可以找到设备对象对应的设备驱动程序。
设备号分配通常由操作系统负责,设备驱动程序通过注册函数来获取设备号。
设备文件是用户通过应用程序访问设备的接口,它是操作系统中的一个特殊文件。
设备文件的创建需要通过设备号和驱动程序的注册函数来完成。
设备操作函数编写设备操作函数是设备驱动程序的核心部分,它包括设备打开、设备关闭、读和写等操作。
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 设备模型中三个很重要的概念就是总线,设备,驱动.即 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驱动框架分析(一)背景•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驱动源码分析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”之类的设备。