FreeBSD的PCI驱动例子
1 /* 2 * Simple KLD to play with the PCI functions. 3 * 4 * Murray Stokely 5 */ 6 7 #include <sys/param.h> /* defines used in kernel.h */ 8 #include <sys/module.h> 9 #include <sys/systm.h> 10 #include <sys/errno.h> 11 #include <sys/kernel.h> /* types used in module initialization */ 12 #include <sys/conf.h> /* cdevsw struct */ 13 #include <sys/uio.h> /* uio struct */ 14 #include <sys/malloc.h> 15 #include <sys/bus.h> /* structs, prototypes for pci bus stuff and DEVMETHOD macros! */ 16 17 #include <machine/bus.h> 18 #include <sys/rman.h> 19 #include <machine/resource.h> 20 21 #include <dev/pci/pcivar.h> /* For pci_get macros! */ 22 #include <dev/pci/pcireg.h> 23 24 /* The softc holds our per-instance data. */ 25 struct mypci_softc { 26 device_t my_dev; 27 struct cdev *my_cdev; 28 }; 29 30 /* Function prototypes */ 31 static d_open_t mypci_open; 32 static d_close_t mypci_close; 33 static d_read_t mypci_read; 34 static d_write_t mypci_write; 35 36 /* Character device entry points */ 37 38 static struct cdevsw mypci_cdevsw = { 39 .d_version = D_VERSION, 40 .d_open = mypci_open, 41 .d_close = mypci_close, 42 .d_read = mypci_read, 43 .d_write = mypci_write, 44 .d_name = "mypci", 45 }; 46 47 /* 48 * In the cdevsw routines, we find our softc by using the si_drv1 member 49 * of struct cdev. We set this variable to point to our softc in our 50 * attach routine when we create the /dev entry. 51 */ 52 53 int 54 mypci_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 55 { 56 struct mypci_softc *sc; 57 58 /* Look up our softc. */ 59 sc = dev->si_drv1; 60 device_printf(sc->my_dev, "Opened successfully.\n"); 61 return (0); 62 } 63 64 int 65 mypci_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 66 { 67 struct mypci_softc *sc; 68 69 /* Look up our softc. */ 70 sc = dev->si_drv1; 71 device_printf(sc->my_dev, "Closed.\n"); 72 return (0); 73 } 74 75 int 76 mypci_read(struct cdev *dev, struct uio *uio, int ioflag) 77 { 78 struct mypci_softc *sc; 79 80 /* Look up our softc. */ 81 sc = dev->si_drv1; 82 device_printf(sc->my_dev, "Asked to read %zd bytes.\n", uio->uio_resid); 83 return (0); 84 } 85 86 int 87 mypci_write(struct cdev *dev, struct uio *uio, int ioflag) 88 { 89 struct mypci_softc *sc; 90 91 /* Look up our softc. */ 92 sc = dev->si_drv1; 93 device_printf(sc->my_dev, "Asked to write %zd bytes.\n", uio->uio_resid); 94 return (0); 95 } 96 97 /* PCI Support Functions */ 98 99 /* 100 * Compare the device ID of this device against the IDs that this driver 101 * supports. If there is a match, set the description and return success. 102 */ 103 static int 104 mypci_probe(device_t dev) 105 { 106 107 device_printf(dev, "MyPCI Probe\nVendor ID : 0x%x\nDevice ID : 0x%x\n", 108 pci_get_vendor(dev), pci_get_device(dev)); 109 110 if (pci_get_vendor(dev) == 0x11c1) { 111 printf("We've got the Winmodem, probe successful!\n"); 112 device_set_desc(dev, "WinModem"); 113 return (BUS_PROBE_DEFAULT); 114 } 115 return (ENXIO); 116 } 117 118 /* Attach function is only called if the probe is successful. */ 119 120 static int 121 mypci_attach(device_t dev) 122 { 123 struct mypci_softc *sc; 124 125 printf("MyPCI Attach for : deviceID : 0x%x\n", pci_get_devid(dev)); 126 127 /* Look up our softc and initialize its fields. */ 128 sc = device_get_softc(dev); 129 sc->my_dev = dev; 130 131 /* 132 * Create a /dev entry for this device. The kernel will assign us 133 * a major number automatically. We use the unit number of this 134 * device as the minor number and name the character device 135 * "mypci<unit>". 136 */ 137 sc->my_cdev = make_dev(&mypci_cdevsw, device_get_unit(dev), 138 UID_ROOT, GID_WHEEL, 0600, "mypci%u", device_get_unit(dev)); 139 sc->my_cdev->si_drv1 = sc; 140 printf("Mypci device loaded.\n"); 141 return (0); 142 } 143 144 /* Detach device. */ 145 146 static int 147 mypci_detach(device_t dev) 148 { 149 struct mypci_softc *sc; 150 151 /* Teardown the state in our softc created in our attach routine. */ 152 sc = device_get_softc(dev); 153 destroy_dev(sc->my_cdev); 154 printf("Mypci detach!\n"); 155 return (0); 156 } 157 158 /* Called during system shutdown after sync. */ 159 160 static int 161 mypci_shutdown(device_t dev) 162 { 163 164 printf("Mypci shutdown!\n"); 165 return (0); 166 } 167 168 /* 169 * Device suspend routine. 170 */ 171 static int 172 mypci_suspend(device_t dev) 173 { 174 175 printf("Mypci suspend!\n"); 176 return (0); 177 } 178 179 /* 180 * Device resume routine. 181 */ 182 static int 183 mypci_resume(device_t dev) 184 { 185 186 printf("Mypci resume!\n"); 187 return (0); 188 } 189 190 static device_method_t mypci_methods[] = { 191 /* Device interface */ 192 DEVMETHOD(device_probe, mypci_probe), 193 DEVMETHOD(device_attach, mypci_attach), 194 DEVMETHOD(device_detach, mypci_detach), 195 DEVMETHOD(device_shutdown, mypci_shutdown), 196 DEVMETHOD(device_suspend, mypci_suspend), 197 DEVMETHOD(device_resume, mypci_resume), 198 199 DEVMETHOD_END 200 }; 201 202 static devclass_t mypci_devclass; 203 204 DEFINE_CLASS_0(mypci, mypci_driver, mypci_methods, sizeof(struct mypci_softc)); 205 DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0);
# Makefile for mypci driver KMOD= mypci SRCS= mypci.c SRCS+= device_if.h bus_if.h pci_if.h .include <bsd.kmod.mk>
Chapter 11. PCI Devices (freebsd.org)上面代码链接地址
第 11 章 PCI设备 (freebsd.org)中文版链接地址
如果你将上面的源文件和 Makefile
放入一个目录,你可以运行 make
编译示例驱动程序。 还有,你可以运行make load
将驱动程序装载到当前正在运行的内核中,而make unload
可在装载后卸载驱动程序。
注:如果make报错(“make” command: unable to locate the kernel source tree)或者其他的,请给系统安装源码