sna: Add zaphod support
Zaphod support is a rudimentary method for creating an Xserver with multiple screens from a single device. The Device is instantiated, with a duplication of its resources, as many as required up to a maximum of the number of its outputs, and each instance is attached to a Screen and added to the ServerLayout. A Device can be bound to a selection of outputs using a comma separated list of RandR names. Note: in general, this is not the preferred solution! And will be superseded by per-crtc-pixmaps in RandR-1.4. For example, the following xorg.conf fragment creates an XServer with two screens, one attached to the LVDS panel on the laptop, and the other to any external output: Section "Device" Identifier "Intel0" Driver "intel" BusID "PCI:0:2:0" Option "ZaphodHeads" "LVDS1" Screen 0 EndSection Section "Device" Identifier "Intel1" Driver "intel" BusID "PCI:0:2:0" Option "ZaphodHeads" "DVI1,VGA1" Screen 1 EndSection Section "Screen" Identifier "Screen0" Device "Intel0" EndSection Section "Screen" Identifier "Screen1" Device "Intel1" EndSection Section "ServerLayout" Identifier "default" Screen "Screen0" Screen "Screen1" EndSection Based on a patch by Ben Skegs <bskeggs@redhat.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
ad5ead8257
commit
265d94e0aa
|
|
@ -222,6 +222,16 @@ This option controls whether the driver automatically notifies
|
|||
applications when monitors are connected or disconnected.
|
||||
.IP
|
||||
Default: enabled.
|
||||
.BI "Option \*qZaphodHeads\*q \*q" string \*q
|
||||
.IP
|
||||
Specify the randr output(s) to use with zaphod mode for a particular driver
|
||||
instance. If you this option you must use it with all instances of the
|
||||
driver
|
||||
.br
|
||||
For example:
|
||||
.B
|
||||
Option \*qZaphodHeads\*q \*qLVDS1,VGA1\*q
|
||||
will assign xrandr outputs LVDS1 and VGA0 to this instance of the driver.
|
||||
|
||||
.SH OUTPUT CONFIGURATION
|
||||
On 830M and better chipsets, the driver supports runtime configuration of
|
||||
|
|
|
|||
|
|
@ -363,12 +363,12 @@ static Bool intel_pci_probe(DriverPtr driver,
|
|||
case PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS:
|
||||
case PCI_CHIP_SANDYBRIDGE_S_GT:
|
||||
#endif
|
||||
sna_init_scrn(scrn);
|
||||
sna_init_scrn(scrn, entity_num);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
#if SNA_DEFAULT
|
||||
sna_init_scrn(scrn);
|
||||
sna_init_scrn(scrn, entity_num);
|
||||
#else
|
||||
intel_init_scrn(scrn);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ enum {
|
|||
OPTION_THROTTLE,
|
||||
OPTION_RELAXED_FENCING,
|
||||
OPTION_VMAP,
|
||||
OPTION_ZAPHOD,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
|||
|
|
@ -1231,6 +1231,43 @@ static const char *output_names[] = {
|
|||
"eDP",
|
||||
};
|
||||
|
||||
static bool
|
||||
sna_zaphod_match(ScrnInfoPtr scrn, const char *s, const char *output)
|
||||
{
|
||||
char t[20];
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
/* match any outputs in a comma list, stopping at whitespace */
|
||||
switch (*s) {
|
||||
case '\0':
|
||||
t[i] = '\0';
|
||||
return strcmp(t, output) == 0;
|
||||
|
||||
case ',':
|
||||
t[i] ='\0';
|
||||
if (strcmp(t, output) == 0)
|
||||
return TRUE;
|
||||
i = 0;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
break;
|
||||
|
||||
default:
|
||||
t[i++] = *s;
|
||||
break;
|
||||
}
|
||||
|
||||
s++;
|
||||
} while (i < sizeof(t));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
|
||||
{
|
||||
|
|
@ -1240,6 +1277,7 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
|
|||
drmModeEncoderPtr kencoder;
|
||||
struct sna_output *sna_output;
|
||||
const char *output_name;
|
||||
const char *s;
|
||||
char name[32];
|
||||
|
||||
koutput = drmModeGetConnector(sna->kgem.fd,
|
||||
|
|
@ -1248,10 +1286,8 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
|
|||
return;
|
||||
|
||||
kencoder = drmModeGetEncoder(sna->kgem.fd, koutput->encoders[0]);
|
||||
if (!kencoder) {
|
||||
drmModeFreeConnector(koutput);
|
||||
return;
|
||||
}
|
||||
if (!kencoder)
|
||||
goto cleanup_connector;
|
||||
|
||||
if (koutput->connector_type < ARRAY_SIZE(output_names))
|
||||
output_name = output_names[koutput->connector_type];
|
||||
|
|
@ -1259,20 +1295,22 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
|
|||
output_name = "UNKNOWN";
|
||||
snprintf(name, 32, "%s%d", output_name, koutput->connector_type_id);
|
||||
|
||||
output = xf86OutputCreate (scrn, &sna_output_funcs, name);
|
||||
if (!output) {
|
||||
drmModeFreeEncoder(kencoder);
|
||||
drmModeFreeConnector(koutput);
|
||||
return;
|
||||
if (xf86IsEntityShared(scrn->entityList[0])) {
|
||||
s = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
|
||||
if (s && !sna_zaphod_match(scrn, s, name)) {
|
||||
ErrorF("output '%s' not matched for zaphod '%s'\n",
|
||||
name, s);
|
||||
goto cleanup_encoder;
|
||||
}
|
||||
}
|
||||
|
||||
output = xf86OutputCreate(scrn, &sna_output_funcs, name);
|
||||
if (!output)
|
||||
goto cleanup_encoder;
|
||||
|
||||
sna_output = calloc(sizeof(struct sna_output), 1);
|
||||
if (!sna_output) {
|
||||
xf86OutputDestroy(output);
|
||||
drmModeFreeConnector(koutput);
|
||||
drmModeFreeEncoder(kencoder);
|
||||
return;
|
||||
}
|
||||
if (!sna_output)
|
||||
goto cleanup_output;
|
||||
|
||||
sna_output->output_id = mode->mode_res->connectors[num];
|
||||
sna_output->mode_output = koutput;
|
||||
|
|
@ -1294,6 +1332,15 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
|
|||
|
||||
sna_output->output = output;
|
||||
list_add(&sna_output->link, &mode->outputs);
|
||||
|
||||
return;
|
||||
|
||||
cleanup_output:
|
||||
xf86OutputDestroy(output);
|
||||
cleanup_connector:
|
||||
drmModeFreeConnector(koutput);
|
||||
cleanup_encoder:
|
||||
drmModeFreeEncoder(kencoder);
|
||||
}
|
||||
|
||||
struct sna_visit_set_pixmap_window {
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ static OptionInfoRec sna_options[] = {
|
|||
{OPTION_THROTTLE, "Throttle", OPTV_BOOLEAN, {0}, TRUE},
|
||||
{OPTION_RELAXED_FENCING, "UseRelaxedFencing", OPTV_BOOLEAN, {0}, TRUE},
|
||||
{OPTION_VMAP, "UseVmap", OPTV_BOOLEAN, {0}, TRUE},
|
||||
{OPTION_ZAPHOD, "ZaphodHeads", OPTV_STRING, {0}, FALSE},
|
||||
{-1, NULL, OPTV_NONE, {0}, FALSE}
|
||||
};
|
||||
|
||||
|
|
@ -257,18 +258,41 @@ static Bool sna_get_early_options(ScrnInfoPtr scrn)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
struct sna_device {
|
||||
int fd;
|
||||
int open_count;
|
||||
};
|
||||
static int sna_device_key;
|
||||
|
||||
static inline struct sna_device *sna_device(ScrnInfoPtr scrn)
|
||||
{
|
||||
return xf86GetEntityPrivate(scrn->entityList[0], sna_device_key)->ptr;
|
||||
}
|
||||
|
||||
static inline void sna_set_device(ScrnInfoPtr scrn, struct sna_device *dev)
|
||||
{
|
||||
xf86GetEntityPrivate(scrn->entityList[0], sna_device_key)->ptr = dev;
|
||||
}
|
||||
|
||||
static int sna_open_drm_master(ScrnInfoPtr scrn)
|
||||
{
|
||||
struct sna_device *dev;
|
||||
struct sna *sna = to_sna(scrn);
|
||||
struct pci_device *dev = sna->PciInfo;
|
||||
struct pci_device *pci = sna->PciInfo;
|
||||
drmSetVersion sv;
|
||||
struct drm_i915_getparam gp;
|
||||
int err, val;
|
||||
char busid[20];
|
||||
int fd;
|
||||
|
||||
dev = sna_device(scrn);
|
||||
if (dev) {
|
||||
dev->open_count++;
|
||||
return dev->fd;
|
||||
}
|
||||
|
||||
snprintf(busid, sizeof(busid), "pci:%04x:%02x:%02x.%d",
|
||||
dev->domain, dev->bus, dev->dev, dev->func);
|
||||
pci->domain, pci->bus, pci->dev, pci->func);
|
||||
|
||||
fd = drmOpen("i915", busid);
|
||||
if (fd == -1) {
|
||||
|
|
@ -305,15 +329,26 @@ static int sna_open_drm_master(ScrnInfoPtr scrn)
|
|||
return -1;
|
||||
}
|
||||
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (dev) {
|
||||
dev->fd = fd;
|
||||
dev->open_count = 1;
|
||||
sna_set_device(scrn, dev);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void sna_close_drm_master(struct sna *sna)
|
||||
static void sna_close_drm_master(ScrnInfoPtr scrn)
|
||||
{
|
||||
if (sna && sna->kgem.fd > 0) {
|
||||
drmClose(sna->kgem.fd);
|
||||
sna->kgem.fd = -1;
|
||||
}
|
||||
struct sna_device *dev = sna_device(scrn);
|
||||
|
||||
if (--dev->open_count)
|
||||
return;
|
||||
|
||||
drmClose(dev->fd);
|
||||
sna_set_device(scrn, NULL);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
static void sna_selftest(void)
|
||||
|
|
@ -321,7 +356,6 @@ static void sna_selftest(void)
|
|||
sna_damage_selftest();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is called before ScreenInit to do any require probing of screen
|
||||
* configuration.
|
||||
|
|
@ -811,12 +845,13 @@ static void sna_free_screen(int scrnIndex, int flags)
|
|||
|
||||
if (sna) {
|
||||
sna_mode_fini(sna);
|
||||
sna_close_drm_master(sna);
|
||||
|
||||
free(sna);
|
||||
scrn->driverPrivate = NULL;
|
||||
}
|
||||
|
||||
sna_close_drm_master(scrn);
|
||||
|
||||
if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
|
||||
vgaHWFreeHWRec(xf86Screens[scrnIndex]);
|
||||
}
|
||||
|
|
@ -911,8 +946,12 @@ static Bool sna_pm_event(int scrnIndex, pmEvent event, Bool undo)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void sna_init_scrn(ScrnInfoPtr scrn)
|
||||
void sna_init_scrn(ScrnInfoPtr scrn, int entity_num)
|
||||
{
|
||||
EntityInfoPtr entity;
|
||||
|
||||
sna_device_key = xf86AllocateEntityPrivateIndex();
|
||||
|
||||
scrn->PreInit = sna_pre_init;
|
||||
scrn->ScreenInit = sna_screen_init;
|
||||
scrn->SwitchMode = sna_switch_mode;
|
||||
|
|
@ -922,4 +961,12 @@ void sna_init_scrn(ScrnInfoPtr scrn)
|
|||
scrn->FreeScreen = sna_free_screen;
|
||||
scrn->ValidMode = sna_valid_mode;
|
||||
scrn->PMEvent = sna_pm_event;
|
||||
|
||||
xf86SetEntitySharable(scrn->entityList[0]);
|
||||
|
||||
entity = xf86GetEntityInfo(entity_num);
|
||||
xf86SetEntityInstanceForScreen(scrn,
|
||||
entity->index,
|
||||
xf86GetNumEntityInstances(entity->index)-1);
|
||||
free(entity);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
const OptionInfoRec *sna_available_options(int chipid, int busid);
|
||||
void sna_init_scrn(ScrnInfoPtr scrn);
|
||||
void sna_init_scrn(ScrnInfoPtr scrn, int entity_num);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue