[uClibc]ARM IO

Vincent Sanders vince at trinity.fluff.org
Tue Oct 22 15:07:05 UTC 2002


Hi,
Thought i would start my contributions to uClibc with a patch ;-)

This is against the 0.9.15 release.

The patch fixes the ioperm() and iopl() calls for the arm systems that
support this type of hardware. and hence makes inb/outb functionality
work properly on the ARM architecture.

The original inout_bwl.c file has a completely bogus implementation.

I havnt implemented this functionality from scratch and most of the
actual code came from glibc (thanks to Phil Blundell for the idea)

The reason I have done this is that now i can compile and use LCDProc
on an ARM uClibc system.

Comments/improvements welcome

-- 
Regards Vincent
http://www.kyllikki.org/
-------------- next part --------------
diff -Nbru uClibc-0.9.15/libc/sysdeps/linux/arm/Makefile build/uClibc-0.9.15/libc/sysdeps/linux/arm/Makefile
--- uClibc-0.9.15/libc/sysdeps/linux/arm/Makefile	2002-07-25 10:16:48.000000000 +0100
+++ build/uClibc-0.9.15/libc/sysdeps/linux/arm/Makefile	2002-10-22 14:53:26.000000000 +0100
@@ -33,7 +33,7 @@
 SSRC=__longjmp.S vfork.S clone.S setjmp.S bsd-setjmp.S bsd-_setjmp.S
 SOBJS=$(patsubst %.S,%.o, $(SSRC))
 
-CSRC=inout_bwl.c brk.c syscall.c
+CSRC=brk.c syscall.c ioperm.c
 COBJS=$(patsubst %.c,%.o, $(CSRC))
 
 OBJS=$(SOBJS) $(MOBJ) $(COBJS)
@@ -64,4 +64,3 @@
 clean:
 	rm -f *.[oa] *~ core
 	rm -f bits/syscall.h
