9.4 ×Ö·ûÉ豸

¡¡¡¡×Ö·ûÉ豸Çý¶¯³ÌÐòÖ±½Ó´ÓÓû§½ø³Ì´«ÊäÊý¾Ý£¬»ò´«ÊäÊý¾Ýµ½Óû§½ø³Ì¡£ ÕâÊÇ×îÆÕͨµÄÒ»ÀàÉ豸Çý¶¯³ÌÐò£¬Ô´ÂëÊ÷ÖÐÓдóÁ¿µÄ¼òµ¥Àý×Ó¡£

¡¡¡¡Õâ¸ö¼òµ¥µÄαÉ豸Àý×Ó»á¼ÇסÄãд¸øËüµÄÈκÎÖµ£¬²¢ÇÒµ±Äã¶ÁÈ¡ËüµÄʱºò »á½«ÕâЩֵ·µ»Ø¸øÄã¡£ÏÂÃæÏÔʾÁËÁ½¸ö°æ±¾£¬Ò»¸öÊÊÓÃÓÚFreeBSD 4.X£¬ Ò»¸öÊÊÓÃÓÚFreeBSD 5.X¡£

Àý 9-1. ÊÊÓÃÓÚFreeBSD 4.XµÄ»ØÏÔαÉ豸Çý¶¯³ÌÐòʵÀý

/*
 * ¼òµ¥¡®echo¡¯Î±É豸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>  /* kernel.hÖÐÓõ½µÄ¶¨Òå */
#include <sys/kernel.h> /* Ä£¿é³õʼ»¯ÖÐʹÓõÄÀàÐÍ */
#include <sys/conf.h>   /* cdevsw½á¹¹ */
#include <sys/uio.h>    /* uio½á¹¹ */
#include <sys/malloc.h>

#define BUFFERSIZE 256

/* º¯ÊýÔ­ÐÍ */
d_open_t        echo_open;
d_close_t       echo_close;
d_read_t        echo_read;
d_write_t       echo_write;

/* ×Ö·ûÉ豸Èë¿Úµã */
static struct cdevsw echo_cdevsw = {
        echo_open,
        echo_close,
        echo_read,
        echo_write,
        noioctl,
        nopoll,
        nommap,
        nostrategy,
        "echo",
        33,              /* Ϊlkms±£Áô - /usr/src/sys/conf/majors */
        nodump,
        nopsize,
        D_TTY,
        -1
};

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

/* ±äÁ¿ */
static dev_t sdev;
static int count;
static t_echo *echomsg;

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

/*
 * Õâ¸öº¯Êý±»kld[un]load(2)ϵͳµ÷ÓÃÀ´µ÷Óã¬
 * ÒÔ¾ö¶¨¼ÓÔØºÍÐ¶ÔØÄ£¿éʱÐèÒª²ÉÈ¡µÄ¶¯×÷¡£
 */

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·ÖÅ乩Çý¶¯³ÌÐòʹÓõÄÄÚ´æ */
                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 = EOPNOTSUPP;
                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);
}

/*
 * readº¯Êý½ÓÊÜÓÉecho_write()´æ´¢µÄbuf£¬²¢½«Æä·µ»Øµ½Óû§¿Õ¼ä£¬
 * ÒÔ¹©ÆäËûº¯Êý·ÃÎÊ¡£
 * uio(9)
 */

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

        /*
         * Õâ¸ö¶Á²Ù×÷Óжà´ó£¿
         * ÓëÓû§ÇëÇóµÄ´óСһÑù£¬»òÕßµÈÓÚÊ£ÓàÊý¾ÝµÄ´óС¡£
         */
        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½ÓÊÜÒ»¸ö×Ö·û´®²¢½«Ëü±£´æµ½»º³åÇø£¬ÓÃÓÚÒÔºóµÄ·ÃÎÊ¡£
 */

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

        /* ½«×Ö·û´®´ÓÓû§¿Õ¼äµÄÄÚ´æ¸´ÖÆµ½Äں˿ռä */
        err = copyin(uio->uio_iov->iov_base, echomsg->msg,
            MIN(uio->uio_iov->iov_len, BUFFERSIZE - 1));

        /* ÏÖÔÚÐèÒªÒÔnull½áÊø×Ö·û´®£¬²¢¼Ç¼³¤¶È */
        *(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);

Àý 9-2. ÊÊÓÃÓÚFreeBSD 5.X»ØÏÔαÉ豸Çý¶¯³ÌÐòʵÀý

/*
 * ¼òµ¥¡®echo¡¯Î±É豸 KLD
 *
 * Murray Stokely
 *
 * ´Ë´úÂëÓÉSøren (Xride) Straarupת»»µ½5.X
 */

#include <sys/types.h>
#include <sys/module.h>
#include <sys/systm.h>  /* uprintf */
#include <sys/errno.h>
#include <sys/param.h>  /* kernel.hÖÐÓõ½µÄ¶¨Òå */
#include <sys/kernel.h> /* Ä£¿é³õʼ»¯ÖÐʹÓõÄÀàÐÍ */
#include <sys/conf.h>   /* cdevsw½á¹¹ */
#include <sys/uio.h>    /* uio½á¹¹ */
#include <sys/malloc.h>

#define BUFFERSIZE 256


/* º¯ÊýÔ­ÐÍ */
static d_open_t      echo_open;
static d_close_t     echo_close;
static d_read_t      echo_read;
static d_write_t     echo_write;

/* ×Ö·ûÉ豸Èë¿Úµã */
static struct cdevsw echo_cdevsw = {
        .d_version = D_VERSION,
        .d_open = echo_open,
        .d_close = echo_close,
        .d_read = echo_read,
        .d_write = echo_write,
        .d_name = "echo",
};

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

/* ±äÁ¿ */
static struct cdev *echo_dev;
static int count;
static t_echo *echomsg;

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

/*
 * Õâ¸öº¯Êý±»kld[un]load(2)ϵͳµ÷ÓÃÀ´µ÷ÓÃ, 
 * ÒÔ¾ö¶¨¼ÓÔØºÍÐ¶ÔØÄ£¿éʱÐèÒª²ÉÈ¡µÄ¶¯×÷. 
 */

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·ÖÅ乩Çý¶¯³ÌÐòʹÓõÄÄÚ´æ */
                echomsg = malloc(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 = EOPNOTSUPP;
                break;
        }
        return(err);
}

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

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

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

/*
 * readº¯Êý½ÓÊÜÓÉecho_write()´æ´¢µÄbuf£¬²¢½«Æä·µ»Øµ½Óû§¿Õ¼ä£¬
 * ÒÔ¹©ÆäËûº¯Êý·ÃÎÊ¡£
 * uio(9)
 */

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

        /*
         * Õâ¸ö¶Á²Ù×÷Óжà´ó£¿
         * µÈÓÚÓû§ÇëÇóµÄ´óС£¬»òÕßµÈÓÚÊ£ÓàÊý¾ÝµÄ´óС¡£
         */
        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½ÓÊÜÒ»¸ö×Ö·û´®²¢½«Ëü±£´æµ½»º³åÇø, ÓÃÓÚÒÔºóµÄ·ÃÎÊ. 
 */

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

        /* ½«×Ö·û´®´ÓÓû§¿Õ¼äµÄÄÚ´æ¸´ÖÆµ½Äں˿ռä */
        err = copyin(uio->uio_iov->iov_base, echomsg->msg,
            MIN(uio->uio_iov->iov_len, BUFFERSIZE - 1));

        /* ÏÖÔÚÐèÒªÒÔnull½áÊø×Ö·û´®£¬²¢¼Ç¼³¤¶È */
        *(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>.