Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * custom_method.c - debugfs interface for customizing ACPI control method
  4 */
  5
  6#include <linux/init.h>
  7#include <linux/module.h>
  8#include <linux/kernel.h>
  9#include <linux/uaccess.h>
 10#include <linux/debugfs.h>
 11#include <linux/acpi.h>
 12#include <linux/security.h>
 13
 14#include "internal.h"
 15
 16#define _COMPONENT		ACPI_SYSTEM_COMPONENT
 17ACPI_MODULE_NAME("custom_method");
 18MODULE_LICENSE("GPL");
 19
 20static struct dentry *cm_dentry;
 21
 22/* /sys/kernel/debug/acpi/custom_method */
 23
 24static ssize_t cm_write(struct file *file, const char __user * user_buf,
 25			size_t count, loff_t *ppos)
 26{
 27	static char *buf;
 28	static u32 max_size;
 29	static u32 uncopied_bytes;
 30
 31	struct acpi_table_header table;
 32	acpi_status status;
 33	int ret;
 34
 35	ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
 36	if (ret)
 37		return ret;
 38
 39	if (!(*ppos)) {
 40		/* parse the table header to get the table length */
 41		if (count <= sizeof(struct acpi_table_header))
 42			return -EINVAL;
 43		if (copy_from_user(&table, user_buf,
 44				   sizeof(struct acpi_table_header)))
 45			return -EFAULT;
 46		uncopied_bytes = max_size = table.length;
 47		buf = kzalloc(max_size, GFP_KERNEL);
 48		if (!buf)
 49			return -ENOMEM;
 50	}
 51
 52	if (buf == NULL)
 53		return -EINVAL;
 54
 55	if ((*ppos > max_size) ||
 56	    (*ppos + count > max_size) ||
 57	    (*ppos + count < count) ||
 58	    (count > uncopied_bytes)) {
 59		kfree(buf);
 60		return -EINVAL;
 61	}
 62
 63	if (copy_from_user(buf + (*ppos), user_buf, count)) {
 64		kfree(buf);
 65		buf = NULL;
 66		return -EFAULT;
 67	}
 68
 69	uncopied_bytes -= count;
 70	*ppos += count;
 71
 72	if (!uncopied_bytes) {
 73		status = acpi_install_method(buf);
 74		kfree(buf);
 75		buf = NULL;
 76		if (ACPI_FAILURE(status))
 77			return -EINVAL;
 78		add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
 79	}
 80
 81	kfree(buf);
 82	return count;
 83}
 84
 85static const struct file_operations cm_fops = {
 86	.write = cm_write,
 87	.llseek = default_llseek,
 88};
 89
 90static int __init acpi_custom_method_init(void)
 91{
 92	cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
 93					acpi_debugfs_dir, NULL, &cm_fops);
 94	return 0;
 95}
 96
 97static void __exit acpi_custom_method_exit(void)
 98{
 99	debugfs_remove(cm_dentry);
100}
101
102module_init(acpi_custom_method_init);
103module_exit(acpi_custom_method_exit);