Blame view
drivers/acpi/ec_sys.c
3.49 KB
9827886dc ACPI: Provide /sy... |
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 ACPI: Provide /sy... |
10 11 12 |
#include <linux/kernel.h> #include <linux/acpi.h> #include <linux/debugfs.h> |
cc4b859c7 acpi: add module.... |
13 |
#include <linux/module.h> |
ecde3003e ACPI / EC: access... |
14 |
#include <linux/uaccess.h> |
1195a0981 ACPI: Provide /sy... |
15 16 17 18 19 |
#include "internal.h" MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>"); MODULE_DESCRIPTION("ACPI EC sysfs access driver"); MODULE_LICENSE("GPL"); |
500de3dd4 acpi ec_sys: Be m... |
20 21 22 23 |
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 ACPI: Provide /sy... |
24 |
#define EC_SPACE_SIZE 256 |
1195a0981 ACPI: Provide /sy... |
25 |
static struct dentry *acpi_ec_debugfs_dir; |
9827886dc ACPI: Provide /sy... |
26 27 28 29 30 31 32 |
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; |
9827886dc ACPI: Provide /sy... |
33 34 35 36 37 38 39 40 41 42 43 44 |
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) { |
ecde3003e ACPI / EC: access... |
45 46 |
u8 byte_read; err = ec_read(*off, &byte_read); |
9827886dc ACPI: Provide /sy... |
47 48 |
if (err) return err; |
ecde3003e ACPI / EC: access... |
49 50 51 52 53 |
if (put_user(byte_read, buf + *off - init_off)) { if (*off - init_off) return *off - init_off; /* partial read */ return -EFAULT; } |
9827886dc ACPI: Provide /sy... |
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
*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; |
9827886dc ACPI: Provide /sy... |
69 |
int err = 0; |
1b6e75ee2 ACPI / EC: Deny w... |
70 71 |
if (!write_support) return -EINVAL; |
9827886dc ACPI: Provide /sy... |
72 73 74 75 76 77 78 79 |
if (*off >= EC_SPACE_SIZE) return 0; if (*off + count >= EC_SPACE_SIZE) { size = EC_SPACE_SIZE - *off; count = size; } while (size) { |
ecde3003e ACPI / EC: access... |
80 81 82 83 84 85 |
u8 byte_write; if (get_user(byte_write, buf + *off - init_off)) { if (*off - init_off) return *off - init_off; /* partial write */ return -EFAULT; } |
9827886dc ACPI: Provide /sy... |
86 87 88 89 90 91 92 93 94 |
err = ec_write(*off, byte_write); if (err) return err; *off += 1; size--; } return count; } |
9c8b04be4 ACPI: constify op... |
95 |
static const struct file_operations acpi_ec_io_ops = { |
9827886dc ACPI: Provide /sy... |
96 |
.owner = THIS_MODULE, |
234e34058 simple_open: auto... |
97 |
.open = simple_open, |
9827886dc ACPI: Provide /sy... |
98 99 |
.read = acpi_ec_read_io, .write = acpi_ec_write_io, |
6038f373a llseek: automatic... |
100 |
.llseek = default_llseek, |
9827886dc ACPI: Provide /sy... |
101 |
}; |
49894d8d5 ACPI / EC: Mark t... |
102 |
static int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) |
1195a0981 ACPI: Provide /sy... |
103 104 105 |
{ struct dentry *dev_dir; char name[64]; |
f4ae40a6a switch debugfs to... |
106 |
umode_t mode = 0400; |
500de3dd4 acpi ec_sys: Be m... |
107 |
|
1195a0981 ACPI: Provide /sy... |
108 109 110 111 112 113 114 115 116 |
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 acpi ec_sys: Be m... |
117 118 |
if (ec_device_count != 0) goto error; |
1195a0981 ACPI: Provide /sy... |
119 120 |
return -ENOMEM; } |
500de3dd4 acpi ec_sys: Be m... |
121 122 123 |
if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe)) goto error; if (!debugfs_create_bool("use_global_lock", 0444, dev_dir, |
6e58f752a ACPI / EC: Fix br... |
124 |
&first_ec->global_lock)) |
500de3dd4 acpi ec_sys: Be m... |
125 126 127 128 129 130 |
goto error; if (write_support) mode = 0600; if (!debugfs_create_file("io", mode, dev_dir, ec, &acpi_ec_io_ops)) goto error; |
1195a0981 ACPI: Provide /sy... |
131 |
return 0; |
500de3dd4 acpi ec_sys: Be m... |
132 133 134 135 |
error: debugfs_remove_recursive(acpi_ec_debugfs_dir); return -ENOMEM; |
1195a0981 ACPI: Provide /sy... |
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
} 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); |