Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 15 Jun 2010 14:22:33 +0300
From:      Alexander Mogilny <sg@sg.org.ua>
To:        Luiz Otavio O Souza <lists.br@gmail.com>
Cc:        freebsd-mips@freebsd.org
Subject:   Re: RouterBOARD RB450G
Message-ID:  <0EFED95F-1B59-4A34-B518-E49A6ACD7D64@sg.org.ua>
In-Reply-To: <EDEDDC71-8C3E-4EDC-949B-AD4EBE6D14DD@gmail.com>
References:  <9C6B899F-0361-4E20-A9C4-20C002A3CA1D@sg.org.ua> <2D2B1168-4E11-4353-8856-FD2728413F1B@bluezbox.com> <EDEDDC71-8C3E-4EDC-949B-AD4EBE6D14DD@gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help

--Apple-Mail-6--206473323
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii


On Jun 12, 2010, at 2:36 PM, Luiz Otavio O Souza wrote:

> Gonzo,
>=20
> I 've most of the trivial fixes for routerboards, just give me a few =
days to extract the current patches.
>=20
> My old stuff can be found on: http://loos.no-ip.org:280/routerboard/
>=20
> The missing bits are: nand (the driver is ported, but i need more =
-free- time to sort out the FS layer), sd/mmc card slot (connected to =
spi bus) and the ethernet switch (useful on RG450(g) which have 4 ports =
connected to switch).
>=20

Hi again!
I confirm that this "old stuff" :) works on RB450G. Web document should =
be corrected to use port 280 for downloading patches from =
http://loos.no-ip.org.
I also made some corrections to gpio.diff as world failed to build =
because of warnings in gpioctl.c . You may see corrected diff attached.
I will now make some tests on the board and give you feedback if =
everything is fine.

Here is my dmesg.boot:

RouterBOOT booter 2.23

RouterBoard 450G

CPU frequency: 680 MHz
  Memory size: 256 MB

Press any key within 2 seconds to enter setup..
Please, check ethernet cable...
trying bootp protocol... OK
Got IP address: 172.16.0.40
resolved mac address 00:E0:81:49:87:F7
Gateway: 172.16.0.1
transfer started .................................. transfer ok, =
time=3D2.75s
setting up elf image... OK
jumping to kernel code
platform frequency: 680000000
arguments:=20
  a0 =3D 00000008
  a1 =3D a0861c00
  a2 =3D 00000000
  a3 =3D 00000000
Cmd line: console=3DttyS0,115200 gpio=3D1983 HZ=3D340000000 mem=3D256M =
kmac=3D00:0C:42:59:30:FF board=3D450G boot=3D1 mlc=3D2
Environment:
envp is invalid
Cache info:
  picache_stride    =3D 4096
  picache_loopcount =3D 16
  pdcache_stride    =3D 4096
  pdcache_loopcount =3D 8
cpu0: MIPS Technologies processor v116.147
  MMU: Standard TLB, 16 entries
  L1 i-cache: 4 ways of 512 sets, 32 bytes per line
  L1 d-cache: 4 ways of 256 sets, 32 bytes per line
  Config1=3D0x9ee3519e<PerfCount,WatchRegs,MIPS16,EJTAG>
  Config3=3D0x20
Copyright (c) 1992-2010 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
        The Regents of the University of California. All rights =
reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 9.0-CURRENT #3: Tue Jun 15 14:00:59 EEST 2010
    root@tbilisi.intra:/usr/obj/mips/mips/usr/src.mips/sys/RB4XX mips
real memory  =3D 268435456 (262144K bytes)
avail memory =3D 257089536 (245MB)
nexus0: <MIPS32 root nexus>
clock0: <Generic MIPS32 ticker> on nexus0
clock0: [FILTER]
apb0 at irq 4 on nexus0
apb0: [FILTER]
uart0: <16550 or compatible> on apb0
uart0: [FILTER]
uart0: console (115200,n,8,1)
gpio0: <Atheros AR71XX GPIO driver> on apb0
gpio0: [GIANT-LOCKED]
gpio0: [FILTER+ITHREAD]
gpioc0: <GPIO controller> on gpio0
gpiobus0: <GPIO bus> on gpio0
gpioled0: <GPIO led> at pin(s) 4 on gpiobus0
ehci0: <AR71XX Integrated USB 2.0 controller> at mem =
0x1b000000-0x1bffffff irq 1 on nexus0
ehci0: [ITHREAD]
usbus0: set host controller mode
usbus0: EHCI version 1.0
usbus0: set host controller mode
usbus0: <AR71XX Integrated USB 2.0 controller> on ehci0
arge0: <Atheros AR71xx built-in ethernet interface> at mem =
0x19000000-0x19000fff irq 2 on nexus0
arge0: Ethernet address: 00:0c:42:59:30:00
arge0: [FILTER+ITHREAD]
arge1: <Atheros AR71xx built-in ethernet interface> at mem =
0x1a000000-0x1a000fff irq 3 on nexus0
miibus0: <MII bus> on arge1
ukphy0: <Generic IEEE 802.3u media interface> PHY 4 on miibus0
ukphy0:  10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT-FDX, =
auto
arge1: Ethernet address: 00:0c:42:59:30:ff
arge1: [FILTER+ITHREAD]
ar71xx_wdog0: <Atheros AR71XX watchdog timer> on nexus0
spi0: <AR71XX SPI> at mem 0x1f000000-0x1f00000f on nexus0
spibus0: <spibus bus> on spi0
Timecounter "MIPS32" frequency 340000000 Hz quality 800
Timecounters tick every 1.000 msec
bootpc_init: wired to interface 'arge1'
Sending DHCP Discover packet from interface arge1 (00:0c:42:59:30:ff)
arge1: link state changed to DOWN
usbus0: 480Mbps High Speed USB v2.0
ugen0.1: <Atheros> at usbus0
uhub0: <Atheros EHCI root HUB, class 9/0, rev 2.00/1.00, addr 1> on =
usbus0
uhub0: 2 ports with 2 removable, self powered
DHCP/BOOTP timeout for server 255.255.255.255
arge1: link state changed to UP
DHCP/BOOTP timeout for server 255.255.255.255
Received DHCP Offer packet on arge1 from 172.16.0.100 (accepted) (no =
root path)
Received DHCP Offer packet on arge1 from 172.16.0.100 (ignored) (no root =
path)
Received DHCP Offer packet on arge1 from 172.16.0.100 (ignored) (no root =
path)
Sending DHCP Request packet from interface arge1 (00:0c:42:59:30:ff)
DHCP/BOOTP timeout for server 255.255.255.255
Received DHCP Ack packet on arge1 from 172.16.0.100 (accepted) (got root =
path)
Received DHCP Ack packet on arge1 from 172.16.0.100 via 172.16.0.1 =
(accepted) (got root path)
arge1 at 172.16.0.40 server 172.16.0.100 via gateway 172.16.0.1 boot =
file boot/kernel/kernel
subnet mask 255.255.255.0 router 172.16.0.1 rootfs =
172.16.0.100:/home/nfs hostname mk-40=20
Adjusted interface arge1
Trying to mount root from nfs:
NFS ROOT: 172.16.0.100:/home/nfs
<...>


Now, tell me how can I help you with writing some code for ethernet =
switch etc? As I need to get it working :).



--Apple-Mail-6--206473323
Content-Disposition: attachment;
	filename=gpio.diff
Content-Type: application/octet-stream;
	name="gpio.diff"
Content-Transfer-Encoding: 7bit

diff --git a/sys/conf/files b/sys/conf/files
index b5a6f8c..7afc80b 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -935,6 +935,13 @@ dev/fxp/if_fxp.c		optional fxp inet
 dev/gem/if_gem.c		optional gem
 dev/gem/if_gem_pci.c		optional gem pci
 dev/gem/if_gem_sbus.c		optional gem sbus
+dev/gpio/gpiobus.c		optional gpio				\
+	dependency	"gpiobus_if.h"
+dev/gpio/gpioc.c		optional gpio				\
+	dependency	"gpio_if.h"
+dev/gpio/gpioled.c		optional gpioled
+dev/gpio/gpio_if.m		optional gpio
+dev/gpio/gpiobus_if.m		optional gpio
 dev/hatm/if_hatm.c		optional hatm pci
 dev/hatm/if_hatm_intr.c		optional hatm pci
 dev/hatm/if_hatm_ioctl.c	optional hatm pci
