The OpenNET Project / Index page

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

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

10.4 Символьные устройства

Драйвер символьного устройства передает данные непосредственно в или из процесса пользователя. Это самый распространенный тип драйвера устройства и в дереве исходных текстов имеется достаточно простых примеров таких драйверов.

В этом простом примере псевдо-устройство запоминает какие угодно значения, которые вы в него записываете, и затем может выдавать их назад при чтении из этого устройства. Приведены две версии, одна для FreeBSD  4.X, а другая для FreeBSD  5.X.

Example 10-1. Пример драйвера псевдо-устройства Echo для FreeBSD 4.X

/*
 * Simple `echo' pseudo-device KLD
 *
 * Murray Stokely
 */

#define MIN(a,b) (((a) < (b)) ? (a) : (b))

#include <sys/types.h>
#include <sys/module.h>
#include <sys/systm.h>  /* uprintf */
#include <sys/errno.h>
#include <sys/param.h>  /* defines used in kernel.h */
#include <sys/kernel.h> /* types used in module initialization */
#include <sys/conf.h>   /* cdevsw struct */
#include <sys/uio.h>    /* uio struct */
#include <sys/malloc.h>

#define BUFFERSIZE 256

/* Function prototypes */
d_open_t    echo_open;
d_close_t   echo_close;
d_read_t    echo_read;
d_write_t   echo_write;

/* Character device entry points */
static struct cdevsw echo_cdevsw = {
    echo_open,
    echo_close,
    echo_read,
    echo_write,
    noioctl,
    nopoll,
    nommap,
    nostrategy,
    "echo",
    33,             /* reserved for lkms - /usr/src/sys/conf/majors */
    nodump,
    nopsize,
    D_TTY,
    -1
};

struct s_echo {
    char msg[BUFFERSIZE];
    int len;
} t_echo;

/* vars */
static dev_t sdev;
static int len;
static int count;
static t_echo *echomsg;

MALLOC_DECLARE(M_ECHOBUF);
MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module");

/*
 * This function is called by the kld[un]load(2) system calls to
 * determine what actions to take when a module is loaded or unloaded.
 */

static int
echo_loader(struct module *m, int what, void *arg)
{
    int err = 0;

    switch (what) {
    case MOD_LOAD:                /* kldload */
        sdev = make_dev(&echo_cdevsw,
                    0,
                    UID_ROOT,
                    GID_WHEEL,
                    0600,
                    "echo");
        /* kmalloc memory for use by this driver */
            MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK);
        printf("Echo device loaded.\n");
        break;
    case MOD_UNLOAD:
        destroy_dev(sdev);
        FREE(echomsg,M_ECHOBUF);
        printf("Echo device unloaded.\n");
        break;
    default:
            err = EINVAL;
            break;
    }
    return(err);
}

int
echo_open(dev_t dev, int oflags, int devtype, struct proc *p)
{
    int err = 0;

    uprintf("Opened device \"echo\" successfully.\n");
    return(err);
}

int
echo_close(dev_t dev, int fflag, int devtype, struct proc *p)
{
    uprintf("Closing device \"echo.\"\n");
    return(0);
}

/*
 * The read function just takes the buf that was saved via
 * echo_write() and returns it to userland for accessing.
 * uio(9)
 */

int
echo_read(dev_t dev, struct uio *uio, int ioflag)
{
    int err = 0;
    int amt;

  /* How big is this read operation?  Either as big as the user wants,
     or as big as the remaining data */
  amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0);
  if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) {
    uprintf("uiomove failed!\n");
  }

  return err;
}

/*
 * echo_write takes in a character string and saves it
 * to buf for later accessing.
 */

int
echo_write(dev_t dev, struct uio *uio, int ioflag)
{
  int err = 0;

  /* Copy the string in from user memory to kernel memory */
  err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE));

  /* Now we need to null terminate */
  *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0;
  /* Record the length */
  echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE);

  if (err != 0) {
    uprintf("Write failed: bad address!\n");
  }

  count++;
  return(err);
}

DEV_MODULE(echo,echo_loader,NULL);

Example 10-2. Пример драйвера псевдо-устройства Echo для FreeBSD 5.X

