重新整理编写字符驱动设备的逻辑
在尚未升级到2.6接口的老代码中,不使用cdev接口,而是使用register_chrdev来注册字符设备,我今天才知道……还想说这个方法好理解的多
所以现在我也得编写符合2.6接口的字符驱动设备,首先来进行逻辑的整理.
1.当模块在挂载时,使用了module_init()函数,也就调用了my_init _module函数,所以在这个函数中我们要做的事是:
(1) 注册设备,得到设备号,主设备号以及副设备号,然后输出
(2) 创建cdev实例并初始化,主要是用它记录我的fileoperations,cdev_add函数将字符设备加入到内核的字符设备数组中
(3) 初始化用于保存write输入的字符串的msg[]数组
2.当模块生成节点,用mymoduleCall打开节点时,也就调用了我自己写的open,read,write和release函数
3.当模块被卸载,使用了module_exit()函数,也就调用了my_cleanup_module函数,在这个函数中,主要要做的事就是将刚注册的设备注销,以及删除cdev注册在设备表里的实例。
CDEV的理解
整个过程和2.6以前接口的编程唯一不同的就是用了cdev,所以这里说一说cdev的理解
cdev应该是一个存储char_device的一些描述信息的结构体,里面存储的owner啊,file operations啊等一系列东西,而以前的代码是直接将这个在注册的时候告诉系统的,我想加入cdev只是为了可以加更多的信息吧。
同时,想要进行cdev_add必须有设备的dev_t类型的设备号,也就是主设备号和次设备号的综合体,所以这也就决定了我们使用malloc_chrdev_region这个函数来进行注册,同时动态得到一个dev的值,在通过MAJOR(dev)函数得到主设备号,通过MINOR(dev)得到次设备号,并输出,我们才能知道mknod时的主、次设备号。
这样,my_init_module()函数的里涉及的代码就能够理解了。
现在看代码就很清楚了
mymodule.c
/*module indispensable*/
#include
#include
#include
/*used by file operations*/
#include
/*copy_to_user©_from_user*/
#include
/*used by cdev*/
#include
int my_init_module(void);
void my_cleanup_module(void);
static intmy_open(struct inode *, struct file *);
static intmy_release(struct inode *, struct file *);
static ssize_t my_read(struct file *, char *, size_t,loff_t *);
static ssize_t my_write(struct file *, const char *, size_t, loff_t *);
#define BUF_LEN 80
char msg[BUF_LEN];
int size=0;
static intDevice_Open = 0; //OPEN counts
/*cdev is a kind of inode used to savethe description of char_dev*/
static structcdev *my_cdev;
/*used to save the Device number both ofMajor and Minor*/
dev_t dev;
int Major=0;
int Minor=0;
/*file operarions struct*/
struct file_operations my_fops={
.read=my_read,
.write=my_write,
.open=my_open,
.release=my_release
};
int my_init_module(void){
int result;
printk("Hello! It is from [mymodule pro] /n");
/*&dev can get the return device number*/
result=alloc_chrdev_region(&dev,0, 1, "char_dev");
if(result<0){
printk("char_dev:alloc_chrdev_region() failed! /n");
}
Major=MAJOR(dev);
Minor=MINOR(dev);
printk("Major:%d,Minor:%d /n",Major,Minor);
/*create the cdev object and initation*/
my_cdev=cdev_alloc();
if(my_cdev == NULL) {
printk("char_dev: cdev_alloc() failed! /n");
unregister_chrdev_region(dev,1);
return -ENOMEM;
}
cdev_init(my_cdev,&my_fops);
my_cdev->owner=THIS_MODULE;
result=cdev_add(my_cdev,dev,1);
if(result<0){
printk("cdev_add failed! /n");
unregister_chrdev_region(dev,1);
cdev_del(my_cdev);
return result;
}
memset( msg, 0, sizeof(msg));
printk("char_dev: device init completed! /n");
return 0;
}
void my_cleanup_module(void){
printk("mymodule says Good Bye to you!/n");
unregister_chrdev_region(dev,1);
cdev_del(my_cdev);
printk("char_dev: device removed! /n");
}
static intmy_open(struct inode *inode,struct file *filp){
if(Device_Open)
return -EBUSY;
Device_Open++;
return 0;
}
static intmy_release(struct inode *inode,struct file *filp){
Device_Open--;
return 0;
}
static ssize_t my_read(struct file *filp,char*buffer,size_t length,loff_t *offset){
//msg_ptr=(char *)filp->private_data;
printk("You are reading! /n");
if((msg != NULL) && (length > 0)) {
size =length < BUF_LEN ? length : BUF_LEN;
if(copy_to_user(buffer,msg,length))
return -ENOMEM;
}
return size;
}
static ssize_t my_write(struct file *filp,constchar *buffer,size_t length,loff_t *offset){
printk("You are writing! /n");
printk("buffer is %s /n",buffer);
//msg_ptr=(char *)filp->private_data;
if((buffer != NULL) && (length > 0)) {
size =length < BUF_LEN ? length : BUF_LEN;
if(copy_from_user(msg, buffer, size))
return -ENOMEM;
else {
printk("char_dev : %d bytes written! /n",size);
}
}
return size;
}
MODULE_LICENSE("GPL");
module_init(my_init_module);
module_exit(my_cleanup_module);
用来使用节点的mymoduleCall.c
#include
#include
#include
#include
#define BUF_LEN 80
int main(){
int fd;
char input[BUF_LEN];
char buffer[BUF_LEN];
memset(input,0,sizeof(input));
memset(buffer,0,sizeof(buffer));
fd=open("mymodule0", O_RDWR);
if(fd < 0){
printf("Opening failed! /n");
exit(fd);
}
printf("Opening succeed! /n");
printf("Begin to write...PLEASE INPUT: /n");
scanf("%s",&input);
//memcpy(input,"hahaha,this will be written intokernel",80);
write(fd,input,120);
printf("Begin to read... /n");
read(fd,buffer,120);
printf("buffer:%s /n",buffer);
close(fd);
return 0;
}
Makefile.c:
KERNELDIR := /lib/modules/`uname -r`/build
obj-m := mymodule.o
module:
make -C$(KERNELDIR) M=`pwd` modules
insmodmymodule.ko
clean:
rm -fr mymodule.omymodule.ko mymodule.mod.* mymodule0
call:
gcc -omymoduleCall mymoduleCall.c
chmod +xmymoduleCall
效果截图:
[root@KathyShaw test8]# ./mymoduleCall
Opening succeed!
Begin to write...PLEASE INPUT:
KATHY SHAW
Begin to read...
buffer:KATHY
内核信息:
Hello! It is from [mymodule pro]
Major:249,Minor:0
char_dev: device init completed!
You are writing!
buffer is KATHY
char_dev : 80 bytes written!
You are reading!
mymodule says Good Bye to you!
char_dev: device removed!