1 /* $NetBSD: lpt_mvme.c,v 1.4 2003/07/14 15:47:19 lukem 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/cdefs.h> 94 __KERNEL_RCSID(0, "$NetBSD: lpt_mvme.c,v 1.4 2003/07/14 15:47:19 lukem Exp $"); 95 96 #include <sys/param.h> 97 #include <sys/systm.h> 98 #include <sys/proc.h> 99 #include <sys/user.h> 100 #include <sys/buf.h> 101 #include <sys/kernel.h> 102 #include <sys/ioctl.h> 103 #include <sys/uio.h> 104 #include <sys/device.h> 105 #include <sys/conf.h> 106 #include <sys/syslog.h> 107 108 #include <machine/cpu.h> 109 #include <machine/bus.h> 110 111 #include <dev/mvme/lptvar.h> 112 113 114 #define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */ 115 #define STEP hz/4 116 117 #define LPTPRI (PZERO+8) 118 #define LPT_BSIZE 1024 119 120 #if !defined(DEBUG) || !defined(notdef) 121 #define LPRINTF(a) 122 #else 123 #define LPRINTF if (lptdebug) printf a 124 int lptdebug = 1; 125 #endif 126 127 #define LPTUNIT(s) (minor(s) & 0x0f) 128 #define LPTFLAGS(s) (minor(s) & 0xf0) 129 130 static void lpt_wakeup __P((void *arg)); 131 static int pushbytes __P((struct lpt_softc *)); 132 133 extern struct cfdriver lpt_cd; 134 135 dev_type_open(lptopen); 136 dev_type_close(lptclose); 137 dev_type_write(lptwrite); 138 dev_type_ioctl(lptioctl); 139 140 const struct cdevsw lpt_cdevsw = { 141 lptopen, lptclose, noread, lptwrite, lptioctl, 142 nostop, notty, nopoll, nommap, nokqfilter, 143 }; 144 145 void 146 lpt_attach_subr(sc) 147 struct lpt_softc *sc; 148 { 149 150 sc->sc_state = 0; 151 callout_init(&sc->sc_wakeup_ch); 152 } 153 154 /* 155 * Reset the printer, then wait until it's selected and not busy. 156 */ 157 int 158 lptopen(dev, flag, mode, p) 159 dev_t dev; 160 int flag; 161 int mode; 162 struct proc *p; 163 { 164 int unit; 165 u_char flags; 166 struct lpt_softc *sc; 167 int error; 168 int spin; 169 170 unit = LPTUNIT(dev); 171 flags = LPTFLAGS(dev); 172 173 if (unit >= lpt_cd.cd_ndevs) 174 return (ENXIO); 175 sc = lpt_cd.cd_devs[unit]; 176 if (!sc) 177 return (ENXIO); 178 179 #ifdef DIAGNOSTIC 180 if (sc->sc_state) 181 printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname, 182 sc->sc_state); 183 #endif 184 185 if (sc->sc_state) 186 return (EBUSY); 187 188 sc->sc_state = LPT_INIT; 189 sc->sc_flags = flags; 190 LPRINTF(("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags)); 191 192 if ((flags & LPT_NOPRIME) == 0) { 193 /* assert Input Prime for 100 usec to start up printer */ 194 (sc->sc_funcs->lf_iprime) (sc); 195 } 196 197 /* select fast or slow strobe depending on minor device number */ 198 if (flags & LPT_FAST_STROBE) 199 (sc->sc_funcs->lf_speed) (sc, LPT_STROBE_FAST); 200 else 201 (sc->sc_funcs->lf_speed) (sc, LPT_STROBE_SLOW); 202 203 /* wait till ready (printer running diagnostics) */ 204 for (spin = 0; (sc->sc_funcs->lf_notrdy) (sc, 1); spin += STEP) { 205 if (spin >= TIMEOUT) { 206 sc->sc_state = 0; 207 return (EBUSY); 208 } 209 /* wait 1/4 second, give up if we get a signal */ 210 error = tsleep((caddr_t) sc, LPTPRI | PCATCH, "lptopen", STEP); 211 if (error != EWOULDBLOCK) { 212 sc->sc_state = 0; 213 return (error); 214 } 215 } 216 217 sc->sc_inbuf = geteblk(LPT_BSIZE); 218 sc->sc_count = 0; 219 sc->sc_state = LPT_OPEN; 220 221 if ((sc->sc_flags & LPT_NOINTR) == 0) 222 lpt_wakeup(sc); 223 224 (sc->sc_funcs->lf_open) (sc, sc->sc_flags & LPT_NOINTR); 225 226 LPRINTF(("%s: opened\n", sc->sc_dev.dv_xname)); 227 return (0); 228 } 229 230 void 231 lpt_wakeup(arg) 232 void *arg; 233 { 234 struct lpt_softc *sc; 235 int s; 236 237 sc = arg; 238 239 s = spltty(); 240 lpt_intr(sc); 241 splx(s); 242 243 callout_reset(&sc->sc_wakeup_ch, STEP, lpt_wakeup, sc); 244 } 245 246 /* 247 * Close the device, and free the local line buffer. 248 */ 249 int 250 lptclose(dev, flag, mode, p) 251 dev_t dev; 252 int flag; 253 int mode; 254 struct proc *p; 255 { 256 struct lpt_softc *sc; 257 int unit; 258 259 unit = LPTUNIT(dev); 260 sc = lpt_cd.cd_devs[unit]; 261 262 if (sc->sc_count) 263 (void) pushbytes(sc); 264 265 if ((sc->sc_flags & LPT_NOINTR) == 0) 266 callout_stop(&sc->sc_wakeup_ch); 267 268 (sc->sc_funcs->lf_close) (sc); 269 270 sc->sc_state = 0; 271 brelse(sc->sc_inbuf); 272 273 LPRINTF(("%s: closed\n", sc->sc_dev.dv_xname)); 274 return (0); 275 } 276 277 int 278 pushbytes(sc) 279 struct lpt_softc *sc; 280 { 281 int s, error, spin, tic; 282 283 if (sc->sc_flags & LPT_NOINTR) { 284 while (sc->sc_count > 0) { 285 spin = 0; 286 while ((sc->sc_funcs->lf_notrdy) (sc, 0)) { 287 if (++spin < sc->sc_spinmax) 288 continue; 289 tic = 0; 290 /* adapt busy-wait algorithm */ 291 sc->sc_spinmax++; 292 while ((sc->sc_funcs->lf_notrdy) (sc, 1)) { 293 /* exponential backoff */ 294 tic = tic + tic + 1; 295 if (tic > TIMEOUT) 296 tic = TIMEOUT; 297 error = tsleep((caddr_t) sc, 298 LPTPRI | PCATCH, "lptpsh", tic); 299 if (error != EWOULDBLOCK) 300 return (error); 301 } 302 break; 303 } 304 305 (sc->sc_funcs->lf_wrdata) (sc, *sc->sc_cp++); 306 sc->sc_count--; 307 308 /* adapt busy-wait algorithm */ 309 if (spin * 2 + 16 < sc->sc_spinmax) 310 sc->sc_spinmax--; 311 } 312 } else { 313 while (sc->sc_count > 0) { 314 /* if the printer is ready for a char, give it one */ 315 if ((sc->sc_state & LPT_OBUSY) == 0) { 316 LPRINTF(("%s: write %d\n", sc->sc_dev.dv_xname, 317 sc->sc_count)); 318 s = spltty(); 319 (void) lpt_intr(sc); 320 splx(s); 321 } 322 error = tsleep((caddr_t) sc, LPTPRI | PCATCH, 323 "lptwrite2", 0); 324 if (error) 325 return (error); 326 } 327 } 328 return (0); 329 } 330 331 /* 332 * Copy a line from user space to a local buffer, then call putc to get the 333 * chars moved to the output queue. 334 */ 335 int 336 lptwrite(dev, uio, flags) 337 dev_t dev; 338 struct uio *uio; 339 int flags; 340 { 341 struct lpt_softc *sc; 342 size_t n; 343 int error; 344 345 sc = lpt_cd.cd_devs[LPTUNIT(dev)]; 346 error = 0; 347 348 while ((n = min(LPT_BSIZE, uio->uio_resid)) != 0) { 349 uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio); 350 sc->sc_count = n; 351 error = pushbytes(sc); 352 if (error) { 353 /* 354 * Return accurate residual if interrupted or timed 355 * out. 356 */ 357 uio->uio_resid += sc->sc_count; 358 sc->sc_count = 0; 359 return (error); 360 } 361 } 362 return (0); 363 } 364 365 /* 366 * Handle printer interrupts which occur when the printer is ready to accept 367 * another char. 368 */ 369 int 370 lpt_intr(sc) 371 struct lpt_softc *sc; 372 { 373 374 if (sc->sc_count) { 375 /* send char */ 376 (sc->sc_funcs->lf_wrdata) (sc, *sc->sc_cp++); 377 sc->sc_count--; 378 sc->sc_state |= LPT_OBUSY; 379 } else 380 sc->sc_state &= ~LPT_OBUSY; 381 382 if (sc->sc_count == 0) { 383 /* none, wake up the top half to get more */ 384 wakeup((caddr_t) sc); 385 } 386 387 return (1); 388 } 389 390 /* ARGSUSED */ 391 int 392 lptioctl(dev, cmd, data, flag, p) 393 dev_t dev; 394 u_long cmd; 395 caddr_t data; 396 int flag; 397 struct proc *p; 398 { 399 400 return (ENODEV); 401 } 402