ixp12x0_com.c revision 1.3 1 /* $NetBSD: ixp12x0_com.c,v 1.3 2002/07/21 14:19:43 ichiro 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 * 3. All advertising materials mentioning features or use of this software
24 * must display the following acknowledgement:
25 * This product includes software developed by the NetBSD
26 * Foundation, Inc. and its contributors.
27 * 4. Neither the name of The NetBSD Foundation nor the names of its
28 * contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
32 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
35 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 /*
45 * Copyright (c) 1991 The Regents of the University of California.
46 * All rights reserved.
47 *
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 * 1. Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * 2. Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * 3. All advertising materials mentioning features or use of this software
57 * must display the following acknowledgement:
58 * This product includes software developed by the University of
59 * California, Berkeley and its contributors.
60 * 4. Neither the name of the University nor the names of its contributors
61 * may be used to endorse or promote products derived from this software
62 * without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74 * SUCH DAMAGE.
75 *
76 * @(#)com.c 7.5 (Berkeley) 5/16/91
77 */
78
79
80 #include "opt_com.h"
81 #include "opt_ddb.h"
82 #include "opt_kgdb.h"
83
84 #include "rnd.h"
85 #if NRND > 0 && defined(RND_COM)
86 #include <sys/rnd.h>
87 #endif
88
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/types.h>
92 #include <sys/conf.h>
93 #include <sys/file.h>
94 #include <sys/device.h>
95 #include <sys/kernel.h>
96 #include <sys/malloc.h>
97 #include <sys/tty.h>
98 #include <sys/uio.h>
99 #include <sys/vnode.h>
100
101 #include <machine/intr.h>
102 #include <machine/bus.h>
103
104 #include <arm/ixp12x0/ixp12x0_comreg.h>
105 #include <arm/ixp12x0/ixp12x0_comvar.h>
106 #include <arm/ixp12x0/ixp12x0reg.h>
107 #include <arm/ixp12x0/ixp12x0var.h>
108
109 #include <arm/ixp12x0/ixpsipvar.h>
110
111 #include <dev/cons.h>
112 #include "ixpcom.h"
113
114 cdev_decl(ixpcom);
115
116 static int ixpcomparam(struct tty *, struct termios *);
117 static void ixpcomstart(struct tty *);
118 static int ixpcomhwiflow(struct tty *, int);
119
120 static u_int cflag2cr(tcflag_t);
121 static void ixpcom_iflush(struct ixpcom_softc *);
122 static void ixpcom_set_cr(struct ixpcom_softc *);
123
124 int ixpcomcngetc(dev_t);
125 void ixpcomcnputc(dev_t, int);
126 void ixpcomcnpollc(dev_t, int);
127
128 static void ixpcomsoft(void* arg);
129 inline static void ixpcom_txsoft(struct ixpcom_softc *, struct tty *);
130 inline static void ixpcom_rxsoft(struct ixpcom_softc *, struct tty *);
131
132 void ixpcomcnprobe(struct consdev *);
133 void ixpcomcninit(struct consdev *);
134
135 u_int32_t ixpcom_cr = 0; /* tell cr to *_intr.c */
136 u_int32_t ixpcom_imask = 0; /* intrrupt mask from *_intr.c */
137
138 static bus_space_tag_t ixpcomconstag;
139 static bus_space_handle_t ixpcomconsioh;
140 static bus_addr_t ixpcomconsaddr = IXPCOM_UART_BASE; /* XXX initial value */
141
142 static int ixpcomconsattached;
143 static int ixpcomconsrate;
144 static tcflag_t ixpcomconscflag;
145 static struct cnm_state ixpcom_cnm_state;
146
147 extern struct cfdriver ixpcom_cd;
148
149 struct consdev ixpcomcons = {
150 NULL, NULL, ixpcomcngetc, ixpcomcnputc, ixpcomcnpollc, NULL,
151 NODEV, CN_NORMAL
152 };
153
154 #ifndef DEFAULT_COMSPEED
155 #define DEFAULT_COMSPEED 38400
156 #endif
157
158 #define COMUNIT_MASK 0x7ffff
159 #define COMDIALOUT_MASK 0x80000
160
161 #define COMUNIT(x) (minor(x) & COMUNIT_MASK)
162 #define COMDIALOUT(x) (minor(x) & COMDIALOUT_MASK)
163
164 #define COM_ISALIVE(sc) ((sc)->enabled != 0 && \
165 ISSET((sc)->sc_dev.dv_flags, DVF_ACTIVE))
166
167 #define COM_BARRIER(t, h, f) bus_space_barrier((t), (h), 0, COM_NPORTS, (f))
168
169 #define COM_LOCK(sc);
170 #define COM_UNLOCK(sc);
171
172 #define SET(t, f) (t) |= (f)
173 #define CLR(t, f) (t) &= ~(f)
174 #define ISSET(t, f) ((t) & (f))
175
176 #define CFLAGS2CR_MASK (CR_PE | CR_OES | CR_SBS | CR_DSS | CR_BRD)
177
178 void
179 ixpcom_attach_subr(sc)
180 struct ixpcom_softc *sc;
181 {
182 bus_addr_t iobase = sc->sc_baseaddr;
183 bus_space_tag_t iot = sc->sc_iot;
184 struct tty *tp;
185
186 if (iot == ixpcomconstag && iobase == ixpcomconsaddr) {
187 ixpcomconsattached = 1;
188 sc->sc_speed = IXPCOMSPEED2BRD(ixpcomconsrate);
189
190 /* Make sure the console is always "hardwired". */
191 delay(10000); /* wait for output to finish */
192 SET(sc->sc_hwflags, COM_HW_CONSOLE);
193 SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
194 }
195
196 tp = ttymalloc();
197 tp->t_oproc = ixpcomstart;
198 tp->t_param = ixpcomparam;
199 tp->t_hwiflow = ixpcomhwiflow;
200
201 sc->sc_tty = tp;
202 sc->sc_rbuf = malloc(IXPCOM_RING_SIZE << 1, M_DEVBUF, M_NOWAIT);
203 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
204 sc->sc_rbavail = IXPCOM_RING_SIZE;
205 if (sc->sc_rbuf == NULL) {
206 printf("%s: unable to allocate ring buffer\n",
207 sc->sc_dev.dv_xname);
208 return;
209 }
210 sc->sc_ebuf = sc->sc_rbuf + (IXPCOM_RING_SIZE << 1);
211 sc->sc_tbc = 0;
212
213 sc->sc_rie = sc->sc_xie = 0;
214 ixpcom_cr = IXPCOMSPEED2BRD(DEFAULT_COMSPEED)
215 | CR_UE | sc->sc_rie | sc->sc_xie | DSS_8BIT;
216
217 tty_attach(tp);
218
219 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
220 int maj;
221
222 /* locate the major number */
223 for (maj = 0; maj < nchrdev; maj++)
224 if (cdevsw[maj].d_open == ixpcomopen)
225 break;
226
227 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
228
229 delay(10000); /* XXX */
230 printf("%s: console\n", sc->sc_dev.dv_xname);
231 delay(10000); /* XXX */
232 }
233
234 sc->sc_si = softintr_establish(IPL_SOFTSERIAL, ixpcomsoft, sc);
235
236 #if NRND > 0 && defined(RND_COM)
237 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
238 RND_TYPE_TTY, 0);
239 #endif
240
241 /* if there are no enable/disable functions, assume the device
242 is always enabled */
243 if (!sc->enable)
244 sc->enabled = 1;
245
246 /* XXX configure register */
247 /* xxx_config(sc) */
248
249 SET(sc->sc_hwflags, COM_HW_DEV_OK);
250 }
251
252 static int
253 ixpcomparam(tp, t)
254 struct tty *tp;
255 struct termios *t;
256 {
257 struct ixpcom_softc *sc
258 = device_lookup(&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(sc)
349 struct ixpcom_softc *sc;
350 {
351 bus_space_tag_t iot = sc->sc_iot;
352 bus_space_handle_t ioh = sc->sc_ioh;
353 int n;
354
355 n = 0;
356 while (bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_TXR) {
357 if (n >= sc->sc_tbc)
358 break;
359 bus_space_write_4(iot, ioh, IXPCOM_DR,
360 0xff & *(sc->sc_tba + n));
361 n++;
362 }
363 sc->sc_tbc -= n;
364 sc->sc_tba += n;
365 }
366
367 static void
368 ixpcomstart(tp)
369 struct tty *tp;
370 {
371 struct ixpcom_softc *sc
372 = device_lookup(&ixpcom_cd, COMUNIT(tp->t_dev));
373 int s;
374
375 if (COM_ISALIVE(sc) == 0)
376 return;
377
378 s = spltty();
379 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
380 goto out;
381 if (sc->sc_tx_stopped)
382 goto out;
383
384 if (tp->t_outq.c_cc <= tp->t_lowat) {
385 if (ISSET(tp->t_state, TS_ASLEEP)) {
386 CLR(tp->t_state, TS_ASLEEP);
387 wakeup(&tp->t_outq);
388 }
389 selwakeup(&tp->t_wsel);
390 if (tp->t_outq.c_cc == 0)
391 goto out;
392 }
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(sc, onoff)
429 struct ixpcom_softc *sc;
430 int onoff;
431 {
432 if (onoff)
433 SET(ixpcom_cr, CR_BRK);
434 else
435 CLR(ixpcom_cr, CR_BRK);
436 if (!sc->sc_heldchange) {
437 if (sc->sc_tx_busy) {
438 sc->sc_heldtbc = sc->sc_tbc;
439 sc->sc_tbc = 0;
440 sc->sc_heldchange = 1;
441 } else
442 ixpcom_set_cr(sc);
443 }
444 }
445
446 static void
447 ixpcom_shutdown(sc)
448 struct ixpcom_softc *sc;
449 {
450 int s;
451
452 s = splserial();
453 COM_LOCK(sc);
454
455 /* Clear any break condition set with TIOCSBRK. */
456 ixpcom_break(sc, 0);
457
458 /* Turn off interrupts. */
459 sc->sc_rie = sc->sc_xie = 0;
460 ixpcom_set_cr(sc);
461
462 if (sc->disable) {
463 #ifdef DIAGNOSTIC
464 if (!sc->enabled)
465 panic("ixpcom_shutdown: not enabled?");
466 #endif
467 (*sc->disable)(sc);
468 sc->enabled = 0;
469 }
470 COM_UNLOCK(sc);
471 splx(s);
472 }
473
474 int
475 ixpcomopen(dev, flag, mode, p)
476 dev_t dev;
477 int flag, mode;
478 struct proc *p;
479 {
480 struct ixpcom_softc *sc;
481 struct tty *tp;
482 int s, s2;
483 int error;
484
485 sc = device_lookup(&ixpcom_cd, COMUNIT(dev));
486 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK) ||
487 sc->sc_rbuf == NULL)
488 return (ENXIO);
489
490 if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
491 return (ENXIO);
492
493 #ifdef KGDB
494 /*
495 * If this is the kgdb port, no other use is permitted.
496 */
497 if (ISSET(sc->sc_hwflags, COM_HW_KGDB))
498 return (EBUSY);
499 #endif
500
501 tp = sc->sc_tty;
502
503 if (ISSET(tp->t_state, TS_ISOPEN) &&
504 ISSET(tp->t_state, TS_XCLUDE) &&
505 p->p_ucred->cr_uid != 0)
506 return (EBUSY);
507
508 s = spltty();
509
510 /*
511 * Do the following iff this is a first open.
512 */
513 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
514 struct termios t;
515
516 tp->t_dev = dev;
517
518 s2 = splserial();
519 COM_LOCK(sc);
520
521 if (sc->enable) {
522 if ((*sc->enable)(sc)) {
523 COM_UNLOCK(sc);
524 splx(s2);
525 splx(s);
526 printf("%s: device enable failed\n",
527 sc->sc_dev.dv_xname);
528 return (EIO);
529 }
530 sc->enabled = 1;
531 #if 0
532 /* XXXXXXXXXXXXXXX */
533 com_config(sc);
534 #endif
535 }
536
537 /* Turn on interrupts. */
538 SET(sc->sc_rie, CR_RIE);
539 ixpcom_set_cr(sc);
540
541 #if 0
542 /* Fetch the current modem control status, needed later. */
543 sc->sc_msr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, com_msr);
544
545 /* Clear PPS capture state on first open. */
546 sc->sc_ppsmask = 0;
547 sc->ppsparam.mode = 0;
548 #endif
549
550 COM_UNLOCK(sc);
551 splx(s2);
552
553 /*
554 * Initialize the termios status to the defaults. Add in the
555 * sticky bits from TIOCSFLAGS.
556 */
557 t.c_ispeed = 0;
558 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
559 t.c_ospeed = ixpcomconsrate;
560 t.c_cflag = ixpcomconscflag;
561 } else {
562 t.c_ospeed = TTYDEF_SPEED;
563 t.c_cflag = TTYDEF_CFLAG;
564 }
565 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
566 SET(t.c_cflag, CLOCAL);
567 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
568 SET(t.c_cflag, CRTSCTS);
569 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
570 SET(t.c_cflag, MDMBUF);
571 /* Make sure ixpcomparam() will do something. */
572 tp->t_ospeed = 0;
573 (void) ixpcomparam(tp, &t);
574 tp->t_iflag = TTYDEF_IFLAG;
575 tp->t_oflag = TTYDEF_OFLAG;
576 tp->t_lflag = TTYDEF_LFLAG;
577 ttychars(tp);
578 ttsetwater(tp);
579
580 s2 = splserial();
581 COM_LOCK(sc);
582
583 /* Clear the input ring, and unblock. */
584 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
585 sc->sc_rbavail = IXPCOM_RING_SIZE;
586 ixpcom_iflush(sc);
587 CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
588
589 #ifdef COM_DEBUG
590 if (ixpcom_debug)
591 comstatus(sc, "ixpcomopen ");
592 #endif
593
594 COM_UNLOCK(sc);
595 splx(s2);
596 }
597
598 splx(s);
599
600 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
601 if (error)
602 goto bad;
603
604 error = (*tp->t_linesw->l_open)(dev, tp);
605 if (error)
606 goto bad;
607
608 return (0);
609
610 bad:
611 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
612 /*
613 * We failed to open the device, and nobody else had it opened.
614 * Clean up the state as appropriate.
615 */
616 ixpcom_shutdown(sc);
617 }
618
619 return (error);
620 }
621
622 int
623 ixpcomclose(dev, flag, mode, p)
624 dev_t dev;
625 int flag, mode;
626 struct proc *p;
627 {
628 struct ixpcom_softc *sc = device_lookup(&ixpcom_cd, COMUNIT(dev));
629 struct tty *tp = sc->sc_tty;
630
631 /* XXX This is for cons.c. */
632 if (!ISSET(tp->t_state, TS_ISOPEN))
633 return (0);
634
635 (*tp->t_linesw->l_close)(tp, flag);
636 ttyclose(tp);
637
638 if (COM_ISALIVE(sc) == 0)
639 return (0);
640
641 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
642 /*
643 * Although we got a last close, the device may still be in
644 * use; e.g. if this was the dialout node, and there are still
645 * processes waiting for carrier on the non-dialout node.
646 */
647 ixpcom_shutdown(sc);
648 }
649
650 return (0);
651 }
652
653 int
654 ixpcomread(dev, uio, flag)
655 dev_t dev;
656 struct uio *uio;
657 int flag;
658 {
659 struct ixpcom_softc *sc = device_lookup(&ixpcom_cd, COMUNIT(dev));
660 struct tty *tp = sc->sc_tty;
661
662 if (COM_ISALIVE(sc) == 0)
663 return (EIO);
664
665 return ((*tp->t_linesw->l_read)(tp, uio, flag));
666 }
667
668 int
669 ixpcomwrite(dev, uio, flag)
670 dev_t dev;
671 struct uio *uio;
672 int flag;
673 {
674 struct ixpcom_softc *sc = device_lookup(&ixpcom_cd, COMUNIT(dev));
675 struct tty *tp = sc->sc_tty;
676
677 if (COM_ISALIVE(sc) == 0)
678 return (EIO);
679
680 return ((*tp->t_linesw->l_write)(tp, uio, flag));
681 }
682
683 int
684 ixpcompoll(dev, events, p)
685 dev_t dev;
686 int events;
687 struct proc *p;
688 {
689 struct ixpcom_softc *sc = device_lookup(&ixpcom_cd, COMUNIT(dev));
690 struct tty *tp = sc->sc_tty;
691
692 if (COM_ISALIVE(sc) == 0)
693 return (EIO);
694
695 return ((*tp->t_linesw->l_poll)(tp, events, p));
696 }
697
698 struct tty *
699 ixpcomtty(dev)
700 dev_t dev;
701 {
702 struct ixpcom_softc *sc = device_lookup(&ixpcom_cd, COMUNIT(dev));
703 struct tty *tp = sc->sc_tty;
704
705 return (tp);
706 }
707
708 int
709 ixpcomioctl(dev, cmd, data, flag, p)
710 dev_t dev;
711 u_long cmd;
712 caddr_t data;
713 int flag;
714 struct proc *p;
715 {
716 return (0);
717 }
718
719 /*
720 * Stop output on a line.
721 */
722 void
723 ixpcomstop(tp, flag)
724 struct tty *tp;
725 int flag;
726 {
727 struct ixpcom_softc *sc
728 = device_lookup(&ixpcom_cd, COMUNIT(tp->t_dev));
729 int s;
730
731 s = splserial();
732 COM_LOCK(sc);
733 if (ISSET(tp->t_state, TS_BUSY)) {
734 /* Stop transmitting at the next chunk. */
735 sc->sc_tbc = 0;
736 sc->sc_heldtbc = 0;
737 if (!ISSET(tp->t_state, TS_TTSTOP))
738 SET(tp->t_state, TS_FLUSH);
739 }
740 COM_UNLOCK(sc);
741 splx(s);
742 }
743
744 static u_int
745 cflag2cr(cflag)
746 tcflag_t cflag;
747 {
748 u_int cr;
749
750 cr = (cflag & PARENB) ? CR_PE : 0;
751 cr |= (cflag & PARODD) ? CR_OES : 0;
752 cr |= (cflag & CSTOPB) ? CR_SBS : 0;
753 cr |= ((cflag & CSIZE) == CS8) ? DSS_8BIT : 0;
754
755 return (cr);
756 }
757
758 static void
759 ixpcom_iflush(sc)
760 struct ixpcom_softc *sc;
761 {
762 bus_space_tag_t iot = sc->sc_iot;
763 bus_space_handle_t ioh = sc->sc_ioh;
764 #ifdef DIAGNOSTIC
765 int reg;
766 #endif
767 int timo;
768
769 #ifdef DIAGNOSTIC
770 reg = 0xffff;
771 #endif
772 timo = 50000;
773 /* flush any pending I/O */
774 while (ISSET(bus_space_read_4(iot, ioh, IXPCOM_SR), SR_RXR)
775 && --timo)
776 #ifdef DIAGNOSTIC
777 reg =
778 #else
779 (void)
780 #endif
781 bus_space_read_4(iot, ioh, IXPCOM_DR);
782 #ifdef DIAGNOSTIC
783 if (!timo)
784 printf("%s: com_iflush timeout %02x\n", sc->sc_dev.dv_xname,
785 reg);
786 #endif
787 }
788
789 static void
790 ixpcom_set_cr(sc)
791 struct ixpcom_softc *sc;
792 {
793 /* XXX */
794 ixpcom_cr &= ~(CR_RIE | CR_XIE);
795 ixpcom_cr |= sc->sc_rie | sc->sc_xie;
796 bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCOM_CR,
797 ixpcom_cr & ~ixpcom_imask);
798 }
799
800 /* Initialization for serial console */
801 int
802 ixpcominit(iot, iobase, baud, cflag, iohp)
803 bus_space_tag_t iot;
804 bus_addr_t iobase;
805 int baud;
806 tcflag_t cflag;
807 bus_space_handle_t *iohp;
808 {
809 int cr;
810
811 if (bus_space_map(iot, iobase, IXPCOM_UART_SIZE, 0, iohp))
812 printf("register map failed\n");
813
814 cr = cflag2cr(cflag);
815 cr |= IXPCOMSPEED2BRD(baud);
816 cr |= CR_UE;
817 ixpcom_cr = cr;
818
819 /* enable the UART */
820 bus_space_write_4(iot, *iohp, IXPCOM_CR, cr);
821
822 return (0);
823 }
824
825 int
826 ixpcomcnattach(iot, iobase, rate, cflag)
827 bus_space_tag_t iot;
828 bus_addr_t iobase;
829 int rate;
830 tcflag_t cflag;
831 {
832 int res;
833
834 if ((res = ixpcominit(iot, iobase, rate, cflag, &ixpcomconsioh)))
835 return (res);
836 cn_tab = &ixpcomcons;
837 cn_init_magic(&ixpcom_cnm_state);
838 /*
839 * XXX
840 *
841 * ixpcom cannot detect a break. It can only detect framing
842 * errors. And, a sequence of "framing error, framing error"
843 * meens a break. So I made this hack:
844 *
845 * 1. Set default magic is a sequence of "BREAK, BREAK".
846 * 2. Tell cn_check_magic() a "framing error" as BREAK.
847 *
848 * see ixpcom_intr() too.
849 *
850 */
851 /* default magic is a couple of BREAK. */
852 cn_set_magic("\047\001\047\001");
853
854 ixpcomconstag = iot;
855 ixpcomconsaddr = iobase;
856 ixpcomconsrate = rate;
857 ixpcomconscflag = cflag;
858
859 return (0);
860 }
861
862 void
863 ixpcomcninit(cp)
864 struct consdev *cp;
865 {
866 printf("ixpcomcninit called\n");
867 #if 0
868 if (cp == NULL) {
869 /* XXX cp == NULL means that MMU is disabled. */
870 ixpcomconsioh = IXPCOM_UART_BASE;
871 ixpcomconstag = &ixpcom_bs_tag;
872 cn_tab = &ixpcomcons;
873
874 IXPREG(IXPCOM_UART_BASE + IXPCOM_CR)
875 = IXPCOMSPEED2BRD(DEFAULT_COMSPEED)
876 | DSS_8BIT
877 | (CR_UE | CR_RIE | CR_XIE);
878 return;
879 }
880
881 if (ixpcominit(&ixpcom_bs_tag, CONADDR, CONSPEED,
882 CONMODE, &ixpcomconsioh))
883 panic("can't init serial console @%x", CONADDR);
884 cn_tab = &ixpcomcons;
885 ixpcomconstag = &ixpcom_bs_tag;
886 #endif
887 }
888
889 void
890 ixpcomcnprobe(cp)
891 struct consdev *cp;
892 {
893 cp->cn_pri = CN_REMOTE;
894 }
895
896 void
897 ixpcomcnpollc(dev, on)
898 dev_t dev;
899 int on;
900 {
901 }
902
903 void
904 ixpcomcnputc(dev, c)
905 dev_t dev;
906 int c;
907 {
908 int s;
909
910 s = spltty(); /* XXX do we need this? */
911
912 while(!(bus_space_read_4(ixpcomconstag, ixpcomconsioh, IXPCOM_SR)
913 & SR_TXR))
914 ;
915
916 bus_space_write_4(ixpcomconstag, ixpcomconsioh, IXPCOM_DR, c);
917
918 #ifdef DEBUG
919 if (c == '\r') {
920 while(!(bus_space_read_4(ixpcomconstag, ixpcomconsioh,
921 IXPCOM_SR)
922 & SR_TXE))
923 ;
924 }
925 #endif
926
927 splx(s);
928 }
929
930 int
931 ixpcomcngetc(dev)
932 dev_t dev;
933 {
934 int c, s;
935
936 s = spltty(); /* XXX do we need this? */
937
938 while(!(bus_space_read_4(ixpcomconstag, ixpcomconsioh, IXPCOM_SR)
939 & SR_RXR))
940 ;
941
942 c = bus_space_read_4(ixpcomconstag, ixpcomconsioh, IXPCOM_DR);
943 c &= 0xff;
944 splx(s);
945
946 return (c);
947 }
948
949 inline static void
950 ixpcom_txsoft(sc, tp)
951 struct ixpcom_softc *sc;
952 struct tty *tp;
953 {
954 CLR(tp->t_state, TS_BUSY);
955 if (ISSET(tp->t_state, TS_FLUSH))
956 CLR(tp->t_state, TS_FLUSH);
957 else
958 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
959 (*tp->t_linesw->l_start)(tp);
960 }
961
962 inline static void
963 ixpcom_rxsoft(sc, tp)
964 struct ixpcom_softc *sc;
965 struct tty *tp;
966 {
967 int (*rint) __P((int c, struct tty *tp)) = tp->t_linesw->l_rint;
968 u_char *get, *end;
969 u_int cc, scc;
970 u_char lsr;
971 int code;
972 int s;
973
974 end = sc->sc_ebuf;
975 get = sc->sc_rbget;
976 scc = cc = IXPCOM_RING_SIZE - sc->sc_rbavail;
977 #if 0
978 if (cc == IXPCOM_RING_SIZE) {
979 sc->sc_floods++;
980 if (sc->sc_errors++ == 0)
981 callout_reset(&sc->sc_diag_callout, 60 * hz,
982 comdiag, sc);
983 }
984 #endif
985 while (cc) {
986 code = get[0];
987 lsr = get[1];
988 if (ISSET(lsr, DR_ROR | DR_FRE | DR_PRE)) {
989 #if 0
990 if (ISSET(lsr, DR_ROR)) {
991 sc->sc_overflows++;
992 if (sc->sc_errors++ == 0)
993 callout_reset(&sc->sc_diag_callout,
994 60 * hz, comdiag, sc);
995 }
996 #endif
997 if (ISSET(lsr, DR_FRE))
998 SET(code, TTY_FE);
999 if (ISSET(lsr, DR_PRE))
1000 SET(code, TTY_PE);
1001 }
1002 if ((*rint)(code, tp) == -1) {
1003 /*
1004 * The line discipline's buffer is out of space.
1005 */
1006 if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
1007 /*
1008 * We're either not using flow control, or the
1009 * line discipline didn't tell us to block for
1010 * some reason. Either way, we have no way to
1011 * know when there's more space available, so
1012 * just drop the rest of the data.
1013 */
1014 get += cc << 1;
1015 if (get >= end)
1016 get -= IXPCOM_RING_SIZE << 1;
1017 cc = 0;
1018 } else {
1019 /*
1020 * Don't schedule any more receive processing
1021 * until the line discipline tells us there's
1022 * space available (through comhwiflow()).
1023 * Leave the rest of the data in the input
1024 * buffer.
1025 */
1026 SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
1027 }
1028 break;
1029 }
1030 get += 2;
1031 if (get >= end)
1032 get = sc->sc_rbuf;
1033 cc--;
1034 }
1035
1036 if (cc != scc) {
1037 sc->sc_rbget = get;
1038 s = splserial();
1039 COM_LOCK(sc);
1040
1041 cc = sc->sc_rbavail += scc - cc;
1042 /* Buffers should be ok again, release possible block. */
1043 if (cc >= 1) {
1044 if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1045 CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1046 SET(sc->sc_rie, CR_RIE);
1047 ixpcom_set_cr(sc);
1048 }
1049 if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) {
1050 CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED);
1051 #if 0
1052 com_hwiflow(sc);
1053 #endif
1054 }
1055 }
1056 COM_UNLOCK(sc);
1057 splx(s);
1058 }
1059 }
1060
1061 static void
1062 ixpcomsoft(void* arg)
1063 {
1064 struct ixpcom_softc *sc = arg;
1065
1066 if (COM_ISALIVE(sc) == 0)
1067 return;
1068
1069 if (sc->sc_rx_ready) {
1070 sc->sc_rx_ready = 0;
1071 ixpcom_rxsoft(sc, sc->sc_tty);
1072 }
1073 if (sc->sc_tx_done) {
1074 sc->sc_tx_done = 0;
1075 ixpcom_txsoft(sc, sc->sc_tty);
1076 }
1077 }
1078
1079 int
1080 ixpcomintr(void* arg)
1081 {
1082 struct ixpcom_softc *sc = arg;
1083 bus_space_tag_t iot = sc->sc_iot;
1084 bus_space_handle_t ioh = sc->sc_ioh;
1085 u_char *put, *end;
1086 u_int cc;
1087 u_int cr;
1088 u_int sr;
1089 u_int32_t c;
1090
1091 if (COM_ISALIVE(sc) == 0)
1092 return (0);
1093
1094 COM_LOCK(sc);
1095 cr = bus_space_read_4(iot, ioh, IXPCOM_CR) & CR_UE;
1096
1097 if (!cr) {
1098 COM_UNLOCK(sc);
1099 return (0);
1100 }
1101
1102 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
1103 if (!ISSET(sr, SR_TXR | SR_RXR))
1104 return (0);
1105
1106 /*
1107 * XXX
1108 *
1109 * ixpcom cannot detect a break. It can only detect framing
1110 * errors. And, a sequence of "framing error, framing error"
1111 * meens a break. So I made this hack:
1112 *
1113 * 1. Set default magic is a sequence of "BREAK, BREAK".
1114 * 2. Tell cn_check_magic() a "framing error" as BREAK.
1115 *
1116 * see ixpcomcnattach() too.
1117 *
1118 */
1119 if (ISSET(sr, SR_FRE)) {
1120 cn_check_magic(sc->sc_tty->t_dev,
1121 CNC_BREAK, ixpcom_cnm_state);
1122 }
1123
1124 end = sc->sc_ebuf;
1125 put = sc->sc_rbput;
1126 cc = sc->sc_rbavail;
1127
1128 if (ISSET(sr, SR_RXR)) {
1129 if (!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1130 while (cc > 0) {
1131 if (!ISSET(sr, SR_RXR))
1132 break;
1133 c = bus_space_read_4(iot, ioh, IXPCOM_DR);
1134 if (ISSET(c, DR_FRE)) {
1135 cn_check_magic(sc->sc_tty->t_dev,
1136 CNC_BREAK,
1137 ixpcom_cnm_state);
1138 }
1139 put[0] = c & 0xff;
1140 put[1] = (c >> 8) & 0xff;
1141 cn_check_magic(sc->sc_tty->t_dev,
1142 put[0], ixpcom_cnm_state);
1143 put += 2;
1144 if (put >= end)
1145 put = sc->sc_rbuf;
1146 cc--;
1147
1148 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
1149 }
1150
1151 /*
1152 * Current string of incoming characters ended because
1153 * no more data was available or we ran out of space.
1154 * Schedule a receive event if any data was received.
1155 * If we're out of space, turn off receive interrupts.
1156 */
1157 sc->sc_rbput = put;
1158 sc->sc_rbavail = cc;
1159 if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
1160 sc->sc_rx_ready = 1;
1161
1162 /*
1163 * See if we are in danger of overflowing a buffer. If
1164 * so, use hardware flow control to ease the pressure.
1165 */
1166
1167 /* but ixpcom cannot. X-( */
1168
1169 /*
1170 * If we're out of space, disable receive interrupts
1171 * until the queue has drained a bit.
1172 */
1173 if (!cc) {
1174 SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1175 CLR(sc->sc_rie, CR_RIE);
1176 ixpcom_set_cr(sc);
1177 }
1178 } else {
1179 #ifdef DIAGNOSTIC
1180 panic("ixpcomintr: we shouldn't reach here\n");
1181 #endif
1182 CLR(sc->sc_rie, CR_RIE);
1183 ixpcom_set_cr(sc);
1184 }
1185 }
1186
1187 /*
1188 * Done handling any receive interrupts. See if data can be
1189 * transmitted as well. Schedule tx done event if no data left
1190 * and tty was marked busy.
1191 */
1192 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
1193 if (ISSET(sr, SR_TXR)) {
1194 /*
1195 * If we've delayed a parameter change, do it now, and restart
1196 * output.
1197 */
1198 if (sc->sc_heldchange) {
1199 ixpcom_set_cr(sc);
1200 sc->sc_heldchange = 0;
1201 sc->sc_tbc = sc->sc_heldtbc;
1202 sc->sc_heldtbc = 0;
1203 }
1204
1205 /* Output the next chunk of the contiguous buffer, if any. */
1206 if (sc->sc_tbc > 0) {
1207 ixpcom_filltx(sc);
1208 } else {
1209 /* Disable transmit completion interrupts if necessary. */
1210 if (ISSET(sc->sc_xie, CR_XIE)) {
1211 CLR(sc->sc_xie, CR_XIE);
1212 ixpcom_set_cr(sc);
1213 }
1214 if (sc->sc_tx_busy) {
1215 sc->sc_tx_busy = 0;
1216 sc->sc_tx_done = 1;
1217 }
1218 }
1219 }
1220 COM_UNLOCK(sc);
1221
1222 /* Wake up the poller. */
1223 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
1224 softintr_schedule(sc->sc_si);
1225 #else
1226 setsoftserial();
1227 #endif
1228
1229 #if NRND > 0 && defined(RND_COM)
1230 rnd_add_uint32(&sc->rnd_source, iir | lsr);
1231 #endif
1232 return (1);
1233 }
1234
1235