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