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