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