141480Smckusick /* 241480Smckusick * Copyright (c) 1982, 1990 The Regents of the University of California. 341480Smckusick * All rights reserved. 441480Smckusick * 541480Smckusick * %sccs.include.redist.c% 641480Smckusick * 7*55068Spendry * @(#)ppi.c 7.5 (Berkeley) 07/12/92 841480Smckusick */ 941480Smckusick 1041480Smckusick /* 1141480Smckusick * Printer/Plotter HPIB interface 1241480Smckusick */ 1341480Smckusick 1441480Smckusick #include "ppi.h" 1541480Smckusick #if NPPI > 0 1641480Smckusick 1745788Sbostic #include "sys/param.h" 18*55068Spendry #include "sys/systm.h" 1945788Sbostic #include "sys/errno.h" 2045788Sbostic #include "sys/uio.h" 2145788Sbostic #include "sys/malloc.h" 2241480Smckusick 2353929Shibler #include "hp/dev/device.h" 2445512Smckusick #include "ppiioctl.h" 2541480Smckusick 2645512Smckusick int ppiattach(), ppistart(), ppitimo(); 2741480Smckusick struct driver ppidriver = { 2841480Smckusick ppiattach, "ppi", ppistart, 2941480Smckusick }; 3041480Smckusick 3141480Smckusick struct ppi_softc { 3241480Smckusick int sc_flags; 3341480Smckusick struct devqueue sc_dq; 3441480Smckusick struct hp_device *sc_hd; 3545512Smckusick struct ppiparam sc_param; 3645512Smckusick #define sc_burst sc_param.burst 3745512Smckusick #define sc_timo sc_param.timo 3845512Smckusick #define sc_delay sc_param.delay 3945512Smckusick int sc_sec; 4041480Smckusick } ppi_softc[NPPI]; 4141480Smckusick 4241480Smckusick /* sc_flags values */ 4345512Smckusick #define PPIF_ALIVE 0x01 4445512Smckusick #define PPIF_OPEN 0x02 4545512Smckusick #define PPIF_UIO 0x04 4645512Smckusick #define PPIF_TIMO 0x08 4745512Smckusick #define PPIF_DELAY 0x10 4841480Smckusick 4941480Smckusick #define UNIT(x) minor(x) 5041480Smckusick 5145512Smckusick #ifdef DEBUG 5245512Smckusick int ppidebug = 0x80; 5345512Smckusick #define PDB_FOLLOW 0x01 5445512Smckusick #define PDB_IO 0x02 5545512Smckusick #define PDB_NOCHECK 0x80 5645512Smckusick #endif 5745512Smckusick 5841480Smckusick ppiattach(hd) 5941480Smckusick register struct hp_device *hd; 6041480Smckusick { 6141480Smckusick register struct ppi_softc *sc = &ppi_softc[hd->hp_unit]; 6241480Smckusick 6345512Smckusick #ifdef DEBUG 6445512Smckusick if ((ppidebug & PDB_NOCHECK) == 0) 6545512Smckusick #endif 6641480Smckusick /* 6741480Smckusick * XXX: the printer/plotter doesn't seem to really return 6841480Smckusick * an ID but this will at least prevent us from mistaking 6941480Smckusick * a cs80 disk or tape for a ppi device. 7041480Smckusick */ 7141480Smckusick if (hpibid(hd->hp_ctlr, hd->hp_slave) & 0x200) 7241480Smckusick return(0); 7341480Smckusick sc->sc_flags = PPIF_ALIVE; 7441480Smckusick sc->sc_dq.dq_ctlr = hd->hp_ctlr; 7541480Smckusick sc->sc_dq.dq_unit = hd->hp_unit; 7641480Smckusick sc->sc_dq.dq_slave = hd->hp_slave; 7741480Smckusick sc->sc_dq.dq_driver = &ppidriver; 7841480Smckusick sc->sc_hd = hd; 7941480Smckusick return(1); 8041480Smckusick } 8141480Smckusick 8241480Smckusick ppiopen(dev, flags) 8341480Smckusick dev_t dev; 8441480Smckusick { 8541480Smckusick register int unit = UNIT(dev); 8641480Smckusick register struct ppi_softc *sc = &ppi_softc[unit]; 8741480Smckusick 8841480Smckusick if (unit >= NPPI || (sc->sc_flags & PPIF_ALIVE) == 0) 8941480Smckusick return(ENXIO); 9045512Smckusick #ifdef DEBUG 9145512Smckusick if (ppidebug & PDB_FOLLOW) 9245512Smckusick printf("ppiopen(%x, %x): flags %x\n", 9345512Smckusick dev, flags, sc->sc_flags); 9445512Smckusick #endif 9541480Smckusick if (sc->sc_flags & PPIF_OPEN) 9641480Smckusick return(EBUSY); 9741480Smckusick sc->sc_flags |= PPIF_OPEN; 9845512Smckusick sc->sc_burst = PPI_BURST; 9945512Smckusick sc->sc_timo = ppimstohz(PPI_TIMO); 10045512Smckusick sc->sc_delay = ppimstohz(PPI_DELAY); 10145512Smckusick sc->sc_sec = -1; 10241480Smckusick return(0); 10341480Smckusick } 10441480Smckusick 10541480Smckusick ppiclose(dev, flags) 10641480Smckusick dev_t dev; 10741480Smckusick { 10841480Smckusick register int unit = UNIT(dev); 10941480Smckusick register struct ppi_softc *sc = &ppi_softc[unit]; 11041480Smckusick 11145512Smckusick #ifdef DEBUG 11245512Smckusick if (ppidebug & PDB_FOLLOW) 11345512Smckusick printf("ppiclose(%x, %x): flags %x\n", 11445512Smckusick dev, flags, sc->sc_flags); 11545512Smckusick #endif 11641480Smckusick sc->sc_flags &= ~PPIF_OPEN; 11741480Smckusick return(0); 11841480Smckusick } 11941480Smckusick 12041480Smckusick ppistart(unit) 12145512Smckusick int unit; 12241480Smckusick { 12345512Smckusick #ifdef DEBUG 12445512Smckusick if (ppidebug & PDB_FOLLOW) 12545512Smckusick printf("ppistart(%x)\n", unit); 12645512Smckusick #endif 12745512Smckusick ppi_softc[unit].sc_flags &= ~PPIF_DELAY; 12841480Smckusick wakeup(&ppi_softc[unit]); 12941480Smckusick } 13041480Smckusick 13145512Smckusick ppitimo(unit) 13245512Smckusick int unit; 13345512Smckusick { 13445512Smckusick #ifdef DEBUG 13545512Smckusick if (ppidebug & PDB_FOLLOW) 13645512Smckusick printf("ppitimo(%x)\n", unit); 13745512Smckusick #endif 13845512Smckusick ppi_softc[unit].sc_flags &= ~(PPIF_UIO|PPIF_TIMO); 13945512Smckusick wakeup(&ppi_softc[unit]); 14045512Smckusick } 14145512Smckusick 14241480Smckusick ppiread(dev, uio) 14341480Smckusick dev_t dev; 14441480Smckusick struct uio *uio; 14541480Smckusick { 14641480Smckusick 14745512Smckusick #ifdef DEBUG 14845512Smckusick if (ppidebug & PDB_FOLLOW) 14945512Smckusick printf("ppiread(%x, %x)\n", dev, uio); 15045512Smckusick #endif 15145512Smckusick return (ppirw(dev, uio)); 15241480Smckusick } 15341480Smckusick 15441480Smckusick ppiwrite(dev, uio) 15541480Smckusick dev_t dev; 15641480Smckusick struct uio *uio; 15741480Smckusick { 15841480Smckusick 15945512Smckusick #ifdef DEBUG 16045512Smckusick if (ppidebug & PDB_FOLLOW) 16145512Smckusick printf("ppiwrite(%x, %x)\n", dev, uio); 16245512Smckusick #endif 16345512Smckusick return (ppirw(dev, uio)); 16441480Smckusick } 16541480Smckusick 16645512Smckusick ppirw(dev, uio) 16741480Smckusick dev_t dev; 16841480Smckusick register struct uio *uio; 16941480Smckusick { 17045512Smckusick int unit = UNIT(dev); 17145512Smckusick register struct ppi_softc *sc = &ppi_softc[unit]; 17241480Smckusick register int s, len, cnt; 17341480Smckusick register char *cp; 17445512Smckusick int error = 0, gotdata = 0; 17545512Smckusick int buflen; 17645512Smckusick char *buf; 17741480Smckusick 17845512Smckusick if (uio->uio_resid == 0) 17945512Smckusick return(0); 18045512Smckusick 18145512Smckusick #ifdef DEBUG 18245512Smckusick if (ppidebug & (PDB_FOLLOW|PDB_IO)) 18345512Smckusick printf("ppirw(%x, %x, %c): burst %d, timo %d, resid %x\n", 18445512Smckusick dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W', 18545512Smckusick sc->sc_burst, sc->sc_timo, uio->uio_resid); 18645512Smckusick #endif 187*55068Spendry buflen = min(sc->sc_burst, uio->uio_resid); 18845512Smckusick buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); 18945512Smckusick sc->sc_flags |= PPIF_UIO; 19045512Smckusick if (sc->sc_timo > 0) { 19145512Smckusick sc->sc_flags |= PPIF_TIMO; 19245512Smckusick timeout(ppitimo, unit, sc->sc_timo); 19345512Smckusick } 19441480Smckusick while (uio->uio_resid > 0) { 195*55068Spendry len = min(buflen, uio->uio_resid); 19645512Smckusick cp = buf; 19745512Smckusick if (uio->uio_rw == UIO_WRITE) { 19841480Smckusick error = uiomove(cp, len, uio); 19941480Smckusick if (error) 20041480Smckusick break; 20141480Smckusick } 20245512Smckusick again: 20341480Smckusick s = splbio(); 20445512Smckusick if ((sc->sc_flags & PPIF_UIO) && hpibreq(&sc->sc_dq) == 0) 20545512Smckusick sleep(sc, PRIBIO+1); 20645512Smckusick /* 20745512Smckusick * Check if we timed out during sleep or uiomove 20845512Smckusick */ 20945512Smckusick (void) splsoftclock(); 21045512Smckusick if ((sc->sc_flags & PPIF_UIO) == 0) { 21145512Smckusick #ifdef DEBUG 21245512Smckusick if (ppidebug & PDB_IO) 21345512Smckusick printf("ppirw: uiomove/sleep timo, flags %x\n", 21445512Smckusick sc->sc_flags); 21545512Smckusick #endif 21645512Smckusick if (sc->sc_flags & PPIF_TIMO) { 21745512Smckusick untimeout(ppitimo, unit); 21845512Smckusick sc->sc_flags &= ~PPIF_TIMO; 21945512Smckusick } 22045512Smckusick splx(s); 22145512Smckusick break; 22245512Smckusick } 22341480Smckusick splx(s); 22445512Smckusick /* 22545512Smckusick * Perform the operation 22645512Smckusick */ 22745512Smckusick if (uio->uio_rw == UIO_WRITE) 22841480Smckusick cnt = hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 22945512Smckusick sc->sc_sec, cp, len); 23041480Smckusick else 23141480Smckusick cnt = hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 23245512Smckusick sc->sc_sec, cp, len); 23341480Smckusick s = splbio(); 23441480Smckusick hpibfree(&sc->sc_dq); 23545512Smckusick #ifdef DEBUG 23645512Smckusick if (ppidebug & PDB_IO) 23745512Smckusick printf("ppirw: %s(%d, %d, %x, %x, %d) -> %d\n", 23845512Smckusick uio->uio_rw == UIO_READ ? "recv" : "send", 23945512Smckusick sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 24045512Smckusick sc->sc_sec, cp, len, cnt); 24145512Smckusick #endif 24241480Smckusick splx(s); 24345512Smckusick if (uio->uio_rw == UIO_READ) { 24445512Smckusick if (cnt) { 24545512Smckusick error = uiomove(cp, cnt, uio); 24645512Smckusick if (error) 24745512Smckusick break; 24845512Smckusick gotdata++; 24945512Smckusick } 25045512Smckusick /* 25145512Smckusick * Didn't get anything this time, but did in the past. 25245512Smckusick * Consider us done. 25345512Smckusick */ 25445512Smckusick else if (gotdata) 25541480Smckusick break; 25641480Smckusick } 25745512Smckusick s = splsoftclock(); 25845512Smckusick /* 25945512Smckusick * Operation timeout (or non-blocking), quit now. 26045512Smckusick */ 26145512Smckusick if ((sc->sc_flags & PPIF_UIO) == 0) { 26245512Smckusick #ifdef DEBUG 26345512Smckusick if (ppidebug & PDB_IO) 26445512Smckusick printf("ppirw: timeout/done\n"); 26545512Smckusick #endif 26645512Smckusick splx(s); 26741480Smckusick break; 26841480Smckusick } 26945512Smckusick /* 27045512Smckusick * Implement inter-read delay 27145512Smckusick */ 27245512Smckusick if (sc->sc_delay > 0) { 27345512Smckusick sc->sc_flags |= PPIF_DELAY; 27445512Smckusick timeout(ppistart, unit, sc->sc_delay); 27545512Smckusick error = tsleep(sc, PCATCH|PZERO+1, "hpib", 0); 27645512Smckusick if (error) { 27745512Smckusick splx(s); 27845512Smckusick break; 27945512Smckusick } 28045512Smckusick } 28145512Smckusick splx(s); 28245512Smckusick /* 28345512Smckusick * Must not call uiomove again til we've used all data 28445512Smckusick * that we already grabbed. 28545512Smckusick */ 28645512Smckusick if (uio->uio_rw == UIO_WRITE && cnt != len) { 28745512Smckusick cp += cnt; 28845512Smckusick len -= cnt; 28945512Smckusick cnt = 0; 29045512Smckusick goto again; 29145512Smckusick } 29241480Smckusick } 29345512Smckusick s = splsoftclock(); 29445512Smckusick if (sc->sc_flags & PPIF_TIMO) { 29545512Smckusick untimeout(ppitimo, unit); 29645512Smckusick sc->sc_flags &= ~PPIF_TIMO; 29745512Smckusick } 29845512Smckusick if (sc->sc_flags & PPIF_DELAY) { 29945512Smckusick untimeout(ppistart, unit); 30045512Smckusick sc->sc_flags &= ~PPIF_DELAY; 30145512Smckusick } 30245512Smckusick splx(s); 30345512Smckusick /* 30445512Smckusick * Adjust for those chars that we uiomove'ed but never wrote 30545512Smckusick */ 30645512Smckusick if (uio->uio_rw == UIO_WRITE && cnt != len) { 30745512Smckusick uio->uio_resid += (len - cnt); 30845512Smckusick #ifdef DEBUG 30945512Smckusick if (ppidebug & PDB_IO) 31045512Smckusick printf("ppirw: short write, adjust by %d\n", 31145512Smckusick len-cnt); 31245512Smckusick #endif 31345512Smckusick } 31445512Smckusick free(buf, M_DEVBUF); 31545512Smckusick #ifdef DEBUG 31645512Smckusick if (ppidebug & (PDB_FOLLOW|PDB_IO)) 31745512Smckusick printf("ppirw: return %d, resid %d\n", error, uio->uio_resid); 31845512Smckusick #endif 31941480Smckusick return (error); 32041480Smckusick } 32145512Smckusick 32245512Smckusick ppiioctl(dev, cmd, data, flag) 32345512Smckusick dev_t dev; 32445512Smckusick int cmd; 32545512Smckusick caddr_t data; 32645512Smckusick int flag; 32745512Smckusick { 32845512Smckusick struct ppi_softc *sc = &ppi_softc[UNIT(dev)]; 32945512Smckusick struct ppiparam *pp, *upp; 33045512Smckusick int error = 0; 33145512Smckusick 33245512Smckusick switch (cmd) { 33345512Smckusick case PPIIOCGPARAM: 33445512Smckusick pp = &sc->sc_param; 33545512Smckusick upp = (struct ppiparam *)data; 33645512Smckusick upp->burst = pp->burst; 33745512Smckusick upp->timo = ppihztoms(pp->timo); 33845512Smckusick upp->delay = ppihztoms(pp->delay); 33945512Smckusick break; 34045512Smckusick case PPIIOCSPARAM: 34145512Smckusick pp = &sc->sc_param; 34245512Smckusick upp = (struct ppiparam *)data; 34345512Smckusick if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX || 34445512Smckusick upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX) 34545512Smckusick return(EINVAL); 34645512Smckusick pp->burst = upp->burst; 34745512Smckusick pp->timo = ppimstohz(upp->timo); 34845512Smckusick pp->delay = ppimstohz(upp->delay); 34945512Smckusick break; 35045512Smckusick case PPIIOCSSEC: 35145512Smckusick sc->sc_sec = *(int *)data; 35245512Smckusick break; 35345512Smckusick default: 35445512Smckusick return(EINVAL); 35545512Smckusick } 35645512Smckusick return (error); 35745512Smckusick } 35845512Smckusick 35945512Smckusick ppihztoms(h) 36045512Smckusick int h; 36145512Smckusick { 36245512Smckusick extern int hz; 36345512Smckusick register int m = h; 36445512Smckusick 36545512Smckusick if (m > 0) 36645512Smckusick m = m * 1000 / hz; 36745512Smckusick return(m); 36845512Smckusick } 36945512Smckusick 37045512Smckusick ppimstohz(m) 37145512Smckusick int m; 37245512Smckusick { 37345512Smckusick extern int hz; 37445512Smckusick register int h = m; 37545512Smckusick 37645512Smckusick if (h > 0) { 37745512Smckusick h = h * hz / 1000; 37845512Smckusick if (h == 0) 37945512Smckusick h = 1000 / hz; 38045512Smckusick } 38145512Smckusick return(h); 38245512Smckusick } 38341480Smckusick #endif 384