0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/acpi.h>
0012 #include <linux/debugfs.h>
0013 #include <linux/module.h>
0014 #include <linux/uaccess.h>
0015 #include "internal.h"
0016
0017 MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
0018 MODULE_DESCRIPTION("ACPI EC sysfs access driver");
0019 MODULE_LICENSE("GPL");
0020
0021 static bool write_support;
0022 module_param_hw(write_support, bool, other, 0644);
0023 MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may "
0024 "be needed.");
0025
0026 #define EC_SPACE_SIZE 256
0027
0028 static struct dentry *acpi_ec_debugfs_dir;
0029
0030 static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
0031 size_t count, loff_t *off)
0032 {
0033
0034
0035
0036 unsigned int size = EC_SPACE_SIZE;
0037 loff_t init_off = *off;
0038 int err = 0;
0039
0040 if (*off >= size)
0041 return 0;
0042 if (*off + count >= size) {
0043 size -= *off;
0044 count = size;
0045 } else
0046 size = count;
0047
0048 while (size) {
0049 u8 byte_read;
0050 err = ec_read(*off, &byte_read);
0051 if (err)
0052 return err;
0053 if (put_user(byte_read, buf + *off - init_off)) {
0054 if (*off - init_off)
0055 return *off - init_off;
0056 return -EFAULT;
0057 }
0058 *off += 1;
0059 size--;
0060 }
0061 return count;
0062 }
0063
0064 static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
0065 size_t count, loff_t *off)
0066 {
0067
0068
0069
0070
0071 unsigned int size = count;
0072 loff_t init_off = *off;
0073 int err = 0;
0074
0075 if (!write_support)
0076 return -EINVAL;
0077
0078 if (*off >= EC_SPACE_SIZE)
0079 return 0;
0080 if (*off + count >= EC_SPACE_SIZE) {
0081 size = EC_SPACE_SIZE - *off;
0082 count = size;
0083 }
0084
0085 while (size) {
0086 u8 byte_write;
0087 if (get_user(byte_write, buf + *off - init_off)) {
0088 if (*off - init_off)
0089 return *off - init_off;
0090 return -EFAULT;
0091 }
0092 err = ec_write(*off, byte_write);
0093 if (err)
0094 return err;
0095
0096 *off += 1;
0097 size--;
0098 }
0099 return count;
0100 }
0101
0102 static const struct file_operations acpi_ec_io_ops = {
0103 .owner = THIS_MODULE,
0104 .open = simple_open,
0105 .read = acpi_ec_read_io,
0106 .write = acpi_ec_write_io,
0107 .llseek = default_llseek,
0108 };
0109
0110 static void acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count)
0111 {
0112 struct dentry *dev_dir;
0113 char name[64];
0114 umode_t mode = 0400;
0115
0116 if (ec_device_count == 0)
0117 acpi_ec_debugfs_dir = debugfs_create_dir("ec", NULL);
0118
0119 sprintf(name, "ec%u", ec_device_count);
0120 dev_dir = debugfs_create_dir(name, acpi_ec_debugfs_dir);
0121
0122 debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe);
0123 debugfs_create_bool("use_global_lock", 0444, dev_dir,
0124 &first_ec->global_lock);
0125
0126 if (write_support)
0127 mode = 0600;
0128 debugfs_create_file("io", mode, dev_dir, ec, &acpi_ec_io_ops);
0129 }
0130
0131 static int __init acpi_ec_sys_init(void)
0132 {
0133 if (first_ec)
0134 acpi_ec_add_debugfs(first_ec, 0);
0135 return 0;
0136 }
0137
0138 static void __exit acpi_ec_sys_exit(void)
0139 {
0140 debugfs_remove_recursive(acpi_ec_debugfs_dir);
0141 }
0142
0143 module_init(acpi_ec_sys_init);
0144 module_exit(acpi_ec_sys_exit);