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
....省略更多.......
*/