1 /* $NetBSD: par.c,v 1.5 1997/10/12 14:44:14 oki Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)ppi.c 7.3 (Berkeley) 12/16/90 36 */ 37 38 /* 39 * parallel port interface 40 */ 41 42 #include "par.h" 43 #if NPAR > 0 44 45 #if NPAR > 1 46 #undef NPAR 47 #define NPAR 1 48 #endif 49 50 #include <sys/param.h> 51 #include <sys/errno.h> 52 #include <sys/uio.h> 53 #include <sys/device.h> 54 #include <sys/malloc.h> 55 #include <sys/file.h> 56 #include <sys/systm.h> 57 #include <sys/proc.h> 58 #include <sys/conf.h> 59 60 #include <x68k/x68k/iodevice.h> 61 #include <x68k/dev/parioctl.h> 62 63 void partimo __P((void *)); 64 void parstart __P((void *);) 65 void parintr __P((void *)); 66 int parrw __P((dev_t, struct uio *)); 67 int parhztoms __P((int)); 68 int parmstohz __P((int)); 69 int parsendch __P((u_char)); 70 int parsend __P((u_char *, int)); 71 72 struct par_softc { 73 struct device sc_dev; 74 int sc_flags; 75 struct parparam sc_param; 76 #define sc_burst sc_param.burst 77 #define sc_timo sc_param.timo 78 #define sc_delay sc_param.delay 79 } ; 80 81 /* sc_flags values */ 82 #define PARF_ALIVE 0x01 83 #define PARF_OPEN 0x02 84 #define PARF_UIO 0x04 85 #define PARF_TIMO 0x08 86 #define PARF_DELAY 0x10 87 #define PARF_OREAD 0x40 /* no support */ 88 #define PARF_OWRITE 0x80 89 90 #define UNIT(x) minor(x) 91 92 #ifdef DEBUG 93 #define PDB_FOLLOW 0x01 94 #define PDB_IO 0x02 95 #define PDB_INTERRUPT 0x04 96 #define PDB_NOCHECK 0x80 97 #if 0 98 int pardebug = PDB_FOLLOW | PDB_IO | PDB_INTERRUPT; 99 #else 100 int pardebug = 0; 101 #endif 102 #endif 103 104 #define PRTI_EN 0x01 105 #define PRT_INT 0x20 106 107 cdev_decl(par); 108 109 int parmatch __P((struct device *, struct cfdata *, void *)); 110 void parattach __P((struct device *, struct device *, void *)); 111 112 struct cfattach par_ca = { 113 sizeof(struct par_softc), (void *)parmatch, parattach 114 }; 115 116 struct cfdriver par_cd = { 117 NULL, "par", DV_DULL 118 }; 119 120 int 121 parmatch(pdp, cfp, aux) 122 struct device *pdp; 123 struct cfdata *cfp; 124 void *aux; 125 { 126 /* X680x0 has only one parallel port */ 127 if (strcmp(aux, "par") || cfp->cf_unit > 0) 128 return 0; 129 return 1; 130 } 131 132 void 133 parattach(pdp, dp, aux) 134 struct device *pdp, *dp; 135 void *aux; 136 { 137 register struct par_softc *sc = (struct par_softc *)dp; 138 139 sc->sc_flags = PARF_ALIVE; 140 printf(": parallel port (write only, interrupt)\n"); 141 ioctlr.intr &= (~PRTI_EN); 142 } 143 144 int 145 paropen(dev, flags, mode, p) 146 dev_t dev; 147 int flags, mode; 148 struct proc *p; 149 { 150 register int unit = UNIT(dev); 151 register struct par_softc *sc = par_cd.cd_devs[unit]; 152 int s; 153 char mask; 154 155 if (unit >= NPAR || !(sc->sc_flags & PARF_ALIVE)) 156 return(ENXIO); 157 if (sc->sc_flags & PARF_OPEN) 158 return(EBUSY); 159 /* X680x0 can't read */ 160 if ((flags & FREAD) == FREAD) 161 return (EINVAL); 162 163 sc->sc_flags |= PARF_OPEN; 164 165 sc->sc_flags |= PARF_OWRITE; 166 167 sc->sc_burst = PAR_BURST; 168 sc->sc_timo = parmstohz(PAR_TIMO); 169 sc->sc_delay = parmstohz(PAR_DELAY); 170 return(0); 171 } 172 173 int 174 parclose(dev, flags, mode, p) 175 dev_t dev; 176 int flags, mode; 177 struct proc *p; 178 { 179 int unit = UNIT(dev); 180 int s; 181 struct par_softc *sc = par_cd.cd_devs[unit]; 182 183 sc->sc_flags &= ~(PARF_OPEN|PARF_OWRITE); 184 185 /* don't allow interrupts any longer */ 186 s = spl1(); 187 ioctlr.intr &= (~PRTI_EN); 188 splx(s); 189 190 return (0); 191 } 192 193 void 194 parstart(arg) 195 void *arg; 196 { 197 int unit = (int)arg; 198 struct par_softc *sc = par_cd.cd_devs[unit]; 199 #ifdef DEBUG 200 if (pardebug & PDB_FOLLOW) 201 printf("parstart(%x)\n", unit); 202 #endif 203 sc->sc_flags &= ~PARF_DELAY; 204 wakeup(sc); 205 } 206 207 void 208 partimo(arg) 209 void *arg; 210 { 211 int unit = (int)arg; 212 struct par_softc *sc = par_cd.cd_devs[unit]; 213 #ifdef DEBUG 214 if (pardebug & PDB_FOLLOW) 215 printf("partimo(%x)\n", unit); 216 #endif 217 sc->sc_flags &= ~(PARF_UIO|PARF_TIMO); 218 wakeup(sc); 219 } 220 221 int 222 parwrite(dev, uio, flag) 223 dev_t dev; 224 struct uio *uio; 225 int flag; 226 { 227 228 #ifdef DEBUG 229 if (pardebug & PDB_FOLLOW) 230 printf("parwrite(%x, %x)\n", dev, uio); 231 #endif 232 return (parrw(dev, uio)); 233 } 234 235 int 236 parrw(dev, uio) 237 dev_t dev; 238 register struct uio *uio; 239 { 240 int unit = UNIT(dev); 241 register struct par_softc *sc = par_cd.cd_devs[unit]; 242 register int s, len, cnt; 243 register char *cp; 244 int error = 0, gotdata = 0; 245 int buflen; 246 char *buf; 247 248 if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ)) 249 return EINVAL; 250 251 if (uio->uio_resid == 0) 252 return(0); 253 254 buflen = min(sc->sc_burst, uio->uio_resid); 255 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); 256 sc->sc_flags |= PARF_UIO; 257 if (sc->sc_timo > 0) { 258 sc->sc_flags |= PARF_TIMO; 259 timeout(partimo, (void *) unit, sc->sc_timo); 260 } 261 while (uio->uio_resid > 0) { 262 len = min(buflen, uio->uio_resid); 263 cp = buf; 264 if (uio->uio_rw == UIO_WRITE) { 265 error = uiomove(cp, len, uio); 266 if (error) 267 break; 268 } 269 again: 270 s = spl1(); 271 /* 272 * Check if we timed out during sleep or uiomove 273 */ 274 (void) splsoftclock(); 275 if ((sc->sc_flags & PARF_UIO) == 0) { 276 #ifdef DEBUG 277 if (pardebug & PDB_IO) 278 printf("parrw: uiomove/sleep timo, flags %x\n", 279 sc->sc_flags); 280 #endif 281 if (sc->sc_flags & PARF_TIMO) { 282 untimeout(partimo, (void *) unit); 283 sc->sc_flags &= ~PARF_TIMO; 284 } 285 splx(s); 286 break; 287 } 288 splx(s); 289 /* 290 * Perform the operation 291 */ 292 cnt = parsend(cp, len); 293 if (cnt < 0) { 294 error = -cnt; 295 break; 296 } 297 298 s = splsoftclock(); 299 /* 300 * Operation timeout (or non-blocking), quit now. 301 */ 302 if ((sc->sc_flags & PARF_UIO) == 0) { 303 #ifdef DEBUG 304 if (pardebug & PDB_IO) 305 printf("parrw: timeout/done\n"); 306 #endif 307 splx(s); 308 break; 309 } 310 /* 311 * Implement inter-read delay 312 */ 313 if (sc->sc_delay > 0) { 314 sc->sc_flags |= PARF_DELAY; 315 timeout(parstart, (void *) unit, sc->sc_delay); 316 error = tsleep(sc, PCATCH|PZERO-1, "par-cdelay", 0); 317 if (error) { 318 splx(s); 319 break; 320 } 321 } 322 splx(s); 323 /* 324 * Must not call uiomove again til we've used all data 325 * that we already grabbed. 326 */ 327 if (uio->uio_rw == UIO_WRITE && cnt != len) { 328 cp += cnt; 329 len -= cnt; 330 cnt = 0; 331 goto again; 332 } 333 } 334 s = splsoftclock(); 335 if (sc->sc_flags & PARF_TIMO) { 336 untimeout(partimo, (void *) unit); 337 sc->sc_flags &= ~PARF_TIMO; 338 } 339 if (sc->sc_flags & PARF_DELAY) { 340 untimeout(parstart, (void *) unit); 341 sc->sc_flags &= ~PARF_DELAY; 342 } 343 splx(s); 344 /* 345 * Adjust for those chars that we uiomove'ed but never wrote 346 */ 347 if (uio->uio_rw == UIO_WRITE && cnt != len) { 348 uio->uio_resid += (len - cnt); 349 #ifdef DEBUG 350 if (pardebug & PDB_IO) 351 printf("parrw: short write, adjust by %d\n", 352 len-cnt); 353 #endif 354 } 355 free(buf, M_DEVBUF); 356 #ifdef DEBUG 357 if (pardebug & (PDB_FOLLOW|PDB_IO)) 358 printf("parrw: return %d, resid %d\n", error, uio->uio_resid); 359 #endif 360 return (error); 361 } 362 363 int 364 parioctl(dev, cmd, data, flag, p) 365 dev_t dev; 366 u_long cmd; 367 caddr_t data; 368 int flag; 369 struct proc *p; 370 { 371 struct par_softc *sc = par_cd.cd_devs[UNIT(dev)]; 372 struct parparam *pp, *upp; 373 int error = 0; 374 375 switch (cmd) { 376 case PARIOCGPARAM: 377 pp = &sc->sc_param; 378 upp = (struct parparam *)data; 379 upp->burst = pp->burst; 380 upp->timo = parhztoms(pp->timo); 381 upp->delay = parhztoms(pp->delay); 382 break; 383 384 case PARIOCSPARAM: 385 pp = &sc->sc_param; 386 upp = (struct parparam *)data; 387 if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX || 388 upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX) 389 return(EINVAL); 390 pp->burst = upp->burst; 391 pp->timo = parmstohz(upp->timo); 392 pp->delay = parmstohz(upp->delay); 393 break; 394 395 default: 396 return(EINVAL); 397 } 398 return (error); 399 } 400 401 int 402 parhztoms(h) 403 int h; 404 { 405 extern int hz; 406 register int m = h; 407 408 if (m > 0) 409 m = m * 1000 / hz; 410 return(m); 411 } 412 413 int 414 parmstohz(m) 415 int m; 416 { 417 extern int hz; 418 register int h = m; 419 420 if (h > 0) { 421 h = h * hz / 1000; 422 if (h == 0) 423 h = 1000 / hz; 424 } 425 return(h); 426 } 427 428 /* stuff below here if for interrupt driven output of data thru 429 the parallel port. */ 430 431 int partimeout_pending; 432 int parsend_pending; 433 434 void 435 parintr(arg) 436 void *arg; 437 { 438 int s, mask; 439 440 mask = (int)arg; 441 s = splclock(); 442 443 ioctlr.intr &= (~PRTI_EN); 444 445 #ifdef DEBUG 446 if (pardebug & PDB_INTERRUPT) 447 printf ("parintr %d(%s)\n", mask, mask ? "FLG" : "tout"); 448 #endif 449 /* if invoked from timeout handler, mask will be 0, 450 * if from interrupt, it will contain the cia-icr mask, 451 * which is != 0 452 */ 453 if (mask) { 454 if (partimeout_pending) 455 untimeout (parintr, 0); 456 if (parsend_pending) 457 parsend_pending = 0; 458 } 459 460 /* either way, there won't be a timeout pending any longer */ 461 partimeout_pending = 0; 462 463 wakeup(parintr); 464 splx (s); 465 } 466 467 int 468 parsendch(ch) 469 u_char ch; 470 { 471 int error = 0; 472 int s; 473 474 /* if either offline, busy or out of paper, wait for that 475 condition to clear */ 476 s = spl1(); 477 while (!error 478 && (parsend_pending 479 || !(ioctlr.intr & PRT_INT))) 480 { 481 extern int hz; 482 483 /* wait a second, and try again */ 484 timeout (parintr, 0, hz); 485 partimeout_pending = 1; 486 /* this is essentially a flipflop to have us wait for the 487 first character being transmitted when trying to transmit 488 the second, etc. */ 489 parsend_pending = 0; 490 /* it's quite important that a parallel putc can be 491 interrupted, given the possibility to lock a printer 492 in an offline condition.. */ 493 if (error = tsleep (parintr, PCATCH|PZERO-1, "parsendch", 0)) { 494 #ifdef DEBUG 495 if (pardebug & PDB_INTERRUPT) 496 printf ("parsendch interrupted, error = %d\n", error); 497 #endif 498 if (partimeout_pending) 499 untimeout (parintr, 0); 500 501 partimeout_pending = 0; 502 } 503 } 504 505 if (!error) { 506 #ifdef DEBUG 507 if (pardebug & PDB_INTERRUPT) 508 printf ("#%d", ch); 509 #endif 510 printer.data = ch; 511 DELAY(1); /* (DELAY(1) == 1us) > 0.5us */ 512 printer.strobe = 0x00; 513 ioctlr.intr |= PRTI_EN; 514 DELAY(1); 515 printer.strobe = 0x01; 516 parsend_pending = 1; 517 } 518 519 splx (s); 520 521 return error; 522 } 523 524 525 int 526 parsend(buf, len) 527 u_char *buf; 528 int len; 529 { 530 int err, orig_len = len; 531 532 for (; len; len--, buf++) 533 if (err = parsendch (*buf)) 534 return err < 0 ? -EINTR : -err; 535 536 /* either all or nothing.. */ 537 return orig_len; 538 } 539 540 #endif 541