XFree86项目尽量避免去修改 DIX 软件的层面除非发现了重大的缺陷。
可参考Xserver-spec相关文档,其中关于DIX对于所有的X server实现都大体相同。
XFree86 DDX 层在 hw/xfree86 中
使之合理
• We cannot rewrite the complete server
• We don’t want to re-invent the wheel
使之模块化
• As many things as possible should go into modules
• The basic loader binary should be minimal
• A clean design with well defined layering is important
• DDX specific global variables are a nano
• The structure should be flexible enough to allow future extensions
• The structure should minimize duplication of common code
牢记并着重处理那些重要的特性。
• multiple screens, including multiple instances of drivers
• mixing different color depths and visuals on different and ideally even on the same screen
• better control of the PCI device used
• better config file parser
• get rid of all VGA compatibility assumptions
ScreenInit :在 server 初始化阶段, 由 DIX 层 为每一个显示屏 调用的初始化函数。
Enter VT : server 获得了 console 的控制权。
Leave VT : server 释放了对 console 的控制权。
Mode Switch :改变了显示器模式
ViewPort change : 改变物理观测点的位置
ScreenSaver state change : 屏保的 激活和停止
除了以上这些事件:XFree86 公共层还需要如下函数
Identify : 打印驱动的自身的信息
Probe : 驱动在这个函数里边用来探测是否有驱动可以使用的硬件
PreInit : 处理来自 xorg.conf 文件的信息,确定硬件的特性,确定是否有一个有效的配置存在。
VidMode 扩展 还需要:
确定一种显示模式是否在当前配置下可用。PreInit函数以及它调用的帮助函数可能也会使用 ValidMode或和其功能类似的函数去做验证。
其它的层需要其它的入口点。
Device 段 用于描述针对特定的单个显卡硬件相关的信息。
With systemd-logind now managing device node access, we also need a bunch of driver changes as many Xorg drivers used to directly open device nodes themselves.
Xorg 1.16 introduces server-managed fds, when:
$ lspci | grep -e VGA -e 3D
$ sudo Xorg :1 -configure
void xf86PlatformDeviceProbe(struct OdevAttributes *attribs)
{
int i;
char *path = attribs->path;
Bool ret;
if (!path)
goto out_free;
for (i = 0; i < xf86_num_platform_devices; i++)
{
char *dpath = xf86_platform_odev_attributes(i)->path;
if (dpath && !strcmp(path, dpath))
break;
}
if (i != xf86_num_platform_devices)
goto out_free;
LogMessage(X_INFO, "xfree86: Adding drm device (%s)\n", path);
if (!xf86VTOwner()) {
/* if we don't currently own the VT then don't probe the device,
just mark it as unowned for later use */
xf86_add_platform_device(attribs, TRUE);
return;
}
ret = get_drm_info(attribs, path, -1);
if (ret == FALSE)
goto out_free;
return;
out_free:
config_odev_free_attributes(attribs);
}
void config_odev_probe(config_odev_probe_proc_ptr probe_callback)
{
#if defined(CONFIG_UDEV_KMS)
config_udev_odev_probe(probe_callback);
#endif
}
int xf86platformProbe(void)
{
int i;
Bool pci = TRUE;
XF86ConfOutputClassPtr cl, cl_head = (xf86configptr) ?
xf86configptr->conf_outputclass_lst : NULL;
char *old_path, *path = NULL;
config_odev_probe(xf86PlatformDeviceProbe);
if (!xf86scanpci()) {
pci = FALSE;
}
for (i = 0; i < xf86_num_platform_devices; i++)
{
char *busid = xf86_platform_odev_attributes(i)->busid;
if (pci && (strncmp(busid, "pci:", 4) == 0))
{
platform_find_pci_info(&xf86_platform_devices[i], busid);
}
/*
* Deal with OutputClass ModulePath directives, these must be
* processed before we do any module loading.
*/
for (cl = cl_head; cl; cl = cl->list.next)
{
if (!OutputClassMatches(cl, &xf86_platform_devices[i]))
continue;
if (cl->modulepath && xf86ModPathFrom != X_CMDLINE)
{
old_path = path;
XNFasprintf(&path, "%s,%s", cl->modulepath, path ? path : xf86ModulePath);
free(old_path);
xf86Msg(X_CONFIG, "OutputClass \"%s\" ModulePath extended to \"%s\"\n", cl->identifier, path);
LoaderSetPath(path);
}
}
}
free(path);
/* First see if there is an OutputClass match marking a device as primary */
for (i = 0; i < xf86_num_platform_devices; i++) {
struct xf86_platform_device *dev = &xf86_platform_devices[i];
for (cl = cl_head; cl; cl = cl->list.next) {
if (!OutputClassMatches(cl, dev))
continue;
if (xf86CheckBoolOption(cl->option_lst, "PrimaryGPU", FALSE)) {
xf86Msg(X_CONFIG, "OutputClass \"%s\" setting %s as PrimaryGPU\n",
cl->identifier, dev->attribs->path);
primaryBus.type = BUS_PLATFORM;
primaryBus.id.plat = dev;
return 0;
}
}
}
/* Then check for pci_device_is_boot_vga() */
for (i = 0; i < xf86_num_platform_devices; i++) {
struct xf86_platform_device *dev = &xf86_platform_devices[i];
if (!dev->pdev)
continue;
pci_device_probe(dev->pdev);
if (pci_device_is_boot_vga(dev->pdev)) {
primaryBus.type = BUS_PLATFORM;
primaryBus.id.plat = dev;
}
}
return 0;
}
void config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)
{
struct udev *udev;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *device;
udev = udev_monitor_get_udev(udev_monitor);
enumerate = udev_enumerate_new(udev);
if (!enumerate)
return;
udev_enumerate_add_match_subsystem(enumerate, "drm");
udev_enumerate_add_match_sysname(enumerate, "card[0-9]*");
#ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
if (ServerIsNotSeat0())
udev_enumerate_add_match_tag(enumerate, SeatId);
#endif
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(device, devices) {
const char *syspath = udev_list_entry_get_name(device);
struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath);
const char *path = udev_device_get_devnode(udev_device);
const char *sysname = udev_device_get_sysname(udev_device);
dev_t devnum = udev_device_get_devnum(udev_device);
if (!path || !syspath)
goto no_probe;
else if (strcmp(udev_device_get_subsystem(udev_device), "drm") != 0)
goto no_probe;
else if (strncmp(sysname, "card", 4) != 0)
goto no_probe;
else if (!check_seat(udev_device))
goto no_probe;
config_udev_odev_setup_attribs(path, syspath, major(devnum),
minor(devnum), probe_callback);
no_probe:
udev_device_unref(udev_device);
}
udev_enumerate_unref(enumerate);
return;
}
struct OdevAttributes {
/* path to kernel device node - Linux e.g. /dev/dri/card0 */
char *path;
/* system device path - Linux e.g. /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/drm/card1 */
char *syspath;
/* DRI-style bus id */
char *busid;
/* Server managed FD */
int fd;
/* Major number of the device node pointed to by ODEV_ATTRIB_PATH */
int major;
/* Minor number of the device node pointed to by ODEV_ATTRIB_PATH */
int minor;
/* kernel driver name */
char *driver;
};
struct OdevAttributes * config_odev_allocate_attributes(void)
{
struct OdevAttributes *attribs = xnfcalloc(1, sizeof (struct OdevAttributes));
attribs->fd = -1;
return attribs;
}
static void config_udev_odev_setup_attribs(const char *path, const char *syspath,
int major, int minor, config_odev_probe_proc_ptr probe_callback)
{
struct OdevAttributes *attribs = config_odev_allocate_attributes();
attribs->path = XNFstrdup(path);
attribs->syspath = XNFstrdup(syspath);
attribs->major = major;
attribs->minor = minor;
/* ownership of attribs is passed to probe layer */
probe_callback(attribs);
}