forked from right-0903/kc57_battery
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ec.c
100 lines (79 loc) · 2.22 KB
/
ec.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// SPDX-License-Identifier: GPL-2.0
#include <linux/acpi.h>
#include <linux/compiler_types.h>
#include <linux/error-injection.h>
#include <linux/rwsem.h>
#include <linux/printk.h>
#include <linux/wmi.h>
#include "ec.h"
#include "wmi.h"
/* ========================================================================== */
static DECLARE_RWSEM(ec_lock);
/* ========================================================================== */
int __must_check kc57_ec_lock(void)
{
return down_write_killable(&ec_lock);
}
void kc57_ec_unlock(void)
{
up_write(&ec_lock);
}
int __must_check kc57_ec_transaction(uint16_t addr, uint16_t data,
union kc57_ec_result *result, bool read)
{
uint8_t buf[] = {
addr & 0xFF,
addr >> 8,
data & 0xFF,
data >> 8,
0,
read ? 1 : 0,
0,
0,
};
static_assert(ARRAY_SIZE(buf) == 8);
/* the returned ACPI_TYPE_BUFFER is 40 bytes long for some reason ... */
uint8_t output_buf[sizeof(union acpi_object) + 40];
struct acpi_buffer input = { sizeof(buf), buf },
output = { sizeof(output_buf), output_buf };
union acpi_object *obj;
acpi_status status = AE_OK;
int err;
if (read) err = down_read_killable(&ec_lock);
else err = down_write_killable(&ec_lock);
if (err)
goto out;
memset(output_buf, 0, sizeof(output_buf));
status = wmi_evaluate_method(KC57_WMI_WMBC_GUID, 0,
KC57_WMBC_GETSETULONG_ID, &input, &output);
if (read) up_read(&ec_lock);
else up_write(&ec_lock);
if (ACPI_FAILURE(status)) {
err = -EIO;
goto out;
}
obj = output.pointer;
if (result) {
if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length >= sizeof(*result)) {
memcpy(result, obj->buffer.pointer, sizeof(*result));
} else {
err = -ENODATA;
goto out;
}
}
out:
pr_debug(
"%s(addr=%#06x, data=%#06x, result=%c, read=%c)"
": (%d) [%#010lx] %s"
": [%*ph]\n",
__func__, (unsigned int) addr, (unsigned int) data,
result ? 'y' : 'n', read ? 'y' : 'n',
err, (unsigned long) status, acpi_format_exception(status),
(obj && obj->type == ACPI_TYPE_BUFFER) ?
(int) min(sizeof(*result), (size_t) obj->buffer.length) : 0,
(obj && obj->type == ACPI_TYPE_BUFFER) ?
obj->buffer.pointer : NULL
);
return err;
}
ALLOW_ERROR_INJECTION(kc57_ec_transaction, ERRNO);