From 7586ac6edea64b30d6187f9ec4d867521c1e769c Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Mon, 4 Jul 2005 18:41:04 +0000 Subject: [PATCH] Bug #2216: Multiseat support. From various Debian and Ubuntu patches by Aivils Stoss, Andreas Schuldei, Branden Robinson, and Daniel Stone. --- hw/xfree86/common/xf86Config.c | 39 +++++ hw/xfree86/common/xf86Globals.c | 1 + hw/xfree86/common/xf86Init.c | 20 +++ hw/xfree86/common/xf86Priv.h | 1 + hw/xfree86/common/xf86pciBus.c | 9 +- hw/xfree86/doc/man/Xorg.man.pre | 15 +- hw/xfree86/doc/man/xorg.conf.man.pre | 24 ++- hw/xfree86/os-support/linux/lnx_init.c | 221 +++++++++++++++---------- 8 files changed, 236 insertions(+), 94 deletions(-) diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c index af27d9531..999c74217 100644 --- a/hw/xfree86/common/xf86Config.c +++ b/hw/xfree86/common/xf86Config.c @@ -1657,6 +1657,20 @@ checkCoreInputDevices(serverLayoutPtr servlayoutp, Bool implicitLayout) return TRUE; } +typedef enum { + LAYOUT_ISOLATEDEVICE, + LAYOUT_SINGLECARD +} LayoutValues; + +static OptionInfoRec LayoutOptions[] = { + { LAYOUT_ISOLATEDEVICE, "IsolateDevice", OPTV_STRING, + {0}, FALSE }, + { LAYOUT_SINGLECARD, "SingleCard", OPTV_BOOLEAN, + {0}, FALSE }, + { -1, NULL, OPTV_NONE, + {0}, FALSE }, +}; + /* * figure out which layout is active, which screens are used in that layout, * which drivers and monitors are used in these screens @@ -2540,6 +2554,8 @@ xf86HandleConfigFile(Bool autoconfig) const char *filename; char *searchpath; MessageType from = X_DEFAULT; + char *scanptr; + Bool singlecard = 0; if (!autoconfig) { if (getuid() == 0) @@ -2613,6 +2629,29 @@ xf86HandleConfigFile(Bool autoconfig) } } + xf86ProcessOptions(-1, xf86ConfigLayout.options, LayoutOptions); + + if ((scanptr = xf86GetOptValString(LayoutOptions, LAYOUT_ISOLATEDEVICE))) { + ; /* IsolateDevice specified; overrides SingleCard */ + } else { + xf86GetOptValBool(LayoutOptions, LAYOUT_SINGLECARD, &singlecard); + if (singlecard) + scanptr = xf86ConfigLayout.screens->screen->device->busID; + } + if (scanptr) { + int bus, device, func, stroffset = 0; + if (strncmp(scanptr, "PCI:", 4) != 0) { + xf86Msg(X_WARNING, "Bus types other than PCI not yet isolable.\n" + "\tIgnoring IsolateDevice option.\n"); + } else if (sscanf(scanptr, "PCI:%d:%d:%d", &bus, &device, &func) == 3) { + xf86IsolateDevice.bus = bus; + xf86IsolateDevice.device = device; + xf86IsolateDevice.func = func; + xf86Msg(X_INFO, + "Isolating PCI bus \"%d:%d:%d\"\n", bus, device, func); + } + } + /* Now process everything else */ if (!configFiles(xf86configptr->conf_files) || diff --git a/hw/xfree86/common/xf86Globals.c b/hw/xfree86/common/xf86Globals.c index a295fb980..1a513e048 100644 --- a/hw/xfree86/common/xf86Globals.c +++ b/hw/xfree86/common/xf86Globals.c @@ -243,6 +243,7 @@ Bool xf86MiscModInDevAllowNonLocal = FALSE; RootWinPropPtr *xf86RegisteredPropertiesTable = NULL; Bool xf86inSuspend = FALSE; Bool xorgHWAccess = FALSE; +PciBusId xf86IsolateDevice; #ifdef DLOPEN_HACK /* diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c index 28ffeeb22..e6754a9f6 100644 --- a/hw/xfree86/common/xf86Init.c +++ b/hw/xfree86/common/xf86Init.c @@ -1681,6 +1681,25 @@ ddxProcessArgument(int argc, char **argv, int i) xf86AllowMouseOpenFail = TRUE; return 1; } + if (!strcmp(argv[i], "-isolateDevice")) + { + int bus, device, func; + if (++i >= argc) + return 0; + if (strncmp(argv[i], "PCI:", 4)) { + ErrorF("Bus types other than PCI not yet isolable\n"); + return 0; + } + if (sscanf(argv[i], "PCI:%d:%d:%d", &bus, &device, &func) == 3) { + xf86IsolateDevice.bus = bus; + xf86IsolateDevice.device = device; + xf86IsolateDevice.func = func; + return 2; + } else { + ErrorF("Invalid isolated device specifiation\n"); + return 0; + } + } /* OS-specific processing */ return xf86ProcessArgument(argc, argv, i); } @@ -1745,6 +1764,7 @@ ddxUseMsg() #endif ErrorF("-bestRefresh choose modes with the best refresh rate\n"); ErrorF("-ignoreABI make module ABI mismatches non-fatal\n"); + ErrorF("-isolateDevice bus_id restrict device resets to bus_id (PCI only)\n"); ErrorF("-version show the server version\n"); /* OS-specific usage */ xf86UseMsg(); diff --git a/hw/xfree86/common/xf86Priv.h b/hw/xfree86/common/xf86Priv.h index 01257fd9b..15456f906 100644 --- a/hw/xfree86/common/xf86Priv.h +++ b/hw/xfree86/common/xf86Priv.h @@ -80,6 +80,7 @@ extern Bool xf86BestRefresh; extern Gamma xf86Gamma; extern char *xf86ServerName; extern Bool xf86ShowUnresolved; +extern PciBusId xf86IsolateDevice; /* Other parameters */ diff --git a/hw/xfree86/common/xf86pciBus.c b/hw/xfree86/common/xf86pciBus.c index 0d8016ff9..8fa199872 100644 --- a/hw/xfree86/common/xf86pciBus.c +++ b/hw/xfree86/common/xf86pciBus.c @@ -194,7 +194,10 @@ FindPCIVideoInfo(void) int i = 0, j, k; int num = 0; pciVideoPtr info; + int DoIsolateDeviceCheck = 0; + if (xf86IsolateDevice.bus || xf86IsolateDevice.device || xf86IsolateDevice.func) + DoIsolateDeviceCheck = 1; pcrpp = xf86PciInfo = xf86scanpci(0); getPciClassFlags(pcrpp); @@ -216,7 +219,11 @@ FindPCIVideoInfo(void) subclass = pcrp->pci_sub_class; } - if (PCIINFOCLASSES(baseclass, subclass)) { + if (PCIINFOCLASSES(baseclass, subclass) && + (DoIsolateDeviceCheck ? + (xf86IsolateDevice.bus == pcrp->busnum && + xf86IsolateDevice.device == pcrp->devnum && + xf86IsolateDevice.func == pcrp->funcnum) : 1)) { num++; xf86PciVideoInfo = xnfrealloc(xf86PciVideoInfo, sizeof(pciVideoPtr) * (num + 1)); diff --git a/hw/xfree86/doc/man/Xorg.man.pre b/hw/xfree86/doc/man/Xorg.man.pre index df13a5b9b..f57dfd607 100644 --- a/hw/xfree86/doc/man/Xorg.man.pre +++ b/hw/xfree86/doc/man/Xorg.man.pre @@ -1,4 +1,4 @@ -.\" $XdotOrg$ +.\" $XdotOrg: xc/programs/Xserver/hw/xfree86/Xorg.man,v 1.2 2004/04/23 19:20:02 eich Exp $ .TH __xservername__ __appmansuffix__ __vendorversion__ .SH NAME __xservername__ - X11R6 X server @@ -257,6 +257,19 @@ that the server does not have. When this option is specified, mismatches like this are downgraded from fatal errors to warnings. This option should be used with care. .TP 8 +.B \-isolateDevice \fIbus\-id\fP +Restrict device resets to the device at +.IR bus\-id . +The +.I bus\-id +string has the form +.IB bustype : bus : device : function +(e.g., \(oqPCI:1:0:0\(cq). +At present, only isolation of PCI devices is supported; i.e., this option +is ignored if +.I bustype +is anything other than \(oqPCI\(cq. +.TP 8 .B \-keeptty Prevent the server from detaching its initial controlling terminal. This option is only useful when debugging the server. Not all platforms diff --git a/hw/xfree86/doc/man/xorg.conf.man.pre b/hw/xfree86/doc/man/xorg.conf.man.pre index d78eeba62..9f83bc907 100644 --- a/hw/xfree86/doc/man/xorg.conf.man.pre +++ b/hw/xfree86/doc/man/xorg.conf.man.pre @@ -1,4 +1,4 @@ -.\" $XdotOrg: xc/programs/Xserver/hw/xfree86/xorg.conf.man,v 1.2 2004/04/23 19:20:02 eich Exp $ +.\" $XdotOrg: xc/programs/Xserver/hw/xfree86/xorg.conf.man,v 1.3 2005/03/22 21:30:43 ajax Exp $ .\" shorthand for double quote that works everywhere. .ds q \N'34' .TH __xconfigfile__ __filemansuffix__ __vendorversion__ @@ -375,7 +375,7 @@ where is the display number for the __xservername__ server. .. .SH SERVERFLAGS SECTION -The +In addition to options specific to this section (described below), the .B ServerFlags section is used to specify some global __xservername__ server options. All of the entries in this section are @@ -1779,12 +1779,30 @@ and core keyboard devices respectively. .RE .TP 7 .B Options -Any option permitted in the +In addition to the following, any option permitted in the .B ServerFlags section may also be specified here. When the same option appears in both places, the value given here overrides the one given in the .B ServerFlags section. +.TP 7 +.BI "Option \*qIsolateDevice\*q \*q" bus\-id \*q +Restrict device resets to the specified +.IR bus\-id . +See the +.B BusID +option (described in +.BR "DEVICE SECTION" , +above) for the format of the +.I bus\-id +parameter. This option overrides +.BR SingleCard , +if specified. At present, only PCI devices can be isolated in this manner. +.TP 7 +.BI "Option \*qSingleCard\*q \*q" boolean \*q +As +.BR IsolateDevice , +except that the bus ID of the first device in the layout is used. .PP Here is an example of a .B ServerLayout diff --git a/hw/xfree86/os-support/linux/lnx_init.c b/hw/xfree86/os-support/linux/lnx_init.c index 842d9a075..a52073d0a 100644 --- a/hw/xfree86/os-support/linux/lnx_init.c +++ b/hw/xfree86/os-support/linux/lnx_init.c @@ -50,6 +50,8 @@ char *fb_dev_name; static Bool KeepTty = FALSE; static int VTnum = -1; +static Bool VTSwitch = TRUE; +static Bool ShareVTs = FALSE; static int activeVT = -1; static int vtPermSave[4]; @@ -125,26 +127,37 @@ xf86OpenConsole(void) "xf86OpenConsole: Cannot open /dev/tty0 (%s)\n", strerror(errno)); - if ((ioctl(fd, VT_OPENQRY, &xf86Info.vtno) < 0) || - (xf86Info.vtno == -1)) { - FatalError("xf86OpenConsole: Cannot find a free VT: %s\n", - strerror(errno)); - } + if (ShareVTs) + { + if (ioctl(fd, VT_GETSTATE, &vts) == 0) + xf86Info.vtno = vts.v_active; + else + FatalError("xf86OpenConsole: Cannot find the current" + " VT (%s)\n", strerror(errno)); + } else { + if ((ioctl(fd, VT_OPENQRY, &xf86Info.vtno) < 0) || + (xf86Info.vtno == -1)) + FatalError("xf86OpenConsole: Cannot find a free VT: %s\n", + strerror(errno)); + } close(fd); } #ifdef USE_DEV_FB - fb_dev_name=getenv("FRAMEBUFFER"); - if (!fb_dev_name) - fb_dev_name="/dev/fb0current"; + if (!ShareVTs) + { + fb_dev_name=getenv("FRAMEBUFFER"); + if (!fb_dev_name) + fb_dev_name="/dev/fb0current"; - if ((fbfd = open(fb_dev_name, O_RDONLY)) < 0) - FatalError("xf86OpenConsole: Cannot open %s (%s)\n", - fb_dev_name, strerror(errno)); + if ((fbfd = open(fb_dev_name, O_RDONLY)) < 0) + FatalError("xf86OpenConsole: Cannot open %s (%s)\n", + fb_dev_name, strerror(errno)); - if (ioctl(fbfd, FBIOGET_VSCREENINFO, &var) < 0) - FatalError("xf86OpenConsole: Unable to get screen info %s\n", - strerror(errno)); + if (ioctl(fbfd, FBIOGET_VSCREENINFO, &var) < 0) + FatalError("xf86OpenConsole: Unable to get screen info %s\n", + strerror(errno)); + } #endif xf86Msg(from, "using VT number %d\n\n", xf86Info.vtno); @@ -180,28 +193,31 @@ xf86OpenConsole(void) FatalError("xf86OpenConsole: Cannot open virtual console" " %d (%s)\n", xf86Info.vtno, strerror(errno)); - /* - * Grab the vt ownership before we overwrite it. - * Hard coded /dev/tty0 into this function as well for below. - */ - if (!saveVtPerms()) - xf86Msg(X_WARNING, - "xf86OpenConsole: Could not save ownership of VT\n"); + if (!ShareVTs) + { + /* + * Grab the vt ownership before we overwrite it. + * Hard coded /dev/tty0 into this function as well for below. + */ + if (!saveVtPerms()) + xf86Msg(X_WARNING, + "xf86OpenConsole: Could not save ownership of VT\n"); - /* change ownership of the vt */ - if (chown(vtname, getuid(), getgid()) < 0) - xf86Msg(X_WARNING,"xf86OpenConsole: chown %s failed: %s\n", - vtname, strerror(errno)); + /* change ownership of the vt */ + if (chown(vtname, getuid(), getgid()) < 0) + xf86Msg(X_WARNING,"xf86OpenConsole: chown %s failed: %s\n", + vtname, strerror(errno)); - /* - * the current VT device we're running on is not "console", we want - * to grab all consoles too - * - * Why is this needed?? - */ - if (chown("/dev/tty0", getuid(), getgid()) < 0) - xf86Msg(X_WARNING,"xf86OpenConsole: chown /dev/tty0 failed: %s\n", - strerror(errno)); + /* + * the current VT device we're running on is not "console", we want + * to grab all consoles too + * + * Why is this needed?? + */ + if (chown("/dev/tty0", getuid(), getgid()) < 0) + xf86Msg(X_WARNING,"xf86OpenConsole: chown /dev/tty0 failed: %s\n", + strerror(errno)); + } /* * Linux doesn't switch to an active vt after the last close of a vt, @@ -224,61 +240,69 @@ xf86OpenConsole(void) } } #endif - + + if (!ShareVTs) + { #if defined(DO_OS_FONTRESTORE) - lnx_savefont(); + lnx_savefont(); #endif - /* - * now get the VT - */ - if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, xf86Info.vtno) < 0) - xf86Msg(X_WARNING, "xf86OpenConsole: VT_ACTIVATE failed: %s\n", + /* + * now get the VT + */ + if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, xf86Info.vtno) < 0) + xf86Msg(X_WARNING, "xf86OpenConsole: VT_ACTIVATE failed: %s\n", + strerror(errno)); + + if (ioctl(xf86Info.consoleFd, VT_WAITACTIVE, xf86Info.vtno) < 0) + xf86Msg(X_WARNING, "xf86OpenConsole: VT_WAITACTIVE failed: %s\n", strerror(errno)); - if (ioctl(xf86Info.consoleFd, VT_WAITACTIVE, xf86Info.vtno) < 0) - xf86Msg(X_WARNING, "xf86OpenConsole: VT_WAITACTIVE failed: %s\n", + if (ioctl(xf86Info.consoleFd, VT_GETMODE, &VT) < 0) + FatalError("xf86OpenConsole: VT_GETMODE failed %s\n", + strerror(errno)); + + signal(SIGUSR1, xf86VTRequest); + + VT.mode = VT_PROCESS; + VT.relsig = SIGUSR1; + VT.acqsig = SIGUSR1; + + if (ioctl(xf86Info.consoleFd, VT_SETMODE, &VT) < 0) + FatalError("xf86OpenConsole: VT_SETMODE VT_PROCESS failed: %s\n", strerror(errno)); - - if (ioctl(xf86Info.consoleFd, VT_GETMODE, &VT) < 0) - FatalError("xf86OpenConsole: VT_GETMODE failed %s\n", - strerror(errno)); - - signal(SIGUSR1, xf86VTRequest); - - VT.mode = VT_PROCESS; - VT.relsig = SIGUSR1; - VT.acqsig = SIGUSR1; - - if (ioctl(xf86Info.consoleFd, VT_SETMODE, &VT) < 0) - FatalError("xf86OpenConsole: VT_SETMODE VT_PROCESS failed: %s\n", - strerror(errno)); - if (ioctl(xf86Info.consoleFd, KDSETMODE, KD_GRAPHICS) < 0) - FatalError("xf86OpenConsole: KDSETMODE KD_GRAPHICS failed %s\n", - strerror(errno)); + if (ioctl(xf86Info.consoleFd, KDSETMODE, KD_GRAPHICS) < 0) + FatalError("xf86OpenConsole: KDSETMODE KD_GRAPHICS failed %s\n", + strerror(errno)); - /* we really should have a InitOSInputDevices() function instead - * of Init?$#*&Device(). So I just place it here */ + /* we really should have a InitOSInputDevices() function instead + * of Init?$#*&Device(). So I just place it here */ #ifdef USE_DEV_FB - /* copy info to new console */ - var.yoffset=0; - var.xoffset=0; - if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &var)) - FatalError("Unable to set screen info\n"); - close(fbfd); + /* copy info to new console */ + var.yoffset=0; + var.xoffset=0; + if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &var)) + FatalError("Unable to set screen info\n"); + close(fbfd); #endif + } else { /* ShareVTs */ + close(xf86Info.consoleFd); + } } else { /* serverGeneration != 1 */ - /* - * now get the VT - */ - if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, xf86Info.vtno) < 0) - xf86Msg(X_WARNING, "xf86OpenConsole: VT_ACTIVATE failed %s\n", - strerror(errno)); + if (!ShareVTs && VTSwitch) + { + /* + * now get the VT + */ + if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, xf86Info.vtno) < 0) + xf86Msg(X_WARNING, "xf86OpenConsole: VT_ACTIVATE failed %s\n", + strerror(errno)); + } - if (ioctl(xf86Info.consoleFd, VT_WAITACTIVE, xf86Info.vtno) < 0) - xf86Msg(X_WARNING, "xf86OpenConsole: VT_WAITACTIVE failed %s\n", - strerror(errno)); + if (ioctl(xf86Info.consoleFd, VT_WAITACTIVE, xf86Info.vtno) < 0) + xf86Msg(X_WARNING, "xf86OpenConsole: VT_WAITACTIVE failed %s\n", + strerror(errno)); } return; } @@ -290,7 +314,11 @@ xf86CloseConsole() #if defined(DO_OS_FONTRESTORE) struct vt_stat vts; int vtno = -1; +#endif + if (ShareVTs) return; + +#if defined(DO_OS_FONTRESTORE) if (ioctl(xf86Info.consoleFd, VT_GETSTATE, &vts) < 0) xf86Msg(X_WARNING, "xf86CloseConsole: VT_GETSTATE failed: %s\n", strerror(errno)); @@ -314,21 +342,24 @@ xf86CloseConsole() strerror(errno)); } - /* - * Perform a switch back to the active VT when we were started - */ - if (activeVT >= 0) { - if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, activeVT) < 0) - xf86Msg(X_WARNING, "xf86CloseConsole: VT_ACTIVATE failed: %s\n", - strerror(errno)); - activeVT = -1; - } + if (VTSwitch) + { + /* + * Perform a switch back to the active VT when we were started + */ + if (activeVT >= 0) { + if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, activeVT) < 0) + xf86Msg(X_WARNING, "xf86CloseConsole: VT_ACTIVATE failed: %s\n", + strerror(errno)); + activeVT = -1; + } #if defined(DO_OS_FONTRESTORE) - if (xf86Info.vtno == vtno) /* check if we are active */ - lnx_restorefont(); - lnx_freefontdata(); + if (xf86Info.vtno == vtno) /* check if we are active */ + lnx_restorefont(); + lnx_freefontdata(); #endif + } close(xf86Info.consoleFd); /* make the vt-manager happy */ restoreVtPerms(); /* restore the permissions */ @@ -348,6 +379,16 @@ xf86ProcessArgument(int argc, char *argv[], int i) KeepTty = TRUE; return(1); } + if (!strcmp(argv[i], "-novtswitch")) + { + VTSwitch = FALSE; + return(1); + } + if (!strcmp(argv[i], "-sharevts")) + { + ShareVTs = TRUE; + return(1); + } if ((argv[i][0] == 'v') && (argv[i][1] == 't')) { if (sscanf(argv[i], "vt%2d", &VTnum) == 0) @@ -367,5 +408,7 @@ xf86UseMsg() ErrorF("vtXX use the specified VT number\n"); ErrorF("-keeptty "); ErrorF("don't detach controlling tty (for debugging only)\n"); + ErrorF("-novtswitch don't immediately switch to new VT\n"); + ErrorF("-sharevts share VTs with another X server\n"); return; }