一个驱动同时支持多个设备

Linux内核 专栏收录该内容
8 篇文章 0 订阅

 

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#define GLOBALMEM_SIZE 0x100
#define MEM_CLEAR 0x01

static int global_major =0;
module_param(global_major,int ,S_IRUGO);
#define DEV_NUM 3

struct globalmem_dev{
	struct cdev cdev;
	struct class *my_class;
	unsigned char mem[GLOBALMEM_SIZE];
};
struct globalmem_dev* globalmem_devp;

static ssize_t char_dev_read(struct file *, char *, size_t,loff_t *);
static ssize_t char_dev_write(struct file *, const char *, size_t,loff_t *);
static int char_dev_open(struct inode *inode, struct file *filp);
static int char_dev_release(struct inode *inode, struct file *filp);

static int char_dev_open(struct inode *inode, struct file *filp)
{ 
	printk("This chrdev is in open\n");
	struct globalmem_dev *dev = container_of(inode->i_cdev,struct globalmem_dev ,cdev);
	filp->private_data=dev;
    return(0);
}

static int char_dev_release(struct inode *inode, struct file *filp)
{
    printk("This chrdev is in release\n");
    return(0);
}

static ssize_t char_dev_read(struct file *filp, char *buf, size_t len,loff_t *offet)
{
	struct globalmem_dev *dev=filp->private_data;
	printk("read buffer len is %u \n",len);
	copy_to_user(buf,dev->mem,len);
    return len;
}
static ssize_t char_dev_write(struct file *filp, const char *buf, size_t len,loff_t *offet)
{
	struct globalmem_dev *dev=filp->private_data;
    printk("the write buffer len is %u\n",len);
    copy_from_user(dev->mem,buf,len);
  	return len;
}
struct file_operations char_dev_fops =
{
	.owner = THIS_MODULE,
    .read = char_dev_read,
    .write = char_dev_write,
    .open = char_dev_open,
    .release = char_dev_release,
};
#define DEV_NAME "globalmem"
static void char_dev_setup_cdev(struct globalmem_dev *dev,int index)
{
	printk("======char_dev_setup_cdev==============\r\n");
	int err,devno=MKDEV(global_major,index);
	cdev_init(&dev->cdev, &char_dev_fops);
	err=cdev_add(&dev->cdev, devno, 1);
	if(err)
		printk("Error %d adding %s_%d",err,DEV_NAME,index);
	
	char strName[20];
	sprintf(strName,"%s%d",DEV_NAME,index);
	printk("strName %s\r\n",strName);
	dev->my_class = class_create(THIS_MODULE,strName);
	device_create(dev->my_class, NULL, devno, NULL, strName);
	printk("create device %s!\r\n",strName);
}
static int char_dev_init(void)
{
	int result = 0;
	int err = 0,i;
	printk("***********************\r\n");
	 dev_t dev = MKDEV(global_major, 0);
	 if (global_major)
    {
        result = register_chrdev_region(dev,DEV_NUM, DEV_NAME); //静态申请设备号
    }
    else
    {       
        err = alloc_chrdev_region(&dev, 0,DEV_NUM, DEV_NAME);//动态分配设备号
        global_major = MAJOR(dev);
    }
	printk("major num is %d \r\n", global_major);
	if (result < 0)
		return result;
	globalmem_devp=kzalloc(sizeof(struct globalmem_dev)*DEV_NUM,GFP_KERNEL);
	if(!globalmem_devp)
	{
		result = -ENOMEM;
		goto fail_malloc;	
	}
	for(i=0;i<DEV_NUM;i++)
	{
		char_dev_setup_cdev(globalmem_devp+i,i);
	}

	fail_malloc:
		unregister_chrdev_region(MKDEV(global_major,0),DEV_NUM);
	return result;
}

static void char_dev_exit(void)
{
	int i;

	for(i=0;i<DEV_NUM;i++)	
	{  
		device_destroy((globalmem_devp+i)->my_class, MKDEV(global_major, i));
	    class_destroy((globalmem_devp+i)->my_class);
	    cdev_del(&(globalmem_devp+i)->cdev);
  	}
	kfree(globalmem_devp);
	unregister_chrdev_region(MKDEV(global_major, 0), DEV_NUM);
 
}

module_init(char_dev_init);
module_exit(char_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Liubz");

字符设备驱动中例子对比,字符设备驱动中的驱动仅支持单个设备,而本例可同时支持多个设备。只是简单得修改了char_dev_open()、char_dev_init()和char_dev_exit()。

在char_dev_read()和char_dev_write()函数中使用了struct globalmem_dev *dev=filp->private_data;获得globalmem_dev的实例指针。实际上,大多数Linux驱动都遵循这样的一个规则,就是将文件的私有数据private_data指向设备结构体。

 

 

支持单实例和多实例代码对比
单实例多实例分析
调用container_of()函数,通过结构体成员的指针找到对应结构体的指针

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值