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