lpt.c revision 1.11
1/* $NetBSD: lpt.c,v 1.11 1997/07/30 15:43:37 leo Exp $ */ 2 3/* 4 * Copyright (c) 1996 Leo Weppelman 5 * Copyright (c) 1993, 1994 Charles Hannum. 6 * Copyright (c) 1990 William F. Jolitz, TeleMuse 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This software is a component of "386BSD" developed by 20 * William F. Jolitz, TeleMuse. 21 * 4. Neither the name of the developer nor the name "386BSD" 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 26 * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 27 * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 28 * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 29 * NOT MAKE USE OF THIS WORK. 30 * 31 * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED 32 * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN 33 * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES 34 * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING 35 * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND 36 * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE 37 * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS 38 * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND 41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 43 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE 44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 50 * SUCH DAMAGE. 51 */ 52 53/* 54 * Device Driver originally written for AT parallel printer port. Now 55 * drives the printer port on the YM2149. 56 */ 57 58#include <sys/param.h> 59#include <sys/systm.h> 60#include <sys/proc.h> 61#include <sys/user.h> 62#include <sys/buf.h> 63#include <sys/kernel.h> 64#include <sys/ioctl.h> 65#include <sys/uio.h> 66#include <sys/device.h> 67#include <sys/conf.h> 68#include <sys/syslog.h> 69 70#include <machine/cpu.h> 71#include <machine/iomap.h> 72#include <machine/mfp.h> 73 74#include <atari/dev/ym2149reg.h> 75#include <atari/atari/intr.h> 76 77#define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */ 78#define STEP hz/4 79 80#define LPTPRI (PZERO+8) 81#define LPT_BSIZE 1024 82 83#if !defined(DEBUG) || !defined(notdef) 84#define lprintf if (0) printf 85#else 86#define lprintf if (lptdebug) printf 87int lptdebug = 1; 88#endif 89 90struct lpt_softc { 91 struct device sc_dev; 92 size_t sc_count; 93 struct buf *sc_inbuf; 94 u_char *sc_cp; 95 int sc_spinmax; 96 u_char sc_state; 97#define LPT_OPEN 0x01 /* device is open */ 98#define LPT_OBUSY 0x02 /* printer is busy doing output */ 99#define LPT_INIT 0x04 /* waiting to initialize for open */ 100 u_char sc_flags; 101#define LPT_AUTOLF 0x20 /* automatic LF on CR XXX: LWP - not yet... */ 102#define LPT_NOINTR 0x40 /* do not use interrupt */ 103}; 104 105#define LPTUNIT(s) (minor(s) & 0x1f) 106#define LPTFLAGS(s) (minor(s) & 0xe0) 107#define NOT_READY() (MFP->mf_gpip & IO_PBSY) 108 109/* {b,c}devsw[] function prototypes */ 110dev_type_open(lpopen); 111dev_type_close(lpclose); 112dev_type_write(lpwrite); 113dev_type_ioctl(lpioctl); 114 115static void lptwakeup __P((void *arg)); 116static int pushbytes __P((struct lpt_softc *)); 117static void lptpseudointr __P((struct lpt_softc *)); 118int lptintr __P((struct lpt_softc *)); 119int lpthwintr __P((struct lpt_softc *, int)); 120 121 122/* 123 * Autoconfig stuff 124 */ 125static void lpattach __P((struct device *, struct device *, void *)); 126static int lpmatch __P((struct device *, struct cfdata *, void *)); 127 128struct cfattach lp_ca = { 129 sizeof(struct lpt_softc), lpmatch, lpattach 130}; 131 132struct cfdriver lp_cd = { 133 NULL, "lpt", DV_DULL, NULL, 0 134}; 135 136/*ARGSUSED*/ 137static int 138lpmatch(pdp, cfp, auxp) 139struct device *pdp; 140struct cfdata *cfp; 141void *auxp; 142{ 143 if (!strcmp((char *)auxp, "lpt") && cfp->cf_unit == 0) 144 return (1); 145 return (0); 146} 147 148/*ARGSUSED*/ 149static void 150lpattach(pdp, dp, auxp) 151struct device *pdp, *dp; 152void *auxp; 153{ 154 struct lpt_softc *sc = (void *)dp; 155 156 sc->sc_state = 0; 157 158 if (intr_establish(0, USER_VEC, 0, (hw_ifun_t)lpthwintr, sc) == NULL) 159 printf("lptattach: Can't establish interrupt\n"); 160 ym2149_strobe(1); 161 162 printf("\n"); 163} 164 165/* 166 * Reset the printer, then wait until it's selected and not busy. 167 */ 168int 169lpopen(dev, flag, mode, p) 170 dev_t dev; 171 int flag, mode; 172 struct proc *p; 173{ 174 int unit = LPTUNIT(dev); 175 u_char flags = LPTFLAGS(dev); 176 struct lpt_softc *sc; 177 int error; 178 int spin; 179 int sps; 180 181 if (unit >= lp_cd.cd_ndevs) 182 return ENXIO; 183 sc = lp_cd.cd_devs[unit]; 184 if (!sc) 185 return ENXIO; 186 187#ifdef DIAGNOSTIC 188 if (sc->sc_state) 189 printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname, 190 sc->sc_state); 191#endif 192 193 if (sc->sc_state) 194 return EBUSY; 195 196 sc->sc_state = LPT_INIT; 197 sc->sc_flags = flags; 198 lprintf("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags); 199 200 /* wait till ready (printer running diagnostics) */ 201 for (spin = 0; NOT_READY(); spin += STEP) { 202 if (spin >= TIMEOUT) { 203 sc->sc_state = 0; 204 return EBUSY; 205 } 206 207 /* wait 1/4 second, give up if we get a signal */ 208 if ((error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptopen", 209 STEP)) != EWOULDBLOCK) { 210 sc->sc_state = 0; 211 return error; 212 } 213 } 214 215 sc->sc_inbuf = geteblk(LPT_BSIZE); 216 sc->sc_count = 0; 217 sc->sc_state = LPT_OPEN; 218 219 if ((sc->sc_flags & LPT_NOINTR) == 0) { 220 lptwakeup(sc); 221 222 sps = splhigh(); 223 MFP->mf_imrb |= IB_PBSY; 224 MFP->mf_ierb |= IB_PBSY; 225 splx(sps); 226 } 227 228 lprintf("%s: opened\n", sc->sc_dev.dv_xname); 229 return 0; 230} 231 232void 233lptwakeup(arg) 234 void *arg; 235{ 236 struct lpt_softc *sc = arg; 237 238 lptpseudointr(sc); 239 240 timeout(lptwakeup, sc, STEP); 241} 242 243/* 244 * Close the device, and free the local line buffer. 245 */ 246int 247lpclose(dev, flag, mode, p) 248 dev_t dev; 249 int flag; 250 int mode; 251 struct proc *p; 252{ 253 int unit = LPTUNIT(dev); 254 struct lpt_softc *sc = lp_cd.cd_devs[unit]; 255 int sps; 256 257 if (sc->sc_count) 258 (void) pushbytes(sc); 259 260 if ((sc->sc_flags & LPT_NOINTR) == 0) { 261 untimeout(lptwakeup, sc); 262 263 sps = splhigh(); 264 MFP->mf_ierb &= ~IB_PBSY; 265 MFP->mf_imrb &= ~IB_PBSY; 266 splx(sps); 267 } 268 269 sc->sc_state = 0; 270 brelse(sc->sc_inbuf); 271 272 lprintf("%s: closed\n", sc->sc_dev.dv_xname); 273 return 0; 274} 275 276int 277pushbytes(sc) 278 struct lpt_softc *sc; 279{ 280 int error; 281 282 if (sc->sc_flags & LPT_NOINTR) { 283 int spin, tic; 284 285 while (sc->sc_count > 0) { 286 spin = 0; 287 while (NOT_READY()) { 288 if (++spin < sc->sc_spinmax) 289 continue; 290 tic = 0; 291 /* adapt busy-wait algorithm */ 292 sc->sc_spinmax++; 293 while (NOT_READY()) { 294 /* exponential backoff */ 295 tic = tic + tic + 1; 296 if (tic > TIMEOUT) 297 tic = TIMEOUT; 298 error = tsleep((caddr_t)sc, 299 LPTPRI | PCATCH, "lptpsh", tic); 300 if (error != EWOULDBLOCK) 301 return error; 302 } 303 break; 304 } 305 306 ym2149_write_ioport(YM_IOB, *sc->sc_cp++); 307 ym2149_strobe(0); 308 sc->sc_count--; 309 ym2149_strobe(1); 310 311 /* adapt busy-wait algorithm */ 312 if (spin*2 + 16 < sc->sc_spinmax) 313 sc->sc_spinmax--; 314 } 315 } else { 316 while (sc->sc_count > 0) { 317 /* if the printer is ready for a char, give it one */ 318 if ((sc->sc_state & LPT_OBUSY) == 0) { 319 lprintf("%s: write %d\n", sc->sc_dev.dv_xname, 320 sc->sc_count); 321 (void) lptpseudointr(sc); 322 } 323 if ((error = tsleep((caddr_t)sc, LPTPRI | PCATCH, 324 "lptwrite2", 0)) != 0) 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 */ 335int 336lpwrite(dev, uio, flags) 337 dev_t dev; 338 struct uio *uio; 339 int flags; 340{ 341 struct lpt_softc *sc = lp_cd.cd_devs[LPTUNIT(dev)]; 342 size_t n; 343 int error = 0; 344 345 while ((n = min(LPT_BSIZE, uio->uio_resid)) > 0) { 346 uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio); 347 sc->sc_count = n; 348 error = pushbytes(sc); 349 if (error) { 350 /* 351 * Return accurate residual if interrupted or timed 352 * out. 353 */ 354 uio->uio_resid += sc->sc_count; 355 sc->sc_count = 0; 356 return error; 357 } 358 } 359 return 0; 360} 361 362/* 363 * Handle printer interrupts which occur when the printer is ready to accept 364 * another char. 365 */ 366int 367lptintr(sc) 368struct lpt_softc *sc; 369{ 370 /* is printer online and ready for output */ 371 if (NOT_READY()) 372 return 0; 373 374 if (sc->sc_count) { 375 376 /* send char */ 377 ym2149_write_ioport(YM_IOB, *sc->sc_cp++); 378 ym2149_strobe(0); 379 sc->sc_count--; 380 ym2149_strobe(1); 381 sc->sc_state |= LPT_OBUSY; 382 } else 383 sc->sc_state &= ~LPT_OBUSY; 384 385 if (sc->sc_count == 0) { 386 /* none, wake up the top half to get more */ 387 wakeup((caddr_t)sc); 388 } 389 390 return 1; 391} 392 393static void 394lptpseudointr(sc) 395struct lpt_softc *sc; 396{ 397 int s; 398 399 s = spltty(); 400 lptintr(sc); 401 splx(s); 402} 403 404int 405lpthwintr(sc, sr) 406struct lpt_softc *sc; 407int sr; 408{ 409 if (!BASEPRI(sr)) 410 add_sicallback((si_farg)lptpseudointr, sc, 0); 411 else lptpseudointr(sc); 412 return 1; 413} 414 415int 416lpioctl(dev, cmd, data, flag, p) 417 dev_t dev; 418 u_long cmd; 419 caddr_t data; 420 int flag; 421 struct proc *p; 422{ 423 int error = 0; 424 425 switch (cmd) { 426 default: 427 error = ENODEV; 428 } 429 430 return error; 431} 432