ixp12x0_com.c revision 1.43 1 /* $NetBSD: ixp12x0_com.c,v 1.43 2014/03/16 05:20:23 dholland Exp $ */
2 /*
3 * Copyright (c) 1998, 1999, 2001, 2002 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Ichiro FUKUHARA and Naoto Shimazaki.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by IWAMOTO Toshihiro.
11 *
12 * This code is derived from software contributed to The NetBSD Foundation
13 * by Charles M. Hannum.
14 *
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.
23 *
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.
35 */
36
37 /*
38 * Copyright (c) 1991 The Regents of the University of California.
39 * All rights reserved.
40 *
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.
52 *
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.
64 *
65 * @(#)com.c 7.5 (Berkeley) 5/16/91
66 */
67
68 #include <sys/cdefs.h>
69 __KERNEL_RCSID(0, "$NetBSD: ixp12x0_com.c,v 1.43 2014/03/16 05:20:23 dholland Exp $");
70
71 #include "opt_ddb.h"
72 #include "opt_kgdb.h"
73
74 #include "rnd.h"
75 #ifdef RND_COM
76 #include <sys/rnd.h>
77 #endif
78
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>
91 #include <sys/lwp.h>
92
93 #include <machine/intr.h>
94 #include <sys/bus.h>
95
96 #include <arm/ixp12x0/ixp12x0_comreg.h>
97 #include <arm/ixp12x0/ixp12x0_comvar.h>
98 #include <arm/ixp12x0/ixp12x0reg.h>
99 #include <arm/ixp12x0/ixp12x0var.h>
100
101 #include <arm/ixp12x0/ixpsipvar.h>
102
103 #include <dev/cons.h>
104 #include "ixpcom.h"
105
106 static int ixpcomparam(struct tty *, struct termios *);
107 static void ixpcomstart(struct tty *);
108 static int ixpcomhwiflow(struct tty *, int);
109
110 static u_int cflag2cr(tcflag_t);
111 static void ixpcom_iflush(struct ixpcom_softc *);
112 static void ixpcom_set_cr(struct ixpcom_softc *);
113
114 int ixpcomcngetc(dev_t);
115 void ixpcomcnputc(dev_t, int);
116 void ixpcomcnpollc(dev_t, int);
117
118 static void ixpcomsoft(void* arg);
119 inline static void ixpcom_txsoft(struct ixpcom_softc *, struct tty *);
120 inline static void ixpcom_rxsoft(struct ixpcom_softc *, struct tty *);
121
122 void ixpcomcnprobe(struct consdev *);
123 void ixpcomcninit(struct consdev *);
124
125 uint32_t ixpcom_cr = 0; /* tell cr to *_intr.c */
126 uint32_t ixpcom_imask = 0; /* intrrupt mask from *_intr.c */
127
128
129 static struct ixpcom_cons_softc {
130 bus_space_tag_t sc_iot;
131 bus_space_handle_t sc_ioh;
132 bus_addr_t sc_baseaddr;
133 int sc_ospeed;
134 tcflag_t sc_cflag;
135 int sc_attached;
136 } ixpcomcn_sc;
137
138 static struct cnm_state ixpcom_cnm_state;
139
140 struct ixpcom_softc* ixpcom_sc = NULL;
141
142 extern struct cfdriver ixpcom_cd;
143
144 dev_type_open(ixpcomopen);
145 dev_type_close(ixpcomclose);
146 dev_type_read(ixpcomread);
147 dev_type_write(ixpcomwrite);
148 dev_type_ioctl(ixpcomioctl);
149 dev_type_stop(ixpcomstop);
150 dev_type_tty(ixpcomtty);
151 dev_type_poll(ixpcompoll);
152
153 const struct cdevsw ixpcom_cdevsw = {
154 .d_open = ixpcomopen,
155 .d_close = ixpcomclose,
156 .d_read = ixpcomread,
157 .d_write = ixpcomwrite,
158 .d_ioctl = ixpcomioctl,
159 .d_stop = ixpcomstop,
160 .d_tty = ixpcomtty,
161 .d_poll = ixpcompoll,
162 .d_mmap = nommap,
163 .d_kqfilter = ttykqfilter,
164 .d_flag = D_TTY
165 };
166
167 struct consdev ixpcomcons = {
168 NULL, NULL, ixpcomcngetc, ixpcomcnputc, ixpcomcnpollc, NULL,
169 NULL, NULL, NODEV, CN_NORMAL
170 };
171
172 #ifndef DEFAULT_COMSPEED
173 #define DEFAULT_COMSPEED 38400
174 #endif
175
176 #define COMUNIT_MASK 0x7ffff
177 #define COMDIALOUT_MASK 0x80000
178
179 #define COMUNIT(x) (minor(x) & COMUNIT_MASK)
180 #define COMDIALOUT(x) (minor(x) & COMDIALOUT_MASK)
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
187 #define COM_LOCK(sc);
188 #define COM_UNLOCK(sc);
189
190 #define CFLAGS2CR_MASK (CR_PE | CR_OES | CR_SBS | CR_DSS | CR_BRD)
191
192 void
193 ixpcom_attach_subr(struct ixpcom_softc *sc)
194 {
195 struct tty *tp;
196
197 ixpcom_sc = sc;
198
199 /* force to use ixpcom0 for console */
200 if (sc->sc_iot == ixpcomcn_sc.sc_iot
201 && sc->sc_baseaddr == ixpcomcn_sc.sc_baseaddr) {
202 ixpcomcn_sc.sc_attached = 1;
203 sc->sc_speed = IXPCOMSPEED2BRD(ixpcomcn_sc.sc_ospeed);
204
205 /* Make sure the console is always "hardwired". */
206 /* XXX IXPCOM_SR should be checked */
207 delay(10000); /* wait for output to finish */
208 SET(sc->sc_hwflags, COM_HW_CONSOLE);
209 SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
210 }
211
212 tp = tty_alloc();
213 tp->t_oproc = ixpcomstart;
214 tp->t_param = ixpcomparam;
215 tp->t_hwiflow = ixpcomhwiflow;
216
217 sc->sc_tty = tp;
218 sc->sc_rbuf = malloc(IXPCOM_RING_SIZE << 1, M_DEVBUF, M_NOWAIT);
219 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
220 sc->sc_rbavail = IXPCOM_RING_SIZE;
221 if (sc->sc_rbuf == NULL) {
222 printf("%s: unable to allocate ring buffer\n",
223 device_xname(sc->sc_dev));
224 return;
225 }
226 sc->sc_ebuf = sc->sc_rbuf + (IXPCOM_RING_SIZE << 1);
227 sc->sc_tbc = 0;
228
229 sc->sc_rie = sc->sc_xie = 0;
230 ixpcom_cr = IXPCOMSPEED2BRD(DEFAULT_COMSPEED)
231 | CR_UE | sc->sc_rie | sc->sc_xie | DSS_8BIT;
232
233 tty_attach(tp);
234
235 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
236 int maj;
237
238 /* locate the major number */
239 maj = cdevsw_lookup_major(&ixpcom_cdevsw);
240
241 cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev));
242
243 aprint_normal("%s: console\n", device_xname(sc->sc_dev));
244 }
245
246 sc->sc_si = softint_establish(SOFTINT_SERIAL, ixpcomsoft, sc);
247
248 #ifdef RND_COM
249 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
250 RND_TYPE_TTY, 0);
251 #endif
252
253 /* if there are no enable/disable functions, assume the device
254 is always enabled */
255 if (!sc->enable)
256 sc->enabled = 1;
257
258 /* XXX configure register */
259 /* xxx_config(sc) */
260
261 SET(sc->sc_hwflags, COM_HW_DEV_OK);
262 }
263
264 static int
265 ixpcomparam(struct tty *tp, struct termios *t)
266 {
267 struct ixpcom_softc *sc
268 = device_lookup_private(&ixpcom_cd, COMUNIT(tp->t_dev));
269 uint32_t cr;
270 int s;
271
272 if (COM_ISALIVE(sc) == 0)
273 return (EIO);
274
275 cr = IXPCOMSPEED2BRD(t->c_ospeed);
276
277 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
278 return (EINVAL);
279
280 /*
281 * For the console, always force CLOCAL and !HUPCL, so that the port
282 * is always active.
283 */
284 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
285 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
286 SET(t->c_cflag, CLOCAL);
287 CLR(t->c_cflag, HUPCL);
288 }
289
290 /*
291 * If there were no changes, don't do anything. This avoids dropping
292 * input and improves performance when all we did was frob things like
293 * VMIN and VTIME.
294 */
295 if (tp->t_ospeed == t->c_ospeed &&
296 tp->t_cflag == t->c_cflag)
297 return (0);
298
299 cr |= cflag2cr(t->c_cflag);
300
301 s = splserial();
302 COM_LOCK(sc);
303
304 ixpcom_cr = (ixpcom_cr & ~CFLAGS2CR_MASK) | cr;
305
306 /*
307 * ixpcom don't have any hardware flow control.
308 * we skip it.
309 */
310
311 /* And copy to tty. */
312 tp->t_ispeed = 0;
313 tp->t_ospeed = t->c_ospeed;
314 tp->t_cflag = t->c_cflag;
315
316 if (!sc->sc_heldchange) {
317 if (sc->sc_tx_busy) {
318 sc->sc_heldtbc = sc->sc_tbc;
319 sc->sc_tbc = 0;
320 sc->sc_heldchange = 1;
321 } else
322 ixpcom_set_cr(sc);
323 }
324
325 COM_UNLOCK(sc);
326 splx(s);
327
328 /*
329 * Update the tty layer's idea of the carrier bit.
330 * We tell tty the carrier is always on.
331 */
332 (void) (*tp->t_linesw->l_modem)(tp, 1);
333
334 #ifdef COM_DEBUG
335 if (com_debug)
336 comstatus(sc, "comparam ");
337 #endif
338
339 if (!ISSET(t->c_cflag, CHWFLOW)) {
340 if (sc->sc_tx_stopped) {
341 sc->sc_tx_stopped = 0;
342 ixpcomstart(tp);
343 }
344 }
345
346 return (0);
347 }
348
349 static int
350 ixpcomhwiflow(struct tty *tp, int block)
351 {
352 return (0);
353 }
354
355 static void
356 ixpcom_filltx(struct ixpcom_softc *sc)
357 {
358 bus_space_tag_t iot = sc->sc_iot;
359 bus_space_handle_t ioh = sc->sc_ioh;
360 int n;
361
362 n = 0;
363 while (bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_TXR) {
364 if (n >= sc->sc_tbc)
365 break;
366 bus_space_write_4(iot, ioh, IXPCOM_DR,
367 0xff & *(sc->sc_tba + n));
368 n++;
369 }
370 sc->sc_tbc -= n;
371 sc->sc_tba += n;
372 }
373
374 static void
375 ixpcomstart(struct tty *tp)
376 {
377 struct ixpcom_softc *sc
378 = device_lookup_private(&ixpcom_cd, COMUNIT(tp->t_dev));
379 int s;
380
381 if (COM_ISALIVE(sc) == 0)
382 return;
383
384 s = spltty();
385 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
386 goto out;
387 if (sc->sc_tx_stopped)
388 goto out;
389
390 if (!ttypull(tp))
391 goto out;
392
393 /* Grab the first contiguous region of buffer space. */
394 {
395 u_char *tba;
396 int tbc;
397
398 tba = tp->t_outq.c_cf;
399 tbc = ndqb(&tp->t_outq, 0);
400
401 (void)splserial();
402 COM_LOCK(sc);
403
404 sc->sc_tba = tba;
405 sc->sc_tbc = tbc;
406 }
407
408 SET(tp->t_state, TS_BUSY);
409 sc->sc_tx_busy = 1;
410
411 /* Enable transmit completion interrupts if necessary. */
412 if (!ISSET(sc->sc_xie, CR_XIE)) {
413 SET(sc->sc_xie, CR_XIE);
414 ixpcom_set_cr(sc);
415 }
416
417 /* Output the first chunk of the contiguous buffer. */
418 ixpcom_filltx(sc);
419
420 COM_UNLOCK(sc);
421 out:
422 splx(s);
423 return;
424 }
425
426 static void
427 ixpcom_break(struct ixpcom_softc *sc, int onoff)
428 {
429 if (onoff)
430 SET(ixpcom_cr, CR_BRK);
431 else
432 CLR(ixpcom_cr, CR_BRK);
433 if (!sc->sc_heldchange) {
434 if (sc->sc_tx_busy) {
435 sc->sc_heldtbc = sc->sc_tbc;
436 sc->sc_tbc = 0;
437 sc->sc_heldchange = 1;
438 } else
439 ixpcom_set_cr(sc);
440 }
441 }
442
443 static void
444 ixpcom_shutdown(struct ixpcom_softc *sc)
445 {
446 int s;
447
448 s = splserial();
449 COM_LOCK(sc);
450
451 /* Clear any break condition set with TIOCSBRK. */
452 ixpcom_break(sc, 0);
453
454 /* Turn off interrupts. */
455 sc->sc_rie = sc->sc_xie = 0;
456 ixpcom_set_cr(sc);
457
458 if (sc->disable) {
459 #ifdef DIAGNOSTIC
460 if (!sc->enabled)
461 panic("ixpcom_shutdown: not enabled?");
462 #endif
463 (*sc->disable)(sc);
464 sc->enabled = 0;
465 }
466 COM_UNLOCK(sc);
467 splx(s);
468 }
469
470 int
471 ixpcomopen(dev_t dev, int flag, int mode, struct lwp *l)
472 {
473 struct ixpcom_softc *sc;
474 struct tty *tp;
475 int s, s2;
476 int error;
477
478 sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
479 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK) ||
480 sc->sc_rbuf == NULL)
481 return (ENXIO);
482
483 if (!device_is_active(sc->sc_dev))
484 return (ENXIO);
485
486 #ifdef KGDB
487 /*
488 * If this is the kgdb port, no other use is permitted.
489 */
490 if (ISSET(sc->sc_hwflags, COM_HW_KGDB))
491 return (EBUSY);
492 #endif
493
494 tp = sc->sc_tty;
495
496 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
497 return (EBUSY);
498
499 s = spltty();
500
501 /*
502 * Do the following iff this is a first open.
503 */
504 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
505 struct termios t;
506
507 tp->t_dev = dev;
508
509 s2 = splserial();
510 COM_LOCK(sc);
511
512 if (sc->enable) {
513 if ((*sc->enable)(sc)) {
514 COM_UNLOCK(sc);
515 splx(s2);
516 splx(s);
517 printf("%s: device enable failed\n",
518 device_xname(sc->sc_dev));
519 return (EIO);
520 }
521 sc->enabled = 1;
522 #if 0
523 /* XXXXXXXXXXXXXXX */
524 com_config(sc);
525 #endif
526 }
527
528 /* Turn on interrupts. */
529 SET(sc->sc_rie, CR_RIE);
530 ixpcom_set_cr(sc);
531
532 #if 0
533 /* Fetch the current modem control status, needed later. */
534 sc->sc_msr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, com_msr);
535
536 /* Clear PPS capture state on first open. */
537 sc->sc_ppsmask = 0;
538 sc->ppsparam.mode = 0;
539 #endif
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 = ixpcomcn_sc.sc_ospeed;
551 t.c_cflag = ixpcomcn_sc.sc_cflag;
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 ixpcomparam() will do something. */
563 tp->t_ospeed = 0;
564 (void) ixpcomparam(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 /* Clear the input ring, and unblock. */
575 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
576 sc->sc_rbavail = IXPCOM_RING_SIZE;
577 ixpcom_iflush(sc);
578 CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
579
580 #ifdef COM_DEBUG
581 if (ixpcom_debug)
582 comstatus(sc, "ixpcomopen ");
583 #endif
584
585 COM_UNLOCK(sc);
586 splx(s2);
587 }
588
589 splx(s);
590
591 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
592 if (error)
593 goto bad;
594
595 error = (*tp->t_linesw->l_open)(dev, tp);
596 if (error)
597 goto bad;
598
599 return (0);
600
601 bad:
602 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
603 /*
604 * We failed to open the device, and nobody else had it opened.
605 * Clean up the state as appropriate.
606 */
607 ixpcom_shutdown(sc);
608 }
609
610 return (error);
611 }
612
613 int
614 ixpcomclose(dev_t dev, int flag, int mode, struct lwp *l)
615 {
616 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
617 struct tty *tp = sc->sc_tty;
618
619 /* XXX This is for cons.c. */
620 if (!ISSET(tp->t_state, TS_ISOPEN))
621 return (0);
622
623 (*tp->t_linesw->l_close)(tp, flag);
624 ttyclose(tp);
625
626 if (COM_ISALIVE(sc) == 0)
627 return (0);
628
629 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
630 /*
631 * Although we got a last close, the device may still be in
632 * use; e.g. if this was the dialout node, and there are still
633 * processes waiting for carrier on the non-dialout node.
634 */
635 ixpcom_shutdown(sc);
636 }
637
638 return (0);
639 }
640
641 int
642 ixpcomread(dev_t dev, struct uio *uio, int flag)
643 {
644 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
645 struct tty *tp = sc->sc_tty;
646
647 if (COM_ISALIVE(sc) == 0)
648 return (EIO);
649
650 return ((*tp->t_linesw->l_read)(tp, uio, flag));
651 }
652
653 int
654 ixpcomwrite(dev_t dev, struct uio *uio, int flag)
655 {
656 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_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_write)(tp, uio, flag));
663 }
664
665 int
666 ixpcompoll(dev_t dev, int events, struct lwp *l)
667 {
668 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
669 struct tty *tp = sc->sc_tty;
670
671 if (COM_ISALIVE(sc) == 0)
672 return (EIO);
673
674 return ((*tp->t_linesw->l_poll)(tp, events, l));
675 }
676
677 struct tty *
678 ixpcomtty(dev_t dev)
679 {
680 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
681 struct tty *tp = sc->sc_tty;
682
683 return (tp);
684 }
685
686 int
687 ixpcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
688 {
689 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev));
690 struct tty *tp = sc->sc_tty;
691 int error;
692 int s;
693
694 if (COM_ISALIVE(sc) == 0)
695 return (EIO);
696
697 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
698 if (error != EPASSTHROUGH)
699 return (error);
700
701 error = ttioctl(tp, cmd, data, flag, l);
702 if (error != EPASSTHROUGH)
703 return (error);
704
705 error = 0;
706
707 s = splserial();
708 COM_LOCK(sc);
709
710 switch (cmd) {
711 case TIOCSBRK:
712 ixpcom_break(sc, 1);
713 break;
714
715 case TIOCCBRK:
716 ixpcom_break(sc, 0);
717 break;
718
719 case TIOCGFLAGS:
720 *(int *)data = sc->sc_swflags;
721 break;
722
723 case TIOCSFLAGS:
724 error = kauth_authorize_device_tty(l->l_cred,
725 KAUTH_DEVICE_TTY_PRIVSET, tp);
726 if (error)
727 break;
728 sc->sc_swflags = *(int *)data;
729 break;
730
731 default:
732 error = EPASSTHROUGH;
733 break;
734 }
735
736 COM_UNLOCK(sc);
737 splx(s);
738
739 return (error);
740 }
741
742 /*
743 * Stop output on a line.
744 */
745 void
746 ixpcomstop(struct tty *tp, int flag)
747 {
748 struct ixpcom_softc *sc
749 = device_lookup_private(&ixpcom_cd, COMUNIT(tp->t_dev));
750 int s;
751
752 s = splserial();
753 COM_LOCK(sc);
754 if (ISSET(tp->t_state, TS_BUSY)) {
755 /* Stop transmitting at the next chunk. */
756 sc->sc_tbc = 0;
757 sc->sc_heldtbc = 0;
758 if (!ISSET(tp->t_state, TS_TTSTOP))
759 SET(tp->t_state, TS_FLUSH);
760 }
761 COM_UNLOCK(sc);
762 splx(s);
763 }
764
765 static u_int
766 cflag2cr(tcflag_t cflag)
767 {
768 u_int cr;
769
770 cr = (cflag & PARENB) ? CR_PE : 0;
771 cr |= (cflag & PARODD) ? CR_OES : 0;
772 cr |= (cflag & CSTOPB) ? CR_SBS : 0;
773 cr |= ((cflag & CSIZE) == CS8) ? DSS_8BIT : 0;
774
775 return (cr);
776 }
777
778 static void
779 ixpcom_iflush(struct ixpcom_softc *sc)
780 {
781 bus_space_tag_t iot = sc->sc_iot;
782 bus_space_handle_t ioh = sc->sc_ioh;
783 #ifdef DIAGNOSTIC
784 int reg;
785 #endif
786 int timo;
787
788 #ifdef DIAGNOSTIC
789 reg = 0xffff;
790 #endif
791 timo = 50000;
792 /* flush any pending I/O */
793 while (ISSET(bus_space_read_4(iot, ioh, IXPCOM_SR), SR_RXR)
794 && --timo)
795 #ifdef DIAGNOSTIC
796 reg =
797 #else
798 (void)
799 #endif
800 bus_space_read_4(iot, ioh, IXPCOM_DR);
801 #ifdef DIAGNOSTIC
802 if (!timo)
803 printf("%s: com_iflush timeout %02x\n", device_xname(sc->sc_dev),
804 reg);
805 #endif
806 }
807
808 static void
809 ixpcom_set_cr(struct ixpcom_softc *sc)
810 {
811 /* XXX */
812 ixpcom_cr &= ~(CR_RIE | CR_XIE);
813 ixpcom_cr |= sc->sc_rie | sc->sc_xie;
814 bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCOM_CR,
815 ixpcom_cr & ~ixpcom_imask);
816 }
817
818 int
819 ixpcomcnattach(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t ioh, int ospeed, tcflag_t cflag)
820 {
821 int cr;
822
823 cn_tab = &ixpcomcons;
824 cn_init_magic(&ixpcom_cnm_state);
825 /*
826 * XXX
827 *
828 * ixpcom cannot detect a break. It can only detect framing
829 * errors. And, a sequence of "framing error, framing error"
830 * meens a break. So I made this hack:
831 *
832 * 1. Set default magic is a sequence of "BREAK, BREAK".
833 * 2. Tell cn_check_magic() a "framing error" as BREAK.
834 *
835 * see ixpcom_intr() too.
836 *
837 */
838 /* default magic is a couple of BREAK. */
839 cn_set_magic("\047\001\047\001");
840
841 ixpcomcn_sc.sc_iot = iot;
842 ixpcomcn_sc.sc_ioh = ioh;
843 ixpcomcn_sc.sc_baseaddr = iobase;
844 ixpcomcn_sc.sc_ospeed = ospeed;
845 ixpcomcn_sc.sc_cflag = cflag;
846
847 cr = cflag2cr(cflag);
848 cr |= IXPCOMSPEED2BRD(ospeed);
849 cr |= CR_UE;
850 ixpcom_cr = cr;
851
852 /* enable the UART */
853 bus_space_write_4(iot, iobase, IXPCOM_CR, cr);
854
855 return (0);
856 }
857
858 void
859 ixpcomcnprobe(struct consdev *cp)
860 {
861 cp->cn_pri = CN_REMOTE;
862 }
863
864 void
865 ixpcomcnpollc(dev_t dev, int on)
866 {
867 }
868
869 void
870 ixpcomcnputc(dev_t dev, int c)
871 {
872 int s;
873 bus_space_tag_t iot = ixpcomcn_sc.sc_iot;
874 bus_space_handle_t ioh = ixpcomcn_sc.sc_ioh;
875
876 s = splserial();
877
878 while(!(bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_TXR))
879 ;
880
881 bus_space_write_4(iot, ioh, IXPCOM_DR, c);
882
883 #ifdef DEBUG
884 if (c == '\r') {
885 while(!(bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_TXE))
886 ;
887 }
888 #endif
889
890 splx(s);
891 }
892
893 int
894 ixpcomcngetc(dev_t dev)
895 {
896 int c;
897 int s;
898 bus_space_tag_t iot = ixpcomcn_sc.sc_iot;
899 bus_space_handle_t ioh = ixpcomcn_sc.sc_ioh;
900
901 s = splserial();
902
903 while(!(bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_RXR))
904 ;
905
906 c = bus_space_read_4(iot, ioh, IXPCOM_DR);
907 c &= 0xff;
908 splx(s);
909
910 return (c);
911 }
912
913 inline static void
914 ixpcom_txsoft(struct ixpcom_softc *sc, struct tty *tp)
915 {
916 CLR(tp->t_state, TS_BUSY);
917 if (ISSET(tp->t_state, TS_FLUSH))
918 CLR(tp->t_state, TS_FLUSH);
919 else
920 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
921 (*tp->t_linesw->l_start)(tp);
922 }
923
924 inline static void
925 ixpcom_rxsoft(struct ixpcom_softc *sc, struct tty *tp)
926 {
927 int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;
928 u_char *get, *end;
929 u_int cc, scc;
930 u_char lsr;
931 int code;
932 int s;
933
934 end = sc->sc_ebuf;
935 get = sc->sc_rbget;
936 scc = cc = IXPCOM_RING_SIZE - sc->sc_rbavail;
937 #if 0
938 if (cc == IXPCOM_RING_SIZE) {
939 sc->sc_floods++;
940 if (sc->sc_errors++ == 0)
941 callout_reset(&sc->sc_diag_callout, 60 * hz,
942 comdiag, sc);
943 }
944 #endif
945 while (cc) {
946 code = get[0];
947 lsr = get[1];
948 if (ISSET(lsr, DR_ROR | DR_FRE | DR_PRE)) {
949 #if 0
950 if (ISSET(lsr, DR_ROR)) {
951 sc->sc_overflows++;
952 if (sc->sc_errors++ == 0)
953 callout_reset(&sc->sc_diag_callout,
954 60 * hz, comdiag, sc);
955 }
956 #endif
957 if (ISSET(lsr, DR_FRE))
958 SET(code, TTY_FE);
959 if (ISSET(lsr, DR_PRE))
960 SET(code, TTY_PE);
961 }
962 if ((*rint)(code, tp) == -1) {
963 /*
964 * The line discipline's buffer is out of space.
965 */
966 if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
967 /*
968 * We're either not using flow control, or the
969 * line discipline didn't tell us to block for
970 * some reason. Either way, we have no way to
971 * know when there's more space available, so
972 * just drop the rest of the data.
973 */
974 get += cc << 1;
975 if (get >= end)
976 get -= IXPCOM_RING_SIZE << 1;
977 cc = 0;
978 } else {
979 /*
980 * Don't schedule any more receive processing
981 * until the line discipline tells us there's
982 * space available (through comhwiflow()).
983 * Leave the rest of the data in the input
984 * buffer.
985 */
986 SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
987 }
988 break;
989 }
990 get += 2;
991 if (get >= end)
992 get = sc->sc_rbuf;
993 cc--;
994 }
995
996 if (cc != scc) {
997 sc->sc_rbget = get;
998 s = splserial();
999 COM_LOCK(sc);
1000
1001 cc = sc->sc_rbavail += scc - cc;
1002 /* Buffers should be ok again, release possible block. */
1003 if (cc >= 1) {
1004 if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1005 CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1006 SET(sc->sc_rie, CR_RIE);
1007 ixpcom_set_cr(sc);
1008 }
1009 if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) {
1010 CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED);
1011 #if 0
1012 com_hwiflow(sc);
1013 #endif
1014 }
1015 }
1016 COM_UNLOCK(sc);
1017 splx(s);
1018 }
1019 }
1020
1021 static void
1022 ixpcomsoft(void* arg)
1023 {
1024 struct ixpcom_softc *sc = arg;
1025
1026 if (COM_ISALIVE(sc) == 0)
1027 return;
1028
1029 if (sc->sc_rx_ready) {
1030 sc->sc_rx_ready = 0;
1031 ixpcom_rxsoft(sc, sc->sc_tty);
1032 }
1033 if (sc->sc_tx_done) {
1034 sc->sc_tx_done = 0;
1035 ixpcom_txsoft(sc, sc->sc_tty);
1036 }
1037 }
1038
1039 int
1040 ixpcomintr(void* arg)
1041 {
1042 struct ixpcom_softc *sc = arg;
1043 bus_space_tag_t iot = sc->sc_iot;
1044 bus_space_handle_t ioh = sc->sc_ioh;
1045 u_char *put, *end;
1046 u_int cc;
1047 u_int cr;
1048 u_int sr;
1049 uint32_t c;
1050
1051 if (COM_ISALIVE(sc) == 0)
1052 return (0);
1053
1054 COM_LOCK(sc);
1055 cr = bus_space_read_4(iot, ioh, IXPCOM_CR) & CR_UE;
1056
1057 if (!cr) {
1058 COM_UNLOCK(sc);
1059 return (0);
1060 }
1061
1062 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
1063 if (!ISSET(sr, SR_TXR | SR_RXR))
1064 return (0);
1065
1066 /*
1067 * XXX
1068 *
1069 * ixpcom cannot detect a break. It can only detect framing
1070 * errors. And, a sequence of "framing error, framing error"
1071 * meens a break. So I made this hack:
1072 *
1073 * 1. Set default magic is a sequence of "BREAK, BREAK".
1074 * 2. Tell cn_check_magic() a "framing error" as BREAK.
1075 *
1076 * see ixpcomcnattach() too.
1077 *
1078 */
1079 if (ISSET(sr, SR_FRE)) {
1080 cn_check_magic(sc->sc_tty->t_dev,
1081 CNC_BREAK, ixpcom_cnm_state);
1082 }
1083
1084 end = sc->sc_ebuf;
1085 put = sc->sc_rbput;
1086 cc = sc->sc_rbavail;
1087
1088 if (ISSET(sr, SR_RXR)) {
1089 if (!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1090 while (cc > 0) {
1091 if (!ISSET(sr, SR_RXR))
1092 break;
1093 c = bus_space_read_4(iot, ioh, IXPCOM_DR);
1094 if (ISSET(c, DR_FRE)) {
1095 cn_check_magic(sc->sc_tty->t_dev,
1096 CNC_BREAK,
1097 ixpcom_cnm_state);
1098 }
1099 put[0] = c & 0xff;
1100 put[1] = (c >> 8) & 0xff;
1101 cn_check_magic(sc->sc_tty->t_dev,
1102 put[0], ixpcom_cnm_state);
1103 put += 2;
1104 if (put >= end)
1105 put = sc->sc_rbuf;
1106 cc--;
1107
1108 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
1109 }
1110
1111 /*
1112 * Current string of incoming characters ended because
1113 * no more data was available or we ran out of space.
1114 * Schedule a receive event if any data was received.
1115 * If we're out of space, turn off receive interrupts.
1116 */
1117 sc->sc_rbput = put;
1118 sc->sc_rbavail = cc;
1119 if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
1120 sc->sc_rx_ready = 1;
1121
1122 /*
1123 * See if we are in danger of overflowing a buffer. If
1124 * so, use hardware flow control to ease the pressure.
1125 */
1126
1127 /* but ixpcom cannot. X-( */
1128
1129 /*
1130 * If we're out of space, disable receive interrupts
1131 * until the queue has drained a bit.
1132 */
1133 if (!cc) {
1134 SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1135 CLR(sc->sc_rie, CR_RIE);
1136 ixpcom_set_cr(sc);
1137 }
1138 } else {
1139 #ifdef DIAGNOSTIC
1140 panic("ixpcomintr: we shouldn't reach here");
1141 #endif
1142 CLR(sc->sc_rie, CR_RIE);
1143 ixpcom_set_cr(sc);
1144 }
1145 }
1146
1147 /*
1148 * Done handling any receive interrupts. See if data can be
1149 * transmitted as well. Schedule tx done event if no data left
1150 * and tty was marked busy.
1151 */
1152 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
1153 if (ISSET(sr, SR_TXR)) {
1154 /*
1155 * If we've delayed a parameter change, do it now, and restart
1156 * output.
1157 */
1158 if (sc->sc_heldchange) {
1159 ixpcom_set_cr(sc);
1160 sc->sc_heldchange = 0;
1161 sc->sc_tbc = sc->sc_heldtbc;
1162 sc->sc_heldtbc = 0;
1163 }
1164
1165 /* Output the next chunk of the contiguous buffer, if any. */
1166 if (sc->sc_tbc > 0) {
1167 ixpcom_filltx(sc);
1168 } else {
1169 /* Disable transmit completion interrupts if necessary. */
1170 if (ISSET(sc->sc_xie, CR_XIE)) {
1171 CLR(sc->sc_xie, CR_XIE);
1172 ixpcom_set_cr(sc);
1173 }
1174 if (sc->sc_tx_busy) {
1175 sc->sc_tx_busy = 0;
1176 sc->sc_tx_done = 1;
1177 }
1178 }
1179 }
1180 COM_UNLOCK(sc);
1181
1182 /* Wake up the poller. */
1183 softint_schedule(sc->sc_si);
1184
1185 #ifdef RND_COM
1186 rnd_add_uint32(&sc->rnd_source, iir | lsr);
1187 #endif
1188 return (1);
1189 }
1190