驱动学习No.1|字符设备驱动


在这里插入图片描述

每个设备都会有对应的设备节点(也就是对应文件/dev/xxx),内核区分设备是根据设备号而非设备节点,就好比每个人对应一个身份证号码而不是名字。

1.字符设备驱动框架

作为字符设备驱动要素:

  1. 必须有一个设备号,用在众多的设备驱动中进行区分
  2. 用户必须知道设备驱动对应的设备节点(设备文件)
    Linux把所有的设备都看成文件,因为是通过文件IO形式操作(open()、read()、write()、close()等)
    crw-r----- 1 root root 13, 64 Mar 28 20:14 event0
    crw-r----- 1 root root 13, 65 Mar 28 20:14 event1
    crw-r----- 1 root root 13, 66 Mar 28 20:14 event2
  3. 对设备操作其实就是对文件操作,应用空间操作open,read,write的时候,实际上是在驱动代码当中也有对应到open,read,write等操作。所以,例如,虽然open可以操作很多设备,但如果对应到/dev/设备节点,那么就实现了唯一性。对应/dev/led打开灯设备,对应/dev/key打开按键设备,……

2.申请设备号

a.作为驱动必须有一个设备号–向系统申请设备号

用于模块加载的函数中

int register_chrdev(unsinged int major, const char * name, const struct file_operations * fops)

参数1:主设备号(major)次设备号(minor)
设备号(32bit)==主设备号(12bit)+次设备号(20bit)
主设备号:表示一类设备–vcs
次设备号:表示同类设备中的某一个:vcs、vcs1、vcs2、……

$ls dev/ -l

在这里插入图片描述

以下的块设备也是这样
在这里插入图片描述

给定的方式有两种:

  1. 动态–参数1直接填0
  2. 静态–指定一个整数,比如123
    参数2:描述一个设备信息(name),可以自定义
    /proc/devices列举出所有的已注册设备
    参数3:文件操作对象–提供open,read,write
    返回值:正确返回0(return 0;),错误返回负数(return -EINVAL;)

b.作为驱动必须有一个设备号–系统释放设备号资源

用于模块卸载的函数中

unregister_chrdev(unsinged int major, const char * name)

参数1:主设备号(major)
参数2:描述一个设备信息,可以自定义
(name)

c.修改Makefile

else
    obj-m += [name].o
endif

m a k e c l e a n 然 后 重 新 make clean然后重新 makecleanmake一下
cat /proc/devices查看用了什么设备
在这里插入图片描述
在这里插入图片描述

3.创建设备节点

a.手动创建

mknod /dev/设备名 类型 主设备号 次设备号
比如:
mknod /dev/chr0 c 123 0

# ls    /dev/chr0   -l
crw-r--r--  1 0     0           123,    0   Jan     1   00:33   /dev/chr0

缺点:/dev/目录中的文件都是在内存中,断电后/dev/文件就会消失

b.自动创建(通过udev/mdev机制)

  1. 先创建一个类
  2. 然后创建类里的设备
struct class *class_create(owner, name)//创建一个类

参数1:THIS_MODULE
参数2:字符串名字,自定义

返回一个class指针

//创建一个设备文件
struct device *device_create(struct class *class, struct device * parent, dev_t devt, void * drvdata, const char * fmt,)

参数1:class结构体,class_create调用之后的返回值
参数2:表示父亲,一般直接填NULL
参数3:设备号类型 dev_t

设备号(32bit)==主设备号(12bit)+次设备号(20bit)

dev_t devt
    #define MAJOR(dev)  ((unsigned int) ((dev) >> MINORBITS))
    #define MINOR(dev)  ((unsigned int) ((dev) & MINORMASK))
    #define MKDEV(ma,mi)    ((ma) << MINORBITS) | (mi))

参数4:私有数据,一般直接填NULL
参数5、6:表示可变参数,字符串,表示设备节点的名字

有创建就有销毁,但顺序是:
3. 先释放设备资源
4. 然后再释放类资源
销毁动作:

void device_destroy(devcls,    MKDEV(dev_major,    0));

参数1:class结构体,device_create调用之后的返回值
参数2:设备号类型 dev_t

void class_destroy(devcls);

参数:class结构体,class_create调用之后的返回值
最后实验成功如下:
在这里插入图片描述

4.驱动led灯

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值