From owner-freebsd-drivers@FreeBSD.ORG Thu Feb 28 17:09:51 2013 Return-Path: Delivered-To: freebsd-drivers@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id DD685C09 for ; Thu, 28 Feb 2013 17:09:51 +0000 (UTC) (envelope-from jhb@freebsd.org) Received: from bigwig.baldwin.cx (bigknife-pt.tunnel.tserv9.chi1.ipv6.he.net [IPv6:2001:470:1f10:75::2]) by mx1.freebsd.org (Postfix) with ESMTP id B5CEB27A for ; Thu, 28 Feb 2013 17:09:51 +0000 (UTC) Received: from jhbbsd.localnet (unknown [209.249.190.124]) by bigwig.baldwin.cx (Postfix) with ESMTPSA id 1C8DFB9A4; Thu, 28 Feb 2013 12:09:51 -0500 (EST) From: John Baldwin To: freebsd-drivers@freebsd.org Subject: Re: ISA driver for IRQ and PortIO Date: Thu, 28 Feb 2013 10:39:41 -0500 User-Agent: KMail/1.13.5 (FreeBSD/8.2-CBSD-20110714-p25; KDE/4.5.5; amd64; ; ) References: <20130227221641.B3CSW.38128.root@cdptpa-web26-z02> In-Reply-To: <20130227221641.B3CSW.38128.root@cdptpa-web26-z02> MIME-Version: 1.0 Content-Type: Text/Plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Message-Id: <201302281039.41919.jhb@freebsd.org> X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.2.7 (bigwig.baldwin.cx); Thu, 28 Feb 2013 12:09:51 -0500 (EST) X-BeenThere: freebsd-drivers@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Writing device drivers for FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2013 17:09:51 -0000 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