// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2015 MediaTek Inc.
 */


#include <linux/arm-smccc.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kallsyms.h>
#include <linux/kdebug.h>
#include <linux/kprobes.h>
#include <linux/kthread.h>
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/sched/rt.h>
#include <linux/sched/task.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/soc/mediatek/mtk_sip_svc.h> /* for SMC ID table */
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <uapi/linux/sched/types.h>

#include <mt-plat/mrdump.h>
#include "aed.h"
#include "mrdump_helper.h"

#define BUFSIZE 128
static int test_case;
static int test_cpu;
static struct task_struct *wk_tsk[AEE_MTK_CPU_NUMS];

static int force_panic_hang(struct notifier_block *this, unsigned long event,
				void *ptr)
{
	pr_notice("\n ==> force panic flow hang\n");
	while (1)
		;
	return 0;
}

static struct notifier_block panic_test = {
	.notifier_call = force_panic_hang,
	.priority = INT_MAX,
};

void notrace wdt_atf_hang(void)
{
	int cpu = raw_smp_processor_id();

	pr_notice(" CPU %d : %s\n", cpu, __func__);

	preempt_disable();
	local_irq_disable();
	while (1)
		;
}

static int kwdt_thread_test(void *arg)
{
	struct sched_param param = {.sched_priority = 99 };
	int cpu = raw_smp_processor_id();

	sched_setscheduler(current, SCHED_FIFO, &param);
	set_current_state(TASK_INTERRUPTIBLE);
	pr_notice("\n ==> %s on CPU %d, test_case = %d\n",
						__func__, cpu, test_case);
	msleep(1000);

	if (test_case == 1) {
		if (cpu == test_cpu) {
			pr_notice("\n CPU %d : disable preemption and local IRQ forever"
								, cpu);
			preempt_disable();
			local_irq_disable();
			while (1)
				;
		} else {
			pr_notice("\n CPU %d : Do nothing and exit\n ", cpu);
		}
	} else if (test_case == 2) {
		if (cpu == test_cpu) {
			msleep(1000);
			pr_notice("\n CPU %d : disable preemption and local IRQ forever"
								, cpu);
			preempt_disable();
			local_irq_disable();
			while (1)
				;
		} else {
			pr_notice("\n CPU %d : disable irq\n ", cpu);
			local_irq_disable();
			while (1)
				;
		}
	} else if (test_case == 3) {
		if (cpu == test_cpu) {
			pr_notice("\n CPU %d : register panic notifier and force hang\n"
								, cpu);
			atomic_notifier_chain_register(&panic_notifier_list,
							&panic_test);
			preempt_disable();
			local_irq_disable();
			while (1)
				;
		} else {
			pr_notice("\n CPU %d : Do nothing and exit\n ", cpu);
		}
	} else if (test_case == 4) {
		pr_notice("\n CPU %d : disable preemption and local IRQ forever\n "
								, cpu);
		preempt_disable();
		local_irq_disable();
		while (1)
			;
	} else if (test_case == 5) {
		pr_notice("\n CPU %d : disable preemption and local IRQ/FIQ forever\n "
								, cpu);
		preempt_disable();
		local_irq_disable();
		while (1)
			;
	} else if (test_case == 6) {
		pr_notice("\n CPU %d : disable preemption and local IRQ/FIQ forever\n "
								, cpu);
		preempt_disable();
		local_irq_disable();
		while (1)
			;
	}
	return 0;
}

