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