3230 lines
81 KiB
C
3230 lines
81 KiB
C
/*
|
|
* Copyright (c) 1997-2003 by The XFree86 Project, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of the copyright holder(s)
|
|
* and author(s) shall not be used in advertising or otherwise to promote
|
|
* the sale, use or other dealings in this Software without prior written
|
|
* authorization from the copyright holder(s) and author(s).
|
|
*/
|
|
|
|
#define REDUCER
|
|
/*
|
|
* This file contains the interfaces to the bus-specific code
|
|
*/
|
|
|
|
#ifdef HAVE_XORG_CONFIG_H
|
|
#include <xorg-config.h>
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <X11/X.h>
|
|
#include "os.h"
|
|
#include "xf86.h"
|
|
#include "xf86Priv.h"
|
|
#include "xf86Resources.h"
|
|
|
|
/* Bus-specific headers */
|
|
|
|
#include "xf86Bus.h"
|
|
|
|
#define XF86_OS_PRIVS
|
|
#define NEED_OS_RAC_PROTOS
|
|
#include "xf86_OSproc.h"
|
|
|
|
#include "xf86RAC.h"
|
|
|
|
/* Entity data */
|
|
EntityPtr *xf86Entities = NULL; /* Bus slots claimed by drivers */
|
|
int xf86NumEntities = 0;
|
|
static int xf86EntityPrivateCount = 0;
|
|
BusAccPtr xf86BusAccInfo = NULL;
|
|
|
|
xf86AccessRec AccessNULL = {NULL,NULL,NULL};
|
|
|
|
xf86CurrentAccessRec xf86CurrentAccess = {NULL,NULL};
|
|
|
|
BusRec primaryBus = { BUS_NONE, {{0}}};
|
|
|
|
static Bool xf86ResAccessEnter = FALSE;
|
|
|
|
#ifdef REDUCER
|
|
/* Resources that temporarily conflict with estimated resources */
|
|
static resPtr AccReducers = NULL;
|
|
#endif
|
|
|
|
/* resource lists */
|
|
resPtr Acc = NULL;
|
|
resPtr osRes = NULL;
|
|
|
|
/* allocatable ranges */
|
|
resPtr ResRange = NULL;
|
|
|
|
/* predefined special resources */
|
|
_X_EXPORT resRange resVgaExclusive[] = {_VGA_EXCLUSIVE, _END};
|
|
_X_EXPORT resRange resVgaShared[] = {_VGA_SHARED, _END};
|
|
_X_EXPORT resRange resVgaMemShared[] = {_VGA_SHARED_MEM,_END};
|
|
_X_EXPORT resRange resVgaIoShared[] = {_VGA_SHARED_IO,_END};
|
|
_X_EXPORT resRange resVgaUnusedExclusive[] = {_VGA_EXCLUSIVE_UNUSED, _END};
|
|
_X_EXPORT resRange resVgaUnusedShared[] = {_VGA_SHARED_UNUSED, _END};
|
|
_X_EXPORT resRange resVgaSparseExclusive[] = {_VGA_EXCLUSIVE_SPARSE, _END};
|
|
_X_EXPORT resRange resVgaSparseShared[] = {_VGA_SHARED_SPARSE, _END};
|
|
_X_EXPORT resRange res8514Exclusive[] = {_8514_EXCLUSIVE, _END};
|
|
_X_EXPORT resRange res8514Shared[] = {_8514_SHARED, _END};
|
|
|
|
/* Flag: do we need RAC ? */
|
|
static Bool needRAC = FALSE;
|
|
static Bool doFramebufferMode = FALSE;
|
|
|
|
/* state change notification callback list */
|
|
static StateChangeNotificationPtr StateChangeNotificationList;
|
|
static void notifyStateChange(xf86NotifyState state);
|
|
|
|
#undef MIN
|
|
#define MIN(x,y) ((x<y)?x:y)
|
|
|
|
|
|
/*
|
|
* Call the bus probes relevant to the architecture.
|
|
*
|
|
* The only one available so far is for PCI and SBUS.
|
|
*/
|
|
|
|
void
|
|
xf86BusProbe(void)
|
|
{
|
|
xf86PciProbe();
|
|
#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__)
|
|
xf86SbusProbe();
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Determine what bus type the busID string represents. The start of the
|
|
* bus-dependent part of the string is returned as retID.
|
|
*/
|
|
|
|
BusType
|
|
StringToBusType(const char* busID, const char **retID)
|
|
{
|
|
char *p, *s;
|
|
BusType ret = BUS_NONE;
|
|
|
|
/* If no type field, Default to PCI */
|
|
if (isdigit(busID[0])) {
|
|
if (retID)
|
|
*retID = busID;
|
|
return BUS_PCI;
|
|
}
|
|
|
|
s = xstrdup(busID);
|
|
p = strtok(s, ":");
|
|
if (p == NULL || *p == 0) {
|
|
xfree(s);
|
|
return BUS_NONE;
|
|
}
|
|
if (!xf86NameCmp(p, "pci") || !xf86NameCmp(p, "agp"))
|
|
ret = BUS_PCI;
|
|
if (!xf86NameCmp(p, "isa"))
|
|
ret = BUS_ISA;
|
|
if (!xf86NameCmp(p, "sbus"))
|
|
ret = BUS_SBUS;
|
|
if (ret != BUS_NONE)
|
|
if (retID)
|
|
*retID = busID + strlen(p) + 1;
|
|
xfree(s);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Entity related code.
|
|
*/
|
|
|
|
void
|
|
xf86EntityInit(void)
|
|
{
|
|
int i;
|
|
resPtr *pprev_next;
|
|
resPtr res;
|
|
xf86AccessPtr pacc;
|
|
|
|
for (i = 0; i < xf86NumEntities; i++)
|
|
if (xf86Entities[i]->entityInit) {
|
|
if (xf86Entities[i]->access->busAcc)
|
|
((BusAccPtr)xf86Entities[i]->access->busAcc)->set_f
|
|
(xf86Entities[i]->access->busAcc);
|
|
pacc = xf86Entities[i]->access->fallback;
|
|
if (pacc->AccessEnable)
|
|
pacc->AccessEnable(pacc->arg);
|
|
xf86Entities[i]->entityInit(i,xf86Entities[i]->private);
|
|
if (pacc->AccessDisable)
|
|
pacc->AccessDisable(pacc->arg);
|
|
/* remove init resources after init is processed */
|
|
pprev_next = &Acc;
|
|
res = Acc;
|
|
while (res) {
|
|
if (res->res_type & ResInit && (res->entityIndex == i)) {
|
|
(*pprev_next) = res->next;
|
|
xfree(res);
|
|
} else
|
|
pprev_next = &(res->next);
|
|
res = (*pprev_next);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
xf86AllocateEntity(void)
|
|
{
|
|
xf86NumEntities++;
|
|
xf86Entities = xnfrealloc(xf86Entities,
|
|
sizeof(EntityPtr) * xf86NumEntities);
|
|
xf86Entities[xf86NumEntities - 1] = xnfcalloc(1,sizeof(EntityRec));
|
|
xf86Entities[xf86NumEntities - 1]->entityPrivates =
|
|
xnfcalloc(sizeof(DevUnion) * xf86EntityPrivateCount, 1);
|
|
return (xf86NumEntities - 1);
|
|
}
|
|
|
|
static void
|
|
EntityEnter(void)
|
|
{
|
|
int i;
|
|
xf86AccessPtr pacc;
|
|
|
|
for (i = 0; i < xf86NumEntities; i++)
|
|
if (xf86Entities[i]->entityEnter) {
|
|
if (xf86Entities[i]->access->busAcc)
|
|
((BusAccPtr)xf86Entities[i]->access->busAcc)->set_f
|
|
(xf86Entities[i]->access->busAcc);
|
|
pacc = xf86Entities[i]->access->fallback;
|
|
if (pacc->AccessEnable)
|
|
pacc->AccessEnable(pacc->arg);
|
|
xf86Entities[i]->entityEnter(i,xf86Entities[i]->private);
|
|
if (pacc->AccessDisable)
|
|
pacc->AccessDisable(pacc->arg);
|
|
}
|
|
}
|
|
|
|
static void
|
|
EntityLeave(void)
|
|
{
|
|
int i;
|
|
xf86AccessPtr pacc;
|
|
|
|
for (i = 0; i < xf86NumEntities; i++)
|
|
if (xf86Entities[i]->entityLeave) {
|
|
if (xf86Entities[i]->access->busAcc)
|
|
((BusAccPtr)xf86Entities[i]->access->busAcc)->set_f
|
|
(xf86Entities[i]->access->busAcc);
|
|
pacc = xf86Entities[i]->access->fallback;
|
|
if (pacc->AccessEnable)
|
|
pacc->AccessEnable(pacc->arg);
|
|
xf86Entities[i]->entityLeave(i,xf86Entities[i]->private);
|
|
if (pacc->AccessDisable)
|
|
pacc->AccessDisable(pacc->arg);
|
|
}
|
|
}
|
|
|
|
_X_EXPORT Bool
|
|
xf86IsEntityPrimary(int entityIndex)
|
|
{
|
|
EntityPtr pEnt = xf86Entities[entityIndex];
|
|
|
|
if (primaryBus.type != pEnt->busType) return FALSE;
|
|
|
|
switch (pEnt->busType) {
|
|
case BUS_PCI:
|
|
return (pEnt->pciBusId.bus == primaryBus.id.pci.bus &&
|
|
pEnt->pciBusId.device == primaryBus.id.pci.device &&
|
|
pEnt->pciBusId.func == primaryBus.id.pci.func);
|
|
case BUS_ISA:
|
|
return TRUE;
|
|
case BUS_SBUS:
|
|
return (pEnt->sbusBusId.fbNum == primaryBus.id.sbus.fbNum);
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
_X_EXPORT Bool
|
|
xf86SetEntityFuncs(int entityIndex, EntityProc init, EntityProc enter,
|
|
EntityProc leave, pointer private)
|
|
{
|
|
if (entityIndex >= xf86NumEntities)
|
|
return FALSE;
|
|
xf86Entities[entityIndex]->entityInit = init;
|
|
xf86Entities[entityIndex]->entityEnter = enter;
|
|
xf86Entities[entityIndex]->entityLeave = leave;
|
|
xf86Entities[entityIndex]->private = private;
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
xf86DriverHasEntities(DriverPtr drvp)
|
|
{
|
|
int i;
|
|
for (i = 0; i < xf86NumEntities; i++) {
|
|
if (xf86Entities[i]->driver == drvp)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86AddEntityToScreen(ScrnInfoPtr pScrn, int entityIndex)
|
|
{
|
|
if (entityIndex == -1)
|
|
return;
|
|
if (xf86Entities[entityIndex]->inUse &&
|
|
!(xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL))
|
|
FatalError("Requested Entity already in use!\n");
|
|
|
|
pScrn->numEntities++;
|
|
pScrn->entityList = xnfrealloc(pScrn->entityList,
|
|
pScrn->numEntities * sizeof(int));
|
|
pScrn->entityList[pScrn->numEntities - 1] = entityIndex;
|
|
xf86Entities[entityIndex]->access->next = pScrn->access;
|
|
pScrn->access = xf86Entities[entityIndex]->access;
|
|
xf86Entities[entityIndex]->inUse = TRUE;
|
|
pScrn->entityInstanceList = xnfrealloc(pScrn->entityInstanceList,
|
|
pScrn->numEntities * sizeof(int));
|
|
pScrn->entityInstanceList[pScrn->numEntities - 1] = 0;
|
|
pScrn->domainIOBase = xf86Entities[entityIndex]->domainIO;
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86SetEntityInstanceForScreen(ScrnInfoPtr pScrn, int entityIndex, int instance)
|
|
{
|
|
int i;
|
|
|
|
if (entityIndex == -1 || entityIndex >= xf86NumEntities)
|
|
return;
|
|
|
|
for (i = 0; i < pScrn->numEntities; i++) {
|
|
if (pScrn->entityList[i] == entityIndex) {
|
|
pScrn->entityInstanceList[i] = instance;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* XXX This needs to be updated for the case where a single entity may have
|
|
* instances associated with more than one screen.
|
|
*/
|
|
_X_EXPORT ScrnInfoPtr
|
|
xf86FindScreenForEntity(int entityIndex)
|
|
{
|
|
int i,j;
|
|
|
|
if (entityIndex == -1) return NULL;
|
|
|
|
if (xf86Screens) {
|
|
for (i = 0; i < xf86NumScreens; i++) {
|
|
for (j = 0; j < xf86Screens[i]->numEntities; j++) {
|
|
if ( xf86Screens[i]->entityList[j] == entityIndex )
|
|
return (xf86Screens[i]);
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86RemoveEntityFromScreen(ScrnInfoPtr pScrn, int entityIndex)
|
|
{
|
|
int i;
|
|
EntityAccessPtr *ptr = (EntityAccessPtr *)&pScrn->access;
|
|
EntityAccessPtr peacc;
|
|
|
|
for (i = 0; i < pScrn->numEntities; i++) {
|
|
if (pScrn->entityList[i] == entityIndex) {
|
|
peacc = xf86Entities[pScrn->entityList[i]]->access;
|
|
(*ptr) = peacc->next;
|
|
/* disable entity: call disable func */
|
|
if (peacc->pAccess && peacc->pAccess->AccessDisable)
|
|
peacc->pAccess->AccessDisable(peacc->pAccess->arg);
|
|
/* also disable fallback - just in case */
|
|
if (peacc->fallback && peacc->fallback->AccessDisable)
|
|
peacc->fallback->AccessDisable(peacc->fallback->arg);
|
|
for (i++; i < pScrn->numEntities; i++)
|
|
pScrn->entityList[i-1] = pScrn->entityList[i];
|
|
pScrn->numEntities--;
|
|
xf86Entities[entityIndex]->inUse = FALSE;
|
|
break;
|
|
}
|
|
ptr = &(xf86Entities[pScrn->entityList[i]]->access->next);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* xf86ClearEntitiesForScreen() - called when a screen is deleted
|
|
* to mark it's entities unused. Called by xf86DeleteScreen().
|
|
*/
|
|
void
|
|
xf86ClearEntityListForScreen(int scrnIndex)
|
|
{
|
|
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
|
|
EntityAccessPtr peacc;
|
|
int i, entityIndex;
|
|
|
|
if (pScrn->entityList == NULL || pScrn->numEntities == 0) return;
|
|
|
|
for (i = 0; i < pScrn->numEntities; i++) {
|
|
entityIndex = pScrn->entityList[i];
|
|
xf86Entities[entityIndex]->inUse = FALSE;
|
|
/* disable resource: call the disable function */
|
|
peacc = xf86Entities[entityIndex]->access;
|
|
if (peacc->pAccess && peacc->pAccess->AccessDisable)
|
|
peacc->pAccess->AccessDisable(peacc->pAccess->arg);
|
|
/* and the fallback function */
|
|
if (peacc->fallback && peacc->fallback->AccessDisable)
|
|
peacc->fallback->AccessDisable(peacc->fallback->arg);
|
|
/* shared resources are only needed when entity is active: remove */
|
|
xf86DeallocateResourcesForEntity(entityIndex, ResShared);
|
|
}
|
|
xfree(pScrn->entityList);
|
|
xfree(pScrn->entityInstanceList);
|
|
if (pScrn->CurrentAccess->pIoAccess == (EntityAccessPtr)pScrn->access)
|
|
pScrn->CurrentAccess->pIoAccess = NULL;
|
|
if (pScrn->CurrentAccess->pMemAccess == (EntityAccessPtr)pScrn->access)
|
|
pScrn->CurrentAccess->pMemAccess = NULL;
|
|
pScrn->entityList = NULL;
|
|
pScrn->entityInstanceList = NULL;
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86DeallocateResourcesForEntity(int entityIndex, unsigned long type)
|
|
{
|
|
resPtr *pprev_next = &Acc;
|
|
resPtr res = Acc;
|
|
|
|
while (res) {
|
|
if (res->entityIndex == entityIndex &&
|
|
(type & ResAccMask & res->res_type))
|
|
{
|
|
(*pprev_next) = res->next;
|
|
xfree(res);
|
|
} else
|
|
pprev_next = &(res->next);
|
|
res = (*pprev_next);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Add an extra device section (GDevPtr) to an entity.
|
|
*/
|
|
|
|
void
|
|
xf86AddDevToEntity(int entityIndex, GDevPtr dev)
|
|
{
|
|
EntityPtr pEnt;
|
|
|
|
if (entityIndex >= xf86NumEntities)
|
|
return;
|
|
|
|
pEnt = xf86Entities[entityIndex];
|
|
pEnt->numInstances++;
|
|
pEnt->devices = xnfrealloc(pEnt->devices,
|
|
pEnt->numInstances * sizeof(GDevPtr));
|
|
pEnt->devices[pEnt->numInstances - 1] = dev;
|
|
dev->claimed = TRUE;
|
|
}
|
|
|
|
/*
|
|
* xf86GetEntityInfo() -- This function hands information from the
|
|
* EntityRec struct to the drivers. The EntityRec structure itself
|
|
* remains invisible to the driver.
|
|
*/
|
|
_X_EXPORT EntityInfoPtr
|
|
xf86GetEntityInfo(int entityIndex)
|
|
{
|
|
EntityInfoPtr pEnt;
|
|
int i;
|
|
|
|
if (entityIndex >= xf86NumEntities)
|
|
return NULL;
|
|
|
|
pEnt = xnfcalloc(1,sizeof(EntityInfoRec));
|
|
pEnt->index = entityIndex;
|
|
pEnt->location = xf86Entities[entityIndex]->bus;
|
|
pEnt->active = xf86Entities[entityIndex]->active;
|
|
pEnt->chipset = xf86Entities[entityIndex]->chipset;
|
|
pEnt->resources = xf86Entities[entityIndex]->resources;
|
|
pEnt->driver = xf86Entities[entityIndex]->driver;
|
|
if ( (xf86Entities[entityIndex]->devices) &&
|
|
(xf86Entities[entityIndex]->devices[0]) ) {
|
|
for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++)
|
|
if (xf86Entities[entityIndex]->devices[i]->screen == 0)
|
|
break;
|
|
pEnt->device = xf86Entities[entityIndex]->devices[i];
|
|
} else
|
|
pEnt->device = NULL;
|
|
|
|
return pEnt;
|
|
}
|
|
|
|
_X_EXPORT int
|
|
xf86GetNumEntityInstances(int entityIndex)
|
|
{
|
|
if (entityIndex >= xf86NumEntities)
|
|
return -1;
|
|
|
|
return xf86Entities[entityIndex]->numInstances;
|
|
}
|
|
|
|
_X_EXPORT GDevPtr
|
|
xf86GetDevFromEntity(int entityIndex, int instance)
|
|
{
|
|
int i;
|
|
|
|
/* We might not use AddDevtoEntity */
|
|
if ( (!xf86Entities[entityIndex]->devices) ||
|
|
(!xf86Entities[entityIndex]->devices[0]) )
|
|
return NULL;
|
|
|
|
if (entityIndex >= xf86NumEntities ||
|
|
instance >= xf86Entities[entityIndex]->numInstances)
|
|
return NULL;
|
|
|
|
for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++)
|
|
if (xf86Entities[entityIndex]->devices[i]->screen == instance)
|
|
break;
|
|
return xf86Entities[entityIndex]->devices[i];
|
|
}
|
|
|
|
/*
|
|
* general generic disable function.
|
|
*/
|
|
static void
|
|
disableAccess(void)
|
|
{
|
|
int i;
|
|
xf86AccessPtr pacc;
|
|
EntityAccessPtr peacc;
|
|
|
|
/* call disable funcs and reset current access pointer */
|
|
/* the entity specific access funcs are in an enabled */
|
|
/* state - driver must restore their state explicitely */
|
|
for (i = 0; i < xf86NumScreens; i++) {
|
|
peacc = xf86Screens[i]->CurrentAccess->pIoAccess;
|
|
while (peacc) {
|
|
if (peacc->pAccess && peacc->pAccess->AccessDisable)
|
|
peacc->pAccess->AccessDisable(peacc->pAccess->arg);
|
|
peacc = peacc->next;
|
|
}
|
|
xf86Screens[i]->CurrentAccess->pIoAccess = NULL;
|
|
peacc = xf86Screens[i]->CurrentAccess->pMemAccess;
|
|
while (peacc) {
|
|
if (peacc->pAccess && peacc->pAccess->AccessDisable)
|
|
peacc->pAccess->AccessDisable(peacc->pAccess->arg);
|
|
peacc = peacc->next;
|
|
}
|
|
xf86Screens[i]->CurrentAccess->pMemAccess = NULL;
|
|
}
|
|
/* then call the generic entity disable funcs */
|
|
for (i = 0; i < xf86NumEntities; i++) {
|
|
pacc = xf86Entities[i]->access->fallback;
|
|
if (pacc->AccessDisable)
|
|
pacc->AccessDisable(pacc->arg);
|
|
}
|
|
}
|
|
|
|
static void
|
|
clearAccess(void)
|
|
{
|
|
int i;
|
|
|
|
/* call disable funcs and reset current access pointer */
|
|
/* the entity specific access funcs are in an enabled */
|
|
/* state - driver must restore their state explicitely */
|
|
for (i = 0; i < xf86NumScreens; i++) {
|
|
xf86Screens[i]->CurrentAccess->pIoAccess = NULL;
|
|
xf86Screens[i]->CurrentAccess->pMemAccess = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Generic interface to bus specific code - add other buses here
|
|
*/
|
|
|
|
/*
|
|
* xf86AccessInit() - set up everything needed for access control
|
|
* called only once on first server generation.
|
|
*/
|
|
void
|
|
xf86AccessInit(void)
|
|
{
|
|
initPciState();
|
|
initPciBusState();
|
|
DisablePciBusAccess();
|
|
DisablePciAccess();
|
|
|
|
xf86ResAccessEnter = TRUE;
|
|
}
|
|
|
|
/*
|
|
* xf86AccessEnter() -- gets called to save the text mode VGA IO
|
|
* resources when reentering the server after a VT switch.
|
|
*/
|
|
void
|
|
xf86AccessEnter(void)
|
|
{
|
|
if (xf86ResAccessEnter)
|
|
return;
|
|
|
|
/*
|
|
* on enter we simply disable routing of special resources
|
|
* to any bus and let the RAC code to "open" the right bridges.
|
|
*/
|
|
PciBusStateEnter();
|
|
DisablePciBusAccess();
|
|
PciStateEnter();
|
|
disableAccess();
|
|
EntityEnter();
|
|
notifyStateChange(NOTIFY_ENTER);
|
|
xf86EnterServerState(SETUP);
|
|
xf86ResAccessEnter = TRUE;
|
|
}
|
|
|
|
/*
|
|
* xf86AccessLeave() -- prepares access for and calls the
|
|
* entityLeave() functions.
|
|
* xf86AccessLeaveState() --- gets called to restore the
|
|
* access to the VGA IO resources when switching VT or on
|
|
* server exit.
|
|
* This was split to call xf86AccessLeaveState() from
|
|
* ddxGiveUp().
|
|
*/
|
|
void
|
|
xf86AccessLeave(void)
|
|
{
|
|
if (!xf86ResAccessEnter)
|
|
return;
|
|
notifyStateChange(NOTIFY_LEAVE);
|
|
disableAccess();
|
|
DisablePciBusAccess();
|
|
EntityLeave();
|
|
}
|
|
|
|
void
|
|
xf86AccessLeaveState(void)
|
|
{
|
|
if (!xf86ResAccessEnter)
|
|
return;
|
|
xf86ResAccessEnter = FALSE;
|
|
PciStateLeave();
|
|
PciBusStateLeave();
|
|
}
|
|
|
|
/*
|
|
* xf86AccessRestoreState() - Restore the access registers to the
|
|
* state before X was started. This is handy for framebuffers.
|
|
*/
|
|
static void
|
|
xf86AccessRestoreState(void)
|
|
{
|
|
if (!xf86ResAccessEnter)
|
|
return;
|
|
PciStateLeave();
|
|
PciBusStateLeave();
|
|
}
|
|
|
|
/*
|
|
* xf86EnableAccess() -- enable access to controlled resources.
|
|
* To reduce latency when switching access the ScrnInfoRec has
|
|
* a linked list of the EntityAccPtr of all screen entities.
|
|
*/
|
|
/*
|
|
* switching access needs to be done in te following oder:
|
|
* disable
|
|
* 1. disable old entity
|
|
* 2. reroute bus
|
|
* 3. enable new entity
|
|
* Otherwise resources needed for access control might be shadowed
|
|
* by other resources!
|
|
*/
|
|
|
|
_X_EXPORT void
|
|
xf86EnableAccess(ScrnInfoPtr pScrn)
|
|
{
|
|
register EntityAccessPtr peAcc = (EntityAccessPtr) pScrn->access;
|
|
register EntityAccessPtr pceAcc;
|
|
register xf86AccessPtr pAcc;
|
|
EntityAccessPtr tmp;
|
|
|
|
#ifdef DEBUG
|
|
ErrorF("Enable access %i\n",pScrn->scrnIndex);
|
|
#endif
|
|
|
|
/* Entity is not under access control or currently enabled */
|
|
if (!pScrn->access) {
|
|
if (pScrn->busAccess) {
|
|
((BusAccPtr)pScrn->busAccess)->set_f(pScrn->busAccess);
|
|
}
|
|
return;
|
|
}
|
|
|
|
switch (pScrn->resourceType) {
|
|
case IO:
|
|
pceAcc = pScrn->CurrentAccess->pIoAccess;
|
|
if (peAcc == pceAcc) {
|
|
return;
|
|
}
|
|
if (pScrn->CurrentAccess->pMemAccess == pceAcc)
|
|
pScrn->CurrentAccess->pMemAccess = NULL;
|
|
while (pceAcc) {
|
|
pAcc = pceAcc->pAccess;
|
|
if ( pAcc && pAcc->AccessDisable)
|
|
(*pAcc->AccessDisable)(pAcc->arg);
|
|
pceAcc = pceAcc->next;
|
|
}
|
|
if (pScrn->busAccess)
|
|
((BusAccPtr)pScrn->busAccess)->set_f(pScrn->busAccess);
|
|
while (peAcc) {
|
|
pAcc = peAcc->pAccess;
|
|
if (pAcc && pAcc->AccessEnable)
|
|
(*pAcc->AccessEnable)(pAcc->arg);
|
|
peAcc = peAcc->next;
|
|
}
|
|
pScrn->CurrentAccess->pIoAccess = (EntityAccessPtr) pScrn->access;
|
|
return;
|
|
|
|
case MEM_IO:
|
|
pceAcc = pScrn->CurrentAccess->pIoAccess;
|
|
if (peAcc != pceAcc) { /* current Io != pAccess */
|
|
tmp = pceAcc;
|
|
while (pceAcc) {
|
|
pAcc = pceAcc->pAccess;
|
|
if (pAcc && pAcc->AccessDisable)
|
|
(*pAcc->AccessDisable)(pAcc->arg);
|
|
pceAcc = pceAcc->next;
|
|
}
|
|
pceAcc = pScrn->CurrentAccess->pMemAccess;
|
|
if (peAcc != pceAcc /* current Mem != pAccess */
|
|
&& tmp !=pceAcc) {
|
|
while (pceAcc) {
|
|
pAcc = pceAcc->pAccess;
|
|
if (pAcc && pAcc->AccessDisable)
|
|
(*pAcc->AccessDisable)(pAcc->arg);
|
|
pceAcc = pceAcc->next;
|
|
}
|
|
}
|
|
} else { /* current Io == pAccess */
|
|
pceAcc = pScrn->CurrentAccess->pMemAccess;
|
|
if (pceAcc == peAcc) { /* current Mem == pAccess */
|
|
return;
|
|
}
|
|
while (pceAcc) { /* current Mem != pAccess */
|
|
pAcc = pceAcc->pAccess;
|
|
if (pAcc && pAcc->AccessDisable)
|
|
(*pAcc->AccessDisable)(pAcc->arg);
|
|
pceAcc = pceAcc->next;
|
|
}
|
|
}
|
|
if (pScrn->busAccess)
|
|
((BusAccPtr)pScrn->busAccess)->set_f(pScrn->busAccess);
|
|
while (peAcc) {
|
|
pAcc = peAcc->pAccess;
|
|
if (pAcc && pAcc->AccessEnable)
|
|
(*pAcc->AccessEnable)(pAcc->arg);
|
|
peAcc = peAcc->next;
|
|
}
|
|
pScrn->CurrentAccess->pMemAccess =
|
|
pScrn->CurrentAccess->pIoAccess = (EntityAccessPtr) pScrn->access;
|
|
return;
|
|
|
|
case MEM:
|
|
pceAcc = pScrn->CurrentAccess->pMemAccess;
|
|
if (peAcc == pceAcc) {
|
|
return;
|
|
}
|
|
if (pScrn->CurrentAccess->pIoAccess == pceAcc)
|
|
pScrn->CurrentAccess->pIoAccess = NULL;
|
|
while (pceAcc) {
|
|
pAcc = pceAcc->pAccess;
|
|
if ( pAcc && pAcc->AccessDisable)
|
|
(*pAcc->AccessDisable)(pAcc->arg);
|
|
pceAcc = pceAcc->next;
|
|
}
|
|
if (pScrn->busAccess)
|
|
((BusAccPtr)pScrn->busAccess)->set_f(pScrn->busAccess);
|
|
while (peAcc) {
|
|
pAcc = peAcc->pAccess;
|
|
if (pAcc && pAcc->AccessEnable)
|
|
(*pAcc->AccessEnable)(pAcc->arg);
|
|
peAcc = peAcc->next;
|
|
}
|
|
pScrn->CurrentAccess->pMemAccess = (EntityAccessPtr) pScrn->access;
|
|
return;
|
|
|
|
case NONE:
|
|
if (pScrn->busAccess) {
|
|
((BusAccPtr)pScrn->busAccess)->set_f(pScrn->busAccess);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86SetCurrentAccess(Bool Enable, ScrnInfoPtr pScrn)
|
|
{
|
|
EntityAccessPtr pceAcc2 = NULL;
|
|
register EntityAccessPtr pceAcc = NULL;
|
|
register xf86AccessPtr pAcc;
|
|
|
|
|
|
switch(pScrn->resourceType) {
|
|
case IO:
|
|
pceAcc = pScrn->CurrentAccess->pIoAccess;
|
|
break;
|
|
case MEM:
|
|
pceAcc = pScrn->CurrentAccess->pMemAccess;
|
|
break;
|
|
case MEM_IO:
|
|
pceAcc = pScrn->CurrentAccess->pMemAccess;
|
|
pceAcc2 = pScrn->CurrentAccess->pIoAccess;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
while (pceAcc) {
|
|
pAcc = pceAcc->pAccess;
|
|
if ( pAcc) {
|
|
if (!Enable) {
|
|
if (pAcc->AccessDisable)
|
|
(*pAcc->AccessDisable)(pAcc->arg);
|
|
} else {
|
|
if (pAcc->AccessEnable)
|
|
(*pAcc->AccessEnable)(pAcc->arg);
|
|
}
|
|
}
|
|
pceAcc = pceAcc->next;
|
|
if (!pceAcc) {
|
|
pceAcc = pceAcc2;
|
|
pceAcc2 = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86SetAccessFuncs(EntityInfoPtr pEnt, xf86SetAccessFuncPtr funcs,
|
|
xf86SetAccessFuncPtr oldFuncs)
|
|
{
|
|
AccessFuncPtr rac;
|
|
|
|
if (!xf86Entities[pEnt->index]->rac)
|
|
xf86Entities[pEnt->index]->rac = xnfcalloc(1,sizeof(AccessFuncRec));
|
|
|
|
rac = xf86Entities[pEnt->index]->rac;
|
|
|
|
if (funcs->mem == funcs->io_mem && funcs->mem && funcs->io)
|
|
xf86Entities[pEnt->index]->entityProp |= NO_SEPARATE_MEM_FROM_IO;
|
|
if (funcs->io == funcs->io_mem && funcs->mem && funcs->io)
|
|
xf86Entities[pEnt->index]->entityProp |= NO_SEPARATE_IO_FROM_MEM;
|
|
|
|
rac->mem_new = funcs->mem;
|
|
rac->io_new = funcs->io;
|
|
rac->io_mem_new = funcs->io_mem;
|
|
|
|
rac->old = oldFuncs;
|
|
}
|
|
|
|
/*
|
|
* Conflict checking
|
|
*/
|
|
|
|
static memType
|
|
getMask(memType val)
|
|
{
|
|
memType mask = 0;
|
|
memType tmp = 0;
|
|
|
|
mask=~mask;
|
|
tmp = ~((~tmp) >> 1);
|
|
|
|
while (!(val & tmp)) {
|
|
mask = mask >> 1;
|
|
val = val << 1;
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
/*
|
|
* checkConflictBlock() -- check for conflicts of a block resource range.
|
|
* If conflict is found return end of conflicting range. Else return 0.
|
|
*/
|
|
static memType
|
|
checkConflictBlock(resRange *range, resPtr pRes)
|
|
{
|
|
memType val,tmp,prev;
|
|
int i;
|
|
|
|
switch (pRes->res_type & ResExtMask) {
|
|
case ResBlock:
|
|
if (range->rBegin < pRes->block_end &&
|
|
range->rEnd > pRes->block_begin) {
|
|
#ifdef DEBUG
|
|
ErrorF("b-b conflict w: %lx %lx\n",
|
|
pRes->block_begin,pRes->block_end);
|
|
#endif
|
|
return pRes->block_end < range->rEnd ?
|
|
pRes->block_end : range->rEnd;
|
|
}
|
|
return 0;
|
|
case ResSparse:
|
|
if (pRes->sparse_base > range->rEnd) return 0;
|
|
|
|
val = (~pRes->sparse_mask | pRes->sparse_base) & getMask(range->rEnd);
|
|
#ifdef DEBUG
|
|
ErrorF("base = 0x%lx, mask = 0x%lx, begin = 0x%lx, end = 0x%lx ,"
|
|
"val = 0x%lx\n",
|
|
pRes->sparse_base, pRes->sparse_mask, range->rBegin,
|
|
range->rEnd, val);
|
|
#endif
|
|
i = sizeof(memType) * 8;
|
|
tmp = prev = pRes->sparse_base;
|
|
|
|
while (i) {
|
|
tmp |= 1<< (--i) & val;
|
|
if (tmp > range->rEnd)
|
|
tmp = prev;
|
|
else
|
|
prev = tmp;
|
|
}
|
|
if (tmp >= range->rBegin) {
|
|
#ifdef DEBUG
|
|
ErrorF("conflict found at: 0x%lx\n",tmp);
|
|
ErrorF("b-d conflict w: %lx %lx\n",
|
|
pRes->sparse_base,pRes->sparse_mask);
|
|
#endif
|
|
return tmp;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* checkConflictSparse() -- check for conflicts of a sparse resource range.
|
|
* If conflict is found return base of conflicting region. Else return 0.
|
|
*/
|
|
#define mt_max ~(memType)0
|
|
#define length sizeof(memType) * 8
|
|
static memType
|
|
checkConflictSparse(resRange *range, resPtr pRes)
|
|
{
|
|
memType val, tmp, prev;
|
|
int i;
|
|
|
|
switch (pRes->res_type & ResExtMask) {
|
|
case ResSparse:
|
|
tmp = pRes->sparse_mask & range->rMask;
|
|
if ((tmp & pRes->sparse_base) == (tmp & range->rBase)) {
|
|
#ifdef DEBUG
|
|
ErrorF("s-b conflict w: %lx %lx\n",
|
|
pRes->sparse_base,pRes->sparse_mask);
|
|
#endif
|
|
return pRes->sparse_mask;
|
|
}
|
|
return 0;
|
|
|
|
case ResBlock:
|
|
if (pRes->block_end < range->rBase) return 0;
|
|
|
|
val = (~range->rMask | range->rBase) & getMask(pRes->block_end);
|
|
i = length;
|
|
tmp = prev = range->rBase;
|
|
|
|
while (i) {
|
|
#ifdef DEBUG
|
|
ErrorF("tmp = 0x%lx\n",tmp);
|
|
#endif
|
|
tmp |= 1<< (--i) & val;
|
|
if (tmp > pRes->block_end)
|
|
tmp = prev;
|
|
else
|
|
prev = tmp;
|
|
}
|
|
if (tmp < pRes->block_begin)
|
|
return 0;
|
|
else {
|
|
/*
|
|
* now we subdivide the block region in sparse regions
|
|
* with base values = 2^n and find the smallest mask.
|
|
* This might be done in a simpler way....
|
|
*/
|
|
memType mask, m_mask = 0, base = pRes->block_begin;
|
|
int i;
|
|
while (base < pRes->block_end) {
|
|
for (i = 1; i < length; i++)
|
|
if ( base != (base & (mt_max << i))) break;
|
|
mask = mt_max >> (length - i);
|
|
do mask >>= 1;
|
|
while ((mask + base + 1) > pRes->block_end);
|
|
/* m_mask and are _inverted_ sparse masks */
|
|
m_mask = mask > m_mask ? mask : m_mask;
|
|
base = base + mask + 1;
|
|
}
|
|
#ifdef DEBUG
|
|
ErrorF("conflict found at: 0x%lx\n",tmp);
|
|
ErrorF("b-b conflict w: %lx %lx\n",
|
|
pRes->block_begin,pRes->block_end);
|
|
#endif
|
|
return ~m_mask;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#undef mt_max
|
|
#undef length
|
|
|
|
/*
|
|
* needCheck() -- this function decides whether to check for conflicts
|
|
* depending on the types of the resource ranges and their locations
|
|
*/
|
|
static Bool
|
|
needCheck(resPtr pRes, unsigned long type, int entityIndex, xf86State state)
|
|
{
|
|
/* the same entity shouldn't conflict with itself */
|
|
ScrnInfoPtr pScrn;
|
|
int i;
|
|
BusType loc = BUS_NONE;
|
|
BusType r_loc = BUS_NONE;
|
|
|
|
/* Ignore overlapped ranges that have been nullified */
|
|
if ((pRes->res_type & ResOverlap) && (pRes->block_begin > pRes->block_end))
|
|
return FALSE;
|
|
|
|
if ((pRes->res_type & ResTypeMask) != (type & ResTypeMask))
|
|
return FALSE;
|
|
|
|
/*
|
|
* Resources set by BIOS (ResBios) are allowed to conflict
|
|
* with resources marked (ResBios).
|
|
*/
|
|
if (pRes->res_type & type & ResBios)
|
|
return FALSE;
|
|
|
|
/*If requested, skip over estimated resources */
|
|
if (pRes->res_type & type & ResEstimated)
|
|
return FALSE;
|
|
|
|
if (type & pRes->res_type & ResUnused)
|
|
return FALSE;
|
|
|
|
if (state == OPERATING) {
|
|
if (type & ResDisableOpr || pRes->res_type & ResDisableOpr)
|
|
return FALSE;
|
|
if (type & pRes->res_type & ResUnusedOpr) return FALSE;
|
|
/*
|
|
* Maybe we should have ResUnused set The resUnusedOpr
|
|
* bit, too. This way we could avoid this confusion
|
|
*/
|
|
if ((type & ResUnusedOpr && pRes->res_type & ResUnused) ||
|
|
(type & ResUnused && pRes->res_type & ResUnusedOpr))
|
|
return FALSE;
|
|
}
|
|
|
|
if (entityIndex > -1)
|
|
loc = xf86Entities[entityIndex]->busType;
|
|
if (pRes->entityIndex > -1)
|
|
r_loc = xf86Entities[pRes->entityIndex]->busType;
|
|
|
|
switch (type & ResAccMask) {
|
|
case ResExclusive:
|
|
switch (pRes->res_type & ResAccMask) {
|
|
case ResExclusive:
|
|
break;
|
|
case ResShared:
|
|
/* ISA buses are only locally exclusive on a PCI system */
|
|
if (loc == BUS_ISA && r_loc == BUS_PCI)
|
|
return FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
case ResShared:
|
|
switch (pRes->res_type & ResAccMask) {
|
|
case ResExclusive:
|
|
/* ISA buses are only locally exclusive on a PCI system */
|
|
if (loc == BUS_PCI && r_loc == BUS_ISA)
|
|
return FALSE;
|
|
break;
|
|
case ResShared:
|
|
return FALSE;
|
|
}
|
|
break;
|
|
case ResAny:
|
|
break;
|
|
}
|
|
|
|
if (pRes->entityIndex == entityIndex) return FALSE;
|
|
|
|
if (pRes->entityIndex > -1 &&
|
|
(pScrn = xf86FindScreenForEntity(entityIndex))) {
|
|
for (i = 0; i < pScrn->numEntities; i++)
|
|
if (pScrn->entityList[i] == pRes->entityIndex) return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* checkConflict() - main conflict checking function which all other
|
|
* function call.
|
|
*/
|
|
static memType
|
|
checkConflict(resRange *rgp, resPtr pRes, int entityIndex,
|
|
xf86State state, Bool ignoreIdentical)
|
|
{
|
|
memType ret;
|
|
|
|
while(pRes) {
|
|
if (!needCheck(pRes,rgp->type, entityIndex ,state)) {
|
|
pRes = pRes->next;
|
|
continue;
|
|
}
|
|
switch (rgp->type & ResExtMask) {
|
|
case ResBlock:
|
|
if (rgp->rEnd < rgp->rBegin) {
|
|
xf86Msg(X_ERROR,"end of block range 0x%lx < begin 0x%lx\n",
|
|
rgp->rEnd,rgp->rBegin);
|
|
return 0;
|
|
}
|
|
if ((ret = checkConflictBlock(rgp, pRes))) {
|
|
if (!ignoreIdentical || (rgp->rBegin != pRes->block_begin)
|
|
|| (rgp->rEnd != pRes->block_end))
|
|
return ret;
|
|
}
|
|
break;
|
|
case ResSparse:
|
|
if ((rgp->rBase & rgp->rMask) != rgp->rBase) {
|
|
xf86Msg(X_ERROR,"sparse io range (base: 0x%lx mask: 0x%lx)"
|
|
"doesn't satisfy (base & mask = mask)\n",
|
|
rgp->rBase, rgp->rMask);
|
|
return 0;
|
|
}
|
|
if ((ret = checkConflictSparse(rgp, pRes))) {
|
|
if (!ignoreIdentical || (rgp->rBase != pRes->sparse_base)
|
|
|| (rgp->rMask != pRes->sparse_mask))
|
|
return ret;
|
|
}
|
|
break;
|
|
}
|
|
pRes = pRes->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ChkConflict() -- used within xxxBus ; find conflict with any location.
|
|
*/
|
|
memType
|
|
ChkConflict(resRange *rgp, resPtr res, xf86State state)
|
|
{
|
|
return checkConflict(rgp, res, -2, state,FALSE);
|
|
}
|
|
|
|
/*
|
|
* xf86ChkConflict() - This function is the low level interface to
|
|
* the resource broker that gets exported. Tests all resources ie.
|
|
* performs test with SETUP flag.
|
|
*/
|
|
_X_EXPORT memType
|
|
xf86ChkConflict(resRange *rgp, int entityIndex)
|
|
{
|
|
return checkConflict(rgp, Acc, entityIndex, SETUP,FALSE);
|
|
}
|
|
|
|
/*
|
|
* Resources List handling
|
|
*/
|
|
|
|
_X_EXPORT resPtr
|
|
xf86JoinResLists(resPtr rlist1, resPtr rlist2)
|
|
{
|
|
resPtr pRes;
|
|
|
|
if (!rlist1)
|
|
return rlist2;
|
|
|
|
if (!rlist2)
|
|
return rlist1;
|
|
|
|
for (pRes = rlist1; pRes->next; pRes = pRes->next)
|
|
;
|
|
pRes->next = rlist2;
|
|
return rlist1;
|
|
}
|
|
|
|
_X_EXPORT resPtr
|
|
xf86AddResToList(resPtr rlist, resRange *range, int entityIndex)
|
|
{
|
|
resPtr new;
|
|
|
|
switch (range->type & ResExtMask) {
|
|
case ResBlock:
|
|
if (range->rEnd < range->rBegin) {
|
|
xf86Msg(X_ERROR,"end of block range 0x%lx < begin 0x%lx\n",
|
|
range->rEnd,range->rBegin);
|
|
return rlist;
|
|
}
|
|
break;
|
|
case ResSparse:
|
|
if ((range->rBase & range->rMask) != range->rBase) {
|
|
xf86Msg(X_ERROR,"sparse io range (base: 0x%lx mask: 0x%lx)"
|
|
"doesn't satisfy (base & mask = mask)\n",
|
|
range->rBase, range->rMask);
|
|
return rlist;
|
|
}
|
|
break;
|
|
}
|
|
|
|
new = xnfalloc(sizeof(resRec));
|
|
/*
|
|
* Only background resources may be registered with ResBios
|
|
* and ResEstimated set. Other resources only set it for
|
|
* testing.
|
|
*/
|
|
if (entityIndex != (-1))
|
|
range->type &= ~(ResBios | ResEstimated);
|
|
new->val = *range;
|
|
new->entityIndex = entityIndex;
|
|
new->next = rlist;
|
|
return new;
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86FreeResList(resPtr rlist)
|
|
{
|
|
resPtr pRes;
|
|
|
|
if (!rlist)
|
|
return;
|
|
|
|
for (pRes = rlist->next; pRes; rlist = pRes, pRes = pRes->next)
|
|
xfree(rlist);
|
|
xfree(rlist);
|
|
}
|
|
|
|
_X_EXPORT resPtr
|
|
xf86DupResList(const resPtr rlist)
|
|
{
|
|
resPtr pRes, ret, prev, new;
|
|
|
|
if (!rlist)
|
|
return NULL;
|
|
|
|
ret = xnfalloc(sizeof(resRec));
|
|
*ret = *rlist;
|
|
prev = ret;
|
|
for (pRes = rlist->next; pRes; pRes = pRes->next) {
|
|
new = xnfalloc(sizeof(resRec));
|
|
*new = *pRes;
|
|
prev->next = new;
|
|
prev = new;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86PrintResList(int verb, resPtr list)
|
|
{
|
|
int i = 0;
|
|
const char *s, *r;
|
|
resPtr tmp = list;
|
|
unsigned long type;
|
|
|
|
if (!list)
|
|
return;
|
|
|
|
type = ResMem;
|
|
r = "M";
|
|
while (1) {
|
|
while (list) {
|
|
if ((list->res_type & ResPhysMask) == type) {
|
|
switch (list->res_type & ResExtMask) {
|
|
case ResBlock:
|
|
xf86ErrorFVerb(verb,
|
|
"\t[%d] %d\t%ld\t0x%08lx - 0x%08lx (0x%lx)",
|
|
i, list->entityIndex,
|
|
(list->res_type & ResDomain) >> 24,
|
|
list->block_begin, list->block_end,
|
|
list->block_end - list->block_begin + 1);
|
|
break;
|
|
case ResSparse:
|
|
xf86ErrorFVerb(verb, "\t[%d] %d\t%ld\t0x%08lx - 0x%08lx ",
|
|
i, list->entityIndex,
|
|
(list->res_type & ResDomain) >> 24,
|
|
list->sparse_base,list->sparse_mask);
|
|
break;
|
|
default:
|
|
list = list->next;
|
|
continue;
|
|
}
|
|
xf86ErrorFVerb(verb, " %s", r);
|
|
switch (list->res_type & ResAccMask) {
|
|
case ResExclusive:
|
|
if (list->res_type & ResUnused)
|
|
s = "x";
|
|
else
|
|
s = "X";
|
|
break;
|
|
case ResShared:
|
|
if (list->res_type & ResUnused)
|
|
s = "s";
|
|
else
|
|
s = "S";
|
|
break;
|
|
default:
|
|
s = "?";
|
|
}
|
|
xf86ErrorFVerb(verb, "%s", s);
|
|
switch (list->res_type & ResExtMask) {
|
|
case ResBlock:
|
|
s = "[B]";
|
|
break;
|
|
case ResSparse:
|
|
s = "[S]";
|
|
break;
|
|
default:
|
|
s = "[?]";
|
|
}
|
|
xf86ErrorFVerb(verb, "%s", s);
|
|
if (list->res_type & ResEstimated)
|
|
xf86ErrorFVerb(verb, "E");
|
|
if (list->res_type & ResOverlap)
|
|
xf86ErrorFVerb(verb, "O");
|
|
if (list->res_type & ResInit)
|
|
xf86ErrorFVerb(verb, "t");
|
|
if (list->res_type & ResBios)
|
|
xf86ErrorFVerb(verb, "(B)");
|
|
if (list->res_type & ResBus)
|
|
xf86ErrorFVerb(verb, "(b)");
|
|
if (list->res_type & ResOprMask) {
|
|
switch (list->res_type & ResOprMask) {
|
|
case ResUnusedOpr:
|
|
s = "(OprU)";
|
|
break;
|
|
case ResDisableOpr:
|
|
s = "(OprD)";
|
|
break;
|
|
default:
|
|
s = "(Opr?)";
|
|
break;
|
|
}
|
|
xf86ErrorFVerb(verb, "%s", s);
|
|
}
|
|
xf86ErrorFVerb(verb, "\n");
|
|
i++;
|
|
}
|
|
list = list->next;
|
|
}
|
|
if (type == ResIo) break;
|
|
type = ResIo;
|
|
r = "I";
|
|
list = tmp;
|
|
}
|
|
}
|
|
|
|
resPtr
|
|
xf86AddRangesToList(resPtr list, resRange *pRange, int entityIndex)
|
|
{
|
|
while(pRange && pRange->type != ResEnd) {
|
|
list = xf86AddResToList(list,pRange,entityIndex);
|
|
pRange++;
|
|
}
|
|
return list;
|
|
}
|
|
|
|
void
|
|
xf86ResourceBrokerInit(void)
|
|
{
|
|
resPtr resPci;
|
|
|
|
osRes = NULL;
|
|
|
|
/* Get the addressable ranges */
|
|
ResRange = xf86BusAccWindowsFromOS();
|
|
xf86MsgVerb(X_INFO, 3, "Addressable bus resource ranges are\n");
|
|
xf86PrintResList(3, ResRange);
|
|
|
|
/* Get the ranges used exclusively by the system */
|
|
osRes = xf86AccResFromOS(osRes);
|
|
xf86MsgVerb(X_INFO, 3, "OS-reported resource ranges:\n");
|
|
xf86PrintResList(3, osRes);
|
|
|
|
/* Bus dep initialization */
|
|
resPci = ResourceBrokerInitPci(&osRes);
|
|
Acc = xf86JoinResLists(xf86DupResList(osRes), resPci);
|
|
|
|
xf86MsgVerb(X_INFO, 3, "All system resource ranges:\n");
|
|
xf86PrintResList(3, Acc);
|
|
|
|
}
|
|
|
|
#define MEM_ALIGN (1024 * 1024)
|
|
|
|
/*
|
|
* RemoveOverlaps() -- remove overlaps between resources of the
|
|
* same kind.
|
|
* Beware: This function doesn't check for access attributes.
|
|
* At resource broker initialization this is no problem as this
|
|
* only deals with exclusive resources.
|
|
*/
|
|
#if 0
|
|
void
|
|
RemoveOverlaps(resPtr target, resPtr list, Bool pow2Alignment, Bool useEstimated)
|
|
{
|
|
resPtr pRes;
|
|
memType size, newsize, adjust;
|
|
|
|
if (!target)
|
|
return;
|
|
|
|
for (pRes = list; pRes; pRes = pRes->next) {
|
|
if (pRes != target
|
|
&& ((pRes->res_type & ResTypeMask) ==
|
|
(target->res_type & ResTypeMask))
|
|
&& pRes->block_begin <= target->block_end
|
|
&& pRes->block_end >= target->block_begin) {
|
|
/* Possibly ignore estimated resources */
|
|
if (!useEstimated && (pRes->res_type & ResEstimated)) continue;
|
|
/*
|
|
* Target should be a larger region than pRes. If pRes fully
|
|
* contains target, don't do anything unless target can overlap.
|
|
*/
|
|
if (pRes->block_begin <= target->block_begin &&
|
|
pRes->block_end >= target->block_end) {
|
|
if (target->res_type & ResOverlap) {
|
|
/* Nullify range but keep its ResOverlap bit on */
|
|
target->block_end = target->block_begin - 1;
|
|
return;
|
|
}
|
|
continue;
|
|
}
|
|
/*
|
|
* In cases where the target and pRes have the same starting
|
|
* address, reduce the size of the target (given it's an estimate).
|
|
*/
|
|
if (pRes->block_begin == target->block_begin) {
|
|
if (target->res_type & ResOverlap)
|
|
target->block_end = target->block_begin - 1;
|
|
else
|
|
target->block_end = pRes->block_end;
|
|
}
|
|
/* Otherwise, trim target to remove the overlap */
|
|
else if (pRes->block_begin <= target->block_end) {
|
|
target->block_end = pRes->block_begin - 1;
|
|
} else if (!pow2Alignment &&
|
|
pRes->block_end >= target->block_begin) {
|
|
target->block_begin = pRes->block_end + 1;
|
|
}
|
|
if (pow2Alignment) {
|
|
/*
|
|
* Align to a power of two. This requires finding the
|
|
* largest power of two that is smaller than the adjusted
|
|
* size.
|
|
*/
|
|
size = target->block_end - target->block_begin + 1;
|
|
newsize = 1UL << (sizeof(memType) * 8 - 1);
|
|
while (!(newsize & size))
|
|
newsize >>= 1;
|
|
target->block_end = target->block_begin + newsize - 1;
|
|
} else if (target->block_end > MEM_ALIGN) {
|
|
/* Align the end to MEM_ALIGN */
|
|
if ((adjust = (target->block_end + 1) % MEM_ALIGN))
|
|
target->block_end -= adjust;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
|
|
void
|
|
RemoveOverlaps(resPtr target, resPtr list, Bool pow2Alignment, Bool useEstimated)
|
|
{
|
|
resPtr pRes;
|
|
memType size, newsize, adjust;
|
|
|
|
if (!target)
|
|
return;
|
|
|
|
if (!(target->res_type & ResEstimated) /* Don't touch sure resources */
|
|
&& !(target->res_type & ResOverlap)) /* Unless they may overlap */
|
|
return;
|
|
|
|
for (pRes = list; pRes; pRes = pRes->next) {
|
|
if (pRes == target
|
|
|| ((pRes->res_type & ResTypeMask) !=
|
|
(target->res_type & ResTypeMask))
|
|
|| pRes->block_begin > target->block_end
|
|
|| pRes->block_end < target->block_begin)
|
|
continue;
|
|
|
|
if (pRes->block_begin <= target->block_begin) {
|
|
/* Possibly ignore estimated resources */
|
|
if (!useEstimated && (pRes->res_type & ResEstimated))
|
|
continue;
|
|
|
|
/* Special cases */
|
|
if (pRes->block_end >= target->block_end) {
|
|
/*
|
|
* If pRes fully contains target, don't do anything
|
|
* unless target can overlap.
|
|
*/
|
|
if (target->res_type & ResOverlap) {
|
|
/* Nullify range but keep its ResOverlap bit on */
|
|
target->block_end = target->block_begin - 1;
|
|
return;
|
|
} else
|
|
continue;
|
|
} else {
|
|
#if 0 /* Don't trim start address - we trust what we got */
|
|
/*
|
|
* If !pow2Alignment trim start address: !pow2Alingment
|
|
* is only set when estimated OS addresses are handled.
|
|
* In cases where the target and pRes have the same
|
|
* starting address, reduce the size of the target
|
|
* (given it's an estimate).
|
|
*/
|
|
if (!pow2Alignment)
|
|
target->block_begin = pRes->block_end + 1;
|
|
else
|
|
#endif
|
|
if (pRes->block_begin == target->block_begin)
|
|
target->block_end = pRes->block_end;
|
|
else
|
|
continue;
|
|
}
|
|
} else {
|
|
/* Trim target to remove the overlap */
|
|
target->block_end = pRes->block_begin - 1;
|
|
}
|
|
if (pow2Alignment) {
|
|
/*
|
|
* Align to a power of two. This requires finding the
|
|
* largest power of two that is smaller than the adjusted
|
|
* size.
|
|
*/
|
|
size = target->block_end - target->block_begin + 1;
|
|
newsize = 1UL << (sizeof(memType) * 8 - 1);
|
|
while (!(newsize & size))
|
|
newsize >>= 1;
|
|
target->block_end = target->block_begin + newsize - 1;
|
|
} else if (target->block_end > MEM_ALIGN) {
|
|
/* Align the end to MEM_ALIGN */
|
|
if ((adjust = (target->block_end + 1) % MEM_ALIGN))
|
|
target->block_end -= adjust;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Resource request code
|
|
*/
|
|
|
|
#define ALIGN(x,a) ((x) + a) &~(a)
|
|
|
|
_X_EXPORT resRange
|
|
xf86GetBlock(unsigned long type, memType size,
|
|
memType window_start, memType window_end,
|
|
memType align_mask, resPtr avoid)
|
|
{
|
|
memType min, max, tmp;
|
|
resRange r = {ResEnd,0,0};
|
|
resPtr res_range = ResRange;
|
|
|
|
if (!size) return r;
|
|
if (window_end < window_start || (window_end - window_start) < (size - 1)) {
|
|
ErrorF("Requesting insufficient memory window!:"
|
|
" start: 0x%lx end: 0x%lx size 0x%lx\n",
|
|
window_start,window_end,size);
|
|
return r;
|
|
}
|
|
type = (type & ~(ResExtMask | ResBios | ResEstimated)) | ResBlock;
|
|
|
|
while (res_range) {
|
|
if ((type & ResTypeMask) == (res_range->res_type & ResTypeMask)) {
|
|
if (res_range->block_begin > window_start)
|
|
min = res_range->block_begin;
|
|
else
|
|
min = window_start;
|
|
if (res_range->block_end < window_end)
|
|
max = res_range->block_end;
|
|
else
|
|
max = window_end;
|
|
min = ALIGN(min,align_mask);
|
|
/* do not produce an overflow! */
|
|
while (min < max && (max - min) >= (size - 1)) {
|
|
RANGE(r,min,min + size - 1,type);
|
|
tmp = ChkConflict(&r,Acc,SETUP);
|
|
if (!tmp) {
|
|
tmp = ChkConflict(&r,avoid,SETUP);
|
|
if (!tmp) {
|
|
return r;
|
|
}
|
|
}
|
|
min = ALIGN(tmp,align_mask);
|
|
}
|
|
}
|
|
res_range = res_range->next;
|
|
}
|
|
RANGE(r,0,0,ResEnd);
|
|
return r;
|
|
}
|
|
|
|
#define mt_max ~(memType)0
|
|
#define length sizeof(memType) * 8
|
|
/*
|
|
* make_base() -- assign the lowest bits to the bits set in mask.
|
|
* example: mask 011010 val 0000110 -> 011000
|
|
*/
|
|
static memType
|
|
make_base(memType val, memType mask)
|
|
{
|
|
int i,j = 0;
|
|
memType ret = 0
|
|
;
|
|
for (i = 0;i<length;i++) {
|
|
if ((1 << i) & mask) {
|
|
ret |= (((val >> j) & 1) << i);
|
|
j++;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* make_base() -- assign the bits set in mask to the lowest bits.
|
|
* example: mask 011010 , val 010010 -> 000011
|
|
*/
|
|
static memType
|
|
unmake_base(memType val, memType mask)
|
|
{
|
|
int i,j = 0;
|
|
memType ret = 0;
|
|
|
|
for (i = 0;i<length;i++) {
|
|
if ((1 << i) & mask) {
|
|
ret |= (((val >> i) & 1) << j);
|
|
j++;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static memType
|
|
fix_counter(memType val, memType old_mask, memType mask)
|
|
{
|
|
mask = old_mask & mask;
|
|
|
|
val = make_base(val,old_mask);
|
|
return unmake_base(val,mask);
|
|
}
|
|
|
|
_X_EXPORT resRange
|
|
xf86GetSparse(unsigned long type, memType fixed_bits,
|
|
memType decode_mask, memType address_mask, resPtr avoid)
|
|
{
|
|
resRange r = {ResEnd,0,0};
|
|
memType new_mask;
|
|
memType mask1;
|
|
memType base;
|
|
memType counter = 0;
|
|
memType counter1;
|
|
memType max_counter = ~(memType)0;
|
|
memType max_counter1;
|
|
memType conflict = 0;
|
|
|
|
/* for sanity */
|
|
type = (type & ~(ResExtMask | ResBios | ResEstimated)) | ResSparse;
|
|
|
|
/*
|
|
* a sparse address consists of 3 parts:
|
|
* fixed_bits: F bits which hard decoded by the hardware
|
|
* decode_bits: D bits which are used to decode address
|
|
* but which may be set by software
|
|
* address_bits: A bits which are used to address the
|
|
* sparse range.
|
|
* the decode_mask marks all decode bits while the address_mask
|
|
* masks out all address_bits:
|
|
* F D A
|
|
* decode_mask: 0 1 0
|
|
* address_mask: 1 1 0
|
|
*/
|
|
decode_mask &= address_mask;
|
|
new_mask = decode_mask;
|
|
|
|
/*
|
|
* We start by setting the decode_mask bits to different values
|
|
* when a conflict is found the address_mask of the conflicting
|
|
* resource is returned. We remove those bits from decode_mask
|
|
* that are also set in the returned address_mask as they always
|
|
* conflict with resources which use them as address masks.
|
|
* The resoulting mask is stored in new_mask.
|
|
* We continue until no conflict is found or until we have
|
|
* tried all possible settings of new_mask.
|
|
*/
|
|
while (1) {
|
|
base = make_base(counter,new_mask) | fixed_bits;
|
|
RANGE(r,base,address_mask,type);
|
|
conflict = ChkConflict(&r,Acc,SETUP);
|
|
if (!conflict) {
|
|
conflict = ChkConflict(&r,avoid,SETUP);
|
|
if (!conflict) {
|
|
return r;
|
|
}
|
|
}
|
|
counter = fix_counter(counter,new_mask,conflict);
|
|
max_counter = fix_counter(max_counter,new_mask,conflict);
|
|
new_mask &= conflict;
|
|
counter ++;
|
|
if (counter > max_counter) break;
|
|
}
|
|
if (!new_mask && (new_mask == decode_mask)) {
|
|
RANGE(r,0,0,ResEnd);
|
|
return r;
|
|
}
|
|
/*
|
|
* if we haven't been successful we also try to modify those
|
|
* bits in decode_mask that are not at the same time set in
|
|
* new mask. These bits overlap with address_bits of some
|
|
* resources. If a conflict with a resource of this kind is
|
|
* found (ie. returned_mask & mask1 != mask1) with
|
|
* mask1 = decode_mask & ~new_mask we cannot
|
|
* use our choice of bits in the new_mask part. We try
|
|
* another choice.
|
|
*/
|
|
max_counter = fix_counter(mt_max,mt_max,new_mask);
|
|
mask1 = decode_mask & ~new_mask;
|
|
max_counter1 = fix_counter(mt_max,mt_max,mask1);
|
|
counter = 0;
|
|
|
|
while (1) {
|
|
counter1 = 0;
|
|
while (1) {
|
|
base = make_base(counter1,mask1);
|
|
RANGE(r,base,address_mask,type);
|
|
conflict = ChkConflict(&r,Acc,SETUP);
|
|
if (!conflict) {
|
|
conflict = ChkConflict(&r,avoid,SETUP);
|
|
if (!conflict) {
|
|
return r;
|
|
}
|
|
}
|
|
counter1 ++;
|
|
if ((mask1 & conflict) != mask1 || counter1 > max_counter1)
|
|
break;
|
|
}
|
|
counter ++;
|
|
if (counter > max_counter) break;
|
|
}
|
|
RANGE(r,0,0,ResEnd);
|
|
return r;
|
|
}
|
|
|
|
#undef length
|
|
#undef mt_max
|
|
|
|
/*
|
|
* Resource registrarion
|
|
*/
|
|
|
|
static resList
|
|
xf86GetResourcesImplicitly(int entityIndex)
|
|
{
|
|
if (entityIndex >= xf86NumEntities) return NULL;
|
|
|
|
switch (xf86Entities[entityIndex]->bus.type) {
|
|
case BUS_ISA:
|
|
case BUS_NONE:
|
|
case BUS_SBUS:
|
|
return NULL;
|
|
case BUS_PCI:
|
|
return GetImplicitPciResources(entityIndex);
|
|
case BUS_last:
|
|
return NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
convertRange2Host(int entityIndex, resRange *pRange)
|
|
{
|
|
if (pRange->type & ResBus) {
|
|
switch (xf86Entities[entityIndex]->busType) {
|
|
case BUS_PCI:
|
|
pciConvertRange2Host(entityIndex,pRange);
|
|
break;
|
|
case BUS_ISA:
|
|
isaConvertRange2Host(pRange);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
pRange->type &= ~ResBus;
|
|
}
|
|
}
|
|
|
|
static void
|
|
xf86ConvertListToHost(int entityIndex, resPtr list)
|
|
{
|
|
while (list) {
|
|
convertRange2Host(entityIndex, &list->val);
|
|
list = list->next;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* xf86RegisterResources() -- attempts to register listed resources.
|
|
* If list is NULL it tries to obtain resources implicitly. Function
|
|
* returns a resPtr listing all resources not successfully registered.
|
|
*/
|
|
|
|
_X_EXPORT resPtr
|
|
xf86RegisterResources(int entityIndex, resList list, unsigned long access)
|
|
{
|
|
resPtr res = NULL;
|
|
resRange range;
|
|
resList list_f = NULL;
|
|
|
|
if (!list) {
|
|
list = xf86GetResourcesImplicitly(entityIndex);
|
|
/* these resources have to be in host address space already */
|
|
if (!list) return NULL;
|
|
list_f = list;
|
|
}
|
|
|
|
while(list->type != ResEnd) {
|
|
range = *list;
|
|
|
|
convertRange2Host(entityIndex,&range);
|
|
|
|
if ((access != ResNone) && (access & ResAccMask)) {
|
|
range.type = (range.type & ~ResAccMask) | (access & ResAccMask);
|
|
}
|
|
range.type &= ~ResEstimated; /* Not allowed for drivers */
|
|
#if !((defined(__alpha__) || (defined(__ia64__))) && defined(linux))
|
|
/* On Alpha Linux, do not check for conflicts, trust the kernel. */
|
|
if (checkConflict(&range, Acc, entityIndex, SETUP,TRUE))
|
|
res = xf86AddResToList(res,&range,entityIndex);
|
|
else
|
|
#endif
|
|
{
|
|
Acc = xf86AddResToList(Acc,&range,entityIndex);
|
|
}
|
|
list++;
|
|
}
|
|
if (list_f)
|
|
xfree(list_f);
|
|
|
|
#ifdef DEBUG
|
|
xf86MsgVerb(X_INFO, 3,"Resources after driver initialization\n");
|
|
xf86PrintResList(3, Acc);
|
|
if (res) xf86MsgVerb(X_INFO, 3,
|
|
"Failed Resources after driver initialization "
|
|
"for Entity: %i\n",entityIndex);
|
|
xf86PrintResList(3, res);
|
|
#endif
|
|
return res;
|
|
|
|
}
|
|
|
|
static void
|
|
busTypeSpecific(EntityPtr pEnt, xf86State state, xf86AccessPtr *acc_mem,
|
|
xf86AccessPtr *acc_io, xf86AccessPtr *acc_mem_io)
|
|
{
|
|
pciAccPtr *ppaccp;
|
|
|
|
switch (pEnt->bus.type) {
|
|
case BUS_ISA:
|
|
case BUS_SBUS:
|
|
*acc_mem = *acc_io = *acc_mem_io = &AccessNULL;
|
|
break;
|
|
break;
|
|
case BUS_PCI:
|
|
ppaccp = xf86PciAccInfo;
|
|
while (*ppaccp) {
|
|
if ((*ppaccp)->busnum == pEnt->pciBusId.bus
|
|
&& (*ppaccp)->devnum == pEnt->pciBusId.device
|
|
&& (*ppaccp)->funcnum == pEnt->pciBusId.func) {
|
|
*acc_io = &(*ppaccp)->ioAccess;
|
|
*acc_mem = &(*ppaccp)->memAccess;
|
|
*acc_mem_io = &(*ppaccp)->io_memAccess;
|
|
break;
|
|
}
|
|
ppaccp++;
|
|
}
|
|
break;
|
|
default:
|
|
*acc_mem = *acc_io = *acc_mem_io = NULL;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void
|
|
setAccess(EntityPtr pEnt, xf86State state)
|
|
{
|
|
|
|
xf86AccessPtr acc_mem, acc_io, acc_mem_io;
|
|
xf86AccessPtr org_mem = NULL, org_io = NULL, org_mem_io = NULL;
|
|
int prop;
|
|
|
|
busTypeSpecific(pEnt,state,&acc_mem,&acc_io,&acc_mem_io);
|
|
|
|
/* The replacement function needs to handle _all_ shared resources */
|
|
/* unless they are handeled locally and disabled otherwise */
|
|
if (pEnt->rac) {
|
|
if (pEnt->rac->io_new) {
|
|
org_io = acc_io;
|
|
acc_io = pEnt->rac->io_new;
|
|
}
|
|
if (pEnt->rac->mem_new) {
|
|
org_mem = acc_mem;
|
|
acc_mem = pEnt->rac->mem_new;
|
|
}
|
|
if (pEnt->rac->io_mem_new) {
|
|
org_mem_io = acc_mem_io;
|
|
acc_mem_io = pEnt->rac->io_mem_new;
|
|
}
|
|
}
|
|
|
|
if (state == OPERATING) {
|
|
prop = pEnt->entityProp;
|
|
switch(pEnt->entityProp & NEED_SHARED) {
|
|
case NEED_SHARED:
|
|
pEnt->access->rt = MEM_IO;
|
|
break;
|
|
case NEED_IO_SHARED:
|
|
pEnt->access->rt = IO;
|
|
break;
|
|
case NEED_MEM_SHARED:
|
|
pEnt->access->rt = MEM;
|
|
break;
|
|
default:
|
|
pEnt->access->rt = NONE;
|
|
}
|
|
} else {
|
|
prop = NEED_SHARED | NEED_MEM | NEED_IO;
|
|
pEnt->access->rt = MEM_IO;
|
|
}
|
|
|
|
switch(pEnt->access->rt) {
|
|
case IO:
|
|
pEnt->access->pAccess = acc_io;
|
|
break;
|
|
case MEM:
|
|
pEnt->access->pAccess = acc_mem;
|
|
break;
|
|
case MEM_IO:
|
|
pEnt->access->pAccess = acc_mem_io;
|
|
break;
|
|
default: /* no conflicts at all */
|
|
pEnt->access->pAccess = NULL; /* remove from RAC */
|
|
break;
|
|
}
|
|
|
|
if (org_io) {
|
|
/* does the driver want the old access func? */
|
|
if (pEnt->rac->old) {
|
|
/* give it to the driver, leave state disabled */
|
|
pEnt->rac->old->io = org_io;
|
|
} else if (org_io->AccessEnable) {
|
|
/* driver doesn't want it - enable generic access */
|
|
org_io->AccessEnable(org_io->arg);
|
|
}
|
|
}
|
|
|
|
if (org_mem_io) {
|
|
/* does the driver want the old access func? */
|
|
if (pEnt->rac->old) {
|
|
/* give it to the driver, leave state disabled */
|
|
pEnt->rac->old->io_mem = org_mem_io;
|
|
} else if (org_mem_io->AccessEnable) {
|
|
/* driver doesn't want it - enable generic access */
|
|
org_mem_io->AccessEnable(org_mem_io->arg);
|
|
}
|
|
}
|
|
|
|
if (org_mem) {
|
|
/* does the driver want the old access func? */
|
|
if (pEnt->rac->old) {
|
|
/* give it to the driver, leave state disabled */
|
|
pEnt->rac->old->mem = org_mem;
|
|
} else if (org_mem->AccessEnable) {
|
|
/* driver doesn't want it - enable generic access */
|
|
org_mem->AccessEnable(org_mem->arg);
|
|
}
|
|
}
|
|
|
|
if (!(prop & NEED_MEM_SHARED)){
|
|
if (prop & NEED_MEM) {
|
|
if (acc_mem && acc_mem->AccessEnable)
|
|
acc_mem->AccessEnable(acc_mem->arg);
|
|
} else {
|
|
if (acc_mem && acc_mem->AccessDisable)
|
|
acc_mem->AccessDisable(acc_mem->arg);
|
|
}
|
|
}
|
|
|
|
if (!(prop & NEED_IO_SHARED)) {
|
|
if (prop & NEED_IO) {
|
|
if (acc_io && acc_io->AccessEnable)
|
|
acc_io->AccessEnable(acc_io->arg);
|
|
} else {
|
|
if (acc_io && acc_io->AccessDisable)
|
|
acc_io->AccessDisable(acc_io->arg);
|
|
}
|
|
}
|
|
|
|
/* disable shared resources */
|
|
if (pEnt->access->pAccess
|
|
&& pEnt->access->pAccess->AccessDisable)
|
|
pEnt->access->pAccess->AccessDisable(pEnt->access->pAccess->arg);
|
|
|
|
/*
|
|
* If device is not under access control it is enabled.
|
|
* If it needs bus routing do it here as it isn't bus
|
|
* type specific. Any conflicts should be checked at this
|
|
* stage
|
|
*/
|
|
if (!pEnt->access->pAccess
|
|
&& (pEnt->entityProp & (state == SETUP ? NEED_VGA_ROUTED_SETUP :
|
|
NEED_VGA_ROUTED)))
|
|
((BusAccPtr)pEnt->busAcc)->set_f(pEnt->busAcc);
|
|
}
|
|
|
|
|
|
/*
|
|
* xf86EnterServerState() -- set state the server is in.
|
|
*/
|
|
|
|
typedef enum { TRI_UNSET, TRI_TRUE, TRI_FALSE } TriState;
|
|
|
|
static void
|
|
SetSIGIOForState(xf86State state)
|
|
{
|
|
static int sigio_state;
|
|
static TriState sigio_blocked = TRI_UNSET;
|
|
|
|
if ((state == SETUP) && (sigio_blocked != TRI_TRUE)) {
|
|
sigio_state = xf86BlockSIGIO();
|
|
sigio_blocked = TRI_TRUE;
|
|
} else if ((state == OPERATING) && (sigio_blocked != TRI_UNSET)) {
|
|
xf86UnblockSIGIO(sigio_state);
|
|
sigio_blocked = TRI_FALSE;
|
|
}
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86EnterServerState(xf86State state)
|
|
{
|
|
EntityPtr pEnt;
|
|
ScrnInfoPtr pScrn;
|
|
int i,j;
|
|
int needVGA = 0;
|
|
resType rt;
|
|
/*
|
|
* This is a good place to block SIGIO during SETUP state.
|
|
* SIGIO should be blocked in SETUP state otherwise (u)sleep()
|
|
* might get interrupted early.
|
|
* We take care not to call xf86BlockSIGIO() twice.
|
|
*/
|
|
SetSIGIOForState(state);
|
|
#ifdef DEBUG
|
|
if (state == SETUP)
|
|
ErrorF("Entering SETUP state\n");
|
|
else
|
|
ErrorF("Entering OPERATING state\n");
|
|
#endif
|
|
|
|
/* When servicing a dumb framebuffer we don't need to do anything */
|
|
if (doFramebufferMode) return;
|
|
|
|
for (i=0; i<xf86NumScreens; i++) {
|
|
pScrn = xf86Screens[i];
|
|
j = pScrn->entityList[pScrn->numEntities - 1];
|
|
pScrn->access = xf86Entities[j]->access;
|
|
|
|
for (j = 0; j<xf86Screens[i]->numEntities; j++) {
|
|
pEnt = xf86Entities[xf86Screens[i]->entityList[j]];
|
|
if (pEnt->entityProp & (state == SETUP ? NEED_VGA_ROUTED_SETUP
|
|
: NEED_VGA_ROUTED))
|
|
xf86Screens[i]->busAccess = pEnt->busAcc;
|
|
}
|
|
if (xf86Screens[i]->busAccess)
|
|
needVGA ++;
|
|
}
|
|
|
|
/*
|
|
* if we just have one screen we don't have RAC.
|
|
* Therefore just enable the screen and return.
|
|
*/
|
|
if (!needRAC) {
|
|
xf86EnableAccess(xf86Screens[0]);
|
|
notifyStateChange(NOTIFY_ENABLE);
|
|
return;
|
|
}
|
|
|
|
if (state == SETUP)
|
|
notifyStateChange(NOTIFY_SETUP_TRANSITION);
|
|
else
|
|
notifyStateChange(NOTIFY_OPERATING_TRANSITION);
|
|
|
|
clearAccess();
|
|
for (i=0; i<xf86NumScreens;i++) {
|
|
|
|
rt = NONE;
|
|
|
|
for (j = 0; j<xf86Screens[i]->numEntities; j++) {
|
|
pEnt = xf86Entities[xf86Screens[i]->entityList[j]];
|
|
setAccess(pEnt,state);
|
|
|
|
if (pEnt->access->rt != NONE) {
|
|
if (rt != NONE && rt != pEnt->access->rt)
|
|
rt = MEM_IO;
|
|
else
|
|
rt = pEnt->access->rt;
|
|
}
|
|
}
|
|
xf86Screens[i]->resourceType = rt;
|
|
if (rt == NONE) {
|
|
xf86Screens[i]->access = NULL;
|
|
if (needVGA < 2)
|
|
xf86Screens[i]->busAccess = NULL;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (xf86Screens[i]->busAccess)
|
|
ErrorF("Screen %i setting vga route\n",i);
|
|
#endif
|
|
switch (rt) {
|
|
case MEM_IO:
|
|
xf86MsgVerb(X_INFO, 3, "Screen %i shares mem & io resources\n",i);
|
|
break;
|
|
case IO:
|
|
xf86MsgVerb(X_INFO, 3, "Screen %i shares io resources\n",i);
|
|
break;
|
|
case MEM:
|
|
xf86MsgVerb(X_INFO, 3, "Screen %i shares mem resources\n",i);
|
|
break;
|
|
default:
|
|
xf86MsgVerb(X_INFO, 3, "Entity %i shares no resources\n",i);
|
|
break;
|
|
}
|
|
}
|
|
if (state == SETUP)
|
|
notifyStateChange(NOTIFY_SETUP);
|
|
else
|
|
notifyStateChange(NOTIFY_OPERATING);
|
|
}
|
|
|
|
/*
|
|
* xf86SetOperatingState() -- Set ResOperMask for resources listed.
|
|
*/
|
|
_X_EXPORT resPtr
|
|
xf86SetOperatingState(resList list, int entityIndex, int mask)
|
|
{
|
|
resPtr acc;
|
|
resPtr r_fail = NULL;
|
|
resRange range;
|
|
|
|
while (list->type != ResEnd) {
|
|
range = *list;
|
|
convertRange2Host(entityIndex,&range);
|
|
|
|
acc = Acc;
|
|
while (acc) {
|
|
#define MASK (ResTypeMask | ResExtMask)
|
|
if ((acc->entityIndex == entityIndex)
|
|
&& (acc->val.a == range.a) && (acc->val.b == range.b)
|
|
&& ((acc->val.type & MASK) == (range.type & MASK)))
|
|
break;
|
|
#undef MASK
|
|
acc = acc->next;
|
|
}
|
|
if (acc)
|
|
acc->val.type = (acc->val.type & ~ResOprMask)
|
|
| (mask & ResOprMask);
|
|
else {
|
|
r_fail = xf86AddResToList(r_fail,&range,entityIndex);
|
|
}
|
|
list ++;
|
|
}
|
|
|
|
return r_fail;
|
|
}
|
|
|
|
/*
|
|
* Stage specific code
|
|
*/
|
|
/*
|
|
* ProcessEstimatedConflicts() -- Do something about driver-registered
|
|
* resources that conflict with estimated resources. For now, just register
|
|
* them with a logged warning.
|
|
*/
|
|
#ifdef REDUCER
|
|
static void
|
|
ProcessEstimatedConflicts(void)
|
|
{
|
|
if (!AccReducers)
|
|
return;
|
|
|
|
/* Temporary */
|
|
xf86MsgVerb(X_WARNING, 3,
|
|
"Registering the following despite conflicts with estimated"
|
|
" resources:\n");
|
|
xf86PrintResList(3, AccReducers);
|
|
Acc = xf86JoinResLists(Acc, AccReducers);
|
|
AccReducers = NULL;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* xf86ClaimFixedResources() -- This function gets called from the
|
|
* driver Probe() function to claim fixed resources.
|
|
*/
|
|
static void
|
|
resError(resList list)
|
|
{
|
|
FatalError("A driver tried to allocate the %s %sresource at \n"
|
|
"0x%lx:0x%lx which conflicted with another resource. Send the\n"
|
|
"output of the server to %s. Please \n"
|
|
"specify your computer hardware as closely as possible.\n",
|
|
ResIsBlock(list)?"Block":"Sparse",
|
|
ResIsMem(list)?"Mem":"Io",
|
|
ResIsBlock(list)?list->rBegin:list->rBase,
|
|
ResIsBlock(list)?list->rEnd:list->rMask,BUILDERADDR);
|
|
}
|
|
|
|
/*
|
|
* xf86ClaimFixedResources() is used to allocate non-relocatable resources.
|
|
* This should only be done by a driver's Probe() function.
|
|
*/
|
|
_X_EXPORT void
|
|
xf86ClaimFixedResources(resList list, int entityIndex)
|
|
{
|
|
resPtr ptr = NULL;
|
|
resRange range;
|
|
|
|
if (!list) return;
|
|
|
|
while (list->type !=ResEnd) {
|
|
range = *list;
|
|
|
|
convertRange2Host(entityIndex,&range);
|
|
|
|
range.type &= ~ResEstimated; /* Not allowed for drivers */
|
|
switch (range.type & ResAccMask) {
|
|
case ResExclusive:
|
|
if (!xf86ChkConflict(&range, entityIndex)) {
|
|
Acc = xf86AddResToList(Acc, &range, entityIndex);
|
|
#ifdef REDUCER
|
|
} else {
|
|
range.type |= ResEstimated;
|
|
if (!xf86ChkConflict(&range, entityIndex) &&
|
|
!checkConflict(&range, AccReducers, entityIndex,
|
|
SETUP, FALSE)) {
|
|
range.type &= ~(ResEstimated | ResBios);
|
|
AccReducers =
|
|
xf86AddResToList(AccReducers, &range, entityIndex);
|
|
#endif
|
|
} else resError(&range); /* no return */
|
|
#ifdef REDUCER
|
|
}
|
|
#endif
|
|
break;
|
|
case ResShared:
|
|
/* at this stage the resources are just added to the
|
|
* EntityRec. After the Probe() phase this list is checked by
|
|
* xf86PostProbe(). All resources which don't
|
|
* conflict with already allocated ones are allocated
|
|
* and removed from the EntityRec. Thus a non-empty resource
|
|
* list in the EntityRec indicates resource conflicts the
|
|
* driver should either handle or fail.
|
|
*/
|
|
if (xf86Entities[entityIndex]->active)
|
|
ptr = xf86AddResToList(ptr,&range,entityIndex);
|
|
break;
|
|
}
|
|
list++;
|
|
}
|
|
xf86Entities[entityIndex]->resources =
|
|
xf86JoinResLists(xf86Entities[entityIndex]->resources,ptr);
|
|
xf86MsgVerb(X_INFO, 3,
|
|
"resource ranges after xf86ClaimFixedResources() call:\n");
|
|
xf86PrintResList(3,Acc);
|
|
#ifdef REDUCER
|
|
ProcessEstimatedConflicts();
|
|
#endif
|
|
#ifdef DEBUG
|
|
if (ptr) {
|
|
xf86MsgVerb(X_INFO, 3, "to be registered later:\n");
|
|
xf86PrintResList(3,ptr);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
checkRoutingForScreens(xf86State state)
|
|
{
|
|
resList list = resVgaUnusedExclusive;
|
|
resPtr pResVGA = NULL;
|
|
resPtr pResVGAHost;
|
|
pointer vga = NULL;
|
|
int i,j;
|
|
int entityIndex;
|
|
EntityPtr pEnt;
|
|
resPtr pAcc;
|
|
resRange range;
|
|
|
|
/*
|
|
* find devices that need VGA routed: ie the ones that have
|
|
* registered VGA resources without ResUnused. ResUnused
|
|
* doesn't conflict with itself therefore use it here.
|
|
*/
|
|
while (list->type != ResEnd) { /* create resPtr from resList for VGA */
|
|
range = *list;
|
|
range.type &= ~(ResBios | ResEstimated); /* if set remove them */
|
|
pResVGA = xf86AddResToList(pResVGA, &range, -1);
|
|
list++;
|
|
}
|
|
|
|
for (i = 0; i < xf86NumScreens; i++) {
|
|
for (j = 0; j < xf86Screens[i]->numEntities; j++) {
|
|
entityIndex = xf86Screens[i]->entityList[j];
|
|
pEnt = xf86Entities[entityIndex];
|
|
pAcc = Acc;
|
|
vga = NULL;
|
|
pResVGAHost = xf86DupResList(pResVGA);
|
|
xf86ConvertListToHost(entityIndex,pResVGAHost);
|
|
while (pAcc) {
|
|
if (pAcc->entityIndex == entityIndex)
|
|
if (checkConflict(&pAcc->val, pResVGAHost,
|
|
entityIndex, state, FALSE)) {
|
|
if (vga && vga != pEnt->busAcc) {
|
|
xf86Msg(X_ERROR, "Screen %i needs vga routed to"
|
|
"different buses - deleting\n",i);
|
|
xf86DeleteScreen(i--,0);
|
|
}
|
|
#ifdef DEBUG
|
|
{
|
|
resPtr rlist = xf86AddResToList(NULL,&pAcc->val,
|
|
pAcc->entityIndex);
|
|
xf86MsgVerb(X_INFO,3,"====== %s\n",
|
|
state == OPERATING ? "OPERATING"
|
|
: "SETUP");
|
|
xf86MsgVerb(X_INFO,3,"%s Resource:\n",
|
|
(pAcc->val.type) & ResMem ? "Mem" :"Io");
|
|
xf86PrintResList(3,rlist);
|
|
xf86FreeResList(rlist);
|
|
xf86MsgVerb(X_INFO,3,"Conflicts with:\n");
|
|
xf86PrintResList(3,pResVGAHost);
|
|
xf86MsgVerb(X_INFO,3,"=====\n");
|
|
}
|
|
#endif
|
|
vga = pEnt->busAcc;
|
|
pEnt->entityProp |= (state == SETUP
|
|
? NEED_VGA_ROUTED_SETUP : NEED_VGA_ROUTED);
|
|
if (state == OPERATING) {
|
|
if (pAcc->val.type & ResMem)
|
|
pEnt->entityProp |= NEED_VGA_MEM;
|
|
else
|
|
pEnt->entityProp |= NEED_VGA_IO;
|
|
}
|
|
}
|
|
pAcc = pAcc->next;
|
|
}
|
|
if (vga)
|
|
xf86MsgVerb(X_INFO, 3,"Setting vga for screen %i.\n",i);
|
|
xf86FreeResList(pResVGAHost);
|
|
}
|
|
}
|
|
xf86FreeResList(pResVGA);
|
|
}
|
|
|
|
/*
|
|
* xf86PostProbe() -- Allocate all non conflicting resources
|
|
* This function gets called by xf86Init().
|
|
*/
|
|
void
|
|
xf86PostProbe(void)
|
|
{
|
|
memType val;
|
|
int i,j;
|
|
resPtr resp, acc, tmp, resp_x, *pprev_next;
|
|
|
|
if (fbSlotClaimed) {
|
|
if (pciSlotClaimed || isaSlotClaimed
|
|
#if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__)
|
|
|| sbusSlotClaimed
|
|
#endif
|
|
) {
|
|
FatalError("Cannot run in framebuffer mode. Please specify busIDs "
|
|
" for all framebuffer devices\n");
|
|
return;
|
|
} else {
|
|
xf86Msg(X_INFO,"Running in FRAMEBUFFER Mode\n");
|
|
xf86AccessRestoreState();
|
|
notifyStateChange(NOTIFY_ENABLE);
|
|
doFramebufferMode = TRUE;
|
|
|
|
return;
|
|
}
|
|
}
|
|
/* don't compare against ResInit - remove it from clone.*/
|
|
acc = tmp = xf86DupResList(Acc);
|
|
pprev_next = &acc;
|
|
while (tmp) {
|
|
if (tmp->res_type & ResInit) {
|
|
(*pprev_next) = tmp->next;
|
|
xfree(tmp);
|
|
} else
|
|
pprev_next = &(tmp->next);
|
|
tmp = (*pprev_next);
|
|
}
|
|
|
|
for (i=0; i<xf86NumEntities; i++) {
|
|
resp = xf86Entities[i]->resources;
|
|
xf86Entities[i]->resources = NULL;
|
|
resp_x = NULL;
|
|
while (resp) {
|
|
if (! (val = checkConflict(&resp->val,acc,i,SETUP,FALSE))) {
|
|
resp->res_type &= ~(ResBios); /* just used for chkConflict() */
|
|
tmp = resp_x;
|
|
resp_x = resp;
|
|
resp = resp->next;
|
|
resp_x->next = tmp;
|
|
#ifdef REDUCER
|
|
} else {
|
|
resp->res_type |= ResEstimated;
|
|
if (!checkConflict(&resp->val, acc, i, SETUP, FALSE)) {
|
|
resp->res_type &= ~(ResEstimated | ResBios);
|
|
tmp = AccReducers;
|
|
AccReducers = resp;
|
|
resp = resp->next;
|
|
AccReducers->next = tmp;
|
|
#endif
|
|
} else {
|
|
xf86MsgVerb(X_INFO, 3, "Found conflict at: 0x%lx\n",val);
|
|
resp->res_type &= ~ResEstimated;
|
|
tmp = xf86Entities[i]->resources;
|
|
xf86Entities[i]->resources = resp;
|
|
resp = resp->next;
|
|
xf86Entities[i]->resources->next = tmp;
|
|
}
|
|
#ifdef REDUCER
|
|
}
|
|
#endif
|
|
}
|
|
xf86JoinResLists(Acc,resp_x);
|
|
#ifdef REDUCER
|
|
ProcessEstimatedConflicts();
|
|
#endif
|
|
}
|
|
xf86FreeResList(acc);
|
|
#if !(defined(__alpha__) && defined(linux)) && \
|
|
!(defined(__ia64__) && defined(linux)) && \
|
|
!(defined(__sparc64__) && defined(__OpenBSD__))
|
|
/*
|
|
* No need to validate on Alpha Linux or OpenBSD/sparc64,
|
|
* trust the kernel.
|
|
*/
|
|
ValidatePci();
|
|
#endif
|
|
|
|
xf86MsgVerb(X_INFO, 3, "resource ranges after probing:\n");
|
|
xf86PrintResList(3, Acc);
|
|
checkRoutingForScreens(SETUP);
|
|
|
|
for (i = 0; i < xf86NumScreens; i++) {
|
|
for (j = 0; j<xf86Screens[i]->numEntities; j++) {
|
|
EntityPtr pEnt = xf86Entities[xf86Screens[i]->entityList[j]];
|
|
if ((pEnt->entityProp & NEED_VGA_ROUTED_SETUP) &&
|
|
((xf86Screens[i]->busAccess = pEnt->busAcc)))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
checkRequiredResources(int entityIndex)
|
|
{
|
|
resRange range;
|
|
resPtr pAcc = Acc;
|
|
const EntityPtr pEnt = xf86Entities[entityIndex];
|
|
while (pAcc) {
|
|
if (pAcc->entityIndex == entityIndex) {
|
|
range = pAcc->val;
|
|
/* ResAny to find conflicts with anything. */
|
|
range.type = (range.type & ~ResAccMask) | ResAny | ResBios;
|
|
if (checkConflict(&range,Acc,entityIndex,OPERATING,FALSE))
|
|
switch (pAcc->res_type & ResPhysMask) {
|
|
case ResMem:
|
|
pEnt->entityProp |= NEED_MEM_SHARED;
|
|
break;
|
|
case ResIo:
|
|
pEnt->entityProp |= NEED_IO_SHARED;
|
|
break;
|
|
}
|
|
if (!(pAcc->res_type & ResOprMask)) {
|
|
switch (pAcc->res_type & ResPhysMask) {
|
|
case ResMem:
|
|
pEnt->entityProp |= NEED_MEM;
|
|
break;
|
|
case ResIo:
|
|
pEnt->entityProp |= NEED_IO;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
pAcc = pAcc->next;
|
|
}
|
|
|
|
/* check if we can separately enable mem/io resources */
|
|
/* XXX we still need to find out how to set this yet */
|
|
if ( ((pEnt->entityProp & NO_SEPARATE_MEM_FROM_IO)
|
|
&& (pEnt->entityProp & NEED_MEM_SHARED))
|
|
|| ((pEnt->entityProp & NO_SEPARATE_IO_FROM_MEM)
|
|
&& (pEnt->entityProp & NEED_IO_SHARED)) )
|
|
pEnt->entityProp |= NEED_SHARED;
|
|
/*
|
|
* After we have checked all resources of an entity agains any
|
|
* other resource we know if the entity need this resource type
|
|
* (ie. mem/io) at all. if not we can disable this type completely,
|
|
* so no need to share it either.
|
|
*/
|
|
if ((pEnt->entityProp & NEED_MEM_SHARED)
|
|
&& (!(pEnt->entityProp & NEED_MEM))
|
|
&& (!(pEnt->entityProp & NO_SEPARATE_MEM_FROM_IO)))
|
|
pEnt->entityProp &= ~(unsigned long)NEED_MEM_SHARED;
|
|
|
|
if ((pEnt->entityProp & NEED_IO_SHARED)
|
|
&& (!(pEnt->entityProp & NEED_IO))
|
|
&& (!(pEnt->entityProp & NO_SEPARATE_IO_FROM_MEM)))
|
|
pEnt->entityProp &= ~(unsigned long)NEED_IO_SHARED;
|
|
}
|
|
|
|
void
|
|
xf86PostPreInit()
|
|
{
|
|
if (doFramebufferMode) return;
|
|
|
|
if (xf86NumScreens > 1)
|
|
needRAC = TRUE;
|
|
|
|
xf86MsgVerb(X_INFO, 3, "do I need RAC?");
|
|
|
|
if (needRAC) {
|
|
xf86ErrorFVerb(3, " Yes, I do.\n");
|
|
} else {
|
|
xf86ErrorFVerb(3, " No, I don't.\n");
|
|
}
|
|
|
|
xf86MsgVerb(X_INFO, 3, "resource ranges after preInit:\n");
|
|
xf86PrintResList(3, Acc);
|
|
}
|
|
|
|
void
|
|
xf86PostScreenInit(void)
|
|
{
|
|
int i,j;
|
|
ScreenPtr pScreen;
|
|
unsigned int flags;
|
|
int nummem = 0, numio = 0;
|
|
|
|
if (doFramebufferMode) {
|
|
SetSIGIOForState(OPERATING);
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
ErrorF("PostScreenInit generation: %i\n",serverGeneration);
|
|
#endif
|
|
if (serverGeneration == 1) {
|
|
checkRoutingForScreens(OPERATING);
|
|
for (i=0; i<xf86NumEntities; i++) {
|
|
checkRequiredResources(i);
|
|
}
|
|
|
|
/*
|
|
* after removing NEED_XXX_SHARED from entities that
|
|
* don't need need XXX resources at all we might have
|
|
* a single entity left that has NEED_XXX_SHARED set.
|
|
* In this case we can delete that, too.
|
|
*/
|
|
for (i = 0; i < xf86NumEntities; i++) {
|
|
if (xf86Entities[i]->entityProp & NEED_MEM_SHARED)
|
|
nummem++;
|
|
if (xf86Entities[i]->entityProp & NEED_IO_SHARED)
|
|
numio++;
|
|
}
|
|
for (i = 0; i < xf86NumEntities; i++) {
|
|
if (nummem < 2)
|
|
xf86Entities[i]->entityProp &= ~NEED_MEM_SHARED;
|
|
if (numio < 2)
|
|
xf86Entities[i]->entityProp &= ~NEED_IO_SHARED;
|
|
}
|
|
}
|
|
|
|
if (xf86Screens && needRAC) {
|
|
int needRACforVga = 0;
|
|
|
|
for (i = 0; i < xf86NumScreens; i++) {
|
|
for (j = 0; j < xf86Screens[i]->numEntities; j++) {
|
|
if (xf86Entities[xf86Screens[i]->entityList[j]]->entityProp
|
|
& NEED_VGA_ROUTED) {
|
|
needRACforVga ++;
|
|
break; /* only count each screen once */
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < xf86NumScreens; i++) {
|
|
Bool needRACforMem = FALSE, needRACforIo = FALSE;
|
|
|
|
for (j = 0; j < xf86Screens[i]->numEntities; j++) {
|
|
if (xf86Entities[xf86Screens[i]->entityList[j]]->entityProp
|
|
& NEED_MEM_SHARED)
|
|
needRACforMem = TRUE;
|
|
if (xf86Entities[xf86Screens[i]->entityList[j]]->entityProp
|
|
& NEED_IO_SHARED)
|
|
needRACforIo = TRUE;
|
|
/*
|
|
* We may need RAC although we don't share any resources
|
|
* as we need to route VGA to the correct bus. This can
|
|
* only be done simultaniously for MEM and IO.
|
|
*/
|
|
if (needRACforVga > 1) {
|
|
if (xf86Entities[xf86Screens[i]->entityList[j]]->entityProp
|
|
& NEED_VGA_MEM)
|
|
needRACforMem = TRUE;
|
|
if (xf86Entities[xf86Screens[i]->entityList[j]]->entityProp
|
|
& NEED_VGA_IO)
|
|
needRACforIo = TRUE;
|
|
}
|
|
}
|
|
|
|
pScreen = xf86Screens[i]->pScreen;
|
|
flags = 0;
|
|
if (needRACforMem) {
|
|
flags |= xf86Screens[i]->racMemFlags;
|
|
xf86ErrorFVerb(3, "Screen %d is using RAC for mem\n", i);
|
|
}
|
|
if (needRACforIo) {
|
|
flags |= xf86Screens[i]->racIoFlags;
|
|
xf86ErrorFVerb(3, "Screen %d is using RAC for io\n", i);
|
|
}
|
|
|
|
xf86RACInit(pScreen,flags);
|
|
}
|
|
}
|
|
|
|
xf86EnterServerState(OPERATING);
|
|
|
|
}
|
|
|
|
/*
|
|
* Sets
|
|
*/
|
|
|
|
|
|
static resPtr
|
|
decomposeSparse(resRange range)
|
|
{
|
|
resRange new;
|
|
resPtr ret = NULL;
|
|
memType val = range.rBegin;
|
|
int i = 0;
|
|
|
|
new.type = (range.type & ~ResExtMask) | ResSparse;
|
|
|
|
while (1) {
|
|
if (val & 0x01) {
|
|
new.rBase = (val << i);
|
|
new.rMask = ~((1 << i) - 1);
|
|
ret = xf86AddResToList(ret,&new,-1);
|
|
val ++;
|
|
}
|
|
i++;
|
|
val >>= 1;
|
|
if ((((val + 1) << i) - 1) > range.rEnd)
|
|
break;
|
|
}
|
|
i--;
|
|
val <<= 1;
|
|
|
|
while (1) {
|
|
if((((val + 1) << i) - 1)> range.rEnd) {
|
|
if (--i < 0) break;
|
|
val <<= 1;
|
|
} else {
|
|
new.rBase = (val << i);
|
|
new.rMask = ~((1 << i) - 1);
|
|
val++;
|
|
ret = xf86AddResToList(ret,&new,-1);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static Bool
|
|
x_isSubsetOf(resRange range, resPtr list1, resPtr list2)
|
|
{
|
|
resRange range1, range2;
|
|
memType m1_A_m2;
|
|
Bool ret;
|
|
resPtr list;
|
|
|
|
if (list1) {
|
|
list = list1;
|
|
if ((range.type & ResTypeMask) == (list->res_type & ResTypeMask)) {
|
|
switch (range.type & ResExtMask) {
|
|
case ResBlock:
|
|
if ((list->res_type & ResExtMask) == ResBlock) {
|
|
if (range.rBegin >= list->block_begin
|
|
&& range.rEnd <= list->block_end)
|
|
return TRUE;
|
|
else if (range.rBegin < list->block_begin
|
|
&& range.rEnd > list->block_end) {
|
|
RANGE(range1, range.rBegin, list->block_begin - 1,
|
|
range.type);
|
|
RANGE(range2, list->block_end + 1, range.rEnd,
|
|
range.type);
|
|
return (x_isSubsetOf(range1,list->next,list2) &&
|
|
x_isSubsetOf(range2,list->next,list2));
|
|
}
|
|
else if (range.rBegin >= list->block_begin
|
|
&& range.rBegin <= list->block_end) {
|
|
RANGE(range1, list->block_end + 1, range.rEnd,
|
|
range.type);
|
|
return (x_isSubsetOf(range1,list->next,list2));
|
|
} else if (range.rEnd >= list->block_begin
|
|
&& range.rEnd <= list->block_end) {
|
|
RANGE(range1,range.rBegin, list->block_begin - 1,
|
|
range.type);
|
|
return (x_isSubsetOf(range1,list->next,list2));
|
|
}
|
|
}
|
|
break;
|
|
case ResSparse:
|
|
if ((list->res_type & ResExtMask) == ResSparse) {
|
|
memType test;
|
|
int i;
|
|
|
|
m1_A_m2 = range.rMask & list->sparse_mask;
|
|
if ((range.rBase ^ list->sparse_base) & m1_A_m2)
|
|
break;
|
|
/*
|
|
* We use the following system:
|
|
* let 0 ^= mask:1 base:0, 1 ^= mask:1 base:1,
|
|
* X mask:0 ; S: set TSS: test set for subset
|
|
* NTSS: new test set after test
|
|
* S: 1 0 1 0 X X 0 1 X
|
|
* TSS: 1 0 0 1 1 0 X X X
|
|
* T: 0 0 1 1 0 0 0 0 0
|
|
* NTSS: 1 0 0/X 1/X 1 0 1 0 X
|
|
* R: 0 0 0 0 0 0 1 1 0
|
|
* If R != 0 TSS and S are disjunct
|
|
* If R == 0 TSS is subset of S
|
|
* If R != 0 NTSS contains elements from TSS
|
|
* which are not also members of S.
|
|
* If a T is set one of the correspondig bits
|
|
* in NTSS must be set to the specified value
|
|
* all other are X
|
|
*/
|
|
test = list->sparse_mask & ~range.rMask;
|
|
if (test == 0)
|
|
return TRUE;
|
|
for (i = 0; i < sizeof(memType); i++) {
|
|
if ((test >> i) & 0x1) {
|
|
RANGE(range1, ((range.rBase & list->sparse_base)
|
|
| (range.rBase & ~list->sparse_mask)
|
|
| ((~list->sparse_base & list->sparse_mask)
|
|
& ~range.rMask)) & range1.rMask,
|
|
((range.rMask | list->sparse_mask) & ~test)
|
|
| (1 << i), range.type);
|
|
return (x_isSubsetOf(range1,list->next,list2));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return (x_isSubsetOf(range,list->next,list2));
|
|
} else if (list2) {
|
|
resPtr tmpList = NULL;
|
|
switch (range.type & ResExtMask) {
|
|
case ResBlock:
|
|
tmpList = decomposeSparse(range);
|
|
while (tmpList) {
|
|
if (!x_isSubsetOf(tmpList->val,list2,NULL)) {
|
|
xf86FreeResList(tmpList);
|
|
return FALSE;
|
|
}
|
|
tmpList = tmpList->next;
|
|
}
|
|
xf86FreeResList(tmpList);
|
|
return TRUE;
|
|
break;
|
|
case ResSparse:
|
|
while (list2) {
|
|
tmpList = xf86JoinResLists(tmpList,decomposeSparse(list2->val));
|
|
list2 = list2->next;
|
|
}
|
|
ret = x_isSubsetOf(range,tmpList,NULL);
|
|
xf86FreeResList(tmpList);
|
|
return ret;
|
|
break;
|
|
}
|
|
} else
|
|
return FALSE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
Bool
|
|
xf86IsSubsetOf(resRange range, resPtr list)
|
|
{
|
|
resPtr dup = xf86DupResList(list);
|
|
resPtr r_sp = NULL, r = NULL, tmp = NULL;
|
|
Bool ret = FALSE;
|
|
|
|
while (dup) {
|
|
tmp = dup;
|
|
dup = dup->next;
|
|
switch (tmp->res_type & ResExtMask) {
|
|
case ResBlock:
|
|
tmp->next = r;
|
|
r = tmp;
|
|
break;
|
|
case ResSparse:
|
|
tmp->next = r_sp;
|
|
r_sp = tmp;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (range.type & ResExtMask) {
|
|
case ResBlock:
|
|
ret = x_isSubsetOf(range,r,r_sp);
|
|
break;
|
|
case ResSparse:
|
|
ret = x_isSubsetOf(range,r_sp,r);
|
|
break;
|
|
}
|
|
xf86FreeResList(r);
|
|
xf86FreeResList(r_sp);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static resPtr
|
|
findIntersect(resRange Range, resPtr list)
|
|
{
|
|
resRange range;
|
|
resPtr new = NULL;
|
|
|
|
while (list) {
|
|
if ((Range.type & ResTypeMask) == (list->res_type & ResTypeMask)) {
|
|
switch (Range.type & ResExtMask) {
|
|
case ResBlock:
|
|
switch (list->res_type & ResExtMask) {
|
|
case ResBlock:
|
|
if (Range.rBegin >= list->block_begin)
|
|
range.rBegin = Range.rBegin;
|
|
else
|
|
range.rBegin = list->block_begin;
|
|
if (Range.rEnd <= list->block_end)
|
|
range.rEnd = Range.rEnd;
|
|
else
|
|
range.rEnd = list->block_end;
|
|
if (range.rEnd > range.rBegin) {
|
|
range.type = Range.type;
|
|
new = xf86AddResToList(new,&range,-1);
|
|
}
|
|
break;
|
|
case ResSparse:
|
|
new = xf86JoinResLists(new,xf86FindIntersectOfLists(new,decomposeSparse(list->val)));
|
|
break;
|
|
}
|
|
break;
|
|
case ResSparse:
|
|
switch (list->res_type & ResExtMask) {
|
|
case ResSparse:
|
|
if (!((~(range.rBase ^ list->sparse_base)
|
|
& (range.rMask & list->sparse_mask)))) {
|
|
RANGE(range, (range.rBase & list->sparse_base)
|
|
| (~range.rMask & list->sparse_base)
|
|
| (~list->sparse_mask & range.rBase),
|
|
range.rMask | list->sparse_mask,
|
|
Range.type);
|
|
new = xf86AddResToList(new,&range,-1);
|
|
}
|
|
break;
|
|
case ResBlock:
|
|
new = xf86JoinResLists(new,xf86FindIntersectOfLists(
|
|
decomposeSparse(range),list));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
list = list->next;
|
|
}
|
|
return new;
|
|
}
|
|
|
|
resPtr
|
|
xf86FindIntersectOfLists(resPtr l1, resPtr l2)
|
|
{
|
|
resPtr ret = NULL;
|
|
|
|
while (l1) {
|
|
ret = xf86JoinResLists(ret,findIntersect(l1->val,l2));
|
|
l1 = l1->next;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#if 0 /* Not used */
|
|
static resPtr
|
|
xf86FindComplement(resRange Range)
|
|
{
|
|
resRange range;
|
|
memType tmp;
|
|
resPtr new = NULL;
|
|
int i;
|
|
|
|
switch (Range.type & ResExtMask) {
|
|
case ResBlock:
|
|
if (Range.rBegin > 0) {
|
|
RANGE(range, 0, Range.rBegin - 1, Range.type);
|
|
new = xf86AddResToList(new,&range,-1);
|
|
}
|
|
if (Range.rEnd < (memType)~0) {
|
|
RANGE(range,Range.rEnd + 1, (memType)~0, Range.type);
|
|
new = xf86AddResToList(new,&range,-1);
|
|
}
|
|
break;
|
|
case ResSparse:
|
|
tmp = Range.rMask;
|
|
for (i = 0; i < sizeof(memType); i++) {
|
|
if (tmp & 0x1) {
|
|
RANGE(range,(~Range.rMask & range.rMask),(1 << i), Range.type);
|
|
new = xf86AddResToList(new,&range,-1);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return new;
|
|
}
|
|
#endif
|
|
|
|
resPtr
|
|
xf86ExtractTypeFromList(resPtr list, unsigned long type)
|
|
{
|
|
resPtr ret = NULL;
|
|
|
|
while (list) {
|
|
if ((list->res_type & ResTypeMask) == type)
|
|
ret = xf86AddResToList(ret,&(list->val),list->entityIndex);
|
|
list = list->next;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*------------------------------------------------------------*/
|
|
static void CheckGenericGA(void);
|
|
|
|
/*
|
|
* xf86FindPrimaryDevice() - Find the display device which
|
|
* was active when the server was started.
|
|
*/
|
|
void
|
|
xf86FindPrimaryDevice()
|
|
{
|
|
/* if no VGA device is found check for primary PCI device */
|
|
if (primaryBus.type == BUS_NONE && xorgHWAccess)
|
|
CheckGenericGA();
|
|
if (primaryBus.type != BUS_NONE) {
|
|
char *bus;
|
|
char *loc = xnfcalloc(1,9);
|
|
if (loc == NULL) return;
|
|
|
|
switch (primaryBus.type) {
|
|
case BUS_PCI:
|
|
bus = "PCI";
|
|
sprintf(loc," %2.2x:%2.2x:%1.1x",primaryBus.id.pci.bus,
|
|
primaryBus.id.pci.device,primaryBus.id.pci.func);
|
|
break;
|
|
case BUS_ISA:
|
|
bus = "ISA";
|
|
loc[0] = '\0';
|
|
break;
|
|
case BUS_SBUS:
|
|
bus = "SBUS";
|
|
sprintf(loc," %2.2x",primaryBus.id.sbus.fbNum);
|
|
break;
|
|
default:
|
|
bus = "";
|
|
loc[0] = '\0';
|
|
}
|
|
|
|
xf86MsgVerb(X_INFO, 2, "Primary Device is: %s%s\n",bus,loc);
|
|
xfree(loc);
|
|
}
|
|
|
|
}
|
|
|
|
#if !defined(__sparc) && !defined(__sparc__) && !defined(__powerpc__) && !defined(__mips__) && !defined(__arm__)
|
|
#include "vgaHW.h"
|
|
#include "compiler.h"
|
|
#endif
|
|
|
|
/*
|
|
* CheckGenericGA() - Check for presence of a VGA device.
|
|
*/
|
|
static void
|
|
CheckGenericGA()
|
|
{
|
|
/* This needs to be changed for multiple domains */
|
|
#if !defined(__sparc__) && !defined(__sparc) && !defined(__powerpc__) && !defined(__mips__) && !defined(__ia64__) && !defined(__arm__) && !defined(__s390__)
|
|
IOADDRESS GenericIOBase = VGAHW_GET_IOBASE();
|
|
CARD8 CurrentValue, TestValue;
|
|
|
|
/* VGA CRTC registers are not used here, so don't bother unlocking them */
|
|
|
|
/* VGA has one more read/write attribute register than EGA */
|
|
(void) inb(GenericIOBase + VGA_IN_STAT_1_OFFSET); /* Reset flip-flop */
|
|
outb(VGA_ATTR_INDEX, 0x14 | 0x20);
|
|
CurrentValue = inb(VGA_ATTR_DATA_R);
|
|
outb(VGA_ATTR_DATA_W, CurrentValue ^ 0x0F);
|
|
outb(VGA_ATTR_INDEX, 0x14 | 0x20);
|
|
TestValue = inb(VGA_ATTR_DATA_R);
|
|
outb(VGA_ATTR_DATA_W, CurrentValue);
|
|
|
|
if ((CurrentValue ^ 0x0F) == TestValue) {
|
|
primaryBus.type = BUS_ISA;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
_X_EXPORT Bool
|
|
xf86NoSharedResources(int screenIndex,resType res)
|
|
{
|
|
int j;
|
|
|
|
if (screenIndex > xf86NumScreens)
|
|
return TRUE;
|
|
|
|
for (j = 0; j < xf86Screens[screenIndex]->numEntities; j++) {
|
|
switch (res) {
|
|
case IO:
|
|
if ( xf86Entities[xf86Screens[screenIndex]->entityList[j]]->entityProp
|
|
& NEED_IO_SHARED)
|
|
return FALSE;
|
|
break;
|
|
case MEM:
|
|
if ( xf86Entities[xf86Screens[screenIndex]->entityList[j]]->entityProp
|
|
& NEED_MEM_SHARED)
|
|
return FALSE;
|
|
break;
|
|
case MEM_IO:
|
|
if ( xf86Entities[xf86Screens[screenIndex]->entityList[j]]->entityProp
|
|
& NEED_SHARED)
|
|
return FALSE;
|
|
break;
|
|
case NONE:
|
|
break;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86RegisterStateChangeNotificationCallback(xf86StateChangeNotificationCallbackFunc func, pointer arg)
|
|
{
|
|
StateChangeNotificationPtr ptr =
|
|
(StateChangeNotificationPtr)xnfalloc(sizeof(StateChangeNotificationRec));
|
|
|
|
ptr->func = func;
|
|
ptr->arg = arg;
|
|
ptr->next = StateChangeNotificationList;
|
|
StateChangeNotificationList = ptr;
|
|
}
|
|
|
|
_X_EXPORT Bool
|
|
xf86DeregisterStateChangeNotificationCallback(xf86StateChangeNotificationCallbackFunc func)
|
|
{
|
|
StateChangeNotificationPtr *ptr = &StateChangeNotificationList;
|
|
StateChangeNotificationPtr tmp;
|
|
|
|
while (*ptr) {
|
|
if ((*ptr)->func == func) {
|
|
tmp = (*ptr);
|
|
(*ptr) = (*ptr)->next;
|
|
xfree(tmp);
|
|
return TRUE;
|
|
}
|
|
ptr = &((*ptr)->next);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
notifyStateChange(xf86NotifyState state)
|
|
{
|
|
StateChangeNotificationPtr ptr = StateChangeNotificationList;
|
|
while (ptr) {
|
|
ptr->func(state,ptr->arg);
|
|
ptr = ptr->next;
|
|
}
|
|
}
|
|
|
|
/* Multihead accel sharing accessor functions and entity Private handling */
|
|
|
|
_X_EXPORT int
|
|
xf86GetLastScrnFlag(int entityIndex)
|
|
{
|
|
if(entityIndex < xf86NumEntities) {
|
|
return(xf86Entities[entityIndex]->lastScrnFlag);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86SetLastScrnFlag(int entityIndex, int scrnIndex)
|
|
{
|
|
if(entityIndex < xf86NumEntities) {
|
|
xf86Entities[entityIndex]->lastScrnFlag = scrnIndex;
|
|
}
|
|
}
|
|
|
|
_X_EXPORT Bool
|
|
xf86IsEntityShared(int entityIndex)
|
|
{
|
|
if(entityIndex < xf86NumEntities) {
|
|
if(xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86SetEntityShared(int entityIndex)
|
|
{
|
|
if(entityIndex < xf86NumEntities) {
|
|
xf86Entities[entityIndex]->entityProp |= IS_SHARED_ACCEL;
|
|
}
|
|
}
|
|
|
|
_X_EXPORT Bool
|
|
xf86IsEntitySharable(int entityIndex)
|
|
{
|
|
if(entityIndex < xf86NumEntities) {
|
|
if(xf86Entities[entityIndex]->entityProp & ACCEL_IS_SHARABLE) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86SetEntitySharable(int entityIndex)
|
|
{
|
|
if(entityIndex < xf86NumEntities) {
|
|
xf86Entities[entityIndex]->entityProp |= ACCEL_IS_SHARABLE;
|
|
}
|
|
}
|
|
|
|
_X_EXPORT Bool
|
|
xf86IsPrimInitDone(int entityIndex)
|
|
{
|
|
if(entityIndex < xf86NumEntities) {
|
|
if(xf86Entities[entityIndex]->entityProp & SA_PRIM_INIT_DONE) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86SetPrimInitDone(int entityIndex)
|
|
{
|
|
if(entityIndex < xf86NumEntities) {
|
|
xf86Entities[entityIndex]->entityProp |= SA_PRIM_INIT_DONE;
|
|
}
|
|
}
|
|
|
|
_X_EXPORT void
|
|
xf86ClearPrimInitDone(int entityIndex)
|
|
{
|
|
if(entityIndex < xf86NumEntities) {
|
|
xf86Entities[entityIndex]->entityProp &= ~SA_PRIM_INIT_DONE;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Allocate a private in the entities.
|
|
*/
|
|
|
|
_X_EXPORT int
|
|
xf86AllocateEntityPrivateIndex(void)
|
|
{
|
|
int idx, i;
|
|
EntityPtr pEnt;
|
|
DevUnion *nprivs;
|
|
|
|
idx = xf86EntityPrivateCount++;
|
|
for (i = 0; i < xf86NumEntities; i++) {
|
|
pEnt = xf86Entities[i];
|
|
nprivs = xnfrealloc(pEnt->entityPrivates,
|
|
xf86EntityPrivateCount * sizeof(DevUnion));
|
|
/* Zero the new private */
|
|
bzero(&nprivs[idx], sizeof(DevUnion));
|
|
pEnt->entityPrivates = nprivs;
|
|
}
|
|
return idx;
|
|
}
|
|
|
|
_X_EXPORT DevUnion *
|
|
xf86GetEntityPrivate(int entityIndex, int privIndex)
|
|
{
|
|
if (entityIndex >= xf86NumEntities || privIndex >= xf86EntityPrivateCount)
|
|
return NULL;
|
|
|
|
return &(xf86Entities[entityIndex]->entityPrivates[privIndex]);
|
|
}
|
|
|