]>
Commit | Line | Data |
---|---|---|
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 | ||
46 | static struct | |
47 | { | |
48 | unsigned long int base; | |
49 | unsigned long int page_mask; | |
50 | } | |
51 | io; | |
52 | ||
53 | __inline__ unsigned long int | |
54 | io_offset (unsigned long int port) | |
55 | { | |
56 | return ((port >> 2) << 12) | (port & 0xfff); | |
57 | } | |
58 | ||
59 | int | |
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 | ||
115 | int | |
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 | ||
134 | unsigned 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 | ||
145 | unsigned 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 | ||
156 | unsigned 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 | ||
167 | void | |
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 | ||
176 | void | |
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 | ||
185 | void | |
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 | ||
194 | weak_alias (_ioperm, ioperm); | |
195 | weak_alias (_iopl, iopl); | |
196 | weak_alias (_inb, inb); | |
197 | weak_alias (_inw, inw); | |
198 | weak_alias (_inl, inl); | |
199 | weak_alias (_outb, outb); | |
200 | weak_alias (_outw, outw); | |
201 | weak_alias (_outl, outl); |