#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()函数,通过结构体成员的指针找到对应结构体的指针 |
![]() | | |
![]() | ![]() |