static ssize_t proc_generate_wdt_write(struct file *file,
			const char __user *buf, size_t size, loff_t *ppos)
{
	unsigned int i = 0;
	char msg[4];
	unsigned char name[20] = { 0 };
	struct arm_smccc_res res;
	int n;

	if ((size < 2) || (size > sizeof(msg))) {
		pr_notice("\n size = %zx\n", size);
		return -EINVAL;
	}
	if (!buf) {
		pr_notice("\n buf = NULL\n");
		return -EINVAL;
	}
	if (copy_from_user(msg, buf, size)) {
		pr_notice("copy_from_user error");
		return -EFAULT;
	}
	test_case = (unsigned int)msg[0] - '0';
	test_cpu = (unsigned int)msg[2] - '0';
	pr_notice("test_case = %d, test_cpu = %d", test_case, test_cpu);
	if ((msg[1] != ':') || (test_case < 1) || (test_case > 6)
	    || (test_cpu < 0) || (test_cpu > nr_cpu_ids)) {
		pr_notice("WDT test - Usage: [test case number(1~6):test cpu(0~%d)]\n"
								, nr_cpu_ids);
		return -EINVAL;
	}

	if (test_case == 1) {
		pr_notice("Test 1 : One CPU WDT timeout (smp_send_stop succeed)\n");
	} else if (test_case == 2) {
		pr_notice("Test 2 : One CPU WDT timeout, other CPU disable irq (smp_send_stop fail in old design)\n");
	} else if (test_case == 3) {
		pr_notice("Test 3 : WDT timeout and loop in panic flow\n");
	} else if (test_case == 4) {
		pr_notice("Test 4 : All CPU WDT timeout (other CPU stop in the loop)\n");
	} else if (test_case == 5) {
		pr_notice("Test 5 : Disable ALL CPU IRQ/FIQ (FIQ : HW_reboot, ATF : HWT\n");
	} else if (test_case == 6) {
		pr_notice("Test 6 : (For ATF) HW_REBOOT : change SMC call back function and while loop\n");
#ifdef CONFIG_ARM64
		arm_smccc_smc(MTK_SIP_KERNEL_WDT, (u64) &wdt_atf_hang, 0, 0, 0,
								0, 0, 0, &res);
#endif
#ifdef CONFIG_ARM_PSCI
		arm_smccc_smc(MTK_SIP_KERNEL_WDT, (u32) &wdt_atf_hang, 0, 0, 0,
								0, 0, 0, &res);
#endif
	} else {
		pr_notice("\n Unknown test_case %d\n", test_case);
		return -EINVAL;
	}

	/* create kernel threads and bind on every cpu */
	for (i = 0; i < nr_cpu_ids; i++) {
		n = snprintf(name, sizeof(name), "wd-test-%d", i);
		if (n < 0 || n >= sizeof(name))
			strncpy(name, "unknown error", sizeof(name) - 1);
		pr_notice("[WDK]thread name: %s\n", name);
		wk_tsk[i] = kthread_create(kwdt_thread_test, NULL, name);
		if (IS_ERR(wk_tsk[i])) {
			int ret = PTR_ERR(wk_tsk[i]);

			wk_tsk[i] = NULL;
			return ret;
		}
		kthread_bind(wk_tsk[i], i);
	}

	for (i = 0; i < nr_cpu_ids; i++) {
		pr_notice(" wake_up_process(wk_tsk[%d])\n", i);
		wake_up_process(wk_tsk[i]);
	}

	return size;
}

static ssize_t proc_generate_wdt_read(struct file *file,
				char __user *buf, size_t size, loff_t *ppos)
{
	char buffer[BUFSIZE];
	int len = snprintf(buffer, BUFSIZE,
			   "WDT test - Usage: [test case number:test cpu]\n");
	if (len < 0)
		pr_notice("%s: snprintf failed\n", __func__);
	if (*ppos)
		return 0;
	if (copy_to_user(buf, buffer, len)) {
		pr_notice("%s fail to output info.\n", __func__);
		return -EFAULT;
	}
	*ppos += len;
	return len;
}


/*****************************BEGIN OOPS***************************/
/**********BEGIN ISR trigger HWT**********/
/* kprobe pre_handler: called just before the probed instruction is executed */
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
	pr_info("process_name:[%s], pid = %d.\n", current->comm, current->pid);
	return 0;
}


/* kprobe post_handler: called after the probed instruction is executed */
int flag = 1;
void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
{
	if (flag) {
		flag = 0;
		mdelay(30 * 1000);
	}
}

