1 /*
2 * Copyright © 2016 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
25 #include <inttypes.h>
26 #include <sys/stat.h>
27 #include <sys/sysmacros.h>
28 #include <sys/mount.h>
29 #include <errno.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <limits.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <i915_drm.h>
38 #include <dirent.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41
42 #include "igt_core.h"
43 #include "igt_sysfs.h"
44 #include "igt_device.h"
45
46 /**
47 * SECTION:igt_sysfs
48 * @short_description: Support code for sysfs features
49 * @title: sysfs
50 * @include: igt.h
51 *
52 * This library provides helpers to access sysfs features. Right now it only
53 * provides basic support for like igt_sysfs_open().
54 */
55
readN(int fd,char * buf,int len)56 static int readN(int fd, char *buf, int len)
57 {
58 int ret, total = 0;
59 do {
60 ret = read(fd, buf + total, len - total);
61 if (ret < 0)
62 ret = -errno;
63 if (ret == -EINTR || ret == -EAGAIN)
64 continue;
65 if (ret <= 0)
66 break;
67 total += ret;
68 } while (total != len);
69 return total ?: ret;
70 }
71
writeN(int fd,const char * buf,int len)72 static int writeN(int fd, const char *buf, int len)
73 {
74 int ret, total = 0;
75 do {
76 ret = write(fd, buf + total, len - total);
77 if (ret < 0)
78 ret = -errno;
79 if (ret == -EINTR || ret == -EAGAIN)
80 continue;
81 if (ret <= 0)
82 break;
83 total += ret;
84 } while (total != len);
85 return total ?: ret;
86 }
87
88 /**
89 * igt_sysfs_path:
90 * @device: fd of the device
91 * @path: buffer to fill with the sysfs path to the device
92 * @pathlen: length of @path buffer
93 *
94 * This finds the sysfs directory corresponding to @device.
95 *
96 * Returns:
97 * The directory path, or NULL on failure.
98 */
igt_sysfs_path(int device,char * path,int pathlen)99 char *igt_sysfs_path(int device, char *path, int pathlen)
100 {
101 struct stat st;
102
103 if (device < 0)
104 return NULL;
105
106 if (fstat(device, &st) || !S_ISCHR(st.st_mode))
107 return NULL;
108
109 snprintf(path, pathlen, "/sys/dev/char/%d:%d",
110 major(st.st_rdev), minor(st.st_rdev));
111
112 if (access(path, F_OK))
113 return NULL;
114
115 return path;
116 }
117
118 /**
119 * igt_sysfs_open:
120 * @device: fd of the device
121 *
122 * This opens the sysfs directory corresponding to device for use
123 * with igt_sysfs_set() and igt_sysfs_get().
124 *
125 * Returns:
126 * The directory fd, or -1 on failure.
127 */
igt_sysfs_open(int device)128 int igt_sysfs_open(int device)
129 {
130 char path[80];
131
132 if (!igt_sysfs_path(device, path, sizeof(path)))
133 return -1;
134
135 return open(path, O_RDONLY);
136 }
137
138 /**
139 * igt_sysfs_set_parameters:
140 * @device: fd of the device
141 * @parameter: the name of the parameter to set
142 * @fmt: printf-esque format string
143 *
144 * Returns true on success
145 */
igt_sysfs_set_parameter(int device,const char * parameter,const char * fmt,...)146 bool igt_sysfs_set_parameter(int device,
147 const char *parameter,
148 const char *fmt, ...)
149 {
150 va_list ap;
151 int dir;
152 int ret;
153
154 dir = igt_sysfs_open_parameters(device);
155 if (dir < 0)
156 return false;
157
158 va_start(ap, fmt);
159 ret = igt_sysfs_vprintf(dir, parameter, fmt, ap);
160 va_end(ap);
161
162 close(dir);
163
164 return ret > 0;
165 }
166
167 /**
168 * igt_sysfs_open_parameters:
169 * @device: fd of the device
170 *
171 * This opens the module parameters directory (under sysfs) corresponding
172 * to the device for use with igt_sysfs_set() and igt_sysfs_get().
173 *
174 * Returns:
175 * The directory fd, or -1 on failure.
176 */
igt_sysfs_open_parameters(int device)177 int igt_sysfs_open_parameters(int device)
178 {
179 int dir, params = -1;
180
181 dir = igt_sysfs_open(device);
182 if (dir >= 0) {
183 params = openat(dir,
184 "device/driver/module/parameters",
185 O_RDONLY);
186 close(dir);
187 }
188
189 if (params < 0) { /* builtin? */
190 drm_version_t version;
191 char name[32] = "";
192 char path[PATH_MAX];
193
194 memset(&version, 0, sizeof(version));
195 version.name_len = sizeof(name);
196 version.name = name;
197 ioctl(device, DRM_IOCTL_VERSION, &version);
198
199 sprintf(path, "/sys/module/%s/parameters", name);
200 params = open(path, O_RDONLY);
201 }
202
203 return params;
204 }
205
206 /**
207 * igt_sysfs_write:
208 * @dir: directory for the device from igt_sysfs_open()
209 * @attr: name of the sysfs node to open
210 * @data: the block to write from
211 * @len: the length to write
212 *
213 * This writes @len bytes from @data to the sysfs file.
214 *
215 * Returns:
216 * The number of bytes written, or -errno on error.
217 */
igt_sysfs_write(int dir,const char * attr,const void * data,int len)218 int igt_sysfs_write(int dir, const char *attr, const void *data, int len)
219 {
220 int fd;
221
222 fd = openat(dir, attr, O_WRONLY);
223 if (fd < 0)
224 return -errno;
225
226 len = writeN(fd, data, len);
227 close(fd);
228
229 return len;
230 }
231
232 /**
233 * igt_sysfs_read:
234 * @dir: directory for the device from igt_sysfs_open()
235 * @attr: name of the sysfs node to open
236 * @data: the block to read into
237 * @len: the maximum length to read
238 *
239 * This reads @len bytes from the sysfs file to @data
240 *
241 * Returns:
242 * The length read, -errno on failure.
243 */
igt_sysfs_read(int dir,const char * attr,void * data,int len)244 int igt_sysfs_read(int dir, const char *attr, void *data, int len)
245 {
246 int fd;
247
248 fd = openat(dir, attr, O_RDONLY);
249 if (fd < 0)
250 return -errno;
251
252 len = readN(fd, data, len);
253 close(fd);
254
255 return len;
256 }
257
258 /**
259 * igt_sysfs_set:
260 * @dir: directory for the device from igt_sysfs_open()
261 * @attr: name of the sysfs node to open
262 * @value: the string to write
263 *
264 * This writes the value to the sysfs file.
265 *
266 * Returns:
267 * True on success, false on failure.
268 */
igt_sysfs_set(int dir,const char * attr,const char * value)269 bool igt_sysfs_set(int dir, const char *attr, const char *value)
270 {
271 int len = strlen(value);
272 return igt_sysfs_write(dir, attr, value, len) == len;
273 }
274
275 /**
276 * igt_sysfs_get:
277 * @dir: directory for the device from igt_sysfs_open()
278 * @attr: name of the sysfs node to open
279 *
280 * This reads the value from the sysfs file.
281 *
282 * Returns:
283 * A nul-terminated string, must be freed by caller after use, or NULL
284 * on failure.
285 */
igt_sysfs_get(int dir,const char * attr)286 char *igt_sysfs_get(int dir, const char *attr)
287 {
288 char *buf;
289 int len, offset, rem;
290 int ret, fd;
291
292 fd = openat(dir, attr, O_RDONLY);
293 if (fd < 0)
294 return NULL;
295
296 offset = 0;
297 len = 64;
298 rem = len - offset - 1;
299 buf = malloc(len);
300 if (!buf)
301 goto out;
302
303 while ((ret = readN(fd, buf + offset, rem)) == rem) {
304 char *newbuf;
305
306 newbuf = realloc(buf, 2*len);
307 if (!newbuf)
308 break;
309
310 buf = newbuf;
311 len *= 2;
312 offset += ret;
313 rem = len - offset - 1;
314 }
315
316 if (ret > 0)
317 offset += ret;
318 buf[offset] = '\0';
319 while (offset > 0 && buf[offset-1] == '\n')
320 buf[--offset] = '\0';
321
322 out:
323 close(fd);
324 return buf;
325 }
326
327 /**
328 * igt_sysfs_scanf:
329 * @dir: directory for the device from igt_sysfs_open()
330 * @attr: name of the sysfs node to open
331 * @fmt: scanf format string
332 * @...: Additional paramaters to store the scaned input values
333 *
334 * scanf() wrapper for sysfs.
335 *
336 * Returns:
337 * Number of values successfully scanned (which can be 0), EOF on errors or
338 * premature end of file.
339 */
igt_sysfs_scanf(int dir,const char * attr,const char * fmt,...)340 int igt_sysfs_scanf(int dir, const char *attr, const char *fmt, ...)
341 {
342 FILE *file;
343 int fd;
344 int ret = -1;
345
346 fd = openat(dir, attr, O_RDONLY);
347 if (fd < 0)
348 return -1;
349
350 file = fdopen(fd, "r");
351 if (file) {
352 va_list ap;
353
354 va_start(ap, fmt);
355 ret = vfscanf(file, fmt, ap);
356 va_end(ap);
357
358 fclose(file);
359 } else {
360 close(fd);
361 }
362
363 return ret;
364 }
365
igt_sysfs_vprintf(int dir,const char * attr,const char * fmt,va_list ap)366 int igt_sysfs_vprintf(int dir, const char *attr, const char *fmt, va_list ap)
367 {
368 char stack[128], *buf = stack;
369 va_list tmp;
370 int ret, fd;
371
372 fd = openat(dir, attr, O_WRONLY);
373 if (fd < 0)
374 return -errno;
375
376 va_copy(tmp, ap);
377 ret = vsnprintf(buf, sizeof(stack), fmt, tmp);
378 va_end(tmp);
379 if (ret < 0)
380 return -EINVAL;
381
382 if (ret > sizeof(stack)) {
383 unsigned int len = ret + 1;
384
385 buf = malloc(len);
386 if (!buf)
387 return -ENOMEM;
388
389 ret = vsnprintf(buf, ret, fmt, ap);
390 if (ret > len) {
391 free(buf);
392 return -EINVAL;
393 }
394 }
395
396 ret = writeN(fd, buf, ret);
397
398 close(fd);
399 if (buf != stack)
400 free(buf);
401
402 return ret;
403 }
404
405 /**
406 * igt_sysfs_printf:
407 * @dir: directory for the device from igt_sysfs_open()
408 * @attr: name of the sysfs node to open
409 * @fmt: printf format string
410 * @...: Additional paramaters to store the scaned input values
411 *
412 * printf() wrapper for sysfs.
413 *
414 * Returns:
415 * Number of characters written, negative value on error.
416 */
igt_sysfs_printf(int dir,const char * attr,const char * fmt,...)417 int igt_sysfs_printf(int dir, const char *attr, const char *fmt, ...)
418 {
419 va_list ap;
420 int ret;
421
422 va_start(ap, fmt);
423 ret = igt_sysfs_vprintf(dir, attr, fmt, ap);
424 va_end(ap);
425
426 return ret;
427 }
428
429 /**
430 * igt_sysfs_get_u32:
431 * @dir: directory for the device from igt_sysfs_open()
432 * @attr: name of the sysfs node to open
433 *
434 * Convenience wrapper to read a unsigned 32bit integer from a sysfs file.
435 *
436 * Returns:
437 * The value read.
438 */
igt_sysfs_get_u32(int dir,const char * attr)439 uint32_t igt_sysfs_get_u32(int dir, const char *attr)
440 {
441 uint32_t result;
442
443 if (igt_sysfs_scanf(dir, attr, "%u", &result) != 1)
444 return 0;
445
446 return result;
447 }
448
449 /**
450 * igt_sysfs_set_u32:
451 * @dir: directory for the device from igt_sysfs_open()
452 * @attr: name of the sysfs node to open
453 * @value: value to set
454 *
455 * Convenience wrapper to write a unsigned 32bit integer to a sysfs file.
456 *
457 * Returns:
458 * True if successfully written
459 */
igt_sysfs_set_u32(int dir,const char * attr,uint32_t value)460 bool igt_sysfs_set_u32(int dir, const char *attr, uint32_t value)
461 {
462 return igt_sysfs_printf(dir, attr, "%u", value) > 0;
463 }
464
465 /**
466 * igt_sysfs_get_boolean:
467 * @dir: directory for the device from igt_sysfs_open()
468 * @attr: name of the sysfs node to open
469 *
470 * Convenience wrapper to read a boolean sysfs file.
471 *
472 * Returns:
473 * The value read.
474 */
igt_sysfs_get_boolean(int dir,const char * attr)475 bool igt_sysfs_get_boolean(int dir, const char *attr)
476 {
477 int result;
478
479 if (igt_sysfs_scanf(dir, attr, "%d", &result) != 1)
480 return false;
481
482 return result;
483 }
484
485 /**
486 * igt_sysfs_set_boolean:
487 * @dir: directory for the device from igt_sysfs_open()
488 * @attr: name of the sysfs node to open
489 * @value: value to set
490 *
491 * Convenience wrapper to write a boolean sysfs file.
492 *
493 * Returns:
494 * The value read.
495 */
igt_sysfs_set_boolean(int dir,const char * attr,bool value)496 bool igt_sysfs_set_boolean(int dir, const char *attr, bool value)
497 {
498 return igt_sysfs_printf(dir, attr, "%d", value) == 1;
499 }
500
bind_con(const char * name,bool enable)501 static void bind_con(const char *name, bool enable)
502 {
503 const char *path = "/sys/class/vtconsole";
504 DIR *dir;
505 struct dirent *de;
506
507 dir = opendir(path);
508 if (!dir)
509 return;
510
511 while ((de = readdir(dir))) {
512 char buf[PATH_MAX];
513 int fd, len;
514
515 if (strncmp(de->d_name, "vtcon", 5))
516 continue;
517
518 sprintf(buf, "%s/%s/name", path, de->d_name);
519 fd = open(buf, O_RDONLY);
520 if (fd < 0)
521 continue;
522
523 buf[sizeof(buf) - 1] = '\0';
524 len = read(fd, buf, sizeof(buf) - 1);
525 close(fd);
526 if (len >= 0)
527 buf[len] = '\0';
528
529 if (!strstr(buf, name))
530 continue;
531
532 sprintf(buf, "%s/%s/bind", path, de->d_name);
533 fd = open(buf, O_WRONLY);
534 if (fd != -1) {
535 igt_ignore_warn(write(fd, enable ? "1\n" : "0\n", 2));
536 close(fd);
537 }
538 break;
539 }
540 closedir(dir);
541 }
542
543 /**
544 * bind_fbcon:
545 * @enable: boolean value
546 *
547 * This functions enables/disables the text console running on top of the
548 * framebuffer device.
549 */
bind_fbcon(bool enable)550 void bind_fbcon(bool enable)
551 {
552 /*
553 * The vtcon bind interface seems somewhat broken. Possibly
554 * depending on the order the console drivers have been
555 * registered you either have to unbind the old driver,
556 * or bind the new driver. Let's do both.
557 */
558 bind_con("dummy device", !enable);
559 bind_con("frame buffer device", enable);
560 }
561
562 /**
563 * kick_snd_hda_intel:
564 *
565 * This functions unbinds the snd_hda_intel driver so the module cand be
566 * unloaded.
567 *
568 */
kick_snd_hda_intel(void)569 void kick_snd_hda_intel(void)
570 {
571 DIR *dir;
572 struct dirent *snd_hda;
573 int fd; size_t len;
574
575 const char *dpath = "/sys/bus/pci/drivers/snd_hda_intel";
576 const char *path = "/sys/bus/pci/drivers/snd_hda_intel/unbind";
577 const char *devid = "0000:";
578
579 fd = open(path, O_WRONLY);
580 if (fd < 0) {
581 return;
582 }
583
584 dir = opendir(dpath);
585 if (!dir)
586 goto out;
587
588 len = strlen(devid);
589 while ((snd_hda = readdir(dir))) {
590 struct stat st;
591 char fpath[PATH_MAX];
592
593 if (*snd_hda->d_name == '.')
594 continue;
595
596 snprintf(fpath, sizeof(fpath), "%s/%s", dpath, snd_hda->d_name);
597 if (lstat(fpath, &st))
598 continue;
599
600 if (!S_ISLNK(st.st_mode))
601 continue;
602
603 if (!strncmp(devid, snd_hda->d_name, len)) {
604 igt_ignore_warn(write(fd, snd_hda->d_name,
605 strlen(snd_hda->d_name)));
606 }
607 }
608
609 closedir(dir);
610 out:
611 close(fd);
612 }
613
614 static int fbcon_cursor_blink_fd = -1;
615 static char fbcon_cursor_blink_prev_value[2];
616
fbcon_cursor_blink_restore(int sig)617 static void fbcon_cursor_blink_restore(int sig)
618 {
619 write(fbcon_cursor_blink_fd, fbcon_cursor_blink_prev_value,
620 strlen(fbcon_cursor_blink_prev_value) + 1);
621 close(fbcon_cursor_blink_fd);
622 }
623
624 /**
625 * fbcon_blink_enable:
626 * @enable: if true enables the fbcon cursor blinking otherwise disables it
627 *
628 * Enables or disables the cursor blinking in fbcon, it also restores the
629 * previous blinking state when exiting test.
630 *
631 */
fbcon_blink_enable(bool enable)632 void fbcon_blink_enable(bool enable)
633 {
634 const char *cur_blink_path = "/sys/class/graphics/fbcon/cursor_blink";
635 int fd, r;
636 char buffer[2];
637
638 fd = open(cur_blink_path, O_RDWR);
639 igt_require(fd >= 0);
640
641 /* Restore original value on exit */
642 if (fbcon_cursor_blink_fd == -1) {
643 r = read(fd, fbcon_cursor_blink_prev_value,
644 sizeof(fbcon_cursor_blink_prev_value));
645 if (r > 0) {
646 fbcon_cursor_blink_fd = dup(fd);
647 igt_assert(fbcon_cursor_blink_fd >= 0);
648 igt_install_exit_handler(fbcon_cursor_blink_restore);
649 }
650 }
651
652 r = snprintf(buffer, sizeof(buffer), enable ? "1" : "0");
653 write(fd, buffer, r + 1);
654 close(fd);
655 }
656