字符驱动设备中几个重要的结构体(cdev,file_operations,inode,file)

1. cdev结构体

struct cdev {
	struct kobject kobj; //内嵌的kobject对象
	struct module *owner; //所属模板
	const struct file_operations *ops; //文件操作的结构体
	struct list_head list;
	dev_t dev; //设备号
	unsigned int count;
};

1.1 cdev的相关操作

void cdev_init(struct cdev *, const struct file_operations *); //初始化使其和文件操作结构相连接

struct cdev *cdev_alloc(void); //为cdev分配内存

int cdev_add(struct cdev *, dev_t, unsigned); //向内核注册一个设备

void cdev_del(struct cdev *); //从内核删除一个设备

1.2 设备号的分配

1.21 主次设备号和dev_t的相互转换

由dev_t号获取主次设备号
MAJOR(dev_t dev)
MINOR(dev_t dev)
由主次设备号获得dev_t
MKDEV(int major,int minor)

1.22 获取及注销设备号

int register_chrdev_region(dev_t from,unsigned count,const char *name); //手动注册
int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name); //由内核分配
void unregion_chrdev_region(dev_t from,unsigned count); //注销设备号

2. file_operations结构体

struct file_operations { 
  struct module *owner; //所属模板
  loff_t(*llseek) (struct file *, loff_t, int); //移动文件指针位置
  ssize_t(*read) (struct file *, char __user *, size_t, loff_t *); //读操作 
  ssize_t(*aio_read) (struct kiocb *, char __user *, size_t, loff_t); //异步读
  ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *); //写操作
  ssize_t(*aio_write) (struct kiocb *, const char __user *, size_t, loff_t); //异步写 
  int (*readdir) (struct file *, void *, filldir_t); 
  unsigned int (*poll) (struct file *, struct poll_table_struct *); //设备是否可以被非阻塞的读写 
  int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); //文件相关控制命令
  int (*mmap) (struct file *, struct vm_area_struct *);  //文件映射
  int (*open) (struct inode *, struct file *); //打开文件 
  int (*flush) (struct file *); 
  int (*release) (struct inode *, struct file *); //关闭文件
  int (*fsync) (struct file *, struct dentry *, int datasync); 
  int (*aio_fsync) (struct kiocb *, int datasync); 
  int (*fasync) (int, struct file *, int); 
  int (*lock) (struct file *, int, struct file_lock *); 
  ssize_t(*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); 
  ssize_t(*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); 
  ssize_t(*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void __user *); 
  ssize_t(*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); 
  unsigned long (*get_unmapped_area) (struct file *, unsigned long, unsigned long, unsigned long, unsigned long); 
  }; 

3. inode结构体

 struct inode{
        umode_t                 i_mode;              /* 访问权限控制 */
        uid_t                   i_uid;               /* 使用者id */
        gid_t                   i_gid;               /* 使用者id组 */
        kdev_t                  i_rdev;              /* 实设备标识符 */
        loff_t                  i_size;              /* 以字节为单位的文件大小 */

        struct timespec         i_atime;             /* 最后访问时间 */
        struct timespec         i_mtime;             /* 最后修改(modify)时间 */
        struct timespec         i_ctime;             /* 最后改变(change)时间 */

        unsigned int            i_blkbits;           /* 以位为单位的块大小 */
        unsigned long           i_blocks;            /* 文件的块数 */

};

4. file 结构体

struct file {
  
        union {
                struct list_head        fu_list;
                struct rcu_head         fu_rcuhead;
        } f_u;
        struct path             f_path;
#define f_dentry        f_path.dentry
#define f_vfsmnt        f_path.mnt
        const struct file_operations    *f_op;
        atomic_t                f_count;
        unsigned int            f_flags;
        mode_t                  f_mode;
        loff_t                  f_pos;
        struct fown_struct      f_owner;
        unsigned int            f_uid, f_gid;
        struct file_ra_state    f_ra;
        unsigned long           f_version;
#ifdef CONFIG_SECURITY
        void                    *f_security;
#endif
        void                    *private_data; //私有数据
#ifdef CONFIG_EPOLL
        struct list_head        f_ep_links;
        spinlock_t              f_ep_lock;
#endif 
        struct address_space    *f_mapping;
};

5. 自动创建设备文件

class_create(owner, name);//创建设备类
struct device *device_create(struct class *cls, struct device *parent,dev_t devt, void *drvdata,const char *fmt, ...)//创建文件

6. 内核空间与用户空间的数据的读写

copy_from_user(void *to, const void __user *from, unsigned long n); //用户区到内核区
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);//内核区到用户区

