135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2012 Red Hat.
335c4bbdfSmrg *
435c4bbdfSmrg * Permission is hereby granted, free of charge, to any person obtaining a
535c4bbdfSmrg * copy of this software and associated documentation files (the "Software"),
635c4bbdfSmrg * to deal in the Software without restriction, including without limitation
735c4bbdfSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
835c4bbdfSmrg * and/or sell copies of the Software, and to permit persons to whom the
935c4bbdfSmrg * Software is furnished to do so, subject to the following conditions:
1035c4bbdfSmrg *
1135c4bbdfSmrg * The above copyright notice and this permission notice shall be included in
1235c4bbdfSmrg * all copies or substantial portions of the Software.
1335c4bbdfSmrg *
1435c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1535c4bbdfSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1635c4bbdfSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1735c4bbdfSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1835c4bbdfSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1935c4bbdfSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2035c4bbdfSmrg * DEALINGS IN THE SOFTWARE.
2135c4bbdfSmrg *
2235c4bbdfSmrg * Author: Dave Airlie <airlied@redhat.com>
2335c4bbdfSmrg */
2435c4bbdfSmrg
2535c4bbdfSmrg/*
2635c4bbdfSmrg * This file contains the interfaces to the bus-specific code
2735c4bbdfSmrg */
2835c4bbdfSmrg
2935c4bbdfSmrg#ifdef HAVE_XORG_CONFIG_H
3035c4bbdfSmrg#include <xorg-config.h>
3135c4bbdfSmrg#endif
3235c4bbdfSmrg
3335c4bbdfSmrg#ifdef XSERVER_PLATFORM_BUS
3435c4bbdfSmrg#include <errno.h>
3535c4bbdfSmrg
3635c4bbdfSmrg#include <pciaccess.h>
3735c4bbdfSmrg#include <fcntl.h>
3835c4bbdfSmrg#include <unistd.h>
3935c4bbdfSmrg#include "os.h"
4035c4bbdfSmrg#include "hotplug.h"
4135c4bbdfSmrg#include "systemd-logind.h"
4235c4bbdfSmrg
431b5d61b8Smrg#include "loaderProcs.h"
4435c4bbdfSmrg#include "xf86.h"
4535c4bbdfSmrg#include "xf86_OSproc.h"
4635c4bbdfSmrg#include "xf86Priv.h"
4735c4bbdfSmrg#include "xf86str.h"
4835c4bbdfSmrg#include "xf86Bus.h"
4935c4bbdfSmrg#include "Pci.h"
5035c4bbdfSmrg#include "xf86platformBus.h"
5135c4bbdfSmrg#include "xf86Config.h"
52ed6184dfSmrg#include "xf86Crtc.h"
5335c4bbdfSmrg
5435c4bbdfSmrg#include "randrstr.h"
5535c4bbdfSmrgint platformSlotClaimed;
5635c4bbdfSmrg
5735c4bbdfSmrgint xf86_num_platform_devices;
5835c4bbdfSmrg
5935c4bbdfSmrgstruct xf86_platform_device *xf86_platform_devices;
6035c4bbdfSmrg
6135c4bbdfSmrgint
6235c4bbdfSmrgxf86_add_platform_device(struct OdevAttributes *attribs, Bool unowned)
6335c4bbdfSmrg{
6435c4bbdfSmrg    xf86_platform_devices = xnfreallocarray(xf86_platform_devices,
6535c4bbdfSmrg                                            xf86_num_platform_devices + 1,
6635c4bbdfSmrg                                            sizeof(struct xf86_platform_device));
6735c4bbdfSmrg
6835c4bbdfSmrg    xf86_platform_devices[xf86_num_platform_devices].attribs = attribs;
6935c4bbdfSmrg    xf86_platform_devices[xf86_num_platform_devices].pdev = NULL;
7035c4bbdfSmrg    xf86_platform_devices[xf86_num_platform_devices].flags =
7135c4bbdfSmrg        unowned ? XF86_PDEV_UNOWNED : 0;
7235c4bbdfSmrg
7335c4bbdfSmrg    xf86_num_platform_devices++;
7435c4bbdfSmrg    return 0;
7535c4bbdfSmrg}
7635c4bbdfSmrg
7735c4bbdfSmrgint
7835c4bbdfSmrgxf86_remove_platform_device(int dev_index)
7935c4bbdfSmrg{
8035c4bbdfSmrg    int j;
8135c4bbdfSmrg
8235c4bbdfSmrg    config_odev_free_attributes(xf86_platform_devices[dev_index].attribs);
8335c4bbdfSmrg
8435c4bbdfSmrg    for (j = dev_index; j < xf86_num_platform_devices - 1; j++)
8535c4bbdfSmrg        memcpy(&xf86_platform_devices[j], &xf86_platform_devices[j + 1], sizeof(struct xf86_platform_device));
8635c4bbdfSmrg    xf86_num_platform_devices--;
8735c4bbdfSmrg    return 0;
8835c4bbdfSmrg}
8935c4bbdfSmrg
9035c4bbdfSmrgBool
9135c4bbdfSmrgxf86_get_platform_device_unowned(int index)
9235c4bbdfSmrg{
9335c4bbdfSmrg    return (xf86_platform_devices[index].flags & XF86_PDEV_UNOWNED) ?
9435c4bbdfSmrg        TRUE : FALSE;
9535c4bbdfSmrg}
9635c4bbdfSmrg
9735c4bbdfSmrgstruct xf86_platform_device *
9835c4bbdfSmrgxf86_find_platform_device_by_devnum(int major, int minor)
9935c4bbdfSmrg{
10035c4bbdfSmrg    int i, attr_major, attr_minor;
10135c4bbdfSmrg
10235c4bbdfSmrg    for (i = 0; i < xf86_num_platform_devices; i++) {
10335c4bbdfSmrg        attr_major = xf86_platform_odev_attributes(i)->major;
10435c4bbdfSmrg        attr_minor = xf86_platform_odev_attributes(i)->minor;
10535c4bbdfSmrg        if (attr_major == major && attr_minor == minor)
10635c4bbdfSmrg            return &xf86_platform_devices[i];
10735c4bbdfSmrg    }
10835c4bbdfSmrg    return NULL;
10935c4bbdfSmrg}
11035c4bbdfSmrg
11135c4bbdfSmrg/*
11235c4bbdfSmrg * xf86IsPrimaryPlatform() -- return TRUE if primary device
11335c4bbdfSmrg * is a platform device and it matches this one.
11435c4bbdfSmrg */
11535c4bbdfSmrg
11635c4bbdfSmrgstatic Bool
11735c4bbdfSmrgxf86IsPrimaryPlatform(struct xf86_platform_device *plat)
11835c4bbdfSmrg{
1191b5d61b8Smrg    /* Add max. 1 screen for the IgnorePrimary fallback path */
1201b5d61b8Smrg    if (xf86ProbeIgnorePrimary && xf86NumScreens == 0)
1211b5d61b8Smrg        return TRUE;
1221b5d61b8Smrg
1231b5d61b8Smrg    if (primaryBus.type == BUS_PLATFORM)
1241b5d61b8Smrg        return plat == primaryBus.id.plat;
1251b5d61b8Smrg#ifdef XSERVER_LIBPCIACCESS
1261b5d61b8Smrg    if (primaryBus.type == BUS_PCI)
1271b5d61b8Smrg        if (plat->pdev)
1281b5d61b8Smrg            if (MATCH_PCI_DEVICES(primaryBus.id.pci, plat->pdev))
1291b5d61b8Smrg                return TRUE;
1301b5d61b8Smrg#endif
1311b5d61b8Smrg    return FALSE;
13235c4bbdfSmrg}
13335c4bbdfSmrg
13435c4bbdfSmrgstatic void
13535c4bbdfSmrgplatform_find_pci_info(struct xf86_platform_device *pd, char *busid)
13635c4bbdfSmrg{
13735c4bbdfSmrg    struct pci_slot_match devmatch;
13835c4bbdfSmrg    struct pci_device *info;
13935c4bbdfSmrg    struct pci_device_iterator *iter;
14035c4bbdfSmrg    int ret;
14135c4bbdfSmrg
14235c4bbdfSmrg    ret = sscanf(busid, "pci:%04x:%02x:%02x.%u",
14335c4bbdfSmrg                 &devmatch.domain, &devmatch.bus, &devmatch.dev,
14435c4bbdfSmrg                 &devmatch.func);
14535c4bbdfSmrg    if (ret != 4)
14635c4bbdfSmrg        return;
14735c4bbdfSmrg
14835c4bbdfSmrg    iter = pci_slot_match_iterator_create(&devmatch);
14935c4bbdfSmrg    info = pci_device_next(iter);
1501b5d61b8Smrg    if (info)
15135c4bbdfSmrg        pd->pdev = info;
15235c4bbdfSmrg    pci_iterator_destroy(iter);
15335c4bbdfSmrg}
15435c4bbdfSmrg
15535c4bbdfSmrgstatic Bool
15635c4bbdfSmrgxf86_check_platform_slot(const struct xf86_platform_device *pd)
15735c4bbdfSmrg{
15835c4bbdfSmrg    int i;
15935c4bbdfSmrg
16035c4bbdfSmrg    for (i = 0; i < xf86NumEntities; i++) {
16135c4bbdfSmrg        const EntityPtr u = xf86Entities[i];
16235c4bbdfSmrg
16335c4bbdfSmrg        if (pd->pdev && u->bus.type == BUS_PCI &&
16435c4bbdfSmrg            MATCH_PCI_DEVICES(pd->pdev, u->bus.id.pci)) {
16535c4bbdfSmrg            return FALSE;
16635c4bbdfSmrg        }
16735c4bbdfSmrg        if ((u->bus.type == BUS_PLATFORM) && (pd == u->bus.id.plat)) {
16835c4bbdfSmrg            return FALSE;
16935c4bbdfSmrg        }
17035c4bbdfSmrg    }
17135c4bbdfSmrg    return TRUE;
17235c4bbdfSmrg}
17335c4bbdfSmrg
17435c4bbdfSmrgstatic Bool
17535c4bbdfSmrgMatchToken(const char *value, struct xorg_list *patterns,
17635c4bbdfSmrg           int (*compare)(const char *, const char *))
17735c4bbdfSmrg{
17835c4bbdfSmrg    const xf86MatchGroup *group;
17935c4bbdfSmrg
18035c4bbdfSmrg    /* If there are no patterns, accept the match */
18135c4bbdfSmrg    if (xorg_list_is_empty(patterns))
18235c4bbdfSmrg        return TRUE;
18335c4bbdfSmrg
18435c4bbdfSmrg    /* If there are patterns but no attribute, reject the match */
18535c4bbdfSmrg    if (!value)
18635c4bbdfSmrg        return FALSE;
18735c4bbdfSmrg
18835c4bbdfSmrg    /*
18935c4bbdfSmrg     * Otherwise, iterate the list of patterns ensuring each entry has a
19035c4bbdfSmrg     * match. Each list entry is a separate Match line of the same type.
19135c4bbdfSmrg     */
19235c4bbdfSmrg    xorg_list_for_each_entry(group, patterns, entry) {
19335c4bbdfSmrg        Bool match = FALSE;
19435c4bbdfSmrg        char *const *cur;
19535c4bbdfSmrg
19635c4bbdfSmrg        for (cur = group->values; *cur; cur++) {
19735c4bbdfSmrg            if ((*compare)(value, *cur) == 0) {
19835c4bbdfSmrg                match = TRUE;
19935c4bbdfSmrg                break;
20035c4bbdfSmrg            }
20135c4bbdfSmrg        }
20235c4bbdfSmrg
20335c4bbdfSmrg        if (!match)
20435c4bbdfSmrg            return FALSE;
20535c4bbdfSmrg    }
20635c4bbdfSmrg
20735c4bbdfSmrg    /* All the entries in the list matched the attribute */
20835c4bbdfSmrg    return TRUE;
20935c4bbdfSmrg}
21035c4bbdfSmrg
21135c4bbdfSmrgstatic Bool
2121b5d61b8SmrgOutputClassMatches(const XF86ConfOutputClassPtr oclass,
2131b5d61b8Smrg                   struct xf86_platform_device *dev)
21435c4bbdfSmrg{
2151b5d61b8Smrg    char *driver = dev->attribs->driver;
21635c4bbdfSmrg
21735c4bbdfSmrg    if (!MatchToken(driver, &oclass->match_driver, strcmp))
21835c4bbdfSmrg        return FALSE;
21935c4bbdfSmrg
22035c4bbdfSmrg    return TRUE;
22135c4bbdfSmrg}
22235c4bbdfSmrg
2231b5d61b8Smrgstatic void
2241b5d61b8Smrgxf86OutputClassDriverList(int index, XF86MatchedDrivers *md)
22535c4bbdfSmrg{
22635c4bbdfSmrg    XF86ConfOutputClassPtr cl;
22735c4bbdfSmrg
22835c4bbdfSmrg    for (cl = xf86configptr->conf_outputclass_lst; cl; cl = cl->list.next) {
2291b5d61b8Smrg        if (OutputClassMatches(cl, &xf86_platform_devices[index])) {
23035c4bbdfSmrg            char *path = xf86_platform_odev_attributes(index)->path;
23135c4bbdfSmrg
23235c4bbdfSmrg            xf86Msg(X_INFO, "Applying OutputClass \"%s\" to %s\n",
23335c4bbdfSmrg                    cl->identifier, path);
23435c4bbdfSmrg            xf86Msg(X_NONE, "\tloading driver: %s\n", cl->driver);
23535c4bbdfSmrg
2361b5d61b8Smrg            xf86AddMatchedDriver(md, cl->driver);
23735c4bbdfSmrg        }
23835c4bbdfSmrg    }
23935c4bbdfSmrg}
24035c4bbdfSmrg
24135c4bbdfSmrg/**
24235c4bbdfSmrg *  @return The numbers of found devices that match with the current system
24335c4bbdfSmrg *  drivers.
24435c4bbdfSmrg */
2451b5d61b8Smrgvoid
2461b5d61b8Smrgxf86PlatformMatchDriver(XF86MatchedDrivers *md)
24735c4bbdfSmrg{
2481b5d61b8Smrg    int i;
24935c4bbdfSmrg    struct pci_device *info = NULL;
25035c4bbdfSmrg    int pass = 0;
25135c4bbdfSmrg
25235c4bbdfSmrg    for (pass = 0; pass < 2; pass++) {
25335c4bbdfSmrg        for (i = 0; i < xf86_num_platform_devices; i++) {
25435c4bbdfSmrg
25535c4bbdfSmrg            if (xf86IsPrimaryPlatform(&xf86_platform_devices[i]) && (pass == 1))
25635c4bbdfSmrg                continue;
25735c4bbdfSmrg            else if (!xf86IsPrimaryPlatform(&xf86_platform_devices[i]) && (pass == 0))
25835c4bbdfSmrg                continue;
25935c4bbdfSmrg
2601b5d61b8Smrg            xf86OutputClassDriverList(i, md);
26135c4bbdfSmrg
26235c4bbdfSmrg            info = xf86_platform_devices[i].pdev;
26335c4bbdfSmrg#ifdef __linux__
26435c4bbdfSmrg            if (info)
2651b5d61b8Smrg                xf86MatchDriverFromFiles(info->vendor_id, info->device_id, md);
26635c4bbdfSmrg#endif
26735c4bbdfSmrg
2681b5d61b8Smrg            if (info != NULL) {
2691b5d61b8Smrg                xf86VideoPtrToDriverList(info, md);
27035c4bbdfSmrg            }
27135c4bbdfSmrg        }
27235c4bbdfSmrg    }
27335c4bbdfSmrg}
27435c4bbdfSmrg
27535c4bbdfSmrgint
27635c4bbdfSmrgxf86platformProbe(void)
27735c4bbdfSmrg{
27835c4bbdfSmrg    int i;
27935c4bbdfSmrg    Bool pci = TRUE;
2801b5d61b8Smrg    XF86ConfOutputClassPtr cl, cl_head = (xf86configptr) ?
2811b5d61b8Smrg            xf86configptr->conf_outputclass_lst : NULL;
2821b5d61b8Smrg    char *old_path, *path = NULL;
28335c4bbdfSmrg
28435c4bbdfSmrg    config_odev_probe(xf86PlatformDeviceProbe);
28535c4bbdfSmrg
28635c4bbdfSmrg    if (!xf86scanpci()) {
28735c4bbdfSmrg        pci = FALSE;
28835c4bbdfSmrg    }
28935c4bbdfSmrg
29035c4bbdfSmrg    for (i = 0; i < xf86_num_platform_devices; i++) {
29135c4bbdfSmrg        char *busid = xf86_platform_odev_attributes(i)->busid;
29235c4bbdfSmrg
293ed6184dfSmrg        if (pci && busid && (strncmp(busid, "pci:", 4) == 0)) {
29435c4bbdfSmrg            platform_find_pci_info(&xf86_platform_devices[i], busid);
29535c4bbdfSmrg        }
2961b5d61b8Smrg
2971b5d61b8Smrg        /*
2981b5d61b8Smrg         * Deal with OutputClass ModulePath directives, these must be
2991b5d61b8Smrg         * processed before we do any module loading.
3001b5d61b8Smrg         */
3011b5d61b8Smrg        for (cl = cl_head; cl; cl = cl->list.next) {
3021b5d61b8Smrg            if (!OutputClassMatches(cl, &xf86_platform_devices[i]))
3031b5d61b8Smrg                continue;
3041b5d61b8Smrg
3051b5d61b8Smrg            if (cl->modulepath && xf86ModPathFrom != X_CMDLINE) {
3061b5d61b8Smrg                old_path = path;
3071b5d61b8Smrg                XNFasprintf(&path, "%s,%s", cl->modulepath,
3081b5d61b8Smrg                            path ? path : xf86ModulePath);
3091b5d61b8Smrg                free(old_path);
3101b5d61b8Smrg                xf86Msg(X_CONFIG, "OutputClass \"%s\" ModulePath extended to \"%s\"\n",
3111b5d61b8Smrg                        cl->identifier, path);
3121b5d61b8Smrg                LoaderSetPath(path);
3131b5d61b8Smrg            }
3141b5d61b8Smrg        }
31535c4bbdfSmrg    }
3161b5d61b8Smrg
3171b5d61b8Smrg    free(path);
3181b5d61b8Smrg
3191b5d61b8Smrg    /* First see if there is an OutputClass match marking a device as primary */
3201b5d61b8Smrg    for (i = 0; i < xf86_num_platform_devices; i++) {
3211b5d61b8Smrg        struct xf86_platform_device *dev = &xf86_platform_devices[i];
3221b5d61b8Smrg        for (cl = cl_head; cl; cl = cl->list.next) {
3231b5d61b8Smrg            if (!OutputClassMatches(cl, dev))
3241b5d61b8Smrg                continue;
3251b5d61b8Smrg
3261b5d61b8Smrg            if (xf86CheckBoolOption(cl->option_lst, "PrimaryGPU", FALSE)) {
3271b5d61b8Smrg                xf86Msg(X_CONFIG, "OutputClass \"%s\" setting %s as PrimaryGPU\n",
3281b5d61b8Smrg                        cl->identifier, dev->attribs->path);
3291b5d61b8Smrg                primaryBus.type = BUS_PLATFORM;
3301b5d61b8Smrg                primaryBus.id.plat = dev;
3311b5d61b8Smrg                return 0;
3321b5d61b8Smrg            }
3331b5d61b8Smrg        }
3341b5d61b8Smrg    }
3351b5d61b8Smrg
3361b5d61b8Smrg    /* Then check for pci_device_is_boot_vga() */
3371b5d61b8Smrg    for (i = 0; i < xf86_num_platform_devices; i++) {
3381b5d61b8Smrg        struct xf86_platform_device *dev = &xf86_platform_devices[i];
3391b5d61b8Smrg
3401b5d61b8Smrg        if (!dev->pdev)
3411b5d61b8Smrg            continue;
3421b5d61b8Smrg
3431b5d61b8Smrg        pci_device_probe(dev->pdev);
3441b5d61b8Smrg        if (pci_device_is_boot_vga(dev->pdev)) {
3451b5d61b8Smrg            primaryBus.type = BUS_PLATFORM;
3461b5d61b8Smrg            primaryBus.id.plat = dev;
3471b5d61b8Smrg        }
3481b5d61b8Smrg    }
3491b5d61b8Smrg
35035c4bbdfSmrg    return 0;
35135c4bbdfSmrg}
35235c4bbdfSmrg
3531b5d61b8Smrgvoid
3541b5d61b8Smrgxf86MergeOutputClassOptions(int entityIndex, void **options)
3551b5d61b8Smrg{
3561b5d61b8Smrg    const EntityPtr entity = xf86Entities[entityIndex];
3571b5d61b8Smrg    struct xf86_platform_device *dev = NULL;
3581b5d61b8Smrg    XF86ConfOutputClassPtr cl;
3591b5d61b8Smrg    XF86OptionPtr classopts;
3601b5d61b8Smrg    int i = 0;
3611b5d61b8Smrg
3621b5d61b8Smrg    switch (entity->bus.type) {
3631b5d61b8Smrg    case BUS_PLATFORM:
3641b5d61b8Smrg        dev = entity->bus.id.plat;
3651b5d61b8Smrg        break;
3661b5d61b8Smrg    case BUS_PCI:
3671b5d61b8Smrg        for (i = 0; i < xf86_num_platform_devices; i++) {
368ed6184dfSmrg            if (xf86_platform_devices[i].pdev) {
369ed6184dfSmrg                if (MATCH_PCI_DEVICES(xf86_platform_devices[i].pdev,
370ed6184dfSmrg                                      entity->bus.id.pci)) {
371ed6184dfSmrg                    dev = &xf86_platform_devices[i];
372ed6184dfSmrg                    break;
373ed6184dfSmrg                }
3741b5d61b8Smrg            }
3751b5d61b8Smrg        }
3761b5d61b8Smrg        break;
3771b5d61b8Smrg    default:
3781b5d61b8Smrg        xf86Msg(X_DEBUG, "xf86MergeOutputClassOptions unsupported bus type %d\n",
3791b5d61b8Smrg                entity->bus.type);
3801b5d61b8Smrg    }
3811b5d61b8Smrg
3821b5d61b8Smrg    if (!dev)
3831b5d61b8Smrg        return;
3841b5d61b8Smrg
3851b5d61b8Smrg    for (cl = xf86configptr->conf_outputclass_lst; cl; cl = cl->list.next) {
3861b5d61b8Smrg        if (!OutputClassMatches(cl, dev) || !cl->option_lst)
3871b5d61b8Smrg            continue;
3881b5d61b8Smrg
3891b5d61b8Smrg        xf86Msg(X_INFO, "Applying OutputClass \"%s\" options to %s\n",
3901b5d61b8Smrg                cl->identifier, dev->attribs->path);
3911b5d61b8Smrg
3921b5d61b8Smrg        classopts = xf86optionListDup(cl->option_lst);
3931b5d61b8Smrg        *options = xf86optionListMerge(*options, classopts);
3941b5d61b8Smrg    }
3951b5d61b8Smrg}
3961b5d61b8Smrg
39735c4bbdfSmrgstatic int
39835c4bbdfSmrgxf86ClaimPlatformSlot(struct xf86_platform_device * d, DriverPtr drvp,
39935c4bbdfSmrg                  int chipset, GDevPtr dev, Bool active)
40035c4bbdfSmrg{
40135c4bbdfSmrg    EntityPtr p = NULL;
40235c4bbdfSmrg    int num;
40335c4bbdfSmrg
40435c4bbdfSmrg    if (xf86_check_platform_slot(d)) {
40535c4bbdfSmrg        num = xf86AllocateEntity();
40635c4bbdfSmrg        p = xf86Entities[num];
40735c4bbdfSmrg        p->driver = drvp;
40835c4bbdfSmrg        p->chipset = chipset;
40935c4bbdfSmrg        p->bus.type = BUS_PLATFORM;
41035c4bbdfSmrg        p->bus.id.plat = d;
41135c4bbdfSmrg        p->active = active;
41235c4bbdfSmrg        p->inUse = FALSE;
41335c4bbdfSmrg        if (dev)
41435c4bbdfSmrg            xf86AddDevToEntity(num, dev);
41535c4bbdfSmrg
41635c4bbdfSmrg        platformSlotClaimed++;
41735c4bbdfSmrg        return num;
41835c4bbdfSmrg    }
41935c4bbdfSmrg    else
42035c4bbdfSmrg        return -1;
42135c4bbdfSmrg}
42235c4bbdfSmrg
42335c4bbdfSmrgstatic int
42435c4bbdfSmrgxf86UnclaimPlatformSlot(struct xf86_platform_device *d, GDevPtr dev)
42535c4bbdfSmrg{
42635c4bbdfSmrg    int i;
42735c4bbdfSmrg
42835c4bbdfSmrg    for (i = 0; i < xf86NumEntities; i++) {
42935c4bbdfSmrg        const EntityPtr p = xf86Entities[i];
43035c4bbdfSmrg
43135c4bbdfSmrg        if ((p->bus.type == BUS_PLATFORM) && (p->bus.id.plat == d)) {
43235c4bbdfSmrg            if (dev)
43335c4bbdfSmrg                xf86RemoveDevFromEntity(i, dev);
43435c4bbdfSmrg            platformSlotClaimed--;
43535c4bbdfSmrg            p->bus.type = BUS_NONE;
43635c4bbdfSmrg            return 0;
43735c4bbdfSmrg        }
43835c4bbdfSmrg    }
43935c4bbdfSmrg    return 0;
44035c4bbdfSmrg}
44135c4bbdfSmrg
44235c4bbdfSmrg
44335c4bbdfSmrg#define END_OF_MATCHES(m)                                               \
44435c4bbdfSmrg    (((m).vendor_id == 0) && ((m).device_id == 0) && ((m).subvendor_id == 0))
44535c4bbdfSmrg
44635c4bbdfSmrgstatic Bool doPlatformProbe(struct xf86_platform_device *dev, DriverPtr drvp,
44735c4bbdfSmrg                            GDevPtr gdev, int flags, intptr_t match_data)
44835c4bbdfSmrg{
44935c4bbdfSmrg    Bool foundScreen = FALSE;
45035c4bbdfSmrg    int entity;
45135c4bbdfSmrg
45235c4bbdfSmrg    if (gdev && gdev->screen == 0 && !xf86_check_platform_slot(dev))
45335c4bbdfSmrg        return FALSE;
45435c4bbdfSmrg
45535c4bbdfSmrg    entity = xf86ClaimPlatformSlot(dev, drvp, 0,
45635c4bbdfSmrg                                   gdev, gdev ? gdev->active : 0);
45735c4bbdfSmrg
45835c4bbdfSmrg    if ((entity == -1) && gdev && (gdev->screen > 0)) {
45935c4bbdfSmrg        unsigned nent;
46035c4bbdfSmrg
46135c4bbdfSmrg        for (nent = 0; nent < xf86NumEntities; nent++) {
46235c4bbdfSmrg            EntityPtr pEnt = xf86Entities[nent];
46335c4bbdfSmrg
46435c4bbdfSmrg            if (pEnt->bus.type != BUS_PLATFORM)
46535c4bbdfSmrg                continue;
46635c4bbdfSmrg            if (pEnt->bus.id.plat == dev) {
46735c4bbdfSmrg                entity = nent;
46835c4bbdfSmrg                xf86AddDevToEntity(nent, gdev);
46935c4bbdfSmrg                break;
47035c4bbdfSmrg            }
47135c4bbdfSmrg        }
47235c4bbdfSmrg    }
47335c4bbdfSmrg    if (entity != -1) {
47435c4bbdfSmrg        if ((dev->flags & XF86_PDEV_SERVER_FD) && (!drvp->driverFunc ||
47535c4bbdfSmrg                !drvp->driverFunc(NULL, SUPPORTS_SERVER_FDS, NULL))) {
47635c4bbdfSmrg            systemd_logind_release_fd(dev->attribs->major, dev->attribs->minor, dev->attribs->fd);
47735c4bbdfSmrg            dev->attribs->fd = -1;
47835c4bbdfSmrg            dev->flags &= ~XF86_PDEV_SERVER_FD;
47935c4bbdfSmrg        }
48035c4bbdfSmrg
48135c4bbdfSmrg        if (drvp->platformProbe(drvp, entity, flags, dev, match_data))
48235c4bbdfSmrg            foundScreen = TRUE;
48335c4bbdfSmrg        else
48435c4bbdfSmrg            xf86UnclaimPlatformSlot(dev, gdev);
48535c4bbdfSmrg    }
48635c4bbdfSmrg    return foundScreen;
48735c4bbdfSmrg}
48835c4bbdfSmrg
48935c4bbdfSmrgstatic Bool
49035c4bbdfSmrgprobeSingleDevice(struct xf86_platform_device *dev, DriverPtr drvp, GDevPtr gdev, int flags)
49135c4bbdfSmrg{
49235c4bbdfSmrg    int k;
49335c4bbdfSmrg    Bool foundScreen = FALSE;
49435c4bbdfSmrg    struct pci_device *pPci;
49535c4bbdfSmrg    const struct pci_id_match *const devices = drvp->supported_devices;
49635c4bbdfSmrg
49735c4bbdfSmrg    if (dev->pdev && devices) {
49835c4bbdfSmrg        int device_id = dev->pdev->device_id;
49935c4bbdfSmrg        pPci = dev->pdev;
50035c4bbdfSmrg        for (k = 0; !END_OF_MATCHES(devices[k]); k++) {
50135c4bbdfSmrg            if (PCI_ID_COMPARE(devices[k].vendor_id, pPci->vendor_id)
50235c4bbdfSmrg                && PCI_ID_COMPARE(devices[k].device_id, device_id)
50335c4bbdfSmrg                && ((devices[k].device_class_mask & pPci->device_class)
50435c4bbdfSmrg                    ==  devices[k].device_class)) {
50535c4bbdfSmrg                foundScreen = doPlatformProbe(dev, drvp, gdev, flags, devices[k].match_data);
50635c4bbdfSmrg                if (foundScreen)
50735c4bbdfSmrg                    break;
50835c4bbdfSmrg            }
50935c4bbdfSmrg        }
51035c4bbdfSmrg    }
51135c4bbdfSmrg    else if (dev->pdev && !devices)
51235c4bbdfSmrg        return FALSE;
51335c4bbdfSmrg    else
51435c4bbdfSmrg        foundScreen = doPlatformProbe(dev, drvp, gdev, flags, 0);
51535c4bbdfSmrg    return foundScreen;
51635c4bbdfSmrg}
51735c4bbdfSmrg
5181b5d61b8Smrgstatic Bool
5191b5d61b8SmrgisGPUDevice(GDevPtr gdev)
5201b5d61b8Smrg{
5211b5d61b8Smrg    int i;
5221b5d61b8Smrg
5231b5d61b8Smrg    for (i = 0; i < gdev->myScreenSection->num_gpu_devices; i++) {
5241b5d61b8Smrg        if (gdev == gdev->myScreenSection->gpu_devices[i])
5251b5d61b8Smrg            return TRUE;
5261b5d61b8Smrg    }
5271b5d61b8Smrg
5281b5d61b8Smrg    return FALSE;
5291b5d61b8Smrg}
5301b5d61b8Smrg
53135c4bbdfSmrgint
53235c4bbdfSmrgxf86platformProbeDev(DriverPtr drvp)
53335c4bbdfSmrg{
53435c4bbdfSmrg    Bool foundScreen = FALSE;
53535c4bbdfSmrg    GDevPtr *devList;
53635c4bbdfSmrg    const unsigned numDevs = xf86MatchDevice(drvp->driverName, &devList);
53735c4bbdfSmrg    int i, j;
53835c4bbdfSmrg
539ed6184dfSmrg    /* find the main device or any device specified in xorg.conf */
54035c4bbdfSmrg    for (i = 0; i < numDevs; i++) {
541ed6184dfSmrg        const char *devpath;
542ed6184dfSmrg
54335c4bbdfSmrg        /* skip inactive devices */
54435c4bbdfSmrg        if (!devList[i]->active)
54535c4bbdfSmrg            continue;
54635c4bbdfSmrg
547ed6184dfSmrg        /* This is specific to modesetting. */
548ed6184dfSmrg        devpath = xf86FindOptionValue(devList[i]->options, "kmsdev");
549ed6184dfSmrg
55035c4bbdfSmrg        for (j = 0; j < xf86_num_platform_devices; j++) {
551ed6184dfSmrg            if (devpath && *devpath) {
552ed6184dfSmrg                if (strcmp(xf86_platform_devices[j].attribs->path, devpath) == 0)
553ed6184dfSmrg                    break;
554ed6184dfSmrg            } else if (devList[i]->busID && *devList[i]->busID) {
55535c4bbdfSmrg                if (xf86PlatformDeviceCheckBusID(&xf86_platform_devices[j], devList[i]->busID))
55635c4bbdfSmrg                    break;
55735c4bbdfSmrg            }
55835c4bbdfSmrg            else {
55935c4bbdfSmrg                /* for non-seat0 servers assume first device is the master */
560ed6184dfSmrg                if (ServerIsNotSeat0()) {
56135c4bbdfSmrg                    break;
562ed6184dfSmrg                } else {
563ed6184dfSmrg                    /* Accept the device if the driver is simpledrm */
564ed6184dfSmrg                    if (strcmp(xf86_platform_devices[j].attribs->driver, "simpledrm") == 0)
565ed6184dfSmrg                        break;
566ed6184dfSmrg                }
56735c4bbdfSmrg
56835c4bbdfSmrg                if (xf86IsPrimaryPlatform(&xf86_platform_devices[j]))
56935c4bbdfSmrg                    break;
57035c4bbdfSmrg            }
57135c4bbdfSmrg        }
57235c4bbdfSmrg
57335c4bbdfSmrg        if (j == xf86_num_platform_devices)
57435c4bbdfSmrg             continue;
57535c4bbdfSmrg
5761b5d61b8Smrg        foundScreen = probeSingleDevice(&xf86_platform_devices[j], drvp, devList[i],
5771b5d61b8Smrg                                        isGPUDevice(devList[i]) ? PLATFORM_PROBE_GPU_SCREEN : 0);
57835c4bbdfSmrg    }
57935c4bbdfSmrg
5801b5d61b8Smrg    free(devList);
5811b5d61b8Smrg
5821b5d61b8Smrg    return foundScreen;
5831b5d61b8Smrg}
5841b5d61b8Smrg
5851b5d61b8Smrgint
5861b5d61b8Smrgxf86platformAddGPUDevices(DriverPtr drvp)
5871b5d61b8Smrg{
5881b5d61b8Smrg    Bool foundScreen = FALSE;
5891b5d61b8Smrg    GDevPtr *devList;
5901b5d61b8Smrg    int j;
5911b5d61b8Smrg
5921b5d61b8Smrg    if (!drvp->platformProbe)
5931b5d61b8Smrg        return FALSE;
5941b5d61b8Smrg
5951b5d61b8Smrg    xf86MatchDevice(drvp->driverName, &devList);
5961b5d61b8Smrg
59735c4bbdfSmrg    /* if autoaddgpu devices is enabled then go find any unclaimed platform
59835c4bbdfSmrg     * devices and add them as GPU screens */
59935c4bbdfSmrg    if (xf86Info.autoAddGPU) {
60035c4bbdfSmrg        for (j = 0; j < xf86_num_platform_devices; j++) {
60135c4bbdfSmrg            if (probeSingleDevice(&xf86_platform_devices[j], drvp,
60235c4bbdfSmrg                                  devList ?  devList[0] : NULL,
60335c4bbdfSmrg                                  PLATFORM_PROBE_GPU_SCREEN))
60435c4bbdfSmrg                foundScreen = TRUE;
60535c4bbdfSmrg        }
60635c4bbdfSmrg    }
60735c4bbdfSmrg
6081b5d61b8Smrg    free(devList);
6091b5d61b8Smrg
61035c4bbdfSmrg    return foundScreen;
61135c4bbdfSmrg}
61235c4bbdfSmrg
61335c4bbdfSmrgint
61435c4bbdfSmrgxf86platformAddDevice(int index)
61535c4bbdfSmrg{
616ed6184dfSmrg    int i, old_screens, scr_index, scrnum;
61735c4bbdfSmrg    DriverPtr drvp = NULL;
61835c4bbdfSmrg    screenLayoutPtr layout;
61935c4bbdfSmrg    static const char *hotplug_driver_name = "modesetting";
62035c4bbdfSmrg
62135c4bbdfSmrg    if (!xf86Info.autoAddGPU)
62235c4bbdfSmrg        return -1;
62335c4bbdfSmrg
62435c4bbdfSmrg    /* force load the driver for now */
62535c4bbdfSmrg    xf86LoadOneModule(hotplug_driver_name, NULL);
62635c4bbdfSmrg
62735c4bbdfSmrg    for (i = 0; i < xf86NumDrivers; i++) {
62835c4bbdfSmrg        if (!xf86DriverList[i])
62935c4bbdfSmrg            continue;
63035c4bbdfSmrg
63135c4bbdfSmrg        if (!strcmp(xf86DriverList[i]->driverName, hotplug_driver_name)) {
63235c4bbdfSmrg            drvp = xf86DriverList[i];
63335c4bbdfSmrg            break;
63435c4bbdfSmrg        }
63535c4bbdfSmrg    }
63635c4bbdfSmrg    if (i == xf86NumDrivers)
63735c4bbdfSmrg        return -1;
63835c4bbdfSmrg
63935c4bbdfSmrg    old_screens = xf86NumGPUScreens;
64035c4bbdfSmrg    doPlatformProbe(&xf86_platform_devices[index], drvp, NULL,
64135c4bbdfSmrg                    PLATFORM_PROBE_GPU_SCREEN, 0);
64235c4bbdfSmrg    if (old_screens == xf86NumGPUScreens)
64335c4bbdfSmrg        return -1;
64435c4bbdfSmrg    i = old_screens;
64535c4bbdfSmrg
64635c4bbdfSmrg    for (layout = xf86ConfigLayout.screens; layout->screen != NULL;
64735c4bbdfSmrg         layout++) {
64835c4bbdfSmrg        xf86GPUScreens[i]->confScreen = layout->screen;
64935c4bbdfSmrg        break;
65035c4bbdfSmrg    }
65135c4bbdfSmrg
65235c4bbdfSmrg    if (xf86GPUScreens[i]->PreInit &&
65335c4bbdfSmrg        xf86GPUScreens[i]->PreInit(xf86GPUScreens[i], 0))
65435c4bbdfSmrg        xf86GPUScreens[i]->configured = TRUE;
65535c4bbdfSmrg
65635c4bbdfSmrg    if (!xf86GPUScreens[i]->configured) {
65735c4bbdfSmrg        ErrorF("hotplugged device %d didn't configure\n", i);
65835c4bbdfSmrg        xf86DeleteScreen(xf86GPUScreens[i]);
65935c4bbdfSmrg        return -1;
66035c4bbdfSmrg    }
66135c4bbdfSmrg
66235c4bbdfSmrg   scr_index = AddGPUScreen(xf86GPUScreens[i]->ScreenInit, 0, NULL);
66335c4bbdfSmrg   if (scr_index == -1) {
66435c4bbdfSmrg       xf86DeleteScreen(xf86GPUScreens[i]);
66535c4bbdfSmrg       xf86UnclaimPlatformSlot(&xf86_platform_devices[index], NULL);
66635c4bbdfSmrg       xf86NumGPUScreens = old_screens;
66735c4bbdfSmrg       return -1;
66835c4bbdfSmrg   }
66935c4bbdfSmrg   dixSetPrivate(&xf86GPUScreens[i]->pScreen->devPrivates,
67035c4bbdfSmrg                 xf86ScreenKey, xf86GPUScreens[i]);
67135c4bbdfSmrg
67235c4bbdfSmrg   CreateScratchPixmapsForScreen(xf86GPUScreens[i]->pScreen);
67335c4bbdfSmrg
67435c4bbdfSmrg   if (xf86GPUScreens[i]->pScreen->CreateScreenResources &&
67535c4bbdfSmrg       !(*xf86GPUScreens[i]->pScreen->CreateScreenResources) (xf86GPUScreens[i]->pScreen)) {
67635c4bbdfSmrg       RemoveGPUScreen(xf86GPUScreens[i]->pScreen);
67735c4bbdfSmrg       xf86DeleteScreen(xf86GPUScreens[i]);
67835c4bbdfSmrg       xf86UnclaimPlatformSlot(&xf86_platform_devices[index], NULL);
67935c4bbdfSmrg       xf86NumGPUScreens = old_screens;
68035c4bbdfSmrg       return -1;
68135c4bbdfSmrg   }
682ed6184dfSmrg   /* attach unbound to the configured protocol screen (or 0) */
683ed6184dfSmrg   scrnum = xf86GPUScreens[i]->confScreen->screennum;
684ed6184dfSmrg   AttachUnboundGPU(xf86Screens[scrnum]->pScreen, xf86GPUScreens[i]->pScreen);
685ed6184dfSmrg   if (xf86Info.autoBindGPU)
686ed6184dfSmrg       RRProviderAutoConfigGpuScreen(xf86ScrnToScreen(xf86GPUScreens[i]),
687ed6184dfSmrg                                     xf86ScrnToScreen(xf86Screens[scrnum]));
68835c4bbdfSmrg
689ed6184dfSmrg   RRResourcesChanged(xf86Screens[scrnum]->pScreen);
690ed6184dfSmrg   RRTellChanged(xf86Screens[scrnum]->pScreen);
69135c4bbdfSmrg
69235c4bbdfSmrg   return 0;
69335c4bbdfSmrg}
69435c4bbdfSmrg
69535c4bbdfSmrgvoid
69635c4bbdfSmrgxf86platformRemoveDevice(int index)
69735c4bbdfSmrg{
69835c4bbdfSmrg    EntityPtr entity;
699ed6184dfSmrg    int ent_num, i, j, scrnum;
70035c4bbdfSmrg    Bool found;
70135c4bbdfSmrg
70235c4bbdfSmrg    for (ent_num = 0; ent_num < xf86NumEntities; ent_num++) {
70335c4bbdfSmrg        entity = xf86Entities[ent_num];
70435c4bbdfSmrg        if (entity->bus.type == BUS_PLATFORM &&
70535c4bbdfSmrg            entity->bus.id.plat == &xf86_platform_devices[index])
70635c4bbdfSmrg            break;
70735c4bbdfSmrg    }
70835c4bbdfSmrg    if (ent_num == xf86NumEntities)
70935c4bbdfSmrg        goto out;
71035c4bbdfSmrg
71135c4bbdfSmrg    found = FALSE;
71235c4bbdfSmrg    for (i = 0; i < xf86NumGPUScreens; i++) {
71335c4bbdfSmrg        for (j = 0; j < xf86GPUScreens[i]->numEntities; j++)
71435c4bbdfSmrg            if (xf86GPUScreens[i]->entityList[j] == ent_num) {
71535c4bbdfSmrg                found = TRUE;
71635c4bbdfSmrg                break;
71735c4bbdfSmrg            }
71835c4bbdfSmrg        if (found)
71935c4bbdfSmrg            break;
72035c4bbdfSmrg    }
72135c4bbdfSmrg    if (!found) {
72235c4bbdfSmrg        ErrorF("failed to find screen to remove\n");
72335c4bbdfSmrg        goto out;
72435c4bbdfSmrg    }
72535c4bbdfSmrg
726ed6184dfSmrg    scrnum = xf86GPUScreens[i]->confScreen->screennum;
727ed6184dfSmrg
72835c4bbdfSmrg    xf86GPUScreens[i]->pScreen->CloseScreen(xf86GPUScreens[i]->pScreen);
72935c4bbdfSmrg
73035c4bbdfSmrg    RemoveGPUScreen(xf86GPUScreens[i]->pScreen);
73135c4bbdfSmrg    xf86DeleteScreen(xf86GPUScreens[i]);
73235c4bbdfSmrg
73335c4bbdfSmrg    xf86UnclaimPlatformSlot(&xf86_platform_devices[index], NULL);
73435c4bbdfSmrg
73535c4bbdfSmrg    xf86_remove_platform_device(index);
73635c4bbdfSmrg
737ed6184dfSmrg    RRResourcesChanged(xf86Screens[scrnum]->pScreen);
738ed6184dfSmrg    RRTellChanged(xf86Screens[scrnum]->pScreen);
73935c4bbdfSmrg out:
74035c4bbdfSmrg    return;
74135c4bbdfSmrg}
74235c4bbdfSmrg
74335c4bbdfSmrg/* called on return from VT switch to find any new devices */
74435c4bbdfSmrgvoid xf86platformVTProbe(void)
74535c4bbdfSmrg{
74635c4bbdfSmrg    int i;
74735c4bbdfSmrg
74835c4bbdfSmrg    for (i = 0; i < xf86_num_platform_devices; i++) {
74935c4bbdfSmrg        if (!(xf86_platform_devices[i].flags & XF86_PDEV_UNOWNED))
75035c4bbdfSmrg            continue;
75135c4bbdfSmrg
75235c4bbdfSmrg        xf86_platform_devices[i].flags &= ~XF86_PDEV_UNOWNED;
75335c4bbdfSmrg        xf86PlatformReprobeDevice(i, xf86_platform_devices[i].attribs);
75435c4bbdfSmrg    }
75535c4bbdfSmrg}
75635c4bbdfSmrg
75735c4bbdfSmrgvoid xf86platformPrimary(void)
75835c4bbdfSmrg{
75935c4bbdfSmrg    /* use the first platform device as a fallback */
76035c4bbdfSmrg    if (primaryBus.type == BUS_NONE) {
76135c4bbdfSmrg        xf86Msg(X_INFO, "no primary bus or device found\n");
76235c4bbdfSmrg
76335c4bbdfSmrg        if (xf86_num_platform_devices > 0) {
76435c4bbdfSmrg            primaryBus.id.plat = &xf86_platform_devices[0];
76535c4bbdfSmrg            primaryBus.type = BUS_PLATFORM;
76635c4bbdfSmrg
76735c4bbdfSmrg            xf86Msg(X_NONE, "\tfalling back to %s\n", primaryBus.id.plat->attribs->syspath);
76835c4bbdfSmrg        }
76935c4bbdfSmrg    }
77035c4bbdfSmrg}
77135c4bbdfSmrg#endif
772