blob: f920954f45e301eed1e7576cddff18f34dd5d16c [file] [log] [blame]
/*
* drivers/framerate_adapter/video_framerate_adapter.c
*
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include "video_framerate_adapter.h"
#define CLASS_NAME "framerate_adapter"
#define DEV_NAME "framerate_dev"
#ifndef VIDEOFRAME_MAJOR
#define VIDEOFRAME_MAJOR 550
#endif
struct frame_rate_dev_s* frame_rate_dev;
void vframe_rate_uevent(int duration)
{
char *configured[2];
char framerate[40] = {0};
sprintf(framerate, "FRAME_RATE_HINT=%lu",
(unsigned long)duration);
configured[0] = framerate;
configured[1] = NULL;
kobject_uevent_env(&frame_rate_dev->dev->kobj,
KOBJ_CHANGE, configured);
pr_info("%s: sent uevent %s\n", __func__, configured[0]);
}
EXPORT_SYMBOL(vframe_rate_uevent);
static const struct file_operations frame_rate_fops = {
.owner = THIS_MODULE
};
static struct class_attribute frame_rate_class_attrs[] = {
__ATTR_NULL
};
static struct class frame_rate_class = {
.name = CLASS_NAME,
.class_attrs = frame_rate_class_attrs,
};
static int frame_rate_driver_init(void)
{
int ret = -1;
frame_rate_dev = kzalloc(sizeof(struct frame_rate_dev_s), GFP_KERNEL);
if (IS_ERR_OR_NULL(frame_rate_dev))
return -ENOMEM;
frame_rate_dev->dev_no = MKDEV(VIDEOFRAME_MAJOR, 100);
ret = register_chrdev_region(frame_rate_dev->dev_no, 1, DEV_NAME);
if (ret < 0) {
pr_err("Can't get major number %d.\n", VIDEOFRAME_MAJOR);
goto err_4;
}
cdev_init(&frame_rate_dev->cdev, &frame_rate_fops);
frame_rate_dev->cdev.owner = THIS_MODULE;
ret = cdev_add(&frame_rate_dev->cdev, frame_rate_dev->dev_no, 1);
if (ret) {
pr_err("Error %d adding cdev fail.\n", ret);
goto err_3;
}
ret = class_register(&frame_rate_class);
if (ret < 0) {
pr_err("Failed in creating class.\n");
goto err_2;
}
frame_rate_dev->dev = device_create(&frame_rate_class, NULL,
frame_rate_dev->dev_no, NULL, DEV_NAME);
if (IS_ERR_OR_NULL(frame_rate_dev->dev)) {
pr_err("Create device failed.\n");
ret = -ENODEV;
goto err_1;
}
pr_info("Registered frame rate driver success.\n");
return 0;
err_1:
device_destroy(&frame_rate_class, frame_rate_dev->dev_no);
err_2:
class_unregister(&frame_rate_class);
err_3:
cdev_del(&frame_rate_dev->cdev);
err_4:
unregister_chrdev_region(frame_rate_dev->dev_no, 1);
kfree(frame_rate_dev);
return ret;
}
static void frame_rate_driver_exit(void)
{
device_destroy(&frame_rate_class, frame_rate_dev->dev_no);
class_unregister(&frame_rate_class);
cdev_del(&frame_rate_dev->cdev);
unregister_chrdev_region(frame_rate_dev->dev_no, 1);
kfree(frame_rate_dev);
}
static int __init frame_rate_module_init(void)
{
int ret = -1;
ret = frame_rate_driver_init();
if (ret) {
pr_info("Error %d frame_rate_module_init init fail.\n", ret);
}
return ret;
}
static void __exit frame_rate_module_exit(void)
{
frame_rate_driver_exit();
pr_info("frame_rate_module_exit\n");
}
module_init(frame_rate_module_init);
module_exit(frame_rate_module_exit);
MODULE_AUTHOR("<shilong.yang@amlogic.com>");
MODULE_DESCRIPTION("framerate adapter");
MODULE_LICENSE("GPL");