Вот исходный текст драйвера некоего контроллера:
/* * 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)