Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Feb 2013 10:39:41 -0500
From:      John Baldwin <jhb@freebsd.org>
To:        freebsd-drivers@freebsd.org
Subject:   Re: ISA driver for IRQ and PortIO
Message-ID:  <201302281039.41919.jhb@freebsd.org>
In-Reply-To: <20130227221641.B3CSW.38128.root@cdptpa-web26-z02>
References:  <20130227221641.B3CSW.38128.root@cdptpa-web26-z02>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wednesday, February 27, 2013 5:16:41 pm star-one@tx.rr.com wrote:
> I need to write a simple device driver for the ISA bus that uses one IRQ and 
a few reads and writes to I/O Ports 0x300 +.
> 
> 
> I don't know even where to start with FreeBSD. I've done drivers before in 
other OS systems and have a book for Linux but FreeBSD seems MUCH differnt.
> 
> 
> Are there any examples I can get?  I thought about modifying the serial 
driver but I'm not een sure if that's a good idea.
> 
> 
> Any help would be great.

There is a FreeBSD Device Driver book.  You will need to allocate 'struct 
resource' objects for your IRQ and I/O port and then use the bus_space API 
with your I/O port resource to do inb/outb operations.  That is, you would 
need something like this:

In /boot/device.hints:

hint.foo.0.at="isa0"
hint.foo.0.irq=X
hint.foo.0.port=0x300

Then a sketch of your driver would be:

#define NPORTS	4	/* How many I/O ports you need starting at 0x300 */

/* Sample only of names for the 4 ports via relative offsets to the start */
#define	CONTROL_REG		0
#define	DATA_REG		1

struct foo_softc {
	device_t dev;
	struct resource *io;
	struct resource *irq;
	void *intr_cookie;
};

/* Interrupt handler. */
static void
foo_int(void *arg)
{
	struct foo_softc *sc;

	sc = arg;
	device_printf(sc->dev, "got an interrupt\n");
}

static int
foo_probe(device_t dev)
{
	/* Ignore PNP devices. */
	if (isa_get_logicalid(dev) != 0)
		return (ENXIO);

	/* Require IRQ and port hints. */
	if (isa_get_port(dev) == -1 ||
	    isa_get_irq(dev) == -1)
		return (ENXIO);

	device_set_desc(dev, "My foo device");
	return (BUS_PROBE_GENERIC);
}

static int
foo_attach(device_t dev)
{
	struct foo_softc *sc;
	int error, rid;

	sc = device_get_softc(dev);
	sc->dev = dev;

	/* Allocate resources. */
	rid = 0;
	sc->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0ul, ~0ul, NPORTS,
	    RF_ACTIVE);
	if (sc->io == NULL) {
		device_printf(dev, "Failed to allocate I/O ports\n");
		error = ENXIO;
		goto out;
	rid = 0;
	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
	if (sc->irq == NULL) {
		device_printf(dev, "Failed to allocate IRQ\n");
		error = ENXIO;
		goto out;
	}

	/* Read a byte from port 0x300 */
	device_printf(dev, "Current control value = %x\n",
	    bus_read_1(sc->io, CONTROL_REG));
	/* Read a byte from port 0x301 */
	device_printf(dev, "Current data value = %x\n",
	    bus_read_1(sc->io, DATA_REG));
	/* Write a byte to the control reg at 0x300 */
	bus_write_1(sc->io, CONTROL_REG, 0xff);

	/* Setup interrupt handler. */
	error = bus_setup_intr(dev, sc->irq, INTR_TYPE_MISC | INTR_MPSAFE, NULL,
	    foo_intr, sc, &sc->intr_cookie);
	if (error != 0) {
		device_printf(dev, "Failed to setup interrupt handler\n");
		goto out;
	}
	return (0);

out:
	if (sc->irq != NULL)
		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
	if (sc->io != NULL)
		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->io);
	return (error);
}

static int
foo_detach(device_t dev)
{
	struct foo_softc *sc;

	sc = device_get_softc(dev);
	bus_teardown_intr(dev, sc->irq, sc->intr_cookie);
	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
	bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->io);
	return (0);
}

static device_method_t foo_methods[] = {
	DEVMETHOD(device_probe,		foo_probe),
	DEVMETHOD(device_attach,	foo_attach),
	DEVMETHOD(device_detach,	foo_detach),
	DEVMETHOD_END
};

static driver_t foo_driver = {
	"foo",
	foo_methods,
	sizeof(struct foo_softc);
};

static devclass_t foo_devclass;

DRIVER_MODULE(foo, isa, foo_driver, foo_devclass, NULL, NULL);

That should get you up and running, but to do something useful with the device 
you'll probably want to create a cdev or some such.

-- 
John Baldwin



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