lnx_platform.c 5.02 KB
Newer Older
1 2 3 4 5 6 7 8 9
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif

#ifdef XSERVER_PLATFORM_BUS

#include <xf86drm.h>
#include <fcntl.h>
#include <unistd.h>
10 11
#include <errno.h>
#include <string.h>
12 13 14 15 16 17 18 19

/* Linux platform device support */
#include "xf86_OSproc.h"

#include "xf86.h"
#include "xf86platformBus.h"
#include "xf86Bus.h"

20
#include "hotplug.h"
21
#include "systemd-logind.h"
22

23
static Bool
24
get_drm_info(struct OdevAttributes *attribs, char *path, int delayed_index)
25
{
26
    drmVersionPtr v;
27
    int fd;
28
    int err = 0;
29 30
    Bool paused, server_fd = FALSE;

31 32
    LogMessage(X_INFO, "Platform probe for %s\n", attribs->syspath);

33
    fd = systemd_logind_take_fd(attribs->major, attribs->minor, path, &paused);
34 35 36 37
    if (fd != -1) {
        if (paused) {
            LogMessage(X_ERROR,
                    "Error systemd-logind returned paused fd for drm node\n");
38
            systemd_logind_release_fd(attribs->major, attribs->minor, -1);
39 40
            return FALSE;
        }
41
        attribs->fd = fd;
42 43 44 45
        server_fd = TRUE;
    }

    if (fd == -1)
46
        fd = open(path, O_RDWR | O_CLOEXEC, 0);
47 48 49 50

    if (fd == -1)
        return FALSE;

51 52
    /* for a delayed probe we've already added the device */
    if (delayed_index == -1) {
53
            xf86_add_platform_device(attribs, FALSE);
54 55
            delayed_index = xf86_num_platform_devices - 1;
    }
56

57 58 59
    if (server_fd)
        xf86_platform_devices[delayed_index].flags |= XF86_PDEV_SERVER_FD;

60 61 62 63 64 65
    v = drmGetVersion(fd);
    if (!v) {
        xf86Msg(X_ERROR, "%s: failed to query DRM version\n", path);
        goto out;
    }

66
    xf86_platform_odev_attributes(delayed_index)->driver = XNFstrdup(v->name);
67 68
    drmFreeVersion(v);

69
out:
70 71
    if (!server_fd)
        close(fd);
72
    return (err == 0);
73 74 75 76 77
}

Bool
xf86PlatformDeviceCheckBusID(struct xf86_platform_device *device, const char *busid)
{
78
    const char *syspath = device->attribs->syspath;
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
    BusType bustype;
    const char *id;

    if (!syspath)
        return FALSE;

    bustype = StringToBusType(busid, &id);
    if (bustype == BUS_PCI) {
        struct pci_device *pPci = device->pdev;
        if (xf86ComparePciBusString(busid,
                                    ((pPci->domain << 8)
                                     | pPci->bus),
                                    pPci->dev, pPci->func)) {
            return TRUE;
        }
    }
    else if (bustype == BUS_PLATFORM) {
        /* match on the minimum string */
        int len = strlen(id);

        if (strlen(syspath) < strlen(id))
            len = strlen(syspath);

        if (strncmp(id, syspath, len))
            return FALSE;
        return TRUE;
    }
    return FALSE;
}

109 110 111 112
void
xf86PlatformReprobeDevice(int index, struct OdevAttributes *attribs)
{
    Bool ret;
113
    char *dpath = attribs->path;
114 115 116 117 118 119 120 121 122 123 124

    ret = get_drm_info(attribs, dpath, index);
    if (ret == FALSE) {
        xf86_remove_platform_device(index);
        return;
    }
    ret = xf86platformAddDevice(index);
    if (ret == -1)
        xf86_remove_platform_device(index);
}

125 126 127 128
void
xf86PlatformDeviceProbe(struct OdevAttributes *attribs)
{
    int i;
129
    char *path = attribs->path;
130 131 132 133 134 135
    Bool ret;

    if (!path)
        goto out_free;

    for (i = 0; i < xf86_num_platform_devices; i++) {
136
        char *dpath = xf86_platform_odev_attributes(i)->path;
137

138
        if (dpath && !strcmp(path, dpath))
139 140 141 142 143 144
            break;
    }

    if (i != xf86_num_platform_devices)
        goto out_free;

Peter Hutterer's avatar
Peter Hutterer committed
145
    LogMessage(X_INFO, "xfree86: Adding drm device (%s)\n", path);
146

147 148 149
    if (!xf86VTOwner()) {
            /* if we don't currently own the VT then don't probe the device,
               just mark it as unowned for later use */
150
            xf86_add_platform_device(attribs, TRUE);
151 152 153 154
            return;
    }

    ret = get_drm_info(attribs, path, -1);
155 156 157 158 159 160
    if (ret == FALSE)
        goto out_free;

    return;

out_free:
161
    config_odev_free_attributes(attribs);
162 163
}

164 165 166 167 168 169 170 171 172
void NewGPUDeviceRequest(struct OdevAttributes *attribs)
{
    int old_num = xf86_num_platform_devices;
    int ret;
    xf86PlatformDeviceProbe(attribs);

    if (old_num == xf86_num_platform_devices)
        return;

173 174 175
    if (xf86_get_platform_device_unowned(xf86_num_platform_devices - 1) == TRUE)
        return;

176 177 178 179 180 181 182 183 184 185 186
    ret = xf86platformAddDevice(xf86_num_platform_devices-1);
    if (ret == -1)
        xf86_remove_platform_device(xf86_num_platform_devices-1);

    ErrorF("xf86: found device %d\n", xf86_num_platform_devices);
    return;
}

void DeleteGPUDeviceRequest(struct OdevAttributes *attribs)
{
    int index;
187
    char *syspath = attribs->syspath;
188

189 190
    if (!syspath)
        goto out;
191 192

    for (index = 0; index < xf86_num_platform_devices; index++) {
193 194
        char *dspath = xf86_platform_odev_attributes(index)->syspath;
        if (dspath && !strcmp(syspath, dspath))
195 196 197 198 199 200 201 202
            break;
    }

    if (index == xf86_num_platform_devices)
        goto out;

    ErrorF("xf86: remove device %d %s\n", index, syspath);

203 204 205 206
    if (xf86_get_platform_device_unowned(index) == TRUE)
            xf86_remove_platform_device(index);
    else
            xf86platformRemoveDevice(index);
207
out:
208
    config_odev_free_attributes(attribs);
209 210
}

211
#endif