下面是用了自定义char_dev结构体,利用container_of来指向。内存空间用kmalloc来申请。练手用的。
#include<linux/module.h>
#include<linux/init.h>
#include<linux/errno.h>
#include<linux/fs.h>
#include<asm/uaccess.h>
#include<linux/kernel.h>//container_of
#include<linux/device.h>
#include<linux/cdev.h>
#include<linux/types.h>
#include<linux/slab.h>//kmalloc
//#include<asm/device.h>
MODULE_LICENSE("Dual BSD/GPL");
#define SIZE 1024
dev_t devno;//设备号
struct cdev cdev;
struct class *char_class;
struct char_dev *dev;
/*char_dev结构体中定义了cdev,方便多设备时cdev指定;内核空间data;空间大小size*/
struct char_dev//dev结构,未包含量子qset什么的。
{
struct cdev cdev;
char *data;//定义data内存空间然后kmalloc分配
unsigned long size;
/*struct char_qset *data;
unsigned long size;*/
//unsigned char data[size];//这个还是静态分配,和上次一样
};
/*struct char_qset//量子集qset结构
{
void **data;
struct char_qset *next;
}*/
//open
int char_open(struct inode *inode,struct file *filp)
{
dev=container_of(inode->i_cdev,struct char_dev,cdev);
filp->private_data=dev;
//dev->size=SIZE;
return 0;
}
//release
int char_release(struct inode *inode,struct file *filp)
{
return 0;
}
//read
ssize_t char_read(struct file *filp,char *buf,size_t count,loff_t *f_pos)
{
dev=filp->private_data;
if(*f_pos>=dev->size){
*f_pos=dev->size;
return 0;
}
if(*f_pos+count>dev->size)
count=dev->size-*f_pos;
if(copy_to_user(buf,dev->data+*f_pos,count)){
printk(KERN_WARNING"copy_to_user error!\n");
return -EFAULT;
}else{
*f_pos+=count;
}
return count;
}
//write
ssize_t char_write(struct file *filp,const char*buf,size_t count,loff_t *f_pos)
{
dev=filp->private_data;
if(*f_pos>=dev->size){
*f_pos=dev->size;
return 0;
}
if(*f_pos+count>dev->size)
count=dev->size-*f_pos;
if(copy_from_user(dev->data+*f_pos,buf,count)){
printk(KERN_WARNING"copy_from_user error!\n");
return -EFAULT;
}else{
*f_pos+=count;
}
return count;
}
//llseek,比上一篇多实现了lseek,来控制偏移量
loff_t char_llseek(struct file *filp,loff_t offset,int whence)
{
loff_t newpos;
switch(whence){
case 0://SEEK_SET
newpos=offset;
break;
case 1://SEEK_CUR
newpos=filp->f_pos+offset;
break;
case 2://SEEK_END
newpos=dev->size-1+offset;
break;
default://can't happen
return -EINVAL;
}
filp->f_pos=newpos;
return newpos;
}
//file_operations,如果不声明上面的open等,必须这个放它们后面
struct file_operations char_fops=
{
.owner=THIS_MODULE,
.open=char_open,
.release=char_release,
.read=char_read,
.write=char_write,
.llseek=char_llseek,//多了这个
};
//加载
static int char_init(void)
{
int result;
/*alloc_chrdev_region(dev_t *dev,第一个次设备号,设备个数,名字)*/
result=alloc_chrdev_region(&devno,0,1,"char_module");
if(result<0){
printk(KERN_WARNING"alloc_chrdev_region error!\n");
return -ENODEV;
}
printk(KERN_INFO"major:%d,minor:%d",MAJOR(devno),MINOR(devno));
/*下面来分配内核空间,这个必须在cdev_init之前申请空间,会用到,不然虽然编译没错误,测试时会出错
可以用kzalloc来代替下面的kmalloc和memset,申请后初始化。
dev=kzalloc(sizeof(struct char_dev),GFP_KERNEL)
*/
/*因为dev是结构体指针,所以要申请空间,如果是struct char_dev dev,则不必*/
dev=kmalloc(sizeof(struct char_dev),GFP_KERNEL);//申请dev结构体空间
if(dev==NULL){
printk(KERN_WARNING"kmalloc error!\n");
return -ENOMEM;
}
memset(dev,0,sizeof(struct char_dev));//初始化空间
/*dev->data申请空间*/
dev->size=SIZE;
dev->data=kmalloc(SIZE,GFP_KERNEL);
if(dev->data==NULL){
printk(KERN_WARNING"kzalloc error!\n");
return -ENOMEM;
}
memset(dev->data,0,SIZE);//初始化
/*cdev_init(struct cdev *cdev,struct file_oppations *fops)*/
cdev_init(&dev->cdev,&char_fops);
dev->cdev.owner=THIS_MODULE;
/*cdev_add(struct cdev *dev,dev_t num,unsigned int count一般是1)*/
cdev_add(&dev->cdev,devno,1);
if(result){
/*unregister_chrdev_region(dev_t first,unsigned int count)*/
unregister_chrdev_region(devno,1);
return -EINVAL;
}
/*class_creat(owner,name)*/
char_class=class_create(THIS_MODULE,"char_module");
if(char_class==0){
printk(KERN_WARNING"class_create error\n");
unregister_chrdev_region(devno,1);
/*cdev_dev(struct cdev *dev)*/
cdev_del(&dev->cdev);
return -EINVAL;
}
/*device_create(上面的class,NULL,dev_t,NULL,device name)*/
device_create(char_class,NULL,devno,NULL,"char_module");
return 0;
}
//卸载
static void char_exit(void)
{
/*unregister_chrdev_region(dev_t first,unsigned int count)*/
unregister_chrdev_region(devno,1);
/*device_destroy(myclass,dev_t)*/
device_destroy(char_class,devno);
/*class_destroy(myclass)*/
class_destroy(char_class);
/*cdev_dev(struct cdev *dev)*/
cdev_del(&dev->cdev);
/*释放空间*/
kfree(dev->data);
kfree(dev);
dev->data=NULL;
dev=NULL;
}
//声明module
module_init(char_init);
module_exit(char_exit);
------------------------------------------------------------------------------------------
红色的就是和上篇不太一样的东西。这个顺序也有调整。修改了printk的输出级别等。
下面是测试程序
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
int fd,size;
char buff_write[]="test data";
char buff_read[128];
if((fd=open("/dev/char_module",2))==-1){//open
printf("open error!\n");
exit(1);
}
if((size=read(fd,buff_read,strlen(buff_read)))<0){//read第一次
printf("read error!\n");
exit(1);
}
printf("read:%dbytes\n",size);
printf("R:%s\n",buff_read);
if((size=write(fd,buff_write,strlen(buff_write)))!=strlen(buff_write)){//write
printf("write error!\n");
exit(1);
}
printf("W:%s\n",buff_write);
if(lseek(fd,0,SEEK_SET)==-1){//重置偏移量
printf("lseek error\n");
exit(1);
}
if((size=read(fd,buff_read,strlen(buff_write)))<0){//read第二次
printf("read error!\n");
exit(1);
}
printf("read:%dbytes\n",size);
printf("R:%s\n",buff_read);
close(fd);
exit(0);
}
---------------------------------------------------------------------------------------
这里的测试程序比上一篇的测试程序要好点。