重新理解字符设备驱动的编写,针对2.6接口

重新整理编写字符驱动设备的逻辑

在尚未升级到2.6接口的老代码中,不使用cdev接口,而是使用register_chrdev来注册字符设备,我今天才知道……还想说这个方法好理解的多

 

所以现在我也得编写符合2.6接口的字符驱动设备,首先来进行逻辑的整理.

1.当模块在挂载时,使用了module_init()函数,也就调用了my_init _module函数,所以在这个函数中我们要做的事是:

(1)  注册设备,得到设备号,主设备号以及副设备号,然后输出

(2)  创建cdev实例并初始化,主要是用它记录我的fileoperationscdev_add函数将字符设备加入到内核的字符设备数组中

(3)  初始化用于保存write输入的字符串的msg[]数组

2.当模块生成节点,用mymoduleCall打开节点时,也就调用了我自己写的open,read,writerelease函数

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)函数得到主设备号,通过MINORdev)得到次设备号,并输出,我们才能知道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!

你可能感兴趣的:(Linux配置)