Back to index

glibc  2.9
ioperm.c
Go to the documentation of this file.
00001 /* Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 /* I/O access is restricted to ISA port space (ports 0..65535).
00021    Modern devices hopefully are sane enough not to put any performance
00022    critical registers in i/o space.
00023 
00024    On the first call to ioperm() or iopl(), the entire (E)ISA port
00025    space is mapped into the virtual address space at address io.base.
00026    mprotect() calls are then used to enable/disable access to ports.
00027    Per 4KB page, there are 4 I/O ports.  */
00028 
00029 #include <errno.h>
00030 #include <fcntl.h>
00031 #include <ctype.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <unistd.h>
00035 
00036 #include <sys/types.h>
00037 #include <sys/mman.h>
00038 
00039 #define MAX_PORT     0x10000
00040 
00041 /*
00042  * Memory fence w/accept.  This should never be used in code that is
00043  * not IA-64 specific.
00044  */
00045 #define __ia64_mf_a()       __asm__ __volatile__ ("mf.a" ::: "memory")
00046 
00047 static struct
00048   {
00049     unsigned long int base;
00050     unsigned long int page_mask;
00051   }
00052 io;
00053 
00054 __inline__ unsigned long int
00055 io_offset (unsigned long int port)
00056 {
00057        return ((port >> 2) << 12) | (port & 0xfff);
00058 }
00059 
00060 int
00061 _ioperm (unsigned long int from, unsigned long int num, int turn_on)
00062 {
00063 #if 0
00064   unsigned long int addr, len, base;
00065 #endif
00066   unsigned long int base;
00067   int prot;
00068 
00069   /* this test isn't as silly as it may look like; consider overflows! */
00070   if (from >= MAX_PORT || from + num > MAX_PORT)
00071     {
00072       __set_errno (EINVAL);
00073       return -1;
00074     }
00075 
00076   if (turn_on)
00077     {
00078       if (!io.base)
00079        {
00080          unsigned long phys_io_base, len;
00081          int fd;
00082 
00083          io.page_mask = ~(__getpagesize() - 1);
00084 
00085          /* get I/O base physical address from ar.k0 as per PRM: */
00086          __asm__ ("mov %0=ar.k0" : "=r"(phys_io_base));
00087 
00088          /* The O_SYNC flag tells the /dev/mem driver to map the
00089              memory uncached: */
00090          fd = __open ("/dev/mem", O_RDWR | O_SYNC);
00091          if (fd < 0)
00092            return -1;
00093 
00094          len = io_offset (MAX_PORT);
00095 #if 1
00096          /* see comment below */
00097          base = (unsigned long int) __mmap (0, len, PROT_READ | PROT_WRITE, MAP_SHARED,
00098                                           fd, phys_io_base);
00099 #else
00100          base = (unsigned long int) __mmap (0, len, PROT_NONE, MAP_SHARED,
00101                                           fd, phys_io_base);
00102 #endif
00103          __close (fd);
00104 
00105          if ((long) base == -1)
00106            return -1;
00107 
00108          io.base = base;
00109        }
00110       prot = PROT_READ | PROT_WRITE;
00111     }
00112   else
00113     {
00114       if (!io.base)
00115        return 0;     /* never was turned on... */
00116 
00117       prot = PROT_NONE;
00118     }
00119 #if 0
00120   /* We can't do mprotect because that would cause us to lose the
00121      uncached flag that the /dev/mem driver turned on.  A MAP_UNCACHED
00122      flag seems so much cleaner...  */
00123   addr = (io.base + io_offset (from)) & io.page_mask;
00124   len  = io.base + io_offset (from + num) - addr;
00125   return mprotect ((void *) addr, len, prot);
00126 #else
00127   return 0;
00128 #endif
00129 }
00130 
00131 int
00132 _iopl (unsigned int level)
00133 {
00134   if (level > 3)
00135     {
00136       __set_errno (EINVAL);
00137       return -1;
00138     }
00139   if (level)
00140     {
00141       int retval = _ioperm (0, MAX_PORT, 1);
00142       /* Match the documented error returns of the x86 version.  */
00143       if (retval < 0 && errno == EACCES)
00144        __set_errno (EPERM);
00145       return retval;
00146     }
00147   return 0;
00148 }
00149 
00150 unsigned int
00151 _inb (unsigned long int port)
00152 {
00153   volatile unsigned char *addr = (void *) io.base + io_offset (port);
00154   unsigned char ret;
00155 
00156   ret = *addr;
00157   __ia64_mf_a();
00158   return ret;
00159 }
00160 
00161 unsigned int
00162 _inw (unsigned long int port)
00163 {
00164   volatile unsigned short *addr = (void *) io.base + io_offset (port);
00165   unsigned short ret;
00166 
00167   ret = *addr;
00168   __ia64_mf_a();
00169   return ret;
00170 }
00171 
00172 unsigned int
00173 _inl (unsigned long int port)
00174 {
00175   volatile unsigned int *addr = (void *) io.base + io_offset (port);
00176   unsigned int ret;
00177 
00178   ret = *addr;
00179   __ia64_mf_a();
00180   return ret;
00181 }
00182 
00183 void
00184 _outb (unsigned char val, unsigned long int port)
00185 {
00186   volatile unsigned char *addr = (void *) io.base + io_offset (port);
00187 
00188   *addr = val;
00189   __ia64_mf_a();
00190 }
00191 
00192 void
00193 _outw (unsigned short val, unsigned long int port)
00194 {
00195   volatile unsigned short *addr = (void *) io.base + io_offset (port);
00196 
00197   *addr = val;
00198   __ia64_mf_a();
00199 }
00200 
00201 void
00202 _outl (unsigned int val, unsigned long int port)
00203 {
00204   volatile unsigned int *addr = (void *) io.base + io_offset (port);
00205 
00206   *addr = val;
00207   __ia64_mf_a();
00208 }
00209 
00210 weak_alias (_ioperm, ioperm);
00211 weak_alias (_iopl, iopl);
00212 weak_alias (_inb, inb);
00213 weak_alias (_inw, inw);
00214 weak_alias (_inl, inl);
00215 weak_alias (_outb, outb);
00216 weak_alias (_outw, outw);
00217 weak_alias (_outl, outl);