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字符设备学习笔记【原创】的更多相关文章

  1. Linux字符设备学习,总结

    注册字符驱动的一种老方法: 注册一个字符设备的经典方法是使用:int register_chrdev(unsigned int major, const char *name, structfile_ ...

  2. Smart210学习记录----beep linux字符设备驱动

    今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...

  3. Linux shell 菜鸟学习笔记....

    20171123 Linux shell 基础学习笔记1. shell 的开始 一般是 #!/bin/bash 通过 #! 来唯一指定使用的shell路径 其他的 # 都表示注释.2. shell 的 ...

  4. 深入理解Linux字符设备驱动

    文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...

  5. 兄弟连Linux运维学习笔记

    最新经典linux运维兄弟连Linux运维学习笔记... --------------- 全程1.5倍播放.加油我一定可以学完Linux----------------------Unix与Linux ...

  6. Linux字符设备驱动实现

    Linux字符设备驱动实现 要求 编写一个字符设备驱动,并利用对字符设备的同步操作,设计实现一个聊天程序.可以有一个读,一个写进程共享该字符设备,进行聊天:也可以由多个读和多个写进程共享该字符设备,进 ...

  7. (57)Linux驱动开发之三Linux字符设备驱动

    1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...

  8. Linux下iptables学习笔记

    Linux下iptables学习笔记 在Centos7版本之后,防火墙应用已经由从前的iptables转变为firewall这款应用了.但是,当今绝大多数的Linux版本(特别是企业中)还是使用的6. ...

  9. Python 图片转字符画 学习笔记

    Python 图片转字符画 学习笔记 标签(空格分隔): Python 声明:此文章和所有代码是学习笔记,非原创,原文教程地址:https://www.shiyanlou.com/courses/37 ...

随机推荐

  1. Linux学习之十一-Linux字符集及乱码处理

    Linux字符集及乱码处理 1.字符(Character)是各种文字和符号的总称,包括各国家文字.标点符号.图形符号.数字等.字符集(Character set)是多个字符的集合,字符集种类较多,每个 ...

  2. Django和Flask的区别以及运行流程

    Django: Python Web框架里比较有名当属Django,Django功能全面,它提供一站式解决方案,集成了MVT(Model-View-Template)和ORM,以及后台管理.但是缺点也 ...

  3. mysql 导入sql文件时编码报错

    1.命令行导入 mysql -uroot -pnewpwd --default-character-set=utf8 databasename < xxx.sql 2.使用source导入 进入 ...

  4. AudioSession/AudioCaptureSession的分析与使用

    这个是AudioSession的结构图: 前一个部分已经介绍了AVFoundation对音频录制.播放的一种方法,以下再介绍第二种: AVCaptureSession 用这个类的长处在什么地方呢? ( ...

  5. bootstrap selectpicker使用问题

    文档查阅:http://silviomoreto.github.io/bootstrap-select/options/ 1.实用属性 size:5  表示下拉列表默认展示5行(ie8展示4.5行) ...

  6. C语言 指向结构体数组的指针

    当结构体指针变量指向一个结构体变量数组的时候,此时指针变量的值就是结构体数组的首地址 关于如何定义结构体数组,和将结构体指针指向结构体变量数组,不是重点. 重点是,明白结构体指针的是怎么移动的, 我个 ...

  7. uva 11404 dp

    UVA 11404 - Palindromic Subsequence 求给定字符串的最长回文子序列,长度一样的输出字典序最小的. 对于 [l, r] 区间的最长回文串.他可能是[l+1, r] 和[ ...

  8. android studio 更新Gradle版本号方法

    在导入其它项目时,常常因为gradle版本号不一致而导致不能编译 解决方法: 第一步: 按提示点击让它下载.事实上目的并非要它下载.因为这样速度会非常慢.这样做仅仅是为了让它在本地创建相应的文件夹结构 ...

  9. VIM中保存编辑的只读文件

    如何在VIM中保存编辑的只读文件 你是否会和我一样经常碰到这样的情景:在VIM中编辑了一个系统配置文件,当需要保存时才发现当前的用户对该文件没有写入的权限.如果已 经做了很多修改,放弃保存的确很懊恼, ...

  10. mysql 相关博客地址

    MySQL概念学习与逐步上手操作系列(一套完整)   https://www.cnblogs.com/zlslch/category/962962.html