diff --git a/sys/dev/gpio/gpio_if.m b/sys/dev/gpio/gpio_if.m
new file mode 100644
index 0000000..8e29607
--- /dev/null
+++ b/sys/dev/gpio/gpio_if.m
@@ -0,0 +1,102 @@
+#-
+# Copyright (c) 2009 Oleksandr Tymoshenko
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+#include <sys/gpio.h>
+
+INTERFACE gpio;
+
+#
+# Get total number of pins
+#
+METHOD int pin_max {
+	device_t dev;
+	int *npins;
+};
+
+#
+# Set value of pin specifed by pin_num 
+#
+METHOD int pin_set {
+	device_t dev;
+	uint32_t pin_num;
+	uint32_t pin_value;
+};
+
+#
+# Get value of pin specifed by pin_num 
+#
+METHOD int pin_get {
+	device_t dev;
+	uint32_t pin_num;
+	uint32_t *pin_value;
+};
+
+#
+# Toggle value of pin specifed by pin_num 
+#
+METHOD int pin_toggle {
+	device_t dev;
+	uint32_t pin_num;
+};
+
+#
+# Get pin capabilities
+#
+METHOD int pin_getcaps {
+	device_t dev;
+	uint32_t pin_num;
+	uint32_t *caps;
+};
+
+#
+# Get pin flags
+#
+METHOD int pin_getflags {
+	device_t dev;
+	uint32_t pin_num;
+	uint32_t *flags;
+};
+
+#
+# Get pin name
+#
+METHOD int pin_getname {
+	device_t dev;
+	uint32_t pin_num;
+	char *name;
+};
+
+#
+# Set current configuration and capabilities
+#
+METHOD int pin_setflags {
+	device_t dev;
+	uint32_t pin_num;
+	uint32_t flags;
+};
diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c
new file mode 100644
index 0000000..05c558f
--- /dev/null
+++ b/sys/dev/gpio/gpiobus.c
@@ -0,0 +1,390 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <sys/gpio.h>
+#include <dev/gpio/gpiobusvar.h>
+#include "gpio_if.h"
+#include "gpiobus_if.h"
+
+static void gpiobus_print_pins(struct gpiobus_ivar *);
+static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int);
+static int gpiobus_probe(device_t);
+static int gpiobus_attach(device_t);
+static int gpiobus_detach(device_t);
+static int gpiobus_suspend(device_t);
+static int gpiobus_resume(device_t);
+static int gpiobus_print_child(device_t, device_t);
+static int gpiobus_child_location_str(device_t, device_t, char *, size_t);
+static int gpiobus_child_pnpinfo_str(device_t, device_t, char *, size_t);
+static device_t gpiobus_add_child(device_t, int, const char *, int);
+static void gpiobus_hinted_child(device_t, const char *, int);
+
+/*
+ * GPIOBUS interface
+ */
+static int gpiobus_pin_setflags(device_t, device_t, uint32_t, uint32_t);
+static int gpiobus_pin_getflags(device_t, device_t, uint32_t, uint32_t*);
+static int gpiobus_pin_getcaps(device_t, device_t, uint32_t, uint32_t*);
+static int gpiobus_pin_set(device_t, device_t, uint32_t, unsigned int);
+static int gpiobus_pin_get(device_t, device_t, uint32_t, unsigned int*);
+static int gpiobus_pin_toggle(device_t, device_t, uint32_t);
+
+static void
+gpiobus_print_pins(struct gpiobus_ivar *devi)
+{
+	int range_start, range_stop, need_coma;
+	int i;
+
+	if (devi->npins == 0)
+		return;
+
+	need_coma = 0;
+	range_start = range_stop = devi->pins[0];
+	for(i = 1; i < devi->npins-1; i++) {
+		if (devi->pins[i] != (range_stop + 1)) {
+			if (need_coma)
+				printf(",");
+			if (range_start != range_stop)
+				printf("%d-%d", range_start, range_stop);
+			else
+				printf("%d", range_start);
+
+			range_start = range_stop = devi->pins[i];
+			need_coma = 1;
+		}
+		else
+			range_stop++;
+	}
+
+	if (need_coma)
+		printf(",");
+	if (range_start != range_stop)
+		printf("%d-%d", range_start, range_stop);
+	else
+		printf("%d", range_start);
+}
+
+static int
+gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask)
+{
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+	int i, npins;
+
+	npins = 0;
+	for (i = 0; i < 32; i++) {
+		if (mask & (1 << i))
+			npins++;
+	}
+
+	if (npins == 0) {
+		device_printf(child, "empty pin mask");
+		return (EINVAL);
+	}
+
+	devi->npins = npins;
+	devi->pins = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF, 
+	    M_NOWAIT | M_ZERO);
+
+	if (!devi->pins)
+		return (ENOMEM);
+
+	npins = 0;
+	for (i = 0; i < 32; i++) {
+
+		if ((mask & (1 << i)) == 0)
+			continue;
+
+		if (i >= sc->npins) {
+			device_printf(child, 
+			    "invalid pin %d, max: %d\n", i, sc->npins - 1);
+			return (EINVAL);
+		}
+
+		devi->pins[npins++] = i;
+		/*
+		 * Mark pin as mapped and give warning if it's already mapped
+		 */
+		if (sc->pins_mapped[i]) {
+			device_printf(child, 
+			    "warning: pin %d is already mapped\n", i);
+			return (EINVAL);
+		}
+		sc->pins_mapped[i] = 1;
+	}
+
+	return (0);
+}
+
+static int
+gpiobus_probe(device_t dev)
+{
+	device_set_desc(dev, "GPIO bus");
+	return (0);
+}
+
+static int
+gpiobus_attach(device_t dev)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	int res;
+
+	sc->dev = dev;
+	sc->pdev = device_get_parent(dev);
+	res = GPIO_PIN_MAX(sc->pdev, &sc->npins);
+	if (res)
+		return (ENXIO);
+
+	/*
+	 * Increase to get number of pins
+	 */
+	sc->npins++;
+
+	KASSERT(sc->npins != 0, ("GPIO device with no pins"));
+
+	sc->pins_mapped = malloc(sizeof(int) * sc->npins, M_DEVBUF, 
+	    M_NOWAIT | M_ZERO);
+
+	if (!sc->pins_mapped)
+		return (ENOMEM);
+
+	/*
+	 * Get parent's pins and mark them as unmapped
+	 */
+	bus_enumerate_hinted_children(dev);
+	return (bus_generic_attach(dev));
+}
+
+/*
+ * Since this is not a self-enumerating bus, and since we always add
+ * children in attach, we have to always delete children here.
+ */
+static int
+gpiobus_detach(device_t dev)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	int err, ndevs, i;
+	device_t *devlist;
+
+	if ((err = bus_generic_detach(dev)) != 0)
+		return (err);
+	if ((err = device_get_children(dev, &devlist, &ndevs)) != 0)
+		return (err);
+	for (i = 0; i < ndevs; i++)
+		device_delete_child(dev, devlist[i]);
+
+	if (sc->pins_mapped) {
+		free(sc->pins_mapped, M_DEVBUF);
+		sc->pins_mapped = NULL;
+	}
+	free(devlist, M_TEMP);
+
+	return (0);
+}
+
+static int
+gpiobus_suspend(device_t dev)
+{
+	return (bus_generic_suspend(dev));
+}
+
+static int
+gpiobus_resume(device_t dev)
+{
+	return (bus_generic_resume(dev));
+}
+
+static int
+gpiobus_print_child(device_t dev, device_t child)
+{
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+	int retval = 0;
+
+	retval += bus_print_child_header(dev, child);
+	retval += printf(" at pin(s) ");
+	gpiobus_print_pins(devi);
+	retval += bus_print_child_footer(dev, child);
+
+	return (retval);
+}
+
+static int
+gpiobus_child_location_str(device_t bus, device_t child, char *buf,
+    size_t buflen)
+{
+	// struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	snprintf(buf, buflen, "pins=?");
+	return (0);
+}
+
+static int
+gpiobus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
+    size_t buflen)
+{
+	*buf = '\0';
+	return (0);
+}
+
+static device_t
+gpiobus_add_child(device_t dev, int order, const char *name, int unit)
+{
+	device_t child;
+	struct gpiobus_ivar *devi;
+
+	child = device_add_child_ordered(dev, order, name, unit);
+	if (child == NULL) 
+		return (child);
+	devi = malloc(sizeof(struct gpiobus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
+	if (devi == NULL) {
+		device_delete_child(dev, child);
+		return (0);
+	}
+	device_set_ivars(child, devi);
+	return (child);
+}
+
+static void
+gpiobus_hinted_child(device_t bus, const char *dname, int dunit)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus);
+	struct gpiobus_ivar *devi;
+	device_t child;
+	int pins;
+
+
+	child = BUS_ADD_CHILD(bus, 0, dname, dunit);
+	devi = GPIOBUS_IVAR(child);
+	resource_int_value(dname, dunit, "pins", &pins);
+	if (gpiobus_parse_pins(sc, child, pins))
+		device_delete_child(bus, child);
+}
+
+static int
+gpiobus_pin_setflags(device_t dev, device_t child, uint32_t pin, 
+    uint32_t flags)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_SETFLAGS(sc->pdev, devi->pins[pin], flags);
+}
+
+static int
+gpiobus_pin_getflags(device_t dev, device_t child, uint32_t pin, 
+    uint32_t *flags)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_GETFLAGS(sc->pdev, devi->pins[pin], flags);
+}
+
+static int
+gpiobus_pin_getcaps(device_t dev, device_t child, uint32_t pin, 
+    uint32_t *caps)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_GETCAPS(sc->pdev, devi->pins[pin], caps);
+}
+
+static int
+gpiobus_pin_set(device_t dev, device_t child, uint32_t pin, 
+    unsigned int value)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_SET(sc->pdev, devi->pins[pin], value);
+}
+
+static int
+gpiobus_pin_get(device_t dev, device_t child, uint32_t pin, 
+    unsigned int *value)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_GET(sc->pdev, devi->pins[pin], value);
+}
+
+static int
+gpiobus_pin_toggle(device_t dev, device_t child, uint32_t pin)
+{
+	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
+	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
+
+	if (pin >= devi->npins)
+		return (EINVAL);
+
+	return GPIO_PIN_TOGGLE(sc->pdev, devi->pins[pin]);
+}
+
+static device_method_t gpiobus_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		gpiobus_probe),
+	DEVMETHOD(device_attach,	gpiobus_attach),
+	DEVMETHOD(device_detach,	gpiobus_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+	DEVMETHOD(device_suspend,	gpiobus_suspend),
+	DEVMETHOD(device_resume,	gpiobus_resume),
+
+	/* Bus interface */
+	DEVMETHOD(bus_add_child,	gpiobus_add_child),
+	DEVMETHOD(bus_print_child,	gpiobus_print_child),
+	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
+	DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str),
+	DEVMETHOD(bus_child_location_str, gpiobus_child_location_str),
+	DEVMETHOD(bus_hinted_child,	gpiobus_hinted_child),
+
+	/* GPIO protocol */
+	DEVMETHOD(gpiobus_pin_getflags, gpiobus_pin_getflags),
+	DEVMETHOD(gpiobus_pin_getcaps, gpiobus_pin_getcaps),
+	DEVMETHOD(gpiobus_pin_setflags, gpiobus_pin_setflags),
+	DEVMETHOD(gpiobus_pin_get, gpiobus_pin_get),
+	DEVMETHOD(gpiobus_pin_set, gpiobus_pin_set),
+	DEVMETHOD(gpiobus_pin_toggle, gpiobus_pin_toggle),
+
+	{ 0, 0 }
+};
+
+static driver_t gpiobus_driver = {
+	"gpiobus",
+	gpiobus_methods,
+	sizeof(struct gpiobus_softc)
+};
+
+devclass_t	gpiobus_devclass;
+
+DRIVER_MODULE(gpiobus, gpio, gpiobus_driver, gpiobus_devclass, 0, 0);
+MODULE_VERSION(gpiobus, 1);
diff --git a/sys/dev/gpio/gpiobus_if.m b/sys/dev/gpio/gpiobus_if.m
new file mode 100644
index 0000000..a406e01
--- /dev/null
+++ b/sys/dev/gpio/gpiobus_if.m
@@ -0,0 +1,91 @@
+#-
+# Copyright (c) 2009 Oleksandr Tymoshenko
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+#include <sys/gpio.h>
+
+INTERFACE gpiobus;
+
+#
+# Set value of pin specifed by pin_num 
+#
+METHOD int pin_set {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+	uint32_t pin_value;
+};
+
+#
+# Get value of pin specifed by pin_num 
+#
+METHOD int pin_get {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+	uint32_t *pin_value;
+};
+
+#
+# Toggle value of pin specifed by pin_num 
+#
+METHOD int pin_toggle {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+};
+
+#
+# Get pin capabilities
+#
+METHOD int pin_getcaps {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+	uint32_t *caps;
+};
+
+#
+# Get pin flags
+#
+METHOD int pin_getflags {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+	uint32_t *flags;
+};
+
+#
+# Set current configuration and capabilities
+#
+METHOD int pin_setflags {
+	device_t dev;
+	device_t child;
+	uint32_t pin_num;
+	uint32_t flags;
+};
diff --git a/sys/dev/gpio/gpiobusvar.h b/sys/dev/gpio/gpiobusvar.h
new file mode 100644
index 0000000..f1a290f
--- /dev/null
+++ b/sys/dev/gpio/gpiobusvar.h
@@ -0,0 +1,22 @@
+#ifndef	__GPIOBUS_H__
+#define	__GPIOBUS_H__
+
+#define GPIOBUS_IVAR(d) (struct gpiobus_ivar *) device_get_ivars(d)
+#define GPIOBUS_SOFTC(d) (struct gpiobus_softc *) device_get_softc(d)
+
+struct gpiobus_softc
+{
+	device_t	pdev;	/* bus device */
+	device_t	dev;
+	int		npins;	/* total pins on bus */
+	int		*pins_mapped; /* mark mapped pins */
+};
+
+
+struct gpiobus_ivar
+{
+	uint32_t	npins;	/* pins total */
+	uint32_t	*pins;	/* pins map */
+};
+
+#endif	/* __GPIOBUS_H__ */
diff --git a/sys/dev/gpio/gpioc.c b/sys/dev/gpio/gpioc.c
new file mode 100644
index 0000000..e507a73
--- /dev/null
+++ b/sys/dev/gpio/gpioc.c
@@ -0,0 +1,174 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/ioccom.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/queue.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <sys/gpio.h>
+#include "gpio_if.h"
+
+#undef GPIOC_DEBUG
+#ifdef GPIOC_DEBUG
+#define dprintf printf
+#else
+#define dprintf(x, arg...)
+#endif
+
+static int gpioc_probe(device_t dev);
+static int gpioc_attach(device_t dev);
+static int gpioc_detach(device_t dev);
+
+static d_ioctl_t	gpioc_ioctl;
+
+static struct cdevsw gpioc_cdevsw = {
+	.d_version	= D_VERSION,
+	.d_ioctl	= gpioc_ioctl,
+	.d_name		= "gpioc",
+#if __FreeBSD_version >= 800039
+	.d_flags	= D_PSEUDO | D_NEEDMINOR
+#endif
+};
+
+struct gpioc_softc {
+	device_t	sc_dev;		/* gpiocX dev */
+	device_t	sc_pdev;	/* gpioX dev */
+	struct cdev	*sc_ctl_dev;	/* controller device */
+	int		sc_unit;
+};
+
+static int
+gpioc_probe(device_t dev)
+{
+	device_set_desc(dev, "GPIO controller");
+	return (0);
+}
+
+static int
+gpioc_attach(device_t dev)
+{
+	struct gpioc_softc *sc = device_get_softc(dev);
+
+	sc->sc_dev = dev;
+	sc->sc_pdev = device_get_parent(dev);
+	sc->sc_unit = device_get_unit(dev);
+	sc->sc_ctl_dev = make_dev(&gpioc_cdevsw, sc->sc_unit,
+	    UID_ROOT, GID_WHEEL, 0600, "gpioc%d", sc->sc_unit);
+	if (!sc->sc_ctl_dev) {
+		printf("Failed to create gpioc%d", sc->sc_unit);
+		return (ENXIO);
+	}
+	sc->sc_ctl_dev->si_drv1 = sc;
+
+	return (0);
+}
+
+static int
+gpioc_detach(device_t dev)
+{
+	struct gpioc_softc *sc = device_get_softc(dev);
+	int err;
+
+	if (sc->sc_ctl_dev);
+		destroy_dev(sc->sc_ctl_dev);
+
+	if ((err = bus_generic_detach(dev)) != 0)
+		return (err);
+
+	return (0);
+}
+
+static int 
+gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag, 
+    struct thread *td)
+{
+	int max_pin, res;
+	struct gpioc_softc *sc = cdev->si_drv1;
+	struct gpio_pin pin;
+	struct gpio_req req;
+
+	switch (cmd) {
+		case GPIOMAXPIN:
+			max_pin = -1;
+			res = GPIO_PIN_MAX(sc->sc_pdev, &max_pin);
+			bcopy(&max_pin, arg, sizeof(max_pin));
+			break;
+		case GPIOGETCONFIG:
+			bcopy(arg, &pin, sizeof(pin));
+			dprintf("get config pin %d\n", pin.gp_pin);
+			res = GPIO_PIN_GETFLAGS(sc->sc_pdev, pin.gp_pin,
+			    &pin.gp_flags);
+			/* Fail early */
+			if (res)
+				break;
+			GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps);
+			GPIO_PIN_GETNAME(sc->sc_pdev, pin.gp_pin, pin.gp_name);
+			bcopy(&pin, arg, sizeof(pin));
+			break;
+		case GPIOSETCONFIG:
+			bcopy(arg, &pin, sizeof(pin));
+			dprintf("set config pin %d\n", pin.gp_pin);
+			res = GPIO_PIN_SETFLAGS(sc->sc_pdev, pin.gp_pin,
+			    pin.gp_flags);
+			break;
+		case GPIOGET:
+			bcopy(arg, &req, sizeof(req));
+			res = GPIO_PIN_GET(sc->sc_pdev, req.gp_pin,
+			    &req.gp_value);
+			dprintf("read pin %d -> %d\n", 
+			    req.gp_pin, req.gp_value);
+			bcopy(&req, arg, sizeof(req));
+			break;
+		case GPIOSET:
+			bcopy(arg, &req, sizeof(req));
+			res = GPIO_PIN_SET(sc->sc_pdev, req.gp_pin, 
+			    req.gp_value);
+			dprintf("write pin %d -> %d\n", 
+			    req.gp_pin, req.gp_value);
+			break;
+		case GPIOTOGGLE:
+			bcopy(arg, &req, sizeof(req));
+			dprintf("toggle pin %d\n", 
+			    req.gp_pin);
+			res = GPIO_PIN_TOGGLE(sc->sc_pdev, req.gp_pin);
+			break;
+		default:
+			return (ENOTTY);
+			break;
+	}
+
+	return (res);
+}
+
+static device_method_t gpioc_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		gpioc_probe),
+	DEVMETHOD(device_attach,	gpioc_attach),
+	DEVMETHOD(device_detach,	gpioc_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+	DEVMETHOD(device_suspend,	bus_generic_suspend),
+	DEVMETHOD(device_resume,	bus_generic_resume),
+
+	{ 0, 0 }
+};
+
+static driver_t gpioc_driver = {
+	"gpioc",
+	gpioc_methods,
+	sizeof(struct gpioc_softc)
+};
+
+devclass_t	gpioc_devclass;
+
+DRIVER_MODULE(gpioc, gpio, gpioc_driver, gpioc_devclass, 0, 0);
+MODULE_VERSION(gpioc, 1);
diff --git a/sys/dev/gpio/gpioled.c b/sys/dev/gpio/gpioled.c
new file mode 100644
index 0000000..082d5e8
--- /dev/null
+++ b/sys/dev/gpio/gpioled.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 2009 Oleksandr Tymoshenko.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+
+#include <dev/led/led.h>
+#include <sys/gpio.h>
+#include "gpiobus_if.h"
+
+/*
+ * Only one pin for led
+ */
+#define	GPIOLED_PIN	0
+
+#define GPIOLED_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
+#define	GPIOLED_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
+#define GPIOLED_LOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+	    "gpioled", MTX_DEF)
+#define GPIOLED_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
+
+struct gpioled_softc 
+{
+	device_t	sc_dev;
+	device_t	sc_busdev;
+	struct mtx	sc_mtx;
+	struct cdev	*sc_leddev;
+};
+
+static void gpioled_control(void *, int);
+static int gpioled_probe(device_t);
+static int gpioled_attach(device_t);
+static int gpioled_detach(device_t);
+
+static void 
+gpioled_control(void *priv, int onoff)
+{
+	struct gpioled_softc *sc = priv;
+	GPIOLED_LOCK(sc);
+	GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN, 
+	    onoff ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
+	GPIOLED_UNLOCK(sc);
+}
+
+static int
+gpioled_probe(device_t dev)
+{
+	device_set_desc(dev, "GPIO led");
+	return (0);
+}
+
+static int
+gpioled_attach(device_t dev)
+{
+	struct gpioled_softc *sc;
+	const char *name;
+
+	sc = device_get_softc(dev);
+	sc->sc_dev = dev;
+	sc->sc_busdev = device_get_parent(dev);
+	GPIOLED_LOCK_INIT(sc);
+	if (resource_string_value(device_get_name(dev), 
+	    device_get_unit(dev), "name", &name))
+		name = NULL;
+
+	sc->sc_leddev = led_create(gpioled_control, sc, name ? name :
+	    device_get_nameunit(dev));
+
+	return (0);
+}
+
+static int
+gpioled_detach(device_t dev)
+{
+	struct gpioled_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (sc->sc_leddev) {
+		led_destroy(sc->sc_leddev);
+		sc->sc_leddev = NULL;
+	}
+	GPIOLED_LOCK_DESTROY(sc);
+	return (0);
+}
+
+static devclass_t gpioled_devclass;
+
+static device_method_t gpioled_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		gpioled_probe),
+	DEVMETHOD(device_attach,	gpioled_attach),
+	DEVMETHOD(device_detach,	gpioled_detach),
+
+	{ 0, 0 }
+};
+
+static driver_t gpioled_driver = {
+	"gpioled",
+	gpioled_methods,
+	sizeof(struct gpioled_softc),
+};
+
+DRIVER_MODULE(gpioled, gpiobus, gpioled_driver, gpioled_devclass, 0, 0);
diff --git a/sys/mips/atheros/ar71xx_gpio.c b/sys/mips/atheros/ar71xx_gpio.c
new file mode 100644
index 0000000..c66266e
--- /dev/null
+++ b/sys/mips/atheros/ar71xx_gpio.c
@@ -0,0 +1,446 @@
+/*-
+ * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * Copyright (c) 2009, Luiz Otavio O Souza. 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * GPIO driver for AR71xx 
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <mips/atheros/ar71xxreg.h>
+#include <mips/atheros/ar71xx_gpiovar.h>
+
+#include "gpio_if.h"
+
+#define	DEFAULT_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
+
+struct ar71xx_gpio_pin {
+	const char *name;
+	int pin;
+	int flags;
+};
+
+static struct ar71xx_gpio_pin ar71xx_gpio_pins[] = {
+	{ "RFled", 2, GPIO_PIN_OUTPUT},
+	{ "SW4", 8,  GPIO_PIN_INPUT},
+	{ NULL, 0, 0},
+};
+
+/*
+ * Helpers
+ */
+static void ar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, 
+    uint32_t mask);
+static void ar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, 
+    uint32_t mask);
+static void ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, 
+    struct gpio_pin *pin, uint32_t flags);
+
+/*
+ * Driver stuff
+ */
+static int ar71xx_gpio_probe(device_t dev);
+static int ar71xx_gpio_attach(device_t dev);
+static int ar71xx_gpio_detach(device_t dev);
+static int ar71xx_gpio_filter(void *arg);
+static void ar71xx_gpio_intr(void *arg);
+
+/*
+ * GPIO interface
+ */
+static int ar71xx_gpio_pin_max(device_t dev, int *maxpin);
+static int ar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
+static int ar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t
+    *flags);
+static int ar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
+static int ar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
+static int ar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
+static int ar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
+static int ar71xx_gpio_pin_toggle(device_t dev, uint32_t pin);
+
+static void
+ar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, uint32_t mask)
+{
+	GPIO_LOCK(sc);
+	GPIO_SET_BITS(sc, AR71XX_GPIO_FUNCTION, mask);
+	GPIO_UNLOCK(sc);
+}
+
+static void
+ar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, uint32_t mask)
+{
+	GPIO_LOCK(sc);
+	GPIO_CLEAR_BITS(sc, AR71XX_GPIO_FUNCTION, mask);
+	GPIO_UNLOCK(sc);
+}
+
+static void
+ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, struct gpio_pin *pin,
+    unsigned int flags)
+{
+	uint32_t mask;
+
+	mask = 1 << pin->gp_pin;
+	GPIO_LOCK(sc);
+
+	/*
+	 * Manage input/output
+	 */
+	if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
+		pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
+		if (flags & GPIO_PIN_OUTPUT) {
+			pin->gp_flags |= GPIO_PIN_OUTPUT;
+			GPIO_SET_BITS(sc, AR71XX_GPIO_OE, mask);
+		}
+		else {
+			pin->gp_flags |= GPIO_PIN_INPUT;
+			GPIO_CLEAR_BITS(sc, AR71XX_GPIO_OE, mask);
+		}
+	}
+
+	GPIO_UNLOCK(sc);
+}
+
+static int
+ar71xx_gpio_pin_max(device_t dev, int *maxpin)
+{
+
+	*maxpin = AR71XX_GPIO_PINS - 1;
+	return (0);
+}
+
+static int
+ar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+	struct ar71xx_gpio_softc *sc = device_get_softc(dev);
+	int i;
+
+	for (i = 0; i < sc->gpio_npins; i++) {
+		if (sc->gpio_pins[i].gp_pin == pin)
+			break;
+	}
+
+	if (i >= sc->gpio_npins)
+		return (EINVAL);
+
+	GPIO_LOCK(sc);
+	*caps = sc->gpio_pins[i].gp_caps;
+	GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+ar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+	struct ar71xx_gpio_softc *sc = device_get_softc(dev);
+	int i;
+
+	for (i = 0; i < sc->gpio_npins; i++) {
+		if (sc->gpio_pins[i].gp_pin == pin)
+			break;
+	}
+
+	if (i >= sc->gpio_npins)
+		return (EINVAL);
+
+	GPIO_LOCK(sc);
+	*flags = sc->gpio_pins[i].gp_flags;
+	GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+ar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+	struct ar71xx_gpio_softc *sc = device_get_softc(dev);
+	int i;
+
+	for (i = 0; i < sc->gpio_npins; i++) {
+		if (sc->gpio_pins[i].gp_pin == pin)
+			break;
+	}
+
+	if (i >= sc->gpio_npins)
+		return (EINVAL);
+
+	GPIO_LOCK(sc);
+	memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
+	GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+ar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+	int i;
+	struct ar71xx_gpio_softc *sc = device_get_softc(dev);
+
+	for (i = 0; i < sc->gpio_npins; i++) {
+		if (sc->gpio_pins[i].gp_pin == pin)
+			break;
+	}
+
+	if (i >= sc->gpio_npins)
+		return (EINVAL);
+
+	/* Filter out unwanted flags */
+	if ((flags &= sc->gpio_pins[i].gp_caps) != flags)
+		return (EINVAL);
+
+	/* Can't mix input/output together */
+	if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) ==
+	    (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT))
+		return (EINVAL);
+
+	ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
+	return (0);
+}
+
+static int
+ar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
+{
+	struct ar71xx_gpio_softc *sc = device_get_softc(dev);
+	int i;
+
+	for (i = 0; i < sc->gpio_npins; i++) {
+		if (sc->gpio_pins[i].gp_pin == pin)
+			break;
+	}
+
+	if (i >= sc->gpio_npins)
+		return (EINVAL);
+
+	GPIO_LOCK(sc);
+	if (value)
+		GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin));
+	else
+		GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin));
+	GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+ar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
+{
+	struct ar71xx_gpio_softc *sc = device_get_softc(dev);
+	int i;
+
+	for (i = 0; i < sc->gpio_npins; i++) {
+		if (sc->gpio_pins[i].gp_pin == pin)
+			break;
+	}
+
+	if (i >= sc->gpio_npins)
+		return (EINVAL);
+
+	GPIO_LOCK(sc);
+	*val = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0;
+	GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+ar71xx_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+	int res, i;
+	struct ar71xx_gpio_softc *sc = device_get_softc(dev);
+
+	for (i = 0; i < sc->gpio_npins; i++) {
+		if (sc->gpio_pins[i].gp_pin == pin)
+			break;
+	}
+
+	if (i >= sc->gpio_npins)
+		return (EINVAL);
+
+	GPIO_LOCK(sc);
+	res = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0;
+	if (res)
+		GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin));
+	else
+		GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin));
+	GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+ar71xx_gpio_filter(void *arg)
+{
+
+	/* TODO: something useful */
+	return (FILTER_STRAY);
+}
+
+
+
+static void
+ar71xx_gpio_intr(void *arg)
+{
+	struct ar71xx_gpio_softc *sc = arg;
+	GPIO_LOCK(sc);
+	/* TODO: something useful */
+	GPIO_UNLOCK(sc);
+}
+
+static int
+ar71xx_gpio_probe(device_t dev)
+{
+
+	device_set_desc(dev, "Atheros AR71XX GPIO driver");
+	return (0);
+}
+
+static int
+ar71xx_gpio_attach(device_t dev)
+{
+	struct ar71xx_gpio_softc *sc = device_get_softc(dev);
+	int error = 0;
+	struct ar71xx_gpio_pin *pinp;
+	int i;
+
+	KASSERT((device_get_unit(dev) == 0),
+	    ("ar71xx_gpio: Only one gpio module supported"));
+
+	mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+	    MTX_DEF);
+
+	/* Map control/status registers. */
+	sc->gpio_mem_rid = 0;
+	sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+	    &sc->gpio_mem_rid, RF_ACTIVE);
+
+	if (sc->gpio_mem_res == NULL) {
+		device_printf(dev, "couldn't map memory\n");
+		error = ENXIO;
+		ar71xx_gpio_detach(dev);
+		return(error);
+	}
+
+	if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 
+	    &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+		device_printf(dev, "unable to allocate IRQ resource\n");
+		return (ENXIO);
+	}
+
+	if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, 
+	    ar71xx_gpio_filter, ar71xx_gpio_intr, sc, &sc->gpio_ih))) {
+		device_printf(dev,
+		    "WARNING: unable to register interrupt handler\n");
+		return (ENXIO);
+	}
+
+	sc->dev = dev;
+	ar71xx_gpio_function_enable(sc, GPIO_SPI_CS1_EN);
+	ar71xx_gpio_function_enable(sc, GPIO_SPI_CS2_EN);
+	/* Configure all pins as input */
+	/* disable interrupts for all pins */
+	GPIO_WRITE(sc, AR71XX_GPIO_INT_MASK, 0);
+	pinp = ar71xx_gpio_pins;
+	i = 0;
+	while (pinp->name) {
+		strncpy(sc->gpio_pins[i].gp_name, pinp->name, GPIOMAXNAME);
+		sc->gpio_pins[i].gp_pin = pinp->pin;
+		sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
+		sc->gpio_pins[i].gp_flags = 0;
+		ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], pinp->flags);
+		pinp++;
+		i++;
+	}
+
+	sc->gpio_npins = i;
+
+	device_add_child(dev, "gpioc", device_get_unit(dev));
+	device_add_child(dev, "gpiobus", device_get_unit(dev));
+	return (bus_generic_attach(dev));
+}
+
+static int
+ar71xx_gpio_detach(device_t dev)
+{
+	struct ar71xx_gpio_softc *sc = device_get_softc(dev);
+
+	KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized"));
+
+	ar71xx_gpio_function_disable(sc, GPIO_SPI_CS1_EN);
+	ar71xx_gpio_function_disable(sc, GPIO_SPI_CS2_EN);
+	bus_generic_detach(dev);
+
+	if (sc->gpio_mem_res)
+		bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid,
+		    sc->gpio_mem_res);
+
+	mtx_destroy(&sc->gpio_mtx);
+
+	return(0);
+}
+
+static device_method_t ar71xx_gpio_methods[] = {
+	DEVMETHOD(device_probe, ar71xx_gpio_probe),
+	DEVMETHOD(device_attach, ar71xx_gpio_attach),
+	DEVMETHOD(device_detach, ar71xx_gpio_detach),
+
+	/* GPIO protocol */
+	DEVMETHOD(gpio_pin_max, ar71xx_gpio_pin_max),
+	DEVMETHOD(gpio_pin_getname, ar71xx_gpio_pin_getname),
+	DEVMETHOD(gpio_pin_getflags, ar71xx_gpio_pin_getflags),
+	DEVMETHOD(gpio_pin_getcaps, ar71xx_gpio_pin_getcaps),
+	DEVMETHOD(gpio_pin_setflags, ar71xx_gpio_pin_setflags),
+	DEVMETHOD(gpio_pin_get, ar71xx_gpio_pin_get),
+	DEVMETHOD(gpio_pin_set, ar71xx_gpio_pin_set),
+	DEVMETHOD(gpio_pin_toggle, ar71xx_gpio_pin_toggle),
+	{0, 0},
+};
+
+static driver_t ar71xx_gpio_driver = {
+	"gpio",
+	ar71xx_gpio_methods,
+	sizeof(struct ar71xx_gpio_softc),
+};
+static devclass_t ar71xx_gpio_devclass;
+
+DRIVER_MODULE(ar71xx_gpio, apb, ar71xx_gpio_driver, ar71xx_gpio_devclass, 0, 0);
diff --git a/sys/mips/atheros/ar71xx_gpiovar.h b/sys/mips/atheros/ar71xx_gpiovar.h
new file mode 100644
index 0000000..9cbea65
--- /dev/null
+++ b/sys/mips/atheros/ar71xx_gpiovar.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * Copyright (c) 2009, Luiz Otavio O Souza.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __AR71XX_GPIOVAR_H__
+#define __AR71XX_GPIOVAR_H__
+
+#define GPIO_LOCK(_sc)		mtx_lock(&(_sc)->gpio_mtx)
+#define GPIO_UNLOCK(_sc)	mtx_unlock(&(_sc)->gpio_mtx)
+#define GPIO_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->gpio_mtx, MA_OWNED)
+
+/*
+ * register space access macros
+ */
+#define GPIO_WRITE(sc, reg, val)	do {	\
+		bus_write_4(sc->gpio_mem_res, (reg), (val)); \
+	} while (0)
+
+#define GPIO_READ(sc, reg)	 bus_read_4(sc->gpio_mem_res, (reg))
+
+#define GPIO_SET_BITS(sc, reg, bits)	\
+	GPIO_WRITE(sc, reg, GPIO_READ(sc, (reg)) | (bits))
+
+#define GPIO_CLEAR_BITS(sc, reg, bits)	\
+	GPIO_WRITE(sc, reg, GPIO_READ(sc, (reg)) & ~(bits))
+
+#define	AR71XX_GPIO_PINS	12
+
+struct ar71xx_gpio_softc {
+	device_t		dev;
+        struct mtx		gpio_mtx;
+        struct resource		*gpio_mem_res;
+        int			gpio_mem_rid;
+        struct resource		*gpio_irq_res;
+        int			gpio_irq_rid;
+        void			*gpio_ih;
+	int			gpio_npins;
+	struct gpio_pin		gpio_pins[AR71XX_GPIO_PINS];
+};
+
+#endif	/* __AR71XX_GPIOVAR_H__ */
diff --git a/sys/mips/atheros/ar71xxreg.h b/sys/mips/atheros/ar71xxreg.h
index 5677a4e..5d36a67 100644
--- a/sys/mips/atheros/ar71xxreg.h
+++ b/sys/mips/atheros/ar71xxreg.h
@@ -134,6 +134,21 @@
 #define		USB_CTRL_CONFIG_RESUME_UTMI_PLS_DIS	(1 << 1)
 #define		USB_CTRL_CONFIG_UTMI_BACKWARD_ENB	(1 << 0)
 
