本章将讨论FreeBSD为了给PCI总线上的设备编写驱动程序而提供的机制。
这儿的信息是关于PCI总线代码如何迭代通过未连接的设备,并查看新 加载的kld是否会连接其中一个。
/*
* 与PCI函数进行交互的简单KLD
*
* Murray Stokely
*/
#include <sys/param.h> /* kernel.h中使用的定义 */
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h> /* 模块初始化中使用的类型 */
#include <sys/conf.h> /* cdevsw结构 */
#include <sys/uio.h> /* uio结构 */
#include <sys/malloc.h>
#include <sys/bus.h> /* pci总线用到的结构、原型 */
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/pci/pcivar.h> /* 为了使用get_pci宏! */
#include <dev/pci/pcireg.h>
/* softc保存我们每个实例的数据。 */
struct mypci_softc {
device_t my_dev;
struct cdev *my_cdev;
};
/* 函数原型 */
static d_open_t mypci_open;
static d_close_t mypci_close;
static d_read_t mypci_read;
static d_write_t mypci_write;
/* 字符设备入口点 */
static struct cdevsw mypci_cdevsw = {
.d_version = D_VERSION,
.d_open = mypci_open,
.d_close = mypci_close,
.d_read = mypci_read,
.d_write = mypci_write,
.d_name = "mypci",
};
/*
* 在cdevsw例程中,我们通过结构体cdev中的成员si_drv1找出我们的softc。
* 当我们建立/dev项时,在我们的已附着的例程中,
* 我们设置这个变量指向我们的softc。
*/
int
mypci_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
struct mypci_softc *sc;
/* Look up our softc. */
sc = dev->si_drv1;
device_printf(sc->my_dev, "Opened successfully.\n");
return (0);
}
int
mypci_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
{
struct mypci_softc *sc;
/* Look up our softc. */
sc = dev->si_drv1;
device_printf(sc->my_dev, "Closed.\n");
return (0);
}
int
mypci_read(struct cdev *dev, struct uio *uio, int ioflag)
{
struct mypci_softc *sc;
/* Look up our softc. */
sc = dev->si_drv1;
device_printf(sc->my_dev, "Asked to read %d bytes.\n", uio->uio_resid);
return (0);
}
int
mypci_write(struct cdev *dev, struct uio *uio, int ioflag)
{
struct mypci_softc *sc;
/* Look up our softc. */
sc = dev->si_drv1;
device_printf(sc->my_dev, "Asked to write %d bytes.\n", uio->uio_resid);
return (0);
}
/* PCI支持函数 */
/*
* 将某个设置的标识与这个驱动程序支持的标识相比较。
* 如果相符,设置描述字符并返回成功。
*/
static int
mypci_probe(device_t dev)
{
device_printf(dev, "MyPCI Probe\nVendor ID : 0x%x\nDevice ID : 0x%x\n",
pci_get_vendor(dev), pci_get_device(dev));
if (pci_get_vendor(dev) == 0x11c1) {
printf("We've got the Winmodem, probe successful!\n");
device_set_desc(dev, "WinModem");
return (BUS_PROBE_DEFAULT);
}
return (ENXIO);
}
/* 只有当探测成功时才调用连接函数 */
static int
mypci_attach(device_t dev)
{
struct mypci_softc *sc;
printf("MyPCI Attach for : deviceID : 0x%x\n", pci_get_devid(dev));
/* Look up our softc and initialize its fields. */
sc = device_get_softc(dev);
sc->my_dev = dev;
/*
* Create a /dev entry for this device. The kernel will assign us
* a major number automatically. We use the unit number of this
* device as the minor number and name the character device
* "mypci<unit>".
*/
sc->my_cdev = make_dev(&
mypci_cdevsw, device_get_unit(dev),
UID_ROOT, GID_WHEEL, 0600, "mypci%u", device_get_unit(dev));
sc->my_cdev->si_drv1 = sc;
printf("Mypci device loaded.\n");
return (0);
}
/* 分离设备。 */
static int
mypci_detach(device_t dev)
{
struct mypci_softc *sc;
/* Teardown the state in our softc created in our attach routine. */
sc = device_get_softc(dev);
destroy_dev(sc->my_cdev);
printf("Mypci detach!\n");
return (0);
}
/* 系统关闭期间在sync之后调用。 */
static int
mypci_shutdown(device_t dev)
{
printf("Mypci shutdown!\n");
return (0);
}
/*
* 设备挂起例程。
*/
static int
mypci_suspend(device_t dev)
{
printf("Mypci suspend!\n");
return (0);
}
/*
* 设备恢复(重新开始)例程。
*/
static int
mypci_resume(device_t dev)
{
printf("Mypci resume!\n");
return (0);
}
static device_method_t mypci_methods[] = {
/* 设备接口 */
DEVMETHOD(device_probe, mypci_probe),
DEVMETHOD(device_attach, mypci_attach),
DEVMETHOD(device_detach, mypci_detach),
DEVMETHOD(device_shutdown, mypci_shutdown),
DEVMETHOD(device_suspend, mypci_suspend),
DEVMETHOD(device_resume, mypci_resume),
{ 0, 0 }
};
static devclass_t mypci_devclass;
DEFINE_CLASS_0(mypci, mypci_driver, mypci_methods, sizeof(struct mypci_softc));
DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0);
# 驱动程序mypci的Makefile KMOD= mypci SRCS= mypci.c SRCS+= device_if.h bus_if.h pci_if.h .include <bsd.kmod.mk>
如果你将上面的源文件和
Makefile
放入一个目录,你可以运行
make
编译示例驱动程序。
还有,你可以运行make load
将驱动程序装载到当前正在运行的内核中,而make
unload
可在装载后卸载驱动程序。
本文档和其它文档可从这里下载: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
如果对于FreeBSD有问题,请先阅读
文档,如不能解决再联系
<questions@FreeBSD.org>.
关于本文档的问题请发信联系
<doc@FreeBSD.org>.