/*
 * Simple `echo' pseudo-device KLD
 *
 * Murray Stokely
 *
 * Converted to 5.X by Sren (Xride) Straarup
 */

#include <sys/types.h>
#include <sys/module.h>
#include <sys/systm.h>  /* uprintf */
#include <sys/errno.h>
#include <sys/param.h>  /* defines used in kernel.h */
#include <sys/kernel.h> /* types used in module initialization */
#include <sys/conf.h>   /* cdevsw struct */
#include <sys/uio.h>    /* uio struct */
#include <sys/malloc.h>

#define BUFFERSIZE 256
#define CDEV_MAJOR      33


/* Function prototypes */
static d_open_t      echo_open;
static d_close_t     echo_close;
static d_read_t      echo_read;
static d_write_t     echo_write;

/* Character device entry points */
static struct cdevsw echo_cdevsw = {
       .d_open = echo_open,
       .d_close = echo_close,
       .d_maj = CDEV_MAJOR,
       .d_name = "echo",
       .d_read = echo_read,
       .d_write = echo_write
};

typedef struct s_echo {
       char msg[BUFFERSIZE];
       int len;
} t_echo;

/* vars */
static dev_t echo_dev;
static int count;
static t_echo *echomsg;

MALLOC_DECLARE(M_ECHOBUF);
MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module");

/*
 * This function is called by the kld[un]load(2) system calls to
 * determine what actions to take when a module is loaded or unloaded.
 */

static int
echo_loader(struct module *m, int what, void *arg)
{
       int err = 0;

       switch (what) {
       case MOD_LOAD:                /* kldload */
               echo_dev = make_dev(&echo_cdevsw,
                   0,
                   UID_ROOT,
                   GID_WHEEL,
                   0600,
                   "echo");
               /* kmalloc memory for use by this driver */
               MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK);
               printf("Echo device loaded.\n");
               break;
       case MOD_UNLOAD:
               destroy_dev(echo_dev);
               FREE(echomsg,M_ECHOBUF);
               printf("Echo device unloaded.\n");
               break;
       default:
               err = EINVAL;
               break;
       }
       return(err);
}

static int
echo_open(dev_t dev, int oflags, int devtype, struct thread *p)
{
       int err = 0;

       uprintf("Opened device \"echo\" successfully.\n");
       return(err);
}

static int
echo_close(dev_t dev, int fflag, int devtype, struct thread *p)
{
       uprintf("Closing device \"echo.\"\n");
       return(0);
}

/*
 * The read function just takes the buf that was saved via
 * echo_write() and returns it to userland for accessing.
 * uio(9)
 */

static int
echo_read(dev_t dev, struct uio *uio, int ioflag)
{
    int err = 0;
    int amt;

    /*
         * How big is this read operation?  Either as big as the user wants,
         * or as big as the remaining data
         */
    amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ?
           echomsg->len - uio->uio_offset : 0);
        if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) {
        uprintf("uiomove failed!\n");
    }
    return(err);
}

/*
 * echo_write takes in a character string and saves it
 * to buf for later accessing.
 */

static int
echo_write(dev_t dev, struct uio *uio, int ioflag)
{
       int err = 0;

       /* Copy the string in from user memory to kernel memory */
       err = copyin(uio->uio_iov->iov_base, echomsg->msg,
           MIN(uio->uio_iov->iov_len,BUFFERSIZE - 1));

       /* Now we need to null terminate, then record the length */
       *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE - 1)) = 0;
       echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE);

       if (err != 0) {
        uprintf("Write failed: bad address!\n");
       }
       count++;
       return(err);
}

DEV_MODULE(echo,echo_loader,NULL);

Для установки этого драйвера во FreeBSD 4.X сначала вам нужно создать файл устройства в вашей файловой системе по команде типа следующей:

# mknod /dev/echo c 33 0

Когда этот драйвер загружен, вы можете выполнять следующие действия:

# echo -n "Test Data" > /dev/echo
# cat /dev/echo
Test Data

Устройства, обслуживающие реальное оборудование, описываются в следующей главе.

Дополнительные источники информации



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

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




Спонсоры:
Слёрм
Inferno Solutions
Hosting by Ihor
Хостинг:

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