DF-4940 / lpbbfake.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | /* * lpbbfake.c -- test harness: virtual I2C bit-bang bridge for if_ic PoCs. * * Registers a driver named "lpbb" on the ISA bus (identify-driven, no real * hardware) and provides the iicbb_if bit-bang methods against virtual * lines: SDA always reads 0 (ACK), SCL always reads 1 (no clock stretch). * * This provides an iicbus instance on any system (incl. QEMU guests with * no I2C controller), so that if_ic (the I2C IP network driver) can attach * and its ioctl/output paths be exercised. * * DF-4939 / DF-4940 evidence harness. Not part of sys/. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/module.h> #include <sys/bus.h> #include <bus/iicbus/iiconf.h> #include <bus/iicbus/iicbus.h> #include "iicbb_if.h" static void lpbbfake_identify(driver_t *, device_t); static int lpbbfake_probe(device_t); static int lpbbfake_attach(device_t); static int lpbbfake_detach(device_t); static int lpbbfake_callback(device_t, int, caddr_t); static void lpbbfake_setsda(device_t, int val); static void lpbbfake_setscl(device_t, int val); static int lpbbfake_getsda(device_t); static int lpbbfake_getscl(device_t); static int lpbbfake_reset(device_t, u_char speed, u_char addr, u_char *oldaddr); struct lpbbfake_softc { device_t child; /* our iicbb child */ }; static device_method_t lpbbfake_methods[] = { /* device interface */ DEVMETHOD(device_identify, lpbbfake_identify), DEVMETHOD(device_probe, lpbbfake_probe), DEVMETHOD(device_attach, lpbbfake_attach), DEVMETHOD(device_detach, lpbbfake_detach), /* iicbb interface (we are the bit-bang backend) */ DEVMETHOD(iicbb_callback, lpbbfake_callback), DEVMETHOD(iicbb_setsda, lpbbfake_setsda), DEVMETHOD(iicbb_setscl, lpbbfake_setscl), DEVMETHOD(iicbb_getsda, lpbbfake_getsda), DEVMETHOD(iicbb_getscl, lpbbfake_getscl), DEVMETHOD(iicbb_reset, lpbbfake_reset), DEVMETHOD_END }; static driver_t lpbb_driver = { "lpbb", lpbbfake_methods, sizeof(struct lpbbfake_softc), }; static devclass_t lpbb_devclass; DRIVER_MODULE(lpbbfake, isa, lpbb_driver, lpbb_devclass, NULL, NULL); MODULE_VERSION(lpbbfake, 1); static void lpbbfake_identify(driver_t *driver, device_t parent) { /* one instance, no resources */ if (device_find_child(parent, "lpbb", 0) == NULL) BUS_ADD_CHILD(parent, parent, 0, "lpbb", 0); } static int lpbbfake_probe(device_t dev) { device_set_desc(dev, "virtual I2C bit-bang bridge (lpbbfake)"); return (BUS_PROBE_DEFAULT); } static int lpbbfake_attach(device_t dev) { struct lpbbfake_softc *sc = device_get_softc(dev); sc->child = device_add_child(dev, "iicbb", -1); if (sc->child == NULL) return (ENXIO); return (bus_generic_attach(dev)); } static int lpbbfake_detach(device_t dev) { struct lpbbfake_softc *sc = device_get_softc(dev); device_t child = sc->child; bus_generic_detach(dev); if (child != NULL) device_delete_child(dev, child); sc->child = NULL; return (0); } static int lpbbfake_callback(device_t dev, int index, caddr_t data) { return (0); } static void lpbbfake_setsda(device_t dev, int val) { } static void lpbbfake_setscl(device_t dev, int val) { } static int lpbbfake_getsda(device_t dev) { return (0); /* slave always ACKs */ } static int lpbbfake_getscl(device_t dev) { return (1); /* no clock stretching */ } static int lpbbfake_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) { if (oldaddr != NULL) *oldaddr = 0x55; return (0); } |