asm-
(体系结构相关头文件)以上平台无关-------------------------以下平台相关
module_init
和module_exit
宏将函数放在内核的某一段
module_init(initFunc);//模块的入口:完成模块的加载
module_exit(exitFunc);//模块的出口:完成模块的卸载
.ko
模块文件linux内核源码默认装在/lib/modules/$(shell uname -r)/build
目录下
把一个模块独立于内核在外面编译再动态加载进去
make ... modules
符号:全局变量和函数
Linux内核采用的是以模块化形式管理内核代码。内核中的每个模块相互之间是相互独立的,也就是说A模块的全局变量和函数,B模块是无法直接访问的。如果想要访问别的模块的变量或函数,就需要用到全局符号表。
Linux内核会把符号放在一个表里面,在编译的时候回去表里面找对应的全局变量和函数的符号。
Ubuntu中
/usr/src/linux-headers-XXXXX-generic/Module.symvers
“XXXXX
是内核版本相当于可以在多个文件中共享的变量或函数,在一个文件中定义,可以在其他文件中使用
在程序中使用下面这个宏导出变量或函数符号,即便是static限定(作用域为当前程序文件)的变量也可以被导出
EXPORT_SYMBOL(变量或函数);
#include
原型:
module_param(name,type,perm);//声明传类型为type的参数name
module_param_arry(name,type,num_point,perm);//传一个元素个数为num_point的数组,数组元素类型为type
module_param_string (name,string,len,perm);//传长度为len的字符串
参数:
加入在程序中声明传递的参数为 var
module_param(var,int,0664);
在命令行加载模块时传参
insmod hello.ko var=1
Sysfs:内核给一些重要的资源创建的目录或者文件,每个模块会在/sys/module
下创建个同名的文件夹
文件夹里的parameters目录下就放着我们传入的参数
用来区分设备的整型数编号
/proc目录:processing进程信息
int register_chrdev_region(dev_t from,unsigned count,const char *name);
功能:注册一系列设备号(主设备号只有一个,但是可以有一系列次设备号)
参数:
申请从from到from+count-1的设备号
int unregister_chrdev_region(dev_t from,unsigned count);
功能:注销设备号
参数:同上
注销从from到from+count-1的设备号
例子:
#include
#include
#include
#include
static int major=250;
static int minor=0;
static dev_t devno;
static int hello_init(void)
{
devno=MKDEV(major,minor);//宏定义:用主设备号和次设备号生成设备号,实际就是(major<<20)|minor
int result=register_chrdev_region(devno,1,"test");//注册设备号
...
}
static void hello_exit(void)
{
unregister_chrdev_region(devno,1);//注销设备号
...
}
module_init(hello_init);
module_exit(hello_exit);
对于每一个字符设备,内核使用一个结构体cdev来维护。
块设备叫gn_disk
网络设备叫net_device
#include
#include
#include
# include
int gpio_request(unsigned gpio, const char *label);
void gpio_free(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
int gpio_direction_input(unsigned gpio);
int gpio_set_value(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
ioctl 是设备驱动程序中设备控制接口函数,一个字符设备驱动通常会实现设备打开、关闭、读、写等功能,在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。
#include
int ioctl(int fd,unsigned long cmd,...);
参数:
...
在c语言中,很多时候都被理解成可变参数。返回值:
long (*unlocked_ioctl)(struct file* file,unsigned int cmd,unsigned long arg);
参数:
返回值: