19042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz/**************************************************************************
29042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz *
39042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
49042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * All Rights Reserved.
59042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz *
69042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * Permission is hereby granted, free of charge, to any person obtaining a
79042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * copy of this software and associated documentation files (the
89042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * "Software"), to deal in the Software without restriction, including
99042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * without limitation the rights to use, copy, modify, merge, publish,
109042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * distribute, sub license, and/or sell copies of the Software, and to
119042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * permit persons to whom the Software is furnished to do so, subject to
129042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * the following conditions:
139042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz *
149042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * The above copyright notice and this permission notice (including the
159042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * next paragraph) shall be included in all copies or substantial portions
169042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * of the Software.
179042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz *
189042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
199042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
209042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
219042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
229042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
239042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
249042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * USE OR OTHER DEALINGS IN THE SOFTWARE.
259042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz *
269042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz **************************************************************************/
279042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz/*
289042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * Thanks to krh and jcristau for the tips on
299042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz * going from fd to pci id via fstat and udev.
309042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz */
319042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
329042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
338e93afc9765f1de613c65a76e9a86e17db96e653Emil Velikov#ifdef HAVE_CONFIG_H
34d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#include "config.h"
358e93afc9765f1de613c65a76e9a86e17db96e653Emil Velikov#endif
369042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz#include <errno.h>
379042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz#include <stdio.h>
38d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#include <stdlib.h>
399042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz#include <xf86drm.h>
40d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#include <string.h>
41d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#include <unistd.h>
42d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
439042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz#include <sys/stat.h>
449042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
459042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz#include "internal.h"
469042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
47d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#define PATH_SIZE 512
48d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
49d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzstatic int
50d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzlinux_name_from_sysfs(int fd, char **out)
51d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz{
52d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	char path[PATH_SIZE+1] = ""; /* initialize to please valgrind */
53d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	char link[PATH_SIZE+1] = "";
54d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	struct stat buffer;
55d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	unsigned maj, min;
56d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	char* slash_name;
57d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	int ret;
58d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
59d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	/*
60d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	 * Inside the sysfs directory for the device there is a symlink
61d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	 * to the directory representing the driver module, that path
62d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	 * happens to hold the name of the driver.
63d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	 *
64d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	 * So lets get the symlink for the drm device. Then read the link
65d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	 * and filter out the last directory which happens to be the name
66d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	 * of the driver, which we can use to load the correct interface.
67d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	 *
68d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	 * Thanks to Ray Strode of Plymouth for the code.
69d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	 */
70d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
71d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	ret = fstat(fd, &buffer);
72d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	if (ret)
73baf0a7daafc7636106e1b19267ed22e22b1a2283Maxime Villard		return -EINVAL;
74d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
75d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	if (!S_ISCHR(buffer.st_mode))
76d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz		return -EINVAL;
77d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
78d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	maj = major(buffer.st_rdev);
79d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	min = minor(buffer.st_rdev);
80d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
81d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	snprintf(path, PATH_SIZE, "/sys/dev/char/%d:%d/device/driver", maj, min);
82d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
83d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	if (readlink(path, link, PATH_SIZE) < 0)
84d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz		return -EINVAL;
85d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
86d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	/* link looks something like this: ../../../bus/pci/drivers/intel */
87d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	slash_name = strrchr(link, '/');
88d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	if (!slash_name)
89d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz		return -EINVAL;
90d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
91d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	/* copy name and at the same time remove the slash */
92d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	*out = strdup(slash_name + 1);
93d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	return 0;
94d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz}
95d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
96d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzstatic int
97d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzlinux_from_sysfs(int fd, struct kms_driver **out)
98d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz{
99d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	char *name;
100d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	int ret;
101d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
102d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	ret = linux_name_from_sysfs(fd, &name);
103d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	if (ret)
104d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz		return ret;
105d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
106f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov#ifdef HAVE_INTEL
107d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	if (!strcmp(name, "intel"))
108d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz		ret = intel_create(fd, out);
109f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov	else
110f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov#endif
111d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#ifdef HAVE_VMWGFX
112f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov	if (!strcmp(name, "vmwgfx"))
113d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz		ret = vmwgfx_create(fd, out);
114f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov	else
115d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#endif
116d5a2e776826f7a849f1cf654fde8611f687eb12cMarcin Kościelnicki#ifdef HAVE_NOUVEAU
117f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov	if (!strcmp(name, "nouveau"))
118d5a2e776826f7a849f1cf654fde8611f687eb12cMarcin Kościelnicki		ret = nouveau_create(fd, out);
119f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov	else
120d5a2e776826f7a849f1cf654fde8611f687eb12cMarcin Kościelnicki#endif
121ed7d177f66885dfbc4e8410154559c4767fefa9fnobled#ifdef HAVE_RADEON
122f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov	if (!strcmp(name, "radeon"))
123ed7d177f66885dfbc4e8410154559c4767fefa9fnobled		ret = radeon_create(fd, out);
124f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov	else
125ed7d177f66885dfbc4e8410154559c4767fefa9fnobled#endif
1263732ef59eb1198d6a4cb5b8bbca6b155c53529f6Hyungwon Hwang#ifdef HAVE_EXYNOS
127f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov	if (!strcmp(name, "exynos"))
1283732ef59eb1198d6a4cb5b8bbca6b155c53529f6Hyungwon Hwang		ret = exynos_create(fd, out);
129d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	else
130f3fd11beaa70b0624ab1d6c7d8e25c65eea942acEmil Velikov#endif
131d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz		ret = -ENOSYS;
132d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
133d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	free(name);
134d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	return ret;
135d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz}
136d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
137d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#if 0
1389042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
1399042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz#include <libudev.h>
1409042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
141d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzstruct create_record
142d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz{
143d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	unsigned vendor;
144d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	unsigned chip;
145d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	int (*func)(int fd, struct kms_driver **out);
146d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz};
147d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
148d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzstatic struct create_record table[] = {
149d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	{ 0x8086, 0x2a42, intel_create }, /* i965 */
150d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#ifdef HAVE_VMWGFX
151d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	{ 0x15ad, 0x0405, vmwgfx_create }, /* VMware vGPU */
152d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#endif
153d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	{ 0, 0, NULL },
154d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz};
155d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
156d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzstatic int
157d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzlinux_get_pciid_from_fd(int fd, unsigned *vendor_id, unsigned *chip_id)
1589042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz{
1599042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	struct udev *udev;
1609042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	struct udev_device *device;
1619042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	struct udev_device *parent;
1629042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	const char *pci_id;
1639042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	struct stat buffer;
1649042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	int ret;
1659042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
1669042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	ret = fstat(fd, &buffer);
1679042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	if (ret)
1689042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz		return -EINVAL;
1699042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
1709042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	if (!S_ISCHR(buffer.st_mode))
1719042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz		return -EINVAL;
1729042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
1739042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	udev = udev_new();
1749042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	if (!udev)
1759042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz		return -ENOMEM;
1769042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
1779042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	device = udev_device_new_from_devnum(udev, 'c', buffer.st_rdev);
1789042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	if (!device)
1799042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz		goto err_free_udev;
1809042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
1819042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	parent = udev_device_get_parent(device);
1829042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	if (!parent)
1839042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz		goto err_free_device;
1849042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
1859042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	pci_id = udev_device_get_property_value(parent, "PCI_ID");
1869042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	if (!pci_id)
1879042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz		goto err_free_device;
1889042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
1899042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	if (sscanf(pci_id, "%x:%x", vendor_id, chip_id) != 2)
1909042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz		goto err_free_device;
1919042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
1929042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	udev_device_unref(device);
1939042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	udev_unref(udev);
1949042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
1959042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	return 0;
1969042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz
1979042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantzerr_free_device:
1989042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	udev_device_unref(device);
1999042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantzerr_free_udev:
2009042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	udev_unref(udev);
2019042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz	return -EINVAL;
2029042d72109d8ae448b8e0f23b93067cc37deff23Jakob Bornecrantz}
203d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
204d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzstatic int
205d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzlinux_from_udev(int fd, struct kms_driver **out)
206d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz{
207d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	unsigned vendor_id, chip_id;
208d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	int ret, i;
209d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
210d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	ret = linux_get_pciid_from_fd(fd, &vendor_id, &chip_id);
211d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	if (ret)
212d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz		return ret;
213d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
214d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	for (i = 0; table[i].func; i++)
215d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz		if (table[i].vendor == vendor_id && table[i].chip == chip_id)
216d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz			return table[i].func(fd, out);
217d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
218d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	return -ENOSYS;
219d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz}
220d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#else
221d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzstatic int
222d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzlinux_from_udev(int fd, struct kms_driver **out)
223d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz{
224d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	return -ENOSYS;
225d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz}
226d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz#endif
227d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
228d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzint
229d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantzlinux_create(int fd, struct kms_driver **out)
230d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz{
231bb994653667986757b4c906b8f144737667f7374Dave Airlie	if (!dumb_create(fd, out))
232bb994653667986757b4c906b8f144737667f7374Dave Airlie		return 0;
233bb994653667986757b4c906b8f144737667f7374Dave Airlie
234d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	if (!linux_from_udev(fd, out))
235d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz		return 0;
236d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz
237d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz	return linux_from_sysfs(fd, out);
238d920fa9d0b54873d53f03a006d0fe3df11136b74Jakob Bornecrantz}
239