xref: /openbsd/sys/dev/sbus/spif.c (revision 1525749f)
1*1525749fSvisa /*	$OpenBSD: spif.c,v 1.27 2022/07/02 08:50:42 visa Exp $	*/
2a8cebae3Sjason 
3a8cebae3Sjason /*
4a8cebae3Sjason  * Copyright (c) 1999-2002 Jason L. Wright (jason@thought.net)
5a8cebae3Sjason  * All rights reserved.
6a8cebae3Sjason  *
7a8cebae3Sjason  * Redistribution and use in source and binary forms, with or without
8a8cebae3Sjason  * modification, are permitted provided that the following conditions
9a8cebae3Sjason  * are met:
10a8cebae3Sjason  * 1. Redistributions of source code must retain the above copyright
11a8cebae3Sjason  *    notice, this list of conditions and the following disclaimer.
12a8cebae3Sjason  * 2. Redistributions in binary form must reproduce the above copyright
13a8cebae3Sjason  *    notice, this list of conditions and the following disclaimer in the
14a8cebae3Sjason  *    documentation and/or other materials provided with the distribution.
15a8cebae3Sjason  *
16a8cebae3Sjason  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17a8cebae3Sjason  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18a8cebae3Sjason  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19a8cebae3Sjason  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20a8cebae3Sjason  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21a8cebae3Sjason  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22a8cebae3Sjason  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23a8cebae3Sjason  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24a8cebae3Sjason  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25a8cebae3Sjason  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26a8cebae3Sjason  * POSSIBILITY OF SUCH DAMAGE.
275248d82bSjason  *
285248d82bSjason  * Effort sponsored in part by the Defense Advanced Research Projects
295248d82bSjason  * Agency (DARPA) and Air Force Research Laboratory, Air Force
305248d82bSjason  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
315248d82bSjason  *
32a8cebae3Sjason  */
33a8cebae3Sjason 
34a8cebae3Sjason /*
35a8cebae3Sjason  * Driver for the SUNW,spif: 8 serial, 1 parallel sbus board
36a8cebae3Sjason  * based heavily on Iain Hibbert's driver for the MAGMA cards
37a8cebae3Sjason  */
38a8cebae3Sjason 
39a8cebae3Sjason #include <sys/param.h>
40a8cebae3Sjason #include <sys/systm.h>
41a8cebae3Sjason #include <sys/proc.h>
42a8cebae3Sjason #include <sys/device.h>
43a8cebae3Sjason #include <sys/kernel.h>
44c0cd3489Sguenther #include <sys/fcntl.h>
45a8cebae3Sjason #include <sys/errno.h>
46a8cebae3Sjason #include <sys/ioctl.h>
47a8cebae3Sjason #include <sys/mbuf.h>
48a8cebae3Sjason #include <sys/socket.h>
49a8cebae3Sjason #include <sys/syslog.h>
50a8cebae3Sjason #include <sys/malloc.h>
51a8cebae3Sjason #include <sys/tty.h>
52a8cebae3Sjason #include <sys/conf.h>
53a8cebae3Sjason 
54a8cebae3Sjason #include <machine/autoconf.h>
55a8cebae3Sjason #include <dev/sbus/sbusvar.h>
56a8cebae3Sjason #include <dev/sbus/spifreg.h>
57a8cebae3Sjason #include <dev/sbus/spifvar.h>
58a8cebae3Sjason 
59c4071fd1Smillert int	spifmatch(struct device *, void *, void *);
60c4071fd1Smillert void	spifattach(struct device *, struct device *, void *);
61a8cebae3Sjason 
62c4071fd1Smillert int	sttymatch(struct device *, void *, void *);
63c4071fd1Smillert void	sttyattach(struct device *, struct device *, void *);
64c4071fd1Smillert int	sttyopen(dev_t, int, int, struct proc *);
65c4071fd1Smillert int	sttyclose(dev_t, int, int, struct proc *);
66c4071fd1Smillert int	sttyread(dev_t, struct uio *, int);
67c4071fd1Smillert int	sttywrite(dev_t, struct uio *, int);
68c4071fd1Smillert int	sttyioctl(dev_t, u_long, caddr_t, int, struct proc *);
69c4071fd1Smillert int	sttystop(struct tty *, int);
70a8cebae3Sjason 
71c4071fd1Smillert int	spifstcintr(void *);
72c4071fd1Smillert int	spifstcintr_mx(struct spif_softc *, int *);
73c4071fd1Smillert int	spifstcintr_tx(struct spif_softc *, int *);
74c4071fd1Smillert int	spifstcintr_rx(struct spif_softc *, int *);
75c4071fd1Smillert int	spifstcintr_rxexception(struct spif_softc *, int *);
76c4071fd1Smillert void	spifsoftintr(void *);
77a8cebae3Sjason 
78c4071fd1Smillert int	stty_param(struct tty *, struct termios *);
79c4071fd1Smillert struct tty *sttytty(dev_t);
80c4071fd1Smillert int	stty_modem_control(struct stty_port *, int, int);
81c4071fd1Smillert void	stty_write_ccr(struct spif_softc *, u_int8_t);
82c4071fd1Smillert int	stty_compute_baud(speed_t, int, u_int8_t *, u_int8_t *);
83c4071fd1Smillert void	stty_start(struct tty *);
84a8cebae3Sjason 
85c4071fd1Smillert int	sbppmatch(struct device *, void *, void *);
86c4071fd1Smillert void	sbppattach(struct device *, struct device *, void *);
87c4071fd1Smillert int	sbppopen(dev_t, int, int, struct proc *);
88c4071fd1Smillert int	sbppclose(dev_t, int, int, struct proc *);
89c4071fd1Smillert int	sbppread(dev_t, struct uio *, int);
90c4071fd1Smillert int	sbppwrite(dev_t, struct uio *, int);
91c4071fd1Smillert int	sbpp_rw(dev_t, struct uio *);
92c4071fd1Smillert int	spifppcintr(void *);
9354e8de3eSmpi int	sbppkqfilter(dev_t, struct knote *);
94c4071fd1Smillert int	sbppioctl(dev_t, u_long, caddr_t, int, struct proc *);
95a8cebae3Sjason 
9622e452dfSmpi const struct cfattach spif_ca = {
97a8cebae3Sjason 	sizeof (struct spif_softc), spifmatch, spifattach
98a8cebae3Sjason };
99a8cebae3Sjason 
100a8cebae3Sjason struct cfdriver spif_cd = {
101a8cebae3Sjason 	NULL, "spif", DV_DULL
102a8cebae3Sjason };
103a8cebae3Sjason 
10422e452dfSmpi const struct cfattach stty_ca = {
105a8cebae3Sjason 	sizeof(struct stty_softc), sttymatch, sttyattach
106a8cebae3Sjason };
107a8cebae3Sjason 
108a8cebae3Sjason struct cfdriver stty_cd = {
109a8cebae3Sjason 	NULL, "stty", DV_TTY
110a8cebae3Sjason };
111a8cebae3Sjason 
11222e452dfSmpi const struct cfattach sbpp_ca = {
113a8cebae3Sjason 	sizeof(struct sbpp_softc), sbppmatch, sbppattach
114a8cebae3Sjason };
115a8cebae3Sjason 
116a8cebae3Sjason struct cfdriver sbpp_cd = {
117a8cebae3Sjason 	NULL, "sbpp", DV_DULL
118a8cebae3Sjason };
119a8cebae3Sjason 
120a8cebae3Sjason /* normal STC access */
121a8cebae3Sjason #define	STC_WRITE(sc,r,v)	\
122a8cebae3Sjason     bus_space_write_1((sc)->sc_bustag, (sc)->sc_stch, (r), (v))
123a8cebae3Sjason #define	STC_READ(sc,r)		\
124a8cebae3Sjason     bus_space_read_1((sc)->sc_bustag, (sc)->sc_stch, (r))
125a8cebae3Sjason 
126a8cebae3Sjason /* IACK STC access */
127a8cebae3Sjason #define	ISTC_WRITE(sc,r,v)	\
128a8cebae3Sjason     bus_space_write_1((sc)->sc_bustag, (sc)->sc_istch, (r), (v))
129a8cebae3Sjason #define	ISTC_READ(sc,r)		\
130a8cebae3Sjason     bus_space_read_1((sc)->sc_bustag, (sc)->sc_istch, (r))
131a8cebae3Sjason 
132a8cebae3Sjason /* PPC access */
133a8cebae3Sjason #define	PPC_WRITE(sc,r,v)	\
134a8cebae3Sjason     bus_space_write_1((sc)->sc_bustag, (sc)->sc_ppch, (r), (v))
135a8cebae3Sjason #define	PPC_READ(sc,r)		\
136a8cebae3Sjason     bus_space_read_1((sc)->sc_bustag, (sc)->sc_ppch, (r))
137a8cebae3Sjason 
138a8cebae3Sjason #define	DTR_WRITE(sc,port,v)						\
139a8cebae3Sjason     do {								\
140a8cebae3Sjason 	sc->sc_ttys->sc_port[(port)].sp_dtr = v;			\
141a8cebae3Sjason 	bus_space_write_1((sc)->sc_bustag,				\
142a8cebae3Sjason 	    sc->sc_dtrh, port, (v == 0) ? 1 : 0);			\
143a8cebae3Sjason     } while (0)
144a8cebae3Sjason 
145a8cebae3Sjason #define	DTR_READ(sc,port)	((sc)->sc_ttys->sc_port[(port)].sp_dtr)
146a8cebae3Sjason 
147a8cebae3Sjason int
spifmatch(struct device * parent,void * vcf,void * aux)1487b598489Sclaudio spifmatch(struct device *parent, void *vcf, void *aux)
149a8cebae3Sjason {
150a8cebae3Sjason 	struct cfdata *cf = vcf;
151a8cebae3Sjason 	struct sbus_attach_args *sa = aux;
152a8cebae3Sjason 
153a8cebae3Sjason 	if (strcmp(cf->cf_driver->cd_name, sa->sa_name) &&
154a8cebae3Sjason 	    strcmp("SUNW,spif", sa->sa_name))
155a8cebae3Sjason 		return (0);
156a8cebae3Sjason 	return (1);
157a8cebae3Sjason }
158a8cebae3Sjason 
159a8cebae3Sjason void
spifattach(struct device * parent,struct device * self,void * aux)1607b598489Sclaudio spifattach(struct device *parent, struct device *self, void *aux)
161a8cebae3Sjason {
162a8cebae3Sjason 	struct spif_softc *sc = (struct spif_softc *)self;
163a8cebae3Sjason 	struct sbus_attach_args *sa = aux;
164a8cebae3Sjason 
165a8cebae3Sjason 	if (sa->sa_nintr != 2) {
166f7d4f266Sjason 		printf(": expected %d interrupts, got %d\n", 2, sa->sa_nintr);
167a8cebae3Sjason 		return;
168a8cebae3Sjason 	}
169a8cebae3Sjason 
170a8cebae3Sjason 	if (sa->sa_nreg != 1) {
171f7d4f266Sjason 		printf(": expected %d registers, got %d\n", 1, sa->sa_nreg);
172a8cebae3Sjason 		return;
173a8cebae3Sjason 	}
174a8cebae3Sjason 
175a8cebae3Sjason 	sc->sc_bustag = sa->sa_bustag;
176a8cebae3Sjason 	if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
177a8cebae3Sjason 	    sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size,
17817e4949aSjason 	    0, 0, &sc->sc_regh) != 0) {
179a8cebae3Sjason 		printf(": can't map registers\n");
180a8cebae3Sjason 		return;
181a8cebae3Sjason 	}
182a8cebae3Sjason 
183a8cebae3Sjason 	if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
184a8cebae3Sjason 	    DTR_REG_OFFSET, DTR_REG_LEN, &sc->sc_dtrh) != 0) {
185a8cebae3Sjason 		printf(": can't map dtr regs\n");
186f7d4f266Sjason 		goto fail_unmapregs;
187a8cebae3Sjason 	}
188a8cebae3Sjason 
189a8cebae3Sjason 	if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
190a8cebae3Sjason 	    STC_REG_OFFSET, STC_REG_LEN, &sc->sc_stch) != 0) {
191a8cebae3Sjason 		printf(": can't map dtr regs\n");
192f7d4f266Sjason 		goto fail_unmapregs;
193a8cebae3Sjason 	}
194a8cebae3Sjason 
195a8cebae3Sjason 	if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
196a8cebae3Sjason 	    ISTC_REG_OFFSET, ISTC_REG_LEN, &sc->sc_istch) != 0) {
197a8cebae3Sjason 		printf(": can't map dtr regs\n");
198f7d4f266Sjason 		goto fail_unmapregs;
199a8cebae3Sjason 	}
200a8cebae3Sjason 
201a8cebae3Sjason 	if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
202a8cebae3Sjason 	    PPC_REG_OFFSET, PPC_REG_LEN, &sc->sc_ppch) != 0) {
203a8cebae3Sjason 		printf(": can't map dtr regs\n");
204f7d4f266Sjason 		goto fail_unmapregs;
205a8cebae3Sjason 	}
206a8cebae3Sjason 
207a8cebae3Sjason 	sc->sc_ppcih = bus_intr_establish(sa->sa_bustag,
20885729938Shenric 	    sa->sa_intr[PARALLEL_INTR].sbi_pri, IPL_TTY, 0, spifppcintr, sc,
20985729938Shenric 	    self->dv_xname);
210a8cebae3Sjason 	if (sc->sc_ppcih == NULL) {
211a8cebae3Sjason 		printf(": failed to establish ppc interrupt\n");
212f7d4f266Sjason 		goto fail_unmapregs;
213a8cebae3Sjason 	}
214a8cebae3Sjason 
215a8cebae3Sjason 	sc->sc_stcih = bus_intr_establish(sa->sa_bustag,
21685729938Shenric 	    sa->sa_intr[SERIAL_INTR].sbi_pri, IPL_TTY, 0, spifstcintr, sc,
21785729938Shenric 	    self->dv_xname);
218a8cebae3Sjason 	if (sc->sc_stcih == NULL) {
219a8cebae3Sjason 		printf(": failed to establish stc interrupt\n");
220f7d4f266Sjason 		goto fail_unmapregs;
221a8cebae3Sjason 	}
222a8cebae3Sjason 
223a8cebae3Sjason 	sc->sc_softih = softintr_establish(IPL_TTY, spifsoftintr, sc);
224a8cebae3Sjason 	if (sc->sc_softih == NULL) {
225a8cebae3Sjason 		printf(": can't get soft intr\n");
226f7d4f266Sjason 		goto fail_unmapregs;
227a8cebae3Sjason 	}
228a8cebae3Sjason 
229a8cebae3Sjason 	sc->sc_node = sa->sa_node;
230a8cebae3Sjason 
231a8cebae3Sjason 	sc->sc_rev = getpropint(sc->sc_node, "revlev", 0);
232a8cebae3Sjason 
233a8cebae3Sjason 	sc->sc_osc = getpropint(sc->sc_node, "verosc", 0);
234a8cebae3Sjason 	switch (sc->sc_osc) {
235a8cebae3Sjason 	case SPIF_OSC10:
236a8cebae3Sjason 		sc->sc_osc = 10000000;
237a8cebae3Sjason 		break;
238a8cebae3Sjason 	case SPIF_OSC9:
239a8cebae3Sjason 	default:
240a8cebae3Sjason 		sc->sc_osc = 9830400;
241a8cebae3Sjason 		break;
242a8cebae3Sjason 	}
243a8cebae3Sjason 
244a8cebae3Sjason 	sc->sc_nser = 8;
245a8cebae3Sjason 	sc->sc_npar = 1;
246a8cebae3Sjason 
247a8cebae3Sjason 	sc->sc_rev2 = STC_READ(sc, STC_GFRCR);
248a8cebae3Sjason 	STC_WRITE(sc, STC_GSVR, 0);
249a8cebae3Sjason 
250a8cebae3Sjason 	stty_write_ccr(sc, CD180_CCR_CMD_RESET | CD180_CCR_RESETALL);
251a8cebae3Sjason 	while (STC_READ(sc, STC_GSVR) != 0xff);
252a8cebae3Sjason 	while (STC_READ(sc, STC_GFRCR) != sc->sc_rev2);
253a8cebae3Sjason 
254a8cebae3Sjason 	STC_WRITE(sc, STC_PPRH, CD180_PPRH);
255a8cebae3Sjason 	STC_WRITE(sc, STC_PPRL, CD180_PPRL);
256a8cebae3Sjason 	STC_WRITE(sc, STC_MSMR, SPIF_MSMR);
257a8cebae3Sjason 	STC_WRITE(sc, STC_TSMR, SPIF_TSMR);
258a8cebae3Sjason 	STC_WRITE(sc, STC_RSMR, SPIF_RSMR);
259a8cebae3Sjason 	STC_WRITE(sc, STC_GSVR, 0);
260a8cebae3Sjason 	STC_WRITE(sc, STC_GSCR1, 0);
261a8cebae3Sjason 	STC_WRITE(sc, STC_GSCR2, 0);
262a8cebae3Sjason 	STC_WRITE(sc, STC_GSCR3, 0);
263a8cebae3Sjason 
26454c6c021Smickey 	printf(": rev %x chiprev %x osc %sMHz\n",
265a8cebae3Sjason 	    sc->sc_rev, sc->sc_rev2, clockfreq(sc->sc_osc));
266a8cebae3Sjason 
267a8cebae3Sjason 	(void)config_found(self, sttymatch, NULL);
268a8cebae3Sjason 	(void)config_found(self, sbppmatch, NULL);
269f7d4f266Sjason 
270f7d4f266Sjason 	return;
271f7d4f266Sjason 
272f7d4f266Sjason fail_unmapregs:
273f7d4f266Sjason 	bus_space_unmap(sa->sa_bustag, sc->sc_regh, sa->sa_reg[0].sbr_size);
274a8cebae3Sjason }
275a8cebae3Sjason 
276a8cebae3Sjason int
sttymatch(struct device * parent,void * vcf,void * aux)2777b598489Sclaudio sttymatch(struct device *parent, void *vcf, void *aux)
278a8cebae3Sjason {
279a8cebae3Sjason 	struct spif_softc *sc = (struct spif_softc *)parent;
280a8cebae3Sjason 
281a8cebae3Sjason 	return (aux == sttymatch && sc->sc_ttys == NULL);
282a8cebae3Sjason }
283a8cebae3Sjason 
284a8cebae3Sjason void
sttyattach(struct device * parent,struct device * dev,void * aux)2857b598489Sclaudio sttyattach(struct device *parent, struct device *dev, void *aux)
286a8cebae3Sjason {
287a8cebae3Sjason 	struct spif_softc *sc = (struct spif_softc *)parent;
288a8cebae3Sjason 	struct stty_softc *ssc = (struct stty_softc *)dev;
289a8cebae3Sjason 	int port;
290a8cebae3Sjason 
291a8cebae3Sjason 	sc->sc_ttys = ssc;
292a8cebae3Sjason 
293a8cebae3Sjason 	for (port = 0; port < sc->sc_nser; port++) {
294a8cebae3Sjason 		struct stty_port *sp = &ssc->sc_port[port];
295a8cebae3Sjason 		struct tty *tp;
296a8cebae3Sjason 
297a8cebae3Sjason 		DTR_WRITE(sc, port, 0);
298a8cebae3Sjason 
299197ff252Sderaadt 		tp = ttymalloc(0);
300a8cebae3Sjason 
301a8cebae3Sjason 		tp->t_oproc = stty_start;
302a8cebae3Sjason 		tp->t_param = stty_param;
303a8cebae3Sjason 
304a8cebae3Sjason 		sp->sp_tty = tp;
305a8cebae3Sjason 		sp->sp_sc = sc;
306a8cebae3Sjason 		sp->sp_channel = port;
307a8cebae3Sjason 
308a8cebae3Sjason 		sp->sp_rbuf = malloc(STTY_RBUF_SIZE, M_DEVBUF, M_NOWAIT);
309a8cebae3Sjason 		if(sp->sp_rbuf == NULL)
310a8cebae3Sjason 			break;
311a8cebae3Sjason 
312a8cebae3Sjason 		sp->sp_rend = sp->sp_rbuf + STTY_RBUF_SIZE;
313a8cebae3Sjason 	}
314a8cebae3Sjason 
315a8cebae3Sjason 	ssc->sc_nports = port;
316a8cebae3Sjason 
317a8cebae3Sjason 	printf(": %d tty%s\n", port, port == 1 ? "" : "s");
318a8cebae3Sjason }
319a8cebae3Sjason 
320a8cebae3Sjason int
sttyopen(dev_t dev,int flags,int mode,struct proc * p)3217b598489Sclaudio sttyopen(dev_t dev, int flags, int mode, struct proc *p)
322a8cebae3Sjason {
323a8cebae3Sjason 	struct spif_softc *csc;
324a8cebae3Sjason 	struct stty_softc *sc;
325a8cebae3Sjason 	struct stty_port *sp;
326a8cebae3Sjason 	struct tty *tp;
327a8cebae3Sjason 	int card = SPIF_CARD(dev);
328a8cebae3Sjason 	int port = SPIF_PORT(dev);
329a8cebae3Sjason 	int s;
330a8cebae3Sjason 
331a8cebae3Sjason 	if (card >= stty_cd.cd_ndevs || card >= spif_cd.cd_ndevs)
332a8cebae3Sjason 		return (ENXIO);
333a8cebae3Sjason 
334a8cebae3Sjason 	sc = stty_cd.cd_devs[card];
335a8cebae3Sjason 	csc = spif_cd.cd_devs[card];
336f7d4f266Sjason 	if (sc == NULL || csc == NULL)
337a8cebae3Sjason 		return (ENXIO);
338a8cebae3Sjason 
339a8cebae3Sjason 	if (port >= sc->sc_nports)
340a8cebae3Sjason 		return (ENXIO);
341a8cebae3Sjason 
342a8cebae3Sjason 	sp = &sc->sc_port[port];
343a8cebae3Sjason 	tp = sp->sp_tty;
344a8cebae3Sjason 	tp->t_dev = dev;
345a8cebae3Sjason 
346a8cebae3Sjason 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
347a8cebae3Sjason 		SET(tp->t_state, TS_WOPEN);
348a8cebae3Sjason 
349a8cebae3Sjason 		ttychars(tp);
350a8cebae3Sjason 		tp->t_iflag = TTYDEF_IFLAG;
351a8cebae3Sjason 		tp->t_oflag = TTYDEF_OFLAG;
352a8cebae3Sjason 		tp->t_cflag = TTYDEF_CFLAG;
353a8cebae3Sjason 		if (ISSET(sp->sp_openflags, TIOCFLAG_CLOCAL))
354a8cebae3Sjason 			SET(tp->t_cflag, CLOCAL);
355a8cebae3Sjason 		if (ISSET(sp->sp_openflags, TIOCFLAG_CRTSCTS))
356a8cebae3Sjason 			SET(tp->t_cflag, CRTSCTS);
357a8cebae3Sjason 		if (ISSET(sp->sp_openflags, TIOCFLAG_MDMBUF))
358a8cebae3Sjason 			SET(tp->t_cflag, MDMBUF);
359a8cebae3Sjason 		tp->t_lflag = TTYDEF_LFLAG;
360a8cebae3Sjason 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
361a8cebae3Sjason 
362a8cebae3Sjason 		sp->sp_rput = sp->sp_rget = sp->sp_rbuf;
363a8cebae3Sjason 
364a8cebae3Sjason 		s = spltty();
365a8cebae3Sjason 
366a8cebae3Sjason 		STC_WRITE(csc, STC_CAR, sp->sp_channel);
367a8cebae3Sjason 		stty_write_ccr(csc, CD180_CCR_CMD_RESET|CD180_CCR_RESETCHAN);
368a8cebae3Sjason 		STC_WRITE(csc, STC_CAR, sp->sp_channel);
369a8cebae3Sjason 
370a8cebae3Sjason 		stty_param(tp, &tp->t_termios);
371a8cebae3Sjason 
372a8cebae3Sjason 		ttsetwater(tp);
373a8cebae3Sjason 
374a8cebae3Sjason 		STC_WRITE(csc, STC_SRER, CD180_SRER_CD | CD180_SRER_RXD);
375a8cebae3Sjason 
376a8cebae3Sjason 		if (ISSET(sp->sp_openflags, TIOCFLAG_SOFTCAR) || sp->sp_carrier)
377a8cebae3Sjason 			SET(tp->t_state, TS_CARR_ON);
378a8cebae3Sjason 		else
379a8cebae3Sjason 			CLR(tp->t_state, TS_CARR_ON);
380a8cebae3Sjason 	}
3813e676399Smpi 	else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0) {
382a8cebae3Sjason 		return (EBUSY);
383a8cebae3Sjason 	} else {
384a8cebae3Sjason 		s = spltty();
385a8cebae3Sjason 	}
386a8cebae3Sjason 
387a8cebae3Sjason 	if (!ISSET(flags, O_NONBLOCK)) {
388a8cebae3Sjason 		while (!ISSET(tp->t_cflag, CLOCAL) &&
389a8cebae3Sjason 		    !ISSET(tp->t_state, TS_CARR_ON)) {
390a8cebae3Sjason 			int error;
391a8cebae3Sjason 
392a8cebae3Sjason 			SET(tp->t_state, TS_WOPEN);
393a8cebae3Sjason 			error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
39476d1ff0eSjan 			    ttopen);
395a8cebae3Sjason 			if (error != 0) {
396a8cebae3Sjason 				splx(s);
397a8cebae3Sjason 				CLR(tp->t_state, TS_WOPEN);
398a8cebae3Sjason 				return (error);
399a8cebae3Sjason 			}
400a8cebae3Sjason 		}
401a8cebae3Sjason 	}
402a8cebae3Sjason 
403a8cebae3Sjason 	splx(s);
404a8cebae3Sjason 
40579f6c33aStedu 	return ((*linesw[tp->t_line].l_open)(dev, tp, p));
406a8cebae3Sjason }
407a8cebae3Sjason 
408a8cebae3Sjason int
sttyclose(dev_t dev,int flags,int mode,struct proc * p)4097b598489Sclaudio sttyclose(dev_t dev, int flags, int mode, struct proc *p)
410a8cebae3Sjason {
411a8cebae3Sjason 	struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
412a8cebae3Sjason 	struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
413a8cebae3Sjason 	struct spif_softc *csc = sp->sp_sc;
414a8cebae3Sjason 	struct tty *tp = sp->sp_tty;
415a8cebae3Sjason 	int port = SPIF_PORT(dev);
416a8cebae3Sjason 	int s;
417a8cebae3Sjason 
41879f6c33aStedu 	(*linesw[tp->t_line].l_close)(tp, flags, p);
419a8cebae3Sjason 	s = spltty();
420a8cebae3Sjason 
421a8cebae3Sjason 	if (ISSET(tp->t_cflag, HUPCL) || !ISSET(tp->t_state, TS_ISOPEN)) {
422a8cebae3Sjason 		stty_modem_control(sp, 0, DMSET);
423a8cebae3Sjason 		STC_WRITE(csc, STC_CAR, port);
424a8cebae3Sjason 		STC_WRITE(csc, STC_CCR,
425a8cebae3Sjason 		    CD180_CCR_CMD_RESET|CD180_CCR_RESETCHAN);
426a8cebae3Sjason 	}
427a8cebae3Sjason 
428a8cebae3Sjason 	splx(s);
429a8cebae3Sjason 	ttyclose(tp);
430a8cebae3Sjason 	return (0);
431a8cebae3Sjason }
432a8cebae3Sjason 
433a8cebae3Sjason int
sttyioctl(dev_t dev,u_long cmd,caddr_t data,int flags,struct proc * p)4347b598489Sclaudio sttyioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
435a8cebae3Sjason {
436a8cebae3Sjason 	struct stty_softc *stc = stty_cd.cd_devs[SPIF_CARD(dev)];
437a8cebae3Sjason 	struct stty_port *sp = &stc->sc_port[SPIF_PORT(dev)];
438a8cebae3Sjason 	struct spif_softc *sc = sp->sp_sc;
439a8cebae3Sjason 	struct tty *tp = sp->sp_tty;
440a8cebae3Sjason 	int error;
441a8cebae3Sjason 
442a8cebae3Sjason 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, p);
443a8cebae3Sjason 	if (error >= 0)
444a8cebae3Sjason 		return (error);
445a8cebae3Sjason 
446a8cebae3Sjason 	error = ttioctl(tp, cmd, data, flags, p);
447a8cebae3Sjason 	if (error >= 0)
448a8cebae3Sjason 		return (error);
449a8cebae3Sjason 
450a8cebae3Sjason 	error = 0;
451a8cebae3Sjason 
452a8cebae3Sjason 	switch (cmd) {
453a8cebae3Sjason 	case TIOCSBRK:
454a8cebae3Sjason 		SET(sp->sp_flags, STTYF_SET_BREAK);
455a8cebae3Sjason 		STC_WRITE(sc, STC_CAR, sp->sp_channel);
456a8cebae3Sjason 		STC_WRITE(sc, STC_SRER,
457a8cebae3Sjason 		    STC_READ(sc, STC_SRER) | CD180_SRER_TXD);
458a8cebae3Sjason 		break;
459a8cebae3Sjason 	case TIOCCBRK:
460a8cebae3Sjason 		SET(sp->sp_flags, STTYF_CLR_BREAK);
461a8cebae3Sjason 		STC_WRITE(sc, STC_CAR, sp->sp_channel);
462a8cebae3Sjason 		STC_WRITE(sc, STC_SRER,
463a8cebae3Sjason 		    STC_READ(sc, STC_SRER) | CD180_SRER_TXD);
464a8cebae3Sjason 		break;
465a8cebae3Sjason 	case TIOCSDTR:
466a8cebae3Sjason 		stty_modem_control(sp, TIOCM_DTR, DMBIS);
467a8cebae3Sjason 		break;
468a8cebae3Sjason 	case TIOCCDTR:
469a8cebae3Sjason 		stty_modem_control(sp, TIOCM_DTR, DMBIC);
470a8cebae3Sjason 		break;
471a8cebae3Sjason 	case TIOCMBIS:
472a8cebae3Sjason 		stty_modem_control(sp, *((int *)data), DMBIS);
473a8cebae3Sjason 		break;
474a8cebae3Sjason 	case TIOCMBIC:
475a8cebae3Sjason 		stty_modem_control(sp, *((int *)data), DMBIC);
476a8cebae3Sjason 		break;
477a8cebae3Sjason 	case TIOCMGET:
478a8cebae3Sjason 		*((int *)data) = stty_modem_control(sp, 0, DMGET);
479a8cebae3Sjason 		break;
480a8cebae3Sjason 	case TIOCMSET:
481a8cebae3Sjason 		stty_modem_control(sp, *((int *)data), DMSET);
482a8cebae3Sjason 		break;
483a8cebae3Sjason 	case TIOCGFLAGS:
484a8cebae3Sjason 		*((int *)data) = sp->sp_openflags;
485a8cebae3Sjason 		break;
486a8cebae3Sjason 	case TIOCSFLAGS:
4873e676399Smpi 		if (suser(p))
488a8cebae3Sjason 			error = EPERM;
489a8cebae3Sjason 		else
490a8cebae3Sjason 			sp->sp_openflags = *((int *)data) &
491a8cebae3Sjason 			    (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL |
492a8cebae3Sjason 			     TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF);
493a8cebae3Sjason 		break;
494a8cebae3Sjason 	default:
495a8cebae3Sjason 		error = ENOTTY;
496a8cebae3Sjason 	}
497a8cebae3Sjason 
498a8cebae3Sjason 	return (error);
499a8cebae3Sjason }
500a8cebae3Sjason 
501a8cebae3Sjason int
stty_modem_control(struct stty_port * sp,int bits,int how)5027b598489Sclaudio stty_modem_control(struct stty_port *sp, int bits, int how)
503a8cebae3Sjason {
504a8cebae3Sjason 	struct spif_softc *csc = sp->sp_sc;
505a8cebae3Sjason 	struct tty *tp = sp->sp_tty;
506a8cebae3Sjason 	int s, msvr;
507a8cebae3Sjason 
508a8cebae3Sjason 	s = spltty();
509a8cebae3Sjason 	STC_WRITE(csc, STC_CAR, sp->sp_channel);
510a8cebae3Sjason 
511a8cebae3Sjason 	switch (how) {
512a8cebae3Sjason 	case DMGET:
513a8cebae3Sjason 		bits = TIOCM_LE;
514a8cebae3Sjason 		if (DTR_READ(csc, sp->sp_channel))
515a8cebae3Sjason 			bits |= TIOCM_DTR;
516a8cebae3Sjason 		msvr = STC_READ(csc, STC_MSVR);
517a8cebae3Sjason 		if (ISSET(msvr, CD180_MSVR_DSR))
518a8cebae3Sjason 			bits |= TIOCM_DSR;
519a8cebae3Sjason 		if (ISSET(msvr, CD180_MSVR_CD))
520a8cebae3Sjason 			bits |= TIOCM_CD;
521a8cebae3Sjason 		if (ISSET(msvr, CD180_MSVR_CTS))
522a8cebae3Sjason 			bits |= TIOCM_CTS;
523a8cebae3Sjason 		if (ISSET(msvr, CD180_MSVR_RTS))
524a8cebae3Sjason 			bits |= TIOCM_RTS;
525a8cebae3Sjason 		break;
526a8cebae3Sjason 	case DMSET:
527a8cebae3Sjason 		DTR_WRITE(csc, sp->sp_channel, ISSET(bits, TIOCM_DTR) ? 1 : 0);
528a8cebae3Sjason 		if (ISSET(bits, TIOCM_RTS))
529a8cebae3Sjason 			STC_WRITE(csc, STC_MSVR,
530a8cebae3Sjason 			    STC_READ(csc, STC_MSVR) & (~CD180_MSVR_RTS));
531a8cebae3Sjason 		else
532a8cebae3Sjason 			STC_WRITE(csc, STC_MSVR,
533a8cebae3Sjason 			    STC_READ(csc, STC_MSVR) | CD180_MSVR_RTS);
534a8cebae3Sjason 		break;
535a8cebae3Sjason 	case DMBIS:
536a8cebae3Sjason 		if (ISSET(bits, TIOCM_DTR))
537a8cebae3Sjason 			DTR_WRITE(csc, sp->sp_channel, 1);
538a8cebae3Sjason 		if (ISSET(bits, TIOCM_RTS) && !ISSET(tp->t_cflag, CRTSCTS))
539a8cebae3Sjason 			STC_WRITE(csc, STC_MSVR,
540a8cebae3Sjason 			    STC_READ(csc, STC_MSVR) & (~CD180_MSVR_RTS));
541a8cebae3Sjason 		break;
542a8cebae3Sjason 	case DMBIC:
543a8cebae3Sjason 		if (ISSET(bits, TIOCM_DTR))
544a8cebae3Sjason 			DTR_WRITE(csc, sp->sp_channel, 0);
545a8cebae3Sjason 		if (ISSET(bits, TIOCM_RTS))
546a8cebae3Sjason 			STC_WRITE(csc, STC_MSVR,
547a8cebae3Sjason 			    STC_READ(csc, STC_MSVR) | CD180_MSVR_RTS);
548a8cebae3Sjason 		break;
549a8cebae3Sjason 	}
550a8cebae3Sjason 
551a8cebae3Sjason 	splx(s);
552a8cebae3Sjason 	return (bits);
553a8cebae3Sjason }
554a8cebae3Sjason 
555a8cebae3Sjason int
stty_param(struct tty * tp,struct termios * t)5567b598489Sclaudio stty_param(struct tty *tp, struct termios *t)
557a8cebae3Sjason {
558a8cebae3Sjason 	struct stty_softc *st = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
559a8cebae3Sjason 	struct stty_port *sp = &st->sc_port[SPIF_PORT(tp->t_dev)];
560a8cebae3Sjason 	struct spif_softc *sc = sp->sp_sc;
561a8cebae3Sjason 	u_int8_t rbprl, rbprh, tbprl, tbprh;
562a8cebae3Sjason 	int s, opt;
563a8cebae3Sjason 
564a8cebae3Sjason 	if (t->c_ospeed &&
565a8cebae3Sjason 	    stty_compute_baud(t->c_ospeed, sc->sc_osc, &tbprl, &tbprh))
566a8cebae3Sjason 		return (EINVAL);
567a8cebae3Sjason 
568a8cebae3Sjason 	if (t->c_ispeed &&
569a8cebae3Sjason 	    stty_compute_baud(t->c_ispeed, sc->sc_osc, &rbprl, &rbprh))
570a8cebae3Sjason 		return (EINVAL);
571a8cebae3Sjason 
572a8cebae3Sjason 	s = spltty();
573a8cebae3Sjason 
574a8cebae3Sjason 	/* hang up line if ospeed is zero, otherwise raise DTR */
575a8cebae3Sjason 	stty_modem_control(sp, TIOCM_DTR,
576a8cebae3Sjason 	    (t->c_ospeed == 0 ? DMBIC : DMBIS));
577a8cebae3Sjason 
578a8cebae3Sjason 	STC_WRITE(sc, STC_CAR, sp->sp_channel);
579a8cebae3Sjason 
580a8cebae3Sjason 	opt = 0;
581a8cebae3Sjason 	if (ISSET(t->c_cflag, PARENB)) {
582a8cebae3Sjason 		opt |= CD180_COR1_PARMODE_NORMAL;
583a8cebae3Sjason 		opt |= (ISSET(t->c_cflag, PARODD) ?
584a8cebae3Sjason 				CD180_COR1_ODDPAR :
585a8cebae3Sjason 				CD180_COR1_EVENPAR);
586a8cebae3Sjason 	}
587a8cebae3Sjason 	else
588a8cebae3Sjason 		opt |= CD180_COR1_PARMODE_NO;
589a8cebae3Sjason 
590a8cebae3Sjason 	if (!ISSET(t->c_iflag, INPCK))
591a8cebae3Sjason 		opt |= CD180_COR1_IGNPAR;
592a8cebae3Sjason 
593a8cebae3Sjason 	if (ISSET(t->c_cflag, CSTOPB))
594a8cebae3Sjason 		opt |= CD180_COR1_STOP2;
595a8cebae3Sjason 
596a8cebae3Sjason 	switch (t->c_cflag & CSIZE) {
597a8cebae3Sjason 	case CS5:
598a8cebae3Sjason 		opt |= CD180_COR1_CS5;
599a8cebae3Sjason 		break;
600a8cebae3Sjason 	case CS6:
601a8cebae3Sjason 		opt |= CD180_COR1_CS6;
602a8cebae3Sjason 		break;
603a8cebae3Sjason 	case CS7:
604a8cebae3Sjason 		opt |= CD180_COR1_CS7;
605a8cebae3Sjason 		break;
606a8cebae3Sjason 	default:
607a8cebae3Sjason 		opt |= CD180_COR1_CS8;
608a8cebae3Sjason 		break;
609a8cebae3Sjason 	}
610a8cebae3Sjason 	STC_WRITE(sc, STC_COR1, opt);
611a8cebae3Sjason 	stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG1);
612a8cebae3Sjason 
613a8cebae3Sjason 	opt = CD180_COR2_ETC;
614a8cebae3Sjason 	if (ISSET(t->c_cflag, CRTSCTS))
615a8cebae3Sjason 		opt |= CD180_COR2_CTSAE;
616a8cebae3Sjason 	STC_WRITE(sc, STC_COR2, opt);
617a8cebae3Sjason 	stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG2);
618a8cebae3Sjason 
619a8cebae3Sjason 	STC_WRITE(sc, STC_COR3, STTY_RX_FIFO_THRESHOLD);
620a8cebae3Sjason 	stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG3);
621a8cebae3Sjason 
622a8cebae3Sjason 	STC_WRITE(sc, STC_SCHR1, 0x11);
623a8cebae3Sjason 	STC_WRITE(sc, STC_SCHR2, 0x13);
624a8cebae3Sjason 	STC_WRITE(sc, STC_SCHR3, 0x11);
625a8cebae3Sjason 	STC_WRITE(sc, STC_SCHR4, 0x13);
626a8cebae3Sjason 	STC_WRITE(sc, STC_RTPR, 0x12);
627a8cebae3Sjason 
628a8cebae3Sjason 	STC_WRITE(sc, STC_MCOR1, CD180_MCOR1_CDZD | STTY_RX_DTR_THRESHOLD);
629a8cebae3Sjason 	STC_WRITE(sc, STC_MCOR2, CD180_MCOR2_CDOD);
630a8cebae3Sjason 	STC_WRITE(sc, STC_MCR, 0);
631a8cebae3Sjason 
632a8cebae3Sjason 	if (t->c_ospeed) {
633a8cebae3Sjason 		STC_WRITE(sc, STC_TBPRH, tbprh);
634a8cebae3Sjason 		STC_WRITE(sc, STC_TBPRL, tbprl);
635a8cebae3Sjason 	}
636a8cebae3Sjason 
637a8cebae3Sjason 	if (t->c_ispeed) {
638a8cebae3Sjason 		STC_WRITE(sc, STC_RBPRH, rbprh);
639a8cebae3Sjason 		STC_WRITE(sc, STC_RBPRL, rbprl);
640a8cebae3Sjason 	}
641a8cebae3Sjason 
642a8cebae3Sjason 	stty_write_ccr(sc, CD180_CCR_CMD_CHAN |
643a8cebae3Sjason 	    CD180_CCR_CHAN_TXEN | CD180_CCR_CHAN_RXEN);
644a8cebae3Sjason 
645a8cebae3Sjason 	sp->sp_carrier = STC_READ(sc, STC_MSVR) & CD180_MSVR_CD;
646a8cebae3Sjason 
647a8cebae3Sjason 	splx(s);
648a8cebae3Sjason 	return (0);
649a8cebae3Sjason }
650a8cebae3Sjason 
651a8cebae3Sjason int
sttyread(dev_t dev,struct uio * uio,int flags)6527b598489Sclaudio sttyread(dev_t dev, struct uio *uio, int flags)
653a8cebae3Sjason {
654a8cebae3Sjason 	struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
655a8cebae3Sjason 	struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
656a8cebae3Sjason 	struct tty *tp = sp->sp_tty;
657a8cebae3Sjason 
658a8cebae3Sjason 	return ((*linesw[tp->t_line].l_read)(tp, uio, flags));
659a8cebae3Sjason }
660a8cebae3Sjason 
661a8cebae3Sjason int
sttywrite(dev_t dev,struct uio * uio,int flags)6627b598489Sclaudio sttywrite(dev_t dev, struct uio *uio, int flags)
663a8cebae3Sjason {
664a8cebae3Sjason 	struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
665a8cebae3Sjason 	struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
666a8cebae3Sjason 	struct tty *tp = sp->sp_tty;
667a8cebae3Sjason 
668a8cebae3Sjason 	return ((*linesw[tp->t_line].l_write)(tp, uio, flags));
669a8cebae3Sjason }
670a8cebae3Sjason 
671a8cebae3Sjason struct tty *
sttytty(dev_t dev)6727b598489Sclaudio sttytty(dev_t dev)
673a8cebae3Sjason {
674a8cebae3Sjason 	struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
675a8cebae3Sjason 	struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
676a8cebae3Sjason 
677a8cebae3Sjason 	return (sp->sp_tty);
678a8cebae3Sjason }
679a8cebae3Sjason 
680a8cebae3Sjason int
sttystop(struct tty * tp,int flags)6817b598489Sclaudio sttystop(struct tty *tp, int flags)
682a8cebae3Sjason {
683a8cebae3Sjason 	struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
684a8cebae3Sjason 	struct stty_port *sp = &sc->sc_port[SPIF_PORT(tp->t_dev)];
685a8cebae3Sjason 	int s;
686a8cebae3Sjason 
687a8cebae3Sjason 	s = spltty();
688a8cebae3Sjason 	if (ISSET(tp->t_state, TS_BUSY)) {
689a8cebae3Sjason 		if (!ISSET(tp->t_state, TS_TTSTOP))
690a8cebae3Sjason 			SET(tp->t_state, TS_FLUSH);
691a8cebae3Sjason 		SET(sp->sp_flags, STTYF_STOP);
692a8cebae3Sjason 	}
693a8cebae3Sjason 	splx(s);
694a8cebae3Sjason 	return (0);
695a8cebae3Sjason }
696a8cebae3Sjason 
697a8cebae3Sjason void
stty_start(struct tty * tp)6987b598489Sclaudio stty_start(struct tty *tp)
699a8cebae3Sjason {
700a8cebae3Sjason 	struct stty_softc *stc = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
701a8cebae3Sjason 	struct stty_port *sp = &stc->sc_port[SPIF_PORT(tp->t_dev)];
702a8cebae3Sjason 	struct spif_softc *sc = sp->sp_sc;
703a8cebae3Sjason 	int s;
704a8cebae3Sjason 
705a8cebae3Sjason 	s = spltty();
706a8cebae3Sjason 
707a8cebae3Sjason 	if (!ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) {
7084cc8800eSnicm 		ttwakeupwr(tp);
709a8cebae3Sjason 		if (tp->t_outq.c_cc) {
710a8cebae3Sjason 			sp->sp_txc = ndqb(&tp->t_outq, 0);
711a8cebae3Sjason 			sp->sp_txp = tp->t_outq.c_cf;
712a8cebae3Sjason 			SET(tp->t_state, TS_BUSY);
713a8cebae3Sjason 			STC_WRITE(sc, STC_CAR, sp->sp_channel);
714a8cebae3Sjason 			STC_WRITE(sc, STC_SRER,
715a8cebae3Sjason 			    STC_READ(sc, STC_SRER) | CD180_SRER_TXD);
716a8cebae3Sjason 		}
717a8cebae3Sjason 	}
718a8cebae3Sjason 
719a8cebae3Sjason 	splx(s);
720a8cebae3Sjason }
721a8cebae3Sjason 
722a8cebae3Sjason int
spifstcintr_rxexception(struct spif_softc * sc,int * needsoftp)7237b598489Sclaudio spifstcintr_rxexception(struct spif_softc *sc, int *needsoftp)
724a8cebae3Sjason {
725a8cebae3Sjason 	struct stty_port *sp;
726a8cebae3Sjason 	u_int8_t channel, *ptr;
727a8cebae3Sjason 
728a8cebae3Sjason 	channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
729a8cebae3Sjason 	sp = &sc->sc_ttys->sc_port[channel];
730a8cebae3Sjason 	ptr = sp->sp_rput;
731a8cebae3Sjason 	*ptr++ = STC_READ(sc, STC_RCSR);
732a8cebae3Sjason 	*ptr++ = STC_READ(sc, STC_RDR);
733a8cebae3Sjason 	if (ptr == sp->sp_rend)
734a8cebae3Sjason 		ptr = sp->sp_rbuf;
735a8cebae3Sjason 	if (ptr == sp->sp_rget) {
736a8cebae3Sjason 		if (ptr == sp->sp_rbuf)
737a8cebae3Sjason 			ptr = sp->sp_rend;
738a8cebae3Sjason 		ptr -= 2;
739a8cebae3Sjason 		SET(sp->sp_flags, STTYF_RING_OVERFLOW);
740a8cebae3Sjason 	}
741a8cebae3Sjason 	STC_WRITE(sc, STC_EOSRR, 0);
742a8cebae3Sjason 	*needsoftp = 1;
743a8cebae3Sjason 	sp->sp_rput = ptr;
744a8cebae3Sjason 	return (1);
745a8cebae3Sjason }
746a8cebae3Sjason 
747a8cebae3Sjason int
spifstcintr_rx(struct spif_softc * sc,int * needsoftp)7487b598489Sclaudio spifstcintr_rx(struct spif_softc *sc, int *needsoftp)
749a8cebae3Sjason {
750a8cebae3Sjason 	struct stty_port *sp;
751a8cebae3Sjason 	u_int8_t channel, *ptr, cnt, rcsr;
752a8cebae3Sjason 	int i;
753a8cebae3Sjason 
754a8cebae3Sjason 	channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
755a8cebae3Sjason 	sp = &sc->sc_ttys->sc_port[channel];
756a8cebae3Sjason 	ptr = sp->sp_rput;
757a8cebae3Sjason 	cnt = STC_READ(sc, STC_RDCR);
758a8cebae3Sjason 	for (i = 0; i < cnt; i++) {
759a8cebae3Sjason 		*ptr++ = 0;
760a8cebae3Sjason 		rcsr = STC_READ(sc, STC_RCSR);
761a8cebae3Sjason 		*ptr++ = STC_READ(sc, STC_RDR);
762a8cebae3Sjason 		if (ptr == sp->sp_rend)
763a8cebae3Sjason 			ptr = sp->sp_rbuf;
764a8cebae3Sjason 		if (ptr == sp->sp_rget) {
765a8cebae3Sjason 			if (ptr == sp->sp_rbuf)
766a8cebae3Sjason 				ptr = sp->sp_rend;
767a8cebae3Sjason 			ptr -= 2;
768a8cebae3Sjason 			SET(sp->sp_flags, STTYF_RING_OVERFLOW);
769a8cebae3Sjason 			break;
770a8cebae3Sjason 		}
771a8cebae3Sjason 	}
772a8cebae3Sjason 	STC_WRITE(sc, STC_EOSRR, 0);
773a8cebae3Sjason 	if (cnt) {
774a8cebae3Sjason 		*needsoftp = 1;
775a8cebae3Sjason 		sp->sp_rput = ptr;
776a8cebae3Sjason 	}
777a8cebae3Sjason 	return (1);
778a8cebae3Sjason }
779a8cebae3Sjason 
780a8cebae3Sjason int
spifstcintr_tx(struct spif_softc * sc,int * needsoftp)7817b598489Sclaudio spifstcintr_tx(struct spif_softc *sc, int *needsoftp)
782a8cebae3Sjason {
783a8cebae3Sjason 	struct stty_port *sp;
784a8cebae3Sjason 	u_int8_t channel, ch;
785a8cebae3Sjason 	int cnt = 0;
786a8cebae3Sjason 
787a8cebae3Sjason 	channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
788a8cebae3Sjason 	sp = &sc->sc_ttys->sc_port[channel];
789a8cebae3Sjason 	if (!ISSET(sp->sp_flags, STTYF_STOP)) {
790a8cebae3Sjason 		if (ISSET(sp->sp_flags, STTYF_SET_BREAK)) {
791a8cebae3Sjason 			STC_WRITE(sc, STC_TDR, 0);
792a8cebae3Sjason 			STC_WRITE(sc, STC_TDR, 0x81);
793a8cebae3Sjason 			CLR(sp->sp_flags, STTYF_SET_BREAK);
794a8cebae3Sjason 			cnt += 2;
795a8cebae3Sjason 		}
796a8cebae3Sjason 		if (ISSET(sp->sp_flags, STTYF_CLR_BREAK)) {
797a8cebae3Sjason 			STC_WRITE(sc, STC_TDR, 0);
798a8cebae3Sjason 			STC_WRITE(sc, STC_TDR, 0x83);
799a8cebae3Sjason 			CLR(sp->sp_flags, STTYF_CLR_BREAK);
800a8cebae3Sjason 			cnt += 2;
801a8cebae3Sjason 		}
802a8cebae3Sjason 
803a8cebae3Sjason 		while (sp->sp_txc > 0 && cnt < (CD180_TX_FIFO_SIZE-1)) {
804a8cebae3Sjason 			ch = *sp->sp_txp;
805a8cebae3Sjason 			sp->sp_txc--;
806a8cebae3Sjason 			sp->sp_txp++;
807a8cebae3Sjason 
808a8cebae3Sjason 			if (ch == 0) {
809a8cebae3Sjason 				STC_WRITE(sc, STC_TDR, ch);
810a8cebae3Sjason 				cnt++;
811a8cebae3Sjason 			}
812a8cebae3Sjason 			STC_WRITE(sc, STC_TDR, ch);
813a8cebae3Sjason 			cnt++;
814a8cebae3Sjason 		}
815a8cebae3Sjason 	}
816a8cebae3Sjason 
817a8cebae3Sjason 	if (sp->sp_txc == 0 ||
818a8cebae3Sjason 	    ISSET(sp->sp_flags, STTYF_STOP)) {
819a8cebae3Sjason 		STC_WRITE(sc, STC_SRER, STC_READ(sc, STC_SRER) &
820a8cebae3Sjason 		    (~CD180_SRER_TXD));
821a8cebae3Sjason 		CLR(sp->sp_flags, STTYF_STOP);
822a8cebae3Sjason 		SET(sp->sp_flags, STTYF_DONE);
823a8cebae3Sjason 		*needsoftp = 1;
824a8cebae3Sjason 	}
825a8cebae3Sjason 
826a8cebae3Sjason 	STC_WRITE(sc, STC_EOSRR, 0);
827a8cebae3Sjason 
828a8cebae3Sjason 	return (1);
829a8cebae3Sjason }
830a8cebae3Sjason 
831a8cebae3Sjason int
spifstcintr_mx(struct spif_softc * sc,int * needsoftp)8327b598489Sclaudio spifstcintr_mx(struct spif_softc *sc, int *needsoftp)
833a8cebae3Sjason {
834a8cebae3Sjason 	struct stty_port *sp;
835a8cebae3Sjason 	u_int8_t channel, mcr;
836a8cebae3Sjason 
837a8cebae3Sjason 	channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
838a8cebae3Sjason 	sp = &sc->sc_ttys->sc_port[channel];
839a8cebae3Sjason 	mcr = STC_READ(sc, STC_MCR);
840a8cebae3Sjason 	if (mcr & CD180_MCR_CD) {
841a8cebae3Sjason 		SET(sp->sp_flags, STTYF_CDCHG);
842a8cebae3Sjason 		*needsoftp = 1;
843a8cebae3Sjason 	}
844a8cebae3Sjason 	STC_WRITE(sc, STC_MCR, 0);
845a8cebae3Sjason 	STC_WRITE(sc, STC_EOSRR, 0);
846a8cebae3Sjason 	return (1);
847a8cebae3Sjason }
848a8cebae3Sjason 
849a8cebae3Sjason int
spifstcintr(void * vsc)8507b598489Sclaudio spifstcintr(void *vsc)
851a8cebae3Sjason {
852a8cebae3Sjason 	struct spif_softc *sc = (struct spif_softc *)vsc;
853a8cebae3Sjason 	int needsoft = 0, r = 0, i;
854a8cebae3Sjason 	u_int8_t ar;
855a8cebae3Sjason 
856a8cebae3Sjason 	for (i = 0; i < 8; i++) {
857a8cebae3Sjason 		ar = ISTC_READ(sc, STC_RRAR) & CD180_GSVR_IMASK;
858a8cebae3Sjason 		if (ar == CD180_GSVR_RXGOOD)
859a8cebae3Sjason 			r |= spifstcintr_rx(sc, &needsoft);
860a8cebae3Sjason 		else if (ar == CD180_GSVR_RXEXCEPTION)
861a8cebae3Sjason 			r |= spifstcintr_rxexception(sc, &needsoft);
862a8cebae3Sjason 	}
863a8cebae3Sjason 
864a8cebae3Sjason 	for (i = 0; i < 8; i++) {
865a8cebae3Sjason 		ar = ISTC_READ(sc, STC_TRAR) & CD180_GSVR_IMASK;
866a8cebae3Sjason 		if (ar == CD180_GSVR_TXDATA)
867a8cebae3Sjason 			r |= spifstcintr_tx(sc, &needsoft);
868a8cebae3Sjason 	}
869a8cebae3Sjason 
870a8cebae3Sjason 	for (i = 0; i < 8; i++) {
871a8cebae3Sjason 		ar = ISTC_READ(sc, STC_MRAR) & CD180_GSVR_IMASK;
872a8cebae3Sjason 		if (ar == CD180_GSVR_STATCHG)
873a8cebae3Sjason 			r |= spifstcintr_mx(sc, &needsoft);
874a8cebae3Sjason 	}
875a8cebae3Sjason 
876a8cebae3Sjason 	if (needsoft)
877a8cebae3Sjason 		softintr_schedule(sc->sc_softih);
878a8cebae3Sjason 	return (r);
879a8cebae3Sjason }
880a8cebae3Sjason 
881a8cebae3Sjason void
spifsoftintr(void * vsc)8827b598489Sclaudio spifsoftintr(void *vsc)
883a8cebae3Sjason {
884a8cebae3Sjason 	struct spif_softc *sc = (struct spif_softc *)vsc;
885a8cebae3Sjason 	struct stty_softc *stc = sc->sc_ttys;
886a8cebae3Sjason 	int r = 0, i, data, s, flags;
887a8cebae3Sjason 	u_int8_t stat, msvr;
888a8cebae3Sjason 	struct stty_port *sp;
889a8cebae3Sjason 	struct tty *tp;
890a8cebae3Sjason 
891a8cebae3Sjason 	if (stc != NULL) {
892a8cebae3Sjason 		for (i = 0; i < stc->sc_nports; i++) {
893a8cebae3Sjason 			sp = &stc->sc_port[i];
894a8cebae3Sjason 			tp = sp->sp_tty;
895a8cebae3Sjason 
896a8cebae3Sjason 			if (!ISSET(tp->t_state, TS_ISOPEN))
897a8cebae3Sjason 				continue;
898a8cebae3Sjason 
899a8cebae3Sjason 			while (sp->sp_rget != sp->sp_rput) {
900a8cebae3Sjason 				stat = sp->sp_rget[0];
901a8cebae3Sjason 				data = sp->sp_rget[1];
902a8cebae3Sjason 				sp->sp_rget += 2;
903a8cebae3Sjason 				if (sp->sp_rget == sp->sp_rend)
904a8cebae3Sjason 					sp->sp_rget = sp->sp_rbuf;
905a8cebae3Sjason 
906a8cebae3Sjason 				if (stat & (CD180_RCSR_BE | CD180_RCSR_FE))
907a8cebae3Sjason 					data |= TTY_FE;
908a8cebae3Sjason 
909a8cebae3Sjason 				if (stat & CD180_RCSR_PE)
910a8cebae3Sjason 					data |= TTY_PE;
911a8cebae3Sjason 
912a8cebae3Sjason 				(*linesw[tp->t_line].l_rint)(data, tp);
913a8cebae3Sjason 				r = 1;
914a8cebae3Sjason 			}
915a8cebae3Sjason 
916a8cebae3Sjason 			s = splhigh();
917a8cebae3Sjason 			flags = sp->sp_flags;
918a8cebae3Sjason 			CLR(sp->sp_flags, STTYF_DONE | STTYF_CDCHG |
919a8cebae3Sjason 			    STTYF_RING_OVERFLOW);
920a8cebae3Sjason 			splx(s);
921a8cebae3Sjason 
922a8cebae3Sjason 			if (ISSET(flags, STTYF_CDCHG)) {
923a8cebae3Sjason 				s = spltty();
924a8cebae3Sjason 				STC_WRITE(sc, STC_CAR, i);
925a8cebae3Sjason 				msvr = STC_READ(sc, STC_MSVR);
926a8cebae3Sjason 				splx(s);
927a8cebae3Sjason 
928a8cebae3Sjason 				sp->sp_carrier = msvr & CD180_MSVR_CD;
929a8cebae3Sjason 				(*linesw[tp->t_line].l_modem)(tp,
930a8cebae3Sjason 				    sp->sp_carrier);
931a8cebae3Sjason 				r = 1;
932a8cebae3Sjason 			}
933a8cebae3Sjason 
934a8cebae3Sjason 			if (ISSET(flags, STTYF_RING_OVERFLOW)) {
935a8cebae3Sjason 				log(LOG_WARNING, "%s-%x: ring overflow\n",
936a8cebae3Sjason 					stc->sc_dev.dv_xname, i);
937a8cebae3Sjason 				r = 1;
938a8cebae3Sjason 			}
939a8cebae3Sjason 
940a8cebae3Sjason 			if (ISSET(flags, STTYF_DONE)) {
941a8cebae3Sjason 				ndflush(&tp->t_outq,
942a8cebae3Sjason 				    sp->sp_txp - tp->t_outq.c_cf);
943a8cebae3Sjason 				CLR(tp->t_state, TS_BUSY);
944a8cebae3Sjason 				(*linesw[tp->t_line].l_start)(tp);
945a8cebae3Sjason 				r = 1;
946a8cebae3Sjason 			}
947a8cebae3Sjason 		}
948a8cebae3Sjason 	}
949a8cebae3Sjason }
950a8cebae3Sjason 
951a8cebae3Sjason void
stty_write_ccr(struct spif_softc * sc,u_int8_t val)9527b598489Sclaudio stty_write_ccr(struct spif_softc *sc, u_int8_t val)
953a8cebae3Sjason {
954a8cebae3Sjason 	int tries = 100000;
955a8cebae3Sjason 
956a8cebae3Sjason 	while (STC_READ(sc, STC_CCR) && tries--)
957a8cebae3Sjason 		/*EMPTY*/;
958a8cebae3Sjason 	if (tries == 0)
959a8cebae3Sjason 		printf("%s: ccr timeout\n", sc->sc_dev.dv_xname);
960a8cebae3Sjason 	STC_WRITE(sc, STC_CCR, val);
961a8cebae3Sjason }
962a8cebae3Sjason 
963a8cebae3Sjason int
stty_compute_baud(speed_t speed,int clock,u_int8_t * bprlp,u_int8_t * bprhp)9647b598489Sclaudio stty_compute_baud(speed_t speed, int clock, u_int8_t *bprlp, u_int8_t *bprhp)
965a8cebae3Sjason {
966a8cebae3Sjason 	u_int32_t rate;
967a8cebae3Sjason 
968a8cebae3Sjason 	rate = (2 * clock) / (16 * speed);
969a8cebae3Sjason 	if (rate & 1)
970a8cebae3Sjason 		rate = (rate >> 1) + 1;
971a8cebae3Sjason 	else
972a8cebae3Sjason 		rate = rate >> 1;
973a8cebae3Sjason 
974a8cebae3Sjason 	if (rate > 0xffff || rate == 0)
975a8cebae3Sjason 		return (1);
976a8cebae3Sjason 
977a8cebae3Sjason 	*bprlp = rate & 0xff;
978a8cebae3Sjason 	*bprhp = (rate >> 8) & 0xff;
979a8cebae3Sjason 	return (0);
980a8cebae3Sjason }
981a8cebae3Sjason 
982a8cebae3Sjason int
sbppmatch(struct device * parent,void * vcf,void * aux)9837b598489Sclaudio sbppmatch(struct device *parent, void *vcf, void *aux)
984a8cebae3Sjason {
985a8cebae3Sjason 	struct spif_softc *sc = (struct spif_softc *)parent;
986a8cebae3Sjason 
987a8cebae3Sjason 	return (aux == sbppmatch && sc->sc_bpps == NULL);
988a8cebae3Sjason }
989a8cebae3Sjason 
990a8cebae3Sjason void
sbppattach(struct device * parent,struct device * dev,void * aux)9917b598489Sclaudio sbppattach(struct device *parent, struct device *dev, void *aux)
992a8cebae3Sjason {
993a8cebae3Sjason 	struct spif_softc *sc = (struct spif_softc *)parent;
994a8cebae3Sjason 	struct sbpp_softc *psc = (struct sbpp_softc *)dev;
995a8cebae3Sjason 	int port;
996a8cebae3Sjason 
997a8cebae3Sjason 	sc->sc_bpps = psc;
998a8cebae3Sjason 
999a8cebae3Sjason 	for (port = 0; port < sc->sc_npar; port++) {
1000a8cebae3Sjason 	}
1001a8cebae3Sjason 
1002a8cebae3Sjason 	psc->sc_nports = port;
1003a8cebae3Sjason 	printf(": %d port%s\n", port, port == 1 ? "" : "s");
1004a8cebae3Sjason }
1005a8cebae3Sjason 
1006a8cebae3Sjason int
sbppopen(dev_t dev,int flags,int mode,struct proc * p)10077b598489Sclaudio sbppopen(dev_t dev, int flags, int mode, struct proc *p)
1008a8cebae3Sjason {
1009a8cebae3Sjason 	return (ENXIO);
1010a8cebae3Sjason }
1011a8cebae3Sjason 
1012a8cebae3Sjason int
sbppclose(dev_t dev,int flags,int mode,struct proc * p)10137b598489Sclaudio sbppclose(dev_t dev, int flags, int mode, struct proc *p)
1014a8cebae3Sjason {
1015a8cebae3Sjason 	return (ENXIO);
1016a8cebae3Sjason }
1017a8cebae3Sjason 
1018a8cebae3Sjason int
spifppcintr(void * v)10197b598489Sclaudio spifppcintr(void *v)
1020a8cebae3Sjason {
1021a8cebae3Sjason 	return (0);
1022a8cebae3Sjason }
1023a8cebae3Sjason 
1024a8cebae3Sjason int
sbppread(dev_t dev,struct uio * uio,int flags)10257b598489Sclaudio sbppread(dev_t dev, struct uio *uio, int flags)
1026a8cebae3Sjason {
1027a8cebae3Sjason 	return (sbpp_rw(dev, uio));
1028a8cebae3Sjason }
1029a8cebae3Sjason 
1030a8cebae3Sjason int
sbppwrite(dev_t dev,struct uio * uio,int flags)10317b598489Sclaudio sbppwrite(dev_t dev, struct uio *uio, int flags)
1032a8cebae3Sjason {
1033a8cebae3Sjason 	return (sbpp_rw(dev, uio));
1034a8cebae3Sjason }
1035a8cebae3Sjason 
1036a8cebae3Sjason int
sbpp_rw(dev_t dev,struct uio * uio)10377b598489Sclaudio sbpp_rw(dev_t dev, struct uio *uio)
1038a8cebae3Sjason {
1039a8cebae3Sjason 	return (ENXIO);
1040a8cebae3Sjason }
1041a8cebae3Sjason 
1042a8cebae3Sjason int
sbppkqfilter(dev_t dev,struct knote * kn)104354e8de3eSmpi sbppkqfilter(dev_t dev, struct knote *kn)
104454e8de3eSmpi {
104554e8de3eSmpi 	return (seltrue_kqfilter(dev, kn));
104654e8de3eSmpi }
1047a8cebae3Sjason 
1048a8cebae3Sjason int
sbppioctl(dev_t dev,u_long cmd,caddr_t data,int flags,struct proc * p)10497b598489Sclaudio sbppioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
1050a8cebae3Sjason {
1051a8cebae3Sjason 	int error;
1052a8cebae3Sjason 
1053a8cebae3Sjason 	error = ENOTTY;
1054a8cebae3Sjason 
1055a8cebae3Sjason 	return (error);
1056a8cebae3Sjason }
1057