mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
1bfff1f439
PD#SWPL-136722 Problem: coverity errors Solution: fix the coverity errors Verify: local Change-Id: I5b210b5c44ee6a0e34c1c8b9685fe2d38cd52b1b Signed-off-by: Dezhen Wang <dezhen.wang@amlogic.com>
306 lines
7.1 KiB
C
306 lines
7.1 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/cdev.h>
|
|
#include <linux/types.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/clk.h>
|
|
#include "efuse.h"
|
|
#include <linux/amlogic/efuse.h>
|
|
#include <linux/io.h>
|
|
#include "efuse_burn.h"
|
|
#include <linux/compat.h>
|
|
|
|
#define EFUSE_BURN_DEVICE_NAME "efuse_burn"
|
|
#define EFUSE_BURN_CLASS_NAME "efuse_burn"
|
|
|
|
static struct aml_efuse_burn_dev *pefuse_burn_dev;
|
|
|
|
static int efuse_burn_open(struct inode *inode, struct file *file)
|
|
{
|
|
struct aml_efuse_burn_dev *devp;
|
|
|
|
devp = container_of(inode->i_cdev, struct aml_efuse_burn_dev, cdev);
|
|
file->private_data = devp;
|
|
|
|
//printk(KERN_NOTICE "%s:%d\n", __func__, __LINE__);
|
|
pr_notice("%s:%d\n", __func__, __LINE__);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int efuse_burn_release(struct inode *inode, struct file *file)
|
|
{
|
|
file->private_data = NULL;
|
|
return 0;
|
|
}
|
|
|
|
static loff_t efuse_burn_llseek(struct file *filp, loff_t off, int whence)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static long efuse_burn_unlocked_ioctl(struct file *file,
|
|
unsigned int cmd, unsigned long arg)
|
|
{
|
|
long ret = -ENOTTY;
|
|
void __user *argp = (void __user *)arg;
|
|
struct efuse_burn_info info;
|
|
|
|
pr_notice("%s:%d\n", __func__, __LINE__);
|
|
switch (cmd) {
|
|
case EFUSE_BURN_CHECK_KEY:
|
|
if (copy_from_user((void *)&info, argp, sizeof(info))) {
|
|
pr_err("%s: copy_from_user fail\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
if (efuse_burn_lockable_is_cfg(info.itemname) == 0) {
|
|
info.itemname[31] = '\0';
|
|
info.status = efuse_burn_check_burned(info.itemname);
|
|
} else {
|
|
pr_err("%s: efuse_burn check item not cfg\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
if (copy_to_user(argp, &info, sizeof(info))) {
|
|
pr_err("%s: copy_to_user fail\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
static long efuse_burn_compat_ioctl(struct file *filp,
|
|
unsigned int cmd, unsigned long args)
|
|
{
|
|
long ret;
|
|
|
|
args = (unsigned long)compat_ptr(args);
|
|
ret = efuse_burn_unlocked_ioctl(filp, cmd, args);
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static ssize_t efuse_burn_read(struct file *file, char __user *buf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
pr_notice("%s:%d\n", __func__, __LINE__);
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t efuse_burn_write(struct file *file,
|
|
const char __user *buf, size_t count, loff_t *ppos)
|
|
{
|
|
struct aml_efuse_burn_dev *devp;
|
|
ssize_t ret;
|
|
char *op = NULL;
|
|
|
|
devp = file->private_data;
|
|
//pr_notice("%s:%d, sizeof(loff_t):%d\n",
|
|
// __func__, __LINE__, sizeof(loff_t));
|
|
//pr_notice("pos=%lld,count=%d\n", *ppos, count);
|
|
if (count != devp->efuse_pattern_size) {
|
|
ret = -EINVAL;
|
|
pr_err("efuse burn: bad pattern size, only support size %d!\n",
|
|
devp->efuse_pattern_size);
|
|
goto exit;
|
|
}
|
|
op = kzalloc(sizeof(char) * count, GFP_KERNEL);
|
|
if (!op) {
|
|
ret = -ENOMEM;
|
|
pr_err("efuse burn: failed to allocate memory!\n");
|
|
goto exit;
|
|
}
|
|
|
|
memset(op, 0, count);
|
|
if (copy_from_user(op, buf, count)) {
|
|
pr_err("%s: copy_from_user fail\n", __func__);
|
|
kfree(op);
|
|
ret = -EFAULT;
|
|
goto exit;
|
|
}
|
|
|
|
ret = efuse_amlogic_set(op, count);
|
|
kfree(op);
|
|
|
|
if (ret) {
|
|
pr_err("efuse burn: pattern programming fail! ret: %d\n",
|
|
(unsigned int)ret);
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
pr_info("efuse burn: pattern programming success!\n");
|
|
|
|
ret = count;
|
|
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
static const struct file_operations efuse_burn_fops = {
|
|
.owner = THIS_MODULE,
|
|
.llseek = efuse_burn_llseek,
|
|
.open = efuse_burn_open,
|
|
.release = efuse_burn_release,
|
|
.read = efuse_burn_read,
|
|
.write = efuse_burn_write,
|
|
.unlocked_ioctl = efuse_burn_unlocked_ioctl,
|
|
#ifdef CONFIG_COMPAT
|
|
.compat_ioctl = efuse_burn_compat_ioctl,
|
|
#endif
|
|
};
|
|
|
|
static ssize_t version_show(struct class *cla,
|
|
struct class_attribute *attr, char *buf)
|
|
{
|
|
ssize_t n = 0;
|
|
|
|
n = sprintf(buf, "ver1.0");
|
|
return n;
|
|
}
|
|
|
|
static ssize_t version_store(struct class *cla,
|
|
struct class_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
pr_notice("%s:%d,buf=0x%lx,count=%zu\n",
|
|
__func__, __LINE__, (long)buf, count);
|
|
return count;
|
|
}
|
|
|
|
static EFUSE_CLASS_ATTR(version);
|
|
|
|
static struct attribute *efuse_burn_class_attrs[] = {
|
|
&class_attr_version.attr,
|
|
NULL,
|
|
};
|
|
ATTRIBUTE_GROUPS(efuse_burn_class);
|
|
|
|
static int efuse_burn_probe(struct platform_device *pdev)
|
|
{
|
|
int ret;
|
|
struct device *devp;
|
|
struct aml_efuse_burn_dev *efuse_burn_dev;
|
|
struct device_node *np = pdev->dev.of_node;
|
|
|
|
efuse_burn_dev = devm_kzalloc(&pdev->dev, sizeof(*efuse_burn_dev),
|
|
GFP_KERNEL);
|
|
if (!efuse_burn_dev) {
|
|
ret = -ENOMEM;
|
|
dev_err(&pdev->dev, "failed to alloc enough mem for efuse_dev\n");
|
|
goto out;
|
|
}
|
|
|
|
efuse_burn_dev->pdev = pdev;
|
|
platform_set_drvdata(pdev, efuse_burn_dev);
|
|
|
|
of_node_get(np);
|
|
|
|
ret = of_property_read_u32(np, "efuse_pattern_size",
|
|
&efuse_burn_dev->efuse_pattern_size);
|
|
if (ret) {
|
|
pr_err("can't get efuse_pattern_size, please configurate size\n");
|
|
goto error1;
|
|
}
|
|
|
|
ret = alloc_chrdev_region(&efuse_burn_dev->devno, 0, 1,
|
|
EFUSE_BURN_DEVICE_NAME);
|
|
if (ret < 0) {
|
|
dev_err(&pdev->dev, "fail to allocate major number\n ");
|
|
goto error1;
|
|
}
|
|
|
|
efuse_burn_dev->cls.name = EFUSE_BURN_CLASS_NAME;
|
|
efuse_burn_dev->cls.owner = THIS_MODULE;
|
|
efuse_burn_dev->cls.class_groups = efuse_burn_class_groups;
|
|
ret = class_register(&efuse_burn_dev->cls);
|
|
if (ret)
|
|
goto error2;
|
|
|
|
cdev_init(&efuse_burn_dev->cdev, &efuse_burn_fops);
|
|
efuse_burn_dev->cdev.owner = THIS_MODULE;
|
|
|
|
ret = cdev_add(&efuse_burn_dev->cdev, efuse_burn_dev->devno, 1);
|
|
if (ret) {
|
|
dev_err(&pdev->dev, "failed to add device\n");
|
|
goto error3;
|
|
}
|
|
|
|
devp = device_create(&efuse_burn_dev->cls, NULL,
|
|
efuse_burn_dev->devno, efuse_burn_dev, "efuse_burn");
|
|
if (IS_ERR(devp)) {
|
|
dev_err(&pdev->dev, "failed to create device node\n");
|
|
ret = PTR_ERR(devp);
|
|
goto error4;
|
|
}
|
|
pefuse_burn_dev = efuse_burn_dev;
|
|
|
|
dev_dbg(&pdev->dev, "device %s created OK\n", EFUSE_BURN_DEVICE_NAME);
|
|
|
|
return 0;
|
|
|
|
error4:
|
|
cdev_del(&efuse_burn_dev->cdev);
|
|
error3:
|
|
class_unregister(&efuse_burn_dev->cls);
|
|
error2:
|
|
unregister_chrdev_region(efuse_burn_dev->devno, 1);
|
|
error1:
|
|
devm_kfree(&pdev->dev, efuse_burn_dev);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static int efuse_burn_remove(struct platform_device *pdev)
|
|
{
|
|
struct aml_efuse_burn_dev *efuse_burn_dev;
|
|
|
|
efuse_burn_dev = platform_get_drvdata(pdev);
|
|
unregister_chrdev_region(efuse_burn_dev->devno, 1);
|
|
device_destroy(&efuse_burn_dev->cls, efuse_burn_dev->devno);
|
|
cdev_del(&efuse_burn_dev->cdev);
|
|
class_unregister(&efuse_burn_dev->cls);
|
|
platform_set_drvdata(pdev, NULL);
|
|
devm_kfree(&pdev->dev, efuse_burn_dev);
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id efuse_burn_dt_match[] = {
|
|
{ .compatible = "amlogic, efuseburn",
|
|
},
|
|
{}
|
|
};
|
|
|
|
static struct platform_driver efuse_burn_driver = {
|
|
.probe = efuse_burn_probe,
|
|
.remove = efuse_burn_remove,
|
|
.driver = {
|
|
.name = EFUSE_BURN_DEVICE_NAME,
|
|
.of_match_table = efuse_burn_dt_match,
|
|
.owner = THIS_MODULE,
|
|
},
|
|
};
|
|
|
|
int __init aml_efuse_burn_init(void)
|
|
{
|
|
return platform_driver_register(&efuse_burn_driver);
|
|
}
|
|
|
|
void aml_efuse_burn_exit(void)
|
|
{
|
|
platform_driver_unregister(&efuse_burn_driver);
|
|
}
|
|
|