static struct kprobe kp_kpd_irq_handler = {
	.symbol_name = "kpd_irq_handler",
	.pre_handler = handler_pre,
	.post_handler = handler_post,
};

static int register_kprobe_kpd_irq_handler(void)
{
	int ret = 0;

	/* All set to register with Kprobes */
	ret = register_kprobe(&kp_kpd_irq_handler);
	if (ret < 0)
		pr_info("register_kprobe failed, returned %d\n", ret);
	else
		pr_info("Planted kprobe at %p, press Vol+/- to trigger.\n",
				kp_kpd_irq_handler.addr);
	return ret;
}

/**********END ISR trigger HWT**********/
/**********BEGIN panic case**********/
static noinline int stack_overflow_routine(int x, int y, int z)
{
	char a[4];
	char *p = a;
	int i;

	for (i = 0; i < (x + y + z) * 2; i++)
		*(p + i) = i;
	/* stack overflow */
	return a[0] + a[3];
}

static noinline void buffer_over_flow(void)
{
	int n;

	pr_info("test case : buffer overflow\n");
	n = stack_overflow_routine(10, 1, 22);
	pr_info("%s: %d\n", __func__, n);
}

static noinline void access_null_pointer(void)
{
	void *p = NULL;

	pr_info("test case : derefence Null pointer\n");
	*((unsigned int *)p) = 0xDEAD;
}

static noinline void double_free(void)
{
	char *p = kmalloc(32, GFP_KERNEL);
	int i;

	if (p == NULL)
		return;

	pr_info("test case : double free\n");
	for (i = 0; i < 32; i++)
		p[i] = (char)i;
	pr_info("aee_ut_ke: call free\n");
	kfree(p);
	pr_info("aee_ut_ke: call free again\n");
	kfree(p);
}

static noinline void devide_by_0(void)
{
	int ZERO = 0;
	int number;

	pr_info("test case: division by %d\n", ZERO);
	number = 100 / ZERO;
	pr_info("%s: %d\n", __func__, number);
}

/**********END panic case**********/

static ssize_t proc_generate_oops_read(struct file *file,
				char __user *buf, size_t size, loff_t *ppos)
{
	int len;
	char buffer[BUFSIZE];

	len = snprintf(buffer, BUFSIZE, "Oops Generated!\n");
	if (copy_to_user(buf, buffer, len))
		pr_notice("%s fail to output info.\n", __func__);

	BUG();
	return len;
}

static ssize_t proc_generate_oops_write(struct file *file,
			const char __user *buf, size_t size, loff_t *ppos)
{
	char msg[6];
	int test_case, test_subcase, test_cpu;

	if ((size < 2) || (size > sizeof(msg))) {
		pr_notice("%s: count = %zx\n", __func__, size);
		return -EINVAL;
	}
	if (!buf) {
		pr_notice("%s: buf = NULL\n", __func__);
		return -EINVAL;
	}
	if (copy_from_user(msg, buf, size)) {
		pr_notice("%s: error\n", __func__);
		return -EFAULT;
	}

	test_case = (unsigned int)msg[0] - '0';
	test_subcase = (unsigned int)msg[2] - '0';
	test_cpu = (unsigned int)msg[4] - '0';
	pr_notice("test_case = %d-%d, test_cpu = %d\n", test_case,
						test_subcase, test_cpu);
	switch (test_case) {
	case 1:
		switch (test_subcase) {
		case 1:
			buffer_over_flow();
			break;
		case 2:
			access_null_pointer();
			break;
		case 3:
			double_free();
			break;
		case 4:
			devide_by_0();
			break;
		default:
			break;
		}
		break;
	case 2:
		register_kprobe_kpd_irq_handler();
		break;
	case 3:
		panic("aee test");
		break;
	default:
		break;
	}
	return size;
}

static int nested_panic(struct notifier_block *this, unsigned long event,
								void *ptr)
{
	pr_notice("\n => force nested panic\n");
	BUG();
	return 0;
}

