Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Feb 2013 12:22:13 -0500
From:      <star-one@tx.rr.com>
To:        freebsd-drivers@freebsd.org, John Baldwin <jhb@freebsd.org>
Subject:   Re: ISA driver for IRQ and PortIO
Message-ID:  <20130228172213.GI7H4.29745.root@cdptpa-web19-z02>
In-Reply-To: <201302281039.41919.jhb@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Thank you.  I'll try that today.

Dave
---- John Baldwin <jhb@freebsd.org> wrote: 
> 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?20130228172213.GI7H4.29745.root>