(1) vi first_drv.c(模块加载模板)
int first_drv_init(void)
{
return 0;
}
void first_drv_exit(void)
{
}
module_init(first_drv_init);
module_exit(first_drv_exit);
make得到
error: type defaults to 'int' in declaration of 'module_init' [-Werror=implicit-int]
error: type defaults to 'int' in declaration of 'module_exit' [-Werror=implicit-int]
于是增加 头文件 #include <linux/module.h>,make得到
WARNING: modpost: missing MODULE_LICENSE() in /home/embedfire/linux/nfs/3/first_drv.o
于是增加 MODULE_LICENSE("GPL"); make通过。
完整代码为:
#include <linux/module.h>
int first_drv_init(void)
{
return 0;
}
void first_drv_exit(void)
{
}
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");
在板子上操作:
# insmod first_drv.ko
first_drv: loading out-of-tree module taints kernel.
# lsmod
first_drv 669 0 - Live 0xbf000000 (O)
# rmmod
注意:vi编辑时,dd删除光标所在行后会上移,DD删除后会留下空白行。
(2) vi first_drv.c(file_operations)
#include <linux/module.h>
static int first_drv_open(struct inode *inode,struct file *file)
{
return 0;
}
static ssize_t first_drv_write(struct file *file,const char __user *buf,size_t len,loff_t *ppos)
{
return 0;
}
static struct file_operations first_drv_fops = {
.open = first_drv_open,
.write = first_drv_write,
};
static int first_drv_init(void)
{
printk("first_drv_init");
return 0;
}
static void first_drv_exit(void)
{
printk("first_drv_exit");
}
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");
make得到
error: variable 'first_drv_fops' has initializer but incomplete type
error: unknown field 'open' specified in initializer
error: unknown field 'write' specified in initializer
增加头文件#include <linux/fs.h>,make得到
warning: 'first_drv_fops' defined but not used [-Wunused-variable]
在板子上操作为:
# insmod first_drv.ko
# lsmod
first_drv 854 0 - Live 0xbf008000 (O)
# rmmod first_drv
first_drv_init
first_drv_exit
怎么回事,在rmmod时一起打印?printk("first_drv_init");和printk("first_drv_exit");改为printk("first_drv_init\n");和printk("first_drv_exit\n");
呵呵,没有回车则字符串会一起缓存再显示到屏幕。
最后的代码为:
#include <linux/fs.h>
#include <linux/module.h>
static int first_drv_open(struct inode *inode,struct file *file)
{
printk("first_drv_open\n");
return 0;
}
static ssize_t first_drv_write(struct file *file,const char __user *buf,size_t len,loff_t *ppos)
{
printk("first_drv_write\n");
return 0;
}
static struct file_operations first_drv_fops = {
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
};
static int first_drv_init(void)
{
printk("first_drv_init\n");
return 0;
}
static void first_drv_exit(void)
{
printk("first_drv_exit\n");
}
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");
注意:1、.owner = THIS_MODULE有什么用?感觉有无影响不大。Linux kernel 笔记 (39)——"THIS_MODULE" | 我的站点 (nanxiao.me)
2、file_operations结构体的初始化为什么加“点”?C99标准,可以不用按结构体成员顺序赋值。linux内核结构体初始化时出现的.owner = THIS_MODULE是什么?-CSDN博客
3、# lsmod出现的first_drv 854 0 - Live 0xbf00c000 (O)中,854不是设备号。
-
模块名称:
first_drv
是模块的名称,表示这是一个名为 "first_drv" 的内核模块。 -
大小:
854
表示该模块占用的内核空间大小,单位通常是字节(bytes)。 -
使用计数:
0
表示没有其他模块或系统组件正在使用这个模块。使用计数通常会随着模块被引用或使用而增加。 -
依赖项:
-
表示该模块没有任何依赖的其他模块。如果模块依赖于其他模块,这里会列出它们的名称。 -
状态:
Live
表示模块当前正在运行,即已经成功加载到内核中。 -
内存地址:
0xbf00c000
是模块在内核内存空间中的地址,这表明模块已被映射到这个地址进行执行。 -
加载选项:
(O)
表示模块是以O
或opt
(可选)标志加载的。这意味着在加载模块时可能指定了某些选项,但具体选项没有在输出中显示。
(3) vi first_drv.c(字符设备驱动注册)
#include <linux/fs.h>
#include <linux/module.h>
static int first_drv_open(struct inode *inode,struct file *file)
{
printk("first_drv_open\n");
return 0;
}
static ssize_t first_drv_write(struct file *file,const char __user *buf,size_t len,loff_t *ppos)
{
printk("first_drv_write\n");
return 0;
}
static struct file_operations first_drv_fops = {
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
};
static int first_drv_init(void)
{
register_chrdev(250,"first_drv",&first_drv_fops);
printk("first_drv_init\n");
return 0;
}
static void first_drv_exit(void)
{
unregister_chrdev(250,"first_drv");
printk("first_drv_exit\n");
}
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");
make通过。
# insmod first_drv.ko
first_drv_init
# lsmod
first_drv 1313 0 - Live 0xbf01c000 (O)
# cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
29 fb
89 i2c
90 mtd
116 alsa
128 ptm
136 pts
153 spi
180 usb
189 usb_device
204 ttySAC
249 hidraw
250 ttySDIO
251 rpmb
252 watchdog
253 rtc
254 gpiochip
???250不是first_drv,已经先被占领了。first_drv.c中修改为111,再试。有了。
111 first_drv
测试下驱动吧,vi firstdrvtest.c
void main(void)
{
int fd;
fd = open("/dev/xxx",O_RDWR);
if(fd<0)
printf("can't open /dev/xxx !\n");
}
make得到
warning: implicit declaration of function 'open' [-Wimplicit-function-declaration]
error: 'O_RDWR' undeclared (first use in this function)
warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
于是 man 2 open,得到并在.c中添加头文件#include <sys/types.h>,#include <sys/stat.h>,#include <fcntl.h>后编译还有警告:
warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
于是man 3 printf,得到并在.c中添加头文件 #include <stdio.h>后编译通过。
在板子上测试 :
# ./firstdrvtest
can't open /dev/xxx !
没有此文件,用mknod添加此文件Usage: mknod [-m MODE] NAME TYPE [MAJOR MINOR]
mknod /dev/xxx c 111 0
再试,成功打开设备文件,现在可以使用此驱动的操作函数了。
# ./firstdrvtest
first_drv_open