Embedded LINUX driver learning 3. Character device (device number application)

1. Device number application function: alloc_chrdrv_region()

1.1 Function header file

//头文件位置:include/linux/fs.h
//函数实现:fs/char_dev.c
#include <linux/fs.h>
int alloc_chrdev_region(dev_t *dev, unsigned baseminor,\
                        unsigned count,const char *name);

1.2 Function function:

Obtain a device number from the kernel and save it in dev;

1.3 Function parameters:

dev: used to save the device number allocated by the kernel (need to use a global static variable, that is: available in the current original file);
baseminor: minor device number, generally filled with 0, that is: the kernel allocates the minor device number from 0
count: minor device Number of numbers;
name: Specify a name, equivalent to a label, which can be viewed by executing cat /proc/devices in the future

1.4 Use of key macro functions

//获取 主、次设备号使用的宏
//定义位置:include/linux/kdev_t.h
#include <linux/kdev_t.h>  //头文件在<linux/fs.h>中已包含
#define MINORBITS       20                    //20位
#define MINORMASK       ((1U << MINORBITS) - 1)     //0~19,20个1,
//Linux系统中,通过一个32bit位的无符号整数表示驱动程序的设备号,
//其中高12位表示主设备号,低20位表示次设备号;
//unsigned int 一共4个字节32位,

//MAJOR(dev)根据设备号获取主设备号,即:将设备号右移20位
#define MAJOR(dev)      ((unsigned int) ((dev) >> MINORBITS))

//MINOR(dev)根据设备号获取次设备号,即:用设备号和20bit位的1逻辑与运算。
#define MINOR(dev)      ((unsigned int) ((dev) & MINORMASK))

//MKDEV(ma,mi) //根据主、次设备号,获取 设备号
//ma为主设备号,mi为次设备号。
#define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))

2. Release device number function

2.1 Function header file

//头文件位置:include/linux/fs.h
//函数实现:fs/char_dev.c
#include <linux/fs.h>
void unregister_chrdev_region(dev_t from, unsigned count)

1.2 Function function:

Release a device number

1.3 Function parameters:

from: the device number to be released;
count: the number of minor device numbers (release as many as you apply for);

3. Examples:

// vim dev_num.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
static dev_t dev_num;
static int dev_init(void){
    
    
    alloc_chrdev_region(&dev_num,0,1,"dev_test");
    printk("%s , 申请的设备号:%d,主设备号:%d,次设备号:%d\n",\
            __func__,dev_num,MAJOR(dev_num),MINOR(dev_num));
    /*
        __func__ : 打印当前函数名
    */
    return 0;
}
static void dev_exit(void){
    
    
    unregister_chrdev_region(dev_num,1);
    printk("%s , 释放设备号:%d\n",__func__,dev_num);

}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
//:wq
//make
// 将生成的驱动模块文件dev_num.ko 拷贝到下位机
//以下所有操作均在下位机执行
//echo 10 >/proc/sys/kernel/printk
//insmod dev_num.ko    //加载模块,打印如下信息: 
//             dev_init , 申请的设备号:255852544,主设备号:244,次设备号:0
//在下位机执行:cat /proc/devices 可以看到主设备号和对应的name
/*
....省略更多.......
189 usb_device
204 ttySAC
216 rfcomm
244 dev_test     //这个是内核为dev_num模块分配的主设备号和我们定义的name.
245 roccat
246 BaseRemoteCtl
247 ttyGS      
....省略更多.......
*/           

Guess you like

Origin blog.csdn.net/weixin_47273317/article/details/107743401