项目中经常会将所用到的所有全局数据结构放到同一个结构体内
struct simple_dev {
dev_t dev_no;
struct cdev cdev;
struct class *class;
struct device *device;
};
该结构体将所用到的全局数据结构放在一起,这样可以在open的时候,将该指针放到file->private_data = dev;私有data字段内,方便其他系统调用接口使用
这里container_of无法操作内部嵌套的指针类型,所以struct cdev cdev;不能用作指针类型
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h> // kfree,kmalloc
#include <linux/cdev.h> // cdev_xxx
#include <linux/device.h> // device_xxx
struct simple_dev {
dev_t dev_no;
struct cdev cdev;
struct class *class;
struct device *device;
};
struct simple_dev *g_simple_dev;
static int simple_cdev_open(struct inode *inode, struct file *file)
{
struct simple_dev *dev;
dev = container_of(inode->i_cdev, struct simple_dev, cdev);
file->private_data = dev;
return 0;
}
static int simple_cdev_release(struct inode *inode, struct file *file)
{
struct simple_dev *dev;
dev = file->private_data;
return 0;
}
/* File operations struct for character device */
static const struct file_operations g_simple_dev_fops = {
.owner = THIS_MODULE,
.open = simple_cdev_open,
.release = simple_cdev_release,
};
static int __init simple_cdev_init(void)
{
int ret;
g_simple_dev = kzalloc(sizeof(struct simple_dev), GFP_KERNEL);
if (!g_simple_dev) {
return -1;
}
ret = alloc_chrdev_region(&g_simple_dev->dev_no, 0, 1, "simple_cdev");
if (!ret) {
goto alloc_chrdev_failed;
}
cdev_init(&g_simple_dev->cdev, &g_simple_dev_fops);
g_simple_dev->cdev.owner = THIS_MODULE;
ret = cdev_add(&g_simple_dev->cdev, g_simple_dev->dev_no, 1);
if (!ret) {
goto cdev_add_failed;
}
g_simple_dev->class = class_create(THIS_MODULE, "simple_cdev");
if (!g_simple_dev->class) {
goto class_create_failed;
}
g_simple_dev->device = device_create(g_simple_dev->class, NULL, g_simple_dev->dev_no, NULL, "simple_cdev");
if (!g_simple_dev->device) {
goto device_create_failed;
}
return 0;
device_create_failed:
class_destroy(g_simple_dev->class);
class_create_failed:
cdev_del(&g_simple_dev->cdev);
cdev_add_failed:
unregister_chrdev_region(g_simple_dev->dev_no, 1);
alloc_chrdev_failed:
kfree(g_simple_dev);
return -1;
}
static void __exit simple_cdev_exit(void)
{
device_destroy(g_simple_dev->class, g_simple_dev->dev_no);
class_destroy(g_simple_dev->class);
cdev_del(&g_simple_dev->cdev);
unregister_chrdev_region(g_simple_dev->dev_no, 1);
kfree(g_simple_dev);
}
MODULE_LICENSE("GPL");
module_init(simple_cdev_init);
module_exit(simple_cdev_exit);