![](https://img-blog.csdnimg.cn/20201014180756926.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
驱动
三三不尽
这个作者很懒,什么都没留下…
展开
-
tasklet
softirq是一种基本的底半部机制,有较强的加锁需求。仅仅在一些对性能敏感的子系统(如网络层、SCSI层和内核定时器等)中才会使用softirq。tasklet建立在softirq之上,使用起来更简单。除非有严格的可扩展性和速度要求,都建议使用tasklet。softirq和tasklet的主要不同是前者是可重用的,而后者不是。softirq的是同实例可运行在不同的处理器上,而tasklet的则...原创 2019-03-07 10:22:30 · 278 阅读 · 0 评论 -
工作队列 workqueue
工作队列是内核用于进行延后工作的一种方式。当然驱动模块中使用之前提到的kernel thread就可以完成延后工作了,但是如果每个驱动模块都创建自己的kernel thread,那么内核线程数量过多,这会影响整体的性能。因此,最好的方法就是把这些需求汇集起来,提供一个统一的机制,也就是workqueue了。它的结构是workqueue_struct;和工作队列息息相关的是工作元素work_...原创 2019-03-04 11:23:32 · 452 阅读 · 0 评论 -
中断处理例程
irqreturn_t handler(int irq, void *dev)中断处理例程和其他的c程序代码没有太大的区别,当然它必须准守之前提到的一些规范。中断处理例程的功能就是将有关中断接收的信息反馈给设备,并根据正在服务的中断的不同含义对数据进行相应的读或写。这里可能会涉及到一步清除‘中断标志位’的操作,大多数硬件设备在它们的“interrupt-pending(中断挂起)”位被清...原创 2019-03-06 20:15:01 · 1529 阅读 · 0 评论 -
udev
udev 是Linux kernel 2.6系列的设备管理器。它主要的功能是管理/dev目录底下的设备节点。它同时也是用来接替devfs及热插拔的功能,这意味着它要在添加/删除硬件时处理/dev目录以及所有用户空间的行为,包括加载固件时Linux 2.6.13内核。udev的最新版本依赖于升级后的的uevent接口的最新版本。使用新版本udev的系统不能在2.6.13以下版本启动,除非使用noud...原创 2019-03-08 14:19:09 · 325 阅读 · 0 评论 -
散列链表hlist
struct hlist_head { struct hlist_node *first;};struct hlist_node { struct hlist_node *next, **pprev;};从上面结构可以看到,散列链表对链表头和链表节点有不同的定义。散列链表的头结构只维护了指向链表第一个结点的指针;而散列链表结点则维护了下个结点的指针和一个二级指针。这个二级...原创 2019-03-02 15:37:47 · 351 阅读 · 0 评论 -
中断上下文
中断服务例程(ISR)是直接与硬件交互的非常重要的代码片段。它们拥有立刻执行的特权,以提高系统的性能;对应它们也需要准守一些注意事项,以便整个系统更为有序的运行,具体如下:中断上下文代码绝不可以停止运行(即让出CPU)。中断处理函数不能通过调用schedule_timeout()等睡眠函数放弃处理器,在从中断处理函数中调用一个内核API前,应该仔细分析它,以确保其内部不会触发阻塞等待。例如,i...原创 2019-03-05 15:16:02 · 1060 阅读 · 0 评论 -
初识中断
由于I/O操作的不确定因素以及处理器和I/O设备之间速度的不匹配(I/O设备的速度要比处理器慢很多),设备往往通过某种硬件信号异步地唤醒起处理器的注意。这些硬件信号就是中断。每个中断设备都被分配了一个相关的标识符,被称为中断请求(IRQ)号。当处理器检测到某一IRQ号对应的中断产生时,它将停止现在的工作,并启动该IRQ所对应的中断服务例程(ISR)。中断处理函数在中断上下文执行。模块在使用中断...原创 2019-03-05 14:41:28 · 130 阅读 · 0 评论 -
container_of
container_of(ptr, type, member)是一个非常实用的宏。它的作用是:通过已知结构体type的成员member的地址ptr,获取结构体type的起始地址。源码如下:#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)/** * container_of - cast ...原创 2019-02-26 10:46:05 · 124 阅读 · 0 评论 -
双向链表 list_head
struct list_head { struct list_head *next, *prev;};从结构上看,就是一个简单的双向链表。在<linux/list.h>中定义其相关的操作。主要API简介:函数 作用 INIT_LIST_HEAD() 初始化表头 list_add 在表头后增加一个元素 list_add_tail 在链...原创 2019-03-02 15:05:31 · 550 阅读 · 0 评论 -
softirq、tasklet和工作队列的对比
softirq tasklet 工作队列 执行上下文 延后的工作运行于中断上下文 延后的工作运行于中断上下文 延后的工作运行于进程上下文 可重用 可以在不同的CPU上同时运行 不能在不同的CPU上同时运行,但是不同的CPU可以在运行不同的tasklet 可以在不同的CPU上同时运行 睡眠 不能睡眠 不能睡眠 可...转载 2019-03-07 10:35:13 · 362 阅读 · 0 评论 -
IS_ERR、PTR_ERR、ERR_PTR
#define MAX_ERRNO 4095#ifndef __ASSEMBLY__#define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)static inline void * __must_check ERR_PTR(long error){ re...原创 2019-03-04 16:20:58 · 288 阅读 · 0 评论 -
类的简单使用
类是一个设备的高层视图,它抽象出了底层的实现细节。类允许用户空间使用设备所提供的功能,而不关心设备时如何连接的,以及它们时怎么工作的。几乎所有的类都显示在/sys/class目录中。举个例子,网络接口都集中在/sys/class/net下。结构体:/** * struct class - device classes * @name: Name of the class....原创 2019-03-14 15:26:31 · 286 阅读 · 0 评论 -
SPI总线初探
SPI(Serial Peripheral Interface,串行外围设备接口)总线和I2C类似,也是串行的主-从接口,继承于很多微处理器内部。和I2C使用2线相比,它使用4线:SCLK(Serial CLocK,串行时钟)CS(Chip Select,片选)MOSI(Master Out Slave In, 主设备输出从设备输入)MISO(Master In Slave Out...原创 2019-03-22 11:31:25 · 164 阅读 · 0 评论 -
platform总线的简单使用
Linux从2.6起就加入了一套新的驱动管理和注册的机制platform平台总线,是一条虚拟的总线,设备用platform_device表示,驱动用platform_driver进行注册。相对于USB、PCI、I2C、SPI等物理总线来说,platform总线是一种虚拟、抽象出来的总线,实际中并不存在这样的总线。那为什么需要platform总线呢?其实是Linux设备驱动模型为了保持设备驱动的统一...原创 2019-03-13 11:23:40 · 635 阅读 · 0 评论 -
kset
一个kset是嵌入相同类型结构的kobject集合。因此kset的主要功能包容;我们可以认为它是kobject的顶层容器类。实际上,在每个kset内部,包含了自己的kobject,并且可以用多种处理kobject的方法处理kset。需要注意的是,kset总是在sysfs中出现;一旦设置了kset并把它添加到系统中,将在sysfs中创建一个目录。kobject不必在sysfs中表示,但是kset中的...原创 2019-03-12 16:52:19 · 417 阅读 · 0 评论 -
USB camera前后摄不固定
项目过程当中使用两颗USB camera,反复开关机后发现一个问题,每次开机后前后摄分配是随机的。百度后发现以下文章很有帮助。Linux USB 摄像头驱动https://blog.csdn.net/qq_26093511/article/details/78763824[RK3288][Android6.0] 调试笔记 --- 如何区分两颗相同的USB UVC Camera...原创 2019-03-08 10:08:55 · 1051 阅读 · 0 评论 -
kobject
在Linux设备模型中,kobject是它的基础结构。其数据结构定义在kernel-4.9/include/linux/kobject.h。struct kobject { const char *name; struct list_head entry; struct kobject *parent; struct kset *kset; struct kobj_type ...原创 2019-03-11 15:42:12 · 250 阅读 · 0 评论 -
I2C总线初探
I2C(Inter-Integrated Circuit,内置集成电路)最初为飞利浦所开发,为2线接口。这2根线为时钟线和双向数据线,分别被称为SCL(Serial CLock,串行时钟)和SDA(Serial DAta,串行数据)。由于I2C总线仅需要一对总线,因此在电路板上占用的空间更少,带来的问题是带宽较窄。即使I2C支持双向数据交换,由于仅有一根数据线,故通信是半双工的。由于I2C被大...原创 2019-03-18 17:10:30 · 710 阅读 · 0 评论 -
字节序
小心,不要做字节序的假设。尽管PC是按照先低字节(little-endian,小头)的方式存储多字节数值的,但某些高端平台是以另一种方式(big-endian,大头)工作的。只要可能,就应该将代码编写成不依赖于所操作数据的字节序的方式。Linux内核定义了一组宏,它可以在处理器字节序和特殊字节序之间进行转换。例如,下面的宏可以将值和对应位的无符号的小头数值互转:#if __BYTE_...原创 2019-03-14 17:40:11 · 432 阅读 · 0 评论 -
另一种简单的读写-simple_read_from_buffer
之前在《简单的读和写》中提到过file_operations结构中的读/写方法中的buff参数是指向用户空间的缓冲区。而用户空间的指针,内核代码不能直接引用其中的内容。所以用了copy_to_user和copy_from_user来完成最后的读写操作。这里介绍另一对可以完成读写的函数:simple_read_from_buffer和simple_write_to_buffer。这两个方...原创 2019-03-14 17:07:42 · 3606 阅读 · 0 评论 -
proc文件系统的简单使用
proc文件系统是一种特殊的、由软件创建的文件系统,内核使用它向外界导出信息,/proc下面的每个文件都绑定一个内核函数,用户读取其中的文件时,该函数动态地生成文件的“内容”。例如,/proc/modules列出的是当前载入模块的列表。在Linux系统中,对/proc的使用很频繁。现代Linux发行版本中的很多工具都是通过/proc来获取它们需要的信息,例如ps、top和uptime。有些设备...原创 2019-03-14 16:44:44 · 577 阅读 · 0 评论 -
内核线程
内核线程是一种内核空间实现后台任务的方式。该任务可以进行繁忙的异步事务处理,也可以睡眠等待某事件的发生。创建内核线程:/* * Create a kernel thread. */pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags){ return _do_fork(flags|CLONE_...原创 2019-03-01 19:44:39 · 359 阅读 · 0 评论 -
通知链
通知链(notifier chain)可用于将状态改变信息发给请求这些改变的代码段。与硬编码不同,通知是一项在感兴趣的事件产生时获得警告的、使用范围很广泛的技术。最初使用通知的目的是将网络事件传递给内核中感兴趣的部分,但是现在它也可用于许多其他目的。通知链相关内容主要定义在kernel-4.9\include\linux\notifier.h和kernel-4.9\kernel\notifie...原创 2019-03-05 10:47:33 · 339 阅读 · 0 评论 -
等待队列
在Linux驱动程序中,可使用等待队列(wait queue)来实现阻塞进程的唤醒,以队列为基础数据结构,与进程调度机制紧密结合,用于实现内核的异步事件通知机制,也可用于同步对系统资源的访问。(信号量在内核中也是依赖等待队列来实现)以下是等待队列的数据结构:struct __wait_queue_head { spinlock_t lock; struct list_head ta...原创 2019-03-01 17:36:03 · 533 阅读 · 0 评论 -
分配内存-vmalloc
内存分配函数vmalloc,它是用来分配虚拟地址空间的连续区域的。尽管这段区域在物理上可能是不连续的(要访问其中的每个页面都必须独立调用函数alloc_page),内核却认为它们在地址上是连续的。vmalloc在发送错误时返回0(NULL地址),成功时返回一个指针,该指针指向一个线性的、大小最小为SIZE的线性内存区域。vmalloc相关的内容定义在<linux/vmalloc.h>...转载 2019-02-15 13:40:15 · 2392 阅读 · 0 评论 -
分配内存-get_free_page
如果模块需要分配大块的内存,使用页面的分配技术会更好一些。unsigned long get_zeroed_page(gfp_t gfp_mask)返回指向新页面的指针并将页面清零。unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);用于以gfp_mask分配方式分配2的order次方个连续的物理...原创 2019-02-15 10:19:54 · 759 阅读 · 0 评论 -
file结构
struct file { union { struct llist_node fu_llist; struct rcu_head fu_rcuhead; } f_u; struct path f_path; struct inode *f_inode; /* cached value */ const struct file_operations *f_op; /*...原创 2019-01-23 16:43:18 · 1059 阅读 · 0 评论 -
内存池-mempool
在内核中有不少地方内存分配不允许失败。 作为一个在这些情况下确保分配的方式, 内核开发者创建了一种称为内存池(或者是 "mempool" )的抽象.。内存池其实就是某种形式的后备高速缓存, 它试图始终保存空闲的内存,以便在紧急时使用.。内存池对象类型mempool_t定义在<linux/mempool.h>中。typedef struct mempool_s { spinl...转载 2019-02-14 16:55:53 · 636 阅读 · 0 评论 -
简单的读和写
对设备的操作都是通过与cdev绑定的file_operations结构中的函数来完成。其中读写操作分别对于以下方法:ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *offp);ssize_t write(struct file *filp, const char __user *buff,...原创 2019-02-02 08:18:48 · 141 阅读 · 0 评论 -
file_operations
在开始编写驱动前,还需要学习一下驱动程序操作时一个重要的数据结构,file_operations。在获取了一些设备编号后,我们还没有将任何驱动程序操作连接到这些编号,file_operations结构就是用来建立这种连接的。这个结构定义在<linux/fs.h>中。struct file_operations { struct module *owner; loff_...原创 2019-01-22 20:24:51 · 6601 阅读 · 0 评论 -
主设备号与次设备号
主设备号与次设备号驱动对应了设备,Linux系统中对于设备的访问是通过文件系统内的设备名称进行的。那些名称被称为特殊文件、设备文件,它们通常位于/dev目录下。进入该目录,通过ls -l命令可以输出目录中的设备文件,其中第一列的'c'表示字符设备。crw------- 1 root root 254, 0 2019-01-21 05:34 BOOTcr...原创 2019-01-21 14:52:18 · 1328 阅读 · 0 评论 -
inode结构
内核用inode结构在内部表示文件,因此它和file结构不同,后者表示打开的文件描述符。对单个文件,可能会有许多个表示打开的文件描述符的file结构,但它们都指向单个inode结构。inode结构中包含了大量有关文件的信息。该结构定义在<linux/fs.h>中。作为常规,只有下面两个字段对编写驱动程序代码有用:dev_t i_rdev;对表示设备文件的inode结...原创 2019-01-24 13:39:35 · 585 阅读 · 0 评论 -
简单认识驱动与模块
什么是驱动?以下百度百科中对驱动解释。驱动(计算机软件术语)驱动程序全称设备驱动程序,是添加到操作系统中的特殊程序,其中包含有关硬件设备的信息。此信息能够使计算机与相应的设备进行通信。驱动程序是硬件厂商根据操作系统编写的配置文件,可以说没有驱动程序,计算机中的硬件就无法工作。 可以看到,驱动相对于一般的软件而言最大的区别是,它是直接与硬件设备进行通讯的。 Linux驱动...原创 2019-01-18 19:20:31 · 1195 阅读 · 0 评论 -
字符设备驱动
字符设备,内核内部使用struct cdev结构来表示,定义在<linux/cdev.h>中,其中还包含与其相关的一些辅助函数。字符(char)设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种特性。字符设备驱动程序通常至少要实现open,close,read和write系统调用。字符终端(/dev/console)和串口(/dev/ttys0以及类似设...原创 2019-01-31 07:09:06 · 113 阅读 · 0 评论 -
简单的GPIO读写
General Purpose Input Output (通用输入/输出)简称为GPIO,或总线扩展器,人们利用工业标准I2C、SMBus或SPI接口简化了I/O口的扩展。在Linux驱动GPIO是使用频率可谓是相当之高。应用程序都能够通过相应的接口使用gpio,gpio使用0~MAX_INT之间的整数标识,不能使用负数。下面简单讲一下它的一些用法。 测试是否合法:int...原创 2019-02-11 11:41:13 · 2901 阅读 · 0 评论 -
竟态-semaphore
在日常开发中,竟态是难以避免的。当多个进程同时访问同一个资源或者数据结构时,竟态便会发生。semaphore便是解决这种现象的一个手段。 semaphore进程同步互斥的量,能保证资源在被一个进程使用时,其他进程无法使用此资源。Linux中使用struct semaphore来定义这个互斥的信号量。 以下是使用过程中会用到的一些方法。 初始化:void se...原创 2019-02-11 17:48:30 · 283 阅读 · 0 评论 -
短延时
在内核中,小于jiffies的延时被认为是短延时。这种延时在进程或者中断上下文都可能发生。由于不可能使用基于jiffies的方法实现短延时,因此唯一的解决途径就只剩下了忙等待。其主要API包括:mdelay()毫秒级延时udelay()微妙级延时ndelay()纳秒级延时1s=10^3ms=10^6us=10^9ns...原创 2019-03-01 10:24:31 · 461 阅读 · 0 评论 -
长延时-2
除了上一篇文章提到的一些方法,内核还提供了定时器API。其相关内容定义在<linux/timer.h>和kernel/time/timer.c中。内核定时器可以在将来的某个时间点调度执行某个动作,同时在该点到达之前不会阻塞当前进程。它可以在未来的某个特定时间点(基于时钟滴答)调度执行某个函数,从而可用于完成许多任务。例如,在硬件无法产生中断时,可以周期性的轮询设备状态。之前提到...原创 2019-03-01 10:02:40 · 244 阅读 · 0 评论 -
后备高速缓存-kmem_cache
Linux内核的高速缓存管理有时称为‘slab分配器’。因此,相关函数和类型在<linux/slab.h>中声明。数据类型kmem_cache。创建缓存:struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags, v...原创 2019-02-14 14:26:04 · 482 阅读 · 0 评论 -
长延时-1
在内核中,以jiffies为单位的进行的延迟通常被认为是长延时。一种可能但非最佳的实现长延时的方法是忙等待,它本身不利用CPU进行有用的工作,同时还不让其他应用使用CPU。来个示例:unsigned long timeout = jiffies + HZ;while(time_before(jiffies, timeout)) { cpu_relax();}对cpu...原创 2019-02-28 17:52:46 · 739 阅读 · 0 评论