+#define	AR71XX_GPIO_BASE		0x18040000
+#define		AR71XX_GPIO_OE			0x00
+#define		AR71XX_GPIO_IN			0x04
+#define		AR71XX_GPIO_OUT			0x08
+#define		AR71XX_GPIO_SET			0x0c
+#define		AR71XX_GPIO_CLEAR		0x10
+#define		AR71XX_GPIO_INT			0x14
+#define		AR71XX_GPIO_INT_TYPE		0x18
+#define		AR71XX_GPIO_INT_POLARITY	0x1c
+#define		AR71XX_GPIO_INT_PENDING		0x20
+#define		AR71XX_GPIO_INT_MASK		0x24
+#define		AR71XX_GPIO_FUNCTION		0x28
+#define			GPIO_SPI_CS2_EN                 (1 << 13)
+#define			GPIO_SPI_CS1_EN                 (1 << 12)
+
 #define	AR71XX_BASE_FREQ		40000000
 #define	AR71XX_PLL_CPU_CONFIG		0x18050000
 #define		PLL_SW_UPDATE			(1 << 31)
diff --git a/sys/mips/atheros/files.ar71xx b/sys/mips/atheros/files.ar71xx
index 29add2e..ee2ad87 100644
--- a/sys/mips/atheros/files.ar71xx
+++ b/sys/mips/atheros/files.ar71xx
@@ -1,6 +1,7 @@
 # $FreeBSD$
 
 mips/atheros/apb.c		standard