static struct notifier_block panic_blk = {
	.notifier_call = nested_panic,
	.priority = INT_MAX - 100,
};

static ssize_t proc_generate_nested_ke_read(struct file *file, char __user *buf,
						size_t size, loff_t *ppos)
{
	atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
	pr_notice("\n => panic_notifier_list registered\n");
	BUG();

	return 0;
}

static ssize_t proc_generate_nested_ke_write(struct file *file,
			const char __user *buf, size_t size, loff_t *ppos)
{
	char msg[6];
	int test_case, test_subcase, test_cpu;

	if ((size < 2) || (size > sizeof(msg))) {
		pr_notice("%s: count = %zx\n", __func__, size);
		return -EINVAL;
	}
	if (!buf) {
		pr_notice("%s: buf = NULL\n", __func__);
		return -EINVAL;
	}
	if (copy_from_user(msg, buf, size)) {
		pr_notice("%s: error\n", __func__);
		return -EFAULT;
	}
	test_case = (unsigned int)msg[0] - '0';
	test_subcase = (unsigned int)msg[2] - '0';
	test_cpu = (unsigned int)msg[4] - '0';
	pr_notice("test_case = %d-%d, test_cpu = %d\n", test_case,
						test_subcase, test_cpu);
	switch (test_case) {
	case 1:
		register_die_notifier(&panic_blk);
		break;
	}
	//BUG();
	return 0;
}


static ssize_t proc_generate_ee_read(struct file *file, char __user *buf,
						size_t size, loff_t *ppos)
{
#define TEST_EE_LOG_SIZE	2048
#define TEST_EE_PHY_SIZE	65536

	char buffer[BUFSIZE];
	char *ptr, *log;
	int i, len;

	if ((*ppos)++)
		return 0;
	ptr = vmalloc(TEST_EE_PHY_SIZE);
	if (!ptr)
		return 0;
	log = kmalloc(TEST_EE_LOG_SIZE, GFP_KERNEL);
	if (!log) {
		vfree(ptr);
		return 0;
	}
	for (i = 0; i < TEST_EE_PHY_SIZE; i++)
		ptr[i] = (i % 26) + 'A';
	for (i = 0; i < TEST_EE_LOG_SIZE; i++)
		log[i] = i % 255;
	aed_md_exception_api((int *)log, TEST_EE_LOG_SIZE, (int *)ptr,
			TEST_EE_PHY_SIZE, __FILE__, DB_OPT_FTRACE);
	vfree(ptr);
	kfree(log);

	len = snprintf(buffer, BUFSIZE, "Modem EE Generated\n");
	if (copy_to_user(buf, buffer, len)) {
		pr_notice("%s fail to output info.\n", __func__);
		return -EFAULT;
	}
	*ppos += len;
	return len;
}

static ssize_t proc_generate_ee_write(struct file *file,
			const char __user *buf, size_t size, loff_t *ppos)
{
	return 0;
}

static ssize_t proc_generate_combo_read(struct file *file, char __user *buf,
						size_t size, loff_t *ppos)
{
#define TEST_COMBO_PHY_SIZE	65536
	char buffer[BUFSIZE];
	int i, len;
	char *ptr;

	if ((*ppos)++)
		return 0;
	ptr = vmalloc(TEST_COMBO_PHY_SIZE);
	if (!ptr)
		return snprintf(buffer, BUFSIZE, "kmalloc fail\n");
	for (i = 0; i < TEST_COMBO_PHY_SIZE; i++)
		ptr[i] = (i % 26) + 'A';

	aed_combo_exception(NULL, 0, (int *)ptr, TEST_COMBO_PHY_SIZE, __FILE__);
	vfree(ptr);

	len = snprintf(buffer, BUFSIZE, "Combo EE Generated\n");
	if (copy_to_user(buf, buffer, len)) {
		pr_notice("%s fail to output info.\n", __func__);
		return -EFAULT;
	}
	*ppos += len;
	return len;
}

