X server

An Introduction to X ServerAn Introduction to X Server

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或和其功能类似的函数去做验证。

其它的层需要其它的入口点。

Xorg.conf

Device 段 用于描述针对特定的单个显卡硬件相关的信息。

Driver changes

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:

  1. the X server is compiled with systemd-logind support; and
  2. systemd-logind is available; and the driver used supports server-managed fds

Identify your card

$ lspci | grep -e VGA -e 3D

list available driver¶

$ sudo Xorg :1 -configure

Probe

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;
}

config_udev_odev_probe

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);
}

The End

你可能感兴趣的:(linux)