+mips/atheros/ar71xx_gpio.c	optional gpio
 mips/atheros/ar71xx_machdep.c	standard
 mips/atheros/ar71xx_ehci.c	optional ehci
 mips/atheros/ar71xx_ohci.c	optional ohci
diff --git a/sys/mips/conf/AR71XX b/sys/mips/conf/AR71XX
index cfdd82d..4cb3f23 100644
--- a/sys/mips/conf/AR71XX
+++ b/sys/mips/conf/AR71XX
@@ -69,6 +69,9 @@ device		arge
 # options		USB_DEBUG
 # device		ehci
 
+device		gpio
+device		gpioled
+
 device		spibus
 device		ar71xx_spi
 device		mx25l
diff --git a/sys/mips/conf/AR71XX.hints b/sys/mips/conf/AR71XX.hints
index 0593dc0..2b7bac0 100644
--- a/sys/mips/conf/AR71XX.hints
+++ b/sys/mips/conf/AR71XX.hints
@@ -48,5 +48,17 @@ hint.spi.0.msize=0x10
 hint.mx25l.0.at="spibus0"
 hint.mx25l.0.cs=0
 
+# GPIO
+hint.gpio.0.at="apb0"
+hint.gpio.0.maddr=0x18040000
+hint.gpio.0.msize=0x1000
+hint.gpio.0.irq=2
+
+# RF led
+hint.gpioled.0.at="gpiobus0"
+hint.gpioled.0.name="rf"
+# pin 2
+hint.gpioled.0.pins=0x0004
+
 # Watchdog
 hint.ar71xx_wdog.0.at="nexus0"
