C++程序  |  131行  |  3.35 KB

/*
 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
 * All Rights Reserved.
 *
 * 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 (including the next
 * paragraph) 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
 * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
 */

#pragma once

#include_next <xf86drm.h>

#include <string.h>
#include <errno.h>

/*
 * FIXME: Below code comes from https://patchwork.kernel.org/patch/10368203/
 * FIXME: Remove or rework once that has been merged
 */

typedef enum drm_match_key {
	/* Match against DRM_NODE_{PRIMARY,RENDER,...} type */
	DRM_MATCH_NODE_TYPE = 1,
	DRM_MATCH_DRIVER_NAME = 2,
	DRM_MATCH_BUS_PCI_VENDOR = 3,
	DRM_MATCH_FUNCTION = 4,
} drm_match_key_t;

typedef struct drm_match_func {
	void *data;
	int (*fp)(int, void*); /* Intended arguments are fp(fd, data) */
} drm_match_func_t;

typedef struct drm_match {
	drm_match_key_t type;
	union {
		int s;
		uint16_t u16;
		char *str;
		drm_match_func_t func;
	};
} drm_match_t;

static inline int drmHandleMatch(int fd, drm_match_t *filters, int nbr_filters)
{
	if (fd < 0)
		goto error;

	if (nbr_filters > 0 && filters == NULL)
		goto error;

	drmVersionPtr ver = drmGetVersion(fd);
	if (!ver)
		goto fail;

	drmDevicePtr dev = NULL;
	if (drmGetDevice2(fd, 0, &dev) != 0) {
		goto fail;
	}

	for (int i = 0; i < nbr_filters; i++) {
		drm_match_t *f = &filters[i];
		switch (f->type) {
		case DRM_MATCH_NODE_TYPE:
			if (!(dev->available_nodes & (1 << f->s)))
				goto fail;
			break;
		case DRM_MATCH_DRIVER_NAME:
			if (!f->str)
				goto error;

			/* This bypass is used by when the driver name is used
			   by the Android property_get() func, when it hasn't found
			   the property and the string is empty as a result. */
			if (strlen(f->str) == 0)
				continue;

			if (strncmp(ver->name, f->str, strlen(ver->name)))
				goto fail;
			break;
		case DRM_MATCH_BUS_PCI_VENDOR:
			if (dev->bustype != DRM_BUS_PCI)
				goto fail;
			if (dev->deviceinfo.pci->vendor_id != f->u16)
				goto fail;
			break;
		case DRM_MATCH_FUNCTION:
			if (!f->func.fp)
				goto error;
			int (*fp)(int, void*) = f->func.fp;
			void *data = f->func.data;
			if (!fp(fd, data))
				goto fail;
			break;
		default:
			goto error;
		}
	}

success:
	drmFreeVersion(ver);
	drmFreeDevice(&dev);
	return 0;
error:
	drmFreeVersion(ver);
	drmFreeDevice(&dev);
	return -EINVAL;
fail:
	drmFreeVersion(ver);
	drmFreeDevice(&dev);
	return 1;
}