892 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			892 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright 1992 by Orest Zborowski <obz@Kodak.com>
 | |
|  * Copyright 1993 by David Wexelblat <dwex@goblin.org>
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that
 | |
|  * copyright notice and this permission notice appear in supporting
 | |
|  * documentation, and that the names of Orest Zborowski and David Wexelblat
 | |
|  * not be used in advertising or publicity pertaining to distribution of
 | |
|  * the software without specific, written prior permission.  Orest Zborowski
 | |
|  * and David Wexelblat make no representations about the suitability of this
 | |
|  * software for any purpose.  It is provided "as is" without express or
 | |
|  * implied warranty.
 | |
|  *
 | |
|  * OREST ZBOROWSKI AND DAVID WEXELBLAT DISCLAIMS ALL WARRANTIES WITH REGARD
 | |
|  * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | |
|  * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID WEXELBLAT BE LIABLE
 | |
|  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | |
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | |
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | |
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_XORG_CONFIG_H
 | |
| #include <xorg-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include <X11/X.h>
 | |
| #include "input.h"
 | |
| #include "scrnintstr.h"
 | |
| 
 | |
| #include "xf86.h"
 | |
| #include "xf86Priv.h"
 | |
| #include "xf86_OSlib.h"
 | |
| #include "xf86OSpriv.h"
 | |
| #include "lnx.h"
 | |
| #ifdef __alpha__
 | |
| #include "shared/xf86Axp.h"
 | |
| #endif
 | |
| 
 | |
| #ifdef HAS_MTRR_SUPPORT
 | |
| #include <asm/mtrr.h>
 | |
| #endif
 | |
| 
 | |
| #ifndef MAP_FAILED
 | |
| #define MAP_FAILED ((void *)-1)
 | |
| #endif
 | |
| 
 | |
| static Bool ExtendedEnabled = FALSE;
 | |
| 
 | |
| #ifdef __ia64__
 | |
| 
 | |
| #include "compiler.h"
 | |
| #include <sys/io.h>
 | |
| 
 | |
| #elif !defined(__powerpc__) && \
 | |
|       !defined(__mc68000__) && \
 | |
|       !defined(__sparc__) && \
 | |
|       !defined(__mips__) && \
 | |
|       !defined(__arm__)
 | |
| 
 | |
| /*
 | |
|  * Due to conflicts with "compiler.h", don't rely on <sys/io.h> to declare
 | |
|  * these.
 | |
|  */
 | |
| extern int ioperm(unsigned long __from, unsigned long __num, int __turn_on);
 | |
| extern int iopl(int __level);
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #ifdef __alpha__
 | |
| 
 | |
| extern void sethae(unsigned long hae);
 | |
| 
 | |
| # define BUS_BASE bus_base
 | |
| 
 | |
| #else 
 | |
| 
 | |
| #define BUS_BASE (0)
 | |
| 
 | |
| #endif /*  __alpha__ */
 | |
| 
 | |
| /***************************************************************************/
 | |
| /* Video Memory Mapping section                                            */
 | |
| /***************************************************************************/
 | |
| 
 | |
| static pointer mapVidMem(int, unsigned long, unsigned long, int);
 | |
| static void unmapVidMem(int, pointer, unsigned long);
 | |
| #if defined (__alpha__) 
 | |
| static pointer mapVidMemSparse(int, unsigned long, unsigned long, int);
 | |
| extern axpDevice lnxGetAXP(void);
 | |
| static void unmapVidMemSparse(int, pointer, unsigned long);
 | |
| static axpDevice axpSystem = -1;
 | |
| static Bool needSparse;
 | |
| static unsigned long hae_thresh;
 | |
| static unsigned long hae_mask;
 | |
| static unsigned long bus_base;
 | |
| static unsigned long sparse_size;
 | |
| #endif
 | |
| 
 | |
| #ifdef HAS_MTRR_SUPPORT
 | |
| 
 | |
| #define SPLIT_WC_REGIONS 1
 | |
| 
 | |
| static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType);
 | |
| static void undoWC(int, pointer);
 | |
| 
 | |
| /* The file desc for /proc/mtrr. Once opened, left opened, and the mtrr
 | |
|    driver will clean up when we exit. */
 | |
| #define MTRR_FD_UNOPENED (-1)	/* We have yet to open /proc/mtrr */
 | |
| #define MTRR_FD_PROBLEM (-2)	/* We tried to open /proc/mtrr, but had
 | |
| 				   a problem. */
 | |
| static int mtrr_fd = MTRR_FD_UNOPENED;
 | |
| 
 | |
| /* Open /proc/mtrr. FALSE on failure. Will always fail on Linux 2.0, 
 | |
|    and will fail on Linux 2.2 with MTRR support configured out,
 | |
|    so verbosity should be chosen appropriately. */
 | |
| static Bool
 | |
| mtrr_open(int verbosity)
 | |
