本文介绍Linux字符设备的静态注册方法,
其中涉及到的模块加载,不了解的可以先参考
构建和运行模块
1. 还是线上源代码:
//memdev.h
# ifndef _MEMDEV_H_
# define _MEMDEV_H_
# ifndef MEMDEV_MAJOR
# define MEMDEV_MAJOR 200
# endif
# ifndef MEMDEV_NR_DEVS
# define MEMDEV_NR_DEVS 2
# endif
# ifndef MEMDEV_SIZE
# define MEMDEV_SIZE 4096
# endif
struct mem_dev{
char * data;
unsigned long size;
};
# endif
//memdev.c
# include < linux / module.h >
# include < linux / types.h >
# include < linux / fs.h >
# include < linux / errno.h >
# include < linux / mm.h >
# include < linux / sched.h >
# include < linux / init.h >
# include < linux / cdev.h >
# include < asm / io.h >
# include < asm / system.h >
# include < asm / uaccess.h >
# include < linux / wait.h >
# include < linux / completion.h >
# include "memdev.h"
MODULE_LICENSE( "Dual BSD/GPL" );
static int mem_major = MEMDEV_MAJOR;
struct mem_dev * mem_devp; /*设备结构体指针*/
struct cdev cdev;
/*文件打开函数*/
int mem_open( struct inode * inode, struct file * filp)
{
printk( "open own file\n" );
return 0 ;
}
/*文件操作结构体*/
static const struct file_operations mem_fops =
{
.owner = THIS_MODULE,
.open = mem_open,
};
/*设备驱动模块加载函数*/
static int memdev_init( void )
{
int result;
int i;
dev_t devno = MKDEV(mem_major, 0 );
/* 静态申请设备号*/
result = register_chrdev_region(devno, 2 , "memdev" );
if (result < 0 )
return result;
/*初始化cdev结构*/
cdev_init( & cdev, & mem_fops);
/* 注册字符设备 */
cdev_add( & cdev, MKDEV(mem_major, 0 ), MEMDEV_NR_DEVS);
return result;
}
/*模块卸载函数*/
static void memdev_exit( void )
{
cdev_del( & cdev); /*注销设备*/
unregister_chrdev_region(MKDEV(mem_major, 0 ), 2 ); /*释放设备号*/
}
module_init(memdev_init);
module_exit(memdev_exit);
# include < linux / module.h >
# include < linux / types.h >
# include < linux / fs.h >
# include < linux / errno.h >
# include < linux / mm.h >
# include < linux / sched.h >
# include < linux / init.h >
# include < linux / cdev.h >
# include < asm / io.h >
# include < asm / system.h >
# include < asm / uaccess.h >
# include < linux / wait.h >
# include < linux / completion.h >
# include "memdev.h"
MODULE_LICENSE( "Dual BSD/GPL" );
static int mem_major = MEMDEV_MAJOR;
struct mem_dev * mem_devp; /*设备结构体指针*/
struct cdev cdev;
/*文件打开函数*/
int mem_open( struct inode * inode, struct file * filp)
{
printk( "open own file\n" );
return 0 ;
}
/*文件操作结构体*/
static const struct file_operations mem_fops =
{
.owner = THIS_MODULE,
.open = mem_open,
};
/*设备驱动模块加载函数*/
static int memdev_init( void )
{
int result;
int i;
dev_t devno = MKDEV(mem_major, 0 );
/* 静态申请设备号*/
result = register_chrdev_region(devno, 2 , "memdev" );
if (result < 0 )
return result;
/*初始化cdev结构*/
cdev_init( & cdev, & mem_fops);
/* 注册字符设备 */
cdev_add( & cdev, MKDEV(mem_major, 0 ), MEMDEV_NR_DEVS);
return result;
}
/*模块卸载函数*/
static void memdev_exit( void )
{
cdev_del( & cdev); /*注销设备*/
unregister_chrdev_region(MKDEV(mem_major, 0 ), 2 ); /*释放设备号*/
}
module_init(memdev_init);
module_exit(memdev_exit);
#Makefile
ifneq ($(KERNELRELEASE),)
obj -m : = memdev.o
else
KERNELDIR ? = /lib /modules /$(shell uname -r) /build
PWD = $(shell pwd)
default :
$(MAKE) -C $(KERNELDIR) M =$(PWD) modules
clean :
rm memdev.mod * module * memdev.o memdev.ko Module. *
endif
ifneq ($(KERNELRELEASE),)
obj -m : = memdev.o
else
KERNELDIR ? = /lib /modules /$(shell uname -r) /build
PWD = $(shell pwd)
default :
$(MAKE) -C $(KERNELDIR) M =$(PWD) modules
clean :
rm memdev.mod * module * memdev.o memdev.ko Module. *
endif
2. 测试
首先先make下,生成memdev.ko
然后insmod memdev.ko生成memdev模块
创建设备节点:sudo mknod /dev/memdev_t c 200 0
接下开使用设备文件
下面是一个测试程序
// memusr.c
# include <stdio.h >
# include <string.h >
int main()
{
FILE *fp0;
/*打开设备文件*/
fp0 = fopen( "/dev/memdev_t", "r+");
if (fp0 == NULL) {
printf( "Open Memdev0 Error!\n");
return - 1;
}
}
编译运行,然后使用dmesg可以看到日志文件里输出
[38439.741816] Hello World!
[38657.654345] Goodbye
[40393.039520] open own file
记得要使用sudo 运行memusr 否则会显示设备打开失败。