¡¡¡¡×Ö·ûÉ豸Çý¶¯³ÌÐòÖ±½Ó´ÓÓû§½ø³Ì´«ÊäÊý¾Ý£¬»ò´«ÊäÊý¾Ýµ½Óû§½ø³Ì¡£ ÕâÊÇ×îÆÕͨµÄÒ»ÀàÉ豸Çý¶¯³ÌÐò£¬Ô´ÂëÊ÷ÖÐÓдóÁ¿µÄ¼òµ¥Àý×Ó¡£
¡¡¡¡Õâ¸ö¼òµ¥µÄαÉ豸Àý×Ó»á¼ÇסÄãд¸øËüµÄÈκÎÖµ£¬²¢ÇÒµ±Äã¶ÁÈ¡ËüµÄʱºò »á½«ÕâЩֵ·µ»Ø¸øÄã¡£ÏÂÃæÏÔʾÁËÁ½¸ö°æ±¾£¬Ò»¸öÊÊÓÃÓÚ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
¡¡¡¡ÕæÕýµÄÓ²¼þÉ豸ÔÚÏÂÒ»ÕÂÃèÊö¡£
¡¡¡¡²¹³ä×ÊÔ´
Dynamic Kernel Linker (KLD) Facility Programming Tutorial - Daemonnews October 2000
How to Write Kernel Drivers with NEWBUS - Daemonnews July 2000
±¾ÎĵµºÍÆäËüÎĵµ¿É´ÓÕâÀïÏÂÔØ£ºftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
Èç¹û¶ÔÓÚFreeBSDÓÐÎÊÌ⣬ÇëÏÈÔĶÁÎĵµ£¬Èç²»Äܽâ¾öÔÙÁªÏµ<questions@FreeBSD.org>.
¹ØÓÚ±¾ÎĵµµÄÎÊÌâÇë·¢ÐÅÁªÏµ <doc@FreeBSD.org>.