1 /* $NetBSD: sa11x0_com.c,v 1.59 2022/10/26 23:38:07 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999, 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by IWAMOTO Toshihiro.
9 *
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Charles M. Hannum.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * Copyright (c) 1991 The Regents of the University of California.
37 * All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)com.c 7.5 (Berkeley) 5/16/91
64 */
65
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: sa11x0_com.c,v 1.59 2022/10/26 23:38:07 riastradh Exp $");
68
69 #include "opt_com.h"
70 #include "opt_console.h"
71 #include "opt_ddb.h"
72 #include "opt_ddbparam.h"
73 #include "opt_kgdb.h"
74 #include "opt_multiprocessor.h"
75 #include "opt_lockdebug.h"
76
77 #ifdef RND_COM
78 #include <sys/rndsource.h>
79 #endif
80
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/types.h>
84 #include <sys/conf.h>
85 #include <sys/file.h>
86 #include <sys/device.h>
87 #include <sys/kernel.h>
88 #include <sys/kmem.h>
89 #include <sys/tty.h>
90 #include <sys/uio.h>
91 #include <sys/vnode.h>
92 #include <sys/kauth.h>
93
94 #include <ddb/db_active.h>
95
96 #include <dev/cons.h>
97
98 #include <sys/bus.h>
99 #include <arm/sa11x0/sa11x0_reg.h>
100 #include <arm/sa11x0/sa11x0_var.h>
101 #include <arm/sa11x0/sa11x0_comreg.h>
102 #include <arm/sa11x0/sa11x0_comvar.h>
103 #include <arm/sa11x0/sa11x0_gpioreg.h>
104
105 #ifdef hpcarm
106 #include <hpc/include/platid.h>
107 #include <hpc/include/platid_mask.h>
108 #endif
109
110 #include "sacom.h"
111
112 dev_type_open(sacomopen);
113 dev_type_close(sacomclose);
114 dev_type_read(sacomread);
115 dev_type_write(sacomwrite);
116 dev_type_ioctl(sacomioctl);
117 dev_type_stop(sacomstop);
118 dev_type_tty(sacomtty);
119 dev_type_poll(sacompoll);
120
121 const struct cdevsw sacom_cdevsw = {
122 .d_open = sacomopen,
123 .d_close = sacomclose,
124 .d_read = sacomread,
125 .d_write = sacomwrite,
126 .d_ioctl = sacomioctl,
127 .d_stop = sacomstop,
128 .d_tty = sacomtty,
129 .d_poll = sacompoll,
130 .d_mmap = nommap,
131 .d_kqfilter = ttykqfilter,
132 .d_discard = nodiscard,
133 .d_flag = D_TTY
134 };
135
136 static int sacom_match(device_t, cfdata_t, void *);
137 static void sacom_attach(device_t, device_t, void *);
138 static void sacom_filltx(struct sacom_softc *);
139 static void sacom_attach_subr(struct sacom_softc *);
140 #if defined(DDB) || defined(KGDB)
141 static void sacom_enable_debugport(struct sacom_softc *);
142 #endif
143 int sacom_detach(device_t, int);
144 void sacom_config(struct sacom_softc *);
145 int sacom_activate(device_t, enum devact);
146 void sacom_shutdown(struct sacom_softc *);
147 static u_int cflag2cr0(tcflag_t);
148 int sacomparam(struct tty *, struct termios *);
149 void sacomstart(struct tty *);
150 int sacomhwiflow(struct tty *, int);
151
152 void sacom_loadchannelregs(struct sacom_softc *);
153 void sacom_hwiflow(struct sacom_softc *);
154 void sacom_break(struct sacom_softc *, int);
155 void sacom_modem(struct sacom_softc *, int);
156 void tiocm_to_sacom(struct sacom_softc *, u_long, int);
157 int sacom_to_tiocm(struct sacom_softc *);
158 void sacom_iflush(struct sacom_softc *);
159
160 int sacominit(bus_space_tag_t, bus_addr_t, int, tcflag_t,
161 bus_space_handle_t *);
162 int sacom_is_console(bus_space_tag_t, bus_addr_t,
163 bus_space_handle_t *);
164
165 void sacomsoft(void *);
166
167 static inline void sacom_rxsoft(struct sacom_softc *, struct tty *);
168 static inline void sacom_txsoft(struct sacom_softc *, struct tty *);
169 static inline void sacom_stsoft(struct sacom_softc *, struct tty *);
170 static inline void sacom_schedrx(struct sacom_softc *);
171
172 #ifdef hpcarm
173 /* HPCARM specific functions */
174 static void sacom_j720_init(device_t, device_t);
175 #endif
176
177 #define COMDIALOUT_MASK TTDIALOUT_MASK
178
179 #define COMUNIT(x) TTUNIT(x)
180 #define COMDIALOUT(x) TTDIALOUT(x)
181
182 #define COM_ISALIVE(sc) ((sc)->enabled != 0 && \
183 device_is_active((sc)->sc_dev))
184
185 #define COM_BARRIER(t, h, f) bus_space_barrier((t), (h), 0, COM_NPORTS, (f))
186 #define COM_LOCK(sc)
187 #define COM_UNLOCK(sc)
188
189 int sacomintr(void *);
190 int sacomcngetc(dev_t);
191 void sacomcnputc(dev_t, int);
192 void sacomcnpollc(dev_t, int);
193
194 void sacomcnprobe(struct consdev *);
195 void sacomcninit(struct consdev *);
196
197 extern struct bus_space sa11x0_bs_tag;
198
199 static bus_space_tag_t sacomconstag;
200 static bus_space_handle_t sacomconsioh;
201 static bus_addr_t sacomconsaddr = SACOM3_BASE; /* XXX */
202
203 static int sacomconsattached;
204 static int sacomconsrate;
205 static tcflag_t sacomconscflag;
206
207 CFATTACH_DECL_NEW(sacom, sizeof(struct sacom_softc),
208 sacom_match, sacom_attach, NULL, NULL);
209 extern struct cfdriver sacom_cd;
210
211 #ifdef hpcarm
212 struct platid_data sacom_platid_table[] = {
213 { &platid_mask_MACH_HP_JORNADA_7XX, sacom_j720_init },
214 { NULL, NULL }
215 };
216 #endif
217
218 struct consdev sacomcons = {
219 NULL, NULL, sacomcngetc, sacomcnputc, sacomcnpollc, NULL,
220 NULL, NULL, NODEV, CN_NORMAL
221 };
222
223 #ifndef CONMODE
224 #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
225 #endif
226 #ifndef CONSPEED
227 #define CONSPEED 9600
228 #endif
229 #ifndef CONADDR
230 #define CONADDR SACOM3_BASE
231 #endif
232
233 static int
sacom_match(device_t parent,cfdata_t match,void * aux)234 sacom_match(device_t parent, cfdata_t match, void *aux)
235 {
236
237 return 1;
238 }
239
240 void
sacom_attach(device_t parent,device_t self,void * aux)241 sacom_attach(device_t parent, device_t self, void *aux)
242 {
243 struct sacom_softc *sc = device_private(self);
244 struct sa11x0_attach_args *sa = aux;
245
246 #ifdef hpcarm
247 struct platid_data *p;
248 void (*mdinit)(device_t, device_t);
249 #endif
250
251 aprint_normal("\n");
252
253 sc->sc_dev = self;
254 sc->sc_iot = sa->sa_iot;
255 sc->sc_baseaddr = sa->sa_addr;
256
257 if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0,
258 &sc->sc_ioh)) {
259 aprint_normal_dev(self, "unable to map registers\n");
260 return;
261 }
262
263 switch (sc->sc_baseaddr) {
264 case SACOM1_BASE:
265 aprint_normal_dev(self, "SA-11x0 UART1\n");
266 break;
267 case SACOM2_BASE:
268 aprint_normal_dev(self, "SA-11x0 UART2 (IRDA)\n");
269 break;
270 case SACOM3_BASE:
271 aprint_normal_dev(self, "SA-11x0 UART3\n");
272 break;
273 default:
274 aprint_normal_dev(self, "unknown SA-11x0 UART\n");
275 break;
276 }
277
278 sacom_attach_subr(sc);
279
280 #ifdef hpcarm
281 /* Do hpcarm specific initialization, if any */
282 if ((p = platid_search_data(&platid, sacom_platid_table)) != NULL) {
283 mdinit = p->data;
284 (*mdinit)(parent, self);
285 }
286 #endif
287
288 sa11x0_intr_establish(0, sa->sa_intr, 1, IPL_SERIAL, sacomintr, sc);
289 }
290
291 void
sacom_attach_subr(struct sacom_softc * sc)292 sacom_attach_subr(struct sacom_softc *sc)
293 {
294 bus_addr_t iobase = sc->sc_baseaddr;
295 bus_space_tag_t iot = sc->sc_iot;
296 struct tty *tp;
297
298 /* XXX Do we need to disable interrupts here? */
299
300 if (iot == sacomconstag && iobase == sacomconsaddr) {
301 sacomconsattached = 1;
302 sc->sc_speed = SACOMSPEED(sacomconsrate);
303
304 /* Make sure the console is always "hardwired". */
305 delay(10000); /* wait for output to finish */
306 SET(sc->sc_hwflags, COM_HW_CONSOLE);
307 SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
308 }
309
310 tp = tty_alloc();
311 tp->t_oproc = sacomstart;
312 tp->t_param = sacomparam;
313 tp->t_hwiflow = sacomhwiflow;
314
315 sc->sc_tty = tp;
316 sc->sc_rbuf = kmem_alloc(SACOM_RING_SIZE << 1, KM_SLEEP);
317 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
318 sc->sc_rbavail = SACOM_RING_SIZE;
319 sc->sc_ebuf = sc->sc_rbuf + (SACOM_RING_SIZE << 1);
320 sc->sc_tbc = 0;
321
322 tty_attach(tp);
323
324 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
325 int maj;
326
327 /* locate the major number */
328 maj = cdevsw_lookup_major(&sacom_cdevsw);
329
330 cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev));
331
332 delay(10000); /* XXX */
333 aprint_normal_dev(sc->sc_dev, "console\n");
334 delay(10000); /* XXX */
335 }
336
337
338 sc->sc_si = softint_establish(SOFTINT_SERIAL, sacomsoft, sc);
339
340 #ifdef RND_COM
341 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
342 RND_TYPE_TTY, RND_FLAG_COLLECT_TIME|
343 RND_FLAG_ESTIMATE_TIME);
344 #endif
345
346 /* if there are no enable/disable functions, assume the device
347 is always enabled */
348 if (!sc->enable)
349 sc->enabled = 1;
350
351 sacom_config(sc);
352
353 SET(sc->sc_hwflags, COM_HW_DEV_OK);
354 }
355
356 /* This is necessary when dynamically changing SAIP configuration. */
357 int
sacom_detach(device_t dev,int flags)358 sacom_detach(device_t dev, int flags)
359 {
360 struct sacom_softc *sc = device_private(dev);
361 int maj, mn;
362
363 if (sc->sc_hwflags & (COM_HW_CONSOLE|COM_HW_KGDB))
364 return EBUSY;
365
366 if (sc->disable != NULL && sc->enabled != 0) {
367 (*sc->disable)(sc);
368 sc->enabled = 0;
369 }
370
371 /* locate the major number */
372 maj = cdevsw_lookup_major(&sacom_cdevsw);
373
374 /* Nuke the vnodes for any open instances. */
375 mn = device_unit(dev);
376 vdevgone(maj, mn, mn, VCHR);
377
378 mn |= COMDIALOUT_MASK;
379 vdevgone(maj, mn, mn, VCHR);
380
381 /* Free the receive buffer. */
382 kmem_free(sc->sc_rbuf, SACOM_RING_SIZE << 1);
383
384 /* Detach and free the tty. */
385 tty_detach(sc->sc_tty);
386 tty_free(sc->sc_tty);
387
388 /* Unhook the soft interrupt handler. */
389 softint_disestablish(sc->sc_si);
390
391 #ifdef RND_COM
392 /* Unhook the entropy source. */
393 rnd_detach_source(&sc->rnd_source);
394 #endif
395
396 return 0;
397 }
398
399 void
sacom_config(struct sacom_softc * sc)400 sacom_config(struct sacom_softc *sc)
401 {
402 bus_space_tag_t iot = sc->sc_iot;
403 bus_space_handle_t ioh = sc->sc_ioh;
404
405 /* Disable engine before configuring the device. */
406 sc->sc_cr3 = 0;
407 bus_space_write_4(iot, ioh, SACOM_CR3, sc->sc_cr3);
408
409 #ifdef DDB
410 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
411 sacom_enable_debugport(sc);
412 #endif
413 }
414
415 #ifdef DDB
416 static void
sacom_enable_debugport(struct sacom_softc * sc)417 sacom_enable_debugport(struct sacom_softc *sc)
418 {
419 bus_space_tag_t iot = sc->sc_iot;
420 bus_space_handle_t ioh = sc->sc_ioh;
421 int s;
422
423 s = splserial();
424 COM_LOCK(sc);
425 sc->sc_cr3 = CR3_RXE | CR3_TXE;
426 bus_space_write_4(iot, ioh, SACOM_CR3, sc->sc_cr3);
427 COM_UNLOCK(sc);
428 splx(s);
429 }
430 #endif
431
432 int
sacom_activate(device_t dev,enum devact act)433 sacom_activate(device_t dev, enum devact act)
434 {
435 struct sacom_softc *sc = device_private(dev);
436
437 switch (act) {
438 case DVACT_DEACTIVATE:
439 sc->enabled = 0;
440 return 0;
441 default:
442 return EOPNOTSUPP;
443 }
444 }
445
446 void
sacom_shutdown(struct sacom_softc * sc)447 sacom_shutdown(struct sacom_softc *sc)
448 {
449 struct tty *tp = sc->sc_tty;
450 int s;
451
452 s = splserial();
453 COM_LOCK(sc);
454
455 /* Clear any break condition set with TIOCSBRK. */
456 sacom_break(sc, 0);
457
458 /*
459 * Hang up if necessary. Wait a bit, so the other side has time to
460 * notice even if we immediately open the port again.
461 * Avoid tsleeping above splhigh().
462 */
463 if (ISSET(tp->t_cflag, HUPCL)) {
464 sacom_modem(sc, 0);
465 COM_UNLOCK(sc);
466 splx(s);
467 /* XXX tsleep will only timeout */
468 (void) tsleep(sc, TTIPRI, ttclos, hz);
469 s = splserial();
470 COM_LOCK(sc);
471 }
472
473 /* Turn off interrupts. */
474 sc->sc_cr3 = 0;
475 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SACOM_CR3, sc->sc_cr3);
476
477 if (sc->disable) {
478 #ifdef DIAGNOSTIC
479 if (!sc->enabled)
480 panic("sacom_shutdown: not enabled?");
481 #endif
482 (*sc->disable)(sc);
483 sc->enabled = 0;
484 }
485 COM_UNLOCK(sc);
486 splx(s);
487 }
488
489 int
sacomopen(dev_t dev,int flag,int mode,struct lwp * l)490 sacomopen(dev_t dev, int flag, int mode, struct lwp *l)
491 {
492 struct sacom_softc *sc;
493 struct tty *tp;
494 int s, s2;
495 int error;
496
497 sc = device_lookup_private(&sacom_cd, COMUNIT(dev));
498 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK) ||
499 sc->sc_rbuf == NULL)
500 return ENXIO;
501
502 if (!device_is_active(sc->sc_dev))
503 return ENXIO;
504
505 tp = sc->sc_tty;
506
507 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
508 return (EBUSY);
509
510 s = spltty();
511
512 /*
513 * Do the following iff this is a first open.
514 */
515 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
516 struct termios t;
517
518 tp->t_dev = dev;
519
520 s2 = splserial();
521 COM_LOCK(sc);
522
523 if (sc->enable) {
524 if ((*sc->enable)(sc)) {
525 COM_UNLOCK(sc);
526 splx(s2);
527 splx(s);
528 aprint_normal_dev(sc->sc_dev, "device enable failed\n");
529 return EIO;
530 }
531 sc->enabled = 1;
532 sacom_config(sc);
533 }
534
535 /* Turn on interrupts. */
536 sc->sc_cr3 = CR3_RXE | CR3_TXE | CR3_RIE | CR3_TIE;
537 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SACOM_CR3,
538 sc->sc_cr3);
539
540
541 COM_UNLOCK(sc);
542 splx(s2);
543
544 /*
545 * Initialize the termios status to the defaults. Add in the
546 * sticky bits from TIOCSFLAGS.
547 */
548 t.c_ispeed = 0;
549 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
550 t.c_ospeed = sacomconsrate;
551 t.c_cflag = sacomconscflag;
552 } else {
553 t.c_ospeed = TTYDEF_SPEED;
554 t.c_cflag = TTYDEF_CFLAG;
555 }
556 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
557 SET(t.c_cflag, CLOCAL);
558 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
559 SET(t.c_cflag, CRTSCTS);
560 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
561 SET(t.c_cflag, MDMBUF);
562 /* Make sure sacomparam() will do something. */
563 tp->t_ospeed = 0;
564 (void) sacomparam(tp, &t);
565 tp->t_iflag = TTYDEF_IFLAG;
566 tp->t_oflag = TTYDEF_OFLAG;
567 tp->t_lflag = TTYDEF_LFLAG;
568 ttychars(tp);
569 ttsetwater(tp);
570
571 s2 = splserial();
572 COM_LOCK(sc);
573
574 /*
575 * Turn on DTR. We must always do this, even if carrier is not
576 * present, because otherwise we'd have to use TIOCSDTR
577 * immediately after setting CLOCAL, which applications do not
578 * expect. We always assert DTR while the device is open
579 * unless explicitly requested to deassert it.
580 */
581 sacom_modem(sc, 1);
582
583 /* Clear the input ring, and unblock. */
584 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
585 sc->sc_rbavail = SACOM_RING_SIZE;
586 sacom_iflush(sc);
587 CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
588 sacom_hwiflow(sc);
589
590 #ifdef COM_DEBUG
591 if (sacom_debug)
592 comstatus(sc, "sacomopen ");
593 #endif
594
595 COM_UNLOCK(sc);
596 splx(s2);
597 }
598
599 splx(s);
600
601 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
602 if (error)
603 goto bad;
604
605 error = (*tp->t_linesw->l_open)(dev, tp);
606 if (error)
607 goto bad;
608
609 return 0;
610
611 bad:
612 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
613 /*
614 * We failed to open the device, and nobody else had it opened.
615 * Clean up the state as appropriate.
616 */
617 sacom_shutdown(sc);
618 }
619
620 return error;
621 }
622
623 int
sacomclose(dev_t dev,int flag,int mode,struct lwp * l)624 sacomclose(dev_t dev, int flag, int mode, struct lwp *l)
625 {
626 struct sacom_softc *sc =
627 device_lookup_private(&sacom_cd, COMUNIT(dev));
628 struct tty *tp = sc->sc_tty;
629
630 /* XXX This is for cons.c. */
631 if (!ISSET(tp->t_state, TS_ISOPEN))
632 return 0;
633
634 (*tp->t_linesw->l_close)(tp, flag);
635 ttyclose(tp);
636
637 if (COM_ISALIVE(sc) == 0)
638 return 0;
639
640 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
641 /*
642 * Although we got a last close, the device may still be in
643 * use; e.g. if this was the dialout node, and there are still
644 * processes waiting for carrier on the non-dialout node.
645 */
646 sacom_shutdown(sc);
647 }
648
649 return 0;
650 }
651
652 int
sacomread(dev_t dev,struct uio * uio,int flag)653 sacomread(dev_t dev, struct uio *uio, int flag)
654 {
655 struct sacom_softc *sc =
656 device_lookup_private(&sacom_cd, COMUNIT(dev));
657 struct tty *tp = sc->sc_tty;
658
659 if (COM_ISALIVE(sc) == 0)
660 return EIO;
661
662 return (*tp->t_linesw->l_read)(tp, uio, flag);
663 }
664
665 int
sacomwrite(dev_t dev,struct uio * uio,int flag)666 sacomwrite(dev_t dev, struct uio *uio, int flag)
667 {
668 struct sacom_softc *sc =
669 device_lookup_private(&sacom_cd, COMUNIT(dev));
670 struct tty *tp = sc->sc_tty;
671
672 if (COM_ISALIVE(sc) == 0)
673 return EIO;
674
675 return (*tp->t_linesw->l_write)(tp, uio, flag);
676 }
677
678 int
sacompoll(dev_t dev,int events,struct lwp * l)679 sacompoll(dev_t dev, int events, struct lwp *l)
680 {
681 struct sacom_softc *sc =
682 device_lookup_private(&sacom_cd, COMUNIT(dev));
683 struct tty *tp = sc->sc_tty;
684
685 if (COM_ISALIVE(sc) == 0)
686 return EIO;
687
688 return (*tp->t_linesw->l_poll)(tp, events, l);
689 }
690
691 struct tty *
sacomtty(dev_t dev)692 sacomtty(dev_t dev)
693 {
694 struct sacom_softc *sc =
695 device_lookup_private(&sacom_cd, COMUNIT(dev));
696 struct tty *tp = sc->sc_tty;
697
698 return tp;
699 }
700
701 int
sacomioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)702 sacomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
703 {
704 struct sacom_softc *sc =
705 device_lookup_private(&sacom_cd, COMUNIT(dev));
706 struct tty *tp = sc->sc_tty;
707 int error;
708 int s;
709
710 if (COM_ISALIVE(sc) == 0)
711 return EIO;
712
713 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
714 if (error != EPASSTHROUGH)
715 return error;
716
717 error = ttioctl(tp, cmd, data, flag, l);
718 if (error != EPASSTHROUGH)
719 return error;
720
721 error = 0;
722
723 s = splserial();
724 COM_LOCK(sc);
725
726 switch (cmd) {
727 case TIOCSBRK:
728 sacom_break(sc, 1);
729 break;
730
731 case TIOCCBRK:
732 sacom_break(sc, 0);
733 break;
734
735 case TIOCSDTR:
736 sacom_modem(sc, 1);
737 break;
738
739 case TIOCCDTR:
740 sacom_modem(sc, 0);
741 break;
742
743 case TIOCGFLAGS:
744 *(int *)data = sc->sc_swflags;
745 break;
746
747 case TIOCSFLAGS:
748 error = kauth_authorize_device_tty(l->l_cred,
749 KAUTH_DEVICE_TTY_PRIVSET, tp);
750 if (error)
751 break;
752 sc->sc_swflags = *(int *)data;
753 break;
754
755 case TIOCMSET:
756 case TIOCMBIS:
757 case TIOCMBIC:
758 tiocm_to_sacom(sc, cmd, *(int *)data);
759 break;
760
761 case TIOCMGET:
762 *(int *)data = sacom_to_tiocm(sc);
763 break;
764
765 default:
766 error = EPASSTHROUGH;
767 break;
768 }
769
770 COM_UNLOCK(sc);
771 splx(s);
772
773 #ifdef COM_DEBUG
774 if (sacom_debug)
775 comstatus(sc, "comioctl ");
776 #endif
777
778 return error;
779 }
780
781 static inline void
sacom_schedrx(struct sacom_softc * sc)782 sacom_schedrx(struct sacom_softc *sc)
783 {
784
785 sc->sc_rx_ready = 1;
786
787 /* Wake up the poller. */
788 softint_schedule(sc->sc_si);
789 }
790
791 void
sacom_break(struct sacom_softc * sc,int onoff)792 sacom_break(struct sacom_softc *sc, int onoff)
793 {
794
795 if (onoff)
796 SET(sc->sc_cr3, CR3_BRK);
797 else
798 CLR(sc->sc_cr3, CR3_BRK);
799
800 if (!sc->sc_heldchange) {
801 if (sc->sc_tx_busy) {
802 sc->sc_heldtbc = sc->sc_tbc;
803 sc->sc_tbc = 0;
804 sc->sc_heldchange = 1;
805 } else
806 sacom_loadchannelregs(sc);
807 }
808 }
809
810 void
sacom_modem(struct sacom_softc * sc,int onoff)811 sacom_modem(struct sacom_softc *sc, int onoff)
812 {
813 if (!sc->sc_heldchange) {
814 if (sc->sc_tx_busy) {
815 sc->sc_heldtbc = sc->sc_tbc;
816 sc->sc_tbc = 0;
817 sc->sc_heldchange = 1;
818 } else
819 sacom_loadchannelregs(sc);
820 }
821 }
822
823 void
tiocm_to_sacom(struct sacom_softc * sc,u_long how,int ttybits)824 tiocm_to_sacom(struct sacom_softc *sc, u_long how, int ttybits)
825 {
826 }
827
828 int
sacom_to_tiocm(struct sacom_softc * sc)829 sacom_to_tiocm(struct sacom_softc *sc)
830 {
831 int ttybits = 0;
832
833 if (sc->sc_cr3 != 0)
834 SET(ttybits, TIOCM_LE);
835
836 return ttybits;
837 }
838
839 static u_int
cflag2cr0(tcflag_t cflag)840 cflag2cr0(tcflag_t cflag)
841 {
842 u_int cr0;
843
844 cr0 = (cflag & PARENB) ? CR0_PE : 0;
845 cr0 |= (cflag & PARODD) ? 0 : CR0_OES;
846 cr0 |= (cflag & CSTOPB) ? CR0_SBS : 0;
847 cr0 |= ((cflag & CSIZE) == CS8) ? CR0_DSS : 0;
848
849 return cr0;
850 }
851
852 int
sacomparam(struct tty * tp,struct termios * t)853 sacomparam(struct tty *tp, struct termios *t)
854 {
855 struct sacom_softc *sc =
856 device_lookup_private(&sacom_cd, COMUNIT(tp->t_dev));
857 int ospeed = SACOMSPEED(t->c_ospeed);
858 u_int cr0;
859 int s;
860
861 if (COM_ISALIVE(sc) == 0)
862 return EIO;
863
864 /* Check requested parameters. */
865 if (ospeed < 0)
866 return EINVAL;
867 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
868 return EINVAL;
869
870 /*
871 * For the console, always force CLOCAL and !HUPCL, so that the port
872 * is always active.
873 */
874 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
875 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
876 SET(t->c_cflag, CLOCAL);
877 CLR(t->c_cflag, HUPCL);
878 }
879
880 /*
881 * If there were no changes, don't do anything. This avoids dropping
882 * input and improves performance when all we did was frob things like
883 * VMIN and VTIME.
884 */
885 if (tp->t_ospeed == t->c_ospeed &&
886 tp->t_cflag == t->c_cflag)
887 return 0;
888
889 cr0 = cflag2cr0(t->c_cflag);
890
891 s = splserial();
892 COM_LOCK(sc);
893
894 sc->sc_cr0 = cr0;
895
896 sc->sc_speed = ospeed;
897
898 /* And copy to tty. */
899 tp->t_ispeed = 0;
900 tp->t_ospeed = t->c_ospeed;
901 tp->t_cflag = t->c_cflag;
902
903 if (!sc->sc_heldchange) {
904 if (sc->sc_tx_busy) {
905 sc->sc_heldtbc = sc->sc_tbc;
906 sc->sc_tbc = 0;
907 sc->sc_heldchange = 1;
908 } else
909 sacom_loadchannelregs(sc);
910 }
911
912 if (!ISSET(t->c_cflag, CHWFLOW)) {
913 /* Disable the high water mark. */
914 if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) {
915 CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
916 sacom_schedrx(sc);
917 }
918 if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) {
919 CLR(sc->sc_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED);
920 sacom_hwiflow(sc);
921 }
922 }
923
924 COM_UNLOCK(sc);
925 splx(s);
926
927 (void) (*tp->t_linesw->l_modem)(tp, 1);
928
929 #ifdef COM_DEBUG
930 if (sacom_debug)
931 comstatus(sc, "comparam ");
932 #endif
933
934 return 0;
935 }
936
937 void
sacom_iflush(struct sacom_softc * sc)938 sacom_iflush(struct sacom_softc *sc)
939 {
940 bus_space_tag_t iot = sc->sc_iot;
941 bus_space_handle_t ioh = sc->sc_ioh;
942 #ifdef DIAGNOSTIC
943 int reg;
944 #endif
945 int timo;
946
947 #ifdef DIAGNOSTIC
948 reg = 0xffff;
949 #endif
950 timo = 50;
951 /* flush any pending I/O */
952 if (sc->sc_cr3 & CR3_RXE) {
953 while (ISSET(bus_space_read_4(iot, ioh, SACOM_SR1), SR1_RNE)
954 && --timo)
955 #ifdef DIAGNOSTIC
956 reg =
957 #else
958 (void)
959 #endif
960 bus_space_read_4(iot, ioh, SACOM_DR);
961 }
962 #if 0
963 /* XXX is it good idea to wait TX finish? */
964 if (sc->sc_cr3 & CR3_TXE) {
965 timo = 500;
966 while (ISSET(bus_space_read_4(iot, ioh, SACOM_SR1), SR1_TBY)
967 && --timo)
968 delay(100);
969 }
970 #endif
971 #ifdef DIAGNOSTIC
972 if (!timo)
973 aprint_debug_dev(sc->sc_dev, "sacom_iflush timeout %02x\n", reg);
974 #endif
975 }
976
977 void
sacom_loadchannelregs(struct sacom_softc * sc)978 sacom_loadchannelregs(struct sacom_softc *sc)
979 {
980 bus_space_tag_t iot = sc->sc_iot;
981 bus_space_handle_t ioh = sc->sc_ioh;
982
983 /* XXXXX necessary? */
984 sacom_iflush(sc);
985
986 /* Need to stop engines first. */
987 bus_space_write_4(iot, ioh, SACOM_CR3, 0);
988
989 bus_space_write_4(iot, ioh, SACOM_CR1, sc->sc_speed >> 8);
990 bus_space_write_4(iot, ioh, SACOM_CR2, sc->sc_speed & 0xff);
991
992 bus_space_write_4(iot, ioh, SACOM_CR0, sc->sc_cr0);
993 bus_space_write_4(iot, ioh, SACOM_CR3, sc->sc_cr3);
994 }
995
996 int
sacomhwiflow(struct tty * tp,int block)997 sacomhwiflow(struct tty *tp, int block)
998 {
999 #if 0
1000 struct sacom_softc *sc =
1001 device_lookup_private(&sacom_cd, COMUNIT(tp->t_dev));
1002 int s;
1003
1004 if (COM_ISALIVE(sc) == 0)
1005 return 0;
1006
1007 if (sc->sc_mcr_rts == 0)
1008 return 0;
1009
1010 s = splserial();
1011 COM_LOCK(sc);
1012
1013 if (block) {
1014 if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
1015 SET(sc->sc_rx_flags, RX_TTY_BLOCKED);
1016 sacom_hwiflow(sc);
1017 }
1018 } else {
1019 if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) {
1020 CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
1021 sacom_schedrx(sc);
1022 }
1023 if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
1024 CLR(sc->sc_rx_flags, RX_TTY_BLOCKED);
1025 sacom_hwiflow(sc);
1026 }
1027 }
1028
1029 COM_UNLOCK(sc);
1030 splx(s);
1031 #endif
1032 return 1;
1033 }
1034
1035 /*
1036 * (un)block input via hw flowcontrol
1037 */
1038 void
sacom_hwiflow(struct sacom_softc * sc)1039 sacom_hwiflow(struct sacom_softc *sc)
1040 {
1041 #if 0
1042 bus_space_tag_t iot = sc->sc_iot;
1043 bus_space_handle_t ioh = sc->sc_ioh;
1044
1045 /* XXX implement */
1046 #endif
1047 }
1048
1049
1050 void
sacomstart(struct tty * tp)1051 sacomstart(struct tty *tp)
1052 {
1053 struct sacom_softc *sc =
1054 device_lookup_private(&sacom_cd, COMUNIT(tp->t_dev));
1055 bus_space_tag_t iot = sc->sc_iot;
1056 bus_space_handle_t ioh = sc->sc_ioh;
1057 int s;
1058
1059 if (COM_ISALIVE(sc) == 0)
1060 return;
1061
1062 s = spltty();
1063 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
1064 goto out;
1065 if (!ttypull(tp))
1066 goto out;
1067
1068 /* Grab the first contiguous region of buffer space. */
1069 {
1070 u_char *tba;
1071 int tbc;
1072
1073 tba = tp->t_outq.c_cf;
1074 tbc = ndqb(&tp->t_outq, 0);
1075
1076 (void)splserial();
1077 COM_LOCK(sc);
1078
1079 sc->sc_tba = tba;
1080 sc->sc_tbc = tbc;
1081 }
1082
1083 SET(tp->t_state, TS_BUSY);
1084 sc->sc_tx_busy = 1;
1085
1086 /* Enable transmit completion interrupts if necessary. */
1087 if (!ISSET(sc->sc_cr3, CR3_TIE)) {
1088 SET(sc->sc_cr3, CR3_TIE);
1089 bus_space_write_4(iot, ioh, SACOM_CR3, sc->sc_cr3);
1090 }
1091
1092 /* Output the first chunk of the contiguous buffer. */
1093 sacom_filltx(sc);
1094
1095 COM_UNLOCK(sc);
1096 out:
1097 splx(s);
1098 return;
1099 }
1100
1101 void
sacom_filltx(struct sacom_softc * sc)1102 sacom_filltx(struct sacom_softc *sc)
1103 {
1104 bus_space_tag_t iot = sc->sc_iot;
1105 bus_space_handle_t ioh = sc->sc_ioh;
1106 int c, n;
1107
1108 n = 0;
1109 while (bus_space_read_4(iot, ioh, SACOM_SR1) & SR1_TNF) {
1110 if (n == SACOM_TXFIFOLEN || n == sc->sc_tbc)
1111 break;
1112 c = *(sc->sc_tba + n);
1113 c &= 0xff;
1114 bus_space_write_4(iot, ioh, SACOM_DR, c);
1115 n++;
1116 }
1117 sc->sc_tbc -= n;
1118 sc->sc_tba += n;
1119 }
1120
1121 /*
1122 * Stop output on a line.
1123 */
1124 void
sacomstop(struct tty * tp,int flag)1125 sacomstop(struct tty *tp, int flag)
1126 {
1127 struct sacom_softc *sc =
1128 device_lookup_private(&sacom_cd, COMUNIT(tp->t_dev));
1129 int s;
1130
1131 s = splserial();
1132 COM_LOCK(sc);
1133 if (ISSET(tp->t_state, TS_BUSY)) {
1134 /* Stop transmitting at the next chunk. */
1135 sc->sc_tbc = 0;
1136 sc->sc_heldtbc = 0;
1137 if (!ISSET(tp->t_state, TS_TTSTOP))
1138 SET(tp->t_state, TS_FLUSH);
1139 }
1140 COM_UNLOCK(sc);
1141 splx(s);
1142 }
1143
1144 static inline void
sacom_rxsoft(struct sacom_softc * sc,struct tty * tp)1145 sacom_rxsoft(struct sacom_softc *sc, struct tty *tp)
1146 {
1147 int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;
1148 u_char *get, *end;
1149 u_int cc, scc;
1150 u_char sr1;
1151 int code;
1152 int s;
1153
1154 end = sc->sc_ebuf;
1155 get = sc->sc_rbget;
1156 scc = cc = SACOM_RING_SIZE - sc->sc_rbavail;
1157
1158 while (cc) {
1159 code = get[0];
1160 sr1 = get[1];
1161 if (ISSET(sr1, SR1_FRE))
1162 SET(code, TTY_FE);
1163 if (ISSET(sr1, SR1_PRE))
1164 SET(code, TTY_PE);
1165 if ((*rint)(code, tp) == -1) {
1166 /*
1167 * The line discipline's buffer is out of space.
1168 */
1169 if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
1170 /*
1171 * We're either not using flow control, or the
1172 * line discipline didn't tell us to block for
1173 * some reason. Either way, we have no way to
1174 * know when there's more space available, so
1175 * just drop the rest of the data.
1176 */
1177 get += cc << 1;
1178 if (get >= end)
1179 get -= SACOM_RING_SIZE << 1;
1180 cc = 0;
1181 } else {
1182 /*
1183 * Don't schedule any more receive processing
1184 * until the line discipline tells us there's
1185 * space available (through comhwiflow()).
1186 * Leave the rest of the data in the input
1187 * buffer.
1188 */
1189 SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
1190 }
1191 break;
1192 }
1193 get += 2;
1194 if (get >= end)
1195 get = sc->sc_rbuf;
1196 cc--;
1197 }
1198
1199 if (cc != scc) {
1200 sc->sc_rbget = get;
1201 s = splserial();
1202 COM_LOCK(sc);
1203
1204 cc = sc->sc_rbavail += scc - cc;
1205 /* Buffers should be ok again, release possible block. */
1206 if (cc >= 1) {
1207 if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1208 CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1209 SET(sc->sc_cr3, CR3_RIE);
1210 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
1211 SACOM_CR3, sc->sc_cr3);
1212 }
1213 }
1214 COM_UNLOCK(sc);
1215 splx(s);
1216 }
1217 }
1218
1219 static inline void
sacom_txsoft(struct sacom_softc * sc,struct tty * tp)1220 sacom_txsoft(struct sacom_softc *sc, struct tty *tp)
1221 {
1222
1223 CLR(tp->t_state, TS_BUSY);
1224 if (ISSET(tp->t_state, TS_FLUSH))
1225 CLR(tp->t_state, TS_FLUSH);
1226 else
1227 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
1228 (*tp->t_linesw->l_start)(tp);
1229 }
1230
1231 static inline void
sacom_stsoft(struct sacom_softc * sc,struct tty * tp)1232 sacom_stsoft(struct sacom_softc *sc, struct tty *tp)
1233 {
1234 }
1235
1236 void
sacomsoft(void * arg)1237 sacomsoft(void *arg)
1238 {
1239 struct sacom_softc *sc = arg;
1240 struct tty *tp;
1241
1242 if (COM_ISALIVE(sc) == 0)
1243 return;
1244
1245 tp = sc->sc_tty;
1246
1247 if (sc->sc_rx_ready) {
1248 sc->sc_rx_ready = 0;
1249 sacom_rxsoft(sc, tp);
1250 }
1251
1252 if (sc->sc_st_check) {
1253 sc->sc_st_check = 0;
1254 sacom_stsoft(sc, tp);
1255 }
1256
1257 if (sc->sc_tx_done) {
1258 sc->sc_tx_done = 0;
1259 sacom_txsoft(sc, tp);
1260 }
1261 }
1262
1263 int
sacomintr(void * arg)1264 sacomintr(void *arg)
1265 {
1266 struct sacom_softc *sc = arg;
1267 bus_space_tag_t iot = sc->sc_iot;
1268 bus_space_handle_t ioh = sc->sc_ioh;
1269 u_char *put, *end;
1270 u_int cc;
1271 u_int sr0, sr1;
1272
1273 if (COM_ISALIVE(sc) == 0)
1274 return 0;
1275
1276 COM_LOCK(sc);
1277 sr0 = bus_space_read_4(iot, ioh, SACOM_SR0);
1278 if (!sr0) {
1279 COM_UNLOCK(sc);
1280 return 0;
1281 }
1282 if (ISSET(sr0, SR0_EIF))
1283 /* XXX silently discard error bits */
1284 bus_space_read_4(iot, ioh, SACOM_DR);
1285 if (ISSET(sr0, SR0_RBB))
1286 bus_space_write_4(iot, ioh, SACOM_SR0, SR0_RBB);
1287 if (ISSET(sr0, SR0_REB)) {
1288 bus_space_write_4(iot, ioh, SACOM_SR0, SR0_REB);
1289 #if defined(DDB) || defined(KGDB)
1290 #ifndef DDB_BREAK_CHAR
1291 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
1292 console_debugger();
1293 }
1294 #endif
1295 #endif /* DDB || KGDB */
1296 }
1297
1298
1299 end = sc->sc_ebuf;
1300 put = sc->sc_rbput;
1301 cc = sc->sc_rbavail;
1302
1303 sr1 = bus_space_read_4(iot, ioh, SACOM_SR1);
1304 if (ISSET(sr0, SR0_RFS | SR0_RID)) {
1305 if (!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1306 while (cc > 0) {
1307 if (!ISSET(sr1, SR1_RNE)) {
1308 bus_space_write_4(iot, ioh, SACOM_SR0,
1309 SR0_RID);
1310 break;
1311 }
1312 put[0] = bus_space_read_4(iot, ioh, SACOM_DR);
1313 put[1] = sr1;
1314 #if defined(DDB) && defined(DDB_BREAK_CHAR)
1315 if (put[0] == DDB_BREAK_CHAR &&
1316 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
1317 console_debugger();
1318
1319 sr1 = bus_space_read_4(iot, ioh, SACOM_SR1);
1320 continue;
1321 }
1322 #endif
1323 put += 2;
1324 if (put >= end)
1325 put = sc->sc_rbuf;
1326 cc--;
1327
1328 sr1 = bus_space_read_4(iot, ioh, SACOM_SR1);
1329 }
1330
1331 /*
1332 * Current string of incoming characters ended because
1333 * no more data was available or we ran out of space.
1334 * Schedule a receive event if any data was received.
1335 * If we're out of space, turn off receive interrupts.
1336 */
1337 sc->sc_rbput = put;
1338 sc->sc_rbavail = cc;
1339 if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
1340 sc->sc_rx_ready = 1;
1341
1342 /* XXX do RX hardware flow control */
1343
1344 /*
1345 * If we're out of space, disable receive interrupts
1346 * until the queue has drained a bit.
1347 */
1348 if (!cc) {
1349 SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1350 CLR(sc->sc_cr3, CR3_RIE);
1351 bus_space_write_4(iot, ioh, SACOM_CR3,
1352 sc->sc_cr3);
1353 }
1354 } else {
1355 #ifdef DIAGNOSTIC
1356 panic("sacomintr: we shouldn't reach here");
1357 #endif
1358 CLR(sc->sc_cr3, CR3_RIE);
1359 bus_space_write_4(iot, ioh, SACOM_CR3, sc->sc_cr3);
1360 }
1361 }
1362
1363 /*
1364 * Done handling any receive interrupts. See if data can be
1365 * transmitted as well. Schedule tx done event if no data left
1366 * and tty was marked busy.
1367 */
1368 sr0 = bus_space_read_4(iot, ioh, SACOM_SR0);
1369 if (ISSET(sr0, SR0_TFS)) {
1370 /*
1371 * If we've delayed a parameter change, do it now, and restart
1372 * output.
1373 * XXX sacom_loadchannelregs() waits TX completion,
1374 * XXX resulting in ~0.1s hang (300bps, 4 bytes) in worst case
1375 */
1376 if (sc->sc_heldchange) {
1377 sacom_loadchannelregs(sc);
1378 sc->sc_heldchange = 0;
1379 sc->sc_tbc = sc->sc_heldtbc;
1380 sc->sc_heldtbc = 0;
1381 }
1382
1383 /* Output the next chunk of the contiguous buffer, if any. */
1384 if (sc->sc_tbc > 0) {
1385 sacom_filltx(sc);
1386 } else {
1387 /* Disable transmit completion interrupts if necessary. */
1388 if (ISSET(sc->sc_cr3, CR3_TIE)) {
1389 CLR(sc->sc_cr3, CR3_TIE);
1390 bus_space_write_4(iot, ioh, SACOM_CR3,
1391 sc->sc_cr3);
1392 }
1393 if (sc->sc_tx_busy) {
1394 sc->sc_tx_busy = 0;
1395 sc->sc_tx_done = 1;
1396 }
1397 }
1398 }
1399 COM_UNLOCK(sc);
1400
1401 /* Wake up the poller. */
1402 softint_schedule(sc->sc_si);
1403
1404 #ifdef RND_COM
1405 rnd_add_uint32(&sc->rnd_source, iir | lsr);
1406 #endif
1407 return 1;
1408 }
1409
1410 static void
sacom_j720_init(device_t parent,device_t self)1411 sacom_j720_init(device_t parent, device_t self)
1412 {
1413 struct sa11x0_softc *sasc;
1414
1415 sasc = device_private(parent);
1416
1417 /* XXX this should be done at sc->enable function */
1418 bus_space_write_4(sasc->sc_iot, sasc->sc_gpioh,
1419 SAGPIO_PCR, 0xa0000);
1420 bus_space_write_4(sasc->sc_iot, sasc->sc_gpioh,
1421 SAGPIO_PSR, 0x100);
1422 }
1423
1424 /* Initialization for serial console */
1425 int
sacominit(bus_space_tag_t iot,bus_addr_t iobase,int baud,tcflag_t cflag,bus_space_handle_t * iohp)1426 sacominit(bus_space_tag_t iot, bus_addr_t iobase, int baud, tcflag_t cflag,
1427 bus_space_handle_t *iohp)
1428 {
1429 int brd, cr0;
1430
1431 if (bus_space_map(iot, iobase, SACOM_NPORTS, 0, iohp))
1432 aprint_normal("register map failed\n");
1433
1434 /* wait for the Tx queue to drain and disable the UART */
1435 while (bus_space_read_4(iot, *iohp, SACOM_SR1) & SR1_TBY)
1436 continue;
1437 bus_space_write_4(iot, *iohp, SACOM_CR3, 0);
1438
1439 cr0 = cflag2cr0(cflag);
1440 bus_space_write_4(iot, *iohp, SACOM_CR0, cr0);
1441
1442 brd = SACOMSPEED(baud);
1443 sacomconsrate = baud;
1444 sacomconsaddr = iobase;
1445 sacomconscflag = cflag;
1446 /* XXX assumes little endian */
1447 bus_space_write_4(iot, *iohp, SACOM_CR1, brd >> 8);
1448 bus_space_write_4(iot, *iohp, SACOM_CR2, brd & 0xff);
1449
1450 /* enable the UART */
1451 bus_space_write_4(iot, *iohp, SACOM_CR3, CR3_RXE | CR3_TXE);
1452
1453 return 0;
1454 }
1455
1456 void
sacomcnprobe(struct consdev * cp)1457 sacomcnprobe(struct consdev *cp)
1458 {
1459 cp->cn_pri = CN_REMOTE;
1460 }
1461
1462 void
sacomcninit(struct consdev * cp)1463 sacomcninit(struct consdev *cp)
1464 {
1465 if (cp == NULL) {
1466 /* XXX cp == NULL means that MMU is disabled. */
1467 sacomconsioh = SACOM3_BASE;
1468 sacomconstag = &sa11x0_bs_tag;
1469 cn_tab = &sacomcons;
1470 return;
1471 }
1472
1473 if (sacominit(&sa11x0_bs_tag, CONADDR, CONSPEED,
1474 CONMODE, &sacomconsioh))
1475 panic("can't init serial console @%x", CONADDR);
1476 cn_tab = &sacomcons;
1477 sacomconstag = &sa11x0_bs_tag;
1478 }
1479
1480 int
sacomcngetc(dev_t dev)1481 sacomcngetc(dev_t dev)
1482 {
1483 int c, s;
1484
1485 s = spltty(); /* XXX do we need this? */
1486
1487 while (!(bus_space_read_4(sacomconstag, sacomconsioh, SACOM_SR1)
1488 & SR1_RNE)) {
1489 #if defined(DDB) || defined(KGDB)
1490 #ifndef DDB_BREAK_CHAR
1491 u_int sr0;
1492
1493 sr0 = bus_space_read_4(sacomconstag, sacomconsioh, SACOM_SR0);
1494 if (ISSET(sr0, SR0_RBB))
1495 bus_space_write_4(sacomconstag, sacomconsioh,
1496 SACOM_SR0, SR0_RBB);
1497 if (ISSET(sr0, SR0_REB)) {
1498 bus_space_write_4(sacomconstag, sacomconsioh,
1499 SACOM_SR0, SR0_REB);
1500 if (db_active == 0)
1501 console_debugger();
1502 }
1503 #endif
1504 #endif /* DDB || KGDB */
1505 }
1506
1507 c = bus_space_read_4(sacomconstag, sacomconsioh, SACOM_DR);
1508 c &= 0xff;
1509 splx(s);
1510
1511 return c;
1512 }
1513
1514 void
sacomcnputc(dev_t dev,int c)1515 sacomcnputc(dev_t dev, int c)
1516 {
1517 int s;
1518
1519 s = spltty(); /* XXX do we need this? */
1520
1521 while (!(bus_space_read_4(sacomconstag, sacomconsioh, SACOM_SR1)
1522 & SR1_TNF))
1523 continue;
1524
1525 bus_space_write_4(sacomconstag, sacomconsioh, SACOM_DR, c);
1526 splx(s);
1527 }
1528
1529 void
sacomcnpollc(dev_t dev,int on)1530 sacomcnpollc(dev_t dev, int on)
1531 {
1532
1533 }
1534
1535 #if 0
1536 #ifdef DEBUG
1537 int
1538 sacomcncharpoll(void)
1539 {
1540 int c;
1541
1542 if (!(bus_space_read_4(sacomconstag, sacomconsioh, SACOM_SR1)
1543 & SR1_RNE))
1544 return -1;
1545
1546 c = bus_space_read_4(sacomconstag, sacomconsioh, SACOM_DR);
1547 c &= 0xff;
1548
1549 return c;
1550 }
1551 #endif
1552 #endif
1553
1554 /* helper function to identify the com ports used by
1555 console or KGDB (and not yet autoconf attached) */
1556 int
sacom_is_console(bus_space_tag_t iot,bus_addr_t iobase,bus_space_handle_t * ioh)1557 sacom_is_console(bus_space_tag_t iot, bus_addr_t iobase,
1558 bus_space_handle_t *ioh)
1559 {
1560 bus_space_handle_t help;
1561
1562 if (!sacomconsattached &&
1563 iot == sacomconstag && iobase == sacomconsaddr)
1564 help = sacomconsioh;
1565 else
1566 return 0;
1567
1568 if (ioh)
1569 *ioh = help;
1570 return 1;
1571 }
1572