diff --git a/sys/sys/gpio.h b/sys/sys/gpio.h
new file mode 100644
index 0000000..3222aed
--- /dev/null
+++ b/sys/sys/gpio.h
@@ -0,0 +1,94 @@
+/* $NetBSD: gpio.h,v 1.7 2009/09/25 20:27:50 mbalmer Exp $ */
+/*	$OpenBSD: gpio.h,v 1.7 2008/11/26 14:51:20 mbalmer Exp $	*/
+/*-
+ * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2009 Marc Balmer <marc@msys.ch>
+ * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __GPIO_H__
+#define __GPIO_H__
+
+#include <sys/ioccom.h>
+
+/* GPIO pin states */
+#define GPIO_PIN_LOW		0x00	/* low level (logical 0) */
+#define GPIO_PIN_HIGH		0x01	/* high level (logical 1) */
+
+/* Max name length of a pin */
+#define GPIOMAXNAME		64
+
+/* GPIO pin configuration flags */
+#define GPIO_PIN_INPUT		0x0001	/* input direction */
+#define GPIO_PIN_OUTPUT		0x0002	/* output direction */
+#define GPIO_PIN_OPENDRAIN	0x0004	/* open-drain output */
+#define GPIO_PIN_PUSHPULL	0x0008	/* push-pull output */
+#define GPIO_PIN_TRISTATE	0x0010	/* output disabled */
+#define GPIO_PIN_PULLUP		0x0020	/* internal pull-up enabled */
+#define GPIO_PIN_PULLDOWN	0x0040	/* internal pull-down enabled */
+#define GPIO_PIN_INVIN		0x0080	/* invert input */
+#define GPIO_PIN_INVOUT		0x0100	/* invert output */
+#define GPIO_PIN_PULSATE	0x0200	/* pulsate in hardware */
+
+struct gpio_pin {
+	uint32_t gp_pin;			/* pin number */
+	char gp_name[GPIOMAXNAME];		/* human-readable name */
+	uint32_t gp_caps;			/* capabilities */
+	uint32_t gp_flags;			/* current flags */
+};
+
+/* GPIO pin request (read/write/toggle) */
+struct gpio_req {
+	uint32_t gp_pin;			/* pin number */
+	uint32_t gp_value;			/* value */
+};
+
+
+/*
+ * ioctls
+ */
+#define GPIOMAXPIN		_IOR('G', 0, int)
+#define	GPIOGETCONFIG		_IOWR('G', 1, struct gpio_pin)
+#define	GPIOSETCONFIG		_IOW('G', 2, struct gpio_pin)
+#define	GPIOGET			_IOWR('G', 3, struct gpio_req)
+#define	GPIOSET			_IOW('G', 4, struct gpio_req)
+#define	GPIOTOGGLE		_IOWR('G', 5, struct gpio_req)
+
+#endif /* __GPIO_H__ */
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index 6497743..37581b8 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -75,6 +75,7 @@ SUBDIR=	alias \
 	getconf \
 	getent \
 	getopt \
