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