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