1.模块传参
在应用程序中,可以通过main函数向其中传参数,实际上对于加载模块的时候还可以通过insmod命令传参数。在linux根目录,使用命令”vim include/linux/moduleparam.h” 中包含了向模块传参数的函数,这个功能是集成的,在任何linux系统中都可以使用。参数传递有两个函数,分别是函数module_param和module_param_array。函数module_param支持单个参数传递,在头文件中,如下所示:
#define module_param(name, type, perm)
module_param_named(name, name, type,perm)
name,模块参数名;type,模块参数数据类型(支持int long short uint ulong ushort类型);perm,模块参数的访问权限(S_IRUSR参数表示所有文件所有者可读)。
#define module_param_array(name, type,nump, perm)
module_param_array_named(name, name, type,nump,perm)
nump,保存参数的数量。参数perm表示此参数在sysfs文件系统中所对应的文件节点的属性,其权限在“include/linux/stat.h“中。对于常用的参数:
#define S_IRUSR 00400 文件所有者可读
#define S_IWUSR 00200 文件所有者可写
#define S_IXUSR 00100 文件所有者可执行
#define S_IRGRP 00040 与文件所有者同组的用户可读
#define S_IROTH 00004 与文件所有者不同组的用户可读
2.静态申请
字符设备的注册需要申请设备号-设备注册-生成设备节点;申请设备号分为静态申请(register_chrdev_region)以及动态申请(alloc_chrdev_region)。
静态申请就是主设备号是程序员手动分配了,动态申请是系统给分配的。对于静态申请register_chrdev_region()是提前知道设备的主次设备号,再去申请设备号。在linux目录,使用命令”vim include/linux/fs.h”查找extern int register_chrdev_region(dev_t, unsigned, const char *)
,对于参数dev_t有几个参数以及函数为它服务。在“include/linux/cdev.h”中,在cdev结构体重有一个专门的参数dev_t dev,cdev类型是字符设备的描述结构,其中设备号必须用dev_t类型来描述,高12位为主设备号,低20位为次设备号。在”include/linux/kdev_t.h”中,有一些专门用来处理dev_t数据类型的宏定义:
MAJOR(dev),是对dev 操作,提取高12 位主设备号;
MINOR(dev),是对dev 操作,提取低20 位数次设备号;
MKDEV(ma,mi),就是对主设备号和低设备号操作,合并为dev 类型。
3.动态申请
在linux根目录,使用命令”vim include/linux/fs.h”查找动态申请函数extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *)
dev,存放返回的设备号;参数unsigned,一般为0;参数unsigned,次设备号连续编号范围;参数const char ,设备名称;函数调用成功则返回0,反之返回-1。
4.程序清单
#include <linux/init.h>
#include <linux/module.h>
/*定义module_param module_param_array的头文件*/
#include <linux/moduleparam.h>
/*定义module_param module_param_array中perm的头文件*/
#include <linux/stat.h>
/*三个字符设备函数*/
#include <linux/fs.h>
/*MKDEV转换设备号数据类型的宏定义*/
#include <linux/kdev_t.h>
/*定义字符设备的结构体*/
#include <linux/cdev.h>
#define DEVICE_NAME "test"
#define DEVICE_MINOR_NUM 2
#define DEV_MAJOR 0
#define DEV_MINOR 0
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("flywang");
int numdev_major = DEV_MAJOR;
int numdev_minor = DEV_MINOR;
/*输入主设备号*/
module_param(numdev_major,int,S_IRUSR);
/*输入次设备号*/
module_param(numdev_minor,int,S_IRUSR);
static int test_init(void)
{
int ret = 0;
dev_t num_dev;
printk(KERN_EMERG "numdev_major is %d!\n",numdev_major);
printk(KERN_EMERG "numdev_minor is %d!\n",numdev_minor);
if(numdev_major){
num_dev = MKDEV(numdev_major,numdev_minor);
/*静态注册设备号*/
ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME);
}
else{
/*动态注册设备号*/
ret = alloc_chrdev_region(&num_dev,numdev_minor,DEVICE_MINOR_NUM,DEVICE_NAME);
/*获得主设备号*/
numdev_major = MAJOR(num_dev);
printk(KERN_EMERG "adev_region req %d !\n",numdev_major);
}
if(ret<0){
printk(KERN_EMERG "register_chrdev_region req %d is failed!\n",numdev_major);
}
printk(KERN_EMERG "test_init!\n");
return 0;
}
static void test_exit(void)
{
printk(KERN_EMERG "test_exit!\n");
unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);
}
module_init(test_init);
module_exit(test_exit);