linux驱动:(10)申请字符类设备号

目录

字符设备和杂项设备区别

注册字符类设备号两个方法 

dev_t类型

注销设备号

静态分配和动态分配例子


字符设备和杂项设备区别

  • 杂项设备的主设备号是固定的,固定为 10,那么我们要学习的字符类设备就需要自己或
    者系统来给我们分配了。
  • 杂项设备可以自动生成设备节点,字符设备需要我们自己生成设备节点。

注册字符类设备号两个方法 

  • 静态分配一个设备号
    • int register_chrdev_region(dev_t,unsigned,const char *)
      • 参数1:设备号的起始值。类型是 dev_t 类型
      • 参数2:次设备号的个数
      • 参数3:设备的名称,可以用 cat /proc/devices 命令来查看
      • 返回值:成功返回0,失败返回非0
    • 需要明确知道我们系统里面哪些设备号没有用到
  • 动态分配一个设备号
    • int alloc_chrdev_region(dev_t ,unsigned,const char *);
      • 参数1:保存生成的设备号。类型是 dev_t 类型
      • 参数2:我们请求的第一个设备号,通常是0
      • 参数3:连续申请设备号的个数
      • 参数4:设备的名称,可以用 cat /proc/devices 命令来查看
      • 返回值:成功返回0,失败返回负数
    • 使用动态分配优先使用255-234

dev_t类型

定义在types.h里的,用来保存设备号的,是一个32位数

高12位保存主设备号,低12位保存次设备号,

typedef _u32 _kernel_dev_t
typedef _kernel_dev_t dev_t

在linux中宏定义来操作设备号

  • #define MINORBITS 20
    • 次设备号的位数为20位
  • #define MINORMASK ((1U << MINORBITS) - 1)
    • 次设备号的掩码
  • #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS )
    • 在dev_t里面获取我们的主设备号
  • #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
    • 在dev_t里面获取我们的次设备号
  • #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
    • 将主设备号和次设备号组成一个dev_t类型
    • ma:主设备号
    • mi:次设备号

注销设备号

  •  unregister_chrdev_region(dev_t,unsigned);
    • 参数1:分配设备号的起始地址。类型是 dev_t 类型
    • 参数2:连续申请设备号的个数

静态分配和动态分配例子

如果加载内核的时候不将主次设备号参数传入,就动态分配,如果传入的话就静态分配

步骤

  • 新建一个parameter.c和一个Makefile
  • 编辑parameter.c
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/miscdevice.h>
    #include <linux/fs.h>
    #include <linux/kdev_t.h>
    #include <linux/uaccess.h>
    
    #define DEVICE_NUMBER 1
    #define DEVICE_SNAME "schrdev" 
    #define DEVICE_ANAME "achrdev" 
    #define DEVICE_MINOR_NUMBER 0
    
    static int major_num,minor_num;
    module_param(major_num,int,S_IRUSR);
    module_param(minor_num,int,S_IRUSR);
    
    static int misc_init(void)
    {
        dev_t dev_num;
        int ret;
        if(major_num)
        {    
            printk("major_num= %d\n",major_num);
            printk("minor_num= %d\n",minor_num);
            dev_num = MKDEV(major_num,minor_num);
            ret = register_chrdev_region(dev_num,DEVICE_NUMBER ,DEVICE_SNAME );
            if(ret<0)
            {
                printk("register_chrdev_region error\n");
            }
            printk("register_chrdev_region ok\n");
        }
        else 
        {
            ret = alloc_chrdev_region(&dev_num,DEVICE_MINOR_NUMBER,DEVICE_NUMBER,DEVICE_ANAME);
            if(ret<0)
            {
                printk("alloc_chrdev_regionerror\n");
            }
            printk("alloc_chrdev_regionok\n");
            major_num = MAJOR(dev_num);
            minor_num= MINOR(dev_num);
            printk("major_num= %d\n",major_num);
            printk("minor_num= %d\n",minor_num);
        }
        return 0;
    }
     
    static void misc_exit(void)
    {
        unregister_chrdev_region(MKDEV(major_num,minor_num),DEVICE_NUMBER);
        printk("misc goodbye");
    }
     
    module_init(misc_init);
    module_exit(misc_exit);
     
    MODULE_LICENSE("GPL");
  • 编辑Makefile
    obj-m +=parameter.o
    KDIR:=自己的linux内核源码根目录路径
    PWD?=$(shell pwd)
    all:
        make -C $(KDIR) M=$(PWD) modules
  • 配置arm和交叉编译环境编译成模块放到开发板中
  • 验证静态分配步骤
    • 输入 cat /proc/devices 查看哪些主设备号可以用
    • 输入 insmod parameter.ko major_num = 9 加载驱动模块
    • 就会打印出主次设备号,次设备号一般会默认为0
  • 验证动态分配步骤
    • 输入 insmod parameter.ko 加载驱动模块
    • 就会打印出主次设备号,主设备号一般会优先使用255-234,次设备号一般会默认为0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值