# Problem developing a device driver for my development board's parallel interface.



## RalfPeg (Nov 5, 2019)

Hi there! I'm trying to access my development board's parallel interface using a device driver. After all I learned so far I developed the following program, which doesn't work.


```
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>

#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/lock.h>
#include <sys/mutex.h>

#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>

#define PPIBASE 0x378

struct myppi_softc
{
    int sc_io_rid;
    struct resource *sc_io_resource;

    struct cdev *sc_cdev0;

    struct mtx sc_mutex;
};

static devclass_t myppi_devclass;

static d_open_t myppi_open;
static d_close_t myppi_close;
static d_read_t myppi_read;
static d_write_t myppi_write;

static struct cdevsw myppi_cdevsw =    {
                        .d_version =    D_VERSION,
                        .d_open =     myppi_open,
                        .d_close =    myppi_close,
                        .d_read =    myppi_read,
                        .d_write =    myppi_write,
                        .d_name =    "myppi"
                    };

static int myppi_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
    uprintf("open\n");

    return 0;
}

static int myppi_close(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
    uprintf("close\n");

    return 0;
}

static int myppi_read(struct cdev *dev, struct uio *uio, int ioflag)
{
    uprintf("read\n");

    return 0;
}

static int myppi_write(struct cdev *dev, struct uio *uio, int ioflag)
{
    struct myppi_softc *sc = dev->si_drv1;

    uprintf("write\n");

    bus_write_1(sc->sc_io_resource, 0, 0xff);

    return 0;
}

static void myppi_identify(driver_t *driver, device_t parent)
{
    device_t child;

    child = device_find_child(parent, "myppi", -1);
    if(!child)
    {
        child = BUS_ADD_CHILD(parent, 0, "myppi", -1);
        bus_set_resource(child, SYS_RES_IOPORT, 0, PPIBASE, 1);
    }
}

static int myppi_probe(device_t dev)
{
    if(!bus_get_resource_start(dev, SYS_RES_IOPORT, 0))
    {
        return ENXIO;
    }

    device_set_desc(dev, "I/O Port Example");

    return BUS_PROBE_SPECIFIC;
}

static int myppi_attach(device_t dev)
{
    struct myppi_softc *sc = device_get_softc(dev);

    sc->sc_io_rid = 0;
    sc->sc_io_resource = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->sc_io_rid, RF_ACTIVE);
    if(!sc->sc_io_resource)
    {
        device_printf(dev, "unable to allocate resource\n");

        return ENXIO;
    }

    sc->sc_cdev0 = make_dev(&myppi_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644, "myppi0");

    sc->sc_cdev0->si_drv1 = sc;

    return 0;
}

static int myppi_detach(device_t dev)
{
    struct myppi_softc *sc = device_get_softc(dev);

    destroy_dev(sc->sc_cdev0);

    bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_io_rid, sc->sc_io_resource);

    return 0;
}

static device_method_t myppi_methods[] =    {
                            DEVMETHOD(device_identify,    myppi_identify),
                            DEVMETHOD(device_probe,        myppi_probe),
                            DEVMETHOD(device_attach,    myppi_attach),
                            DEVMETHOD(device_detach,    myppi_detach),
                            { 0, 0 }
                        };

static driver_t myppi_driver =    {
                    "myppi",
                    myppi_methods,
                    sizeof(struct myppi_softc)
                };

DRIVER_MODULE(myppi, acpi, myppi_driver, myppi_devclass, 0, 0);
```

dmesg says this after calling make load
`myppi0: <I/O Port Example> port 0x378 on acpi0
myppi0: unable to allocate resource
device_attach: myppi0 attach returned 6
myppi1: <I/O Port Example> port 0x20-0x21,0x24-0x25,0x28-0x29,0x2c-0x2d,0x30-0x31,0x34-0x35,0x38-0x39,0x3c-0x3d,0xa0-0xa1,0xa4-0xa5,0xa8-0xa9,0xac-0xad,0xb0-0xb1,0xb4-0xb5,0xb8-0xb9,0xbc-0xbd,0x4d0-0x4d1 irq 2 on acpi0`

and about the parallel interface it says this
`ppc1: <Parallel port> port 0x378-0x37f irq 5 on acpi0
ppc1: Generic chipset (NIBBLE-only) in COMPATIBLE mode
ppbus0: <Parallel port bus> on ppc1
lpt0: <Printer> on ppbus0
lpt0: Interrupt-driven port
ppi0: <Parallel I/O> on ppbus0`

Calling 'echo "1" > /devmyppi0' doens't make the signals rise. Using outb does work by the way. I guess there's something I didn't understand yet, but what could it be? oh and why is there a "myppi1" on dmesg?


----------



## unitrunker (Nov 5, 2019)

This isn't the answer you're looking for but might give you a better result. Don't use "bitbanging" techniques on the host PC. It's hard to get consistent timing under a multitasking kernel. Use a small Arduino to manage that. They're cheap and can guarantee timing constraints. Use USB or serial to talk to the Arduino.


----------



## RalfPeg (Nov 6, 2019)

wtf nobody knows anything?


----------



## unitrunker (Nov 7, 2019)

Ralf - I think it is more the case that most computers don't have a parallel port. They're slow and obsolete - like my Epson MX-100 with greenbar paper and ink ribbon. The cool kids have moved on to Arduinos and Raspberry PIs.


----------



## mast07 (Nov 7, 2019)

Your myppi0 does not attach sucessfully. Possibly the ppi-driver has registered the address-resource exclusively and your driver is not allowed to also allocate that resource.
AFAIK outb() does act directly on the physical memory, so there is no driver involved.


----------

