字符设备驱动程序之申请设备号

Linux 内核中驱动程序是通过内核模块编码的形式插入到内核中

Linux内核将外设分为三类

1、字符设备:应用程序与该设备之间数据交互形式是“字节流”---一般只能顺序访问

2、快设备:应用程序与该设备之间数据交互以块为单位---一般支持随机访问

3、网络设备:应用程序与该设备之间数据交互建立在某种协议栈的基础上

Linux内核中采用struct cdev类型的对象来表示一个字符设备,因此内核中与多少字符设备驱动程序,就有多少个struct cdev类型的对象

Linux内核采用一种链式数据结构来管理这些struct cdev类型的对象

每一个struct cdev对象都有唯一的身份标识--------设备号

那么什么是设备号呢?

设备号是一个32位的整数(dev_t 类型),其中高12位被称为主设备号,低20位被称为次设备号。

内核提供了三个宏:

1、MKDEV(主设备号,次设备号)   -----组合成完整的设备号

2、MAJOR(完整设备号)                  -------从完整设备号中分离主设备号

3、MINOR(完整设备号)                   -------从完整设备号中分离次设备号

主设备号:表示哪一类设备,同类设备的驱动程序逻辑是一样的

次设备号:表示该类设备中的哪一个设备。

编写字符设备驱动程序的基本步骤大体如下

insmod时:

1、创建一个struct cdev类型对象

(1)、全局变量定义

(2)、动态分配

2、(向内核申请)为该对象指定一个空闲的设备号(该设备号未被其他设备占用),作为struct cdeb对象的身份标识。

申请设备号:register_chrdev_regionalloc_chrdev_region

3、为struct cdev中的某些成员设置初值        cdev_init

4、将struct cdev 对象插入到内核管理该类对象的链式数据结构中        dev_add

rmmod时:

1、将本字符设备对应的struct cdev的设备号归还给内核        unregister_chrdev_region

2、从内核管理的struct cdev 对象的链式数据结构中移除本字符设备对应的struct cdev对象  cdev_del

3、如果struct cdev对象的空间是动态分配的,应释放其占用的内存空间

其中申请设备号可以手动分配也可以动态分配,内核提供了两个函数

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

功能:手动分配设备号,先验证设备号是否被占用,若没有则申请占用该设备号

参数:from:自己指定的设备号

           count:申请的设备数量

            name:在/proc/devices文件中对于的设备名称,方便用户查询主设备号

(可通过cat   /proc/devices命令查询)

返回值:成功0,失败负数

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

功能:动态分配设备号,查询内核里未被占用的设备号,如果找到则占用

参数:dev:分配设备号成功后用来存放分配的设备号

            baseminior:起始的次设备号,一般为0

            count:申请的设备数量

             name :在/proc/devices文件中对于的设备名称,方便用户查询主设备号

返回值:成功0,失败负数

下面是具体的申请设备号的代码实现

#include <linux/module.h>
#include <linux/kernel.h>
int major = 0;//主设备号
int minor = 0;//次设备号
int devcnt = 1;     //申请设备数量

struct cdev mydev;

static int __init hello_init(void)//入口函数
{
        dev_t devno = MKDEV(major,minor);
        int ret = 0 ;
        ret = register_chdev_region(devno,devcnt,"myfirstdev");
        if(ret)
        {
            ret=alloc_chdev_region(&devno,minor,devcnt,"myfirstdev");
            if(ret)
            {
                printK("alloc_chdev_region is failed\n");
                return -1;
            }
            major = MAJOR(devno);

        }

        return 0;
}

static void __exit hello_exit(void)//出口函数
{
    dev_t devno = MKDEV(major,minor);
    unregister_chrdev_region(devno,devcnt);
    cdev_del(&mydev);

}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值