The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Каталог документации / Раздел "Руководства по FreeBSD на русском" / Оглавление документа

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

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


/*
 * Power controller (c) 1998, vadik likholetov vadik@sensi.org Hardware by
 * Alexandr Priomov, alexandr@sensi.org
 */

#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)

     

Этот, и другие документы, могут быть скачаны с ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

По вопросам связанными с FreeBSD, прочитайте документацию прежде чем писать в <questions@FreeBSD.org>.
По вопросам связанным с этой документацией, пишите <doc@FreeBSD.org>.
По вопросам связанным с русским переводом документации, пишите <frdp@FreeBSD.org.ua>.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру