]>
Commit | Line | Data |
---|---|---|
34a956db MG |
1 | /* |
2 | * Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org> | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along | |
15 | * with this program; if not, write to the Free Software Foundation, Inc., | |
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
17 | */ | |
18 | ||
19 | ||
20 | #include <linux/init.h> | |
21 | #include <linux/module.h> | |
22 | #include <linux/slab.h> | |
23 | #include <acpi/acpi_drivers.h> | |
24 | ||
25 | MODULE_LICENSE("GPL"); | |
26 | ||
27 | static ssize_t irst_show_wakeup_events(struct device *dev, | |
28 | struct device_attribute *attr, | |
29 | char *buf) | |
30 | { | |
31 | struct acpi_device *acpi; | |
32 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | |
33 | union acpi_object *result; | |
34 | acpi_status status; | |
35 | ||
36 | acpi = to_acpi_device(dev); | |
37 | ||
38 | status = acpi_evaluate_object(acpi->handle, "GFFS", NULL, &output); | |
39 | if (!ACPI_SUCCESS(status)) | |
40 | return -EINVAL; | |
41 | ||
42 | result = output.pointer; | |
43 | ||
44 | if (result->type != ACPI_TYPE_INTEGER) { | |
45 | kfree(result); | |
46 | return -EINVAL; | |
47 | } | |
48 | ||
49 | return sprintf(buf, "%lld\n", result->integer.value); | |
50 | } | |
51 | ||
52 | static ssize_t irst_store_wakeup_events(struct device *dev, | |
53 | struct device_attribute *attr, | |
54 | const char *buf, size_t count) | |
55 | { | |
56 | struct acpi_device *acpi; | |
57 | struct acpi_object_list input; | |
58 | union acpi_object param; | |
59 | acpi_status status; | |
60 | unsigned long value; | |
61 | int error; | |
62 | ||
63 | acpi = to_acpi_device(dev); | |
64 | ||
65 | error = kstrtoul(buf, 0, &value); | |
66 | ||
67 | if (error) | |
68 | return error; | |
69 | ||
70 | param.type = ACPI_TYPE_INTEGER; | |
71 | param.integer.value = value; | |
72 | ||
73 | input.count = 1; | |
74 | input.pointer = ¶m; | |
75 | ||
76 | status = acpi_evaluate_object(acpi->handle, "SFFS", &input, NULL); | |
77 | ||
78 | if (!ACPI_SUCCESS(status)) | |
79 | return -EINVAL; | |
80 | ||
81 | return count; | |
82 | } | |
83 | ||
84 | static struct device_attribute irst_wakeup_attr = { | |
85 | .attr = { .name = "wakeup_events", .mode = 0600 }, | |
86 | .show = irst_show_wakeup_events, | |
87 | .store = irst_store_wakeup_events | |
88 | }; | |
89 | ||
90 | static ssize_t irst_show_wakeup_time(struct device *dev, | |
91 | struct device_attribute *attr, char *buf) | |
92 | { | |
93 | struct acpi_device *acpi; | |
94 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | |
95 | union acpi_object *result; | |
96 | acpi_status status; | |
97 | ||
98 | acpi = to_acpi_device(dev); | |
99 | ||
100 | status = acpi_evaluate_object(acpi->handle, "GFTV", NULL, &output); | |
101 | if (!ACPI_SUCCESS(status)) | |
102 | return -EINVAL; | |
103 | ||
104 | result = output.pointer; | |
105 | ||
106 | if (result->type != ACPI_TYPE_INTEGER) { | |
107 | kfree(result); | |
108 | return -EINVAL; | |
109 | } | |
110 | ||
111 | return sprintf(buf, "%lld\n", result->integer.value); | |
112 | } | |
113 | ||
114 | static ssize_t irst_store_wakeup_time(struct device *dev, | |
115 | struct device_attribute *attr, | |
116 | const char *buf, size_t count) | |
117 | { | |
118 | struct acpi_device *acpi; | |
119 | struct acpi_object_list input; | |
120 | union acpi_object param; | |
121 | acpi_status status; | |
122 | unsigned long value; | |
123 | int error; | |
124 | ||
125 | acpi = to_acpi_device(dev); | |
126 | ||
127 | error = kstrtoul(buf, 0, &value); | |
128 | ||
129 | if (error) | |
130 | return error; | |
131 | ||
132 | param.type = ACPI_TYPE_INTEGER; | |
133 | param.integer.value = value; | |
134 | ||
135 | input.count = 1; | |
136 | input.pointer = ¶m; | |
137 | ||
138 | status = acpi_evaluate_object(acpi->handle, "SFTV", &input, NULL); | |
139 | ||
140 | if (!ACPI_SUCCESS(status)) | |
141 | return -EINVAL; | |
142 | ||
143 | return count; | |
144 | } | |
145 | ||
146 | static struct device_attribute irst_timeout_attr = { | |
147 | .attr = { .name = "wakeup_time", .mode = 0600 }, | |
148 | .show = irst_show_wakeup_time, | |
149 | .store = irst_store_wakeup_time | |
150 | }; | |
151 | ||
152 | static int irst_add(struct acpi_device *acpi) | |
153 | { | |
154 | int error = 0; | |
155 | ||
156 | error = device_create_file(&acpi->dev, &irst_timeout_attr); | |
157 | if (error) | |
158 | goto out; | |
159 | ||
160 | error = device_create_file(&acpi->dev, &irst_wakeup_attr); | |
161 | if (error) | |
162 | goto out_timeout; | |
163 | ||
164 | return 0; | |
165 | ||
166 | out_timeout: | |
167 | device_remove_file(&acpi->dev, &irst_timeout_attr); | |
168 | out: | |
169 | return error; | |
170 | } | |
171 | ||
172 | static int irst_remove(struct acpi_device *acpi) | |
173 | { | |
174 | device_remove_file(&acpi->dev, &irst_wakeup_attr); | |
175 | device_remove_file(&acpi->dev, &irst_timeout_attr); | |
176 | ||
177 | return 0; | |
178 | } | |
179 | ||
180 | static const struct acpi_device_id irst_ids[] = { | |
181 | {"INT3392", 0}, | |
182 | {"", 0} | |
183 | }; | |
184 | ||
185 | static struct acpi_driver irst_driver = { | |
186 | .owner = THIS_MODULE, | |
187 | .name = "intel_rapid_start", | |
188 | .class = "intel_rapid_start", | |
189 | .ids = irst_ids, | |
190 | .ops = { | |
191 | .add = irst_add, | |
192 | .remove = irst_remove, | |
193 | }, | |
194 | }; | |
195 | ||
196 | static int irst_init(void) | |
197 | { | |
198 | return acpi_bus_register_driver(&irst_driver); | |
199 | } | |
200 | ||
201 | static void irst_exit(void) | |
202 | { | |
203 | acpi_bus_unregister_driver(&irst_driver); | |
204 | } | |
205 | ||
206 | module_init(irst_init); | |
207 | module_exit(irst_exit); | |
208 | ||
209 | MODULE_DEVICE_TABLE(acpi, irst_ids); |