static ssize_t proc_generate_combo_write(struct file *file,
			const char __user *buf, size_t size, loff_t *ppos)
{
	return 0;
}

static ssize_t proc_generate_md32_read(struct file *file, char __user *buf,
				size_t size, loff_t *ppos)
{
#define TEST_MD32_PHY_SIZE	65536
	char buffer[BUFSIZE];
	int i, len;
	char *ptr;

	if ((*ppos)++)
		return 0;
	ptr = vmalloc(TEST_MD32_PHY_SIZE);
	if (!ptr)
		return 0;
	for (i = 0; i < TEST_MD32_PHY_SIZE; i++)
		ptr[i] = (i % 26) + 'a';

	len = snprintf(buffer, BUFSIZE, "MD32 EE log here\n");
	if (len <= 0)
		pr_debug("%s: snprintf error\n", __func__);
	aed_md32_exception((int *)buffer, (int)sizeof(buffer), (int *)ptr,
			TEST_MD32_PHY_SIZE, __FILE__);
	vfree(ptr);

	len = snprintf(buffer, BUFSIZE, "MD32 EE Generated\n");
	if (len < 0) {
		pr_info("%s: snprintf failed\n", __func__);
		return -EFAULT;
	}
	if (copy_to_user(buf, buffer, len)) {
		pr_notice("%s fail to output info.\n", __func__);
		return -EFAULT;
	}
	*ppos += len;
	return len;
}

static ssize_t proc_generate_md32_write(struct file *file,
					const char __user *buf, size_t size,
					loff_t *ppos)
{
	return 0;
}

static ssize_t proc_generate_scp_read(struct file *file,
				       char __user *buf, size_t size,
				       loff_t *ppos)
{
#define TEST_SCP_PHY_SIZE	65536
	char buffer[BUFSIZE];
	int i, len;
	char *ptr;

	if ((*ppos)++)
		return 0;
	ptr = vmalloc(TEST_SCP_PHY_SIZE);
	if (!ptr)
		return 0;
	for (i = 0; i < TEST_SCP_PHY_SIZE; i++)
		ptr[i] = (i % 26) + 'a';

	len = snprintf(buffer, BUFSIZE, "SCP EE log here\n");
	if (len <= 0)
		pr_debug("%s: snprintf error\n", __func__);
	aed_scp_exception((int *)buffer, (int)sizeof(buffer), (int *)ptr,
						TEST_SCP_PHY_SIZE, __FILE__);
	vfree(ptr);

	len = snprintf(buffer, BUFSIZE, "SCP EE Generated\n");
	if (len < 0) {
		pr_info("%s: snprintf failed\n", __func__);
		return -EFAULT;
	}
	if (copy_to_user(buf, buffer, len)) {
		pr_notice("%s fail to output info.\n", __func__);
		return -EFAULT;
	}
	*ppos += len;
	return len;
}

static ssize_t proc_generate_scp_write(struct file *file,
					const char __user *buf, size_t size,
					loff_t *ppos)
{
	return 0;
}

static ssize_t proc_generate_adsp_read(struct file *file,
					char __user *buf, size_t size,
					loff_t *ppos)
{
#define TEST_ADSP_PHY_SIZE      65536
	char buffer[BUFSIZE];
	int i;
	char *ptr;
	int n;

	if ((*ppos)++)
		return 0;
	ptr = kmalloc(TEST_ADSP_PHY_SIZE, GFP_KERNEL);
	if (ptr == NULL)
		return sprintf(buffer, "kmalloc fail\n");
	for (i = 0; i < TEST_ADSP_PHY_SIZE; i++)
		ptr[i] = (i % 26) + 'a';

	n = sprintf(buffer, "ADSP EE log here\n");
	if (n < 0 || n >= sizeof(buffer))
		strncpy(buffer, "unknown error", sizeof(buffer));
	aed_common_exception("adsp", (int *)buffer, (int)sizeof(buffer),
				(int *)ptr, TEST_ADSP_PHY_SIZE, __FILE__);
	kfree(ptr);
	return sprintf(buffer, "ADSP EE Generated\n");
}

