1 1.19 riastrad /* $NetBSD: lpt_mvme.c,v 1.19 2018/09/03 16:29:32 riastradh Exp $ */ 2 1.1 scw 3 1.1 scw /*- 4 1.1 scw * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc. 5 1.1 scw * All rights reserved. 6 1.1 scw * 7 1.1 scw * This code is derived from software contributed to The NetBSD Foundation 8 1.1 scw * by Steve C. Woodford. 9 1.1 scw * 10 1.1 scw * Redistribution and use in source and binary forms, with or without 11 1.1 scw * modification, are permitted provided that the following conditions 12 1.1 scw * are met: 13 1.1 scw * 1. Redistributions of source code must retain the above copyright 14 1.1 scw * notice, this list of conditions and the following disclaimer. 15 1.1 scw * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 scw * notice, this list of conditions and the following disclaimer in the 17 1.1 scw * documentation and/or other materials provided with the distribution. 18 1.1 scw * 19 1.1 scw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 scw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 scw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 scw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 scw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 scw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 scw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 scw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 scw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 scw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 scw * POSSIBILITY OF SUCH DAMAGE. 30 1.1 scw */ 31 1.1 scw 32 1.1 scw /* 33 1.1 scw * Copyright (c) 1993, 1994 Charles M. Hannum. 34 1.1 scw * Copyright (c) 1990 William F. Jolitz, TeleMuse 35 1.1 scw * All rights reserved. 36 1.1 scw * 37 1.1 scw * Redistribution and use in source and binary forms, with or without 38 1.1 scw * modification, are permitted provided that the following conditions 39 1.1 scw * are met: 40 1.1 scw * 1. Redistributions of source code must retain the above copyright 41 1.1 scw * notice, this list of conditions and the following disclaimer. 42 1.1 scw * 2. Redistributions in binary form must reproduce the above copyright 43 1.1 scw * notice, this list of conditions and the following disclaimer in the 44 1.1 scw * documentation and/or other materials provided with the distribution. 45 1.1 scw * 3. All advertising materials mentioning features or use of this software 46 1.1 scw * must display the following acknowledgement: 47 1.6 perry * This software is a component of "386BSD" developed by 48 1.1 scw * William F. Jolitz, TeleMuse. 49 1.1 scw * 4. Neither the name of the developer nor the name "386BSD" 50 1.1 scw * may be used to endorse or promote products derived from this software 51 1.1 scw * without specific prior written permission. 52 1.1 scw * 53 1.6 perry * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 54 1.6 perry * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 55 1.6 perry * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 56 1.6 perry * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 57 1.1 scw * NOT MAKE USE OF THIS WORK. 58 1.1 scw * 59 1.1 scw * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED 60 1.6 perry * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN 61 1.6 perry * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES 62 1.6 perry * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING 63 1.6 perry * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND 64 1.6 perry * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE 65 1.6 perry * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS 66 1.1 scw * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. 67 1.1 scw * 68 1.1 scw * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND 69 1.1 scw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 70 1.1 scw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 71 1.1 scw * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE 72 1.1 scw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 73 1.1 scw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 74 1.1 scw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 75 1.1 scw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 76 1.1 scw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 77 1.1 scw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 78 1.1 scw * SUCH DAMAGE. 79 1.1 scw */ 80 1.1 scw 81 1.1 scw /* 82 1.1 scw * Device Driver for an MVME68K/MVME88K board's parallel printer port 83 1.1 scw * This driver attaches above the board-specific back-end. 84 1.1 scw */ 85 1.4 lukem 86 1.4 lukem #include <sys/cdefs.h> 87 1.19 riastrad __KERNEL_RCSID(0, "$NetBSD: lpt_mvme.c,v 1.19 2018/09/03 16:29:32 riastradh Exp $"); 88 1.1 scw 89 1.1 scw #include <sys/param.h> 90 1.1 scw #include <sys/systm.h> 91 1.1 scw #include <sys/proc.h> 92 1.1 scw #include <sys/buf.h> 93 1.1 scw #include <sys/kernel.h> 94 1.1 scw #include <sys/ioctl.h> 95 1.1 scw #include <sys/uio.h> 96 1.1 scw #include <sys/device.h> 97 1.1 scw #include <sys/conf.h> 98 1.1 scw #include <sys/syslog.h> 99 1.1 scw 100 1.11 ad #include <sys/cpu.h> 101 1.11 ad #include <sys/bus.h> 102 1.1 scw 103 1.1 scw #include <dev/mvme/lptvar.h> 104 1.1 scw 105 1.1 scw 106 1.1 scw #define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */ 107 1.1 scw #define STEP hz/4 108 1.1 scw 109 1.1 scw #define LPTPRI (PZERO+8) 110 1.1 scw #define LPT_BSIZE 1024 111 1.1 scw 112 1.1 scw #if !defined(DEBUG) || !defined(notdef) 113 1.1 scw #define LPRINTF(a) 114 1.1 scw #else 115 1.12 cube #define LPRINTF if (lptdebug) aprint_verbose_dev a 116 1.1 scw int lptdebug = 1; 117 1.1 scw #endif 118 1.1 scw 119 1.1 scw #define LPTUNIT(s) (minor(s) & 0x0f) 120 1.1 scw #define LPTFLAGS(s) (minor(s) & 0xf0) 121 1.1 scw 122 1.5 perry static void lpt_wakeup(void *arg); 123 1.5 perry static int pushbytes(struct lpt_softc *); 124 1.1 scw 125 1.1 scw extern struct cfdriver lpt_cd; 126 1.1 scw 127 1.2 gehenna dev_type_open(lptopen); 128 1.2 gehenna dev_type_close(lptclose); 129 1.2 gehenna dev_type_write(lptwrite); 130 1.2 gehenna dev_type_ioctl(lptioctl); 131 1.2 gehenna 132 1.2 gehenna const struct cdevsw lpt_cdevsw = { 133 1.17 dholland .d_open = lptopen, 134 1.17 dholland .d_close = lptclose, 135 1.17 dholland .d_read = noread, 136 1.17 dholland .d_write = lptwrite, 137 1.17 dholland .d_ioctl = lptioctl, 138 1.17 dholland .d_stop = nostop, 139 1.17 dholland .d_tty = notty, 140 1.17 dholland .d_poll = nopoll, 141 1.17 dholland .d_mmap = nommap, 142 1.17 dholland .d_kqfilter = nokqfilter, 143 1.18 dholland .d_discard = nodiscard, 144 1.17 dholland .d_flag = 0 145 1.2 gehenna }; 146 1.1 scw 147 1.1 scw void 148 1.15 dsl lpt_attach_subr(struct lpt_softc *sc) 149 1.1 scw { 150 1.1 scw 151 1.1 scw sc->sc_state = 0; 152 1.9 ad callout_init(&sc->sc_wakeup_ch, 0); 153 1.1 scw } 154 1.1 scw 155 1.1 scw /* 156 1.1 scw * Reset the printer, then wait until it's selected and not busy. 157 1.1 scw */ 158 1.1 scw int 159 1.14 cegger lptopen(dev_t dev, int flag, int mode, struct lwp *l) 160 1.1 scw { 161 1.1 scw u_char flags; 162 1.1 scw struct lpt_softc *sc; 163 1.1 scw int error; 164 1.1 scw int spin; 165 1.1 scw 166 1.1 scw flags = LPTFLAGS(dev); 167 1.1 scw 168 1.14 cegger sc = device_lookup_private(&lpt_cd, LPTUNIT(dev)); 169 1.1 scw if (!sc) 170 1.1 scw return (ENXIO); 171 1.1 scw 172 1.1 scw #ifdef DIAGNOSTIC 173 1.1 scw if (sc->sc_state) 174 1.12 cube aprint_verbose_dev(sc->sc_dev, "stat=0x%x not zero\n", 175 1.1 scw sc->sc_state); 176 1.1 scw #endif 177 1.1 scw 178 1.1 scw if (sc->sc_state) 179 1.1 scw return (EBUSY); 180 1.1 scw 181 1.1 scw sc->sc_state = LPT_INIT; 182 1.1 scw sc->sc_flags = flags; 183 1.12 cube LPRINTF((sc->sc_dev, "open: flags=0x%x\n", flags)); 184 1.1 scw 185 1.1 scw if ((flags & LPT_NOPRIME) == 0) { 186 1.1 scw /* assert Input Prime for 100 usec to start up printer */ 187 1.1 scw (sc->sc_funcs->lf_iprime) (sc); 188 1.1 scw } 189 1.1 scw 190 1.1 scw /* select fast or slow strobe depending on minor device number */ 191 1.1 scw if (flags & LPT_FAST_STROBE) 192 1.1 scw (sc->sc_funcs->lf_speed) (sc, LPT_STROBE_FAST); 193 1.1 scw else 194 1.1 scw (sc->sc_funcs->lf_speed) (sc, LPT_STROBE_SLOW); 195 1.1 scw 196 1.1 scw /* wait till ready (printer running diagnostics) */ 197 1.1 scw for (spin = 0; (sc->sc_funcs->lf_notrdy) (sc, 1); spin += STEP) { 198 1.1 scw if (spin >= TIMEOUT) { 199 1.1 scw sc->sc_state = 0; 200 1.1 scw return (EBUSY); 201 1.1 scw } 202 1.1 scw /* wait 1/4 second, give up if we get a signal */ 203 1.8 christos error = tsleep((void *) sc, LPTPRI | PCATCH, "lptopen", STEP); 204 1.1 scw if (error != EWOULDBLOCK) { 205 1.1 scw sc->sc_state = 0; 206 1.1 scw return (error); 207 1.1 scw } 208 1.1 scw } 209 1.1 scw 210 1.1 scw sc->sc_inbuf = geteblk(LPT_BSIZE); 211 1.1 scw sc->sc_count = 0; 212 1.1 scw sc->sc_state = LPT_OPEN; 213 1.1 scw 214 1.1 scw if ((sc->sc_flags & LPT_NOINTR) == 0) 215 1.1 scw lpt_wakeup(sc); 216 1.1 scw 217 1.1 scw (sc->sc_funcs->lf_open) (sc, sc->sc_flags & LPT_NOINTR); 218 1.1 scw 219 1.12 cube LPRINTF((sc->sc_dev, "opened\n")); 220 1.1 scw return (0); 221 1.1 scw } 222 1.1 scw 223 1.1 scw void 224 1.15 dsl lpt_wakeup(void *arg) 225 1.1 scw { 226 1.1 scw struct lpt_softc *sc; 227 1.1 scw int s; 228 1.1 scw 229 1.1 scw sc = arg; 230 1.1 scw 231 1.1 scw s = spltty(); 232 1.1 scw lpt_intr(sc); 233 1.1 scw splx(s); 234 1.1 scw 235 1.1 scw callout_reset(&sc->sc_wakeup_ch, STEP, lpt_wakeup, sc); 236 1.1 scw } 237 1.1 scw 238 1.1 scw /* 239 1.1 scw * Close the device, and free the local line buffer. 240 1.1 scw */ 241 1.1 scw int 242 1.14 cegger lptclose(dev_t dev, int flag, int mode, struct lwp *l) 243 1.1 scw { 244 1.1 scw struct lpt_softc *sc; 245 1.1 scw 246 1.14 cegger sc = device_lookup_private(&lpt_cd, LPTUNIT(dev)); 247 1.1 scw 248 1.1 scw if (sc->sc_count) 249 1.1 scw (void) pushbytes(sc); 250 1.1 scw 251 1.1 scw if ((sc->sc_flags & LPT_NOINTR) == 0) 252 1.1 scw callout_stop(&sc->sc_wakeup_ch); 253 1.1 scw 254 1.1 scw (sc->sc_funcs->lf_close) (sc); 255 1.1 scw 256 1.1 scw sc->sc_state = 0; 257 1.10 ad brelse(sc->sc_inbuf, 0); 258 1.1 scw 259 1.12 cube LPRINTF((sc->sc_dev, "%s: closed\n")); 260 1.1 scw return (0); 261 1.1 scw } 262 1.1 scw 263 1.1 scw int 264 1.15 dsl pushbytes(struct lpt_softc *sc) 265 1.1 scw { 266 1.1 scw int s, error, spin, tic; 267 1.1 scw 268 1.1 scw if (sc->sc_flags & LPT_NOINTR) { 269 1.1 scw while (sc->sc_count > 0) { 270 1.1 scw spin = 0; 271 1.1 scw while ((sc->sc_funcs->lf_notrdy) (sc, 0)) { 272 1.1 scw if (++spin < sc->sc_spinmax) 273 1.1 scw continue; 274 1.1 scw tic = 0; 275 1.1 scw /* adapt busy-wait algorithm */ 276 1.1 scw sc->sc_spinmax++; 277 1.1 scw while ((sc->sc_funcs->lf_notrdy) (sc, 1)) { 278 1.1 scw /* exponential backoff */ 279 1.1 scw tic = tic + tic + 1; 280 1.1 scw if (tic > TIMEOUT) 281 1.1 scw tic = TIMEOUT; 282 1.8 christos error = tsleep((void *) sc, 283 1.1 scw LPTPRI | PCATCH, "lptpsh", tic); 284 1.1 scw if (error != EWOULDBLOCK) 285 1.1 scw return (error); 286 1.1 scw } 287 1.1 scw break; 288 1.1 scw } 289 1.1 scw 290 1.1 scw (sc->sc_funcs->lf_wrdata) (sc, *sc->sc_cp++); 291 1.1 scw sc->sc_count--; 292 1.1 scw 293 1.1 scw /* adapt busy-wait algorithm */ 294 1.1 scw if (spin * 2 + 16 < sc->sc_spinmax) 295 1.1 scw sc->sc_spinmax--; 296 1.1 scw } 297 1.1 scw } else { 298 1.1 scw while (sc->sc_count > 0) { 299 1.1 scw /* if the printer is ready for a char, give it one */ 300 1.1 scw if ((sc->sc_state & LPT_OBUSY) == 0) { 301 1.12 cube LPRINTF((sc->sc_dev, "write %d\n", 302 1.1 scw sc->sc_count)); 303 1.1 scw s = spltty(); 304 1.1 scw (void) lpt_intr(sc); 305 1.1 scw splx(s); 306 1.1 scw } 307 1.8 christos error = tsleep((void *) sc, LPTPRI | PCATCH, 308 1.1 scw "lptwrite2", 0); 309 1.1 scw if (error) 310 1.1 scw return (error); 311 1.1 scw } 312 1.1 scw } 313 1.1 scw return (0); 314 1.1 scw } 315 1.1 scw 316 1.1 scw /* 317 1.1 scw * Copy a line from user space to a local buffer, then call putc to get the 318 1.1 scw * chars moved to the output queue. 319 1.1 scw */ 320 1.1 scw int 321 1.14 cegger lptwrite(dev_t dev, struct uio *uio, int flags) 322 1.1 scw { 323 1.1 scw struct lpt_softc *sc; 324 1.1 scw size_t n; 325 1.1 scw int error; 326 1.1 scw 327 1.14 cegger sc = device_lookup_private(&lpt_cd, LPTUNIT(dev)); 328 1.1 scw error = 0; 329 1.1 scw 330 1.19 riastrad while ((n = uimin(LPT_BSIZE, uio->uio_resid)) != 0) { 331 1.1 scw uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio); 332 1.1 scw sc->sc_count = n; 333 1.1 scw error = pushbytes(sc); 334 1.1 scw if (error) { 335 1.1 scw /* 336 1.1 scw * Return accurate residual if interrupted or timed 337 1.1 scw * out. 338 1.1 scw */ 339 1.1 scw uio->uio_resid += sc->sc_count; 340 1.1 scw sc->sc_count = 0; 341 1.1 scw return (error); 342 1.1 scw } 343 1.1 scw } 344 1.1 scw return (0); 345 1.1 scw } 346 1.1 scw 347 1.1 scw /* 348 1.1 scw * Handle printer interrupts which occur when the printer is ready to accept 349 1.1 scw * another char. 350 1.1 scw */ 351 1.1 scw int 352 1.15 dsl lpt_intr(struct lpt_softc *sc) 353 1.1 scw { 354 1.1 scw 355 1.1 scw if (sc->sc_count) { 356 1.1 scw /* send char */ 357 1.1 scw (sc->sc_funcs->lf_wrdata) (sc, *sc->sc_cp++); 358 1.1 scw sc->sc_count--; 359 1.1 scw sc->sc_state |= LPT_OBUSY; 360 1.1 scw } else 361 1.1 scw sc->sc_state &= ~LPT_OBUSY; 362 1.1 scw 363 1.1 scw if (sc->sc_count == 0) { 364 1.1 scw /* none, wake up the top half to get more */ 365 1.8 christos wakeup((void *) sc); 366 1.1 scw } 367 1.1 scw 368 1.1 scw return (1); 369 1.1 scw } 370 1.1 scw 371 1.1 scw /* ARGSUSED */ 372 1.1 scw int 373 1.15 dsl lptioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 374 1.1 scw { 375 1.1 scw 376 1.1 scw return (ENODEV); 377 1.1 scw } 378