xref: /OK3568_Linux_fs/kernel/drivers/acpi/ec_sys.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * ec_sys.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2010 SUSE Products GmbH/Novell
6*4882a593Smuzhiyun  * Author:
7*4882a593Smuzhiyun  *      Thomas Renninger <trenn@suse.de>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/acpi.h>
12*4882a593Smuzhiyun #include <linux/debugfs.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/uaccess.h>
15*4882a593Smuzhiyun #include "internal.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
18*4882a593Smuzhiyun MODULE_DESCRIPTION("ACPI EC sysfs access driver");
19*4882a593Smuzhiyun MODULE_LICENSE("GPL");
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun static bool write_support;
22*4882a593Smuzhiyun module_param(write_support, bool, 0644);
23*4882a593Smuzhiyun MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may "
24*4882a593Smuzhiyun 		 "be needed.");
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define EC_SPACE_SIZE 256
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun static struct dentry *acpi_ec_debugfs_dir;
29*4882a593Smuzhiyun 
acpi_ec_read_io(struct file * f,char __user * buf,size_t count,loff_t * off)30*4882a593Smuzhiyun static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
31*4882a593Smuzhiyun 			       size_t count, loff_t *off)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	/* Use this if support reading/writing multiple ECs exists in ec.c:
34*4882a593Smuzhiyun 	 * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
35*4882a593Smuzhiyun 	 */
36*4882a593Smuzhiyun 	unsigned int size = EC_SPACE_SIZE;
37*4882a593Smuzhiyun 	loff_t init_off = *off;
38*4882a593Smuzhiyun 	int err = 0;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	if (*off >= size)
41*4882a593Smuzhiyun 		return 0;
42*4882a593Smuzhiyun 	if (*off + count >= size) {
43*4882a593Smuzhiyun 		size -= *off;
44*4882a593Smuzhiyun 		count = size;
45*4882a593Smuzhiyun 	} else
46*4882a593Smuzhiyun 		size = count;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	while (size) {
49*4882a593Smuzhiyun 		u8 byte_read;
50*4882a593Smuzhiyun 		err = ec_read(*off, &byte_read);
51*4882a593Smuzhiyun 		if (err)
52*4882a593Smuzhiyun 			return err;
53*4882a593Smuzhiyun 		if (put_user(byte_read, buf + *off - init_off)) {
54*4882a593Smuzhiyun 			if (*off - init_off)
55*4882a593Smuzhiyun 				return *off - init_off; /* partial read */
56*4882a593Smuzhiyun 			return -EFAULT;
57*4882a593Smuzhiyun 		}
58*4882a593Smuzhiyun 		*off += 1;
59*4882a593Smuzhiyun 		size--;
60*4882a593Smuzhiyun 	}
61*4882a593Smuzhiyun 	return count;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
acpi_ec_write_io(struct file * f,const char __user * buf,size_t count,loff_t * off)64*4882a593Smuzhiyun static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
65*4882a593Smuzhiyun 				size_t count, loff_t *off)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	/* Use this if support reading/writing multiple ECs exists in ec.c:
68*4882a593Smuzhiyun 	 * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
69*4882a593Smuzhiyun 	 */
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	unsigned int size = count;
72*4882a593Smuzhiyun 	loff_t init_off = *off;
73*4882a593Smuzhiyun 	int err = 0;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	if (!write_support)
76*4882a593Smuzhiyun 		return -EINVAL;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	if (*off >= EC_SPACE_SIZE)
79*4882a593Smuzhiyun 		return 0;
80*4882a593Smuzhiyun 	if (*off + count >= EC_SPACE_SIZE) {
81*4882a593Smuzhiyun 		size = EC_SPACE_SIZE - *off;
82*4882a593Smuzhiyun 		count = size;
83*4882a593Smuzhiyun 	}
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	while (size) {
86*4882a593Smuzhiyun 		u8 byte_write;
87*4882a593Smuzhiyun 		if (get_user(byte_write, buf + *off - init_off)) {
88*4882a593Smuzhiyun 			if (*off - init_off)
89*4882a593Smuzhiyun 				return *off - init_off; /* partial write */
90*4882a593Smuzhiyun 			return -EFAULT;
91*4882a593Smuzhiyun 		}
92*4882a593Smuzhiyun 		err = ec_write(*off, byte_write);
93*4882a593Smuzhiyun 		if (err)
94*4882a593Smuzhiyun 			return err;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 		*off += 1;
97*4882a593Smuzhiyun 		size--;
98*4882a593Smuzhiyun 	}
99*4882a593Smuzhiyun 	return count;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun static const struct file_operations acpi_ec_io_ops = {
103*4882a593Smuzhiyun 	.owner = THIS_MODULE,
104*4882a593Smuzhiyun 	.open  = simple_open,
105*4882a593Smuzhiyun 	.read  = acpi_ec_read_io,
106*4882a593Smuzhiyun 	.write = acpi_ec_write_io,
107*4882a593Smuzhiyun 	.llseek = default_llseek,
108*4882a593Smuzhiyun };
109*4882a593Smuzhiyun 
acpi_ec_add_debugfs(struct acpi_ec * ec,unsigned int ec_device_count)110*4882a593Smuzhiyun static void acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	struct dentry *dev_dir;
113*4882a593Smuzhiyun 	char name[64];
114*4882a593Smuzhiyun 	umode_t mode = 0400;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	if (ec_device_count == 0)
117*4882a593Smuzhiyun 		acpi_ec_debugfs_dir = debugfs_create_dir("ec", NULL);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	sprintf(name, "ec%u", ec_device_count);
120*4882a593Smuzhiyun 	dev_dir = debugfs_create_dir(name, acpi_ec_debugfs_dir);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe);
123*4882a593Smuzhiyun 	debugfs_create_bool("use_global_lock", 0444, dev_dir,
124*4882a593Smuzhiyun 			    &first_ec->global_lock);
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	if (write_support)
127*4882a593Smuzhiyun 		mode = 0600;
128*4882a593Smuzhiyun 	debugfs_create_file("io", mode, dev_dir, ec, &acpi_ec_io_ops);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
acpi_ec_sys_init(void)131*4882a593Smuzhiyun static int __init acpi_ec_sys_init(void)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	if (first_ec)
134*4882a593Smuzhiyun 		acpi_ec_add_debugfs(first_ec, 0);
135*4882a593Smuzhiyun 	return 0;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
acpi_ec_sys_exit(void)138*4882a593Smuzhiyun static void __exit acpi_ec_sys_exit(void)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	debugfs_remove_recursive(acpi_ec_debugfs_dir);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun module_init(acpi_ec_sys_init);
144*4882a593Smuzhiyun module_exit(acpi_ec_sys_exit);
145