ISA driver for IRQ and PortIO
star-one at tx.rr.com
star-one at tx.rr.com
Thu Feb 28 17:22:14 UTC 2013
Thank you. I'll try that today.
Dave
---- John Baldwin <jhb at freebsd.org> wrote:
> On Wednesday, February 27, 2013 5:16:41 pm star-one at 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
More information about the freebsd-drivers
mailing list