OSDN Git Service

hidden_def/hidden_proto: convert all users (I hope) termios split, add some missing...
[uclinux-h8/uClibc.git] / libc / sysdeps / linux / arm / ioperm.c
1 /* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Phil Blundell, based on the Alpha version by
4    David Mosberger.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 /* I/O port access on the ARM is something of a fiction.  What we do is to
22    map an appropriate area of /dev/mem into user space so that a program
23    can blast away at the hardware in such a way as to generate I/O cycles
24    on the bus.  To insulate user code from dependencies on particular
25    hardware we don't allow calls to inb() and friends to be inlined, but
26    force them to come through code in here every time.  Performance-critical
27    registers tend to be memory mapped these days so this should be no big
28    problem.  */
29
30 /* Once upon a time this file used mprotect to enable and disable
31    access to particular areas of I/O space.  Unfortunately the
32    mprotect syscall also has the side effect of enabling caching for
33    the area affected (this is a kernel limitation).  So we now just
34    enable all the ports all of the time.  */
35
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <ctype.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43
44 #include <sys/types.h>
45 #include <sys/mman.h>
46
47 #include <asm/page.h>
48 #include <sys/sysctl.h>
49
50 libc_hidden_proto(readlink)
51 libc_hidden_proto(mmap)
52 libc_hidden_proto(sscanf)
53 libc_hidden_proto(fscanf)
54 libc_hidden_proto(fprintf)
55 libc_hidden_proto(fgets)
56 libc_hidden_proto(fopen)
57 libc_hidden_proto(fclose)
58 libc_hidden_proto(strcmp)
59 libc_hidden_proto(open)
60 libc_hidden_proto(close)
61
62 #include <linux/version.h>
63
64 #define PATH_ARM_SYSTYPE        "/etc/arm_systype"
65 #define PATH_CPUINFO            "/proc/cpuinfo"
66
67 #define MAX_PORT        0x10000
68
69 static struct {
70     unsigned long int   base;
71     unsigned long int   io_base;
72     unsigned int                shift;
73     unsigned int                initdone;       /* since all the above could be 0 */
74 } io;
75
76 #define IO_BASE_FOOTBRIDGE      0x7c000000
77 #define IO_SHIFT_FOOTBRIDGE     0
78
79 static struct platform {
80     const char          *name;
81     unsigned long int   io_base;
82     unsigned int                shift;
83 } platform[] = {
84     /* All currently supported platforms are in fact the same. :-)  */
85     {"Chalice-CATS",    IO_BASE_FOOTBRIDGE,     IO_SHIFT_FOOTBRIDGE},
86     {"DEC-EBSA285",     IO_BASE_FOOTBRIDGE,     IO_SHIFT_FOOTBRIDGE},
87     {"Corel-NetWinder", IO_BASE_FOOTBRIDGE,     IO_SHIFT_FOOTBRIDGE},
88     {"Rebel-NetWinder", IO_BASE_FOOTBRIDGE,     IO_SHIFT_FOOTBRIDGE},
89 };
90
91 #define IO_ADDR(port)   (io.base + ((port) << io.shift))
92
93 /*
94  * Initialize I/O system.  There are several ways to get the information
95  * we need.  Each is tried in turn until one succeeds.
96  *
97  * 1. Sysctl (CTL_BUS, BUS_ISA, ISA_*).  This is the preferred method
98  *    but not all kernels support it.
99  *
100  * 2. Read the value (not the contents) of symlink PATH_ARM_SYSTYPE.
101  *    - If it matches one of the entries in the table above, use the
102  *      corresponding values.
103  *    - If it begins with a number, assume this is a previously
104  *      unsupported system and the values encode, in order,
105  *      "<io_base>,<port_shift>".
106  *
107  * 3. Lookup the "system type" field in /proc/cpuinfo.  Again, if it
108  *    matches an entry in the platform[] table, use the corresponding
109  *    values.
110  *
111  * 4. BUS_ISA is changed to CTL_BUS_ISA (for kernel since 2.4.23).
112  */
113
114 static int
115 init_iosys (void)
116 {
117     char systype[256];
118     int i, n;
119     
120 #if LINUX_VERSION_CODE < 132119
121     static int iobase_name[] = { CTL_BUS, BUS_ISA, BUS_ISA_PORT_BASE };
122     static int ioshift_name[] = { CTL_BUS, BUS_ISA, BUS_ISA_PORT_SHIFT };
123 #else
124     static int iobase_name[] = { CTL_BUS, CTL_BUS_ISA, BUS_ISA_PORT_BASE };
125     static int ioshift_name[] = { CTL_BUS, CTL_BUS_ISA, BUS_ISA_PORT_SHIFT };
126 #endif
127
128     size_t len = sizeof(io.base);
129
130     if (! sysctl (iobase_name, 3, &io.io_base, &len, NULL, 0)
131         && ! sysctl (ioshift_name, 3, &io.shift, &len, NULL, 0)) {
132         io.initdone = 1;
133         return 0;
134     }
135
136     n = readlink (PATH_ARM_SYSTYPE, systype, sizeof (systype) - 1);
137     if (n > 0) {
138         systype[n] = '\0';
139         if (isdigit (systype[0])) {
140             if (sscanf (systype, "%li,%i", &io.io_base, &io.shift) == 2) {
141                 io.initdone = 1;
142                 return 0;
143             }
144             /* else we're likely going to fail with the system match below */
145         }
146     }
147     else {
148         FILE * fp;
149
150         fp = fopen (PATH_CPUINFO, "r");
151         if (! fp)
152             return -1;
153         while ((n = fscanf (fp, "Hardware\t: %256[^\n]\n", systype)) != EOF) {
154             if (n == 1)
155                 break;
156             else
157                 fgets (systype, 256, fp);
158         }
159         fclose (fp);
160
161         if (n == EOF) {
162             /* this can happen if the format of /proc/cpuinfo changes...  */
163             fprintf (stderr, "ioperm: Unable to determine system type.\n"
164                      "\t(May need " PATH_ARM_SYSTYPE " symlink?)\n");
165             __set_errno (ENODEV);
166             return -1;
167         }
168     }
169
170     /* translate systype name into i/o system: */
171     for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i) {
172         if (strcmp (platform[i].name, systype) == 0) {
173             io.shift = platform[i].shift;
174             io.io_base = platform[i].io_base;
175             io.initdone = 1;
176             return 0;
177         }
178     }
179
180     /* systype is not a known platform name... */
181     __set_errno (EINVAL);
182     return -1;
183 }
184
185 int ioperm (unsigned long int from, unsigned long int num, int turn_on)
186 {
187     if (! io.initdone && init_iosys () < 0)
188         return -1;
189
190     /* this test isn't as silly as it may look like; consider overflows! */
191     if (from >= MAX_PORT || from + num > MAX_PORT) {
192         __set_errno (EINVAL);
193         return -1;
194     }
195
196     if (turn_on) {
197         if (! io.base) {
198             int fd;
199
200             fd = open ("/dev/mem", O_RDWR);
201             if (fd < 0)
202                 return -1;
203
204             io.base = (unsigned long int) mmap (0, MAX_PORT << io.shift,
205                                           PROT_READ | PROT_WRITE,
206                                           MAP_SHARED, fd, io.io_base);
207             close (fd);
208             if ((long) io.base == -1)
209                 return -1;
210         }
211     }
212
213     return 0;
214 }
215 libc_hidden_proto(ioperm)
216 libc_hidden_def(ioperm)
217
218
219 void
220 outb(unsigned char b, unsigned long int port)
221 {
222     *((volatile unsigned char *)(IO_ADDR (port))) = b;
223 }
224
225
226 void
227 outw(unsigned short b, unsigned long int port)
228 {
229     *((volatile unsigned short *)(IO_ADDR (port))) = b;
230 }
231
232
233 void
234 outl(unsigned int b, unsigned long int port)
235 {
236     *((volatile unsigned long *)(IO_ADDR (port))) = b;
237 }
238
239
240 unsigned int
241 inb (unsigned long int port)
242 {
243     return *((volatile unsigned char *)(IO_ADDR (port)));
244 }
245
246
247 unsigned int
248 inw(unsigned long int port)
249 {
250     return *((volatile unsigned short *)(IO_ADDR (port)));
251 }
252
253
254 unsigned int
255 inl(unsigned long int port)
256 {
257     return *((volatile unsigned long *)(IO_ADDR (port)));
258 }