第 11 章 PCI设备
上一页 | 部分 II. 设备驱动程序 | 下一页

## 第 11 章 PCI设备

翻译：spellar @SMTH.

本章将讨论FreeBSD为了给PCI总线上的设备编写驱动程序而提供的机制。

## 11.1. 探测与连接

这儿的信息是关于PCI总线代码如何迭代通过未连接的设备，并查看新 加载的kld是否会连接其中一个。

### 11.1.1. 示例驱动程序源代码(`mypci.c`)

/* * 与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, d_thread_t *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, d_thread_t *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);

### 11.1.2. 示例驱动程序的`Makefile`

# 驱动程序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`可在装载后卸载驱动程序。

### 11.1.3. 更多资源

- PCI Special Interest Group
- PCI System Architecture, Fourth Edition by Tom Shanley, et al.

上一页 | 上一级 | 下一页
10.12. xxx_intr | 起始页 | 11.2. 总线资源

本文档和其它文档可从这里下载： ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题，请先阅读 文档，如不能解决再联系 <questions@FreeBSD.org>.
关于本文档的问题请发信联系 <doc@FreeBSD.org>.