Commit 9827886dce77c47c378ce3154689cea2c45c731d

Authored by Thomas Renninger
Committed by Matthew Garrett
1 parent 1195a09816

ACPI: Provide /sys/kernel/debug//ec/ec0/io for binary access to the EC

A userspace app to easily read/write the EC can be found here:
ftp://ftp.suse.com/pub/people/trenn/sources/ec/ec_access.c

Multiple ECs are not supported, but shouldn't be hard to add as soon
as the ec driver itself will support them.

Signed-off-by: Thomas Renninger <trenn@suse.de>
CC: Alexey Starikovskiy <astarikovskiy@suse.de>
CC: Len Brown <lenb@kernel.org>
CC: linux-kernel@vger.kernel.org
CC: linux-acpi@vger.kernel.org
CC: platform-driver-x86@vger.kernel.org
Signed-off-by: Matthew Garrett <mjg@redhat.com>

Showing 1 changed file with 86 additions and 0 deletions Side-by-side Diff

drivers/acpi/ec_sys.c
  1 +/*
  2 + * ec_sys.c
  3 + *
  4 + * Copyright (C) 2010 SUSE Products GmbH/Novell
  5 + * Author:
  6 + * Thomas Renninger <trenn@suse.de>
  7 + *
  8 + * This work is licensed under the terms of the GNU GPL, version 2.
  9 + */
  10 +
1 11 #include <linux/kernel.h>
2 12 #include <linux/acpi.h>
3 13 #include <linux/debugfs.h>
4 14  
... ... @@ -7,12 +17,87 @@
7 17 MODULE_DESCRIPTION("ACPI EC sysfs access driver");
8 18 MODULE_LICENSE("GPL");
9 19  
  20 +#define EC_SPACE_SIZE 256
  21 +
10 22 struct sysdev_class acpi_ec_sysdev_class = {
11 23 .name = "ec",
12 24 };
13 25  
14 26 static struct dentry *acpi_ec_debugfs_dir;
15 27  
  28 +static int acpi_ec_open_io(struct inode *i, struct file *f)
  29 +{
  30 + f->private_data = i->i_private;
  31 + return 0;
  32 +}
  33 +
  34 +static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
  35 + size_t count, loff_t *off)
  36 +{
  37 + /* Use this if support reading/writing multiple ECs exists in ec.c:
  38 + * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
  39 + */
  40 + unsigned int size = EC_SPACE_SIZE;
  41 + u8 *data = (u8 *) buf;
  42 + loff_t init_off = *off;
  43 + int err = 0;
  44 +
  45 + if (*off >= size)
  46 + return 0;
  47 + if (*off + count >= size) {
  48 + size -= *off;
  49 + count = size;
  50 + } else
  51 + size = count;
  52 +
  53 + while (size) {
  54 + err = ec_read(*off, &data[*off - init_off]);
  55 + if (err)
  56 + return err;
  57 + *off += 1;
  58 + size--;
  59 + }
  60 + return count;
  61 +}
  62 +
  63 +static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
  64 + size_t count, loff_t *off)
  65 +{
  66 + /* Use this if support reading/writing multiple ECs exists in ec.c:
  67 + * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
  68 + */
  69 +
  70 + unsigned int size = count;
  71 + loff_t init_off = *off;
  72 + u8 *data = (u8 *) buf;
  73 + int err = 0;
  74 +
  75 + if (*off >= EC_SPACE_SIZE)
  76 + return 0;
  77 + if (*off + count >= EC_SPACE_SIZE) {
  78 + size = EC_SPACE_SIZE - *off;
  79 + count = size;
  80 + }
  81 +
  82 + while (size) {
  83 + u8 byte_write = data[*off - init_off];
  84 + err = ec_write(*off, byte_write);
  85 + if (err)
  86 + return err;
  87 +
  88 + *off += 1;
  89 + size--;
  90 + }
  91 + return count;
  92 +}
  93 +
  94 +static struct file_operations acpi_ec_io_ops = {
  95 + .owner = THIS_MODULE,
  96 + .open = acpi_ec_open_io,
  97 + .read = acpi_ec_read_io,
  98 + .write = acpi_ec_write_io,
  99 +};
  100 +
16 101 int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count)
17 102 {
18 103 struct dentry *dev_dir;
... ... @@ -35,6 +120,7 @@
35 120 debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe);
36 121 debugfs_create_bool("use_global_lock", 0444, dev_dir,
37 122 (u32 *)&first_ec->global_lock);
  123 + debugfs_create_file("io", 0666, dev_dir, ec, &acpi_ec_io_ops);
38 124 return 0;
39 125 }
40 126