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