linux字符设备学习笔记【原创】
1、申请设备号
int register_chrdev_region(dev_t from, unsigned count, const char *name)
指定从设备号from开始,申请count个设备号,在/proc/devices中的名字为name。返回值:成功返回0,失败返回错误码。
2、动态的申请设备号
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
动态申请从次设备号baseminor开始的count个设备号,在/proc/devices中的名字为name,并通过dev指针把分配到的设备号返回给调用函数者。返回值:成功返回0,失败返回错误码。
3、卸载申请的设备号
void unregister_chrdev_region(dev_t from, unsigned count)
使用:释放从from开始count个设备号。
4、注册字符设备
1)分配cdev;
2)初始化cdev;
3)添加cdev;
4.1 分配cdev
struct cdev* test_cdev;
test_cdev = cdev_alloc();
4.2 初始化cdev
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
cdev:之前我定义的cdev结构体;fops:设备对应的文件操作结构体。返回值:(函数有可能失败,查看返回值是必须的);成功返回0,示范返回对应的错误码;
4.3 添加cdev
int cdev_add(struct cdev *cdev, dev_t dev, unsigned count)
cdev:指定要被添加的cdev结构体;dev:对应的设备号;count:从设备号dev开始添加count个设备.返回值:成功返回0,失败返回对应的错误码。
4.3 卸载cdev
void cdev_del(struct cdev *p)
5、error
Linux的出错处理在设计的时候是考虑了跟平台架构相关。
6、驱动、设备文件、设备号、应用程序之间的关系
设备号的申请通过register_chrdev_region()调用这个函数进行申请设备号,之后调用cdev_init()将设备注册进内核,要将设备号与驱动关联起来调用cdev_add(),要给应用程序提供一个接口去访问内核的驱动,需要创建一个文本文件可以手动的创建
mknod /dev/test c 250 0 应用程序通过open这个路径"/dev/test"就可以访问内核。
7、struct file
在内核中,file结构体是用来维护打开的文件的。每打开一次文件,内核空间里就会多增加一个file来维护,当文件关闭是释放。
loff_t f_pos;这是用来记录文件的偏移量。
8、等待队列
定义
wait_queue_head_t test_queue;
初始化
init_waitqueue_head(&test_queue); 如果condition为真,将进程加入等待队列并等待唤醒
wait_event_interruptible(wq, condition)函数调用成功会进入可中断休眠
wait_event(queue, condition)函数成功会进入不可中断休眠,不推荐 void wake_up(wait_queue_head_t *queue); //唤醒等待队列中所有休眠的进程
void wake_up_interruptible(wait_queue_head_t *queue); //唤醒等待队列中所有可中断睡眠的进
9、自旋锁、
使用静态定义并初始化:spinlock_t lock = SPIN_LOCK_UNLOCKED;
使用动态定义并初始化:spinlock_t lock; spin_lock_init(&lock);
在进入临界区前,必须先获得锁,使用函数:spin_lock(&lock);
在退出临界区后,需要释放锁,使用函数:spin_unlock(&lock);
10、信号量
定义并初始化一个叫name的计数信号量,允许conut个进程同时持有锁:static DECLARE_SEMAPHORE_GENERIC(name, count)
定义并初始化一个叫name的互斥信号量:static DECLARE_MUTEX(name)\
第二种是动态定义并初始化:
struct semaphore sem;
sema_init(&sem, count);
/*初始化一个互斥信号量*/
#define init_MUTEX(sem) sema_init(sem, 1)
/*初始化一个互斥信号量并加锁*/
#define init_MUTEX_LOCKED(sem) sema_init(sem, 0)
获取信号量:
1/*获取信号量sem,如果不能获取,切换状态至TASK_UNINTERRUPTIBLE*/
voud down(struct semaphore *sem)
上面的函数不太常用,因为它的睡眠不能被中断打断,一般使用下面的函数
2/*获取信号量sem,如果不能获取,切换状态至TASK_INTERRUPTIBLE,如果睡眠期间被中断打断,函数返回非0值*/
int down_interruputible(struct semaphore *sem)
3/*尝试获得信号量,如果获得信号量就返回零,不能获得也不睡眠,返回非零值*/
int down_try_lock(struct semaphore *sem)
11、使用kmalloc需要包含的头文件
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/fs.h>
12、IO内存
物理地址映射虚拟地址的函数
void *ioremap(unsigned long phys_addr, unsigned long size);
撤销映射的函数
void ioumap(void *addr);
13、注册中断处理函数
int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)
使用:
将中断号irq与中断处理函数handler对应
参数:
irq:指定要分配的中断号,中断号的定义在“include/mach/irqs.h”中。注意,不管是单独占有中断请求线的中断,还是共享中断请求线的每个中断,都有一个对应的中断号。,所以,调用该函数不需要考虑是哪种中断(是否共享寄存器),你想哪种中断响应,你就填对应的中断号。
handler:中断处理函数指针。
irqflags:中断处理标记,待会介绍:
devname:该字符串将显示在/proc/irq和/pro/interrupt中。
dev_id:ID 号,待会会介绍。
返回值:成功返回0,失败返回非0。
释放中断
void free_irq(unsigned int irq, void *dev_id)
中断处理函数
static irqreturn_t intr_handler(int irq, void *dev_id)
第一个参数irq,这是调用中断处理函数时传给它的中断号,第二个参数dev_id,这个参数与request_irq()的参数dev_id一致
cat /proc/interrupts 查看自己申请中断的名称
14、tasklet的使用
定义一个结构体
struct tasklet_struct test_tasklet;
初始化结构体的tasklet的中断处理函数
void tasklet_fun(unsigned long data)
{
printk("---------%s---------\r\n",__func__);
printk("data[%ld]\r\n",data);
}
调用中断处理函数
tasklet_schedule(&test_tasklet);
初始化tasklet结构体将中断处理函数与之关联
tasklet_init(&test_tasklet,tasklet_fun,(unsigned long));
13 卸载tasklet_kill(&xiaobai_tasklet);
15、工作队列的使用
定义与创建工作队列:
struct workqueue_struct *test_wq;
test_wq = create_workqueue("test workqueue");
定义工作与处理函数
struct work_struct test_work;
void test_func(struct work_struct *work)
{
printk("hello test work!\n");
}
将工作与处理函数想关联
INIT_WORK(&test_work,test_func);
将工作加入工作队列进行调度
queue_work(test_wq,&test_work);
销毁工作队列
flush_workqueue(test_wq);
destroy_workqueue(test_wq);
16、定时器的使用
定义一个定时器
struct timer_list my_timer;
初始化定时器
init_timer(&my_timer);
设置超时时间和定时器的处理函数
my_timer.expires = jiffies + *HZ;
my_timer.function = timer_func,
my_timer.data = (unsigned long);
void timer_func(unsigned long data)
{
printk("-----------%s------------\r\n",__func__);
printk("time out![%ld][%s]\r\n",data,current->comm); //my_timer.expires = jiffies + 2*HZ;
//add_timer(&my_timer);
mod_timer(&my_timer,jiffies + *HZ);
} 激活定时器
add_timer(&my_timer);
在定时器的处理函数添加,每隔2秒就会执行一次定时器的处理函数
mod_timer(&my_timer,jiffies + *HZ);
linux字符设备学习笔记【原创】的更多相关文章
- Linux字符设备学习,总结
注册字符驱动的一种老方法: 注册一个字符设备的经典方法是使用:int register_chrdev(unsigned int major, const char *name, structfile_ ...
- Smart210学习记录----beep linux字符设备驱动
今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...
- Linux shell 菜鸟学习笔记....
20171123 Linux shell 基础学习笔记1. shell 的开始 一般是 #!/bin/bash 通过 #! 来唯一指定使用的shell路径 其他的 # 都表示注释.2. shell 的 ...
- 深入理解Linux字符设备驱动
文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...
- 兄弟连Linux运维学习笔记
最新经典linux运维兄弟连Linux运维学习笔记... --------------- 全程1.5倍播放.加油我一定可以学完Linux----------------------Unix与Linux ...
- Linux字符设备驱动实现
Linux字符设备驱动实现 要求 编写一个字符设备驱动,并利用对字符设备的同步操作,设计实现一个聊天程序.可以有一个读,一个写进程共享该字符设备,进行聊天:也可以由多个读和多个写进程共享该字符设备,进 ...
- (57)Linux驱动开发之三Linux字符设备驱动
1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...
- Linux下iptables学习笔记
Linux下iptables学习笔记 在Centos7版本之后,防火墙应用已经由从前的iptables转变为firewall这款应用了.但是,当今绝大多数的Linux版本(特别是企业中)还是使用的6. ...
- Python 图片转字符画 学习笔记
Python 图片转字符画 学习笔记 标签(空格分隔): Python 声明:此文章和所有代码是学习笔记,非原创,原文教程地址:https://www.shiyanlou.com/courses/37 ...
随机推荐
- AngularJS中选择样式
代码下载:https://files.cnblogs.com/files/xiandedanteng/angularJSSelectClass.rar 要点,{{ctrl.name}}比<spa ...
- C 语言经典100例
C 语言经典100例 C 语言练习实例1 C 语言练习实例2 C 语言练习实例3 C 语言练习实例4 C 语言练习实例5 C 语言练习实例6 C 语言练习实例7 C 语言练习实例8 C 语言练习实例9 ...
- Vmware+gdb调试Linux内核——工欲善其事,必先利其器
今天我最终忍受不了qemu的低速跟不可理喻的各种bug,開始寻找新的调试内核的方法.然后想到了Vmware,那么成熟的虚拟机怎么可能调试不了内核.于是尝试了一番,发现结果很的棒!所以立刻奋笔疾书.把这 ...
- Android日期对话框NumberPicker的使用方法教程
NumberPicker是Android3.0之后引入的一个控件.NumberPicker 是用于选择一组提前定义好数字的控件.比方时间hour的选择仅仅有0-23有效,则能够通过setMinValu ...
- 应用程序之UITableView的编辑模式
cell分层结构 效果展示 代码实现 一.cell的分层结构 二.效果展示 三.代码实现 // // ViewController.m // 01-TableView的删除实现 // // Creat ...
- 基于Repository模式设计项目架构—你可以参考的项目架构设计
关于Repository模式,直接百度查就可以了,其来源是<企业应用架构模式>.我们新建一个Infrastructure文件夹,这里就是基础设施部分,EF Core的上下文类以及Repos ...
- Linux禁止Ctrl+Alt+Del重新启动
方法1:改动/etc/inittab 屏蔽 ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now 或者删除改行内容 保存退出 适用对象:RedHat4.8 ...
- [水]ZOJ1201
给原排列 求 其前面有多少个数比他大. 给每一个数1...2..n前面有多少个数比他大,求原序列 第一个直接统计 第二个从1開始找出第inv[i]+1个空位置放进去就好 printf里的format ...
- *Android 多线程下载 仿下载助手
今天带来一个多线程下载的 样例.先看一下效果.点击 下载 開始下载,同一时候显示下载进度.完成下载,变成程 安装,点击安装 提示 安装应用. 界面效果 线程池 ThreadPoolExecutor , ...
- (4.5.4)Android測试TestCase单元(Unit test)測试和instrumentationCase单元測试
Android单元和instrumentation单元測试 Developing Android unit and instrumentation tests Android的单元測试是基于JUnit ...