| {
 | |
| 	/* Only report absence of /proc/mtrr once. */
 | |
| 	static Bool warned = FALSE;
 | |
| 
 | |
| 	if (mtrr_fd == MTRR_FD_UNOPENED) { 
 | |
| 		mtrr_fd = open("/proc/mtrr", O_WRONLY);
 | |
| 
 | |
| 		if (mtrr_fd < 0)
 | |
| 			mtrr_fd = MTRR_FD_PROBLEM;
 | |
| 	}
 | |
| 
 | |
| 	if (mtrr_fd == MTRR_FD_PROBLEM) {
 | |
| 		/* To make sure we only ever warn once, need to check
 | |
| 		   verbosity outside xf86MsgVerb */
 | |
| 		if (!warned && verbosity <= xf86GetVerbosity()) {
 | |
| 			xf86MsgVerb(X_WARNING, verbosity,
 | |
| 				  "System lacks support for changing MTRRs\n");
 | |
| 			warned = TRUE;
 | |
| 		}
 | |
| 
 | |
| 		return FALSE;
 | |
| 	}
 | |
| 	else
 | |
| 		return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * We maintain a list of WC regions for each physical mapping so they can
 | |
|  * be undone when unmapping.
 | |
|  */
 | |
| 
 | |
| struct mtrr_wc_region {
 | |
| 	struct mtrr_sentry	sentry;
 | |
| 	Bool			added;		/* added WC or removed it */
 | |
| 	struct mtrr_wc_region *	next;
 | |
| };
 | |
| 
 | |
| 
 | |
| static struct mtrr_wc_region *
 | |
| mtrr_cull_wc_region(int screenNum, unsigned long base, unsigned long size,
 | |
| 		      MessageType from)
 | |
| {
 | |
| 	/* Some BIOS writers thought that setting wc over the mmio
 | |
| 	   region of a graphics devices was a good idea. Try to fix
 | |
| 	   it. */
 | |
| 
 | |
| 	struct mtrr_gentry gent;
 | |
| 	struct mtrr_wc_region *wcreturn = NULL, *wcr;
 | |
| 	int count, ret=0;
 | |
| 
 | |
| 	/* Linux 2.0 users should not get a warning without -verbose */
 | |
| 	if (!mtrr_open(2))
 | |
| 		return NULL;
 | |
| 
 | |
| 	for (gent.regnum = 0; 
 | |
| 	     ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0;
 | |
| 	     gent.regnum++) {
 | |
| 		if (gent.type != MTRR_TYPE_WRCOMB
 | |
| 		    || gent.base + gent.size <= base
 | |
| 		    || base + size <= gent.base)
 | |
| 			continue;
 | |
| 
 | |
| 		/* Found an overlapping region. Delete it. */
 | |
| 		
 | |
| 		wcr = xalloc(sizeof(*wcr));
 | |
| 		if (!wcr)
 | |
| 			return NULL;
 | |
| 		wcr->sentry.base = gent.base;
 | |
| 		wcr->sentry.size = gent.size;
 | |
| 		wcr->sentry.type = MTRR_TYPE_WRCOMB;
 | |
| 		wcr->added = FALSE;
 | |
| 		
 | |
| 		count = 3;
 | |
| 		while (count-- && 
 | |
| 		       (ret = ioctl(mtrr_fd, MTRRIOC_KILL_ENTRY, &(wcr->sentry))) < 0);
 | |
| 		
 | |
| 		if (ret >= 0) {
 | |
| 			xf86DrvMsg(screenNum, from,
 | |
| 				   "Removed MMIO write-combining range "
 | |
| 				   "(0x%lx,0x%lx)\n",
 | |
| 				   (unsigned long) gent.base, (unsigned long) gent.size);
 | |
| 			wcr->next = wcreturn;
 | |
| 			wcreturn = wcr;
 | |
| 			gent.regnum--;
 | |
| 		} else {
 | |
| 			xfree(wcr);
 | |
| 			xf86DrvMsgVerb(screenNum, X_WARNING, 0,
 | |
| 				   "Failed to remove MMIO "
 | |
| 				   "write-combining range (0x%lx,0x%lx)\n",
 | |
| 				       gent.base, (unsigned long) gent.size);
 | |
| 		}
 | |
| 	}
 | |
| 	return wcreturn;
 | |
| }
 | |
| 
 | |
| 
 | |
| static struct mtrr_wc_region *
 | |
| mtrr_remove_offending(int screenNum, unsigned long base, unsigned long size,
 | |
| 		      MessageType from)
 | |
| {
 | |
|     struct mtrr_gentry gent;
 | |
|     struct mtrr_wc_region *wcreturn = NULL, **wcr;
 | |
| 
 | |
|     if (!mtrr_open(2))
 | |
| 	return NULL;
 | |
| 
 | |
|     wcr = &wcreturn;
 | |
|     for (gent.regnum = 0; 
 | |
| 	 ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; gent.regnum++ ) {
 | |
| 	if (gent.type == MTRR_TYPE_WRCOMB
 | |
| 	    && ((gent.base >= base && gent.base + gent.size < base + size) || 
 | |
| 		(gent.base >  base && gent.base + gent.size <= base + size))) {
 | |
| 	    *wcr = mtrr_cull_wc_region(screenNum, gent.base, gent.size, from);
 | |
| 	    if (*wcr) gent.regnum--;
 | |
| 	    while(*wcr) {
 | |
| 		wcr = &((*wcr)->next);
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     return wcreturn;
 | |
| }
 | |
| 
 | |
| 
 | |
| static struct mtrr_wc_region *
 | |
| mtrr_add_wc_region(int screenNum, unsigned long base, unsigned long size,
 | |
| 		   MessageType from)
 | |
| {
 | |
|         struct mtrr_wc_region **wcr, *wcreturn, *curwcr;
 | |
| 
 | |
|        /*
 | |
|         * There can be only one....
 | |
|         */
 | |
| 
 | |
| 	wcreturn = mtrr_remove_offending(screenNum, base, size, from);
 | |
| 	wcr = &wcreturn;
 | |
| 	while (*wcr) {
 | |
| 	    wcr = &((*wcr)->next);
 | |
| 	} 
 | |
| 
 | |
| 	/* Linux 2.0 should not warn, unless the user explicitly asks for
 | |
| 	   WC. */
 | |
| 
 | |
| 	if (!mtrr_open(from == X_CONFIG ? 0 : 2))
 | |
| 		return wcreturn;
 | |
| 
 | |
| 	*wcr = curwcr = xalloc(sizeof(**wcr));
 | |
| 	if (!curwcr)
 | |
| 	    return wcreturn;
 | |
| 
 | |
| 	curwcr->sentry.base = base;
 | |
| 	curwcr->sentry.size = size;
 | |
| 	curwcr->sentry.type = MTRR_TYPE_WRCOMB;
 | |
| 	curwcr->added = TRUE;
 | |
| 	curwcr->next = NULL;
 | |
| 
 | |
| #if SPLIT_WC_REGIONS
 | |
| 	/*
 | |
| 	 * Splits up the write-combining region if it is not aligned on a
 | |
|  	 * size boundary.
 | |
| 	 */
 | |
| 
 | |
| 	{
 | |
| 	    unsigned long lbase, d_size = 1;
 | |
| 	    unsigned long n_size = size;
 | |
| 	    unsigned long n_base = base;
 | |
| 
 | |
| 	    for (lbase = n_base, d_size = 1; !(lbase & 1);
 | |
| 		 lbase = lbase >> 1, d_size <<= 1);
 | |
| 	    while (d_size > n_size)
 | |
| 		d_size = d_size >> 1;
 | |
| #ifdef DEBUG
 | |
| 	    ErrorF("WC_BASE: 0x%lx WC_END: 0x%lx\n",base,base+d_size-1);
 | |
| #endif
 | |
| 	    n_base += d_size;
 | |
| 	    n_size -= d_size;
 | |
| 	    if (n_size) {
 | |
| 		xf86DrvMsgVerb(screenNum,X_INFO,3,"Splitting WC range: "
 | |
| 			       "base: 0x%lx, size: 0x%lx\n",base,size);
 | |
| 		curwcr->next = mtrr_add_wc_region(screenNum, n_base, n_size,from);
 | |
| 	    }
 | |
| 	    curwcr->sentry.size = d_size;
 | |
| 	} 
 | |
| 	
 | |
| 	/*****************************************************************/
 | |
| #endif /* SPLIT_WC_REGIONS */
 | |
| 
 | |
| 	if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &curwcr->sentry) >= 0) {
 | |
| 		/* Avoid printing on every VT switch */
 | |
| 		if (xf86ServerIsInitialising()) {
 | |
| 			xf86DrvMsg(screenNum, from,
 | |
| 				   "Write-combining range (0x%lx,0x%lx)\n",
 | |
| 				   base, size);
 | |
| 		}
 | |
| 		return wcreturn;
 | |
| 	}
 | |
| 	else {
 | |
| 	        *wcr = curwcr->next;
 | |
| 		xfree(curwcr);
 | |
| 		
 | |
| 		/* Don't complain about the VGA region: MTRR fixed
 | |
| 		   regions aren't currently supported, but might be in
 | |
| 		   the future. */
 | |
| 		if ((unsigned long)base >= 0x100000) {
 | |
| 			xf86DrvMsgVerb(screenNum, X_WARNING, 0,
 | |
| 				"Failed to set up write-combining range "
 | |
| 				"(0x%lx,0x%lx)\n", base, size);
 | |
| 		}
 | |
| 		return wcreturn;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| mtrr_undo_wc_region(int screenNum, struct mtrr_wc_region *wcr)
 | |
| {
 | |
| 	struct mtrr_wc_region *p, *prev;
 | |
| 
 | |
| 	if (mtrr_fd > 0) {
 | |
| 		p = wcr;
 | |
| 		while (p) {
 | |
| 			if (p->added)
 | |
| 				ioctl(mtrr_fd, MTRRIOC_DEL_ENTRY, &p->sentry);
 | |
| 			prev = p;
 | |
| 			p = p->next;
 | |
| 			xfree(prev);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static pointer
 | |
| setWC(int screenNum, unsigned long base, unsigned long size, Bool enable,
 | |
|       MessageType from)
 | |
| {
 | |
| 	if (enable)
 | |
| 		return mtrr_add_wc_region(screenNum, base, size, from);
 | |
| 	else
 | |
| 		return mtrr_cull_wc_region(screenNum, base, size, from);
 | |
| }
 | |
| 
 | |
| static void
 | |
| undoWC(int screenNum, pointer regioninfo)
 | |
| {
 | |
| 	mtrr_undo_wc_region(screenNum, regioninfo);
 | |
| }
 | |
| 
 | |
| #endif /* HAS_MTRR_SUPPORT */
 | |
| 
 | |
| void
 | |
| xf86OSInitVidMem(VidMemInfoPtr pVidMem)
 | |
| {
 | |
| 	pVidMem->linearSupported = TRUE;
 | |
| #ifdef __alpha__
 | |
| 	if (axpSystem == -1) {
 | |
| 	  axpSystem = lnxGetAXP();
 | |
| 	  if ((needSparse = (_bus_base_sparse() > 0))) {
 | |
| 	    hae_thresh = xf86AXPParams[axpSystem].hae_thresh;
 | |
| 	    hae_mask = xf86AXPParams[axpSystem].hae_mask;
 | |
| 	    sparse_size = xf86AXPParams[axpSystem].size;
 | |
| 	  }
 | |
| 	  bus_base = _bus_base();
 | |
| 	}
 | |
| 	if (needSparse) {
 | |
| 	  xf86Msg(X_INFO,"Machine needs sparse mapping\n");
 | |
| 	  pVidMem->mapMem = mapVidMemSparse;
 | |
| 	  pVidMem->unmapMem = unmapVidMemSparse;
 | |
| 	} else {
 | |
| 	  xf86Msg(X_INFO,"Machine type has 8/16 bit access\n");
 | |
| 	  pVidMem->mapMem = mapVidMem;
 | |
| 	  pVidMem->unmapMem = unmapVidMem;
 | |
| 	}	
 | |
| #else
 | |
| 	pVidMem->mapMem = mapVidMem;
 | |
| 	pVidMem->unmapMem = unmapVidMem;
 | |
| #endif /* __alpha__ */
 | |
| 
 | |
| 
 | |
| #ifdef HAS_MTRR_SUPPORT
 | |
| 	pVidMem->setWC = setWC;
 | |
| 	pVidMem->undoWC = undoWC;
 | |
| #endif
 | |
| 	pVidMem->initialised = TRUE;
 | |
| }
 | |
| 
 | |
| #ifdef __sparc__
 | |
| /* Basically, you simply cannot do this on Sparc.  You have to do something portable
 | |
|  * like use /dev/fb* or mmap() on /proc/bus/pci/X/Y nodes. -DaveM
 | |
|  */
 | |
| static pointer mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
 | |
| {
 | |
| 	return NULL;
 | |
| }
 | |
| #else
 | |
| static pointer
 | |
| mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
 | |
| {
 | |
|     pointer base;
 | |
|     int fd;
 | |
|     int mapflags = MAP_SHARED; 
 | |
|     int prot;
 | |
|     memType realBase, alignOff;
 | |
| 
 | |
|     realBase = Base & ~(getpagesize() - 1);
 | |
|     alignOff = Base - realBase;
 | |
| #ifdef DEBUG
 | |
|     ErrorF("base: %lx, realBase: %lx, alignOff: %lx \n",
 | |
| 	   Base,realBase,alignOff);
 | |
| #endif
 | |
|     
 | |
| #if defined(__ia64__) || defined(__arm__) || defined(__s390__)
 | |
| #ifndef MAP_WRITECOMBINED
 | |
| #define MAP_WRITECOMBINED 0x00010000
 | |
| #endif
 | |
| #ifndef MAP_NONCACHED
 | |
| #define MAP_NONCACHED 0x00020000
 | |
| #endif
 | |
|     if(flags & VIDMEM_FRAMEBUFFER) 
 | |
|         mapflags |= MAP_WRITECOMBINED; 
 | |
|     else
 | |
|         mapflags |= MAP_NONCACHED; 
 | |
| #endif
 | |
| 
 | |
| #if 0
 | |
|     /* this will disappear when people upgrade their kernels */
 | |
|     fd = open(DEV_MEM,
 | |
| 	      ((flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR) | O_SYNC);
 | |
| #else
 | |
|     fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR);
 | |
| #endif
 | |
|     if (fd < 0)
 | |
|     {
 | |
| 	FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n",
 | |
| 		   strerror(errno));
 | |
|     }
 | |
| 
 | |
|     if (flags & VIDMEM_READONLY)
 | |
| 	prot = PROT_READ;
 | |
|     else
 | |
| 	prot = PROT_READ | PROT_WRITE;
 | |
| 
 | |
|     /* This requires linux-0.99.pl10 or above */
 | |
|     base = mmap((caddr_t)0, Size + alignOff, prot, mapflags, fd,
 | |
|  		(off_t)realBase  + BUS_BASE);
 | |
|     close(fd);
 | |
|     if (base == MAP_FAILED) {
 | |
|         FatalError("xf86MapVidMem: Could not mmap framebuffer"
 | |
| 		   " (0x%08lx,0x%lx) (%s)\n", Base, Size,
 | |
| 		   strerror(errno));
 | |
|     }
 | |
| #ifdef DEBUG
 | |
|     ErrorF("base: %lx aligned base: %lx\n",base, base + alignOff);
 | |
| #endif
 | |
|     return (char *)base + alignOff;
 | |
| }
 | |
| #endif /* !(__sparc__) */
 | |
|     
 | |
| static void
 | |
| unmapVidMem(int ScreenNum, pointer Base, unsigned long Size)
 | |
| {
 | |
|     memType alignOff = (memType)Base 
 | |
| 	- ((memType)Base & ~(getpagesize() - 1));
 | |
|     
 | |
| #ifdef DEBUG
 | |
|     ErrorF("alignment offset: %lx\n",alignOff);
 | |
| #endif
 | |
|     munmap((caddr_t)((memType)Base - alignOff), (Size + alignOff));
 | |
| }
 | |
| 
 | |
| 
 | |
| /***************************************************************************/
 | |
| /* I/O Permissions section                                                 */
 | |
| /***************************************************************************/
 | |
| 
 | |
| #if defined(__powerpc__)
 | |
| volatile unsigned char *ioBase = NULL;
 | |
| 
 | |
| #ifndef __NR_pciconfig_iobase
 | |
| #define __NR_pciconfig_iobase	200
 | |
| #endif
 | |
| 
 | |
| #endif
 | |
| 
 | |
| Bool
 | |
| xf86EnableIO(void)
 | |
| {
 | |
| #if defined(__powerpc__)
 | |
| 	int fd;
 | |
| 	unsigned int ioBase_phys;
 | |
| #endif
 | |
| 
 | |
| 	if (ExtendedEnabled)
 | |
| 		return TRUE;
 | |
| 
 | |
| #if defined(__powerpc__)
 | |
| 	ioBase_phys = syscall(__NR_pciconfig_iobase, 2, 0, 0);
 | |
| 
 | |
| 	fd = open("/dev/mem", O_RDWR);
 | |
| 	if (ioBase == NULL) {
 | |
| 		ioBase = (volatile unsigned char *)mmap(0, 0x20000,
 | |
| 				PROT_READ | PROT_WRITE, MAP_SHARED, fd,
 | |
| 				ioBase_phys);
 | |
| /* Should this be fatal or just a warning? */
 | |
| #if 0
 | |
| 		if (ioBase == MAP_FAILED) {
 | |
| 		    xf86Msg(X_WARNING,
 | |
| 			    "xf86EnableIOPorts: Failed to map iobase (%s)\n",
 | |
| 			    strerror(errno));
 | |
| 		    return FALSE;
 | |
| 		}
 | |
| #endif
 | |
| 	}
 | |
| 	close(fd);
 | |
| #elif !defined(__mc68000__) && !defined(__sparc__) && !defined(__mips__) && !defined(__sh__) && !defined(__hppa__) && !defined(__s390__) && !defined(__arm__) && !defined(__m32r__)
 | |
|         if (ioperm(0, 1024, 1) || iopl(3)) {
 | |
|                 if (errno == ENODEV)
 | |
|                         ErrorF("xf86EnableIOPorts: no I/O ports found\n");
 | |
|                 else
 | |
|                         FatalError("xf86EnableIOPorts: failed to set IOPL"
 | |
|                                    " for I/O (%s)\n", strerror(errno));
 | |
| 		return FALSE;
 | |
|         }
 | |
| # if !defined(__alpha__)
 | |
| 	ioperm(0x40,4,0); /* trap access to the timer chip */
 | |
| 	ioperm(0x60,4,0); /* trap access to the keyboard controller */
 | |
| # endif
 | |
| #endif
 | |
| 	ExtendedEnabled = TRUE;
 | |
| 
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| void
 | |
| xf86DisableIO(void)
 | |
| {
 | |
| 	if (!ExtendedEnabled)
 | |
| 		return;
 | |
| #if defined(__powerpc__)
 | |
| 	munmap(ioBase, 0x20000);
 | |
| 	ioBase = NULL;
 | |
| #elif !defined(__mc68000__) && !defined(__sparc__) && !defined(__mips__) && !defined(__sh__) && !defined(__hppa__) && !defined(__arm__) && !defined(__s390__) && !defined(__m32r__)
 | |
| 	iopl(0);
 | |
| 	ioperm(0, 1024, 0);
 | |
| #endif
 | |
| 	ExtendedEnabled = FALSE;
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| #if defined (__alpha__)
 | |
| 
 | |
| #define vuip    volatile unsigned int *
 | |
| 
 | |
| extern int readDense8(pointer Base, register unsigned long Offset);
 | |
| extern int readDense16(pointer Base, register unsigned long Offset);
 | |
| extern int readDense32(pointer Base, register unsigned long Offset);
 | |
| extern void
 | |
| writeDenseNB8(int Value, pointer Base, register unsigned long Offset);
 | |
| extern void
 | |
| writeDenseNB16(int Value, pointer Base, register unsigned long Offset);
 | |
| extern void
 | |
| writeDenseNB32(int Value, pointer Base, register unsigned long Offset);
 | |
| extern void
 | |
| writeDense8(int Value, pointer Base, register unsigned long Offset);
 | |
| extern void
 | |
| writeDense16(int Value, pointer Base, register unsigned long Offset);
 | |
| extern void
 | |
| writeDense32(int Value, pointer Base, register unsigned long Offset);
 | |
| 
 | |
| static int readSparse8(pointer Base, register unsigned long Offset);
 | |
| static int readSparse16(pointer Base, register unsigned long Offset);
 | |
| static int readSparse32(pointer Base, register unsigned long Offset);
 | |
| static void
 | |
| writeSparseNB8(int Value, pointer Base, register unsigned long Offset);
 | |
| static void
 | |
| writeSparseNB16(int Value, pointer Base, register unsigned long Offset);
 | |
| static void
 | |
| writeSparseNB32(int Value, pointer Base, register unsigned long Offset);
 | |
| static void
 | |
| writeSparse8(int Value, pointer Base, register unsigned long Offset);
 | |
| static void
 | |
| writeSparse16(int Value, pointer Base, register unsigned long Offset);
 | |
| static void
 | |
| writeSparse32(int Value, pointer Base, register unsigned long Offset);
 | |
| 
 | |
| #define DENSE_BASE	0x2ff00000000UL
 | |
| #define SPARSE_BASE	0x30000000000UL
 | |
| 
 | |
| static unsigned long msb_set = 0;
 | |
| 
 | |
| static pointer
 | |
| mapVidMemSparse(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
 | |
| {
 | |
|     int fd, prot;
 | |
|     unsigned long ret, rets = 0;
 | |
| 
 | |
|     static Bool was_here = FALSE;
 | |
| 
 | |
|     if (!was_here) {
 | |
|       was_here = TRUE;
 | |
| 
 | |
|       xf86WriteMmio8 = writeSparse8;
 | |
|       xf86WriteMmio16 = writeSparse16;
 | |
|       xf86WriteMmio32 = writeSparse32;
 | |
|       xf86WriteMmioNB8 = writeSparseNB8;
 | |
|       xf86WriteMmioNB16 = writeSparseNB16;
 | |
|       xf86WriteMmioNB32 = writeSparseNB32;
 | |
|       xf86ReadMmio8 = readSparse8;
 | |
|       xf86ReadMmio16 = readSparse16;
 | |
|       xf86ReadMmio32 = readSparse32;
 | |
|     }
 | |
| 	
 | |
|     fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR);
 | |
|     if (fd < 0) {
 | |
|         FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n",
 | |
| 		   strerror(errno));
 | |
|     }
 | |
| 
 | |
| #if 0
 | |
|     xf86Msg(X_INFO,"mapVidMemSparse: try Base 0x%lx size 0x%lx flags 0x%x\n",
 | |
| 	    Base, Size, flags);
 | |
| #endif
 | |
| 
 | |
|     if (flags & VIDMEM_READONLY)
 | |
| 	prot = PROT_READ;
 | |
|     else
 | |
| 	prot = PROT_READ | PROT_WRITE;
 | |
| 
 | |
|     /* This requirers linux-0.99.pl10 or above */
 | |
| 
 | |
|     /*
 | |
|      * Always do DENSE mmap, since read32/write32 currently require it.
 | |
|      */
 | |
|     ret = (unsigned long)mmap((caddr_t)(DENSE_BASE + Base), Size,
 | |
| 		   prot, MAP_SHARED, fd,
 | |
| 		   (off_t) (bus_base + Base));
 | |
| 
 | |
|     /*
 | |
|      * Do SPARSE mmap only when MMIO and not MMIO_32BIT, or FRAMEBUFFER
 | |
|      * and SPARSE (which should require the use of read/write macros).
 | |
|      *
 | |
|      * By not SPARSE mmapping an 8MB framebuffer, we can save approx. 256K
 | |
|      * bytes worth of pagetable (32 pages).
 | |
|      */
 | |
|     if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) ||
 | |
| 	((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE)))
 | |
|     {
 | |
|         rets = (unsigned long)mmap((caddr_t)(SPARSE_BASE + (Base << 5)),
 | |
| 				   Size << 5, prot, MAP_SHARED, fd,
 | |
| 				   (off_t) _bus_base_sparse() + (Base << 5));
 | |
|     }
 | |
| 
 | |
|     close(fd);
 | |
|       
 | |
|     if (ret == (unsigned long)MAP_FAILED) {
 | |
|         FatalError("xf86MapVidMemSparse: Could not (dense) mmap fb (%s)\n",
 | |
| 		   strerror(errno));
 | |
|     }
 | |
| 
 | |
|     if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) ||
 | |
| 	((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE)))
 | |
|     {
 | |
|         if (rets == (unsigned long)MAP_FAILED ||
 | |
| 	    rets != (SPARSE_BASE + (Base << 5)))
 | |
| 	{
 | |
| 	    FatalError("mapVidMemSparse: Could not (sparse) mmap fb (%s)\n",
 | |
| 		       strerror(errno));
 | |
| 	}
 | |
|     }
 | |
| 
 | |
| #if 1
 | |
|     if (rets)
 | |
|         xf86Msg(X_INFO,"mapVidMemSparse: mapped Base 0x%lx size 0x%lx"
 | |
| 		" to DENSE at 0x%lx and SPARSE at 0x%lx\n",
 | |
| 		Base, Size, ret, rets);
 | |
|     else
 | |
|         xf86Msg(X_INFO,"mapVidMemSparse: mapped Base 0x%lx size 0x%lx"
 | |
| 		" to DENSE only at 0x%lx\n",
 | |
| 		Base, Size, ret);
 | |
| 
 | |
| #endif
 | |
|     return (pointer) ret;
 | |
| }
 | |
| 
 | |
| static void
 | |
| unmapVidMemSparse(int ScreenNum, pointer Base, unsigned long Size)
 | |
| {
 | |
|     unsigned long Offset = (unsigned long)Base - DENSE_BASE;
 | |
| #if 1
 | |
|     xf86Msg(X_INFO,"unmapVidMemSparse: unmapping Base 0x%lx Size 0x%lx\n",
 | |
| 	    Base, Size);
 | |
| #endif
 | |
|     /* Unmap DENSE always. */
 | |
|     munmap((caddr_t)Base, Size);
 | |
| 
 | |
|     /* Unmap SPARSE always, and ignore error in case we did not map it. */
 | |
|     munmap((caddr_t)(SPARSE_BASE + (Offset << 5)), Size << 5);
 | |
| }
 | |
| 
 | |
| static int
 | |
| readSparse8(pointer Base, register unsigned long Offset)
 | |
| {
 | |
|     register unsigned long result, shift;
 | |
|     register unsigned long msb;
 | |
| 
 | |
|     mem_barrier();
 | |
|     Offset += (unsigned long)Base - DENSE_BASE;
 | |
|     shift = (Offset & 0x3) << 3;
 | |
|     if (Offset >= (hae_thresh)) {
 | |
|         msb = Offset & hae_mask;
 | |
|         Offset -= msb;
 | |
| 	if (msb_set != msb) {
 | |
| 	    sethae(msb);
 | |
| 	    msb_set = msb;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     mem_barrier();
 | |
|     result = *(vuip) (SPARSE_BASE + (Offset << 5));
 | |
|     result >>= shift;
 | |
|     return 0xffUL & result;
 | |
| }
 | |
| 
 | |
| static int
 | |
| readSparse16(pointer Base, register unsigned long Offset)
 | |
| {
 | |
|     register unsigned long result, shift;
 | |
|     register unsigned long msb;
 | |
| 
 | |
|     mem_barrier();
 | |
|     Offset += (unsigned long)Base - DENSE_BASE;
 | |
|     shift = (Offset & 0x2) << 3;
 | |
|     if (Offset >= hae_thresh) {
 | |
|         msb = Offset & hae_mask;
 | |
|         Offset -= msb;
 | |
| 	if (msb_set != msb) {
 | |
| 	    sethae(msb);
 | |
| 	    msb_set = msb;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     mem_barrier();
 | |
|     result = *(vuip)(SPARSE_BASE + (Offset<<5) + (1<<(5-2)));
 | |
|     result >>= shift;
 | |
|     return 0xffffUL & result;
 | |
| }
 | |
| 
 | |
| static int
 | |
| readSparse32(pointer Base, register unsigned long Offset)
 | |
| {
 | |
|     /* NOTE: this is really using DENSE. */
 | |
|     mem_barrier();
 | |
|     return *(vuip)((unsigned long)Base+(Offset));
 | |
| }
 | |
| 
 | |
| static void
 | |
| writeSparse8(int Value, pointer Base, register unsigned long Offset)
 | |
| {
 | |
|     register unsigned long msb;
 | |
|     register unsigned int b = Value & 0xffU;
 | |
| 
 | |
|     write_mem_barrier();
 | |
|     Offset += (unsigned long)Base - DENSE_BASE;
 | |
|     if (Offset >= hae_thresh) {
 | |
|         msb = Offset & hae_mask;
 | |
| 	Offset -= msb;
 | |
| 	if (msb_set != msb) {
 | |
| 	    sethae(msb); 
 | |
| 	    msb_set = msb;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     write_mem_barrier();
 | |
|     *(vuip) (SPARSE_BASE + (Offset << 5)) = b * 0x01010101;
 | |
| }
 | |
| 
 | |
| static void
 | |
| writeSparse16(int Value, pointer Base, register unsigned long Offset)
 | |
| {
 | |
|     register unsigned long msb;
 | |
|     register unsigned int w = Value & 0xffffU;
 | |
| 
 | |
|     write_mem_barrier();
 | |
|     Offset += (unsigned long)Base - DENSE_BASE;
 | |
|     if (Offset >= hae_thresh) {
 | |
|         msb = Offset & hae_mask;
 | |
| 	Offset -= msb;
 | |
| 	if (msb_set != msb) {
 | |
| 	    sethae(msb);
 | |
| 	    msb_set = msb;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     write_mem_barrier();
 | |
|     *(vuip)(SPARSE_BASE + (Offset<<5) + (1<<(5-2))) = w * 0x00010001;
 | |
| }
 | |
| 
 | |
| static void
 | |
| writeSparse32(int Value, pointer Base, register unsigned long Offset)
 | |
| {
 | |
|     /* NOTE: this is really using DENSE. */
 | |
|     write_mem_barrier();
 | |
|     *(vuip)((unsigned long)Base + (Offset)) = Value;
 | |
|     return;
 | |
| }
 | |
| 
 | |
| static void
 | |
| writeSparseNB8(int Value, pointer Base, register unsigned long Offset)
 | |
| {
 | |
|     register unsigned long msb;
 | |
|     register unsigned int b = Value & 0xffU;
 | |
| 
 | |
|     Offset += (unsigned long)Base - DENSE_BASE;
 | |
|     if (Offset >= hae_thresh) {
 | |
|         msb = Offset & hae_mask;
 | |
| 	Offset -= msb;
 | |
| 	if (msb_set != msb) {
 | |
| 	    sethae(msb);
 | |
| 	    msb_set = msb;
 | |
| 	}
 | |
|     }
 | |
|     *(vuip) (SPARSE_BASE + (Offset << 5)) = b * 0x01010101;
 | |
| }
 | |
| 
 | |
| static void
 | |
| writeSparseNB16(int Value, pointer Base, register unsigned long Offset)
 | |
| {
 | |
|     register unsigned long msb;
 | |
|     register unsigned int w = Value & 0xffffU;
 | |
| 
 | |
|     Offset += (unsigned long)Base - DENSE_BASE;
 | |
|     if (Offset >= hae_thresh) {
 | |
|         msb = Offset & hae_mask;
 | |
| 	Offset -= msb;
 | |
| 	if (msb_set != msb) {
 | |
| 	    sethae(msb);
 | |
| 	    msb_set = msb;
 | |
| 	}
 | |
|     }
 | |
|     *(vuip)(SPARSE_BASE+(Offset<<5)+(1<<(5-2))) = w * 0x00010001;
 | |
| }
 | |
| 
 | |
| static void
 | |
| writeSparseNB32(int Value, pointer Base, register unsigned long Offset)
 | |
| {
 | |
|     /* NOTE: this is really using DENSE. */
 | |
|     *(vuip)((unsigned long)Base + (Offset)) = Value;
 | |
|     return;
 | |
| }
 | |
| 
 | |
| void (*xf86WriteMmio8)(int Value, pointer Base, unsigned long Offset)
 | |
|      = writeDense8;
 | |
| void (*xf86WriteMmio16)(int Value, pointer Base, unsigned long Offset)
 | |
|      = writeDense16;
 | |
| void (*xf86WriteMmio32)(int Value, pointer Base, unsigned long Offset)
 | |
|      = writeDense32;
 | |
| void (*xf86WriteMmioNB8)(int Value, pointer Base, unsigned long Offset)
 | |
|      = writeDenseNB8;
 | |
| void (*xf86WriteMmioNB16)(int Value, pointer Base, unsigned long Offset)
 | |
|      = writeDenseNB16;
 | |
| void (*xf86WriteMmioNB32)(int Value, pointer Base, unsigned long Offset)
 | |
|      = writeDenseNB32;
 | |
| int  (*xf86ReadMmio8)(pointer Base, unsigned long Offset)
 | |
|      = readDense8;
 | |
| int  (*xf86ReadMmio16)(pointer Base, unsigned long Offset)
 | |
|      = readDense16;
 | |
| int  (*xf86ReadMmio32)(pointer Base, unsigned long Offset)
 | |
|      = readDense32;
 | |
| 
 | |
| #endif /* __alpha__ */
 |