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