ixp12x0_com.c revision 1.1 1 /* $NetBSD: ixp12x0_com.c,v 1.1 2002/07/15 16:27:17 ichiro Exp $ */
2 #define 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 <dev/cons.h>
103
104 #include <machine/bus.h>
105
106 #include <arm/ixp12x0/ixp12x0_comreg.h>
107 #include <arm/ixp12x0/ixp12x0_comvar.h>
108 #include <arm/ixp12x0/ixp12x0reg.h>
109 #include <arm/ixp12x0/ixp12x0var.h>
110
111 #include <arm/ixp12x0/ixpsipvar.h>
112
113 #include "ixpcom.h"
114
115 #ifdef POLLING_COM
116 #undef CR_RIE
117 #define CR_RIE 0
118 #undef CR_XIE
119 #define CR_XIE 0
120 #endif
121
122 #ifdef NOXIE
123 #undef CR_XIE
124 #define CR_XIE 0
125 #endif
126
127
128 cdev_decl(ixpcom);
129
130 static int ixpcom_match(struct device *, struct cfdata *, void *);
131 static void ixpcom_attach(struct device *, struct device *, void *);
132 static int ixpcom_detach(struct device *, int);
133 static int ixpcom_activate(struct device *, enum devact);
134
135 static int ixpcomparam(struct tty *, struct termios *);
136 static void ixpcomstart(struct tty *);
137 static int ixpcomhwiflow(struct tty *, int);
138
139 static void ixpcom_attach_subr(struct ixpcom_softc *);
140
141 static u_int cflag2cr(tcflag_t);
142
143 int ixpcomcngetc(dev_t);
144 void ixpcomcnputc(dev_t, int);
145 void ixpcomcnpollc(dev_t, int);
146
147 static void ixpcomsoft(void* arg);
148 inline static void ixpcom_txsoft(struct ixpcom_softc *, struct tty *);
149 inline static void ixpcom_rxsoft(struct ixpcom_softc *, struct tty *);
150
151 void ixpcomcnprobe(struct consdev *);
152 void ixpcomcninit(struct consdev *);
153
154 static int ixpcomintr(void* arg);
155
156 u_int32_t ixpcom_cr = 0; /* tell cr to *_intr.c */
157 u_int32_t ixpcom_imask = 0; /* intrrupt mask from *_intr.c */
158
159 static bus_space_tag_t ixpcomconstag;
160 static bus_space_handle_t ixpcomconsioh;
161 static bus_addr_t ixpcomconsaddr = IXPCOM_UART_BASE; /* XXX initial value */
162
163 static int ixpcomconsattached;
164 static int ixpcomconsrate;
165 static tcflag_t ixpcomconscflag;
166
167 struct cfattach ixpcom_ca = {
168 sizeof(struct ixpcom_softc), ixpcom_match, ixpcom_attach,
169 ixpcom_detach, ixpcom_activate
170 };
171 extern struct cfdriver ixpcom_cd;
172
173 struct consdev ixpcomcons = {
174 NULL, NULL, ixpcomcngetc, ixpcomcnputc, ixpcomcnpollc, NULL,
175 NODEV, CN_NORMAL
176 };
177
178 #ifndef DEFAULT_COMSPEED
179 #define DEFAULT_COMSPEED 38400
180 #endif
181
182 #define COMUNIT_MASK 0x7ffff
183 #define COMDIALOUT_MASK 0x80000
184
185 #define COMUNIT(x) (minor(x) & COMUNIT_MASK)
186 #define COMDIALOUT(x) (minor(x) & COMDIALOUT_MASK)
187
188 #define COM_ISALIVE(sc) ((sc)->enabled != 0 && \
189 ISSET((sc)->sc_dev.dv_flags, DVF_ACTIVE))
190
191 #define COM_BARRIER(t, h, f) bus_space_barrier((t), (h), 0, COM_NPORTS, (f))
192
193 #define COM_LOCK(sc);
194 #define COM_UNLOCK(sc);
195
196 #define SET(t, f) (t) |= (f)
197 #define CLR(t, f) (t) &= ~(f)
198 #define ISSET(t, f) ((t) & (f))
199
200 static int
201 ixpcom_match(parent, match, aux)
202 struct device *parent;
203 struct cfdata *match;
204 void *aux;
205 {
206 return (1);
207 }
208
209 void
210 ixpcom_attach(parent, self, aux)
211 struct device *parent;
212 struct device *self;
213 void *aux;
214 {
215 struct ixpcom_softc *sc = (struct ixpcom_softc *)self;
216 struct ixpsip_attach_args *sa = aux;
217
218 printf("\n");
219
220 sc->sc_iot = sa->sa_iot;
221 sc->sc_baseaddr = sa->sa_addr;
222
223 if(bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0,
224 &sc->sc_ioh)) {
225 printf("%s: unable to map registers\n", sc->sc_dev.dv_xname);
226 return;
227 }
228
229 printf("%s: IXP12x0 UART\n", sc->sc_dev.dv_xname);
230
231 ixpcom_attach_subr(sc);
232
233 #ifdef POLLING_COM
234 { void* d; d = d = ixpcomintr; }
235 #else
236 ixp12x0_intr_establish(IXP12X0_INTR_UART, IPL_SERIAL, ixpcomintr, sc);
237 #endif
238 }
239
240 void
241 ixpcom_attach_subr(sc)
242 struct ixpcom_softc *sc;
243 {
244 bus_addr_t iobase = sc->sc_baseaddr;
245 bus_space_tag_t iot = sc->sc_iot;
246 struct tty *tp;
247
248 if (iot == ixpcomconstag && iobase == ixpcomconsaddr) {
249 ixpcomconsattached = 1;
250 sc->sc_speed = IXPCOMSPEED(ixpcomconsrate);
251
252 /* Make sure the console is always "hardwired". */
253 delay(10000); /* wait for output to finish */
254 SET(sc->sc_hwflags, COM_HW_CONSOLE);
255 SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
256 }
257
258 tp = ttymalloc();
259 tp->t_oproc = ixpcomstart;
260 tp->t_param = ixpcomparam;
261 tp->t_hwiflow = ixpcomhwiflow;
262
263 sc->sc_tty = tp;
264 sc->sc_rbuf = malloc(IXPCOM_RING_SIZE << 1, M_DEVBUF, M_NOWAIT);
265 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
266 sc->sc_rbavail = IXPCOM_RING_SIZE;
267 if (sc->sc_rbuf == NULL) {
268 printf("%s: unable to allocate ring buffer\n",
269 sc->sc_dev.dv_xname);
270 return;
271 }
272 sc->sc_ebuf = sc->sc_rbuf + (IXPCOM_RING_SIZE << 1);
273 sc->sc_tbc = 0;
274
275 sc->sc_rie = sc->sc_xie = 0;
276 ixpcom_cr = IXPCOMSPEED2BRD(DEFAULT_COMSPEED)
277 | CR_UE | sc->sc_rie | sc->sc_xie | DSS_8BIT;
278
279 tty_attach(tp);
280
281 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
282 int maj;
283
284 /* locate the major number */
285 for (maj = 0; maj < nchrdev; maj++)
286 if (cdevsw[maj].d_open == ixpcomopen)
287 break;
288
289 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
290
291 delay(10000); /* XXX */
292 printf("%s: console\n", sc->sc_dev.dv_xname);
293 delay(10000); /* XXX */
294 }
295
296 sc->sc_si = softintr_establish(IPL_SOFTSERIAL, ixpcomsoft, sc);
297
298 #if NRND > 0 && defined(RND_COM)
299 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
300 RND_TYPE_TTY, 0);
301 #endif
302
303 /* if there are no enable/disable functions, assume the device
304 is always enabled */
305 if (!sc->enable)
306 sc->enabled = 1;
307
308 /* XXX configure register */
309 /* xxx_config(sc) */
310
311 SET(sc->sc_hwflags, COM_HW_DEV_OK);
312 }
313
314 int
315 ixpcom_detach(self, flags)
316 struct device *self;
317 int flags;
318 {
319 struct ixpcom_softc *sc = (struct ixpcom_softc *)self;
320 int maj, mn;
321
322 /* locate the major number */
323 for (maj = 0; maj < nchrdev; maj++)
324 if (cdevsw[maj].d_open == ixpcomopen)
325 break;
326
327 /* Nuke the vnodes for any open instances. */
328 mn = self->dv_unit;
329 vdevgone(maj, mn, mn, VCHR);
330
331 mn |= COMDIALOUT_MASK;
332 vdevgone(maj, mn, mn, VCHR);
333
334 /* Free the receive buffer. */
335 free(sc->sc_rbuf, M_DEVBUF);
336
337 /* Detach and free the tty. */
338 tty_detach(sc->sc_tty);
339 ttyfree(sc->sc_tty);
340
341 #if NRND > 0 && defined(RND_COM)
342 /* Unhook the entropy source. */
343 rnd_detach_source(&sc->rnd_source);
344 #endif
345
346 return (0);
347 }
348
349 int
350 ixpcom_activate(self, act)
351 struct device *self;
352 enum devact act;
353 {
354 struct ixpcom_softc *sc = (struct ixpcom_softc *)self;
355 int s, rv = 0;
356
357 s = splserial();
358 COM_LOCK(sc);
359 switch (act) {
360 case DVACT_ACTIVATE:
361 rv = EOPNOTSUPP;
362 break;
363 case DVACT_DEACTIVATE:
364 if (sc->sc_hwflags & (COM_HW_CONSOLE|COM_HW_KGDB))
365 rv = EBUSY;
366 break;
367 }
368
369 COM_UNLOCK(sc);
370 splx(s);
371 return (rv);
372 }
373
374 int
375 ixpcomparam(tp, t)
376 struct tty *tp;
377 struct termios *t;
378 {
379 return (0);
380 }
381
382 int
383 ixpcomhwiflow(tp, block)
384 struct tty *tp;
385 int block;
386 {
387 return (0);
388 }
389
390 void
391 ixpcomstart(tp)
392 struct tty *tp;
393 {
394 return;
395 }
396
397 int
398 ixpcomopen(dev, flag, mode, p)
399 dev_t dev;
400 int flag, mode;
401 struct proc *p;
402 {
403 return (0);
404 }
405 static u_int
406 cflag2cr(cflag)
407 tcflag_t cflag;
408 {
409 u_int cr;
410
411 cr = (cflag & PARENB) ? CR_PE : 0;
412 cr |= (cflag & PARODD) ? CR_OES : 0;
413 cr |= (cflag & CSTOPB) ? CR_SBS : 0;
414 cr |= ((cflag & CSIZE) == CS8) ? DSS_8BIT : 0;
415
416 return (cr);
417 }
418
419 static void
420 ixpcom_loadchannelregs(sc)
421 struct ixpcom_softc *sc;
422 {
423 /* XXX */
424 ixpcom_cr &= ~(CR_RIE | CR_XIE);
425 ixpcom_cr |= sc->sc_rie | sc->sc_xie;
426 ixpcom_cr &= ixpcom_imask;
427 bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCOM_CR, ixpcom_cr);
428 }
429
430 /* Initialization for serial console */
431 int
432 ixpcominit(iot, iobase, baud, cflag, iohp)
433 bus_space_tag_t iot;
434 bus_addr_t iobase;
435 int baud;
436 tcflag_t cflag;
437 bus_space_handle_t *iohp;
438 {
439 int cr;
440
441 if (bus_space_map(iot, iobase, IXPCOM_UART_SIZE, 0, iohp))
442 printf("register map failed\n");
443
444 cr = cflag2cr(cflag);
445 cr |= (IXPCOMSPEED(baud) << 16);
446 #if 0
447 cr |= (CR_UE | CR_RIE | CR_XIE);
448 #endif
449 cr |= CR_UE;
450 ixpcom_cr = cr;
451
452 /* enable the UART */
453 bus_space_write_4(iot, *iohp, IXPCOM_CR, cr);
454
455 return (0);
456 }
457
458 int
459 ixpcomcnattach(iot, iobase, rate, cflag)
460 bus_space_tag_t iot;
461 bus_addr_t iobase;
462 int rate;
463 tcflag_t cflag;
464 {
465 int res;
466
467 if ((res = ixpcominit(iot, iobase, rate, cflag, &ixpcomconsioh)))
468 return (res);
469 cn_tab = &ixpcomcons;
470
471 ixpcomconstag = iot;
472 ixpcomconsaddr = iobase;
473 ixpcomconsrate = rate;
474 ixpcomconscflag = cflag;
475
476 return (0);
477 }
478
479 #if 0
480 void
481 ixpcomcninit(cp)
482 struct consdev *cp;
483 {
484 if (cp == NULL) {
485 /* XXX cp == NULL means that MMU is disabled. */
486 ixpcomconsioh = IXPCOM_UART_BASE;
487 ixpcomconstag = &ixpcom_bs_tag;
488 cn_tab = &ixpcomcons;
489
490 IXPREG(IXPCOM_UART_BASE + IXPCOM_CR)
491 = (IXPCOMSPEED(38400) << 16)
492 | DSS_8BIT
493 | (CR_UE | CR_RIE | CR_XIE);
494 return;
495 }
496
497 if (ixpcominit(&ixpcom_bs_tag, CONADDR, CONSPEED,
498 CONMODE, &ixpcomconsioh))
499 panic("can't init serial console @%x", CONADDR);
500 cn_tab = &ixpcomcons;
501 ixpcomconstag = &ixpcom_bs_tag;
502 }
503 #endif
504
505 void
506 ixpcomcnprobe(cp)
507 struct consdev *cp;
508 {
509 cp->cn_pri = CN_REMOTE;
510 }
511
512 void
513 ixpcomcnpollc(dev, on)
514 dev_t dev;
515 int on;
516 {
517 }
518
519 void
520 ixpcomcnputc(dev, c)
521 dev_t dev;
522 int c;
523 {
524 int s;
525
526 s = spltty(); /* XXX do we need this? */
527
528 while(!(bus_space_read_4(ixpcomconstag, ixpcomconsioh, IXPCOM_SR)
529 & SR_TXR))
530 ;
531
532 bus_space_write_4(ixpcomconstag, ixpcomconsioh, IXPCOM_DR, c);
533 splx(s);
534 }
535
536 int
537 ixpcomcngetc(dev)
538 dev_t dev;
539 {
540 int c, s;
541
542 s = spltty(); /* XXX do we need this? */
543
544 while(!(bus_space_read_4(ixpcomconstag, ixpcomconsioh, IXPCOM_SR)
545 & SR_RXR))
546 ;
547
548 c = bus_space_read_4(ixpcomconstag, ixpcomconsioh, IXPCOM_DR);
549 c &= 0xff;
550 splx(s);
551
552 return (c);
553 }
554
555 inline static void
556 ixpcom_txsoft(sc, tp)
557 struct ixpcom_softc *sc;
558 struct tty *tp;
559 {
560 }
561
562 inline static void
563 ixpcom_rxsoft(sc, tp)
564 struct ixpcom_softc *sc;
565 struct tty *tp;
566 {
567 int (*rint) __P((int c, struct tty *tp)) = tp->t_linesw->l_rint;
568 u_char *get, *end;
569 u_int cc, scc;
570 u_char lsr;
571 int code;
572 int s;
573
574 end = sc->sc_ebuf;
575 get = sc->sc_rbget;
576 scc = cc = IXPCOM_RING_SIZE - sc->sc_rbavail;
577 #if 0
578 if (cc == IXPCOM_RING_SIZE) {
579 sc->sc_floods++;
580 if (sc->sc_errors++ == 0)
581 callout_reset(&sc->sc_diag_callout, 60 * hz,
582 comdiag, sc);
583 }
584 #endif
585 while (cc) {
586 code = get[0];
587 lsr = get[1];
588 if (ISSET(lsr, DR_ROR | DR_FRE | DR_PRE)) {
589 #if 0
590 if (ISSET(lsr, DR_ROR)) {
591 sc->sc_overflows++;
592 if (sc->sc_errors++ == 0)
593 callout_reset(&sc->sc_diag_callout,
594 60 * hz, comdiag, sc);
595 }
596 #endif
597 if (ISSET(lsr, DR_FRE))
598 SET(code, TTY_FE);
599 if (ISSET(lsr, DR_PRE))
600 SET(code, TTY_PE);
601 }
602 if ((*rint)(code, tp) == -1) {
603 /*
604 * The line discipline's buffer is out of space.
605 */
606 if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
607 /*
608 * We're either not using flow control, or the
609 * line discipline didn't tell us to block for
610 * some reason. Either way, we have no way to
611 * know when there's more space available, so
612 * just drop the rest of the data.
613 */
614 get += cc << 1;
615 if (get >= end)
616 get -= IXPCOM_RING_SIZE << 1;
617 cc = 0;
618 } else {
619 /*
620 * Don't schedule any more receive processing
621 * until the line discipline tells us there's
622 * space available (through comhwiflow()).
623 * Leave the rest of the data in the input
624 * buffer.
625 */
626 SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
627 }
628 break;
629 }
630 get += 2;
631 if (get >= end)
632 get = sc->sc_rbuf;
633 cc--;
634 }
635
636 if (cc != scc) {
637 sc->sc_rbget = get;
638 s = splserial();
639 COM_LOCK(sc);
640
641 cc = sc->sc_rbavail += scc - cc;
642 /* Buffers should be ok again, release possible block. */
643 if (cc >= 1) {
644 if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
645 CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
646 SET(sc->sc_rie, CR_RIE);
647 ixpcom_loadchannelregs(sc);
648 }
649 if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) {
650 CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED);
651 #if 0
652 com_hwiflow(sc);
653 #endif
654 }
655 }
656 COM_UNLOCK(sc);
657 splx(s);
658 }
659 }
660
661 static void
662 ixpcomsoft(void* arg)
663 {
664 struct ixpcom_softc *sc = arg;
665
666 if (COM_ISALIVE(sc) == 0)
667 return;
668
669 if (sc->sc_rx_ready) {
670 sc->sc_rx_ready = 0;
671 ixpcom_rxsoft(sc, sc->sc_tty);
672 }
673 if (sc->sc_tx_done) {
674 sc->sc_tx_done = 0;
675 ixpcom_txsoft(sc, sc->sc_tty);
676 }
677 }
678
679 static int
680 ixpcomintr(void* arg)
681 {
682 struct ixpcom_softc *sc = arg;
683 bus_space_tag_t iot = sc->sc_iot;
684 bus_space_handle_t ioh = sc->sc_ioh;
685 u_char *put, *end;
686 u_int cc;
687 u_int cr;
688 u_int sr;
689 u_int32_t c;
690
691 if (COM_ISALIVE(sc) == 0)
692 return (0);
693
694 COM_LOCK(sc);
695 cr = bus_space_read_4(iot, ioh, IXPCOM_CR) & CR_UE;
696
697 if (!cr) {
698 COM_UNLOCK(sc);
699 return (0);
700 }
701
702 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
703 if (!ISSET(sr, SR_TXR | SR_RXR))
704 return (0);
705
706 #if 0
707 /*
708 * IPX12x0 doesn't have a "Receiver End of Break Status" bit
709 * in status registar. Currentry I have no idea to determine
710 * whether break signal is received.
711 */
712 if (XXX) {
713 bus_space_write_4(iot, ioh, SACOM_SR0, SR0_REB);
714 #if defined(DDB) || defined(KGDB)
715 #ifndef DDB_BREAK_CHAR
716 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
717 console_debugger();
718 }
719 #endif
720 #endif /* DDB || KGDB */
721 }
722 #endif
723
724 end = sc->sc_ebuf;
725 put = sc->sc_rbput;
726 cc = sc->sc_rbavail;
727
728 if (ISSET(sr, SR_RXR)) {
729 if (!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
730 while (cc > 0) {
731 if (!ISSET(sr, SR_RXR))
732 break;
733 c = bus_space_read_4(iot, ioh, IXPCOM_DR);
734 put[0] = c & 0xff;
735 put[1] = (c >> 8) & 0xff;
736 #if defined(DDB) && defined(DDB_BREAK_CHAR)
737 if (put[0] == DDB_BREAK_CHAR &&
738 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
739 console_debugger();
740
741 sr = bus_space_read_4(iot, ioh,
742 IXPCOM_SR);
743 continue;
744 }
745 #endif
746 put += 2;
747 if (put >= end)
748 put = sc->sc_rbuf;
749 cc--;
750
751 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
752 }
753
754 /*
755 * Current string of incoming characters ended because
756 * no more data was available or we ran out of space.
757 * Schedule a receive event if any data was received.
758 * If we're out of space, turn off receive interrupts.
759 */
760 sc->sc_rbput = put;
761 sc->sc_rbavail = cc;
762 if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
763 sc->sc_rx_ready = 1;
764
765 /* XXX do RX hardware flow control */
766
767 /*
768 * If we're out of space, disable receive interrupts
769 * until the queue has drained a bit.
770 */
771 if (!cc) {
772 SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
773 CLR(sc->sc_rie, CR_RIE);
774 ixpcom_loadchannelregs(sc);
775 }
776 } else {
777 #ifdef DIAGNOSTIC
778 panic("ixpcomintr: we shouldn't reach here\n");
779 #endif
780 CLR(sc->sc_rie, CR_RIE);
781 ixpcom_loadchannelregs(sc);
782 }
783 }
784
785 /*
786 * Done handling any receive interrupts. See if data can be
787 * transmitted as well. Schedule tx done event if no data left
788 * and tty was marked busy.
789 */
790 #if 0
791 sr = bus_space_read_4(iot, ioh, IXPCOM_SR);
792 if (ISSET(sr, SR_TXR)) {
793 /*
794 * If we've delayed a parameter change, do it now, and restart
795 * output.
796 * XXX sacom_loadchanelregs() waits TX completion,
797 * XXX resulting in ~0.1s hang (300bps, 4 bytes) in worst case
798 */
799 if (sc->sc_heldchange) {
800 ixpcom_loadparams(sc);
801 sc->sc_heldchange = 0;
802 sc->sc_tbc = sc->sc_heldtbc;
803 sc->sc_heldtbc = 0;
804 }
805
806 /* Output the next chunk of the contiguous buffer, if any. */
807 if (sc->sc_tbc > 0) {
808 sacom_filltx(sc);
809 } else {
810 /* Disable transmit completion interrupts if necessary. */
811 if (ISSET(sc->sc_cr3, CR3_XIE)) {
812 CLR(sc->sc_cr3, CR3_XIE);
813 bus_space_write_4(iot, ioh, SACOM_CR3,
814 sc->sc_cr3);
815 }
816 if (sc->sc_tx_busy) {
817 sc->sc_tx_busy = 0;
818 sc->sc_tx_done = 1;
819 }
820 }
821 }
822 #endif
823 COM_UNLOCK(sc);
824
825 /* Wake up the poller. */
826 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
827 softintr_schedule(sc->sc_si);
828 #else
829 setsoftserial();
830 #endif
831
832 #if NRND > 0 && defined(RND_COM)
833 rnd_add_uint32(&sc->rnd_source, iir | lsr);
834 #endif
835 return (1);
836 }
837