blob: e7c67dae3a13959661dfe21aee8d2c5b234b1140 [file] [log] [blame]
Chris Wilsonb3082ae2016-05-26 15:05:38 +01001/*
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>
Ausmus, James7c9dccb2017-09-27 16:08:27 -070027#include <sys/sysmacros.h>
Chris Wilsonb3082ae2016-05-26 15:05:38 +010028#include <sys/mount.h>
29#include <errno.h>
Chris Wilsone3abb202016-07-22 18:03:30 +010030#include <stdarg.h>
Chris Wilsonb3082ae2016-05-26 15:05:38 +010031#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>
Marius Vlad0268d732016-12-01 21:45:47 +000038#include <dirent.h>
39#include <unistd.h>
40#include <fcntl.h>
Chris Wilsonb3082ae2016-05-26 15:05:38 +010041
Marius Vlad0268d732016-12-01 21:45:47 +000042#include "igt_core.h"
Chris Wilsonb3082ae2016-05-26 15:05:38 +010043#include "igt_sysfs.h"
44
Daniel Vetter430c1342016-07-27 13:07:39 +020045/**
46 * SECTION:igt_sysfs
47 * @short_description: Support code for sysfs features
48 * @title: sysfs
49 * @include: igt.h
50 *
51 * This library provides helpers to access sysfs features. Right now it only
52 * provides basic support for like igt_sysfs_open().
53 */
54
Chris Wilsonb3082ae2016-05-26 15:05:38 +010055static int readN(int fd, char *buf, int len)
56{
57 int total = 0;
58 do {
59 int ret = read(fd, buf + total, len - total);
60 if (ret < 0 && (errno == EINTR || errno == EAGAIN))
61 continue;
62
63 if (ret <= 0)
64 return total ?: ret;
65
66 total += ret;
Chris Wilsona056f7c2017-03-25 00:11:26 +000067 if (total == len)
68 return total;
Chris Wilsonb3082ae2016-05-26 15:05:38 +010069 } while (1);
70}
71
72static int writeN(int fd, const char *buf, int len)
73{
74 int total = 0;
75 do {
76 int ret = write(fd, buf + total, len - total);
77 if (ret < 0 && (errno == EINTR || errno == EAGAIN))
78 continue;
79
80 if (ret <= 0)
81 return total ?: ret;
82
83 total += ret;
Chris Wilsona056f7c2017-03-25 00:11:26 +000084 if (total == len)
85 return total;
Chris Wilsonb3082ae2016-05-26 15:05:38 +010086 } while (1);
87}
88
89/**
Chris Wilsone56ab792017-08-22 13:47:33 +010090 * igt_sysfs_path:
Chris Wilsonb3082ae2016-05-26 15:05:38 +010091 * @device: fd of the device (or -1 to default to Intel)
Chris Wilsone56ab792017-08-22 13:47:33 +010092 * @path: buffer to fill with the sysfs path to the device
93 * @pathlen: length of @path buffer
Daniel Vetter430c1342016-07-27 13:07:39 +020094 * @idx: optional pointer to store the card index of the opened device
Chris Wilsonb3082ae2016-05-26 15:05:38 +010095 *
Chris Wilsone56ab792017-08-22 13:47:33 +010096 * This finds the sysfs directory corresponding to @device.
Chris Wilsonb3082ae2016-05-26 15:05:38 +010097 *
98 * Returns:
Chris Wilsone56ab792017-08-22 13:47:33 +010099 * The directory path, or NULL on failure.
Chris Wilsonb3082ae2016-05-26 15:05:38 +0100100 */
Chris Wilsone56ab792017-08-22 13:47:33 +0100101char *igt_sysfs_path(int device, char *path, int pathlen, int *idx)
Chris Wilsonb3082ae2016-05-26 15:05:38 +0100102{
Chris Wilsonb3082ae2016-05-26 15:05:38 +0100103 struct stat st;
104
Daniel Vetter430c1342016-07-27 13:07:39 +0200105 if (device != -1 && (fstat(device, &st) || !S_ISCHR(st.st_mode)))
Chris Wilsone56ab792017-08-22 13:47:33 +0100106 return NULL;
Chris Wilsonb3082ae2016-05-26 15:05:38 +0100107
108 for (int n = 0; n < 16; n++) {
Chris Wilsone56ab792017-08-22 13:47:33 +0100109 int len = snprintf(path, pathlen, "/sys/class/drm/card%d", n);
Daniel Vetter430c1342016-07-27 13:07:39 +0200110 if (device != -1) {
Chris Wilsonb3082ae2016-05-26 15:05:38 +0100111 FILE *file;
112 int ret, maj, min;
113
114 sprintf(path + len, "/dev");
115 file = fopen(path, "r");
116 if (!file)
117 continue;
118
119 ret = fscanf(file, "%d:%d", &maj, &min);
120 fclose(file);
121
122 if (ret != 2 ||
123 major(st.st_rdev) != maj ||
124 minor(st.st_rdev) != min)
125 continue;
126 } else {
127 /* Bleh. Search for intel */
128 sprintf(path + len, "/error");
129 if (stat(path, &st))
130 continue;
131 }
132
133 path[len] = '\0';
134 if (idx)
135 *idx = n;
Chris Wilsone56ab792017-08-22 13:47:33 +0100136 return path;
Chris Wilsonb3082ae2016-05-26 15:05:38 +0100137 }
138
Chris Wilsone56ab792017-08-22 13:47:33 +0100139 return NULL;
140}
141
142/**
143 * igt_sysfs_open:
144 * @device: fd of the device (or -1 to default to Intel)
145 * @idx: optional pointer to store the card index of the opened device
146 *
147 * This opens the sysfs directory corresponding to device for use
148 * with igt_sysfs_set() and igt_sysfs_get().
149 *
150 * Returns:
151 * The directory fd, or -1 on failure.
152 */
153int igt_sysfs_open(int device, int *idx)
154{
155 char path[80];
156
157 if (!igt_sysfs_path(device, path, sizeof(path), idx))
158 return -1;
159
160 return open(path, O_RDONLY);
Chris Wilsonb3082ae2016-05-26 15:05:38 +0100161}
162
163/**
Chris Wilson310eaeb2017-06-05 11:55:57 +0100164 * igt_sysfs_set_parameters:
165 * @device: fd of the device (or -1 to default to Intel)
166 * @parameter: the name of the parameter to set
167 * @fmt: printf-esque format string
168 *
169 * Returns true on success
170 */
171bool igt_sysfs_set_parameter(int device,
172 const char *parameter,
173 const char *fmt, ...)
174{
175 va_list ap;
176 int dir;
177 int ret;
178
179 dir = igt_sysfs_open_parameters(device);
180 if (dir < 0)
181 return false;
182
183 va_start(ap, fmt);
184 ret = igt_sysfs_vprintf(dir, parameter, fmt, ap);
185 va_end(ap);
186
187 close(dir);
188
189 return ret > 0;
190}
191
192/**
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100193 * igt_sysfs_open_parameters:
194 * @device: fd of the device (or -1 to default to Intel)
195 *
196 * This opens the module parameters directory (under sysfs) corresponding
197 * to the device for use with igt_sysfs_set() and igt_sysfs_get().
198 *
199 * Returns:
200 * The directory fd, or -1 on failure.
201 */
Daniel Vetter430c1342016-07-27 13:07:39 +0200202int igt_sysfs_open_parameters(int device)
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100203{
204 int dir, params;
205
Daniel Vetter430c1342016-07-27 13:07:39 +0200206 dir = igt_sysfs_open(device, &params);
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100207 if (dir < 0)
208 return -1;
209
Chris Wilsone2762682016-10-19 14:07:25 +0100210 params = -1;
211 //params = openat(dir, "device/driver/module/parameters", O_RDONLY);
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100212 close(dir);
213
Chris Wilsonacd5d3d2016-10-14 18:32:51 +0100214 if (params < 0) { /* builtin? */
215 drm_version_t version;
216 char name[32] = "";
Eric Anholt7f92d002017-09-02 21:38:51 -0700217 char path[PATH_MAX];
Chris Wilsonacd5d3d2016-10-14 18:32:51 +0100218
219 memset(&version, 0, sizeof(version));
220 version.name_len = sizeof(name);
221 version.name = name;
222 ioctl(device, DRM_IOCTL_VERSION, &version);
223
224 sprintf(path, "/sys/module/%s/parameters", name);
225 params = open(path, O_RDONLY);
226 }
227
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100228 return params;
229}
Chris Wilsonc5da0662017-02-23 02:04:48 +0000230
231/**
232 * igt_sysfs_write:
233 * @dir: directory for the device from igt_sysfs_open()
234 * @attr: name of the sysfs node to open
235 * @data: the block to write from
236 * @len: the length to write
237 *
238 * This writes @len bytes from @data to the sysfs file.
239 *
240 * Returns:
241 * The number of bytes written, or -1 on error.
242 */
243int igt_sysfs_write(int dir, const char *attr, const void *data, int len)
244{
245 int fd;
246
247 fd = openat(dir, attr, O_WRONLY);
248 if (fd < 0)
249 return false;
250
251 len = writeN(fd, data, len);
252 close(fd);
253
254 return len;
255}
256
257/**
258 * igt_sysfs_read:
259 * @dir: directory for the device from igt_sysfs_open()
260 * @attr: name of the sysfs node to open
261 * @data: the block to read into
262 * @len: the maximum length to read
263 *
264 * This reads @len bytes from the sysfs file to @data
265 *
266 * Returns:
267 * The length read, -1 on failure.
268 */
269int igt_sysfs_read(int dir, const char *attr, void *data, int len)
270{
271 int fd;
272
Chris Wilsone5200022017-03-27 16:35:42 +0100273 fd = openat(dir, attr, O_RDONLY);
Chris Wilsonc5da0662017-02-23 02:04:48 +0000274 if (fd < 0)
275 return false;
276
277 len = readN(fd, data, len);
278 close(fd);
279
280 return len;
281}
282
Chris Wilsonc6e26e42016-07-22 12:58:54 +0100283/**
Chris Wilsonb3082ae2016-05-26 15:05:38 +0100284 * igt_sysfs_set:
285 * @dir: directory for the device from igt_sysfs_open()
286 * @attr: name of the sysfs node to open
287 * @value: the string to write
288 *
289 * This writes the value to the sysfs file.
290 *
291 * Returns:
292 * True on success, false on failure.
293 */
294bool igt_sysfs_set(int dir, const char *attr, const char *value)
295{
Chris Wilsonc5da0662017-02-23 02:04:48 +0000296 int len = strlen(value);
297 return igt_sysfs_write(dir, attr, value, len) == len;
Chris Wilsonb3082ae2016-05-26 15:05:38 +0100298}
299
300/**
301 * igt_sysfs_get:
302 * @dir: directory for the device from igt_sysfs_open()
303 * @attr: name of the sysfs node to open
304 *
305 * This reads the value from the sysfs file.
306 *
307 * Returns:
308 * A nul-terminated string, must be freed by caller after use, or NULL
309 * on failure.
310 */
311char *igt_sysfs_get(int dir, const char *attr)
312{
313 char *buf;
314 int len, offset, rem;
315 int ret, fd;
316
317 fd = openat(dir, attr, O_RDONLY);
318 if (fd < 0)
319 return NULL;
320
321 offset = 0;
322 len = 64;
323 rem = len - offset - 1;
324 buf = malloc(len);
325 if (!buf)
326 goto out;
327
328 while ((ret = readN(fd, buf + offset, rem)) == rem) {
329 char *newbuf;
330
331 newbuf = realloc(buf, 2*len);
332 if (!newbuf)
333 break;
334
Chris Wilson8deba382016-06-20 19:21:26 +0100335 buf = newbuf;
Chris Wilsonb3082ae2016-05-26 15:05:38 +0100336 len *= 2;
337 offset += ret;
338 rem = len - offset - 1;
339 }
340
341 if (ret != -1)
342 offset += ret;
343 buf[offset] = '\0';
344 while (offset > 0 && buf[offset-1] == '\n')
345 buf[--offset] = '\0';
346
347out:
348 close(fd);
349 return buf;
350}
Chris Wilsonb64d10c2016-07-22 17:53:51 +0100351
Daniel Vetter430c1342016-07-27 13:07:39 +0200352/**
353 * igt_sysfs_scanf:
354 * @dir: directory for the device from igt_sysfs_open()
355 * @attr: name of the sysfs node to open
356 * @fmt: scanf format string
357 * @...: Additional paramaters to store the scaned input values
358 *
359 * scanf() wrapper for sysfs.
360 *
361 * Returns:
362 * Number of values successfully scanned (which can be 0), EOF on errors or
363 * premature end of file.
364 */
Chris Wilsone3abb202016-07-22 18:03:30 +0100365int igt_sysfs_scanf(int dir, const char *attr, const char *fmt, ...)
366{
367 FILE *file;
368 int fd;
369 int ret = -1;
370
371 fd = openat(dir, attr, O_RDONLY);
372 if (fd < 0)
373 return -1;
374
375 file = fdopen(fd, "r");
376 if (file) {
377 va_list ap;
378
379 va_start(ap, fmt);
380 ret = vfscanf(file, fmt, ap);
381 va_end(ap);
382
383 fclose(file);
384 }
385 close(fd);
386
387 return ret;
388}
389
Chris Wilson310eaeb2017-06-05 11:55:57 +0100390int igt_sysfs_vprintf(int dir, const char *attr, const char *fmt, va_list ap)
Chris Wilsone3abb202016-07-22 18:03:30 +0100391{
392 FILE *file;
393 int fd;
394 int ret = -1;
395
396 fd = openat(dir, attr, O_WRONLY);
397 if (fd < 0)
398 return -1;
399
400 file = fdopen(fd, "w");
401 if (file) {
Chris Wilsone3abb202016-07-22 18:03:30 +0100402 ret = vfprintf(file, fmt, ap);
Chris Wilsone3abb202016-07-22 18:03:30 +0100403 fclose(file);
404 }
405 close(fd);
406
407 return ret;
408}
409
Daniel Vetter430c1342016-07-27 13:07:39 +0200410/**
Chris Wilson310eaeb2017-06-05 11:55:57 +0100411 * igt_sysfs_printf:
412 * @dir: directory for the device from igt_sysfs_open()
413 * @attr: name of the sysfs node to open
414 * @fmt: printf format string
415 * @...: Additional paramaters to store the scaned input values
416 *
417 * printf() wrapper for sysfs.
418 *
419 * Returns:
420 * Number of characters written, negative value on error.
421 */
422int igt_sysfs_printf(int dir, const char *attr, const char *fmt, ...)
423{
424 va_list ap;
425 int ret;
426
427 va_start(ap, fmt);
428 ret = igt_sysfs_vprintf(dir, attr, fmt, ap);
429 va_end(ap);
430
431 return ret;
432}
433
434/**
Peter Antoinecb5d6032016-08-04 14:39:26 +0100435 * igt_sysfs_get_u32:
436 * @dir: directory for the device from igt_sysfs_open()
437 * @attr: name of the sysfs node to open
438 *
439 * Convenience wrapper to read a unsigned 32bit integer from a sysfs file.
440 *
441 * Returns:
442 * The value read.
443 */
444uint32_t igt_sysfs_get_u32(int dir, const char *attr)
445{
446 uint32_t result;
447
448 if (igt_sysfs_scanf(dir, attr, "%u", &result) != 1)
449 return 0;
450
451 return result;
452}
453
454/**
455 * igt_sysfs_set_u32:
456 * @dir: directory for the device from igt_sysfs_open()
457 * @attr: name of the sysfs node to open
458 * @value: value to set
459 *
460 * Convenience wrapper to write a unsigned 32bit integer to a sysfs file.
461 *
462 * Returns:
463 * True if successfully written
464 */
465bool igt_sysfs_set_u32(int dir, const char *attr, uint32_t value)
466{
Tvrtko Ursulin8c2676a2017-09-29 12:29:49 +0100467 return igt_sysfs_printf(dir, attr, "%u", value) > 0;
Peter Antoinecb5d6032016-08-04 14:39:26 +0100468}
469
470/**
Daniel Vetter430c1342016-07-27 13:07:39 +0200471 * igt_sysfs_get_boolean:
472 * @dir: directory for the device from igt_sysfs_open()
473 * @attr: name of the sysfs node to open
474 *
475 * Convenience wrapper to read a boolean sysfs file.
476 *
477 * Returns:
478 * The value read.
479 */
Chris Wilsonb64d10c2016-07-22 17:53:51 +0100480bool igt_sysfs_get_boolean(int dir, const char *attr)
481{
Chris Wilsone3abb202016-07-22 18:03:30 +0100482 int result;
Chris Wilsonb64d10c2016-07-22 17:53:51 +0100483
Chris Wilsone3abb202016-07-22 18:03:30 +0100484 if (igt_sysfs_scanf(dir, attr, "%d", &result) != 1)
485 return false;
Chris Wilsonb64d10c2016-07-22 17:53:51 +0100486
487 return result;
488}
489
Daniel Vetter430c1342016-07-27 13:07:39 +0200490/**
491 * igt_sysfs_set_boolean:
492 * @dir: directory for the device from igt_sysfs_open()
493 * @attr: name of the sysfs node to open
494 * @value: value to set
495 *
496 * Convenience wrapper to write a boolean sysfs file.
497 *
498 * Returns:
499 * The value read.
500 */
Chris Wilsonb64d10c2016-07-22 17:53:51 +0100501bool igt_sysfs_set_boolean(int dir, const char *attr, bool value)
502{
Chris Wilsone3abb202016-07-22 18:03:30 +0100503 return igt_sysfs_printf(dir, attr, "%d", value) == 1;
Chris Wilsonb64d10c2016-07-22 17:53:51 +0100504}
Marius Vlad0268d732016-12-01 21:45:47 +0000505
506/**
507 * kick_fbcon:
508 * @enable: boolean value
509 *
510 * This functions enables/disables the text console running on top of the
511 * framebuffer device.
512 */
513void kick_fbcon(bool enable)
514{
Marius Vlad0268d732016-12-01 21:45:47 +0000515 const char *path = "/sys/class/vtconsole";
516 DIR *dir;
Chris Wilsona3556f42016-12-21 16:37:07 +0000517 struct dirent *de;
Marius Vlad0268d732016-12-01 21:45:47 +0000518
519 dir = opendir(path);
520 if (!dir)
521 return;
522
Chris Wilsona3556f42016-12-21 16:37:07 +0000523 while ((de = readdir(dir))) {
Eric Anholt7f92d002017-09-02 21:38:51 -0700524 char buf[PATH_MAX];
Marius Vlad0268d732016-12-01 21:45:47 +0000525 int fd, len;
526
Chris Wilsona3556f42016-12-21 16:37:07 +0000527 if (strncmp(de->d_name, "vtcon", 5))
Marius Vlad0268d732016-12-01 21:45:47 +0000528 continue;
529
Chris Wilsona3556f42016-12-21 16:37:07 +0000530 sprintf(buf, "%s/%s/name", path, de->d_name);
Marius Vlad0268d732016-12-01 21:45:47 +0000531 fd = open(buf, O_RDONLY);
532 if (fd < 0)
533 continue;
534
Chris Wilsona3556f42016-12-21 16:37:07 +0000535 buf[sizeof(buf) - 1] = '\0';
Marius Vlad0268d732016-12-01 21:45:47 +0000536 len = read(fd, buf, sizeof(buf) - 1);
537 close(fd);
538 if (len >= 0)
539 buf[len] = '\0';
540
Ville Syrjäläd18fca72017-09-06 15:41:08 +0300541 if (!strstr(buf, enable ? "dummy device" :
542 "frame buffer device"))
Chris Wilsona3556f42016-12-21 16:37:07 +0000543 continue;
544
545 sprintf(buf, "%s/%s/bind", path, de->d_name);
546 fd = open(buf, O_WRONLY);
547 if (fd != -1) {
Ville Syrjäläd18fca72017-09-06 15:41:08 +0300548 igt_ignore_warn(write(fd, "0\n", 2));
Chris Wilsona3556f42016-12-21 16:37:07 +0000549 close(fd);
Marius Vlad0268d732016-12-01 21:45:47 +0000550 }
551 }
552 closedir(dir);
553}
554
555/**
556 * kick_snd_hda_intel:
557 *
558 * This functions unbinds the snd_hda_intel driver so the module cand be
559 * unloaded.
560 *
561 */
562void kick_snd_hda_intel(void)
563{
564 DIR *dir;
565 struct dirent *snd_hda;
566 int fd; size_t len;
567
568 const char *dpath = "/sys/bus/pci/drivers/snd_hda_intel";
569 const char *path = "/sys/bus/pci/drivers/snd_hda_intel/unbind";
570 const char *devid = "0000:";
571
572 fd = open(path, O_WRONLY);
573 if (fd < 0) {
574 return;
575 }
576
577 dir = opendir(dpath);
578 if (!dir)
579 goto out;
580
581 len = strlen(devid);
582 while ((snd_hda = readdir(dir))) {
583 struct stat st;
584 char fpath[PATH_MAX];
585
586 if (*snd_hda->d_name == '.')
587 continue;
588
589 snprintf(fpath, sizeof(fpath), "%s/%s", dpath, snd_hda->d_name);
590 if (lstat(fpath, &st))
591 continue;
592
593 if (!S_ISLNK(st.st_mode))
594 continue;
595
596 if (!strncmp(devid, snd_hda->d_name, len)) {
597 igt_ignore_warn(write(fd, snd_hda->d_name,
598 strlen(snd_hda->d_name)));
599 }
600 }
601
602 closedir(dir);
603out:
604 close(fd);
605}