Linux2.6内核下的简单字符设备
1.自定设备符结构体
struct VirtualDisk{
struct cdev cdev;
unsigned char mem[VIRTUALDISK_SIZE];
long count;
};
2.声明函数
//设备驱动模块加载函数
int __init VirtualDisk_init(void);
//模块卸载函数
void __exit VirtualDisk_exit(void);
//初始化并注册
static void VirtualDisk_setup_cdev(struct VirtualDisk *, int );
//文件打开函数
int VirtualDisk_open(struct inode *, struct file *);
//文件读函数
static ssize_t VirtualDisk_read(struct file *, char __user *, size_t, loff_t *);
//文件写函数
static ssize_t VirtualDisk_write(struct file *, const char __user *, size_t, loff_t *);
3.初始化文件操作结构体
static const struct file_operations VirtualDisk_fops = {
.owner = THIS_MODULE,
.read = VirtualDisk_read,
.write = VirtualDisk_write,
.open = VirtualDisk_open,
};
4.定义函数
int __init VirtualDisk_init(void)
{
int result ;
dev_t devno = MKDEV(VirtualDisk_major, 0); //构建设备号
if(VirtualDisk_major)
{
result = register_chrdev_region(devno, 1, "VirtualDisk");//静态申请
}
else
{
result = alloc_chrdev_region(&devno, 0, 1, "VirtualDisk");//动态申请
VirtualDisk_major = MAJOR(devno);
}
if(result < 0)
{
return result;
}
VirtualDisk_devp = kmalloc(sizeof(struct VirtualDisk),GFP_KERNEL);//动态申请设备结构体内存
if(!VirtualDisk_devp)
{
result = -ENOMEM;
goto fail_kmalloc;
}
memset(VirtualDisk_devp, 0, sizeof(struct VirtualDisk));
VirtualDisk_setup_cdev(VirtualDisk_devp, 0);
printk("register_chrdev_region success\n");
return 0;
fail_kmalloc:
unregister_chrdev_region(devno, 1);
return result;
}
void __exit VirtualDisk_exit(void)
{
cdev_del(&VirtualDisk_devp->cdev);//注销设备结构体
kfree(VirtualDisk_devp);//释放内存
unregister_chrdev_region(MKDEV(VirtualDisk_major,0),1);//释放设备号
}
static void VirtualDisk_setup_cdev(struct VirtualDisk *dev, int minor)
{
int err;
dev_t devno = MKDEV(VirtualDisk_major, minor);
printk("major:%d\n",MAJOR(devno));
printk("minor:%d\n",MINOR(devno));
cdev_init(&dev->cdev, &VirtualDisk_fops);//初始化cdev设备
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev, devno, 1);//注册cdev设备到系统
if(err)
{
printk(KERN_NOTICE "Error in cdev_add()\n");
}
}
int VirtualDisk_open(struct inode *inode, struct file *filp)
{
filp->private_data = VirtualDisk_devp;
struct VirtualDisk *devp = filp->private_data;
devp->count++;
return 0;
}
static ssize_t VirtualDisk_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct VirtualDisk *devp = filp->private_data;
if(p >= VIRTUALDISK_SIZE)
{
return count? -ENXIO: 0;
}
if(count > VIRTUALDISK_SIZE)
{
count = VIRTUALDISK_SIZE - p;
}
if(copy_to_user(buf, (void *)(devp->mem + p), count))//将内核中的内容拷贝到用户空间
{
ret = -EFAULT;
}
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "read %d bytes from %d\n",count,p);
}
*ppos = 0;//将内核指针复位
printk("read:%s\n",buf);
return ret;
}
static ssize_t VirtualDisk_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
int ret = 0;
unsigned int count = size;
struct VirtualDisk *devp = filp->private_data;
if(p >= VIRTUALDISK_SIZE)
{
return count? -ENXIO:0;
}
if(count > VIRTUALDISK_SIZE)
{
count = VIRTUALDISK_SIZE - p;
}
if(copy_from_user(devp->mem + p, buf, count))
{
ret = -EFAULT;
}
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "written %d bytes from %d\n",count,p);
}
*ppos = 0;//内核指针复位
printk("write:%s\n",buf);
return ret;
}
//模块函数
module_init(VirtualDisk_init);
module_exit(VirtualDisk_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Zhang San");
5.Makefile文件
obj-m := VirtualDisk.o
#内核中Makefile文件的位置
KDIR := /lib/modules/2.6.35-22-generic/build
all:
make -C $(KDIR) M=$(shell pwd) modules
clean:
rm -f *.ko *.o *.mod *.mod.c *.symvers *.order
6.编译
make
编译后的结果:
7.加载模块
sudo insmod VirtualDisk.ko
8.在/dev文件夹下创建设备文件
sudo /dev/VirtualDisk c 200 0
9.测试(简单的open、write、read)
测试程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define BFSIZE 256
int main()
{
int fd,size;
const char *buff= "hello";
char temp[BFSIZE];
if((fd = open("/dev/VirtualDisk",O_RDWR)) < 0)//打开文件描述符
{
perror("open");
exit(1);
}
if((size = write(fd,buff,strlen(buff))) < 0)//写
{
perror("write");
exit(1);
}
if((size = read(fd,temp,BFSIZE)) < 0)//读
{
perror("read");
exit(1);
}
printf("Read from device :%s\n",temp);
close(fd);
return 0;
}
测试结果
1.测试程序
2.内核空间
10.卸载驱动
sudo rmmod VirtualDisk
11.删除设备文件
sudo rm -f /dev/VirtualDisk.
结束。