+	gpioctl \
 	${_gprof} \
 	gzip \
 	head \
diff --git a/usr.bin/gpioctl/Makefile b/usr.bin/gpioctl/Makefile
new file mode 100644
index 0000000..1daf641
--- /dev/null
+++ b/usr.bin/gpioctl/Makefile
@@ -0,0 +1,6 @@
+#	@(#)Makefile	8.1 (Berkeley) 6/9/93
+# $FreeBSD$
+
+PROG=	gpioctl
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/gpioctl/gpioctl.1 b/usr.bin/gpioctl/gpioctl.1
new file mode 100644
index 0000000..116e471
--- /dev/null
+++ b/usr.bin/gpioctl/gpioctl.1
@@ -0,0 +1,47 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 18, 2009
+.Dt GPIOCTL 1
+.Os
+.Sh NAME
+.Nm gpioctl
+.Nd manage GPIO devices
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility manages GPIO devices
+.Sh HISTORY
+None
diff --git a/usr.bin/gpioctl/gpioctl.c b/usr.bin/gpioctl/gpioctl.c
new file mode 100644
index 0000000..abbe95d
--- /dev/null
+++ b/usr.bin/gpioctl/gpioctl.c
@@ -0,0 +1,327 @@
+/*-
+ * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/gpio.h>
+
+struct flag_desc {
+	const char *name;
+	uint32_t flag;
+};
+
+struct flag_desc gpio_flags[] = {
+	{ "IN", GPIO_PIN_INPUT },
+	{ "OUT", GPIO_PIN_OUTPUT },
+	{ "OD", GPIO_PIN_OPENDRAIN },
+	{ "PP", GPIO_PIN_PUSHPULL },
+	{ "TS", GPIO_PIN_TRISTATE },
+	{ "PU", GPIO_PIN_PULLUP },
+	{ "PD", GPIO_PIN_PULLDOWN },
+	{ "II", GPIO_PIN_INVIN },
+	{ "IO", GPIO_PIN_INVOUT },
+	{ "PULSE", GPIO_PIN_PULSATE },
+	{ NULL, 0 },
+};
+
+static void usage(void);
+static const char* cap2str(uint32_t);
+int str2cap(const char*);
+static int str2int(const char*, int*);
+static void print_caps(int);
+static void dump_pins(int, int);
+static void fail(const char*, ...);
+
+int
+main(int argc, char **argv)
+{
+	int i;
+	struct gpio_pin pin;
+	struct gpio_req req;
+	char *ctlfile = NULL;
+	int pinn, pinv, fd, ch;
+	int flags, flag, ok;
+	int config, toggle, verbose, list;
+
+	pinn = config = toggle = verbose = list = 0;
+
+	while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) {
+		switch (ch) {
+		case 'c':
+			config = 1;
+			pinn = str2int(optarg, &ok);
+			if (!ok)
+				fail("Invalid pin number: %s\n", optarg);
+			break;
+		case 'f':
+			ctlfile = optarg;
+			break;
+		case 'l':
+			list = 1;
+			break;
+		case 't':
+			toggle = 1;
+			pinn = str2int(optarg, &ok);
+			if (!ok)
+				fail("Invalid pin number: %s\n", optarg);
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		default:
+			usage();
+			break;
+		}
+	}
+	argv += optind;
+	argc -= optind;
+	for (i = 0; i < argc; i++)
+		printf("%d/%s\n", i, argv[i]);
+
+	if (ctlfile == NULL)
+		fail("No gpioctl device provided\n");
+
+	fd = open(ctlfile, O_RDONLY);
+	if (fd < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	if (list) {
+		dump_pins(fd, verbose);
+		close(fd);
+		exit(0);
+	}
+
+	if (toggle) {
+		/*
+		 * -t pin assumes no additional arguments
+		 */
+		if(argc > 0) {
+			usage();
+			exit(1);
+		}
+
+		req.gp_pin = pinn;
+		if (ioctl(fd, GPIOTOGGLE, &req) < 0) {
+			perror("ioctl(GPIOTOGGLE)");
+			exit(1);
+		}
+
+		close(fd);
+		exit (0);
+	}
+
+	if (config) {
+		flags = 0;
+		for (i = 0; i < argc; i++) {
+			flag = str2cap(argv[i]);
+			if (flag < 0)
+				fail("Invalid flag: %s\n", argv[i]);
+			flags |= flag;
+		}
+
+		pin.gp_pin = pinn;
+		pin.gp_flags = flags;
+		if (ioctl(fd, GPIOSETCONFIG, &pin) < 0) {
+			perror("ioctl(GPIOSETCONFIG)");
+			exit(1);
+		}
+
+		exit(0);
+	}
+
+	/*
+	 * Last two cases - set value or print value
+	 */
+	if ((argc == 0) || (argc > 2)) {
+		usage();
+		exit(1);
+	}
+
+	pinn = str2int(argv[0], &ok);
+	if (!ok)
+		fail("Invalid pin number: %s\n", argv[0]);
+
+	/*
+	 * Read pin value
+	 */
+	if (argc == 1) {
+		req.gp_pin = pinn;
+		if (ioctl(fd, GPIOGET, &req) < 0) {
+			perror("ioctl(GPIOGET)");
+			exit(1);
+		}
+		printf("%d\n", req.gp_value);
+		exit (0);
+	}
+
+	/*
+	 * Set pin value
+	 */
+
+	/* Is it valid number and 0 or 1?  */
+	pinv = str2int(argv[0], &ok);
+	if (!ok || ((pinv != 0) && (pinv != 1)))
+		fail("Invalid pin value: %s\n", argv[0]);
+
+	req.gp_pin = pinn;
+	req.gp_pin = pinv;
+	if (ioctl(fd, GPIOSET, &req) < 0) {
+		perror("ioctl(GPIOSET)");
+		exit(1);
+	}
+
+	close(fd);
+	exit(0);
+}
+
+static void
+usage()
+{
+	fprintf(stderr, "Usage:\n");
+	fprintf(stderr, "\tgpioctl -f ctldev -l [-v]\n");
+	fprintf(stderr, "\tgpioctl -f ctldev -t pin\n");
+	fprintf(stderr, "\tgpioctl -f ctldev -c pin flag ...\n");
+	fprintf(stderr, "\tgpioctl -f ctldev pin [0|1]\n");
+	exit(1);
+}
+
+static const char *
+cap2str(uint32_t cap)
+{
+	struct flag_desc * pdesc = gpio_flags;
+	while (pdesc->name) {
+		if (pdesc->flag == cap)
+			return pdesc->name;
+		pdesc++;
+	}
+
+	return "UNKNOWN";
+}
+
+int
+str2cap(const char *str)
+{
+	struct flag_desc * pdesc = gpio_flags;
+	while (pdesc->name) {
+		if (strcasecmp(str, pdesc->name))
+			return pdesc->flag;
+		pdesc++;
+	}
+
+	return (-1);
+}
+
+/*
+ * Our handmade function for converting string to number
+ */
+static int
+str2int(const char *s, int *ok)
+{
+	char *endptr;
+	int res = strtod(s, &endptr);
+	if (endptr != s + strlen(s) )
+		*ok = 0;
+	else
+		*ok = 1;
+
+	return res;
+}
+
+static void
+print_caps(int caps)
+{
+	int i, need_coma;
+
+	need_coma = 0;
+	printf("<");
+	for (i = 0; i < 32; i++) {
+		if (caps & (1 << i)) {
+			if (need_coma)
+				printf(",");
+			printf("%s", cap2str(1 << i));
+			need_coma = 1;
+		}
+	}
+	printf(">");
+}
+
+static void
+dump_pins(int fd, int verbose)
+{
+	int i, maxpin;
+	struct gpio_pin pin;
+	struct gpio_req req;
+
+	if (ioctl(fd, GPIOMAXPIN, &maxpin) < 0) {
+		perror("ioctl(GPIOMAXPIN)");
+		exit(1);
+	}
+
+	for (i = 0; i <= maxpin; i++) {
+		pin.gp_pin = i;
+		if (ioctl(fd, GPIOGETCONFIG, &pin) < 0)
+			/* For some reason this pin is inaccessible */
+			continue;
+
+		req.gp_pin = i;
+		if (ioctl(fd, GPIOGET, &req) < 0) {
+			/* Now, that's wrong */
+			perror("ioctl(GPIOGET)");
+			exit(1);
+		}
+
+		printf("pin %02d:\t%d\t%s", pin.gp_pin, req.gp_value,
+		    pin.gp_name);
+
+		print_caps(pin.gp_flags);
+
+		if (verbose) {
+			printf(", caps:");
+			print_caps(pin.gp_caps);
+		}
+		printf("\n");
+	}
+}
+
+static void
+fail(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	exit(1);
+}

