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:
Chris Wilson 2011-06-07 14:23:51 +01:00
parent ad5ead8257
commit 265d94e0aa
6 changed files with 133 additions and 28 deletions

View File

@ -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

View File

@ -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

View File

@ -201,6 +201,7 @@ enum {
OPTION_THROTTLE,
OPTION_RELAXED_FENCING,
OPTION_VMAP,
OPTION_ZAPHOD,
};
enum {

View File

@ -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 {

View File

@ -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);
}

View File

@ -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);