linux内核笔记(二)字符设备驱动

字符设备驱动是Linux系统中最多的一类驱动,也是较简单的一类驱动。

Linux系统根据驱动程序实现的模型框架将设备的驱动分为三类

  • 字符驱动程序

设备对设局的处理是按照字节流的形式进行的,可以支持随机访问,也可以不支持随机访问,因为数据流量通常不大,一般没有高速缓存。典型的字符设备有串口(接受数据没有具体要求,可以是任意多个字符,不支持lessk操作)、键盘、帧缓存设备(显卡,可以随机访问)等。

  • 块设备驱动

设备对数据的数据是按照若干个块进行的,一个块有其固定的大小。这类设备都支持随机访问,并且为了提高效率,可以将之前用过的数据缓存起来,以便下次使用。典型的块设备有硬盘、光盘、SD卡。

  • 网络设备驱动

专门针对网络设备的一类驱动,主要是进行网络数据的收发。

但在现实生活中,有的设备很难被界定,甚至同时拥有两种驱动。一个设备的驱动属于哪一类,还要看具体的适用场合和最终的用途。

字符设备驱动基础

在Linux中,一切设备皆文件,设备文件通常位于/dev目录下,使用ls -l /dev可以查看设备文件及相关信息

ls -l /dev

b开头的是块设备,c开头的是字符设备,sda是整个硬盘,tty是终端设备,shell程序使用这些设备来同设备进行交互。

设备文件比普通文件多两个数字,数字分别是主设备号、次设备号。这两个号是设备在内核中的身份或标志,是内核区分不同设备的唯一信息。通常内核用主设备号区分一类设备,次设备号用于区分同意设备的不同个体或分区,路径名是用户层用于区分设备信息的。

Linux中,设备文件通常是自动创建的,也有mknod命令可以手动创建一个设备文件。 

mknod命令,创建一个节点(设备文件有时又称设备节点)。在Linux中,一个节点代表一个文件,创建一个文件最主要的根本工作就是分配一个新的节点(这里是存在于磁盘上的节点,还有位于内存中的节点inode),包含节点好的分配(唯一,用于区分不同的文件),然后初始化这个新结点(文件模式、访问时间、用户ID、组ID等元数据信息,设备文件还要初始化设备号),再将这个初始化好的节点写入磁盘。还要在文件所在的目录下添加一个目录项,目录项中包含了前面分配的节点号和文件的名字,然后写入磁盘。

字符设备驱动框架

要实现一个字符设备驱动,最重要的是构造一个cdev结构对象,并让cdev同设备号与设备的操作方法集合相关联,然后将该cdev结构对象添加到内核的cdev_map散列表中。

  • 在驱动中注册设备号:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

#include <linux/fs.h>

#define VSER_MAJOR 256
#define VSER_MINOR 0
#define VSER_DEV_CNT 1
#define VSER_DEV_NAME "vser"

static int __int vser_init(void){
    int rev;
    dev_t dev;//无符号32位整数,主设备号12位,次设备号20位

    dev = MKDEV(VSER_MAJOR,VSER_MINOR);//使用MKDEV宏将主设备号和次设备号合并成一个设备号
    ret = register_chrdev_region(dev,VSER_DEV_CNT,VSER_DEV_NAME);
    //将构造的设备号注册到内核
    if(ret)
        goto reg_err;
    return 0;

reg_err:
    return ret;
}

static void __exit vser_exit(void){
    dev_t dev;
    
    dev = MKDEV(VSER_MAJOR,VSER_MINOR);
    unregister_chrdev_region(dev,VSER_DEV_CNT);
    //注销
}

module_init(vser_init);
module_exit(vser_exit);

MODULE_LICENSE("GPL");

register_chrdev_region函数

int register_chrdev_region(dev_t from,unsigned count ,const char *name);

 该函数一次可以注册多个连续的号,由count形参指定个数,由from指定起始的设备号,name用于标记设备号的名称。调用成功返回0,失败返回负数。注册出错,使用goto语句跳转到错误处理代码执行(在驱动错误处理常见)

 如果两个驱动使用了相同的设备号,那么后加载的驱动将失败,因为设备号冲突了。为了解决这个问题,可以使用动态分配设备号的函数。

int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unisged count,const char *name);

 count和name形参和register_chrdev_region函数的形参一样。baseminor时动

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值