--Apple-Mail-6--206473323
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=us-ascii

 
--Apple-Mail-6--206473323
Content-Disposition: attachment;
	filename=gpioctl.c
Content-Type: application/octet-stream;
	name="gpioctl.c"
Content-Transfer-Encoding: 7bit

/*-
 * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/gpio.h>

struct flag_desc {
	const char *name;
	uint32_t flag;
};

struct flag_desc gpio_flags[] = {
	{ "IN", GPIO_PIN_INPUT },
	{ "OUT", GPIO_PIN_OUTPUT },
	{ "OD", GPIO_PIN_OPENDRAIN },
	{ "PP", GPIO_PIN_PUSHPULL },
	{ "TS", GPIO_PIN_TRISTATE },
	{ "PU", GPIO_PIN_PULLUP },
	{ "PD", GPIO_PIN_PULLDOWN },
	{ "II", GPIO_PIN_INVIN },
	{ "IO", GPIO_PIN_INVOUT },
	{ "PULSE", GPIO_PIN_PULSATE },
	{ NULL, 0 },
};

static void usage(void);
static const char* cap2str(uint32_t);
int str2cap(const char*);
static int str2int(const char*, int*);
static void print_caps(int);
static void dump_pins(int, int);
static void fail(const char*, ...);

int
main(int argc, char **argv)
{
	int i;
	struct gpio_pin pin;
	struct gpio_req req;
	char *ctlfile = NULL;
	int pinn, pinv, fd, ch;
	int flags, flag, ok;
	int config, toggle, verbose, list;

	pinn = config = toggle = verbose = list = 0;

	while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) {
		switch (ch) {
		case 'c':
			config = 1;
			pinn = str2int(optarg, &ok);
			if (!ok)
				fail("Invalid pin number: %s\n", optarg);
			break;
		case 'f':
			ctlfile = optarg;
			break;
		case 'l':
			list = 1;
			break;
		case 't':
			toggle = 1;
			pinn = str2int(optarg, &ok);
			if (!ok)
				fail("Invalid pin number: %s\n", optarg);
			break;
		case 'v':
			verbose = 1;
			break;
		default:
			usage();
			break;
		}
	}
	argv += optind;
	argc -= optind;
	for (i = 0; i < argc; i++)
		printf("%d/%s\n", i, argv[i]);

	if (ctlfile == NULL)
		fail("No gpioctl device provided\n");

	fd = open(ctlfile, O_RDONLY);
	if (fd < 0) {
		perror("open");
		exit(1);
	}

	if (list) {
		dump_pins(fd, verbose);
		close(fd);
		exit(0);
	}

	if (toggle) {
		/*
		 * -t pin assumes no additional arguments
		 */
		if(argc > 0) {
			usage();
			exit(1);
		}

		req.gp_pin = pinn;
		if (ioctl(fd, GPIOTOGGLE, &req) < 0) {
			perror("ioctl(GPIOTOGGLE)");
			exit(1);
		}

		close(fd);
		exit (0);
	}

	if (config) {
		flags = 0;
		for (i = 0; i < argc; i++) {
			flag = str2cap(argv[i]);
			if (flag < 0)
				fail("Invalid flag: %s\n", argv[i]);
			flags |= flag;
		}

		pin.gp_pin = pinn;
		pin.gp_flags = flags;
		if (ioctl(fd, GPIOSETCONFIG, &pin) < 0) {
			perror("ioctl(GPIOSETCONFIG)");
			exit(1);
		}

		exit(0);
	}

	/*
	 * Last two cases - set value or print value
	 */
	if ((argc == 0) || (argc > 2)) {
		usage();
		exit(1);
	}

	pinn = str2int(argv[0], &ok);
	if (!ok)
		fail("Invalid pin number: %s\n", argv[0]);

	/*
	 * Read pin value
	 */
	if (argc == 1) {
		req.gp_pin = pinn;
		if (ioctl(fd, GPIOGET, &req) < 0) {
			perror("ioctl(GPIOGET)");
			exit(1);
		}
		printf("%d\n", req.gp_value);
		exit (0);
	}

	/*
	 * Set pin value
	 */

	/* Is it valid number and 0 or 1?  */
	pinv = str2int(argv[0], &ok);
	if (!ok || ((pinv != 0) && (pinv != 1)))
		fail("Invalid pin value: %s\n", argv[0]);

	req.gp_pin = pinn;
	req.gp_pin = pinv;
	if (ioctl(fd, GPIOSET, &req) < 0) {
		perror("ioctl(GPIOSET)");
		exit(1);
	}

	close(fd);
	exit(0);
}

