xref: /csrg-svn/sys/hp300/dev/ppi.c (revision 55068)
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