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

Archive Download this file



interactive