static ssize_t proc_generate_adsp_write(struct file *file,
					const char __user *buf, size_t size,
					loff_t *ppos)
{
	return 0;
}

static uint32_t test_value[3];
static ssize_t proc_generate_platform_write(struct file *file,
					const char __user *buf, size_t size,
					loff_t *ppos)
{
	char msg[BUFSIZE], *name, *cur = msg;
	int ret = 0, i = 0;
	void __iomem *base;

	if ((size < 10) || (size > sizeof(msg))) {
		pr_notice("%s: count = %zx\n", __func__, size);
		return -EINVAL;
	}
	if (!buf) {
		pr_notice("%s: buf = NULL\n", __func__);
		return -EINVAL;
	}
	if (copy_from_user(msg, buf, size)) {
		pr_notice("%s: error\n", __func__);
		return -EFAULT;
	}

	while ((name = strsep(&cur, " ")) && *name && i < 3) {
		ret = kstrtoul(name, 16, (unsigned long *)(&test_value[i]));
		if (ret) {
			pr_notice("kstrtoul %s error.\n", name);
			return -EINVAL;
		}
		i++;
	}

	if ((test_value[0] != 0x72656164) && (test_value[0] != 0x77726974))
		return -EINVAL;

	base = ioremap(test_value[1], 0x100);
	if (!base) {
		pr_notice("Couldn't map 0x%x.\n", test_value[1]);
		return -ENOMEM;
	}

	if (test_value[0] == 0x72656164 && i == 2) {
		pr_info("read 0x%x value:", test_value[1]);
		test_value[2] = readl(base);
		pr_info("0x%x.\n", test_value[2]);
	} else if (test_value[0] == 0x77726974 && i == 3) {
		pr_info("write 0x%x to 0x%x.\n", test_value[2], test_value[1]);
		writel(test_value[2], base);
	} else {
		test_value[0] = 0;
		test_value[1] = 0;
		test_value[2] = 0;
	}

	iounmap(base);
	return size;
}

static ssize_t proc_generate_platform_read(struct file *file,
					char __user *buf, size_t size,
					loff_t *ppos)
{
	char buffer[BUFSIZE];
	int len = 0;

	if ((*ppos)++)
		return 0;

	if (test_value[0] == 0x72656164)
		len = snprintf(buffer, BUFSIZE, "read 0x%x value 0x%x.\n",
			test_value[1], test_value[2]);
	else if (test_value[0] == 0x77726974)
		len = snprintf(buffer, BUFSIZE, "write 0x%x value 0x%x.\n",
			test_value[1], test_value[2]);

	if (copy_to_user(buf, buffer, len)) {
		pr_notice("%s fail to output info.\n", __func__);
		return -EFAULT;
	}
	*ppos += len;
	return len;
}



static ssize_t proc_generate_kernel_notify_read(struct file *file,
						char __user *buf, size_t size,
						loff_t *ppos)
{
	char buffer[BUFSIZE];
	int len = snprintf(buffer, BUFSIZE,
			   "Usage: write message with format \"R|W|E:Tag:You Message\" into this file to generate kernel warning\n");
	if (*ppos)
		return 0;
	if (copy_to_user(buf, buffer, len)) {
		pr_notice("%s fail to output info.\n", __func__);
		return -EFAULT;
	}
	*ppos += len;
	return len;
}


