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. EXCEL最大行数问题:org.apache.xmlbeans.impl.store.Saver$TextSaver.resize(Saver.java:1700)

    今天在使用POI导出数据时,出现如下错误: ES查询阅读推荐比: resList: start: 写入excel Exception in thread "main" java.l ...

  2. JavaScript实现网页元素的拖拽效果

    以下的页面中放了两个div,能够通过鼠标拖拽这两个元素到任何位置. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFja2ZydWVk/font/5a6 ...

  3. pkav之当php懈垢windows通用上传缺陷

    $pkav->publish{当php懈垢windows}剑心@xsser抛弃了我,但我却不能抛弃乌云..php懈垢windows,就像男人邂逅女人,早晚都会出问题的..感谢二哥@gainove ...

  4. vue.js+koa2项目实战(一)创建项目和elementUI配置

    前端采用vuex+element-ui: 后端采用koa2+restfulAPI+sequlize: (一)项目介绍 宠物社区 1.社区 2.好友 3.说说 4.宠粮 5.健康 (二)项目框架 1.V ...

  5. Node.app让Nodejs平台在iOS和OS X系统上奔跑

    首先呢,欢迎大家去查看相同内容的链接:http://www.livyfeel.com/nodeapp/. 由于那个平台我用的markdown语法,我也懒得改动了,就这样黏贴过来了. 这是一个惊人的恐怖 ...

  6. HTTP头解读

    Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET.POST.PUT.DELETE.一个URL地址用于描述一个网络上的资源, 而HTTP中的GET.POST.PUT. DELETE ...

  7. LeetCode Hash Table 3. Longest Substring Without Repeating Characters

    HashMap的应用可以提高查找的速度,键key,值value的使用拜托了传统数组的遍历查找方式,对于判断一个字符或者字符串是否已经存在的问题可以非常好的解决.而本题需要解决的问题就是判断新遍历到的字 ...

  8. python for android : BeautifulSoup 有 bug

    BeautifulSoup 善于网页数据分析 .可是 python for android : BeautifulSoup 有 bug , text = h4.a.text 仅仅能取得 None,因此 ...

  9. PowerDesigner将PDM导出生成WORD文档(转)

    今天的温习老知识,是如何将一个PD设计的PDM来导出WORD文档,这是一个非常实用的功能,可以在软件过程的数据库设计文档编写中节省N多时间, 那不废话了,我们就开始今天的讲解吧! 第一步,点击Repo ...

  10. SQL注入基础入门

    一般的WEB架构 SQL注入成因: 用户开启浏览器并连接http://www.xxx.com.位于逻辑层的Web服务器从文件系统中加载脚本将其传递给脚本引擎,脚本引擎负责解析并执行脚本. 脚本使用数据 ...