linux驱动2:设备号与字符设备注册与注销

目录

一、设备号 

1、设备号的组成 

2、设备号查询

 二、注册与注销函数

1、注册与注销函数参数

2、注册与注销函数的缺点

三、代码编写

 1、主设备号和设备名字

 2、设备操作函数结构体

3、 设备操作函数结构体调用的函数

open函数

 release函数 

read函数 

write函数 

4、添加注册和注销字符设备 


一、设备号 

1、设备号的组成 

为了方便管理, Linux 中每个设备都有一个设备号,设备号由主设备号和次设备号两部分组成,主设备号表示某一个具体的驱动,次设备号表示使用这个驱动的各个设备
Linux 提供一个名为 dev_t 的数据类型表示设备号, dev_t 定义在文件 include/linux/types.h 里面定义如下:

12 typedef __u32 __kernel_dev_t;
......
15 typedef __kernel_dev_t dev_t;

可以看出 dev_t 是__u32 类型的,而__u32 定义在文件 include/uapi/asm-generic/int-ll64.h 里
面,定义如下:

26 typedef unsigned int __u32;

综上所述, dev_t 其实就是 unsigned int 类型,是一个 32 位的数据类型。这 32 位的数据构成了主设备号和次设备号两部分,其中高 12 位为主设备号, 低 20 位为次设备号。因此 Linux系统中主设备号范围为 0~4095(2的12次方),所以在选择主设备号的时候一定不要超过这个范围。在文件 include/linux/kdev_t.h 中提供了几个关于设备号的操作函数(本质是宏),定义如下

6 #define MINORBITS 20
7 #define MINORMASK ((1U << MINORBITS) - 1)
8 
9 #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
10 #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
11 #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))

第 6 行,宏 MINORBITS 表示次设备号位数,一共是 20 位。
第 7 行,宏 MINORMASK 表示次设备号掩码。
第 9 行,宏 MAJOR 用于从 dev_t 中获取主设备号,将 dev_t 右移 20 位即可。
第 10 行,宏 MINOR 用于从 dev_t 中获取次设备号,取 dev_t 的低 20 位的值即可。
第 11 行,宏 MKDEV 用于将给定的主设备号和次设备号的值组合成 dev_t 类型的设备号。

2、设备号查询

在开发板上输入命令

cat /proc/devices

 可以看到分字符设备和块设备,可以看到200设备号没有使用,下面代码编写就用200

 二、注册与注销函数

1、注册与注销函数参数

对于字符设备驱动而言,当驱动模块加载成功以后需要注册字符设备,

同样,卸载驱动模块的时候也需要注销掉字符设备

字符设备的注册和注销函数原型如下所示:

static inline int register_chrdev(unsigned int major, const char *name,

                                                        const struct file_operations *fops)
static inline void unregister_chrdev(unsigned int major, const char *name)

register_chrdev 函数用于注册字符设备,有三个参数

major: 主设备号
name:设备名字,指向一串字符串
fops: 结构体 file_operations 类型指针,指向设备的操作函数集合变量

unregister_chrdev 函数用户注销字符设备,此函数有两个参数,这两个参数含义如下:
major: 要注销的设备对应的主设备号
name: 要注销的设备对应的设备名 

2、注册与注销函数的缺点

用这个函数注册驱动,需要知道那个主设备没有被使用,而且次设备号是被全部占用,还要手动指定设备号,后续会使用更智能的函数

三、代码编写

 1、主设备号和设备名字

在chrdevbase.c编写代码,代码如下

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/fs.h>

#define CHARDEVBASE_MAJOR   200             /*主设备号*/
#define CHARDEVBASE_NAME    "chrdevbase"    /*名字,别重复*/

在这开头部分设置好主设备号和设备名字

 2、设备操作函数结构体

在上面分析register_chrdev 函数用于注册字符设备,有三个参数

第三个参数为操作函数集合,原型是“const struct file_operations *fops“

所以下面要设置部分设备操作函数结构体,代码如下

static struct file_operations chrdevbase_fops=
{
    .owner = THIS_MODULE,
    .open = chrdevbase_open,
    .release = chrdevbase_release,
    .read = chrdevbase_read,
    .write = chrdevbase_write,
};

.是结构体体初始化方式之一,比如“.owner = THIS_MODULE ”指的是对dev_fops 结构体中的owner成员进行初始化,赋值为THIS_MODULE,会执行THIS_MODULE函数编译成模块

其余同理,当应用程序调用 open 函数的时候此函数就会调用 chrdevbase_read 函数,因此要在结构体前面,需要实现对应的各个函数内容供给结构体调用

3、 设备操作函数结构体调用的函数

函数分别如下:

open函数

static int chrdevbase_open(struct inode *inode , struct file *filp)
{
    printk("chrdevbase_open\r\n");
    return 0;
}

 release函数 

static int chrdevbase_release(struct inode *inode , struct file *filp)
{
    printk("chrdevbase_release\r\n");
    return 0;
}

read函数 

static ssize_t chrdevbase_read(struct file *filp , __user char *buf, size_t count, loff_t *ppos)
{
    printk("chrdevbase_read\r\n");
    return 0;
} 

write函数 

static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
    printk("chrdevbase_write\r\n");
    return 0;
} 

4、添加注册和注销字符设备 

 下面设置在驱动入口和出口函数,添加注册和注销字符设备

/* 驱动入口函数 */
static int __init chrdevbase_init(void)
{
    /* 入口函数具体内容 */

    int ret = 0;    /*用来接收返回值*/

    printk("chrdevbase_init\r\n");

    /*注册字符设备*/
    ret = register_chrdev(CHARDEVBASE_MAJOR , CHARDEVBASE_NAME , &chrdevbase_fops);

    if(ret <0)
    {
        printk("chrdevbase init failed\r\n");
    }
    return 0;
}

/* 驱动出口函数 */
static void __exit chrdevbase_exit(void)
{
    /* 出口函数具体内容 */
    printk("chrdevbase_exit\r\n");

    /*注销字符设备*/
    unregister_chrdev(CHARDEVBASE_MAJOR , CHARDEVBASE_NAME);
}

设置一个变量ret用来接收register_chrdev函数注册字符设备返回值,如果小于0说明注册失败

register_chrdev函数的三个参数分别是上面设置的,一一代入即可,同理,注销字符设备也是一样

后续会编写一个应用程序来测试该驱动

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值