pax_global_header00006660000000000000000000000064136067653010014521gustar00rootroot0000000000000052 comment=3907336a4107aa1cadf9032e5508b4d626ad2c99 drm_info-2.2.0/000077500000000000000000000000001360676530100133175ustar00rootroot00000000000000drm_info-2.2.0/.build.yml000066400000000000000000000004031360676530100152140ustar00rootroot00000000000000image: debian/stable packages: - libdrm-dev - meson - pkgconf sources: - https://github.com/ascent12/drm_info tasks: - setup: | cd drm_info meson subprojects download meson build - build: | cd drm_info ninja -C build drm_info-2.2.0/.gitignore000066400000000000000000000001061360676530100153040ustar00rootroot00000000000000subprojects/packagecache subprojects/json-c-0.13.1 subprojects/libdrm drm_info-2.2.0/LICENSE000066400000000000000000000020421360676530100143220ustar00rootroot00000000000000Copyright (c) 2018 Scott Anderson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. drm_info-2.2.0/README.md000066400000000000000000000022571360676530100146040ustar00rootroot00000000000000# drm_info [![builds.sr.ht status](https://builds.sr.ht/~ascent/drm_info.svg)](https://builds.sr.ht/~ascent/drm_info?) Small utility to dump info about DRM devices. Requires libdrm and json-c. ## Building Build with ``` meson build cd build ninja sudo ninja install ``` If you don't have the minimum json-c version (0.13.0), meson will automatically download and compile it for you. If you don't want this, run the first meson command with ``` meson build --wrap-mode nofallback ``` ## Usage ``` drm_info [-j] [--] [path]... ``` - `-j` - Output info in JSON. Otherwise the output is pretty-printed. - `path` - Zero or more paths to a DRM device to print info about, e.g. `/dev/dri/card0`. If no paths are given, all devices found in `/dev/dri/card*` are printed. ## DRM database [drmdb](https://drmdb.emersion.fr) is a database of Direct Rendering Manager dumps. This database is used to keep track of GPUs and DRM driver features support. Please help us gather more data! You can do so by uploading DRM information from your GPU. ``` drm_info -j | curl -X POST -d @- https://drmdb.emersion.fr/submit ``` This will upload information about your GPUs, your GPU drivers and your screens. drm_info-2.2.0/drm_info.h000066400000000000000000000002321360676530100152620ustar00rootroot00000000000000#ifndef DRM_INFO_H #define DRM_INFO_H struct json_object; struct json_object *drm_info(char *paths[]); void print_drm(struct json_object *obj); #endif drm_info-2.2.0/fourcc.py000077500000000000000000000035371360676530100151650ustar00rootroot00000000000000#!/usr/bin/env python3 import sys import re from itertools import chain, combinations def powerset(s): return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1)) def case_print(f, c, s): f.write('\tcase {}:\n'.format(c)) f.write('\t\treturn "{}";\n'.format(s)) def afbc_print(f, l): fmt = 'DRM_FORMAT_MOD_ARM_AFBC({})' if l: # Strip prefix to stop string being stupidly long short = [s[len('AFBC_FORMAT_MOD_'):] for s in l] case_print(f, fmt.format('|'.join(l)), fmt.format('|'.join(short))) else: case_print(f, fmt.format(0), fmt.format(0)) info = { 'fmt': r'^#define (\w+)\s*(?:\\$\s*)?fourcc_code', 'basic_pre': r'\bI915_FORMAT_MOD_\w+\b', 'basic_post': r'\b(DRM_FORMAT_MOD_(?:INVALID|LINEAR|SAMSUNG|QCOM|VIVANTE|NVIDIA|BROADCOM|ALLWINNER)\w*)\s', 'afbc_block': r'\bAFBC_FORMAT_MOD_BLOCK_SIZE(?:_\d+x\d+)+\b', 'afbc_bitmask': r'\bAFBC_FORMAT_MOD_[A-Z]+\b', } with open(sys.argv[1], 'r') as f: data = f.read() for k, v in info.items(): info[k] = re.findall(v, data, flags=re.M) with open(sys.argv[2], 'w') as f: f.write('''\ #include #include #include "tables.h" const char *format_str(uint32_t format) { switch (format) { case DRM_FORMAT_INVALID: return "INVALID"; ''') for ident in info['fmt']: case_print(f, ident, ident[len('DRM_FORMAT_'):]) f.write('''\ default: return "Unknown"; } } const char *modifier_str(uint64_t modifier) { switch (modifier) { ''') for ident in info['basic_pre'] + info['basic_post']: case_print(f, ident, ident) # ARM framebuffer compression # Not all of the combintations we generate will be valid modifers exposed # by the driver for bits in powerset(info['afbc_bitmask']): bits = list(bits) bits.sort() afbc_print(f, bits) for block in info['afbc_block']: afbc_print(f, bits + [block]) f.write('''\ default: return "Unknown"; } } ''') drm_info-2.2.0/json.c000066400000000000000000000527201360676530100144420ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include "drm_info.h" static const struct { const char *name; uint64_t cap; } client_caps[] = { { "STEREO_3D", DRM_CLIENT_CAP_STEREO_3D }, { "UNIVERSAL_PLANES", DRM_CLIENT_CAP_UNIVERSAL_PLANES }, { "ATOMIC", DRM_CLIENT_CAP_ATOMIC }, { "ASPECT_RATIO", DRM_CLIENT_CAP_ASPECT_RATIO }, { "WRITEBACK_CONNECTORS", DRM_CLIENT_CAP_WRITEBACK_CONNECTORS }, }; static const struct { const char *name; uint64_t cap; } caps[] = { { "DUMB_BUFFER", DRM_CAP_DUMB_BUFFER }, { "VBLANK_HIGH_CRTC", DRM_CAP_VBLANK_HIGH_CRTC }, { "DUMB_PREFERRED_DEPTH", DRM_CAP_DUMB_PREFERRED_DEPTH }, { "DUMB_PREFER_SHADOW", DRM_CAP_DUMB_PREFER_SHADOW }, { "PRIME", DRM_CAP_PRIME }, { "TIMESTAMP_MONOTONIC", DRM_CAP_TIMESTAMP_MONOTONIC }, { "ASYNC_PAGE_FLIP", DRM_CAP_ASYNC_PAGE_FLIP }, { "CURSOR_WIDTH", DRM_CAP_CURSOR_WIDTH }, { "CURSOR_HEIGHT", DRM_CAP_CURSOR_HEIGHT }, { "ADDFB2_MODIFIERS", DRM_CAP_ADDFB2_MODIFIERS }, { "PAGE_FLIP_TARGET", DRM_CAP_PAGE_FLIP_TARGET }, { "CRTC_IN_VBLANK_EVENT", DRM_CAP_CRTC_IN_VBLANK_EVENT }, { "SYNCOBJ", DRM_CAP_SYNCOBJ }, { "SYNCOBJ_TIMELINE", DRM_CAP_SYNCOBJ_TIMELINE }, }; static int json_object_uint_to_json_string(struct json_object *obj, struct printbuf *pb, int level, int flags) { (void)level; (void)flags; uint64_t u = (uint64_t)json_object_get_int64(obj); char buf[21]; // 20 digits + NULL byte int len = snprintf(buf, sizeof(buf), "%" PRIu64, u); return printbuf_memappend(pb, buf, len); } static struct json_object *new_json_object_uint64(uint64_t u) { struct json_object *obj = json_object_new_int64((int64_t)u); json_object_set_serializer(obj, json_object_uint_to_json_string, NULL, NULL); return obj; } static struct json_object *kernel_info(void) { struct utsname utsname; if (uname(&utsname) != 0) { perror("uname"); return NULL; } struct json_object *obj = json_object_new_object(); json_object_object_add(obj, "sysname", json_object_new_string(utsname.sysname)); json_object_object_add(obj, "release", json_object_new_string(utsname.release)); json_object_object_add(obj, "version", json_object_new_string(utsname.version)); return obj; } static struct json_object *driver_info(int fd) { drmVersion *ver = drmGetVersion(fd); if (!ver) { perror("drmGetVersion"); return NULL; } struct json_object *obj = json_object_new_object(); json_object_object_add(obj, "name", json_object_new_string(ver->name)); json_object_object_add(obj, "desc", json_object_new_string(ver->desc)); struct json_object *ver_obj = json_object_new_object(); json_object_object_add(ver_obj, "major", json_object_new_int(ver->version_major)); json_object_object_add(ver_obj, "minor", json_object_new_int(ver->version_minor)); json_object_object_add(ver_obj, "patch", json_object_new_int(ver->version_patchlevel)); json_object_object_add(ver_obj, "date", json_object_new_string(ver->date)); json_object_object_add(obj, "version", ver_obj); drmFreeVersion(ver); json_object_object_add(obj, "kernel", kernel_info()); struct json_object *client_caps_obj = json_object_new_object(); for (size_t i = 0; i < sizeof(client_caps) / sizeof(client_caps[0]); ++i) { bool supported = drmSetClientCap(fd, client_caps[i].cap, 1) == 0; json_object_object_add(client_caps_obj, client_caps[i].name, json_object_new_boolean(supported)); } json_object_object_add(obj, "client_caps", client_caps_obj); struct json_object *caps_obj = json_object_new_object(); for (size_t i = 0; i < sizeof(caps) / sizeof(caps[0]); ++i) { struct json_object *cap_obj = NULL; uint64_t cap; if (drmGetCap(fd, caps[i].cap, &cap) == 0) { cap_obj = json_object_new_int64(cap); } json_object_object_add(caps_obj, caps[i].name, cap_obj); } json_object_object_add(obj, "caps", caps_obj); return obj; } static struct json_object *device_info(int fd) { drmDevice *dev; if (drmGetDevice(fd, &dev) != 0) { perror("drmGetDevice"); return NULL; } struct json_object *obj = json_object_new_object(); json_object_object_add(obj, "bus_type", new_json_object_uint64(dev->bustype)); struct json_object *device_data_obj = NULL; switch (dev->bustype) { case DRM_BUS_PCI:; drmPciDeviceInfo *pci = dev->deviceinfo.pci; device_data_obj = json_object_new_object(); json_object_object_add(device_data_obj, "vendor", new_json_object_uint64(pci->vendor_id)); json_object_object_add(device_data_obj, "device", new_json_object_uint64(pci->device_id)); json_object_object_add(device_data_obj, "subsystem_vendor", new_json_object_uint64(pci->subvendor_id)); json_object_object_add(device_data_obj, "subsystem_device", new_json_object_uint64(pci->subdevice_id)); break; case DRM_BUS_PLATFORM:; drmPlatformDeviceInfo *platform = dev->deviceinfo.platform; device_data_obj = json_object_new_object(); struct json_object *compatible_arr = json_object_new_array(); for (size_t i = 0; platform->compatible[i]; ++i) json_object_array_add(compatible_arr, json_object_new_string(platform->compatible[i])); json_object_object_add(device_data_obj, "compatible", compatible_arr); break; } json_object_object_add(obj, "device_data", device_data_obj); drmFreeDevice(&dev); return obj; } static struct json_object *in_formats_info(int fd, uint32_t blob_id) { struct json_object *arr = json_object_new_array(); drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd, blob_id); if (!blob) { perror("drmModeGetPropertyBlob"); return NULL; } struct drm_format_modifier_blob *data = blob->data; uint32_t *fmts = (uint32_t *) ((char *)data + data->formats_offset); struct drm_format_modifier *mods = (struct drm_format_modifier *) ((char *)data + data->modifiers_offset); for (uint32_t i = 0; i < data->count_modifiers; ++i) { struct json_object *mod_obj = json_object_new_object(); json_object_object_add(mod_obj, "modifier", new_json_object_uint64(mods[i].modifier)); struct json_object *fmts_arr = json_object_new_array(); for (uint64_t j = 0; j < 64; ++j) { if (mods[i].formats & (1ull << j)) { uint32_t fmt = fmts[j + mods[i].offset]; json_object_array_add(fmts_arr, new_json_object_uint64(fmt)); } } json_object_object_add(mod_obj, "formats", fmts_arr); json_object_array_add(arr, mod_obj); } drmModeFreePropertyBlob(blob); return arr; } static struct json_object *mode_info(const drmModeModeInfo *mode) { struct json_object *obj = json_object_new_object(); json_object_object_add(obj, "clock", new_json_object_uint64(mode->clock)); json_object_object_add(obj, "hdisplay", new_json_object_uint64(mode->hdisplay)); json_object_object_add(obj, "hsync_start", new_json_object_uint64(mode->hsync_start)); json_object_object_add(obj, "hsync_end", new_json_object_uint64(mode->hsync_end)); json_object_object_add(obj, "htotal", new_json_object_uint64(mode->htotal)); json_object_object_add(obj, "hskew", new_json_object_uint64(mode->hskew)); json_object_object_add(obj, "vdisplay", new_json_object_uint64(mode->vdisplay)); json_object_object_add(obj, "vsync_start", new_json_object_uint64(mode->vsync_start)); json_object_object_add(obj, "vsync_end", new_json_object_uint64(mode->vsync_end)); json_object_object_add(obj, "vtotal", new_json_object_uint64(mode->vtotal)); json_object_object_add(obj, "vscan", new_json_object_uint64(mode->vscan)); json_object_object_add(obj, "vrefresh", new_json_object_uint64(mode->vrefresh)); json_object_object_add(obj, "flags", new_json_object_uint64(mode->flags)); json_object_object_add(obj, "type", new_json_object_uint64(mode->type)); json_object_object_add(obj, "name", json_object_new_string(mode->name)); return obj; } static struct json_object *mode_id_info(int fd, uint32_t blob_id) { drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd, blob_id); if (!blob) { perror("drmModeGetPropertyBlob"); return NULL; } drmModeModeInfo *mode = blob->data; struct json_object *obj = mode_info(mode); drmModeFreePropertyBlob(blob); return obj; } static struct json_object *writeback_pixel_formats_info(int fd, uint32_t blob_id) { struct json_object *arr = json_object_new_array(); drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd, blob_id); if (!blob) { perror("drmModeGetPropertyBlob"); return NULL; } uint32_t *fmts = blob->data; uint32_t fmts_len = blob->length / sizeof(uint32_t); for (uint32_t i = 0; i < fmts_len; ++i) { json_object_array_add(arr, new_json_object_uint64(fmts[i])); } drmModeFreePropertyBlob(blob); return arr; } static struct json_object *path_info(int fd, uint32_t blob_id) { drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd, blob_id); if (!blob) { perror("drmModeGetPropertyBlob"); return NULL; } struct json_object *obj = json_object_new_string_len(blob->data, blob->length); drmModeFreePropertyBlob(blob); return obj; } static struct json_object *fb_info(int fd, uint32_t id) { // TODO: use drmModeGetFB2: https://patchwork.freedesktop.org/series/67552/ drmModeFB *fb = drmModeGetFB(fd, id); if (!fb) { perror("drmModeGetFB"); return NULL; } struct json_object *obj = json_object_new_object(); json_object_object_add(obj, "id", new_json_object_uint64(fb->fb_id)); json_object_object_add(obj, "width", new_json_object_uint64(fb->width)); json_object_object_add(obj, "height", new_json_object_uint64(fb->height)); json_object_object_add(obj, "pitch", new_json_object_uint64(fb->pitch)); json_object_object_add(obj, "bpp", new_json_object_uint64(fb->bpp)); json_object_object_add(obj, "depth", new_json_object_uint64(fb->depth)); drmModeFreeFB(fb); return obj; } static struct json_object *properties_info(int fd, uint32_t id, uint32_t type) { drmModeObjectProperties *props = drmModeObjectGetProperties(fd, id, type); if (!props) { perror("drmModeObjectGetProperties"); return NULL; } struct json_object *obj = json_object_new_object(); for (uint32_t i = 0; i < props->count_props; ++i) { drmModePropertyRes *prop = drmModeGetProperty(fd, props->props[i]); if (!prop) { perror("drmModeGetProperty"); continue; } uint32_t flags = prop->flags; uint32_t type = flags & (DRM_MODE_PROP_LEGACY_TYPE | DRM_MODE_PROP_EXTENDED_TYPE); bool atomic = flags & DRM_MODE_PROP_ATOMIC; bool immutable = flags & DRM_MODE_PROP_IMMUTABLE; uint64_t value = props->prop_values[i]; struct json_object *prop_obj = json_object_new_object(); json_object_object_add(prop_obj, "id", new_json_object_uint64(prop->prop_id)); json_object_object_add(prop_obj, "flags", new_json_object_uint64(flags)); json_object_object_add(prop_obj, "type", new_json_object_uint64(type)); json_object_object_add(prop_obj, "atomic", json_object_new_boolean(atomic)); json_object_object_add(prop_obj, "immutable", json_object_new_boolean(immutable)); json_object_object_add(prop_obj, "raw_value", new_json_object_uint64(value)); struct json_object *spec_obj = NULL; switch (type) { case DRM_MODE_PROP_RANGE: spec_obj = json_object_new_object(); json_object_object_add(spec_obj, "min", new_json_object_uint64(prop->values[0])); json_object_object_add(spec_obj, "max", new_json_object_uint64(prop->values[1])); break; case DRM_MODE_PROP_ENUM: case DRM_MODE_PROP_BITMASK: spec_obj = json_object_new_array(); for (int j = 0; j < prop->count_enums; ++j) { struct json_object *item_obj = json_object_new_object(); json_object_object_add(item_obj, "name", json_object_new_string(prop->enums[j].name)); json_object_object_add(item_obj, "value", new_json_object_uint64(prop->enums[j].value)); json_object_array_add(spec_obj, item_obj); } break; case DRM_MODE_PROP_OBJECT: spec_obj = new_json_object_uint64(prop->values[0]); break; case DRM_MODE_PROP_SIGNED_RANGE: spec_obj = json_object_new_object(); json_object_object_add(spec_obj, "min", json_object_new_int64((int64_t)prop->values[0])); json_object_object_add(spec_obj, "max", json_object_new_int64((int64_t)prop->values[1])); break; } json_object_object_add(prop_obj, "spec", spec_obj); struct json_object *value_obj = NULL; switch (type) { case DRM_MODE_PROP_RANGE: case DRM_MODE_PROP_ENUM: case DRM_MODE_PROP_BITMASK: case DRM_MODE_PROP_OBJECT: value_obj = new_json_object_uint64(value); break; case DRM_MODE_PROP_BLOB: // TODO: base64-encode blob contents value_obj = NULL; break; case DRM_MODE_PROP_SIGNED_RANGE: value_obj = json_object_new_int64((int64_t)value); break; } json_object_object_add(prop_obj, "value", value_obj); struct json_object *data_obj = NULL; switch (type) { case DRM_MODE_PROP_BLOB: if (!value) { break; } if (strcmp(prop->name, "IN_FORMATS") == 0) { data_obj = in_formats_info(fd, value); } else if (strcmp(prop->name, "MODE_ID") == 0) { data_obj = mode_id_info(fd, value); } else if (strcmp(prop->name, "WRITEBACK_PIXEL_FORMATS") == 0) { data_obj = writeback_pixel_formats_info(fd, value); } else if (strcmp(prop->name, "PATH") == 0) { data_obj = path_info(fd, value); } break; case DRM_MODE_PROP_RANGE: // This is a special case, as the SRC_* properties are // in 16.16 fixed point if (strncmp(prop->name, "SRC_", 4) == 0) { data_obj = new_json_object_uint64(value >> 16); } break; case DRM_MODE_PROP_OBJECT: if (!value) { break; } if (strcmp(prop->name, "FB_ID") == 0) { data_obj = fb_info(fd, value); } break; } json_object_object_add(prop_obj, "data", data_obj); json_object_object_add(obj, prop->name, prop_obj); drmModeFreeProperty(prop); } drmModeFreeObjectProperties(props); return obj; } static struct json_object *connectors_info(int fd, drmModeRes *res) { struct json_object *arr = json_object_new_array(); for (int i = 0; i < res->count_connectors; ++i) { drmModeConnector *conn = drmModeGetConnector(fd, res->connectors[i]); if (!conn) { perror("drmModeGetConnector"); continue; } struct json_object *conn_obj = json_object_new_object(); json_object_object_add(conn_obj, "id", new_json_object_uint64(conn->connector_id)); json_object_object_add(conn_obj, "type", new_json_object_uint64(conn->connector_type)); json_object_object_add(conn_obj, "status", new_json_object_uint64(conn->connection)); json_object_object_add(conn_obj, "phy_width", new_json_object_uint64(conn->mmWidth)); json_object_object_add(conn_obj, "phy_height", new_json_object_uint64(conn->mmHeight)); json_object_object_add(conn_obj, "subpixel", new_json_object_uint64(conn->subpixel)); json_object_object_add(conn_obj, "encoder_id", new_json_object_uint64(conn->encoder_id)); struct json_object *encoders_arr = json_object_new_array(); for (int j = 0; j < conn->count_encoders; ++j) { json_object_array_add(encoders_arr, new_json_object_uint64(conn->encoders[j])); } json_object_object_add(conn_obj, "encoders", encoders_arr); struct json_object *modes_arr = json_object_new_array(); for (int j = 0; j < conn->count_modes; ++j) { const drmModeModeInfo *mode = &conn->modes[j]; json_object_array_add(modes_arr, mode_info(mode)); } json_object_object_add(conn_obj, "modes", modes_arr); struct json_object *props_obj = properties_info(fd, conn->connector_id, DRM_MODE_OBJECT_CONNECTOR); json_object_object_add(conn_obj, "properties", props_obj); drmModeFreeConnector(conn); json_object_array_add(arr, conn_obj); } return arr; } static struct json_object *encoders_info(int fd, drmModeRes *res) { struct json_object *arr = json_object_new_array(); for (int i = 0; i < res->count_encoders; ++i) { drmModeEncoder *enc = drmModeGetEncoder(fd, res->encoders[i]); if (!enc) { perror("drmModeGetEncoder"); continue; } struct json_object *enc_obj = json_object_new_object(); json_object_object_add(enc_obj, "id", new_json_object_uint64(enc->encoder_id)); json_object_object_add(enc_obj, "type", new_json_object_uint64(enc->encoder_type)); json_object_object_add(enc_obj, "crtc_id", new_json_object_uint64(enc->crtc_id)); json_object_object_add(enc_obj, "possible_crtcs", new_json_object_uint64(enc->possible_crtcs)); json_object_object_add(enc_obj, "possible_clones", new_json_object_uint64(enc->possible_clones)); drmModeFreeEncoder(enc); json_object_array_add(arr, enc_obj); } return arr; } static struct json_object *crtcs_info(int fd, drmModeRes *res) { struct json_object *arr = json_object_new_array(); for (int i = 0; i < res->count_crtcs; ++i) { drmModeCrtc *crtc = drmModeGetCrtc(fd, res->crtcs[i]); if (!crtc) { perror("drmModeGetCrtc"); continue; } struct json_object *crtc_obj = json_object_new_object(); json_object_object_add(crtc_obj, "id", new_json_object_uint64(crtc->crtc_id)); json_object_object_add(crtc_obj, "fb_id", new_json_object_uint64(crtc->buffer_id)); json_object_object_add(crtc_obj, "x", new_json_object_uint64(crtc->x)); json_object_object_add(crtc_obj, "y", new_json_object_uint64(crtc->y)); if (crtc->mode_valid) { json_object_object_add(crtc_obj, "mode", mode_info(&crtc->mode)); } else { json_object_object_add(crtc_obj, "mode", NULL); } json_object_object_add(crtc_obj, "gamma_size", json_object_new_int(crtc->gamma_size)); struct json_object *props_obj = properties_info(fd, crtc->crtc_id, DRM_MODE_OBJECT_CRTC); json_object_object_add(crtc_obj, "properties", props_obj); drmModeFreeCrtc(crtc); json_object_array_add(arr, crtc_obj); } return arr; } static struct json_object *planes_info(int fd) { drmModePlaneRes *res = drmModeGetPlaneResources(fd); if (!res) { perror("drmModeGetPlaneResources"); return NULL; } struct json_object *arr = json_object_new_array(); for (uint32_t i = 0; i < res->count_planes; ++i) { drmModePlane *plane = drmModeGetPlane(fd, res->planes[i]); if (!plane) { perror("drmModeGetPlane"); continue; } struct json_object *plane_obj = json_object_new_object(); json_object_object_add(plane_obj, "id", new_json_object_uint64(plane->plane_id)); json_object_object_add(plane_obj, "possible_crtcs", new_json_object_uint64(plane->possible_crtcs)); json_object_object_add(plane_obj, "crtc_id", new_json_object_uint64(plane->crtc_id)); json_object_object_add(plane_obj, "fb_id", new_json_object_uint64(plane->fb_id)); json_object_object_add(plane_obj, "crtc_x", new_json_object_uint64(plane->crtc_x)); json_object_object_add(plane_obj, "crtc_y", new_json_object_uint64(plane->crtc_y)); json_object_object_add(plane_obj, "x", new_json_object_uint64(plane->x)); json_object_object_add(plane_obj, "y", new_json_object_uint64(plane->y)); json_object_object_add(plane_obj, "gamma_size", new_json_object_uint64(plane->gamma_size)); struct json_object *formats_arr = json_object_new_array(); for (uint32_t j = 0; j < plane->count_formats; ++j) { json_object_array_add(formats_arr, new_json_object_uint64(plane->formats[j])); } json_object_object_add(plane_obj, "formats", formats_arr); struct json_object *props_obj = properties_info(fd, plane->plane_id, DRM_MODE_OBJECT_PLANE); json_object_object_add(plane_obj, "properties", props_obj); drmModeFreePlane(plane); json_object_array_add(arr, plane_obj); } drmModeFreePlaneResources(res); return arr; } static struct json_object *node_info(const char *path) { int fd = open(path, O_RDONLY); if (fd < 0) { perror(path); return NULL; } struct json_object *obj = json_object_new_object(); // Get driver info before getting resources, as it'll try to enable some // DRM client capabilities json_object_object_add(obj, "driver", driver_info(fd)); json_object_object_add(obj, "device", device_info(fd)); drmModeRes *res = drmModeGetResources(fd); if (!res) { perror("drmModeGetResources"); close(fd); json_object_put(obj); return NULL; } struct json_object *fb_size_obj = json_object_new_object(); json_object_object_add(fb_size_obj, "min_width", new_json_object_uint64(res->min_width)); json_object_object_add(fb_size_obj, "max_width", new_json_object_uint64(res->max_width)); json_object_object_add(fb_size_obj, "min_height", new_json_object_uint64(res->min_height)); json_object_object_add(fb_size_obj, "max_height", new_json_object_uint64(res->max_height)); json_object_object_add(obj, "fb_size", fb_size_obj); json_object_object_add(obj, "connectors", connectors_info(fd, res)); json_object_object_add(obj, "encoders", encoders_info(fd, res)); json_object_object_add(obj, "crtcs", crtcs_info(fd, res)); json_object_object_add(obj, "planes", planes_info(fd)); drmModeFreeResources(res); close(fd); return obj; } /* paths is a NULL terminated argv array */ struct json_object *drm_info(char *paths[]) { struct json_object *obj = json_object_new_object(); /* Print everything by default */ if (!paths[0]) { drmDevice *devices[64]; int n = drmGetDevices(devices, sizeof(devices) / sizeof(devices[0])); if (n < 0) { perror("drmGetDevices"); json_object_put(obj); return NULL; } for (int i = 0; i < n; ++i) { drmDevice *dev = devices[i]; if (!(dev->available_nodes & (1 << DRM_NODE_PRIMARY))) continue; const char *path = dev->nodes[DRM_NODE_PRIMARY]; struct json_object *dev_obj = node_info(path); if (!dev_obj) continue; json_object_object_add(obj, path, dev_obj); } drmFreeDevices(devices, n); } else { for (char **path = paths; *path; ++path) { struct json_object *dev = node_info(*path); if (!dev) continue; json_object_object_add(obj, *path, dev); } } return obj; } drm_info-2.2.0/main.c000066400000000000000000000013561360676530100144140ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "drm_info.h" int main(int argc, char *argv[]) { bool json = false; int opt; while ((opt = getopt(argc, argv, "j")) != -1) { switch (opt) { case 'j': json = true; break; default: fprintf(stderr, "usage: drm_info [-j] [--] [path]...\n"); exit(opt == '?' ? EXIT_SUCCESS : EXIT_FAILURE); } } struct json_object *obj = drm_info(&argv[optind]); if (!obj) { exit(EXIT_FAILURE); } if (json) { json_object_to_fd(STDOUT_FILENO, obj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED); } else { print_drm(obj); } json_object_put(obj); return EXIT_SUCCESS; } drm_info-2.2.0/meson.build000066400000000000000000000045371360676530100154720ustar00rootroot00000000000000project('drm_info', 'c', version: '2.2.0', license: 'MIT', meson_version: '>=0.49.0', default_options: [ 'c_std=c11', 'warning_level=2', ], ) add_project_arguments('-D_POSIX_C_SOURCE=200809L', language: 'c') jsonc = dependency('json-c', version: '>=0.13', fallback: ['json-c', 'json_c']) libpci = dependency('libpci', required: get_option('libpci')) libdrm = dependency('libdrm', fallback: ['libdrm', 'ext_libdrm'], default_options: [ 'libkms=false', 'intel=false', 'radeon=false', 'amdgpu=false', 'nouveau=false', 'vmwgfx=false', 'omap=false', 'exynos=false', 'freedreno=false', 'tegra=false', 'vc4=false', 'etnaviv=false', 'cairo-tests=false', 'man-pages=false', 'valgrind=false', ], ) inc = [] # libdrm pretty consistently pulls in the linux userspace API headers. # We want a new libdrm to get all of the #defines in those headers, but # we don't actually need to link against a new version of libdrm itself. # # We need to make sure we don't use any new libdrm functions, but those # are added very infrequently, so this is unlikely to be an issue. if libdrm.version().version_compare('<2.4.99') if libdrm.type_name() == 'internal' error('libdrm subproject out of date. Run `meson subprojects update`.') endif msg = [ 'System libdrm version does not have latest Linux DRM headers.', 'Attempting to use headers from meson subproject if present.', 'If this fails, update your system libdrm or run `meson subprojects download`.', ] foreach s : msg warning(s) endforeach fourcc_h = files('subprojects/libdrm/include/drm/drm_fourcc.h') inc += include_directories('subprojects/libdrm/include/drm') libdrm = libdrm.partial_dependency(link_args: true) elif libdrm.type_name() == 'internal' fourcc_h = files('subprojects/libdrm/include/drm/drm_fourcc.h') else fourcc_h = files(libdrm.get_pkgconfig_variable('includedir') / 'libdrm/drm_fourcc.h') endif if libpci.found() add_project_arguments('-DHAVE_LIBPCI', language: 'c') endif python3 = import('python').find_installation() tables_c = custom_target('tables_c', output : 'tables.c', command : [python3, files('fourcc.py'), fourcc_h, '@OUTPUT@']) executable('drm_info', [files('main.c', 'json.c', 'pretty.c'), tables_c], include_directories: inc, dependencies: [libdrm, libpci, jsonc], install: true, ) drm_info-2.2.0/meson_options.txt000066400000000000000000000001521360676530100167520ustar00rootroot00000000000000option('libpci', type: 'feature', value: 'auto', description: 'Print PCI device names via libpci' ) drm_info-2.2.0/pretty.c000066400000000000000000000610751360676530100150230ustar00rootroot00000000000000#include #include #include #include #include #include #include #ifdef HAVE_LIBPCI #include #endif #include "drm_info.h" #include "tables.h" #define L_LINE "│ " #define L_VAL "├───" #define L_LAST "└───" #define L_GAP " " static uint64_t get_object_uint64(struct json_object *obj) { return (uint64_t)json_object_get_int64(obj); } static const char *get_object_object_string(struct json_object *obj, const char *key) { struct json_object *str_obj = json_object_object_get(obj, key); if (!str_obj) { return NULL; } return json_object_get_string(str_obj); } static uint64_t get_object_object_uint64(struct json_object *obj, const char *key) { struct json_object *uint64_obj = json_object_object_get(obj, key); if (!uint64_obj) { return 0; } return get_object_uint64(uint64_obj); } static void print_driver(struct json_object *obj) { const char *name = get_object_object_string(obj, "name"); const char *desc = get_object_object_string(obj, "desc"); struct json_object *version_obj = json_object_object_get(obj, "version"); int version_major = get_object_object_uint64(version_obj, "major"); int version_minor = get_object_object_uint64(version_obj, "minor"); int version_patch = get_object_object_uint64(version_obj, "patch"); const char *version_date = get_object_object_string(version_obj, "date"); printf(L_VAL "Driver: %s (%s) version %d.%d.%d (%s)\n", name, desc, version_major, version_minor, version_patch, version_date); struct json_object_iter iter; struct json_object *client_caps_obj = json_object_object_get(obj, "client_caps"); json_object_object_foreachC(client_caps_obj, iter) { json_bool supported = json_object_get_boolean(iter.val); printf(L_LINE L_VAL "DRM_CLIENT_CAP_%s %s\n", iter.key, supported ? "supported" : "not supported"); } struct json_object *caps_obj = json_object_object_get(obj, "caps"); json_object_object_foreachC(caps_obj, iter) { printf(!iter.entry->next ? L_LINE L_LAST : L_LINE L_VAL); if (iter.val == NULL) { printf("DRM_CAP_%s not supported\n", iter.key); } else { printf("DRM_CAP_%s = %"PRIu64"\n", iter.key, get_object_uint64(iter.val)); } } } static const char *bustype_str(int type) { switch (type) { case DRM_BUS_PCI: return "PCI"; case DRM_BUS_USB: return "USB"; case DRM_BUS_PLATFORM: return "platform"; case DRM_BUS_HOST1X: return "host1x"; default: return "unknown"; } } static void print_device(struct json_object *obj) { int bus_type = get_object_object_uint64(obj, "bus_type"); struct json_object *data_obj = json_object_object_get(obj, "device_data"); printf(L_VAL "Device: %s", bustype_str(bus_type)); switch (bus_type) { case DRM_BUS_PCI:; uint16_t vendor = get_object_object_uint64(data_obj, "vendor"); uint16_t device = get_object_object_uint64(data_obj, "device"); printf(" %04x:%04x", vendor, device); #ifdef HAVE_LIBPCI struct pci_access *pci = pci_alloc(); char name[512]; if (pci_lookup_name(pci, name, sizeof(name), PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, vendor, device)) { printf(" %s", name); } pci_cleanup(pci); #endif break; case DRM_BUS_PLATFORM:; struct json_object *compatible_arr = json_object_object_get(data_obj, "compatible"); for (size_t i = 0; i < json_object_array_length(compatible_arr); i++) { printf(" %s", json_object_get_string( json_object_array_get_idx(compatible_arr, i))); } break; } printf("\n"); } // The refresh rate provided by the mode itself is innacurate, // so we calculate it ourself. static int32_t refresh_rate(struct json_object *obj) { int clock = get_object_object_uint64(obj, "clock"); int htotal = get_object_object_uint64(obj, "htotal"); int vtotal = get_object_object_uint64(obj, "vtotal"); int vscan = get_object_object_uint64(obj, "vscan"); int flags = get_object_object_uint64(obj, "flags"); int32_t refresh = (clock * 1000000LL / htotal + vtotal / 2) / vtotal; if (flags & DRM_MODE_FLAG_INTERLACE) refresh *= 2; if (flags & DRM_MODE_FLAG_DBLSCAN) refresh /= 2; if (vscan > 1) refresh /= vscan; return refresh; } static void print_mode(struct json_object *obj) { int hdisplay = get_object_object_uint64(obj, "hdisplay"); int vdisplay = get_object_object_uint64(obj, "vdisplay"); int type = get_object_object_uint64(obj, "type"); int flags = get_object_object_uint64(obj, "flags"); printf("%"PRIu16"x%"PRIu16"@%.02f ", hdisplay, vdisplay, refresh_rate(obj) / 1000.0); if (type & DRM_MODE_TYPE_PREFERRED) printf("preferred "); if (type & DRM_MODE_TYPE_USERDEF) printf("userdef "); if (type & DRM_MODE_TYPE_DRIVER) printf("driver "); if (flags & DRM_MODE_FLAG_PHSYNC) printf("phsync "); if (flags & DRM_MODE_FLAG_NHSYNC) printf("nhsync "); if (flags & DRM_MODE_FLAG_PVSYNC) printf("pvsync "); if (flags & DRM_MODE_FLAG_NVSYNC) printf("nvsync "); if (flags & DRM_MODE_FLAG_INTERLACE) printf("interlace "); if (flags & DRM_MODE_FLAG_DBLSCAN) printf("dblscan "); if (flags & DRM_MODE_FLAG_CSYNC) printf("csync "); if (flags & DRM_MODE_FLAG_PCSYNC) printf("pcsync "); if (flags & DRM_MODE_FLAG_NCSYNC) printf("nvsync "); if (flags & DRM_MODE_FLAG_HSKEW) printf("hskew "); if (flags & DRM_MODE_FLAG_DBLCLK) printf("dblclk "); if (flags & DRM_MODE_FLAG_CLKDIV2) printf("clkdiv2 "); switch (flags & DRM_MODE_FLAG_PIC_AR_MASK) { case DRM_MODE_FLAG_PIC_AR_NONE: break; case DRM_MODE_FLAG_PIC_AR_4_3: printf("4:3 "); break; case DRM_MODE_FLAG_PIC_AR_16_9: printf("16:9 "); break; case DRM_MODE_FLAG_PIC_AR_64_27: printf("64:27 "); break; case DRM_MODE_FLAG_PIC_AR_256_135: printf("256:135 "); break; } switch (flags & DRM_MODE_FLAG_3D_MASK) { case DRM_MODE_FLAG_3D_NONE: break; case DRM_MODE_FLAG_3D_FRAME_PACKING: printf("3d-frame-packing "); break; case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE: printf("3d-field-alternative "); break; case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE: printf("3d-line-alternative "); break; case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL: printf("3d-side-by-side-full "); break; case DRM_MODE_FLAG_3D_L_DEPTH: printf("3d-l-depth "); break; case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH: printf("3d-l-depth-gfx-gfx-depth "); break; case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM: printf("3d-top-and-bottom "); break; case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF: printf("3d-side-by-side-half "); break; } } /* Replace well-known constants with strings */ static const char *u64_str(uint64_t val) { switch (val) { case INT8_MAX: return "INT8_MAX"; case UINT8_MAX: return "UINT8_MAX"; case INT16_MAX: return "INT16_MAX"; case UINT16_MAX: return "UINT16_MAX"; case INT32_MAX: return "INT32_MAX"; case UINT32_MAX: return "UINT32_MAX"; case INT64_MAX: return "INT64_MAX"; case UINT64_MAX: return "UINT64_MAX"; default: return NULL; } } /* Replace well-known constants with strings */ static const char *i64_str(int64_t val) { switch (val) { case INT8_MIN: return "INT8_MIN"; case INT16_MIN: return "INT16_MIN"; case INT32_MIN: return "INT32_MIN"; case INT64_MIN: return "INT64_MIN"; case INT8_MAX: return "INT8_MAX"; case UINT8_MAX: return "UINT8_MAX"; case INT16_MAX: return "INT16_MAX"; case UINT16_MAX: return "UINT16_MAX"; case INT32_MAX: return "INT32_MAX"; case UINT32_MAX: return "UINT32_MAX"; case INT64_MAX: return "INT64_MAX"; default: return NULL; } } static const char *obj_str(uint32_t type) { switch (type) { case DRM_MODE_OBJECT_CRTC: return "CRTC"; case DRM_MODE_OBJECT_CONNECTOR: return "connector"; case DRM_MODE_OBJECT_ENCODER: return "encoder"; case DRM_MODE_OBJECT_MODE: return "mode"; case DRM_MODE_OBJECT_PROPERTY: return "property"; case DRM_MODE_OBJECT_FB: return "framebuffer"; case DRM_MODE_OBJECT_BLOB: return "blob"; case DRM_MODE_OBJECT_PLANE: return "plane"; case DRM_MODE_OBJECT_ANY: return "any"; default: return "unknown"; } } static void print_in_formats(struct json_object *arr, const char *prefix) { for (size_t i = 0; i < json_object_array_length(arr); ++i) { bool last = i == json_object_array_length(arr) - 1; struct json_object *mod_obj = json_object_array_get_idx(arr, i); uint64_t mod = get_object_object_uint64(mod_obj, "modifier"); struct json_object *formats_arr = json_object_object_get(mod_obj, "formats"); printf("%s%s%s (0x%"PRIx64")\n", prefix, last ? L_LAST : L_VAL, modifier_str(mod), mod); for (size_t j = 0; j < json_object_array_length(formats_arr); ++j) { bool fmt_last = j == json_object_array_length(formats_arr) - 1; uint32_t fmt = get_object_uint64( json_object_array_get_idx(formats_arr, j)); printf("%s%s%s%s (0x%08"PRIx32")\n", prefix, last ? L_GAP : L_LINE, fmt_last ? L_LAST : L_VAL, format_str(fmt), fmt); } } } static void print_mode_id(struct json_object *obj, const char *prefix) { printf("%s" L_LAST, prefix); print_mode(obj); printf("\n"); } static void print_writeback_pixel_formats(struct json_object *arr, const char *prefix) { for (size_t i = 0; i < json_object_array_length(arr); ++i) { bool last = i == json_object_array_length(arr) - 1; uint32_t fmt = get_object_uint64(json_object_array_get_idx(arr, i)); printf("%s%s%s (0x%08"PRIx32")\n", prefix, last ? L_LAST : L_VAL, format_str(fmt), fmt); } } static void print_path(struct json_object *obj, const char *prefix) { printf("%s" L_LAST "%s\n", prefix, json_object_get_string(obj)); } static void print_fb(struct json_object *obj, const char *prefix) { uint32_t id = get_object_object_uint64(obj, "id"); uint32_t width = get_object_object_uint64(obj, "width"); uint32_t height = get_object_object_uint64(obj, "height"); struct json_object *pitch_obj = json_object_object_get(obj, "pitch"); struct json_object *bpp_obj = json_object_object_get(obj, "bpp"); struct json_object *depth_obj = json_object_object_get(obj, "depth"); bool has_legacy = pitch_obj && bpp_obj && depth_obj; printf("%s" L_VAL "Object ID: %"PRIu32"\n", prefix, id); printf("%s%sSize: %"PRIu32"x%"PRIu32"\n", prefix, has_legacy ? L_VAL : L_LAST, width, height); if (has_legacy) { printf("%s" L_VAL "Pitch: %"PRIu32"\n", prefix, (uint32_t)get_object_uint64(pitch_obj)); printf("%s" L_VAL "Bits per pixel: %"PRIu32"\n", prefix, (uint32_t)get_object_uint64(bpp_obj)); printf("%s" L_LAST "Depth: %"PRIu32"\n", prefix, (uint32_t)get_object_uint64(depth_obj)); } } static void print_properties(struct json_object *obj, const char *prefix) { printf("%s" L_LAST "Properties\n", prefix); struct json_object_iter iter; json_object_object_foreachC(obj, iter) { bool last = !iter.entry->next; const char *prop_name = iter.key; struct json_object *prop_obj = iter.val; char sub_prefix[strlen(prefix) + 2 * strlen(L_VAL) + 1]; snprintf(sub_prefix, sizeof(sub_prefix), "%s" L_GAP "%s", prefix, last ? L_GAP : L_LINE); uint32_t flags = get_object_object_uint64(prop_obj, "flags"); uint32_t type = flags & (DRM_MODE_PROP_LEGACY_TYPE | DRM_MODE_PROP_EXTENDED_TYPE); bool atomic = flags & DRM_MODE_PROP_ATOMIC; bool immutable = flags & DRM_MODE_PROP_IMMUTABLE; printf("%s" L_GAP "%s\"%s\"", prefix, last ? L_LAST : L_VAL, prop_name); if (atomic && immutable) printf(" (atomic, immutable)"); else if (atomic) printf(" (atomic)"); else if (immutable) printf(" (immutable)"); printf(": "); uint64_t raw_val = get_object_object_uint64(prop_obj, "raw_value"); struct json_object *spec_obj = json_object_object_get(prop_obj, "spec"); struct json_object *val_obj = json_object_object_get(prop_obj, "value"); struct json_object *data_obj = json_object_object_get(prop_obj, "data"); bool first; switch (type) { case DRM_MODE_PROP_RANGE:; uint64_t min = get_object_object_uint64(spec_obj, "min"); uint64_t max = get_object_object_uint64(spec_obj, "max"); const char *min_str = u64_str(min); const char *max_str = u64_str(max); if (min_str) printf("range [%s, ", min_str); else printf("range [%"PRIu64", ", min); if (max_str) printf("%s]", max_str); else printf("%"PRIu64"]", max); if (data_obj != NULL) printf(" = %"PRIu64"\n", get_object_uint64(data_obj)); else printf(" = %"PRIu64"\n", get_object_uint64(val_obj)); break; case DRM_MODE_PROP_ENUM: printf("enum {"); const char *val_name = NULL; first = true; for (size_t j = 0; j < json_object_array_length(spec_obj); ++j) { struct json_object *item_obj = json_object_array_get_idx(spec_obj, j); const char *item_name = get_object_object_string(item_obj, "name"); uint64_t item_value = get_object_object_uint64(item_obj, "value"); if (raw_val == item_value) { val_name = item_name; } printf("%s%s", first ? "" : ", ", item_name); first = false; } printf("} = "); if (val_name) { printf("%s\n", val_name); } else { printf("invalid (%"PRIu64")\n", raw_val); } break; case DRM_MODE_PROP_BLOB:; printf("blob = %" PRIu64 "\n", raw_val); if (!data_obj) break; if (strcmp(prop_name, "IN_FORMATS") == 0) print_in_formats(data_obj, sub_prefix); else if (strcmp(prop_name, "MODE_ID") == 0) print_mode_id(data_obj, sub_prefix); else if (strcmp(prop_name, "WRITEBACK_PIXEL_FORMATS") == 0) print_writeback_pixel_formats(data_obj, sub_prefix); else if (strcmp(prop_name, "PATH") == 0) print_path(data_obj, sub_prefix); break; case DRM_MODE_PROP_BITMASK: printf("bitmask {"); first = true; for (size_t j = 0; j < json_object_array_length(spec_obj); ++j) { struct json_object *item_obj = json_object_array_get_idx(spec_obj, j); const char *item_name = get_object_object_string(item_obj, "name"); printf("%s%s", first ? "" : ", ", item_name); first = false; } printf("} = ("); first = true; for (size_t j = 0; j < json_object_array_length(spec_obj); ++j) { struct json_object *item_obj = json_object_array_get_idx(spec_obj, j); const char *item_name = get_object_object_string(item_obj, "name"); uint64_t item_value = get_object_object_uint64(item_obj, "value"); if ((item_value & raw_val) != item_value) { continue; } printf("%s%s", first ? "" : " | ", item_name); first = false; } printf(")\n"); break; case DRM_MODE_PROP_OBJECT:; uint32_t obj_type = get_object_uint64(spec_obj); printf("object %s = %"PRIu64"\n", obj_str(obj_type), raw_val); if (!data_obj) break; if (strcmp(prop_name, "FB_ID") == 0) print_fb(data_obj, sub_prefix); break; case DRM_MODE_PROP_SIGNED_RANGE:; int64_t smin = json_object_get_int64(json_object_object_get(spec_obj, "min")); int64_t smax = json_object_get_int64(json_object_object_get(spec_obj, "max")); const char *smin_str = i64_str(smin); const char *smax_str = i64_str(smax); if (smin_str) printf("srange [%s, ", smin_str); else printf("srange [%"PRIi64", ", smin); if (smax_str) printf("%s]", smax_str); else printf("%"PRIi64"]", smax); if (data_obj != NULL) printf(" = %"PRIi64"\n", json_object_get_int64(data_obj)); else printf(" = %"PRIi64"\n", json_object_get_int64(val_obj)); break; default: printf("unknown type (%"PRIu32") = %"PRIu64"\n", type, raw_val); } } } static void print_modes(struct json_object *arr, const char *prefix) { if (json_object_array_length(arr) == 0) { return; } printf("%s" L_VAL "Modes\n", prefix); for (size_t i = 0; i < json_object_array_length(arr); ++i) { bool last = i == json_object_array_length(arr) - 1; printf("%s" L_LINE "%s", prefix, last ? L_LAST : L_VAL); print_mode(json_object_array_get_idx(arr, i)); printf("\n"); } } static const char *conn_name(uint32_t type) { switch (type) { case DRM_MODE_CONNECTOR_Unknown: return "unknown"; case DRM_MODE_CONNECTOR_VGA: return "VGA"; case DRM_MODE_CONNECTOR_DVII: return "DVI-I"; case DRM_MODE_CONNECTOR_DVID: return "DVI-D"; case DRM_MODE_CONNECTOR_DVIA: return "DVI-A"; case DRM_MODE_CONNECTOR_Composite: return "composite"; case DRM_MODE_CONNECTOR_SVIDEO: return "S-VIDEO"; case DRM_MODE_CONNECTOR_LVDS: return "LVDS"; case DRM_MODE_CONNECTOR_Component: return "component"; case DRM_MODE_CONNECTOR_9PinDIN: return "DIN"; case DRM_MODE_CONNECTOR_DisplayPort: return "DisplayPort"; case DRM_MODE_CONNECTOR_HDMIA: return "HDMI-A"; case DRM_MODE_CONNECTOR_HDMIB: return "HDMI-B"; case DRM_MODE_CONNECTOR_TV: return "TV"; case DRM_MODE_CONNECTOR_eDP: return "eDP"; case DRM_MODE_CONNECTOR_VIRTUAL: return "virtual"; case DRM_MODE_CONNECTOR_DSI: return "DSI"; case DRM_MODE_CONNECTOR_DPI: return "DPI"; case DRM_MODE_CONNECTOR_WRITEBACK: return "writeback"; default: return "unknown"; } } static const char *conn_status(drmModeConnection conn) { switch (conn) { case DRM_MODE_CONNECTED: return "connected"; case DRM_MODE_DISCONNECTED: return "disconnected"; case DRM_MODE_UNKNOWNCONNECTION: return "unknown"; default: return "unknown"; } } static const char *conn_subpixel(drmModeSubPixel subpixel) { switch (subpixel) { case DRM_MODE_SUBPIXEL_UNKNOWN: return "unknown"; case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB: return "horizontal RGB"; case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR: return "horizontal BGR"; case DRM_MODE_SUBPIXEL_VERTICAL_RGB: return "vertical RGB"; case DRM_MODE_SUBPIXEL_VERTICAL_BGR: return "vertical BGR"; case DRM_MODE_SUBPIXEL_NONE: return "none"; default: return "unknown"; } } static ssize_t find_encoder_index(struct json_object *encoders_arr, uint32_t enc_id) { for (size_t i = 0; i < json_object_array_length(encoders_arr); ++i) { struct json_object *obj = json_object_array_get_idx(encoders_arr, i); uint32_t id = get_object_object_uint64(obj, "id"); if (enc_id == id) { return i; } } return -1; } static void print_connectors(struct json_object *arr, struct json_object *encoders_arr) { printf(L_VAL "Connectors\n"); for (size_t i = 0; i < json_object_array_length(arr); ++i) { struct json_object *obj = json_object_array_get_idx(arr, i); bool last = i == json_object_array_length(arr) - 1; uint32_t id = get_object_object_uint64(obj, "id"); uint32_t type = get_object_object_uint64(obj, "type"); drmModeConnection status = get_object_object_uint64(obj, "status"); uint32_t phy_width = get_object_object_uint64(obj, "phy_width"); uint32_t phy_height = get_object_object_uint64(obj, "phy_height"); drmModeSubPixel subpixel = get_object_object_uint64(obj, "subpixel"); struct json_object *encs_arr = json_object_object_get(obj, "encoders"); struct json_object *modes_arr = json_object_object_get(obj, "modes"); struct json_object *props_obj = json_object_object_get(obj, "properties"); printf(L_LINE "%sConnector %zu\n", last ? L_LAST : L_VAL, i); printf(L_LINE "%s" L_VAL "Object ID: %"PRIu32"\n", last ? L_GAP : L_LINE, id); printf(L_LINE "%s" L_VAL "Type: %s\n", last ? L_GAP : L_LINE, conn_name(type)); printf(L_LINE "%s" L_VAL "Status: %s\n", last ? L_GAP : L_LINE, conn_status(status)); if (status != DRM_MODE_DISCONNECTED) { printf(L_LINE "%s" L_VAL "Physical size: %"PRIu32"x%"PRIu32" mm\n", last ? L_GAP : L_LINE, phy_width, phy_height); printf(L_LINE "%s" L_VAL "Subpixel: %s\n", last ? L_GAP : L_LINE, conn_subpixel(subpixel)); } bool first = true; printf(L_LINE "%s" L_VAL "Encoders: {", last ? L_GAP : L_LINE); for (size_t j = 0; j < json_object_array_length(encs_arr); ++j) { uint32_t enc_id = get_object_uint64( json_object_array_get_idx(encs_arr, j)); printf("%s%zi", first ? "" : ", ", find_encoder_index(encoders_arr, enc_id)); first = false; } printf("}\n"); print_modes(modes_arr, last ? L_LINE L_GAP : L_LINE L_LINE); print_properties(props_obj, last ? L_LINE L_GAP : L_LINE L_LINE); } } static const char *encoder_str(uint32_t type) { switch (type) { case DRM_MODE_ENCODER_NONE: return "none"; case DRM_MODE_ENCODER_DAC: return "DAC"; case DRM_MODE_ENCODER_TMDS: return "TMDS"; case DRM_MODE_ENCODER_LVDS: return "LVDS"; case DRM_MODE_ENCODER_TVDAC: return "TV DAC"; case DRM_MODE_ENCODER_VIRTUAL: return "virtual"; case DRM_MODE_ENCODER_DSI: return "DSI"; case DRM_MODE_ENCODER_DPMST: return "DP MST"; case DRM_MODE_ENCODER_DPI: return "DPI"; default: return "unknown"; } } static void print_bitmask(uint32_t mask) { bool first = true; printf("{"); for (uint32_t i = 0; i < 31; ++i) { if (!(mask & (1 << i))) continue; printf("%s%"PRIu32, first ? "" : ", ", i); first = false; } printf("}"); } static void print_encoders(struct json_object *arr) { printf(L_VAL "Encoders\n"); for (size_t i = 0; i < json_object_array_length(arr); ++i) { struct json_object *obj = json_object_array_get_idx(arr, i); bool last = i == json_object_array_length(arr) - 1; uint32_t id = get_object_object_uint64(obj, "id"); uint32_t type = get_object_object_uint64(obj, "type"); uint32_t crtcs = get_object_object_uint64(obj, "possible_crtcs"); uint32_t clones = get_object_object_uint64(obj, "possible_clones"); printf(L_LINE "%sEncoder %zu\n", last ? L_LAST : L_VAL, i); printf(L_LINE "%s" L_VAL "Object ID: %"PRIu32"\n", last ? L_GAP : L_LINE, id); printf(L_LINE "%s" L_VAL "Type: %s\n", last ? L_GAP : L_LINE, encoder_str(type)); printf(L_LINE "%s" L_VAL "CRTCS: ", last ? L_GAP : L_LINE); print_bitmask(crtcs); printf("\n"); printf(L_LINE "%s" L_LAST "Clones: ", last ? L_GAP : L_LINE); print_bitmask(clones); printf("\n"); } } static void print_crtcs(struct json_object *arr) { printf(L_VAL "CRTCs\n"); for (size_t i = 0; i < json_object_array_length(arr); ++i) { struct json_object *obj = json_object_array_get_idx(arr, i); bool last = i == json_object_array_length(arr) - 1; uint32_t id = get_object_object_uint64(obj, "id"); struct json_object *props_obj = json_object_object_get(obj, "properties"); printf(L_LINE "%sCRTC %zu\n", last ? L_LAST : L_VAL, i); printf(L_LINE "%s" L_VAL "Object ID: %"PRIu32"\n", last ? L_GAP : L_LINE, id); struct json_object *mode_obj = json_object_object_get(obj, "mode"); if (mode_obj) { printf(L_LINE "%s" L_VAL "Mode: ", last ? L_GAP : L_LINE); print_mode(mode_obj); printf("\n"); } print_properties(props_obj, last ? L_LINE L_GAP : L_LINE L_LINE); } } static void print_planes(struct json_object *arr) { printf(L_LAST "Planes\n"); for (size_t i = 0; i < json_object_array_length(arr); ++i) { struct json_object *obj = json_object_array_get_idx(arr, i); bool last = i == json_object_array_length(arr) - 1; uint32_t id = get_object_object_uint64(obj, "id"); uint32_t crtcs = get_object_object_uint64(obj, "possible_crtcs"); struct json_object *formats_arr = json_object_object_get(obj, "formats"); struct json_object *props_obj = json_object_object_get(obj, "properties"); printf(L_GAP "%sPlane %zu\n", last ? L_LAST : L_VAL, i); printf(L_GAP "%s" L_VAL "Object ID: %"PRIu32"\n", last ? L_GAP : L_LINE, id); printf(L_GAP "%s" L_VAL "CRTCs: ", last ? L_GAP : L_LINE); print_bitmask(crtcs); printf("\n"); printf(L_GAP "%s" L_VAL "Formats:\n", last ? L_GAP : L_LINE); for (size_t j = 0; j < json_object_array_length(formats_arr); ++j) { uint32_t fmt = get_object_uint64( json_object_array_get_idx(formats_arr, j)); bool fmt_last = j == json_object_array_length(formats_arr) - 1; printf(L_GAP "%s" L_LINE "%s%s (0x%08"PRIx32")\n", last ? L_GAP : L_LINE, fmt_last ? L_LAST : L_VAL, format_str(fmt), fmt); } print_properties(props_obj, last ? L_GAP L_GAP : L_GAP L_LINE); } } static void print_node(const char *path, struct json_object *obj) { printf("Node: %s\n", path); print_driver(json_object_object_get(obj, "driver")); print_device(json_object_object_get(obj, "device")); printf(L_VAL "Framebuffer size\n"); struct json_object *fb_size_obj = json_object_object_get(obj, "fb_size"); printf(L_LINE L_VAL "Width: [%"PRIu64", %"PRIu64"]\n", get_object_object_uint64(fb_size_obj, "min_width"), get_object_object_uint64(fb_size_obj, "max_width")); printf(L_LINE L_LAST "Height: [%"PRIu64", %"PRIu64"]\n", get_object_object_uint64(fb_size_obj, "min_height"), get_object_object_uint64(fb_size_obj, "max_height")); struct json_object *encs_arr = json_object_object_get(obj, "encoders"); print_connectors(json_object_object_get(obj, "connectors"), encs_arr); print_encoders(encs_arr); print_crtcs(json_object_object_get(obj, "crtcs")); print_planes(json_object_object_get(obj, "planes")); } void print_drm(struct json_object *obj) { json_object_object_foreach(obj, path, node_obj) { print_node(path, node_obj); } } drm_info-2.2.0/subprojects/000077500000000000000000000000001360676530100156625ustar00rootroot00000000000000drm_info-2.2.0/subprojects/json-c.wrap000066400000000000000000000007011360676530100177440ustar00rootroot00000000000000[wrap-file] directory = json-c-0.13.1 source_url = https://s3.amazonaws.com/json-c_releases/releases/json-c-0.13.1.tar.gz source_filename = json-c-0.13.1.tar.gz source_hash = b87e608d4d3f7bfdd36ef78d56d53c74e66ab278d318b71e6002a369d36f4873 patch_url = https://github.com/mesonbuild/json-c/releases/download/0.13.1-1/json-c.zip patch_filename = json-c-0.13.1-1-wrap.zip patch_hash = 213a735c3c5f7ff4aa38850cd7bf236337c47fd553b9fcded64e709cab66b9fd drm_info-2.2.0/subprojects/libdrm.wrap000066400000000000000000000001401360676530100200210ustar00rootroot00000000000000[wrap-git] url = https://gitlab.freedesktop.org/mesa/drm.git revision = libdrm-2.4.99 depth = 1 drm_info-2.2.0/tables.h000066400000000000000000000003361360676530100147440ustar00rootroot00000000000000#ifndef TABLES_H #define TABLES_H #include /* The implementation of these functions are generated by fourcc.py */ const char *format_str(uint32_t format); const char *modifier_str(uint64_t modifier); #endif