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