11.3. Поделитесь примером драйвера устройства, пожалуйста.

Вот исходный текст драйвера некоего контроллера:


    /*
     * Power controller (c) 1998, vadik likholetov [email protected] Hardware by
     * Alexandr Priomov, [email protected]
     */

    #include "pwc.h"

    #include <sys/param.h>
    #include <sys/systm.h>
    #include <sys/kernel.h>
    #include <sys/conf.h>
    #include <sys/uio.h>


    #include <i386/isa/isa.h>
    #include <i386/isa/isa_device.h>
    #include <i386/isa/lptreg.h>

    static struct pwc_softc {
        int         sc_port;
        short       sc_state;
        int         hw_state;
    }       pwc_sc[NPWC];

    #define TASK_SIZE 12

    #define DEFAULT 0      /* default state for device */
    #define OPEN (1<<0)    /* device is open */
    #define OBUSY (1<<1)   /* doing output */
    #define OPENDING (1<<2)       /* pending output */


    static int  pwc_probe(struct isa_device * dvp);
    static int  pwc_attach(struct isa_device * isdp);

    struct isa_driver pwcdriver = {
        pwc_probe, pwc_attach, "pwc"
    };


    static d_open_t pwc_open;
    static d_close_t pwc_close;
    static d_write_t pwc_write;


    #define CDEV_MAJOR 220

    static struct cdevsw pwc_cdevsw =
    {pwc_open, pwc_close, noread, pwc_write,
        noioctl, nullstop, nullreset, nodevtotty,
    seltrue, nommap, nostrat, "pwc", NULL, -1};

    int
    pwc_probe(struct isa_device * dvp)
    {
        /* TODO -- test hardware for presence */
        return 1;
    }

    int
    pwc_attach(struct isa_device * isdp)
    {
        struct pwc_softc *sc;
        int         unit = isdp->id_unit;

        sc = pwc_sc + unit;
        sc->sc_port = isdp->id_iobase;
        sc->sc_state = DEFAULT;
        outb(sc->sc_port, 0);
        outb(sc->sc_port + lpt_control, 0);
        return 1;
    }


    static int
    pwc_open(dev_t dev, int flags, int fmt, struct proc * p)
    {
        struct pwc_softc *sc;

        u_int       unit = minor(dev);

        sc = pwc_sc + unit;

        if ((unit >= NPWC) || (sc->sc_port == 0))
          return ENXIO;

        if (sc->sc_state != DEFAULT)
          return EBUSY;

        return 0;
    }

    static int
    pwc_close(dev_t dev, int flags, int fmt, struct proc * p)
    {
        struct pwc_softc *sc = pwc_sc + minor(dev);

        sc->sc_state &= ~OPEN;
        while (sc->sc_state & OBUSY)
          if (tsleep((caddr_t) sc, PZERO | PCATCH, "pwcclose", hz) != EWOULDBLOCK)
           break;

        sc->sc_state = DEFAULT;

        return 0;
    }

    static int
    pwc_write(dev_t dev, struct uio * uio, int ioflag)
    {
        struct pwc_softc *sc = pwc_sc + minor(dev);
        char        buffer[TASK_SIZE];
        int         port = sc->sc_port;
        int         s;
        int         ret;
        int         i, j, d;

        if (uio->uio_resid != TASK_SIZE)
          return EOPNOTSUPP;

        s = spltty();
        if (sc->sc_state & OBUSY)
          return EBUSY;

        sc->sc_state |= OBUSY;
        splx(s);

        /* output goes there */

        uiomove(buffer, TASK_SIZE, uio);

        if (!(inb(port + lpt_status) & ~LPS_NACK)) {
          printf("pwc%d: no power on device\n", minor(dev));
          ret = EIO;
          goto gout;
        }
    #define NTRIES 10
        for (i = 0; i < TASK_SIZE; i++) {
          for (j = 0; j < NTRIES; j++)
           if ((inb(port + lpt_status) & LPS_NBSY))
            break;
           else
            DELAY(1);
          if (j == NTRIES) {
           printf("pwc%d: timeout(1) waiting for ~BSY (%x)\n",
    minor(dev),inb(port+lpt_status));
           ret = EIO;
           goto gout;
          }
          d = buffer[i] == '1' ? 1 : 0;

          if (i > 3 && i < 8)
           i ^= 1;

          outb(port + lpt_data, d);
          outb(port + lpt_control, LPC_STB);
          DELAY(1);     /* ??? */
          outb(port + lpt_control, 0);
        }

        for (j = 0; j < NTRIES; j++)
          if (inb(port + lpt_status) & LPS_NBSY)
           break;
          else
           DELAY(1);

        if (j == NTRIES) {
          printf("pwc%d: timeout(2) waiting for ~BSY\n", minor(dev));
          ret = EIO;
          goto gout;
        }
        ret = 0;
    gout:
        s = spltty();
        sc->sc_state &= ~OBUSY;

    #if 0
        if (sc->sc_state & OPENDING)
    #endif
          wakeup((caddr_t) sc);

        splx(s);
        return ret;
    }


    static      pwc_devsw_installed = 0;

    static void
    pwc_drvinit(void *unused)
    {
        dev_t       dev;

        if (!pwc_devsw_installed) {
          dev = makedev(CDEV_MAJOR, 0);
          cdevsw_add(&dev, &pwc_cdevsw, NULL);
          pwc_devsw_installed = 1;
        }
    }

    SYSINIT(pwcdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, pwc_drvinit,
    NULL)