No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / arm / ixp12x0 / ixp12x0_com.c
blob8f505688e64b5cca2e9ac6ed41e75f29a7ecdaf4
1 /* $NetBSD: ixp12x0_com.c,v 1.35 2009/03/14 14:45:55 dsl Exp $ */
2 /*
3 * Copyright (c) 1998, 1999, 2001, 2002 The NetBSD Foundation, Inc.
4 * All rights reserved.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Ichiro FUKUHARA and Naoto Shimazaki.
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by IWAMOTO Toshihiro.
12 * This code is derived from software contributed to The NetBSD Foundation
13 * by Charles M. Hannum.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
38 * Copyright (c) 1991 The Regents of the University of California.
39 * All rights reserved.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
65 * @(#)com.c 7.5 (Berkeley) 5/16/91
68 #include <sys/cdefs.h>
69 __KERNEL_RCSID(0, "$NetBSD: ixp12x0_com.c,v 1.35 2009/03/14 14:45:55 dsl Exp $");
71 #include "opt_ddb.h"
72 #include "opt_kgdb.h"
74 #include "rnd.h"
75 #if NRND > 0 && defined(RND_COM)
76 #include <sys/rnd.h>
77 #endif
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/types.h>
82 #include <sys/conf.h>
83 #include <sys/file.h>
84 #include <sys/device.h>
85 #include <sys/kernel.h>
86 #include <sys/malloc.h>
87 #include <sys/tty.h>
88 #include <sys/uio.h>
89 #include <sys/vnode.h>
90 #include <sys/kauth.h>
92 #include <machine/intr.h>
93 #include <machine/bus.h>
95 #include <arm/ixp12x0/ixp12x0_comreg.h>
96 #include <arm/ixp12x0/ixp12x0_comvar.h>
97 #include <arm/ixp12x0/ixp12x0reg.h>
98 #include <arm/ixp12x0/ixp12x0var.h>
100 #include <arm/ixp12x0/ixpsipvar.h>
102 #include <dev/cons.h>
103 #include "ixpcom.h"
105 static int ixpcomparam(struct tty *, struct termios *);
106 static void ixpcomstart(struct tty *);
107 static int ixpcomhwiflow(struct tty *, int);
109 static u_int cflag2cr(tcflag_t);
110 static void ixpcom_iflush(struct ixpcom_softc *);
111 static void ixpcom_set_cr(struct ixpcom_softc *);
113 int ixpcomcngetc(dev_t);
114 void ixpcomcnputc(dev_t, int);
115 void ixpcomcnpollc(dev_t, int);
117 static void ixpcomsoft(void* arg);
118 inline static void ixpcom_txsoft(struct ixpcom_softc *, struct tty *);
119 inline static void ixpcom_rxsoft(struct ixpcom_softc *, struct tty *);
121 void ixpcomcnprobe(struct consdev *);
122 void ixpcomcninit(struct consdev *);
124 u_int32_t ixpcom_cr = 0; /* tell cr to *_intr.c */
125 u_int32_t ixpcom_imask = 0; /* intrrupt mask from *_intr.c */
128 static struct ixpcom_cons_softc {
129 bus_space_tag_t sc_iot;
130 bus_space_handle_t sc_ioh;
131 bus_addr_t sc_baseaddr;
132 int sc_ospeed;
133 tcflag_t sc_cflag;
134 int sc_attached;
135 } ixpcomcn_sc;
137 static struct cnm_state ixpcom_cnm_state;
139 struct ixpcom_softc* ixpcom_sc = NULL;
141 extern struct cfdriver ixpcom_cd;
143 dev_type_open(ixpcomopen);
144 dev_type_close(ixpcomclose);
145 dev_type_read(ixpcomread);
146 dev_type_write(ixpcomwrite);
147 dev_type_ioctl(ixpcomioctl);
148 dev_type_stop(ixpcomstop);
149 dev_type_tty(ixpcomtty);
150 dev_type_poll(ixpcompoll);
152 const struct cdevsw ixpcom_cdevsw = {
153 ixpcomopen, ixpcomclose, ixpcomread, ixpcomwrite, ixpcomioctl,
154 ixpcomstop, ixpcomtty, ixpcompoll, nommap, ttykqfilter, D_TTY
157 struct consdev ixpcomcons = {
158 NULL, NULL, ixpcomcngetc, ixpcomcnputc, ixpcomcnpollc, NULL,
159 NULL, NULL, NODEV, CN_NORMAL
162 #ifndef DEFAULT_COMSPEED
163 #define DEFAULT_COMSPEED 38400
164 #endif
166 #define COMUNIT_MASK 0x7ffff
167 #define COMDIALOUT_MASK 0x80000
169 #define COMUNIT(x) (minor(x) & COMUNIT_MASK)
170 #define COMDIALOUT(x) (minor(x) & COMDIALOUT_MASK)
172 #define COM_ISALIVE(sc) ((sc)->enabled != 0 && \
173 device_is_active(&(sc)->sc_dev))
175 #define COM_BARRIER(t, h, f) bus_space_barrier((t), (h), 0, COM_NPORTS, (f))
177 #define COM_LOCK(sc);
178 #define COM_UNLOCK(sc);
180 #define CFLAGS2CR_MASK (CR_PE | CR_OES | CR_SBS | CR_DSS | CR_BRD)
182 void
183 ixpcom_attach_subr(struct ixpcom_softc *sc)
185 struct tty *tp;
187 ixpcom_sc = sc;
189 /* force to use ixpcom0 for console */
190 if (sc->sc_iot == ixpcomcn_sc.sc_iot
191 && sc->sc_baseaddr == ixpcomcn_sc.sc_baseaddr) {
192 ixpcomcn_sc.sc_attached = 1;
193 sc->sc_speed = IXPCOMSPEED2BRD(ixpcomcn_sc.sc_ospeed);
195 /* Make sure the console is always "hardwired". */
196 /* XXX IXPCOM_SR should be checked */
197 delay(10000); /* wait for output to finish */
198 SET(sc->sc_hwflags, COM_HW_CONSOLE);
199 SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
202 tp = ttymalloc();
203 tp->t_oproc = ixpcomstart;
204 tp->t_param = ixpcomparam;
205 tp->t_hwiflow = ixpcomhwiflow;
207 sc->sc_tty = tp;
208 sc->sc_rbuf = malloc(IXPCOM_RING_SIZE << 1, M_DEVBUF, M_NOWAIT);
209 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
210 sc->sc_rbavail = IXPCOM_RING_SIZE;
211 if (sc->sc_rbuf == NULL) {
212 printf("%s: unable to allocate ring buffer\n",
213 sc->sc_dev.dv_xname);
214 return;
216 sc->sc_ebuf = sc->sc_rbuf + (IXPCOM_RING_SIZE << 1);
217 sc->sc_tbc = 0;
219 sc->sc_rie = sc->sc_xie = 0;
220 ixpcom_cr = IXPCOMSPEED2BRD(DEFAULT_COMSPEED)
221 | CR_UE | sc->sc_rie | sc->sc_xie | DSS_8BIT;
223 tty_attach(tp);
225 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
226 int maj;
228 /* locate the major number */
229 maj = cdevsw_lookup_major(&ixpcom_cdevsw);
231 cn_tab->cn_dev = makedev(maj, device_unit(&sc->sc_dev));
233 aprint_normal("%s: console\n", sc->sc_dev.dv_xname);
236 sc->sc_si = softint_establish(SOFTINT_SERIAL, ixpcomsoft, sc);
238 #if NRND > 0 && defined(RND_COM)
239 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
240 RND_TYPE_TTY, 0);
241 #endif
243 /* if there are no enable/disable functions, assume the device
244 is always enabled */
245 if (!sc->enable)
246 sc->enabled = 1;
248 /* XXX configure register */
249 /* xxx_config(sc) */
251 SET(sc->sc_hwflags, COM_HW_DEV_OK);
254 static int
255 ixpcomparam(struct tty *tp, struct termios *t)
257 struct ixpcom_softc *sc
258 = device_lookup_private(&ixpcom_cd, COMUNIT(tp->t_dev));
259 u_int32_t cr;
260 int s;
262 if (COM_ISALIVE(sc) == 0)
263 return (EIO);
265 cr = IXPCOMSPEED2BRD(t->c_ospeed);
267 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
268 return (EINVAL);
271 * For the console, always force CLOCAL and !HUPCL, so that the port
272 * is always active.
274 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
275 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
276 SET(t->c_cflag, CLOCAL);
277 CLR(t->c_cflag, HUPCL);
281 * If there were no changes, don't do anything. This avoids dropping
282 * input and improves performance when all we did was frob things like
283 * VMIN and VTIME.
285 if (tp->t_ospeed == t->c_ospeed &&
286 tp->t_cflag == t->c_cflag)
287 return (0);
289 cr |= cflag2cr(t->c_cflag);
291 s = splserial();
292 COM_LOCK(sc);
294 ixpcom_cr = (ixpcom_cr & ~CFLAGS2CR_MASK) | cr;
297 * ixpcom don't have any hardware flow control.
298 * we skip it.
301 /* And copy to tty. */
302 tp->t_ispeed = 0;
303 tp->t_ospeed = t->c_ospeed;
304 tp->t_cflag = t->c_cflag;
306 if (!sc->sc_heldchange) {
307 if (sc->sc_tx_busy) {
308 sc->sc_heldtbc = sc->sc_tbc;
309 sc->sc_tbc = 0;
310 sc->sc_heldchange = 1;
311 } else
312 ixpcom_set_cr(sc);
315 COM_UNLOCK(sc);
316 splx(s);
319 * Update the tty layer's idea of the carrier bit.
320 * We tell tty the carrier is always on.
322 (void) (*tp->t_linesw->l_modem)(tp, 1);
324 #ifdef COM_DEBUG
325 if (com_debug)
326 comstatus(sc, "comparam ");
327 #endif
329 if (!ISSET(t->c_cflag, CHWFLOW)) {
330 if (sc->sc_tx_stopped) {
331 sc->sc_tx_stopped = 0;
332 ixpcomstart(tp);
336 return (0);
339 static int
340 ixpcomhwiflow(struct tty *tp, int block)
342 return (0);
345 static void
346 ixpcom_filltx(struct ixpcom_softc *sc)
348 bus_space_tag_t iot = sc->sc_iot;
349 bus_space_handle_t ioh = sc->sc_ioh;
350 int n;
352 n = 0;
353 while (bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_TXR) {
354 if (n >= sc->sc_tbc)
355 break;
356 bus_space_write_4(iot, ioh, IXPCOM_DR,
357 0xff & *(sc->sc_tba + n));
358 n++;
360 sc->sc_tbc -= n;
361 sc->sc_tba += n;
364 static void
365 ixpcomstart(struct tty *tp)
367 struct ixpcom_softc *sc
368 = device_lookup_private(&ixpcom_cd, COMUNIT(tp->t_dev));
369 int s;
371 if (COM_ISALIVE(sc) == 0)
372 return;
374 s = spltty();
375 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
376 goto out;
377 if (sc->sc_tx_stopped)
378 goto out;
380 if (!ttypull(tp))
381 goto out;
383 /* Grab the first contiguous region of buffer space. */
385 u_char *tba;
386 int tbc;
388 tba = tp->t_outq.c_cf;
389 tbc = ndqb(&tp->t_outq, 0);
391 (void)splserial();
392 COM_LOCK(sc);
394 sc->sc_tba = tba;
395 sc->sc_tbc = tbc;
398 SET(tp->t_state, TS_BUSY);
399 sc->sc_tx_busy = 1;
401 /* Enable transmit completion interrupts if necessary. */
402 if (!ISSET(sc->sc_xie, CR_XIE)) {
403 SET(sc->sc_xie, CR_XIE);
404 ixpcom_set_cr(sc);
407 /* Output the first chunk of the contiguous buffer. */
408 ixpcom_filltx(sc);
410 COM_UNLOCK(sc);
411 out:
412 splx(s);
413 return;
416 static void
417 ixpcom_break(struct ixpcom_softc *sc, int onoff)
419 if (onoff)
420 SET(ixpcom_cr, CR_BRK);
421 else
422 CLR(ixpcom_cr, CR_BRK);
423 if (!sc->sc_heldchange) {
424 if (sc->sc_tx_busy) {
425 sc->sc_heldtbc = sc->sc_tbc;
426 sc->sc_tbc = 0;
427 sc->sc_heldchange = 1;
428 } else
429 ixpcom_set_cr(sc);
433 static void
434 ixpcom_shutdown(struct ixpcom_softc *sc)
436 int s;
438 s = splserial();
439 COM_LOCK(sc);
441 /* Clear any break condition set with TIOCSBRK. */
442 ixpcom_break(sc, 0);
444 /* Turn off interrupts. */
445 sc->sc_rie = sc->sc_xie = 0;
446 ixpcom_set_cr(sc);
448 if (sc->disable) {
449 #ifdef DIAGNOSTIC
450 if (!sc->enabled)
451 panic("ixpcom_shutdown: not enabled?");
452 #endif
453 (*sc->disable)(sc);
454 sc->enabled = 0;
456 COM_UNLOCK(sc);
457 splx(s);
461 ixpcomopen(dev_t dev, int flag, int mode, struct lwp *l)
463 struct ixpcom_softc *sc;
464 struct tty *tp;
465 int s, s2;
466 int error;
468 sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
469 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK) ||
470 sc->sc_rbuf == NULL)
471 return (ENXIO);
473 if (!device_is_active(&sc->sc_dev))
474 return (ENXIO);
476 #ifdef KGDB
478 * If this is the kgdb port, no other use is permitted.
480 if (ISSET(sc->sc_hwflags, COM_HW_KGDB))
481 return (EBUSY);
482 #endif
484 tp = sc->sc_tty;
486 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
487 return (EBUSY);
489 s = spltty();
492 * Do the following iff this is a first open.
494 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
495 struct termios t;
497 tp->t_dev = dev;
499 s2 = splserial();
500 COM_LOCK(sc);
502 if (sc->enable) {
503 if ((*sc->enable)(sc)) {
504 COM_UNLOCK(sc);
505 splx(s2);
506 splx(s);
507 printf("%s: device enable failed\n",
508 sc->sc_dev.dv_xname);
509 return (EIO);
511 sc->enabled = 1;
512 #if 0
513 /* XXXXXXXXXXXXXXX */
514 com_config(sc);
515 #endif
518 /* Turn on interrupts. */
519 SET(sc->sc_rie, CR_RIE);
520 ixpcom_set_cr(sc);
522 #if 0
523 /* Fetch the current modem control status, needed later. */
524 sc->sc_msr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, com_msr);
526 /* Clear PPS capture state on first open. */
527 sc->sc_ppsmask = 0;
528 sc->ppsparam.mode = 0;
529 #endif
531 COM_UNLOCK(sc);
532 splx(s2);
535 * Initialize the termios status to the defaults. Add in the
536 * sticky bits from TIOCSFLAGS.
538 t.c_ispeed = 0;
539 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
540 t.c_ospeed = ixpcomcn_sc.sc_ospeed;
541 t.c_cflag = ixpcomcn_sc.sc_cflag;
542 } else {
543 t.c_ospeed = TTYDEF_SPEED;
544 t.c_cflag = TTYDEF_CFLAG;
546 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
547 SET(t.c_cflag, CLOCAL);
548 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
549 SET(t.c_cflag, CRTSCTS);
550 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
551 SET(t.c_cflag, MDMBUF);
552 /* Make sure ixpcomparam() will do something. */
553 tp->t_ospeed = 0;
554 (void) ixpcomparam(tp, &t);
555 tp->t_iflag = TTYDEF_IFLAG;
556 tp->t_oflag = TTYDEF_OFLAG;
557 tp->t_lflag = TTYDEF_LFLAG;
558 ttychars(tp);
559 ttsetwater(tp);
561 s2 = splserial();
562 COM_LOCK(sc);
564 /* Clear the input ring, and unblock. */
565 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
566 sc->sc_rbavail = IXPCOM_RING_SIZE;
567 ixpcom_iflush(sc);
568 CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
570 #ifdef COM_DEBUG
571 if (ixpcom_debug)
572 comstatus(sc, "ixpcomopen ");
573 #endif
575 COM_UNLOCK(sc);
576 splx(s2);
579 splx(s);
581 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
582 if (error)
583 goto bad;
585 error = (*tp->t_linesw->l_open)(dev, tp);
586 if (error)
587 goto bad;
589 return (0);
591 bad:
592 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
594 * We failed to open the device, and nobody else had it opened.
595 * Clean up the state as appropriate.
597 ixpcom_shutdown(sc);
600 return (error);
604 ixpcomclose(dev_t dev, int flag, int mode, struct lwp *l)
606 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
607 struct tty *tp = sc->sc_tty;
609 /* XXX This is for cons.c. */
610 if (!ISSET(tp->t_state, TS_ISOPEN))
611 return (0);
613 (*tp->t_linesw->l_close)(tp, flag);
614 ttyclose(tp);
616 if (COM_ISALIVE(sc) == 0)
617 return (0);
619 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
621 * Although we got a last close, the device may still be in
622 * use; e.g. if this was the dialout node, and there are still
623 * processes waiting for carrier on the non-dialout node.
625 ixpcom_shutdown(sc);
628 return (0);
632 ixpcomread(dev_t dev, struct uio *uio, int flag)
634 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
635 struct tty *tp = sc->sc_tty;
637 if (COM_ISALIVE(sc) == 0)
638 return (EIO);
640 return ((*tp->t_linesw->l_read)(tp, uio, flag));
644 ixpcomwrite(dev_t dev, struct uio *uio, int flag)
646 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
647 struct tty *tp = sc->sc_tty;
649 if (COM_ISALIVE(sc) == 0)
650 return (EIO);
652 return ((*tp->t_linesw->l_write)(tp, uio, flag));
656 ixpcompoll(dev_t dev, int events, struct lwp *l)
658 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
659 struct tty *tp = sc->sc_tty;
661 if (COM_ISALIVE(sc) == 0)
662 return (EIO);
664 return ((*tp->t_linesw->l_poll)(tp, events, l));
667 struct tty *
668 ixpcomtty(dev_t dev)
670 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
671 struct tty *tp = sc->sc_tty;
673 return (tp);
677 ixpcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
679 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
680 struct tty *tp = sc->sc_tty;
681 int error;
682 int s;
684 if (COM_ISALIVE(sc) == 0)
685 return (EIO);
687 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
688 if (error != EPASSTHROUGH)
689 return (error);
691 error = ttioctl(tp, cmd, data, flag, l);
692 if (error != EPASSTHROUGH)
693 return (error);
695 error = 0;
697 s = splserial();
698 COM_LOCK(sc);
700 switch (cmd) {
701 case TIOCSBRK:
702 ixpcom_break(sc, 1);
703 break;
705 case TIOCCBRK:
706 ixpcom_break(sc, 0);
707 break;
709 case TIOCGFLAGS:
710 *(int *)data = sc->sc_swflags;
711 break;
713 case TIOCSFLAGS:
714 error = kauth_authorize_device_tty(l->l_cred,
715 KAUTH_DEVICE_TTY_PRIVSET, tp);
716 if (error)
717 break;
718 sc->sc_swflags = *(int *)data;
719 break;
721 default:
722 error = EPASSTHROUGH;
723 break;
726 COM_UNLOCK(sc);
727 splx(s);
729 return (error);
733 * Stop output on a line.
735 void
736 ixpcomstop(struct tty *tp, int flag)
738 struct ixpcom_softc *sc
739 = device_lookup_private(&ixpcom_cd, COMUNIT(tp->t_dev));
740 int s;
742 s = splserial();
743 COM_LOCK(sc);
744 if (ISSET(tp->t_state, TS_BUSY)) {
745 /* Stop transmitting at the next chunk. */
746 sc->sc_tbc = 0;
747 sc->sc_heldtbc = 0;
748 if (!ISSET(tp->t_state, TS_TTSTOP))
749 SET(tp->t_state, TS_FLUSH);
751 COM_UNLOCK(sc);
752 splx(s);
755 static u_int
756 cflag2cr(tcflag_t cflag)
758 u_int cr;
760 cr = (cflag & PARENB) ? CR_PE : 0;
761 cr |= (cflag & PARODD) ? CR_OES : 0;
762 cr |= (cflag & CSTOPB) ? CR_SBS : 0;
763 cr |= ((cflag & CSIZE) == CS8) ? DSS_8BIT : 0;
765 return (cr);
768 static void
769 ixpcom_iflush(struct ixpcom_softc *sc)
771 bus_space_tag_t iot = sc->sc_iot;
772 bus_space_handle_t ioh = sc->sc_ioh;
773 #ifdef DIAGNOSTIC
774 int reg;
775 #endif
776 int timo;
778 #ifdef DIAGNOSTIC
779 reg = 0xffff;
780 #endif
781 timo = 50000;
782 /* flush any pending I/O */
783 while (ISSET(bus_space_read_4(iot, ioh, IXPCOM_SR), SR_RXR)
784 && --timo)
785 #ifdef DIAGNOSTIC
786 reg =
787 #else
788 (void)
789 #endif
790 bus_space_read_4(iot, ioh, IXPCOM_DR);
791 #ifdef DIAGNOSTIC
792 if (!timo)
793 printf("%s: com_iflush timeout %02x\n", sc->sc_dev.dv_xname,
794 reg);
795 #endif
798 static void
799 ixpcom_set_cr(struct ixpcom_softc *sc)
801 /* XXX */
802 ixpcom_cr &= ~(CR_RIE | CR_XIE);
803 ixpcom_cr |= sc->sc_rie | sc->sc_xie;
804 bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCOM_CR,
805 ixpcom_cr & ~ixpcom_imask);
809 ixpcomcnattach(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t ioh, int ospeed, tcflag_t cflag)
811 int cr;
813 cn_tab = &ixpcomcons;
814 cn_init_magic(&ixpcom_cnm_state);
816 * XXX
818 * ixpcom cannot detect a break. It can only detect framing
819 * errors. And, a sequence of "framing error, framing error"
820 * meens a break. So I made this hack:
822 * 1. Set default magic is a sequence of "BREAK, BREAK".
823 * 2. Tell cn_check_magic() a "framing error" as BREAK.
825 * see ixpcom_intr() too.
828 /* default magic is a couple of BREAK. */
829 cn_set_magic("\047\001\047\001");
831 ixpcomcn_sc.sc_iot = iot;
832 ixpcomcn_sc.sc_ioh = ioh;
833 ixpcomcn_sc.sc_baseaddr = iobase;
834 ixpcomcn_sc.sc_ospeed = ospeed;
835 ixpcomcn_sc.sc_cflag = cflag;
837 cr = cflag2cr(cflag);
838 cr |= IXPCOMSPEED2BRD(ospeed);
839 cr |= CR_UE;
840 ixpcom_cr = cr;
842 /* enable the UART */
843 bus_space_write_4(iot, iobase, IXPCOM_CR, cr);
845 return (0);
848 void
849 ixpcomcnprobe(struct consdev *cp)
851 cp->cn_pri = CN_REMOTE;
854 void
855 ixpcomcnpollc(dev_t dev, int on)
859 void
860 ixpcomcnputc(dev_t dev, int c)
862 int s;
863 bus_space_tag_t iot = ixpcomcn_sc.sc_iot;
864 bus_space_handle_t ioh = ixpcomcn_sc.sc_ioh;
866 s = splserial();
868 while(!(bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_TXR))
871 bus_space_write_4(iot, ioh, IXPCOM_DR, c);
873 #ifdef DEBUG
874 if (c == '\r') {
875 while(!(bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_TXE))
878 #endif
880 splx(s);
884 ixpcomcngetc(dev_t dev)
886 int c;
887 int s;
888 bus_space_tag_t iot = ixpcomcn_sc.sc_iot;
889 bus_space_handle_t ioh = ixpcomcn_sc.sc_ioh;
891 s = splserial();
893 while(!(bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_RXR))
896 c = bus_space_read_4(iot, ioh, IXPCOM_DR);
897 c &= 0xff;
898 splx(s);
900 return (c);
903 inline static void
904 ixpcom_txsoft(struct ixpcom_softc *sc, struct tty *tp)
906 CLR(tp->t_state, TS_BUSY);
907 if (ISSET(tp->t_state, TS_FLUSH))
908 CLR(tp->t_state, TS_FLUSH);
909 else
910 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
911 (*tp->t_linesw->l_start)(tp);
914 inline static void
915 ixpcom_rxsoft(struct ixpcom_softc *sc, struct tty *tp)
917 int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;
918 u_char *get, *end;
919 u_int cc, scc;
920 u_char lsr;
921 int code;
922 int s;
924 end = sc->sc_ebuf;
925 get = sc->sc_rbget;
926 scc = cc = IXPCOM_RING_SIZE - sc->sc_rbavail;
927 #if 0
928 if (cc == IXPCOM_RING_SIZE) {
929 sc->sc_floods++;
930 if (sc->sc_errors++ == 0)
931 callout_reset(&sc->sc_diag_callout, 60 * hz,
932 comdiag, sc);
934 #endif
935 while (cc) {
936 code = get[0];
937 lsr = get[1];
938 if (ISSET(lsr, DR_ROR | DR_FRE | DR_PRE)) {
939 #if 0
940 if (ISSET(lsr, DR_ROR)) {
941 sc->sc_overflows++;
942 if (sc->sc_errors++ == 0)
943 callout_reset(&sc->sc_diag_callout,
944 60 * hz, comdiag, sc);
946 #endif
947 if (ISSET(lsr, DR_FRE))
948 SET(code, TTY_FE);
949 if (ISSET(lsr, DR_PRE))
950 SET(code, TTY_PE);
952 if ((*rint)(code, tp) == -1) {
954 * The line discipline's buffer is out of space.
956 if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
958 * We're either not using flow control, or the
959 * line discipline didn't tell us to block for
960 * some reason. Either way, we have no way to
961 * know when there's more space available, so
962 * just drop the rest of the data.
964 get += cc << 1;
965 if (get >= end)
966 get -= IXPCOM_RING_SIZE << 1;
967 cc = 0;
968 } else {
970 * Don't schedule any more receive processing
971 * until the line discipline tells us there's
972 * space available (through comhwiflow()).
973 * Leave the rest of the data in the input
974 * buffer.
976 SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
978 break;
980 get += 2;
981 if (get >= end)
982 get = sc->sc_rbuf;
983 cc--;
986 if (cc != scc) {
987 sc->sc_rbget = get;
988 s = splserial();
989 COM_LOCK(sc);
991 cc = sc->sc_rbavail += scc - cc;
992 /* Buffers should be ok again, release possible block. */
993 if (cc >= 1) {
994 if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
995 CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
996 SET(sc->sc_rie, CR_RIE);
997 ixpcom_set_cr(sc);
999 if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) {
1000 CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED);
1001 #if 0
1002 com_hwiflow(sc);
1003 #endif
1006 COM_UNLOCK(sc);
1007 splx(s);
1011 static void
1012 ixpcomsoft(void* arg)
1014 struct ixpcom_softc *sc = arg;
1016 if (COM_ISALIVE(sc) == 0)
1017 return;
1019 if (sc->sc_rx_ready) {
1020 sc->sc_rx_ready = 0;
1021 ixpcom_rxsoft(sc, sc->sc_tty);
1023 if (sc->sc_tx_done) {
1024 sc->sc_tx_done = 0;
1025 ixpcom_txsoft(sc, sc->sc_tty);
1030 ixpcomintr(void* arg)
1032 struct ixpcom_softc *sc = arg;
1033 bus_space_tag_t iot = sc->sc_iot;
1034 bus_space_handle_t ioh = sc->sc_ioh;
1035 u_char *put, *end;
1036 u_int cc;
1037 u_int cr;
1038 u_int sr;
1039 u_int32_t c;
1041 if (COM_ISALIVE(sc) == 0)
1042 return (0);
1044 COM_LOCK(sc);
1045 cr = bus_space_read_4(iot, ioh, IXPCOM_CR) & CR_UE;
1047 if (!cr) {
1048 COM_UNLOCK(sc);
1049 return (0);
1052 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
1053 if (!ISSET(sr, SR_TXR | SR_RXR))
1054 return (0);
1057 * XXX
1059 * ixpcom cannot detect a break. It can only detect framing
1060 * errors. And, a sequence of "framing error, framing error"
1061 * meens a break. So I made this hack:
1063 * 1. Set default magic is a sequence of "BREAK, BREAK".
1064 * 2. Tell cn_check_magic() a "framing error" as BREAK.
1066 * see ixpcomcnattach() too.
1069 if (ISSET(sr, SR_FRE)) {
1070 cn_check_magic(sc->sc_tty->t_dev,
1071 CNC_BREAK, ixpcom_cnm_state);
1074 end = sc->sc_ebuf;
1075 put = sc->sc_rbput;
1076 cc = sc->sc_rbavail;
1078 if (ISSET(sr, SR_RXR)) {
1079 if (!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1080 while (cc > 0) {
1081 if (!ISSET(sr, SR_RXR))
1082 break;
1083 c = bus_space_read_4(iot, ioh, IXPCOM_DR);
1084 if (ISSET(c, DR_FRE)) {
1085 cn_check_magic(sc->sc_tty->t_dev,
1086 CNC_BREAK,
1087 ixpcom_cnm_state);
1089 put[0] = c & 0xff;
1090 put[1] = (c >> 8) & 0xff;
1091 cn_check_magic(sc->sc_tty->t_dev,
1092 put[0], ixpcom_cnm_state);
1093 put += 2;
1094 if (put >= end)
1095 put = sc->sc_rbuf;
1096 cc--;
1098 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
1102 * Current string of incoming characters ended because
1103 * no more data was available or we ran out of space.
1104 * Schedule a receive event if any data was received.
1105 * If we're out of space, turn off receive interrupts.
1107 sc->sc_rbput = put;
1108 sc->sc_rbavail = cc;
1109 if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
1110 sc->sc_rx_ready = 1;
1113 * See if we are in danger of overflowing a buffer. If
1114 * so, use hardware flow control to ease the pressure.
1117 /* but ixpcom cannot. X-( */
1120 * If we're out of space, disable receive interrupts
1121 * until the queue has drained a bit.
1123 if (!cc) {
1124 SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1125 CLR(sc->sc_rie, CR_RIE);
1126 ixpcom_set_cr(sc);
1128 } else {
1129 #ifdef DIAGNOSTIC
1130 panic("ixpcomintr: we shouldn't reach here");
1131 #endif
1132 CLR(sc->sc_rie, CR_RIE);
1133 ixpcom_set_cr(sc);
1138 * Done handling any receive interrupts. See if data can be
1139 * transmitted as well. Schedule tx done event if no data left
1140 * and tty was marked busy.
1142 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
1143 if (ISSET(sr, SR_TXR)) {
1145 * If we've delayed a parameter change, do it now, and restart
1146 * output.
1148 if (sc->sc_heldchange) {
1149 ixpcom_set_cr(sc);
1150 sc->sc_heldchange = 0;
1151 sc->sc_tbc = sc->sc_heldtbc;
1152 sc->sc_heldtbc = 0;
1155 /* Output the next chunk of the contiguous buffer, if any. */
1156 if (sc->sc_tbc > 0) {
1157 ixpcom_filltx(sc);
1158 } else {
1159 /* Disable transmit completion interrupts if necessary. */
1160 if (ISSET(sc->sc_xie, CR_XIE)) {
1161 CLR(sc->sc_xie, CR_XIE);
1162 ixpcom_set_cr(sc);
1164 if (sc->sc_tx_busy) {
1165 sc->sc_tx_busy = 0;
1166 sc->sc_tx_done = 1;
1170 COM_UNLOCK(sc);
1172 /* Wake up the poller. */
1173 softint_schedule(sc->sc_si);
1175 #if NRND > 0 && defined(RND_COM)
1176 rnd_add_uint32(&sc->rnd_source, iir | lsr);
1177 #endif
1178 return (1);