/***************************************************************************/
/*                             Druckersoftware                             */
/*                    Copyright (C) Carl Valentin GmbH                     */
/***************************************************************************/

/*
 * cv_char_dev_simple.h
 *
 *  Created on: 18.07.2022
 *      Author: preitinger
 */

#ifndef CV_CHAR_DEV_SIMPLE_H_
#define CV_CHAR_DEV_SIMPLE_H_

#include <linux/types.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/fs.h>

typedef struct {
    dev_t devNum;
    struct cdev dev;
    struct class* clazz;

} t_cv_char_dev_simple;

int cv_cds_create(t_cv_char_dev_simple* p, const char* name, struct file_operations* fops) {
    int err = 0;

    p->clazz = class_create(THIS_MODULE, name);

    if (IS_ERR(p->clazz)) {
        err = PTR_ERR(p->clazz);
        goto err0;
    }

    if ((err = alloc_chrdev_region(&p->devNum, 0, 1, name))) {
        pr_err("alloc_chrdev_region failed for %s\n", name);
        goto err1;
    }

    cdev_init(&p->dev, fops);

    if (((err = cdev_add(&p->dev, p->devNum, 1)))) {
        goto err2;
    }
    {
        struct device* dev;
        dev = device_create(p->clazz, NULL, p->devNum, "%s", name);
        pr_info("dev->devt=%d\n", dev->devt);

        if (IS_ERR(dev)) {
            err = PTR_ERR(dev);
            goto err3;
        }
    }

    goto err0;

    err3:
    cdev_del(&p->dev);

    err2:
    unregister_chrdev_region(p->devNum, 1);

    err1:
    class_destroy(p->clazz);

    err0:
    return err;
}

void cv_cds_delete(t_cv_char_dev_simple* p) {
    pr_info("p->devNum=%d\n", p->devNum);
    device_destroy(p->clazz, p->devNum);
    cdev_del(&p->dev);
    unregister_chrdev_region(p->devNum, 1);
    class_destroy(p->clazz);

}

#endif /* CV_CHAR_DEV_SIMPLE_H_ */