-
diff -Nbru uClibc-0.9.15/libc/sysdeps/linux/arm/inout_bwl.c build/uClibc-0.9.15/libc/sysdeps/linux/arm/inout_bwl.c
--- uClibc-0.9.15/libc/sysdeps/linux/arm/inout_bwl.c	2001-09-27 08:48:05.000000000 +0100
+++ build/uClibc-0.9.15/libc/sysdeps/linux/arm/inout_bwl.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,87 +0,0 @@
-/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Phil Blundell, based on the Alpha version by
-   David Mosberger.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-/* I/O port access on the ARM is something of a fiction.  What we do is to
-   map an appropriate area of /dev/mem into user space so that a program
-   can blast away at the hardware in such a way as to generate I/O cycles
-   on the bus.  To insulate user code from dependencies on particular
-   hardware we don't allow calls to inb() and friends to be inlined, but
-   force them to come through code in here every time.  Performance-critical
-   registers tend to be memory mapped these days so this should be no big
-   problem.  */
-
-/* Once upon a time this file used mprotect to enable and disable
-   access to particular areas of I/O space.  Unfortunately the
-   mprotect syscall also has the side effect of enabling caching for
-   the area affected (this is a kernel limitation).  So we now just
-   enable all the ports all of the time.  */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-
-#define IO_BASE			0x7c000000
-#define IO_SHIFT		0
-#define IO_ADDR(port)	(IO_BASE + ((port) << IO_SHIFT))
-
-
-void outb (unsigned char b, unsigned long int port)
-{
-  *((volatile unsigned char *)(IO_ADDR (port))) = b;
-}
-
-
-void outw (unsigned short b, unsigned long int port)
-{
-  *((volatile unsigned short *)(IO_ADDR (port))) = b;
-}
-
-
-void outl (unsigned int b, unsigned long int port)
-{
-  *((volatile unsigned long *)(IO_ADDR (port))) = b;
-}
-
-
-unsigned int inb (unsigned long int port)
-{
-  return *((volatile unsigned char *)(IO_ADDR (port)));
-}
-
-
-unsigned int inw (unsigned long int port)
-{
-  return *((volatile unsigned short *)(IO_ADDR (port)));
-}
-
-
-unsigned int inl (unsigned long int port)
-{
-  return *((volatile unsigned long *)(IO_ADDR (port)));
-}
-
diff -Nbru uClibc-0.9.15/libc/sysdeps/linux/arm/ioperm.c build/uClibc-0.9.15/libc/sysdeps/linux/arm/ioperm.c
--- uClibc-0.9.15/libc/sysdeps/linux/arm/ioperm.c	1970-01-01 01:00:00.000000000 +0100
+++ build/uClibc-0.9.15/libc/sysdeps/linux/arm/ioperm.c	2002-10-22 15:54:55.000000000 +0100
@@ -0,0 +1,266 @@
+/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Phil Blundell, based on the Alpha version by
+   David Mosberger.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* I/O port access on the ARM is something of a fiction.  What we do is to
+   map an appropriate area of /dev/mem into user space so that a program
+   can blast away at the hardware in such a way as to generate I/O cycles
+   on the bus.  To insulate user code from dependencies on particular
+   hardware we don't allow calls to inb() and friends to be inlined, but
+   force them to come through code in here every time.  Performance-critical
+   registers tend to be memory mapped these days so this should be no big
+   problem.  */
+
+/* Once upon a time this file used mprotect to enable and disable
+   access to particular areas of I/O space.  Unfortunately the
+   mprotect syscall also has the side effect of enabling caching for
+   the area affected (this is a kernel limitation).  So we now just
+   enable all the ports all of the time.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <asm/page.h>
+#include <sys/sysctl.h>
+
+#define PATH_ARM_SYSTYPE	"/etc/arm_systype"
+#define PATH_CPUINFO		"/proc/cpuinfo"
+
+#define MAX_PORT	0x10000
+
+static struct {
+    unsigned long int	base;
+    unsigned long int	io_base;
+    unsigned int		shift;
+    unsigned int		initdone;	/* since all the above could be 0 */
+} io;
+
+#define IO_BASE_FOOTBRIDGE	0x7c000000
+#define IO_SHIFT_FOOTBRIDGE	0
+
+static struct platform {
+    const char		*name;
+    unsigned long int	io_base;
+    unsigned int		shift;
+} platform[] = {
+    /* All currently supported platforms are in fact the same. :-)  */
+    {"Chalice-CATS",	IO_BASE_FOOTBRIDGE,	IO_SHIFT_FOOTBRIDGE},
+    {"DEC-EBSA285",	IO_BASE_FOOTBRIDGE,	IO_SHIFT_FOOTBRIDGE},
+    {"Corel-NetWinder",	IO_BASE_FOOTBRIDGE,	IO_SHIFT_FOOTBRIDGE},
+    {"Rebel-NetWinder",	IO_BASE_FOOTBRIDGE,	IO_SHIFT_FOOTBRIDGE},
+};
+
+#define IO_ADDR(port)	(io.base + ((port) << io.shift))
+
+/*
+ * Initialize I/O system.  There are several ways to get the information
+ * we need.  Each is tried in turn until one succeeds.
+ *
+ * 1. Sysctl (CTL_BUS, BUS_ISA, ISA_*).  This is the preferred method
+ *    but not all kernels support it.
+ *
+ * 2. Read the value (not the contents) of symlink PATH_ARM_SYSTYPE.
+ *    - If it matches one of the entries in the table above, use the
+ *      corresponding values.
+ *    - If it begins with a number, assume this is a previously
+ *      unsupported system and the values encode, in order,
+ *      "<io_base>,<port_shift>".
+ *
+ * 3. Lookup the "system type" field in /proc/cpuinfo.  Again, if it
+ *    matches an entry in the platform[] table, use the corresponding
+ *    values.
+ */
+
+static int
+init_iosys (void)
+{
+    char systype[256];
+    int i, n;
+    static int iobase_name[] = { CTL_BUS, BUS_ISA, BUS_ISA_PORT_BASE };
+    static int ioshift_name[] = { CTL_BUS, BUS_ISA, BUS_ISA_PORT_SHIFT };
+    size_t len = sizeof(io.base);
+
+    if (! sysctl (iobase_name, 3, &io.io_base, &len, NULL, 0)
+	&& ! sysctl (ioshift_name, 3, &io.shift, &len, NULL, 0))
+    {
+	io.initdone = 1;
+	return 0;
+    }
+
+    n = readlink (PATH_ARM_SYSTYPE, systype, sizeof (systype) - 1);
+    if (n > 0)
+    {
+	systype[n] = '\0';
+	if (isdigit (systype[0]))
+	{
+	    if (sscanf (systype, "%li,%i", &io.io_base, &io.shift) == 2)
+	    {
+		io.initdone = 1;
+		return 0;
+	    }
+	    /* else we're likely going to fail with the system match below */
+	}
+    }
+    else
+    {
+	FILE * fp;
+
+	fp = fopen (PATH_CPUINFO, "r");
+	if (! fp)
+	    return -1;
+	while ((n = fscanf (fp, "Hardware\t: %256[^\n]\n", systype))
+	       != EOF)
+	{
+	    if (n == 1)
+		break;
+	    else
+		fgets (systype, 256, fp);
+	}
+	fclose (fp);
+
+	if (n == EOF)
+	{
+	    /* this can happen if the format of /proc/cpuinfo changes...  */
+	    fprintf (stderr,
+		     "ioperm: Unable to determine system type.\n"
+		     "\t(May need " PATH_ARM_SYSTYPE " symlink?)\n");
+	    __set_errno (ENODEV);
+	    return -1;
+	}
+    }
+
+    /* translate systype name into i/o system: */
+    for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i)
+    {
+	if (strcmp (platform[i].name, systype) == 0)
+	{
+	    io.shift = platform[i].shift;
+	    io.io_base = platform[i].io_base;
+	    io.initdone = 1;
+	    return 0;
+	}
+    }
+
+    /* systype is not a known platform name... */
+    __set_errno (EINVAL);
+    return -1;
+}
+
+int
+ioperm (unsigned long int from, unsigned long int num, int turn_on)
+{
+    if (! io.initdone && init_iosys () < 0)
+	return -1;
+
+    /* this test isn't as silly as it may look like; consider overflows! */
+    if (from >= MAX_PORT || from + num > MAX_PORT)
+    {
+	__set_errno (EINVAL);
+	return -1;
+    }
+
+    if (turn_on)
+    {
+	if (! io.base)
+	{
+	    int fd;
+
+	    fd = open ("/dev/mem", O_RDWR);
+	    if (fd < 0)
+		return -1;
+
+	    io.base =
+		(unsigned long int) mmap (0, MAX_PORT << io.shift,
+					  PROT_READ | PROT_WRITE,
+					  MAP_SHARED, fd, io.io_base);
+	    close (fd);
+	    if ((long) io.base == -1)
+		return -1;
+
+	}
+    }
+
+    return 0;
+}
+
+
+int
+_iopl (unsigned int level)
+{
+    if (level > 3)
+    {
+	__set_errno (EINVAL);
+	return -1;
+    }
+    if (level)
+    {
+	return ioperm (0, MAX_PORT, 1);
+    }
+    return 0;
+}
+
+
+void
+outb(unsigned char b, unsigned long int port)
+{
+    *((volatile unsigned char *)(IO_ADDR (port))) = b;
+}
+
+
+void
+outw(unsigned short b, unsigned long int port)
+{
+    *((volatile unsigned short *)(IO_ADDR (port))) = b;
+}
+
+
+void
+outl(unsigned int b, unsigned long int port)
+{
+    *((volatile unsigned long *)(IO_ADDR (port))) = b;
+}
+
+
+unsigned int
+inb (unsigned long int port)
+{
+    return *((volatile unsigned char *)(IO_ADDR (port)));
+}
+
+
+unsigned int
+inw(unsigned long int port)
+{
+    return *((volatile unsigned short *)(IO_ADDR (port)));
+}
+
+
+unsigned int
+inl(unsigned long int port)
+{
+    return *((volatile unsigned long *)(IO_ADDR (port)));
+}
diff -Nbru uClibc-0.9.15/libc/sysdeps/linux/common/syscalls.c build/uClibc-0.9.15/libc/sysdeps/linux/common/syscalls.c
--- uClibc-0.9.15/libc/sysdeps/linux/common/syscalls.c	2002-08-21 01:54:51.000000000 +0100
+++ build/uClibc-0.9.15/libc/sysdeps/linux/common/syscalls.c	2002-10-22 15:13:40.000000000 +0100
@@ -898,7 +898,9 @@
 //#define __NR_ioperm           101
 #ifdef L_ioperm
 #	if defined __UCLIBC_HAS_MMU__ && defined __NR_ioperm
