1 /* $NetBSD: par.c,v 1.29 2002/10/23 09:10:35 jdolecek 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 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: par.c,v 1.29 2002/10/23 09:10:35 jdolecek Exp $"); 40 41 /* 42 * parallel port interface 43 */ 44 45 #include "par.h" 46 #if NPAR > 0 47 48 #include <sys/param.h> 49 #include <sys/errno.h> 50 #include <sys/uio.h> 51 #include <sys/device.h> 52 #include <sys/malloc.h> 53 #include <sys/file.h> 54 #include <sys/systm.h> 55 #include <sys/callout.h> 56 #include <sys/proc.h> 57 #include <sys/conf.h> 58 59 #include <amiga/amiga/device.h> 60 #include <amiga/amiga/cia.h> 61 #include <amiga/dev/parioctl.h> 62 63 struct par_softc { 64 struct device sc_dev; 65 66 int sc_flags; 67 struct parparam sc_param; 68 #define sc_burst sc_param.burst 69 #define sc_timo sc_param.timo 70 #define sc_delay sc_param.delay 71 72 struct callout sc_timo_ch; 73 struct callout sc_start_ch; 74 } *par_softcp; 75 76 #define getparsp(x) (x > 0 ? NULL : par_softcp) 77 78 /* sc_flags values */ 79 #define PARF_ALIVE 0x01 80 #define PARF_OPEN 0x02 81 #define PARF_UIO 0x04 82 #define PARF_TIMO 0x08 83 #define PARF_DELAY 0x10 84 #define PARF_OREAD 0x40 85 #define PARF_OWRITE 0x80 86 87 #define UNIT(x) minor(x) 88 89 #ifdef DEBUG 90 int pardebug = 0; 91 #define PDB_FOLLOW 0x01 92 #define PDB_IO 0x02 93 #define PDB_INTERRUPT 0x04 94 #define PDB_NOCHECK 0x80 95 #endif 96 97 int parrw(dev_t, struct uio *); 98 int parhztoms(int); 99 int parmstohz(int); 100 int parsend(u_char *, int); 101 int parreceive(u_char *, int); 102 int parsendch(u_char); 103 104 void partimo(void *); 105 void parstart(void *); 106 void parintr(void *); 107 108 void parattach(struct device *, struct device *, void *); 109 int parmatch(struct device *, struct cfdata *, void *); 110 111 CFATTACH_DECL(par, sizeof(struct par_softc), 112 parmatch, parattach, NULL, NULL); 113 114 dev_type_open(paropen); 115 dev_type_close(parclose); 116 dev_type_read(parread); 117 dev_type_write(parwrite); 118 dev_type_ioctl(parioctl); 119 120 const struct cdevsw par_cdevsw = { 121 paropen, parclose, parread, parwrite, parioctl, 122 nostop, notty, nopoll, nommap, nokqfilter, 123 }; 124 125 /*ARGSUSED*/ 126 int 127 parmatch(struct device *pdp, struct cfdata *cfp, void *auxp) 128 { 129 static int par_found = 0; 130 131 if (!matchname((char *)auxp, "par") || par_found) 132 return(0); 133 134 par_found = 1; 135 return(1); 136 } 137 138 void 139 parattach(struct device *pdp, struct device *dp, void *auxp) 140 { 141 par_softcp = (struct par_softc *)dp; 142 143 #ifdef DEBUG 144 if ((pardebug & PDB_NOCHECK) == 0) 145 #endif 146 par_softcp->sc_flags = PARF_ALIVE; 147 printf("\n"); 148 149 callout_init(&par_softcp->sc_timo_ch); 150 callout_init(&par_softcp->sc_start_ch); 151 } 152 153 int 154 paropen(dev_t dev, int flags, int mode, struct proc *p) 155 { 156 int unit = UNIT(dev); 157 struct par_softc *sc = getparsp(unit); 158 159 if (unit >= NPAR || (sc->sc_flags & PARF_ALIVE) == 0) 160 return(ENXIO); 161 #ifdef DEBUG 162 if (pardebug & PDB_FOLLOW) { 163 printf("paropen(%x, %x): flags %x, ", 164 dev, flags, sc->sc_flags); 165 printf ("port = $%x\n", ((ciab.pra ^ CIAB_PRA_SEL) 166 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT))); 167 } 168 #endif 169 if (sc->sc_flags & PARF_OPEN) 170 return(EBUSY); 171 /* can either read or write, but not both */ 172 if ((flags & (FREAD|FWRITE)) == (FREAD|FWRITE)) 173 return EINVAL; 174 175 sc->sc_flags |= PARF_OPEN; 176 177 if (flags & FREAD) 178 sc->sc_flags |= PARF_OREAD; 179 else 180 sc->sc_flags |= PARF_OWRITE; 181 182 sc->sc_burst = PAR_BURST; 183 sc->sc_timo = parmstohz(PAR_TIMO); 184 sc->sc_delay = parmstohz(PAR_DELAY); 185 /* enable interrupts for CIAA-FLG */ 186 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG; 187 return(0); 188 } 189 190 int 191 parclose(dev_t dev, int flags, int mode, struct proc *p) 192 { 193 int unit = UNIT(dev); 194 struct par_softc *sc = getparsp(unit); 195 196 #ifdef DEBUG 197 if (pardebug & PDB_FOLLOW) 198 printf("parclose(%x, %x): flags %x\n", 199 dev, flags, sc->sc_flags); 200 #endif 201 sc->sc_flags &= ~(PARF_OPEN|PARF_OREAD|PARF_OWRITE); 202 /* don't allow interrupts for CIAA-FLG any longer */ 203 ciaa.icr = CIA_ICR_FLG; 204 return(0); 205 } 206 207 void 208 parstart(void *arg) 209 { 210 struct par_softc *sc = arg; 211 212 #ifdef DEBUG 213 if (pardebug & PDB_FOLLOW) 214 printf("parstart(%x)\n", sc->sc_dev.dv_unit); 215 #endif 216 sc->sc_flags &= ~PARF_DELAY; 217 wakeup(sc); 218 } 219 220 void 221 partimo(void *arg) 222 { 223 struct par_softc *sc = arg; 224 225 #ifdef DEBUG 226 if (pardebug & PDB_FOLLOW) 227 printf("partimo(%x)\n", sc->sc_dev.dv_unit); 228 #endif 229 sc->sc_flags &= ~(PARF_UIO|PARF_TIMO); 230 wakeup(sc); 231 } 232 233 int 234 parread(dev_t dev, struct uio *uio, int flags) 235 { 236 237 #ifdef DEBUG 238 if (pardebug & PDB_FOLLOW) 239 printf("parread(%x, %p)\n", dev, uio); 240 #endif 241 return (parrw(dev, uio)); 242 } 243 244 245 int 246 parwrite(dev_t dev, struct uio *uio, int flags) 247 { 248 249 #ifdef DEBUG 250 if (pardebug & PDB_FOLLOW) 251 printf("parwrite(%x, %p)\n", dev, uio); 252 #endif 253 return (parrw(dev, uio)); 254 } 255 256 257 int 258 parrw(dev_t dev, register struct uio *uio) 259 { 260 int unit = UNIT(dev); 261 register struct par_softc *sc = getparsp(unit); 262 register int s, len, cnt; 263 register char *cp; 264 int error = 0, gotdata = 0; 265 int buflen; 266 char *buf; 267 268 len = 0; 269 cnt = 0; 270 if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ)) 271 return EINVAL; 272 273 if (uio->uio_resid == 0) 274 return(0); 275 276 #ifdef DEBUG 277 if (pardebug & (PDB_FOLLOW|PDB_IO)) 278 printf("parrw(%x, %p, %c): burst %d, timo %d, resid %x\n", 279 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W', 280 sc->sc_burst, sc->sc_timo, uio->uio_resid); 281 #endif 282 buflen = min(sc->sc_burst, uio->uio_resid); 283 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); 284 sc->sc_flags |= PARF_UIO; 285 if (sc->sc_timo > 0) 286 { 287 sc->sc_flags |= PARF_TIMO; 288 callout_reset(&sc->sc_timo_ch, sc->sc_timo, partimo, sc); 289 } 290 while (uio->uio_resid > 0) 291 { 292 len = min(buflen, uio->uio_resid); 293 cp = buf; 294 if (uio->uio_rw == UIO_WRITE) 295 { 296 error = uiomove(cp, len, uio); 297 if (error) 298 break; 299 } 300 again: 301 s = splbio(); 302 #if 0 303 if ((sc->sc_flags & PARF_UIO) && hpibreq(&sc->sc_dq) == 0) 304 sleep(sc, PRIBIO+1); 305 #endif 306 /* 307 * Check if we timed out during sleep or uiomove 308 */ 309 (void) spllowersoftclock(); 310 if ((sc->sc_flags & PARF_UIO) == 0) 311 { 312 #ifdef DEBUG 313 if (pardebug & PDB_IO) 314 printf("parrw: uiomove/sleep timo, flags %x\n", 315 sc->sc_flags); 316 #endif 317 if (sc->sc_flags & PARF_TIMO) 318 { 319 callout_stop(&sc->sc_timo_ch); 320 sc->sc_flags &= ~PARF_TIMO; 321 } 322 splx(s); 323 break; 324 } 325 splx(s); 326 /* 327 * Perform the operation 328 */ 329 if (uio->uio_rw == UIO_WRITE) 330 cnt = parsend (cp, len); 331 else 332 cnt = parreceive (cp, len); 333 334 if (cnt < 0) 335 { 336 error = -cnt; 337 break; 338 } 339 340 s = splbio(); 341 #if 0 342 hpibfree(&sc->sc_dq); 343 #endif 344 #ifdef DEBUG 345 if (pardebug & PDB_IO) 346 printf("parrw: %s(%p, %d) -> %d\n", 347 uio->uio_rw == UIO_READ ? "recv" : "send", cp, len, cnt); 348 #endif 349 splx(s); 350 if (uio->uio_rw == UIO_READ) 351 { 352 if (cnt) 353 { 354 error = uiomove(cp, cnt, uio); 355 if (error) 356 break; 357 gotdata++; 358 } 359 /* 360 * Didn't get anything this time, but did in the past. 361 * Consider us done. 362 */ 363 else if (gotdata) 364 break; 365 } 366 s = splsoftclock(); 367 /* 368 * Operation timeout (or non-blocking), quit now. 369 */ 370 if ((sc->sc_flags & PARF_UIO) == 0) 371 { 372 #ifdef DEBUG 373 if (pardebug & PDB_IO) 374 printf("parrw: timeout/done\n"); 375 #endif 376 splx(s); 377 break; 378 } 379 /* 380 * Implement inter-read delay 381 */ 382 if (sc->sc_delay > 0) 383 { 384 sc->sc_flags |= PARF_DELAY; 385 callout_reset(&sc->sc_start_ch, sc->sc_delay, parstart, sc); 386 error = tsleep(sc, PCATCH | (PZERO - 1), "par-cdelay", 0); 387 if (error) 388 { 389 splx(s); 390 break; 391 } 392 } 393 splx(s); 394 /* 395 * Must not call uiomove again til we've used all data 396 * that we already grabbed. 397 */ 398 if (uio->uio_rw == UIO_WRITE && cnt != len) 399 { 400 cp += cnt; 401 len -= cnt; 402 cnt = 0; 403 goto again; 404 } 405 } 406 s = splsoftclock(); 407 if (sc->sc_flags & PARF_TIMO) 408 { 409 callout_stop(&sc->sc_timo_ch); 410 sc->sc_flags &= ~PARF_TIMO; 411 } 412 if (sc->sc_flags & PARF_DELAY) 413 { 414 callout_stop(&sc->sc_start_ch); 415 sc->sc_flags &= ~PARF_DELAY; 416 } 417 splx(s); 418 /* 419 * Adjust for those chars that we uiomove'ed but never wrote 420 */ 421 if (uio->uio_rw == UIO_WRITE && cnt != len) 422 { 423 uio->uio_resid += (len - cnt); 424 #ifdef DEBUG 425 if (pardebug & PDB_IO) 426 printf("parrw: short write, adjust by %d\n", 427 len-cnt); 428 #endif 429 } 430 free(buf, M_DEVBUF); 431 #ifdef DEBUG 432 if (pardebug & (PDB_FOLLOW|PDB_IO)) 433 printf("parrw: return %d, resid %d\n", error, uio->uio_resid); 434 #endif 435 return (error); 436 } 437 438 int 439 parioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 440 { 441 struct par_softc *sc = getparsp(UNIT(dev)); 442 struct parparam *pp, *upp; 443 int error = 0; 444 445 switch (cmd) 446 { 447 case PARIOCGPARAM: 448 pp = &sc->sc_param; 449 upp = (struct parparam *)data; 450 upp->burst = pp->burst; 451 upp->timo = parhztoms(pp->timo); 452 upp->delay = parhztoms(pp->delay); 453 break; 454 455 case PARIOCSPARAM: 456 pp = &sc->sc_param; 457 upp = (struct parparam *)data; 458 if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX || 459 upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX) 460 return(EINVAL); 461 pp->burst = upp->burst; 462 pp->timo = parmstohz(upp->timo); 463 pp->delay = parmstohz(upp->delay); 464 break; 465 466 default: 467 return(EINVAL); 468 } 469 return (error); 470 } 471 472 int 473 parhztoms(int h) 474 { 475 extern int hz; 476 register int m = h; 477 478 if (m > 0) 479 m = m * 1000 / hz; 480 return(m); 481 } 482 483 int 484 parmstohz(int m) 485 { 486 extern int hz; 487 register int h = m; 488 489 if (h > 0) { 490 h = h * hz / 1000; 491 if (h == 0) 492 h = 1000 / hz; 493 } 494 return(h); 495 } 496 497 /* stuff below here if for interrupt driven output of data thru 498 the parallel port. */ 499 500 int parsend_pending; 501 502 void 503 parintr(void *arg) 504 { 505 int s; 506 507 s = splclock(); 508 509 #ifdef DEBUG 510 if (pardebug & PDB_INTERRUPT) 511 printf("parintr\n"); 512 #endif 513 parsend_pending = 0; 514 515 wakeup(parintr); 516 splx(s); 517 } 518 519 int 520 parsendch (u_char ch) 521 { 522 int error = 0; 523 int s; 524 525 /* if either offline, busy or out of paper, wait for that 526 condition to clear */ 527 s = splclock(); 528 while (!error 529 && (parsend_pending 530 || ((ciab.pra ^ CIAB_PRA_SEL) 531 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT)))) 532 { 533 extern int hz; 534 535 #ifdef DEBUG 536 if (pardebug & PDB_INTERRUPT) 537 printf ("parsendch, port = $%x\n", 538 ((ciab.pra ^ CIAB_PRA_SEL) 539 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT))); 540 #endif 541 /* this is essentially a flipflop to have us wait for the 542 first character being transmitted when trying to transmit 543 the second, etc. */ 544 parsend_pending = 0; 545 /* it's quite important that a parallel putc can be 546 interrupted, given the possibility to lock a printer 547 in an offline condition.. */ 548 error = tsleep(parintr, PCATCH | (PZERO - 1), "parsendch", hz); 549 if (error == EWOULDBLOCK) 550 error = 0; 551 if (error > 0) 552 { 553 #ifdef DEBUG 554 if (pardebug & PDB_INTERRUPT) 555 printf ("parsendch interrupted, error = %d\n", error); 556 #endif 557 } 558 } 559 560 if (! error) 561 { 562 #ifdef DEBUG 563 if (pardebug & PDB_INTERRUPT) 564 printf ("#%d", ch); 565 #endif 566 ciaa.prb = ch; 567 parsend_pending = 1; 568 } 569 570 splx (s); 571 572 return error; 573 } 574 575 576 int 577 parsend (u_char *buf, int len) 578 { 579 int err, orig_len = len; 580 581 /* make sure I/O lines are setup right for output */ 582 583 /* control lines set to input */ 584 ciab.ddra &= ~(CIAB_PRA_SEL|CIAB_PRA_POUT|CIAB_PRA_BUSY); 585 /* data lines to output */ 586 ciaa.ddrb = 0xff; 587 588 for (; len; len--, buf++) 589 if ((err = parsendch (*buf)) != 0) 590 return err < 0 ? -EINTR : -err; 591 592 /* either all or nothing.. */ 593 return orig_len; 594 } 595 596 597 598 int 599 parreceive (u_char *buf, int len) 600 { 601 /* oh deary me, something's gotta be left to be implemented 602 later... */ 603 return 0; 604 } 605 606 607 #endif 608