本文介绍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 " );
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 " );
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! ");
return -1;
}
}
编译运行,然后使用dmesg可以看到日志文件里输出
[38439.741816] Hello World!
[38657.654345] Goodbye
[40393.039520] open own file
记得要使用sudo 运行memusr 否则会显示设备打开失败。