DF-5447 / uvscom_preparam_harness.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 | /* * DF-5447 KLD harness -- PRODUCTION-CODE demonstration that * uvscom_pre_param() rejects every baud rate, including all eleven * supported ones (uvscom.c:514-533). * * Method: this module #includes the unmodified production * sys/bus/u4b/serial/uvscom.c into its own translation unit (with the * newbus DRIVER_MODULE / MODULE_DEPEND / MODULE_VERSION registration * macros expanded to nothing so the harness does not register a second * "uvscom" driver on uhub), then calls the real, static * uvscom_pre_param() for every speed the hardware supports. * * Production contract (usb_serial.c:1678-1684): * * if (sc->sc_callback->ucom_pre_param) { * error = (sc->sc_callback->ucom_pre_param) (sc, t); * if (error) { * goto done; <-- termios change REJECTED * } * } * * so any non-zero return kills the tcsetattr (and silently kills the * open-time programming at usb_serial.c:842, whose error is discarded). * * Expected baseline (phase A): all 11 supported speeds -> EINVAL (35), * i.e. "SUPPORTED speeds accepted: 0/11". * Expected after fix.diff (phase B, rerun of the same harness against the * patched /usr/src copy): 11/11 accepted, B230400 -> EINVAL. */ #include <sys/param.h> #include <sys/types.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/bus.h> #include <sys/lock.h> /* NOTE: no u4b/usb* headers here on purpose: uvscom.c must include them * itself (its own include order -- USB_DEBUG_VAR before usb_debug.h -- * is required for DPRINTF/DPRINTFN to be defined). */ MODULE_DEPEND(hx5447, usb, 1, 1, 1); MODULE_DEPEND(hx5447, ucom, 1, 1, 1); /* * Neuter the newbus/module registration the production file would * otherwise perform. DRIVER_MODULE lives in <sys/bus.h> (already * included above), MODULE_DEPEND/MODULE_VERSION in <sys/module.h>. */ #undef DRIVER_MODULE #undef DRIVER_MODULE_ORDERED #undef MODULE_DEPEND #undef MODULE_VERSION #define DRIVER_MODULE(name, busname, driver, devclass, evh, arg) #define DRIVER_MODULE_ORDERED(name, busname, driver, devclass, evh, arg, order) #define MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) #define MODULE_VERSION(module, version) /* THE PRODUCTION DRIVER, textually unmodified. */ #include "../uvscom.c" /* * Keep -Werror happy: uvscom_devclass and uvscom_driver are normally * referenced by DRIVER_MODULE, which we expanded away. */ static void hx5447_touch_statics(void) { if (uvscom_devclass != NULL) kprintf("UVS5447: unexpected devclass %p\n", uvscom_devclass); kprintf("UVS5447: production driver \"%s\" compiled into harness " "(registration neutered)\n", uvscom_driver.name); } static const speed_t hx_speeds[] = { B150, B300, B600, B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, }; static int hx5447_run(char phase) { struct ucom_softc ucom_stub; struct termios t; int accepted = 0; size_t i; int e; memset(&ucom_stub, 0, sizeof(ucom_stub)); memset(&t, 0, sizeof(t)); kprintf("UVS5447[%c]: calling production uvscom_pre_param() " "(uvscom.c:514-533) for all 11 supported speeds\n", phase); for (i = 0; i < sizeof(hx_speeds) / sizeof(hx_speeds[0]); i++) { t.c_ospeed = hx_speeds[i]; e = uvscom_pre_param(&ucom_stub, &t); kprintf("UVS5447[%c]: pre_param(B%d) = %d (%s)\n", phase, (int)hx_speeds[i], e, e == 0 ? "ACCEPTED" : e == EINVAL ? "EINVAL -- REJECTED" : "unexpected"); if (e == 0) accepted++; } /* B230400 is NOT supported by the hardware (no case label). */ t.c_ospeed = B230400; e = uvscom_pre_param(&ucom_stub, &t); kprintf("UVS5447[%c]: pre_param(B230400) = %d (%s, expected EINVAL)\n", phase, e, e == EINVAL ? "ok" : "WRONG"); kprintf("UVS5447[%c]: SUPPORTED speeds accepted: %d/11 %s\n", phase, accepted, accepted == 11 ? "(fixed)" : accepted == 0 ? "(BUG: every tcsetattr fails EINVAL, " "uvscom_cfg_param() is unreachable, uvscom.c:532 return(0) dead)" : "(partial?)"); return (accepted == 11 ? 0 : 1); } static int hx5447_modevent(module_t mod, int type, void *data) { int error = 0; switch (type) { case MOD_LOAD: hx5447_touch_statics(); kprintf("UVS5447: DF-5447 production-code harness: " "uvscom_pre_param inverted switch\n"); hx5447_run('A'); kprintf("UVS5447: harness complete\n"); break; case MOD_UNLOAD: break; default: error = EOPNOTSUPP; break; } return (error); } static moduledata_t hx_mod = { "uvscompreparam", hx5447_modevent, 0 }; DECLARE_MODULE(uvscompreparam, hx_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); |