+#		if !defined (__arm__)
 		_syscall3(int, ioperm, unsigned long, from, unsigned long, num, int, turn_on);
+#		endif
 #	else
 		int ioperm(unsigned long from, unsigned long num, int turn_on)
 		{
@@ -982,12 +984,20 @@
 #	if defined __UCLIBC_HAS_MMU__ && defined __NR_iopl && ! defined(__mc68000__)
 		_syscall1(int, iopl, int, level);
 #	else
+#		if defined (__arm__)
+		int iopl(int level)
+                {
+                  return _iopl(level);
+                }
+
+#		else
 		int iopl(int level)
 		{
 			__set_errno(ENOSYS);
 			return -1;
 		}
 #	endif
+#	endif
 #endif
 
 //#define __NR_vhangup          111
@@ -1222,7 +1232,27 @@
 #endif
 
 //#define __NR__sysctl          149
+#ifdef __NR__sysctl
+#ifdef L__sysctl
+#include <linux/sysctl.h>
+_syscall1(int, _sysctl, struct __sysctl_args *, args);
+int sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
+			void *newval, size_t newlen)
+{
+	struct __sysctl_args args =
+	{
+		name: name,
+		nlen: nlen,
+		oldval: oldval,
+		oldlenp: oldlenp,
+		newval: newval,
+		newlen: newlen
+	};
+
+	return _sysctl(&args);
+}
+#endif
+#endif
 
 //#define __NR_mlock            150
 #ifdef L_mlock
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 232 bytes
Desc: not available
Url : http://lists.busybox.net/pipermail/uclibc/attachments/20021022/9e43665b/attachment.pgp 


More information about the uClibc mailing list