]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/ia64/ioperm.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / ia64 / ioperm.c
CommitLineData
b168057a 1/* Copyright (C) 1999-2015 Free Software Foundation, Inc.
d5efd131
MF
2 This file is part of the GNU C Library.
3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
75efb018
MF
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
d5efd131
MF
18
19/* I/O access is restricted to ISA port space (ports 0..65535).
20 Modern devices hopefully are sane enough not to put any performance
21 critical registers in i/o space.
22
23 On the first call to ioperm() or iopl(), the entire (E)ISA port
24 space is mapped into the virtual address space at address io.base.
25 mprotect() calls are then used to enable/disable access to ports.
26 Per 4KB page, there are 4 I/O ports. */
27
28#include <errno.h>
29#include <fcntl.h>
30#include <ctype.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34
35#include <sys/types.h>
36#include <sys/mman.h>
37
38#define MAX_PORT 0x10000
39
40/*
41 * Memory fence w/accept. This should never be used in code that is
42 * not IA-64 specific.
43 */
44#define __ia64_mf_a() __asm__ __volatile__ ("mf.a" ::: "memory")
45
46static struct
47 {
48 unsigned long int base;
49 unsigned long int page_mask;
50 }
51io;
52
53__inline__ unsigned long int
54io_offset (unsigned long int port)
55{
56 return ((port >> 2) << 12) | (port & 0xfff);
57}
58
59int
60_ioperm (unsigned long int from, unsigned long int num, int turn_on)
61{
d5efd131 62 unsigned long int base;
d5efd131
MF
63
64 /* this test isn't as silly as it may look like; consider overflows! */
65 if (from >= MAX_PORT || from + num > MAX_PORT)
66 {
67 __set_errno (EINVAL);
68 return -1;
69 }
70
71 if (turn_on)
72 {
73 if (!io.base)
74 {
75 unsigned long phys_io_base, len;
76 int fd;
77
78 io.page_mask = ~(__getpagesize() - 1);
79
80 /* get I/O base physical address from ar.k0 as per PRM: */
81 __asm__ ("mov %0=ar.k0" : "=r"(phys_io_base));
82
83 /* The O_SYNC flag tells the /dev/mem driver to map the
84 memory uncached: */
85 fd = __open ("/dev/mem", O_RDWR | O_SYNC);
86 if (fd < 0)
87 return -1;
88
89 len = io_offset (MAX_PORT);
d5efd131
MF
90 /* see comment below */
91 base = (unsigned long int) __mmap (0, len, PROT_READ | PROT_WRITE, MAP_SHARED,
92 fd, phys_io_base);
d5efd131
MF
93 __close (fd);
94
95 if ((long) base == -1)
96 return -1;
97
98 io.base = base;
99 }
d5efd131
MF
100 }
101 else
102 {
103 if (!io.base)
104 return 0; /* never was turned on... */
d5efd131 105 }
fe1a83aa 106
d5efd131
MF
107 /* We can't do mprotect because that would cause us to lose the
108 uncached flag that the /dev/mem driver turned on. A MAP_UNCACHED
fe1a83aa
MF
109 flag seems so much cleaner...
110
111 See the history of this file for a version that tried mprotect. */
d5efd131 112 return 0;
d5efd131
MF
113}
114
115int
116_iopl (unsigned int level)
117{
118 if (level > 3)
119 {
120 __set_errno (EINVAL);
121 return -1;
122 }
123 if (level)
124 {
125 int retval = _ioperm (0, MAX_PORT, 1);
126 /* Match the documented error returns of the x86 version. */
127 if (retval < 0 && errno == EACCES)
128 __set_errno (EPERM);
129 return retval;
130 }
131 return 0;
132}
133
134unsigned int
135_inb (unsigned long int port)
136{
137 volatile unsigned char *addr = (void *) io.base + io_offset (port);
138 unsigned char ret;
139
140 ret = *addr;
141 __ia64_mf_a();
142 return ret;
143}
144
145unsigned int
146_inw (unsigned long int port)
147{
148 volatile unsigned short *addr = (void *) io.base + io_offset (port);
149 unsigned short ret;
150
151 ret = *addr;
152 __ia64_mf_a();
153 return ret;
154}
155
156unsigned int
157_inl (unsigned long int port)
158{
159 volatile unsigned int *addr = (void *) io.base + io_offset (port);
160 unsigned int ret;
161
162 ret = *addr;
163 __ia64_mf_a();
164 return ret;
165}
166
167void
168_outb (unsigned char val, unsigned long int port)
169{
170 volatile unsigned char *addr = (void *) io.base + io_offset (port);
171
172 *addr = val;
173 __ia64_mf_a();
174}
175
176void
177_outw (unsigned short val, unsigned long int port)
178{
179 volatile unsigned short *addr = (void *) io.base + io_offset (port);
180
181 *addr = val;
182 __ia64_mf_a();
183}
184
185void
186_outl (unsigned int val, unsigned long int port)
187{
188 volatile unsigned int *addr = (void *) io.base + io_offset (port);
189
190 *addr = val;
191 __ia64_mf_a();
192}
193
194weak_alias (_ioperm, ioperm);
195weak_alias (_iopl, iopl);
196weak_alias (_inb, inb);
197weak_alias (_inw, inw);
198weak_alias (_inl, inl);
199weak_alias (_outb, outb);
200weak_alias (_outw, outw);
201weak_alias (_outl, outl);