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