static void
usage(void)
{
	fprintf(stderr, "Usage:\n");
	fprintf(stderr, "\tgpioctl -f ctldev -l [-v]\n");
	fprintf(stderr, "\tgpioctl -f ctldev -t pin\n");
	fprintf(stderr, "\tgpioctl -f ctldev -c pin flag ...\n");
	fprintf(stderr, "\tgpioctl -f ctldev pin [0|1]\n");
	exit(1);
}

static const char *
cap2str(uint32_t cap)
{
	struct flag_desc * pdesc = gpio_flags;
	while (pdesc->name) {
		if (pdesc->flag == cap)
			return pdesc->name;
		pdesc++;
	}

	return "UNKNOWN";
}

int
str2cap(const char *str)
{
	struct flag_desc * pdesc = gpio_flags;
	while (pdesc->name) {
		if (strcasecmp(str, pdesc->name))
			return pdesc->flag;
		pdesc++;
	}

	return (-1);
}

/*
 * Our handmade function for converting string to number
 */
static int
str2int(const char *s, int *ok)
{
	char *endptr;
	int res = strtod(s, &endptr);
	if (endptr != s + strlen(s) )
		*ok = 0;
	else
		*ok = 1;

	return res;
}

static void
print_caps(int caps)
{
	int i, need_coma;

	need_coma = 0;
	printf("<");
	for (i = 0; i < 32; i++) {
		if (caps & (1 << i)) {
			if (need_coma)
				printf(",");
			printf("%s", cap2str(1 << i));
			need_coma = 1;
		}
	}
	printf(">");
}

static void
dump_pins(int fd, int verbose)
{
	int i, maxpin;
	struct gpio_pin pin;
	struct gpio_req req;

	if (ioctl(fd, GPIOMAXPIN, &maxpin) < 0) {
		perror("ioctl(GPIOMAXPIN)");
		exit(1);
	}

	for (i = 0; i <= maxpin; i++) {
		pin.gp_pin = i;
		if (ioctl(fd, GPIOGETCONFIG, &pin) < 0)
			/* For some reason this pin is inaccessible */
			continue;

		req.gp_pin = i;
		if (ioctl(fd, GPIOGET, &req) < 0) {
			/* Now, that's wrong */
			perror("ioctl(GPIOGET)");
			exit(1);
		}

		printf("pin %02d:\t%d\t%s", pin.gp_pin, req.gp_value,
		    pin.gp_name);

		print_caps(pin.gp_flags);

		if (verbose) {
			printf(", caps:");
			print_caps(pin.gp_caps);
		}
		printf("\n");
	}
}

static void
fail(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);
	exit(1);
}

--Apple-Mail-6--206473323
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=us-ascii

 
--Apple-Mail-6--206473323
Content-Disposition: attachment;
	filename=RB4XX
Content-Type: application/octet-stream;
	name="RB4XX"
Content-Transfer-Encoding: 7bit

#
# $FreeBSD$
#

ident		RB4XX
cpu		CPU_MIPS4KC
options 	ISA_MIPS32
makeoptions	TARGET_BIG_ENDIAN
makeoptions	KERNLOADADDR=0x80050000
options		HZ=1000

files		"../atheros/files.ar71xx"
hints		"RB450.hints"

#makeoptions	DEBUG=-g		#Build kernel with gdb(1) debug symbols
makeoptions	MODULES_OVERRIDE=""

#options		DDB
#options		KDB

options		SCHED_4BSD		#4BSD scheduler
options		INET			#InterNETworking
options		NFSCLIENT		#Network Filesystem Client
options		NFS_ROOT		#NFS usable as /, requires NFSCLIENT
options		PSEUDOFS		#Pseudo-filesystem framework
options		_KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions

# options		NFS_LEGACYRPC
# Debugging for use in -current
# options		INVARIANTS
# options		INVARIANT_SUPPORT
# options		WITNESS
# options		WITNESS_SKIPSPIN
options         FFS                     #Berkeley Fast Filesystem
options         SOFTUPDATES             #Enable FFS soft updates support
options         UFS_ACL                 #Support for access control lists
options         UFS_DIRHASH             #Improve performance on big directories


options		BOOTP
options		BOOTP_NFSROOT
options		BOOTP_NFSV3
options		BOOTP_WIRED_TO=arge1
options		BOOTP_COMPAT
options		ROOTDEVNAME=\"nfs:192.168.10.1:/mnt/bsd\"

device		pci

#device		ath             # Atheros pci/cardbus NIC's
#options 	ATH_DEBUG
#device		ath_hal
#option		AH_SUPPORT_AR5416
#device		ath_rate_sample

device		mii
device		arge

device		usb
options		USB_EHCI_BIG_ENDIAN_DESC        # handle big-endian byte order
options		USB_DEBUG
device		ehci

device		gpio
device		gpioled

device		spibus
device		ar71xx_spi
#device		nand			# Generic NAND disk support
#device		rb_nand			# RouterBoard NAND Support
#device		geom_nand		# NAND slices support
#options		YAFFS

device		ar71xx_wdog

device		uart

device		loop
device		ether
device		md
device		bpf
device		random
device		if_bridge

device		pf
device		pfsync
device		pflog

options		RB_GPIO_PINS
options		FIX_RB_MAC_ADDRESS

--Apple-Mail-6--206473323
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=us-ascii

 
--Apple-Mail-6--206473323
Content-Disposition: attachment;
	filename=RB450.hints
Content-Type: application/octet-stream;
	name="RB450.hints"
Content-Transfer-Encoding: 7bit

# $FreeBSD$
hint.apb.0.at="nexus0"
hint.apb.0.irq=4

# uart0
hint.uart.0.at="apb0"
# see atheros/uart_cpu_ar71xx.c why +3
hint.uart.0.maddr=0x18020003
hint.uart.0.msize=0x18
hint.uart.0.irq=3

#ohci
#hint.ohci.0.at="apb0"
#hint.ohci.0.maddr=0x1c000000
#hint.ohci.0.msize=0x01000000
#hint.ohci.0.irq=6

# ehci
hint.ehci.0.at="nexus0"
hint.ehci.0.maddr=0x1b000000
hint.ehci.0.msize=0x01000000
hint.ehci.0.irq=1

# pci
#hint.pcib.0.at="nexus0"
#hint.pcib.0.irq=0

hint.arge.0.at="nexus0"
hint.arge.0.maddr=0x19000000
hint.arge.0.msize=0x1000
hint.arge.0.irq=2
# PHY0, PHY1, PHY2, PHY3
hint.arge.0.phymask=0x0f

hint.arge.1.at="nexus0"
hint.arge.1.maddr=0x1A000000
hint.arge.1.msize=0x1000
hint.arge.1.irq=3
# PHY4
hint.arge.1.phymask=0x10

# Watchdog
hint.ar71xx_wdog.0.at="nexus0"

# GPIO
hint.gpio.0.at="apb0"
hint.gpio.0.maddr=0x18040000
hint.gpio.0.msize=0x1000
hint.gpio.0.irq=2

# User led
hint.gpioled.0.at="gpiobus0"
hint.gpioled.0.name="user"
# pin 4
hint.gpioled.0.pins=0x0010

# SPI flash
hint.spi.0.at="nexus0"
hint.spi.0.maddr=0x1f000000
hint.spi.0.msize=0x10

# RB Flash
#hint.rb_nand.0.at="spibus0"
#hint.rb_nand.0.cs=0

# NAND slices for RouterBoard
hint.nand_slice.0.size="0x40000"
hint.nand_slice.0.offset="0"
hint.nand_slice.0.name="bootloader"
hint.nand_slice.1.size="0x3c0000"
hint.nand_slice.1.offset="0x40000"
hint.nand_slice.1.name="kernelfs"
hint.nand_slice.2.size="0"
hint.nand_slice.2.offset="0x400000"
hint.nand_slice.2.name="rootfs"

--Apple-Mail-6--206473323--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?0EFED95F-1B59-4A34-B518-E49A6ACD7D64>