字符设备驱动程序直接从用户进程传输数据,或传输数据到用户进程。 这是最普通的一类设备驱动程序,源码树中有大量的简单例子。
这个简单的伪设备例子会记住你写给它的任何值,并且当你读取它的时候 会将这些值返回给你。下面显示了两个版本,一个适用于FreeBSD 4.X, 一个适用于FreeBSD 5.X。
&
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);&
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>.