Device Specific Data Structure with Platform Driver and Character Device Interface

When your miscdevice is being open for the first time, miscdevice framework will set file->private_data to your struct miscdevice (see misc_open() function and also comment to misc_register() function). You can rely on this and use file->private_data in your file operations to obtain your custom structure, using container_of() macro. Of course, your custom structure must contain your struct miscdevice for that. The neat and commonly used way to do so is to create helper function called to_*(), which will figure out and return your custom struct by file pointer provided. So if you called your custom struct my_struct, you should call that helper function as to_my_struct().

Also, if you are writing platform driver, you can use platform_set_drvdata() instead of dev_set_drvdata(). This is needed so you can obtain your custom structure in remove() function of your platform driver.

Here is an example for everything explained above:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

struct my_struct {
    struct platform_device *pdev;
    struct miscdevice mdev;
};

static inline struct my_struct *to_my_struct(struct file *file)
{
    struct miscdevice *miscdev = file->private_data;

    return container_of(miscdev, struct my_struct, mdev);
}

static ssize_t my_read(struct file *file, char __user *buf, size_t count,
                       loff_t *pos)
{
    struct my_struct *my = to_my_struct(file); /* just for example */

    (void)my; /* unused */
    return simple_read_from_buffer(buf, count, pos, "my text", 7);
}

static const struct file_operations my_fops = {
    .owner  = THIS_MODULE,
    .read   = my_read,
};

static int my_probe(struct platform_device *pdev)
{
    struct my_struct *my;
    int ret;

    my = kmalloc(sizeof(*my), GFP_KERNEL);
    if (!my)
        return -ENOMEM;

    platform_set_drvdata(pdev, my);
    my->pdev = pdev;

    my->mdev.minor  = MISC_DYNAMIC_MINOR;
    my->mdev.name   = "my";
    my->mdev.fops   = &my_fops;
    my->mdev.parent = NULL;

    ret = misc_register(&my->mdev);
    if (ret) {
        dev_err(&pdev->dev, "Failed to register miscdev\n");
        return ret;
    }

    dev_info(&pdev->dev, "Registered\n");

    return 0;
}

static int my_remove(struct platform_device *pdev)
{
    struct my_struct *my = platform_get_drvdata(pdev);

    misc_deregister(&my->mdev);
    kfree(my);
    dev_info(&pdev->dev, "Unregistered\n");

    return 0;
}

static struct platform_driver my_driver = {
    .probe      = my_probe,
    .remove     = my_remove,
    .driver = {
        .name = "my",
    },
};

module_platform_driver(my_driver);

MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("Platform device driver using char device example");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:my");

By the way, you can look for examples in kernel code, just by using keywords, like this:

$ git grep -l --all-match -e 'misc_register(' -e 'platform_device' -e 'file->private_data' -- drivers/