Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 21 Apr 2014 22:01:09 -0400
From:      Larry Baird <lab@gta.com>
To:        freebsd-hackers@freebsd.org
Subject:   apu1c led driver
Message-ID:  <20140422020109.GA57760@gta.com>

next in thread | raw e-mail | index | archive | help
There exists a nice simple linux driver for the leds on a pc engines apu1c
board at http://daduke.org/linux/apu/.  Converting driver to use led(4)
and run on FreeBSD seemed straight forward.  Or that is until I realized
I don't know how to alloc and write to a fixed set of I/O ports. I believe
the magic happens by using bus_alloc_resource(). Code below attempts to allow
control of the second of three leds on the apu1c board.  Once I get that
working, it should be easy to extend driver to support all three leds.
What is the correct way to allocate and write to a a set of I/O ports at
address 0xFED801BD?

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <x86/bus.h>
#include <dev/led/led.h>

#define BASEADDR        (0xFED801BD)
#define LEDON           (0x8)
#define LEDOFF          (0xC8)

#define GPIO_187      187       // MODESW
#define GPIO_189      189       // LED1#
#define GPIO_190      190       // LED2#
#define GPIO_191      191       // LED3#

struct apuled_softc {
	device_t	sc_dev;
        int             sc_rid;
        int             sc_type;
        int             sc_offset;
	struct resource *sc_res;
	void     	*sc_led1;
};

/*
 * Device methods.
 */
static int	apuled_probe(device_t dev);
static int	apuled_attach(device_t dev);
static int	apuled_detach(device_t dev);

static device_method_t apuled_methods[] = {
	/* Device interface */
	DEVMETHOD(device_probe,		apuled_probe),
	DEVMETHOD(device_attach,	apuled_attach),
	DEVMETHOD(device_detach,	apuled_detach),

	DEVMETHOD_END
};

static driver_t apuled_driver = {
	"apuled",
	apuled_methods,
	sizeof(struct apuled_softc),
};

static devclass_t apuled_devclass;
DRIVER_MODULE(apuled, pci, apuled_driver, apuled_devclass, NULL, NULL);


static int
apuled_probe(device_t dev)
{
	device_set_desc(dev, "APU led");

	return (BUS_PROBE_GENERIC);
}

static void
led_func(void *ptr, int onoff)
{
	struct apuled_softc *sc = (struct apuled_softc *)ptr;
	u_int8_t value;

	if ( onoff ) {
		value = LEDON;
	} else {
		value = LEDOFF;
	}

	bus_write_1(sc->sc_res, 1, value);
}

static int
apuled_attach(device_t dev)
{
	struct apuled_softc *sc = device_get_softc(dev);

	sc->sc_dev = dev;
	sc->sc_rid = 1;
	sc->sc_type = SYS_RES_IOPORT;

	if ( (sc->sc_res = bus_alloc_resource( sc->sc_dev,
					   sc->sc_type,
					   &sc->sc_rid,
					   BASEADDR,
					   BASEADDR + 4,
					   4,
					   RF_ACTIVE)) == NULL ) {
		device_printf( sc->sc_dev, "Unable to allocate bus resource\n" );
		return ENXIO;

	} else if ( (sc->sc_led1 = led_create(led_func, sc, "led1")) == NULL ) {
		device_printf( sc->sc_dev, "Unable to create LED 1\n" );
		return ENXIO;

	} else {
		device_printf( sc->sc_dev, "LED 1 created\n" );
	}

	return (0);
}

int
apuled_detach(device_t dev)
{
	struct apuled_softc *sc = device_get_softc(dev);

	if ( sc->sc_led1 != NULL ) {
		led_destroy( sc->sc_led1 );
	}

	if ( sc->sc_res != NULL ) {
		bus_release_resource( sc->sc_dev, sc->sc_type, sc->sc_rid, sc->sc_res );
	}

	return (0);
}

-- 
------------------------------------------------------------------------
Larry Baird
Global Technology Associates, Inc. 1992-2012 	| http://www.gta.com
Celebrating Twenty Years of Software Innovation | Orlando, FL
Email: lab@gta.com                 		| TEL 407-380-0220



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20140422020109.GA57760>