1 /* $NetBSD: par.c,v 1.7 1998/08/07 16:16:36 minoura 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 <machine/parioctl.h> 61 62 #include <x68k/x68k/iodevice.h> 63 64 void partimo __P((void *)); 65 void parstart __P((void *);) 66 void parintr __P((void *)); 67 int parrw __P((dev_t, struct uio *)); 68 int parhztoms __P((int)); 69 int parmstohz __P((int)); 70 int parsendch __P((u_char)); 71 int parsend __P((u_char *, int)); 72 73 struct par_softc { 74 struct device sc_dev; 75 int sc_flags; 76 struct parparam sc_param; 77 #define sc_burst sc_param.burst 78 #define sc_timo sc_param.timo 79 #define sc_delay sc_param.delay 80 } ; 81 82 /* sc_flags values */ 83 #define PARF_ALIVE 0x01 84 #define PARF_OPEN 0x02 85 #define PARF_UIO 0x04 86 #define PARF_TIMO 0x08 87 #define PARF_DELAY 0x10 88 #define PARF_OREAD 0x40 /* no support */ 89 #define PARF_OWRITE 0x80 90 91 #define UNIT(x) minor(x) 92 93 #ifdef DEBUG 94 #define PDB_FOLLOW 0x01 95 #define PDB_IO 0x02 96 #define PDB_INTERRUPT 0x04 97 #define PDB_NOCHECK 0x80 98 #if 0 99 int pardebug = PDB_FOLLOW | PDB_IO | PDB_INTERRUPT; 100 #else 101 int pardebug = 0; 102 #endif 103 #endif 104 105 #define PRTI_EN 0x01 106 #define PRT_INT 0x20 107 108 cdev_decl(par); 109 110 int parmatch __P((struct device *, struct cfdata *, void *)); 111 void parattach __P((struct device *, struct device *, void *)); 112 113 struct cfattach par_ca = { 114 sizeof(struct par_softc), (void *)parmatch, parattach 115 }; 116 117 extern struct cfdriver par_cd; 118 119 int 120 parmatch(pdp, cfp, aux) 121 struct device *pdp; 122 struct cfdata *cfp; 123 void *aux; 124 { 125 /* X680x0 has only one parallel port */ 126 if (strcmp(aux, "par") || cfp->cf_unit > 0) 127 return 0; 128 return 1; 129 } 130 131 void 132 parattach(pdp, dp, aux) 133 struct device *pdp, *dp; 134 void *aux; 135 { 136 register struct par_softc *sc = (struct par_softc *)dp; 137 138 sc->sc_flags = PARF_ALIVE; 139 printf(": parallel port (write only, interrupt)\n"); 140 ioctlr.intr &= (~PRTI_EN); 141 } 142 143 int 144 paropen(dev, flags, mode, p) 145 dev_t dev; 146 int flags, mode; 147 struct proc *p; 148 { 149 register int unit = UNIT(dev); 150 register struct par_softc *sc = par_cd.cd_devs[unit]; 151 int s; 152 char mask; 153 154 if (unit >= NPAR || !(sc->sc_flags & PARF_ALIVE)) 155 return(ENXIO); 156 if (sc->sc_flags & PARF_OPEN) 157 return(EBUSY); 158 /* X680x0 can't read */ 159 if ((flags & FREAD) == FREAD) 160 return (EINVAL); 161 162 sc->sc_flags |= PARF_OPEN; 163 164 sc->sc_flags |= PARF_OWRITE; 165 166 sc->sc_burst = PAR_BURST; 167 sc->sc_timo = parmstohz(PAR_TIMO); 168 sc->sc_delay = parmstohz(PAR_DELAY); 169 return(0); 170 } 171 172 int 173 parclose(dev, flags, mode, p) 174 dev_t dev; 175 int flags, mode; 176 struct proc *p; 177 { 178 int unit = UNIT(dev); 179 int s; 180 struct par_softc *sc = par_cd.cd_devs[unit]; 181 182 sc->sc_flags &= ~(PARF_OPEN|PARF_OWRITE); 183 184 /* don't allow interrupts any longer */ 185 s = spl1(); 186 ioctlr.intr &= (~PRTI_EN); 187 splx(s); 188 189 return (0); 190 } 191 192 void 193 parstart(arg) 194 void *arg; 195 { 196 int unit = (int)arg; 197 struct par_softc *sc = par_cd.cd_devs[unit]; 198 #ifdef DEBUG 199 if (pardebug & PDB_FOLLOW) 200 printf("parstart(%x)\n", unit); 201 #endif 202 sc->sc_flags &= ~PARF_DELAY; 203 wakeup(sc); 204 } 205 206 void 207 partimo(arg) 208 void *arg; 209 { 210 int unit = (int)arg; 211 struct par_softc *sc = par_cd.cd_devs[unit]; 212 #ifdef DEBUG 213 if (pardebug & PDB_FOLLOW) 214 printf("partimo(%x)\n", unit); 215 #endif 216 sc->sc_flags &= ~(PARF_UIO|PARF_TIMO); 217 wakeup(sc); 218 } 219 220 int 221 parwrite(dev, uio, flag) 222 dev_t dev; 223 struct uio *uio; 224 int flag; 225 { 226 227 #ifdef DEBUG 228 if (pardebug & PDB_FOLLOW) 229 printf("parwrite(%x, %x)\n", dev, uio); 230 #endif 231 return (parrw(dev, uio)); 232 } 233 234 int 235 parrw(dev, uio) 236 dev_t dev; 237 register struct uio *uio; 238 { 239 int unit = UNIT(dev); 240 register struct par_softc *sc = par_cd.cd_devs[unit]; 241 register int s, len, cnt; 242 register char *cp; 243 int error = 0, gotdata = 0; 244 int buflen; 245 char *buf; 246 247 if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ)) 248 return EINVAL; 249 250 if (uio->uio_resid == 0) 251 return(0); 252 253 buflen = min(sc->sc_burst, uio->uio_resid); 254 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); 255 sc->sc_flags |= PARF_UIO; 256 if (sc->sc_timo > 0) { 257 sc->sc_flags |= PARF_TIMO; 258 timeout(partimo, (void *) unit, sc->sc_timo); 259 } 260 while (uio->uio_resid > 0) { 261 len = min(buflen, uio->uio_resid); 262 cp = buf; 263 if (uio->uio_rw == UIO_WRITE) { 264 error = uiomove(cp, len, uio); 265 if (error) 266 break; 267 } 268 again: 269 s = spl1(); 270 /* 271 * Check if we timed out during sleep or uiomove 272 */ 273 (void) splsoftclock(); 274 if ((sc->sc_flags & PARF_UIO) == 0) { 275 #ifdef DEBUG 276 if (pardebug & PDB_IO) 277 printf("parrw: uiomove/sleep timo, flags %x\n", 278 sc->sc_flags); 279 #endif 280 if (sc->sc_flags & PARF_TIMO) { 281 untimeout(partimo, (void *) unit); 282 sc->sc_flags &= ~PARF_TIMO; 283 } 284 splx(s); 285 break; 286 } 287 splx(s); 288 /* 289 * Perform the operation 290 */ 291 cnt = parsend(cp, len); 292 if (cnt < 0) { 293 error = -cnt; 294 break; 295 } 296 297 s = splsoftclock(); 298 /* 299 * Operation timeout (or non-blocking), quit now. 300 */ 301 if ((sc->sc_flags & PARF_UIO) == 0) { 302 #ifdef DEBUG 303 if (pardebug & PDB_IO) 304 printf("parrw: timeout/done\n"); 305 #endif 306 splx(s); 307 break; 308 } 309 /* 310 * Implement inter-read delay 311 */ 312 if (sc->sc_delay > 0) { 313 sc->sc_flags |= PARF_DELAY; 314 timeout(parstart, (void *) unit, sc->sc_delay); 315 error = tsleep(sc, PCATCH|PZERO-1, "par-cdelay", 0); 316 if (error) { 317 splx(s); 318 break; 319 } 320 } 321 splx(s); 322 /* 323 * Must not call uiomove again til we've used all data 324 * that we already grabbed. 325 */ 326 if (uio->uio_rw == UIO_WRITE && cnt != len) { 327 cp += cnt; 328 len -= cnt; 329 cnt = 0; 330 goto again; 331 } 332 } 333 s = splsoftclock(); 334 if (sc->sc_flags & PARF_TIMO) { 335 untimeout(partimo, (void *) unit); 336 sc->sc_flags &= ~PARF_TIMO; 337 } 338 if (sc->sc_flags & PARF_DELAY) { 339 untimeout(parstart, (void *) unit); 340 sc->sc_flags &= ~PARF_DELAY; 341 } 342 splx(s); 343 /* 344 * Adjust for those chars that we uiomove'ed but never wrote 345 */ 346 if (uio->uio_rw == UIO_WRITE && cnt != len) { 347 uio->uio_resid += (len - cnt); 348 #ifdef DEBUG 349 if (pardebug & PDB_IO) 350 printf("parrw: short write, adjust by %d\n", 351 len-cnt); 352 #endif 353 } 354 free(buf, M_DEVBUF); 355 #ifdef DEBUG 356 if (pardebug & (PDB_FOLLOW|PDB_IO)) 357 printf("parrw: return %d, resid %d\n", error, uio->uio_resid); 358 #endif 359 return (error); 360 } 361 362 int 363 parioctl(dev, cmd, data, flag, p) 364 dev_t dev; 365 u_long cmd; 366 caddr_t data; 367 int flag; 368 struct proc *p; 369 { 370 struct par_softc *sc = par_cd.cd_devs[UNIT(dev)]; 371 struct parparam *pp, *upp; 372 int error = 0; 373 374 switch (cmd) { 375 case PARIOCGPARAM: 376 pp = &sc->sc_param; 377 upp = (struct parparam *)data; 378 upp->burst = pp->burst; 379 upp->timo = parhztoms(pp->timo); 380 upp->delay = parhztoms(pp->delay); 381 break; 382 383 case PARIOCSPARAM: 384 pp = &sc->sc_param; 385 upp = (struct parparam *)data; 386 if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX || 387 upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX) 388 return(EINVAL); 389 pp->burst = upp->burst; 390 pp->timo = parmstohz(upp->timo); 391 pp->delay = parmstohz(upp->delay); 392 break; 393 394 default: 395 return(EINVAL); 396 } 397 return (error); 398 } 399 400 int 401 parhztoms(h) 402 int h; 403 { 404 extern int hz; 405 register int m = h; 406 407 if (m > 0) 408 m = m * 1000 / hz; 409 return(m); 410 } 411 412 int 413 parmstohz(m) 414 int m; 415 { 416 extern int hz; 417 register int h = m; 418 419 if (h > 0) { 420 h = h * hz / 1000; 421 if (h == 0) 422 h = 1000 / hz; 423 } 424 return(h); 425 } 426 427 /* stuff below here if for interrupt driven output of data thru 428 the parallel port. */ 429 430 int partimeout_pending; 431 int parsend_pending; 432 433 void 434 parintr(arg) 435 void *arg; 436 { 437 int s, mask; 438 439 mask = (int)arg; 440 s = splclock(); 441 442 ioctlr.intr &= (~PRTI_EN); 443 444 #ifdef DEBUG 445 if (pardebug & PDB_INTERRUPT) 446 printf ("parintr %d(%s)\n", mask, mask ? "FLG" : "tout"); 447 #endif 448 /* if invoked from timeout handler, mask will be 0, 449 * if from interrupt, it will contain the cia-icr mask, 450 * which is != 0 451 */ 452 if (mask) { 453 if (partimeout_pending) 454 untimeout (parintr, 0); 455 if (parsend_pending) 456 parsend_pending = 0; 457 } 458 459 /* either way, there won't be a timeout pending any longer */ 460 partimeout_pending = 0; 461 462 wakeup(parintr); 463 splx (s); 464 } 465 466 int 467 parsendch(ch) 468 u_char ch; 469 { 470 int error = 0; 471 int s; 472 473 /* if either offline, busy or out of paper, wait for that 474 condition to clear */ 475 s = spl1(); 476 while (!error 477 && (parsend_pending 478 || !(ioctlr.intr & PRT_INT))) 479 { 480 extern int hz; 481 482 /* wait a second, and try again */ 483 timeout (parintr, 0, hz); 484 partimeout_pending = 1; 485 /* this is essentially a flipflop to have us wait for the 486 first character being transmitted when trying to transmit 487 the second, etc. */ 488 parsend_pending = 0; 489 /* it's quite important that a parallel putc can be 490 interrupted, given the possibility to lock a printer 491 in an offline condition.. */ 492 if (error = tsleep (parintr, PCATCH|PZERO-1, "parsendch", 0)) { 493 #ifdef DEBUG 494 if (pardebug & PDB_INTERRUPT) 495 printf ("parsendch interrupted, error = %d\n", error); 496 #endif 497 if (partimeout_pending) 498 untimeout (parintr, 0); 499 500 partimeout_pending = 0; 501 } 502 } 503 504 if (!error) { 505 #ifdef DEBUG 506 if (pardebug & PDB_INTERRUPT) 507 printf ("#%d", ch); 508 #endif 509 printer.data = ch; 510 DELAY(1); /* (DELAY(1) == 1us) > 0.5us */ 511 printer.strobe = 0x00; 512 ioctlr.intr |= PRTI_EN; 513 DELAY(1); 514 printer.strobe = 0x01; 515 parsend_pending = 1; 516 } 517 518 splx (s); 519 520 return error; 521 } 522 523 524 int 525 parsend(buf, len) 526 u_char *buf; 527 int len; 528 { 529 int err, orig_len = len; 530 531 for (; len; len--, buf++) 532 if (err = parsendch (*buf)) 533 return err < 0 ? -EINTR : -err; 534 535 /* either all or nothing.. */ 536 return orig_len; 537 } 538 539 #endif 540