字符设备驱动范例,手动注册设备号。代码是ctrl+v来的
#进入nfs目录
cd /disk3/nfs/myfile/chapter01
vim chardev.c
chardev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#define VSER_MAJOR 256
#define VSER_MINOR 0
#define VSER_DEV_CNT 1
#define VSER_DEV_NAME "vser"
static int __init vser_init(void)
{
int ret;
dev_t dev;
dev = MKDEV(VSER_MAJOR,VSER_MAJOR);
ret = register_chrdev_region(dev,VSER_DEV_CNT,VSER_DEV_NAME);
if(ret)
{
goto reg_err;
}
return 0;
reg_err:
return ret;
}
static void __exit vser_exit(void)
{
dev_t dev;
dev = MKDEV(VSER_MAJOR,VSER_MINOR);
unregister_chrdev_region(dev,VSER_DEV_CNT);
}
module_init(vser_init);
module_exit(vser_exit);
MODULE_LICENSE("GPL");
编译
将第5章的Makefile拷贝过来,修改目标文件名
make
#下面为开发板操作
$ cd /mnt/myfile/chapter01
$ insmod chardev.ko
$ cat /proc/devices
Character devices:
1 mem
256 vser
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
可以看到设备已注册成功。
下面为注意事项:
- 设备注册不一定会成功。原因有,设备号冲突。解决方法,改为由内核分配设备号。
- 和应用层不同,内核经常使用goto来处理错误。
__init暗示内核表明该函数仅在初始化期间使用。在模块被装载后,模块装载器会将初始化函数占用的内存释放。
__exit修饰词标记该代码仅用于卸载模块(编译器会将此函数放置在特殊的ELF段)。如果被修饰的模块被直接内嵌到内核或者内核配置不许卸载此模块,那么被标记为__exit的函数将被舍弃。
如果未定义module_exit()函数,模块也无法被卸载。