This source file includes following definitions.
- acpi_thermal_rel_open
- acpi_thermal_rel_release
- acpi_parse_trt
- acpi_parse_art
- get_single_name
- fill_art
- fill_trt
- acpi_thermal_rel_ioctl
- acpi_thermal_rel_misc_device_add
- acpi_thermal_rel_misc_device_remove
1
2
3
4
5
6
7
8
9
10
11
12
13 #include <linux/init.h>
14 #include <linux/export.h>
15 #include <linux/module.h>
16 #include <linux/device.h>
17 #include <linux/platform_device.h>
18 #include <linux/io.h>
19 #include <linux/acpi.h>
20 #include <linux/uaccess.h>
21 #include <linux/miscdevice.h>
22 #include "acpi_thermal_rel.h"
23
24 static acpi_handle acpi_thermal_rel_handle;
25 static DEFINE_SPINLOCK(acpi_thermal_rel_chrdev_lock);
26 static int acpi_thermal_rel_chrdev_count;
27 static int acpi_thermal_rel_chrdev_exclu;
28
29 static int acpi_thermal_rel_open(struct inode *inode, struct file *file)
30 {
31 spin_lock(&acpi_thermal_rel_chrdev_lock);
32 if (acpi_thermal_rel_chrdev_exclu ||
33 (acpi_thermal_rel_chrdev_count && (file->f_flags & O_EXCL))) {
34 spin_unlock(&acpi_thermal_rel_chrdev_lock);
35 return -EBUSY;
36 }
37
38 if (file->f_flags & O_EXCL)
39 acpi_thermal_rel_chrdev_exclu = 1;
40 acpi_thermal_rel_chrdev_count++;
41
42 spin_unlock(&acpi_thermal_rel_chrdev_lock);
43
44 return nonseekable_open(inode, file);
45 }
46
47 static int acpi_thermal_rel_release(struct inode *inode, struct file *file)
48 {
49 spin_lock(&acpi_thermal_rel_chrdev_lock);
50 acpi_thermal_rel_chrdev_count--;
51 acpi_thermal_rel_chrdev_exclu = 0;
52 spin_unlock(&acpi_thermal_rel_chrdev_lock);
53
54 return 0;
55 }
56
57
58
59
60
61
62
63
64
65
66 int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp,
67 bool create_dev)
68 {
69 acpi_status status;
70 int result = 0;
71 int i;
72 int nr_bad_entries = 0;
73 struct trt *trts;
74 struct acpi_device *adev;
75 union acpi_object *p;
76 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
77 struct acpi_buffer element = { 0, NULL };
78 struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" };
79
80 status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer);
81 if (ACPI_FAILURE(status))
82 return -ENODEV;
83
84 p = buffer.pointer;
85 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
86 pr_err("Invalid _TRT data\n");
87 result = -EFAULT;
88 goto end;
89 }
90
91 *trt_count = p->package.count;
92 trts = kcalloc(*trt_count, sizeof(struct trt), GFP_KERNEL);
93 if (!trts) {
94 result = -ENOMEM;
95 goto end;
96 }
97
98 for (i = 0; i < *trt_count; i++) {
99 struct trt *trt = &trts[i - nr_bad_entries];
100
101 element.length = sizeof(struct trt);
102 element.pointer = trt;
103
104 status = acpi_extract_package(&(p->package.elements[i]),
105 &trt_format, &element);
106 if (ACPI_FAILURE(status)) {
107 nr_bad_entries++;
108 pr_warn("_TRT package %d is invalid, ignored\n", i);
109 continue;
110 }
111 if (!create_dev)
112 continue;
113
114 result = acpi_bus_get_device(trt->source, &adev);
115 if (result)
116 pr_warn("Failed to get source ACPI device\n");
117
118 result = acpi_bus_get_device(trt->target, &adev);
119 if (result)
120 pr_warn("Failed to get target ACPI device\n");
121 }
122
123 result = 0;
124
125 *trtp = trts;
126
127 *trt_count -= nr_bad_entries;
128 end:
129 kfree(buffer.pointer);
130 return result;
131 }
132 EXPORT_SYMBOL(acpi_parse_trt);
133
134
135
136
137
138
139
140
141
142
143 int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
144 bool create_dev)
145 {
146 acpi_status status;
147 int result = 0;
148 int i;
149 int nr_bad_entries = 0;
150 struct art *arts;
151 struct acpi_device *adev;
152 union acpi_object *p;
153 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
154 struct acpi_buffer element = { 0, NULL };
155 struct acpi_buffer art_format = {
156 sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" };
157
158 status = acpi_evaluate_object(handle, "_ART", NULL, &buffer);
159 if (ACPI_FAILURE(status))
160 return -ENODEV;
161
162 p = buffer.pointer;
163 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
164 pr_err("Invalid _ART data\n");
165 result = -EFAULT;
166 goto end;
167 }
168
169
170 *art_count = p->package.count - 1;
171 arts = kcalloc(*art_count, sizeof(struct art), GFP_KERNEL);
172 if (!arts) {
173 result = -ENOMEM;
174 goto end;
175 }
176
177 for (i = 0; i < *art_count; i++) {
178 struct art *art = &arts[i - nr_bad_entries];
179
180 element.length = sizeof(struct art);
181 element.pointer = art;
182
183 status = acpi_extract_package(&(p->package.elements[i + 1]),
184 &art_format, &element);
185 if (ACPI_FAILURE(status)) {
186 pr_warn("_ART package %d is invalid, ignored", i);
187 nr_bad_entries++;
188 continue;
189 }
190 if (!create_dev)
191 continue;
192
193 if (art->source) {
194 result = acpi_bus_get_device(art->source, &adev);
195 if (result)
196 pr_warn("Failed to get source ACPI device\n");
197 }
198 if (art->target) {
199 result = acpi_bus_get_device(art->target, &adev);
200 if (result)
201 pr_warn("Failed to get target ACPI device\n");
202 }
203 }
204
205 *artp = arts;
206
207 *art_count -= nr_bad_entries;
208 end:
209 kfree(buffer.pointer);
210 return result;
211 }
212 EXPORT_SYMBOL(acpi_parse_art);
213
214
215
216 static void get_single_name(acpi_handle handle, char *name)
217 {
218 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER};
219
220 if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)))
221 pr_warn("Failed to get device name from acpi handle\n");
222 else {
223 memcpy(name, buffer.pointer, ACPI_NAMESEG_SIZE);
224 kfree(buffer.pointer);
225 }
226 }
227
228 static int fill_art(char __user *ubuf)
229 {
230 int i;
231 int ret;
232 int count;
233 int art_len;
234 struct art *arts = NULL;
235 union art_object *art_user;
236
237 ret = acpi_parse_art(acpi_thermal_rel_handle, &count, &arts, false);
238 if (ret)
239 goto free_art;
240 art_len = count * sizeof(union art_object);
241 art_user = kzalloc(art_len, GFP_KERNEL);
242 if (!art_user) {
243 ret = -ENOMEM;
244 goto free_art;
245 }
246
247 for (i = 0; i < count; i++) {
248
249 get_single_name(arts[i].source, art_user[i].source_device);
250 get_single_name(arts[i].target, art_user[i].target_device);
251
252 memcpy(&art_user[i].weight, &arts[i].weight,
253 sizeof(u64) * (ACPI_NR_ART_ELEMENTS - 2));
254 }
255
256 if (copy_to_user(ubuf, art_user, art_len))
257 ret = -EFAULT;
258 kfree(art_user);
259 free_art:
260 kfree(arts);
261 return ret;
262 }
263
264 static int fill_trt(char __user *ubuf)
265 {
266 int i;
267 int ret;
268 int count;
269 int trt_len;
270 struct trt *trts = NULL;
271 union trt_object *trt_user;
272
273 ret = acpi_parse_trt(acpi_thermal_rel_handle, &count, &trts, false);
274 if (ret)
275 goto free_trt;
276 trt_len = count * sizeof(union trt_object);
277 trt_user = kzalloc(trt_len, GFP_KERNEL);
278 if (!trt_user) {
279 ret = -ENOMEM;
280 goto free_trt;
281 }
282
283 for (i = 0; i < count; i++) {
284
285 get_single_name(trts[i].source, trt_user[i].source_device);
286 get_single_name(trts[i].target, trt_user[i].target_device);
287 trt_user[i].sample_period = trts[i].sample_period;
288 trt_user[i].influence = trts[i].influence;
289 }
290
291 if (copy_to_user(ubuf, trt_user, trt_len))
292 ret = -EFAULT;
293 kfree(trt_user);
294 free_trt:
295 kfree(trts);
296 return ret;
297 }
298
299 static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
300 unsigned long __arg)
301 {
302 int ret = 0;
303 unsigned long length = 0;
304 int count = 0;
305 char __user *arg = (void __user *)__arg;
306 struct trt *trts = NULL;
307 struct art *arts = NULL;
308
309 switch (cmd) {
310 case ACPI_THERMAL_GET_TRT_COUNT:
311 ret = acpi_parse_trt(acpi_thermal_rel_handle, &count,
312 &trts, false);
313 kfree(trts);
314 if (!ret)
315 return put_user(count, (unsigned long __user *)__arg);
316 return ret;
317 case ACPI_THERMAL_GET_TRT_LEN:
318 ret = acpi_parse_trt(acpi_thermal_rel_handle, &count,
319 &trts, false);
320 kfree(trts);
321 length = count * sizeof(union trt_object);
322 if (!ret)
323 return put_user(length, (unsigned long __user *)__arg);
324 return ret;
325 case ACPI_THERMAL_GET_TRT:
326 return fill_trt(arg);
327 case ACPI_THERMAL_GET_ART_COUNT:
328 ret = acpi_parse_art(acpi_thermal_rel_handle, &count,
329 &arts, false);
330 kfree(arts);
331 if (!ret)
332 return put_user(count, (unsigned long __user *)__arg);
333 return ret;
334 case ACPI_THERMAL_GET_ART_LEN:
335 ret = acpi_parse_art(acpi_thermal_rel_handle, &count,
336 &arts, false);
337 kfree(arts);
338 length = count * sizeof(union art_object);
339 if (!ret)
340 return put_user(length, (unsigned long __user *)__arg);
341 return ret;
342
343 case ACPI_THERMAL_GET_ART:
344 return fill_art(arg);
345
346 default:
347 return -ENOTTY;
348 }
349 }
350
351 static const struct file_operations acpi_thermal_rel_fops = {
352 .owner = THIS_MODULE,
353 .open = acpi_thermal_rel_open,
354 .release = acpi_thermal_rel_release,
355 .unlocked_ioctl = acpi_thermal_rel_ioctl,
356 .llseek = no_llseek,
357 };
358
359 static struct miscdevice acpi_thermal_rel_misc_device = {
360 .minor = MISC_DYNAMIC_MINOR,
361 "acpi_thermal_rel",
362 &acpi_thermal_rel_fops
363 };
364
365 int acpi_thermal_rel_misc_device_add(acpi_handle handle)
366 {
367 acpi_thermal_rel_handle = handle;
368
369 return misc_register(&acpi_thermal_rel_misc_device);
370 }
371 EXPORT_SYMBOL(acpi_thermal_rel_misc_device_add);
372
373 int acpi_thermal_rel_misc_device_remove(acpi_handle handle)
374 {
375 misc_deregister(&acpi_thermal_rel_misc_device);
376
377 return 0;
378 }
379 EXPORT_SYMBOL(acpi_thermal_rel_misc_device_remove);
380
381 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
382 MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com");
383 MODULE_DESCRIPTION("Intel acpi thermal rel misc dev driver");
384 MODULE_LICENSE("GPL v2");