7. 实例

在内核区开辟256字节的内存为虚拟的设备,然后进行读写操作(参看宋宝华的linux驱动开发详解)

/*
 * globamem.c
 *
 *  Created on: 2016年11月17日
 *      Author: chy
 */

#include <linux/stat.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/gfp.h>
#include <linux/io.h>
#define buff_size 256 //设备缓冲区的大小
#define dev_num 2 //设备的个数
//#define DEBUG //若打印调试信息则开启

struct globamem{ //设备描述
	char buff[buff_size];
	ssize_t size;
};
struct globamem *mem = NULL;

static int open_file(struct inode *node,struct file *g_file) //打开文件
{
	int minor = MINOR(node->i_rdev); //获取此设备号
	struct globamem *dev = &mem[minor];

	g_file->private_data = dev;

	return 0;
}

static int close_file(struct inode *node,struct file *g_file) //关闭
{
	return 0;
}

static ssize_t read_file(struct file *g_file,char __user *buf,size_t size,loff_t *pos)//读
{
	loff_t port = *pos;
	int ans = 0;
	struct globamem *temp = g_file->private_data;
    ssize_t count = size;

#ifdef DEBUG
	printk(KERN_INFO "read file = %s pos=%ld %ld\n",temp->buff,port,g_file->f_pos);
#endif

	if(port >= strlen(temp->buff) || port > buff_size)
		return ans;

	if(port + count > strlen(temp->buff))
		count = strlen(temp->buff) - port;
	else count = strlen(temp->buff);

	if(copy_to_user(buf,temp->buff + port,count + 1))
		ans =  -EFAULT;
	else{
		*pos += count;
		ans = count;
	}
#ifdef DEBUG
	printk(KERN_INFO "read over %d %s\n",ans,temp->buff);
#endif

	return ans;
}

static ssize_t write_file(struct file *g_file,const char __user *buf,size_t size,loff_t *pos) //写
{
	unsigned long port = *pos;
	int ans = 0;
	struct globamem *temp = g_file->private_data;
	ssize_t file_size = size;

#ifdef DEBUG
	printk(KERN_INFO "write file\n");
#endif

	if(port >= buff_size)
		return ans;

	if(strlen(buf) > buff_size - port)
		file_size = buff_size - port;
	else file_size = strlen(buf);

	if(copy_from_user(temp->buff + port,buf,file_size + 1))
		ans = -EFAULT;
	else{
		*pos += file_size;
		ans = file_size;
	}

	return ans;
}

static long g_ioctl(struct file *g_file,unsigned int cmd,unsigned long arg) //IO控制命令
{
	struct globamem *g = g_file->private_data;

	switch(cmd){
	case 0: memset(g->buff,0,buff_size); break;
	default: return -EINVAL;
	}
	return 0;
}

static const struct  file_operations fos = { //文件操作
		.owner = THIS_MODULE,
		.read = read_file,
		.write = write_file,
		.open = open_file,
		.release = close_file,
		.unlocked_ioctl = g_ioctl,
};

dev_t dev_no;
struct cdev dev;
struct class *dev_class = NULL;

static int globamem_init(void) //加载
{
	int ret;

	ret = alloc_chrdev_region(&dev_no,0,2,"globamem_s"); //自动分配设备号
	if(ret < 0)
		return ret;

	mem = (struct globamem*)kmalloc(sizeof(struct globamem) * dev_num,GFP_KERNEL);

	dev.owner = THIS_MODULE;
	cdev_init(&dev,&fos); //初始化设备
	cdev_add(&dev,dev_no,2); //向内核注册设备


	/*生成设备文件*/
	dev_class = class_create(THIS_MODULE,"globamem_class");
	device_create(dev_class, NULL, MKDEV(MAJOR(dev_no),0), NULL, "globamem_1_dev");
	device_create(dev_class, NULL, MKDEV(MAJOR(dev_no),1), NULL, "globamem_2_dev");

	return 0;
}

static void globamem_exit(void) //卸载
{

	int i;
	for(i = 0; i < dev_num; i++)
		kfree(&mem[i]);

	cdev_del(&dev); //删除设备

	/*删除设备文件*/
	device_destroy(dev_class, MKDEV(MAJOR(dev_no),0));
	device_destroy(dev_class,MKDEV(MAJOR(dev_no),1));
	class_destroy(dev_class);

	unregister_chrdev_region(dev_no,2); //释放设备号

	return;
}

MODULE_LICENSE("GPL v2");
module_init(globamem_init);
module_exit(globamem_exit);





  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值