linux异步通知
异步通知异步通知:一旦设备准备就绪,则主动通知应用程序,这样引用程序根本不需要查询设备状态,由此引入了信号的概念,信号是在软件层次上的对中断机制的一种模拟,驱动可以通过主动向应用程序发送信号的方式来报告自己可以访问了,应用程序获取到信号以后就可以从驱动设备中读取或者写入数据了。整个过程就相当于应用程序收到了驱动发送过来了的一个中断,然后应用程序去响应这个中断,。
信号Linux中用异步信号来实现进程通信(IPC)。
123456789101112131415161718192021222324252627282930313233343534 #define SIGHUP 1 /* 终端挂起或控制进程终止 */35 #define SIGINT 2 /* 终端中断(Ctrl+C 组合键) */36 #define SIGQUIT 3 /* 终端退出(Ctrl+\组合键) */37 #define SIGILL 4 /* 非法指令 */38 #define SIGTRAP 5 /* debug 使用,有断点指令产生 */39 #define SIGABRT 6 /* 由 abort(3) ...
linux阻塞与非阻塞
阻塞和非阻塞IO阻塞式
当应用程序对设备驱动进行操作的时候,如果不能获取到设备资源,那么阻塞式 IO 就会将应用程序对应的线程挂起,直到设备资源可以获取为止。
非阻塞式
对于非阻塞 IO,应用程序对应的线程不会挂起,它要么一直轮询等待,直到设备资源可以使用,要么就直接放弃。
等待队列等待队列头阻塞式的好处就是,当无法获取资源的时候进程进入休眠状态,让出cpu来干别的事情,可以操作的时候再进行唤醒(一般在中断里唤醒)。
Linux内核提供了等待队列来实现阻塞进程的唤醒工作,首先要创建并初始化一个等待队列头,等待队列头使用结构体wait_queue_head_t表示。
1234567struct __wait_queue_head{ spinlock_t lock; struct list_head task_list;}typedef struct __wait_queue_head wait_queue_head_t;//使用init_waitqueue_head初始化等待队列头void init_waitqueue_head(wait_queu ...
linux中断
linux中断中断是指CPU在执行程序执行中,出现了突发事件,CPU必须暂停当前程序的执行,处理突发事件,处理完后又返回程序到中断的位置继续进行。
根据中断入口跳转方法不同,分为向量中断和非向量中断,采用向量中断的CPU通常为不同的中断分配不同的中断号,当检测到某中断到来后,自动跳转到该中断号对应的地址执行。不同中断号的中断有不同的入口地址。非向量中断的多个中断共享一个入口地址,进入该入口地址后,再通过软件判断中断标志来标识,具体哪个中断。
申请和释放中断request_irq 函数用于申请中断, request_irq函数可能会导致睡眠,因此不能在中断上下文或者其他禁止睡眠的代码段中使用 request_irq 函数。 request_irq 函数会激活(使能)中断,所以不需要我们手动去使能中断。
12345int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
irq:要申请中断的中断号。
每个中断都有一个中断号,通 ...
linux内核定时器
时间管理和内核定时器Linux 内核中有大量的函数需要时间管理,比如周期性的调度程序、延时程序、对于我们驱动编写者来说最常用的定时器。硬件定时器提供时钟源,时钟源的频率可以设置, 设置好以后就周期性的产生定时中断,系统使用定时中断来计时。中断周期性产生的频率就是系统频率,也叫做节拍率(tick rate)(有的资料也叫系统频率)。
可以在编译 Linux 内核的时候可以通过图形化界面设置系统节拍率,
12-> Kernel Features-> Timer frequency (<choice> [=y])
高节拍率和低节拍率的优缺点:
①、高节拍率会提高系统时间精度,如果采用 100Hz 的节拍率,时间精度就是 10ms,采用1000Hz 的话时间精度就是 1ms,精度提高了 10 倍。高精度时钟的好处有很多,对于那些对时间要求严格的函数来说,能够以更高的精度运行,时间测量也更加准确。②、高节拍率会导致中断的产生更加频繁,频繁的中断会加剧系统的负担, 1000Hz 和 100Hz的系统节拍率相比,系统要花费 10 倍的“精力”去处理中断。中断服务函数占 ...
globalmem设备驱动
globalmem驱动globalmem为“全局内存”的意思,在globalmem字符设备中会分配一片大小为GLOBALMEM_SIZE的内存空间,并在驱动中提供对这片内存的读写、控制和定位函数,供用户空间的进程能通过Linux系统调用获取和设置这片内存。
头文件、宏定义以及结构体1234567891011121314151617181920#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/slab.h>#include <linux/uaccess.h>#define GLOBALMEM_SIZE 0x1000#define MEM_CLEAR 0x1#define GLOBALMEM_MAJOR 230static int globalmem_major = GLOBALMEM_MAJOR;module_param(globalmem_maj ...
linux并发与竞争
并发若我们谈及计算机系统中的并发,则是指同一个系统中,多个独立活动同时进行,而非依次进行。起初的计算机并发只是一种制造并发的假象,因为只有一个处理器,在同一时刻实质只能处理一个任务,不过是一秒钟内进行多个任务的切换。看起来是同时进行的,因此叫做任务交换。
多年来,配备了多处理器的计算机一直被用作服务器,它要承担高性能的计算任务;现今,基于一芯多核处理器(简称多核处理器)的计算机日渐普及,多核处理器也用在台式计算机上。
无论是装配多个处理器,还是单个多核处理器,或是多个多核处理器,这些计算机都能真正并行运作多个任务,我们称之为硬件并发(hardware concurrency)。
并发方式多进程并发在应用软件内部,一种并发方式是,将一个应用软件拆分成多个独立进程同时运行,它们都只含单一线程,非常类似于同时运行浏览器和文字处理软件。这些独立进程可以通过所有常规的进程间通信途径相互传递信息(信号、套接字、文件、管道等)。
多线程并发另一种并发方式是在单一进程内运行多线程。线程非常像轻量级进程,每个线程都独立运行,并能各自执行不同的指令序列。
不过,同一进程内的所有线程都共用相同的地址空间,且 ...
gpio子系统
GPIO子系统GPIO子系统API函数对于驱动开发人员,设置好设备树以后就可以使用 gpio 子系统提供的 API 函数来操作指定的 GPIO, gpio 子系统向驱动开发人员屏蔽了具体的读写寄存器过程。这就是驱动分层与分离的好处,大家各司其职,做好自己的本职工作即可。 gpio 子系统提供的常用的 API 函数有下面几个:
gpio_request函数,用于申请一个 GPIO 管脚
在使用一个 GPIO 之前一定要使用 gpio_request进行申请
1int gpio_request(unsigned gpio, const char *label)
gpio:要申请的gpio号,使用of_get_named_gpio函数从设备树获取指定gpio属性
label: gpio的名字
返回值:0申请成功,其他值失败
gpio_free函数, 释放gpio
1void gpio_free(unsigned gpio)
gpio: 释放的gpio
返回值无
gpio_direction_input函数 , 设置gpio为输入
1void gpio_direction_in ...
设备树上的驱动开发
设备树驱动编写框架
编写设备树节点首先是将节点编写在使用的开发板的dts文件中,比如编写led的节点。首先将节点编写在根节点下:
12345678910111213alphaled//节点名字{ #address-cells = <1>; #size-cells = <1>; compatible = "atkalpha-led"; status = "okay"; reg = { 0X020C406C 0X04 //CCM_CCGR1_BASE 0X020E0068 0X04 //SW_MUX_GPIO103_BASE 0X020E02F4 0X04 //SW_PAD_GPIO103_BASE 0X0209C000 0X04 //GPIO1_DR_BASE 0X0209C004 0X04 //GPIO1_GDIR_BASE };};
在节点中已经写入物理地址,所以驱动程序进行获取就行不用写了,设备树修改完 ...
nfs挂载设备树失败
VFS: Cannot open root device “nfs” or unknown-block(2,0)首先说明一下问题,之前根文件系统一直正常使用,突然今天进行了以上报错,首先是搜索了一下问题,说是开发板内核和Ubuntu的nfs版本不匹配,之前遇到过,系统换成Ubuntu16版本的了,应该可以排除,但是也试了一下不好使。
感觉是ip地址的变化将bootargs变量里的服务器ip地址的数值进行了相应的改变,但是还是没有变化。
查了相关的问题搜索发现,没有解决方案,我先是进行了开发板的固化系统,使用了emmc中的根文件系统,发现没有问题,但是使用网络nfs挂载还是出现了问题,最后通过装载了第二个系统进行挂载发现了问题所在。
问题是:板子的ip地址和别的设备的ip地址冲突了(虽然之前也dhcp了但当时没好使),加上了服务器ip地址的变化导致的。
所以为了一劳永逸,将Ubuntu的动态分配ip地址进行了更改,改为静态分配ip地址。
1ipaddr
可以查看发现网卡的名字。
网卡名字叫做ens33
1sudo vi /etc/network/interfaces
1234567 ...
设备树常用的of操作树
设备树常用 OF 操作函数设备树描述了设备的详细信息,这些信息包括数字类型的、字符串类型的、数组类型的,在编写驱动的时候需要获取到这些信息。比如设备树使用 reg 属性描述了某个外设的寄存器地址为 0X02005482,长度为 0X400,我们在编写驱动的时候需要获取到 reg 属性0X02005482和 0X400 这两个值,然后初始化外设。
Linux 内核给我们提供了一系列的函数来获取设备树中的节点或者属性信息,这一系列的函数都有一个统一的前缀“of_”,所以在很多资料里面也被叫做 OF 函数。这些 OF 函数原型都定义在 include/linux/of.h 文件中。
linux内核使用device_code结构体来描述一个节点,此结构体定义在include/linux/of.h
123456789101112131415161718192021struct device_node { const char *name; /* 节点名字 */ const char *type; /* 设备类型 */ phandle phand ...