static ssize_t proc_generate_kernel_notify_write(struct file *file,
						 const char __user *buf,
						 size_t size,
						 loff_t *ppos)
{
	char msg[164], *colon_ptr;

	if (size == 0)
		return -EINVAL;

	if ((size < 5) || (size >= sizeof(msg))) {
		pr_notice("aed: %s size sould be >= 5 and <= %zx bytes.\n",
				__func__, sizeof(msg));
		return -EINVAL;
	}
	if (!buf) {
		pr_notice("aed: %s buf = NULL\n", __func__);
		return -EINVAL;
	}

	if (copy_from_user(msg, buf, size)) {
		pr_notice("aed: %s unable to read message\n", __func__);
		return -EFAULT;
	}
	/* Be safe */
	msg[size] = 0;

	if (msg[1] != ':')
		return -EINVAL;
	colon_ptr = strchr(&msg[2], ':');
	if (!colon_ptr || ((colon_ptr - msg) > 32)) {
		pr_notice("aed: %s cannot find valid module name\n", __func__);
		return -EINVAL;
	}
	*colon_ptr = 0;

	switch (msg[0]) {
	case 'R':
		aee_kernel_reminding_api(__FILE__, __LINE__,
				DB_OPT_DEFAULT | DB_OPT_NATIVE_BACKTRACE, &msg[2], colon_ptr + 1);
		break;

	case 'W':
		aee_kernel_warning_api(__FILE__, __LINE__,
				DB_OPT_DEFAULT | DB_OPT_NATIVE_BACKTRACE, &msg[2], colon_ptr + 1);
		break;

	case 'E':
		aee_kernel_exception_api(__FILE__, __LINE__,
				DB_OPT_DEFAULT | DB_OPT_NATIVE_BACKTRACE, &msg[2], colon_ptr + 1);
		break;

	default:
		return -EINVAL;
	}

	return size;
}

AED_FILE_OPS(generate_oops);
AED_FILE_OPS(generate_nested_ke);
AED_FILE_OPS(generate_kernel_notify);
AED_FILE_OPS(generate_wdt);
AED_FILE_OPS(generate_ee);
AED_FILE_OPS(generate_combo);
AED_FILE_OPS(generate_md32);
AED_FILE_OPS(generate_scp);
AED_FILE_OPS(generate_adsp);
AED_FILE_OPS(generate_platform);

int aed_proc_debug_init(struct proc_dir_entry *aed_proc_dir)
{
	/* 0600: S_IRUSR | S_IWUSR */
	AED_PROC_ENTRY(aed/generate-oops, generate_oops, 0600);
	/* 0400: S_IRUSR */
	AED_PROC_ENTRY(aed/generate-nested-ke, generate_nested_ke, 0400);
	/* 0600: S_IRUSR | S_IWUSR */
	AED_PROC_ENTRY(aed/generate-kernel-notify, generate_kernel_notify, 0600);
	AED_PROC_ENTRY(aed/generate-wdt, generate_wdt, 0600);
	/* 0400: S_IRUSR */
	AED_PROC_ENTRY(aed/generate-ee, generate_ee, 0400);
	AED_PROC_ENTRY(aed/generate-combo, generate_combo, 0400);
	AED_PROC_ENTRY(aed/generate-md32, generate_md32, 0400);
	AED_PROC_ENTRY(aed/generate-scp, generate_scp, 0400);
	AED_PROC_ENTRY(aed/generate-adsp, generate_adsp, 0400);
	AED_PROC_ENTRY(aed/generate-platform, generate_platform, 0600);

	return 0;
}

int aed_proc_debug_done(struct proc_dir_entry *aed_proc_dir)
{
	remove_proc_entry("generate-oops", aed_proc_dir);
	remove_proc_entry("generate-nested-ke", aed_proc_dir);
	remove_proc_entry("generate-kernel-notify", aed_proc_dir);
	remove_proc_entry("generate-ee", aed_proc_dir);
	remove_proc_entry("generate-combo", aed_proc_dir);
	remove_proc_entry("generate-md32", aed_proc_dir);
	remove_proc_entry("generate-scp", aed_proc_dir);
	remove_proc_entry("generate-wdt", aed_proc_dir);
	remove_proc_entry("generate-adsp", aed_proc_dir);
	remove_proc_entry("generate-platform", aed_proc_dir);
	return 0;
}
