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