Annotation of sys/dev/ic/cy.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: cy.c,v 1.25 2005/11/21 18:16:39 millert Exp $ */
2: /*
3: * Copyright (c) 1996 Timo Rossi.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: * 3. Neither the name of the author nor the names of contributors
15: * may be used to endorse or promote products derived from this software
16: * without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28: * SUCH DAMAGE.
29: */
30:
31: /*
32: * cy.c
33: *
34: * Driver for Cyclades Cyclom-8/16/32 multiport serial cards
35: * (currently not tested with Cyclom-32 cards)
36: *
37: * Timo Rossi, 1996
38: *
39: * Supports both ISA and PCI Cyclom cards
40: *
41: * Uses CD1400 automatic CTS flow control, and
42: * if CY_HW_RTS is defined, uses CD1400 automatic input flow control.
43: * This requires a special cable that exchanges the RTS and DTR lines.
44: *
45: * Lots of debug output can be enabled by defining CY_DEBUG
46: * Some debugging counters (number of receive/transmit interrupts etc.)
47: * can be enabled by defining CY_DEBUG1
48: *
49: * This version uses the bus_space/io_??() stuff
50: *
51: */
52:
53: /* NCY is the number of Cyclom cards in the machine */
54: #include "cy.h"
55: #if NCY > 0
56:
57: #include <sys/types.h>
58: #include <sys/param.h>
59: #include <sys/ioctl.h>
60: #include <sys/syslog.h>
61: #include <sys/fcntl.h>
62: #include <sys/tty.h>
63: #include <sys/proc.h>
64: #include <sys/conf.h>
65: #include <sys/user.h>
66: #include <sys/selinfo.h>
67: #include <sys/device.h>
68: #include <sys/malloc.h>
69: #include <sys/systm.h>
70:
71: #include <machine/bus.h>
72: #include <machine/intr.h>
73:
74: #if NCY_ISA > 0
75: #include <dev/isa/isavar.h>
76: #include <dev/isa/isareg.h>
77: #endif /* NCY_ISA > 0 */
78: #if NCY_PCI > 0
79: #include <dev/pci/pcivar.h>
80: #include <dev/pci/pcireg.h>
81: #include <dev/pci/pcidevs.h>
82: #endif /* NCY_PCI > 0 */
83:
84: #include <dev/ic/cd1400reg.h>
85: #include <dev/ic/cyreg.h>
86:
87:
88: int cy_intr(void *);
89: int cyparam(struct tty *, struct termios *);
90: void cystart(struct tty *);
91: void cy_poll(void *);
92: int cy_modem_control(struct cy_port *, int, int);
93: void cy_enable_transmitter(struct cy_port *);
94: void cd1400_channel_cmd(struct cy_port *, int);
95: int cy_speed(speed_t, int *, int *, int);
96:
97: struct cfdriver cy_cd = {
98: NULL, "cy", DV_TTY
99: };
100:
101: /*
102: * Common probe routine
103: *
104: * returns the number of chips found.
105: */
106: int
107: cy_probe_common(bus_space_tag_t memt, bus_space_handle_t memh, int bustype)
108: {
109: int cy_chip, chip_offs;
110: u_char firmware_ver;
111: int nchips;
112:
113: /* Cyclom card hardware reset */
114: bus_space_write_1(memt, memh, CY16_RESET<<bustype, 0);
115: DELAY(500); /* wait for reset to complete */
116: bus_space_write_1(memt, memh, CY_CLEAR_INTR<<bustype, 0);
117:
118: #ifdef CY_DEBUG
119: printf("cy: card reset done\n");
120: #endif
121:
122: nchips = 0;
123:
124: for (cy_chip = 0, chip_offs = 0;
125: cy_chip < CY_MAX_CD1400s;
126: cy_chip++, chip_offs += (CY_CD1400_MEMSPACING << bustype)) {
127: int i;
128:
129: /* the last 4 cd1400s are 'interleaved'
130: with the first 4 on 32-port boards */
131: if (cy_chip == 4)
132: chip_offs -= (CY32_ADDR_FIX << bustype);
133:
134: #ifdef CY_DEBUG
135: printf("cy: probe chip %d offset 0x%lx ... ",
136: cy_chip, chip_offs);
137: #endif
138:
139: /* wait until the chip is ready for command */
140: DELAY(1000);
141: if (bus_space_read_1(memt, memh, chip_offs +
142: ((CD1400_CCR << 1) << bustype)) != 0) {
143: #ifdef CY_DEBUG
144: printf("not ready for command\n");
145: #endif
146: break;
147: }
148:
149: /* clear the firmware version reg. */
150: bus_space_write_1(memt, memh, chip_offs +
151: ((CD1400_GFRCR << 1) << bustype), 0);
152:
153: /*
154: * On Cyclom-16 references to non-existent chip 4
155: * actually access chip 0 (address line 9 not decoded).
156: * Here we check if the clearing of chip 4 GFRCR actually
157: * cleared chip 0 GFRCR. In that case we have a 16 port card.
158: */
159: if (cy_chip == 4 &&
160: bus_space_read_1(memt, memh, chip_offs +
161: ((CD1400_GFRCR << 1) << bustype)) == 0)
162: break;
163:
164: /* reset the chip */
165: bus_space_write_1(memt, memh, chip_offs +
166: ((CD1400_CCR << 1) << bustype),
167: CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
168:
169: /* wait for the chip to initialize itself */
170: for (i = 0; i < 200; i++) {
171: DELAY(50);
172: firmware_ver = bus_space_read_1(memt, memh, chip_offs +
173: ((CD1400_GFRCR << 1) << bustype));
174: if ((firmware_ver & 0xf0) == 0x40) /* found a CD1400 */
175: break;
176: }
177: #ifdef CY_DEBUG
178: printf("firmware version 0x%x\n", firmware_ver);
179: #endif
180:
181: if ((firmware_ver & 0xf0) != 0x40)
182: break;
183:
184: /* firmware version OK, CD1400 found */
185: nchips++;
186: }
187:
188: if (nchips == 0) {
189: #ifdef CY_DEBUG
190: printf("no CD1400s found\n");
191: #endif
192: return (0);
193: }
194:
195: #ifdef CY_DEBUG
196: printf("found %d CD1400s\n", nchips);
197: #endif
198:
199: return (nchips);
200: }
201:
202: void
203: cy_attach(parent, self)
204: struct device *parent, *self;
205: {
206: int card, port, cy_chip, num_chips, cdu, chip_offs, cy_clock;
207: struct cy_softc *sc = (void *)self;
208:
209: card = sc->sc_dev.dv_unit;
210: num_chips = sc->sc_nr_cd1400s;
211: if (num_chips == 0)
212: return;
213:
214: timeout_set(&sc->sc_poll_to, cy_poll, sc);
215: bzero(sc->sc_ports, sizeof(sc->sc_ports));
216: sc->sc_nports = num_chips * CD1400_NO_OF_CHANNELS;
217:
218: port = 0;
219: for (cy_chip = 0, chip_offs = 0;
220: cy_chip < num_chips;
221: cy_chip++, chip_offs += (CY_CD1400_MEMSPACING<<sc->sc_bustype)) {
222: if (cy_chip == 4)
223: chip_offs -= (CY32_ADDR_FIX<<sc->sc_bustype);
224:
225: #ifdef CY_DEBUG
226: printf("attach CD1400 #%d offset 0x%x\n", cy_chip, chip_offs);
227: #endif
228: sc->sc_cd1400_offs[cy_chip] = chip_offs;
229:
230: /* configure port 0 as serial port
231: (should already be after reset) */
232: cd_write_reg_sc(sc, cy_chip, CD1400_GCR, 0);
233:
234: /* Set cy_clock depending on firmware version */
235: if (cd_read_reg_sc(sc, cy_chip, CD1400_GFRCR) <= 0x46)
236: cy_clock = CY_CLOCK;
237: else
238: cy_clock = CY_CLOCK_60;
239:
240: /* set up a receive timeout period (1ms) */
241: cd_write_reg_sc(sc, cy_chip, CD1400_PPR,
242: (cy_clock / CD1400_PPR_PRESCALER / 1000) + 1);
243:
244: for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; cdu++) {
245: sc->sc_ports[port].cy_port_num = port;
246: sc->sc_ports[port].cy_memt = sc->sc_memt;
247: sc->sc_ports[port].cy_memh = sc->sc_memh;
248: sc->sc_ports[port].cy_chip_offs = chip_offs;
249: sc->sc_ports[port].cy_bustype = sc->sc_bustype;
250: sc->sc_ports[port].cy_clock = cy_clock;
251:
252: /* should we initialize anything else here? */
253: port++;
254: } /* for(each port on one CD1400...) */
255:
256: } /* for(each CD1400 on a card... ) */
257:
258: printf(": %d ports\n", port);
259:
260: /* ensure an edge for the next interrupt */
261: bus_space_write_1(sc->sc_memt, sc->sc_memh,
262: CY_CLEAR_INTR<<sc->sc_bustype, 0);
263: }
264:
265: /*
266: * open routine. returns zero if successful, else error code
267: */
268: int cyopen(dev_t, int, int, struct proc *);
269: int cyclose(dev_t, int, int, struct proc *);
270: int cyread(dev_t, struct uio *, int);
271: int cywrite(dev_t, struct uio *, int);
272: struct tty *cytty(dev_t);
273: int cyioctl(dev_t, u_long, caddr_t, int, struct proc *);
274: int cystop(struct tty *, int flag);
275:
276: int
277: cyopen(dev, flag, mode, p)
278: dev_t dev;
279: int flag, mode;
280: struct proc *p;
281: {
282: int card = CY_CARD(dev);
283: int port = CY_PORT(dev);
284: struct cy_softc *sc;
285: struct cy_port *cy;
286: struct tty *tp;
287: int s, error;
288:
289: if (card >= cy_cd.cd_ndevs ||
290: (sc = cy_cd.cd_devs[card]) == NULL) {
291: return (ENXIO);
292: }
293:
294: #ifdef CY_DEBUG
295: printf("%s open port %d flag 0x%x mode 0x%x\n", sc->sc_dev.dv_xname,
296: port, flag, mode);
297: #endif
298:
299: cy = &sc->sc_ports[port];
300:
301: s = spltty();
302: if (cy->cy_tty == NULL) {
303: cy->cy_tty = ttymalloc();
304: }
305: splx(s);
306:
307: tp = cy->cy_tty;
308: tp->t_oproc = cystart;
309: tp->t_param = cyparam;
310: tp->t_dev = dev;
311:
312: if (!ISSET(tp->t_state, TS_ISOPEN)) {
313: SET(tp->t_state, TS_WOPEN);
314: ttychars(tp);
315: tp->t_iflag = TTYDEF_IFLAG;
316: tp->t_oflag = TTYDEF_OFLAG;
317: tp->t_cflag = TTYDEF_CFLAG;
318: if (ISSET(cy->cy_openflags, TIOCFLAG_CLOCAL))
319: SET(tp->t_cflag, CLOCAL);
320: if (ISSET(cy->cy_openflags, TIOCFLAG_CRTSCTS))
321: SET(tp->t_cflag, CRTSCTS);
322: if (ISSET(cy->cy_openflags, TIOCFLAG_MDMBUF))
323: SET(tp->t_cflag, MDMBUF);
324: tp->t_lflag = TTYDEF_LFLAG;
325: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
326:
327: s = spltty();
328:
329: /*
330: * Allocate input ring buffer if we don't already have one
331: */
332: if (cy->cy_ibuf == NULL) {
333: cy->cy_ibuf = malloc(IBUF_SIZE, M_DEVBUF, M_NOWAIT);
334: if (cy->cy_ibuf == NULL) {
335: printf("%s: (port %d) can't allocate input buffer\n",
336: sc->sc_dev.dv_xname, port);
337: splx(s);
338: return (ENOMEM);
339: }
340: cy->cy_ibuf_end = cy->cy_ibuf + IBUF_SIZE;
341: }
342:
343: /* mark the ring buffer as empty */
344: cy->cy_ibuf_rd_ptr = cy->cy_ibuf_wr_ptr = cy->cy_ibuf;
345:
346: /* select CD1400 channel */
347: cd_write_reg(cy, CD1400_CAR, port & CD1400_CAR_CHAN);
348: /* reset the channel */
349: cd1400_channel_cmd(cy, CD1400_CCR_CMDRESET);
350: /* encode unit (port) number in LIVR */
351: /* there is just enough space for 5 bits (32 ports) */
352: cd_write_reg(cy, CD1400_LIVR, port << 3);
353:
354: cy->cy_channel_control = 0;
355:
356: if (!timeout_pending(&sc->sc_poll_to))
357: timeout_add(&sc->sc_poll_to, 1);
358:
359: /* this sets parameters and raises DTR */
360: cyparam(tp, &tp->t_termios);
361:
362: ttsetwater(tp);
363:
364: /* raise RTS too */
365: cy_modem_control(cy, TIOCM_RTS, DMBIS);
366:
367: cy->cy_carrier_stat = cd_read_reg(cy, CD1400_MSVR2);
368:
369: /* enable receiver and modem change interrupts */
370: cd_write_reg(cy, CD1400_SRER,
371: CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
372:
373: if (CY_DIALOUT(dev) ||
374: ISSET(cy->cy_openflags, TIOCFLAG_SOFTCAR) ||
375: ISSET(tp->t_cflag, MDMBUF) ||
376: ISSET(cy->cy_carrier_stat, CD1400_MSVR2_CD))
377: SET(tp->t_state, TS_CARR_ON);
378: else
379: CLR(tp->t_state, TS_CARR_ON);
380: } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) {
381: return (EBUSY);
382: } else {
383: s = spltty();
384: }
385:
386: /* wait for carrier if necessary */
387: if (!ISSET(flag, O_NONBLOCK)) {
388: while (!ISSET(tp->t_cflag, CLOCAL) &&
389: !ISSET(tp->t_state, TS_CARR_ON)) {
390: SET(tp->t_state, TS_WOPEN);
391: error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
392: "cydcd", 0);
393: if (error != 0) {
394: splx(s);
395: CLR(tp->t_state, TS_WOPEN);
396: return (error);
397: }
398: }
399: }
400:
401: splx(s);
402:
403: return (*linesw[tp->t_line].l_open)(dev, tp);
404: }
405:
406: /*
407: * close routine. returns zero if successful, else error code
408: */
409: int
410: cyclose(dev, flag, mode, p)
411: dev_t dev;
412: int flag, mode;
413: struct proc *p;
414: {
415: int card = CY_CARD(dev);
416: int port = CY_PORT(dev);
417: struct cy_softc *sc = cy_cd.cd_devs[card];
418: struct cy_port *cy = &sc->sc_ports[port];
419: struct tty *tp = cy->cy_tty;
420: int s;
421:
422: #ifdef CY_DEBUG
423: printf("%s close port %d, flag 0x%x, mode 0x%x\n", sc->sc_dev.dv_xname,
424: port, flag, mode);
425: #endif
426:
427: (*linesw[tp->t_line].l_close)(tp, flag);
428: s = spltty();
429:
430: if (ISSET(tp->t_cflag, HUPCL) &&
431: !ISSET(cy->cy_openflags, TIOCFLAG_SOFTCAR)) {
432: /* drop DTR and RTS
433: (should we wait for output buffer to become empty first?) */
434: cy_modem_control(cy, 0, DMSET);
435: }
436:
437: /*
438: * XXX should we disable modem change and
439: * receive interrupts here or somewhere ?
440: */
441: CLR(tp->t_state, TS_BUSY | TS_FLUSH);
442:
443: splx(s);
444: ttyclose(tp);
445:
446: return (0);
447: }
448:
449: /*
450: * Read routine
451: */
452: int
453: cyread(dev, uio, flag)
454: dev_t dev;
455: struct uio *uio;
456: int flag;
457: {
458: int card = CY_CARD(dev);
459: int port = CY_PORT(dev);
460: struct cy_softc *sc = cy_cd.cd_devs[card];
461: struct cy_port *cy = &sc->sc_ports[port];
462: struct tty *tp = cy->cy_tty;
463:
464: #ifdef CY_DEBUG
465: printf("%s read port %d uio 0x%x flag 0x%x\n", sc->sc_dev.dv_xname,
466: port, uio, flag);
467: #endif
468:
469: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
470: }
471:
472: /*
473: * Write routine
474: */
475: int
476: cywrite(dev, uio, flag)
477: dev_t dev;
478: struct uio *uio;
479: int flag;
480: {
481: int card = CY_CARD(dev);
482: int port = CY_PORT(dev);
483: struct cy_softc *sc = cy_cd.cd_devs[card];
484: struct cy_port *cy = &sc->sc_ports[port];
485: struct tty *tp = cy->cy_tty;
486:
487: #ifdef CY_DEBUG
488: printf("%s write port %d uio 0x%x flag 0x%x\n", sc->sc_dev.dv_xname,
489: port, uio, flag);
490: #endif
491:
492: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
493: }
494:
495: /*
496: * return tty pointer
497: */
498: struct tty *
499: cytty(dev)
500: dev_t dev;
501: {
502: int card = CY_CARD(dev);
503: int port = CY_PORT(dev);
504: struct cy_softc *sc = cy_cd.cd_devs[card];
505: struct cy_port *cy = &sc->sc_ports[port];
506: struct tty *tp = cy->cy_tty;
507:
508: return (tp);
509: }
510:
511: /*
512: * ioctl routine
513: */
514: int
515: cyioctl(dev, cmd, data, flag, p)
516: dev_t dev;
517: u_long cmd;
518: caddr_t data;
519: int flag;
520: struct proc *p;
521: {
522: int card = CY_CARD(dev);
523: int port = CY_PORT(dev);
524: struct cy_softc *sc = cy_cd.cd_devs[card];
525: struct cy_port *cy = &sc->sc_ports[port];
526: struct tty *tp = cy->cy_tty;
527: int error;
528:
529: #ifdef CY_DEBUG
530: printf("%s port %d ioctl cmd 0x%x data 0x%x flag 0x%x\n",
531: sc->sc_dev.dv_xname, port, cmd, data, flag);
532: #endif
533:
534: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
535: if (error >= 0)
536: return (error);
537:
538: error = ttioctl(tp, cmd, data, flag, p);
539: if (error >= 0)
540: return (error);
541:
542: /* XXX should not allow dropping DTR when dialin? */
543:
544: switch (cmd) {
545: case TIOCSBRK: /* start break */
546: SET(cy->cy_flags, CYF_START_BREAK);
547: cy_enable_transmitter(cy);
548: break;
549:
550: case TIOCCBRK: /* stop break */
551: SET(cy->cy_flags, CYF_END_BREAK);
552: cy_enable_transmitter(cy);
553: break;
554:
555: case TIOCSDTR: /* DTR on */
556: cy_modem_control(cy, TIOCM_DTR, DMBIS);
557: break;
558:
559: case TIOCCDTR: /* DTR off */
560: cy_modem_control(cy, TIOCM_DTR, DMBIC);
561: break;
562:
563: case TIOCMSET: /* set new modem control line values */
564: cy_modem_control(cy, *((int *)data), DMSET);
565: break;
566:
567: case TIOCMBIS: /* turn modem control bits on */
568: cy_modem_control(cy, *((int *)data), DMBIS);
569: break;
570:
571: case TIOCMBIC: /* turn modem control bits off */
572: cy_modem_control(cy, *((int *)data), DMBIC);
573: break;
574:
575: case TIOCMGET: /* get modem control/status line state */
576: *((int *)data) = cy_modem_control(cy, 0, DMGET);
577: break;
578:
579: case TIOCGFLAGS:
580: *((int *)data) = cy->cy_openflags |
581: (CY_DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0);
582: break;
583:
584: case TIOCSFLAGS:
585: error = suser(p, 0);
586: if (error != 0)
587: return (EPERM);
588:
589: cy->cy_openflags = *((int *)data) &
590: (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL |
591: TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF);
592: break;
593:
594: default:
595: return (ENOTTY);
596: }
597:
598: return (0);
599: }
600:
601: /*
602: * start output
603: */
604: void
605: cystart(tp)
606: struct tty *tp;
607: {
608: int card = CY_CARD(tp->t_dev);
609: int port = CY_PORT(tp->t_dev);
610: struct cy_softc *sc = cy_cd.cd_devs[card];
611: struct cy_port *cy = &sc->sc_ports[port];
612: int s;
613:
614: #ifdef CY_DEBUG
615: printf("%s port %d start, tty 0x%x\n", sc->sc_dev.dv_xname, port, tp);
616: #endif
617:
618: s = spltty();
619:
620: #ifdef CY_DEBUG1
621: cy->cy_start_count++;
622: #endif
623:
624: if (!ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) {
625: if (tp->t_outq.c_cc <= tp->t_lowat) {
626: if (ISSET(tp->t_state, TS_ASLEEP)) {
627: CLR(tp->t_state, TS_ASLEEP);
628: wakeup(&tp->t_outq);
629: }
630:
631: selwakeup(&tp->t_wsel);
632:
633: if (tp->t_outq.c_cc == 0)
634: goto out;
635: }
636:
637: SET(tp->t_state, TS_BUSY);
638: cy_enable_transmitter(cy);
639: }
640: out:
641:
642: splx(s);
643: }
644:
645: /*
646: * stop output
647: */
648: int
649: cystop(tp, flag)
650: struct tty *tp;
651: int flag;
652: {
653: int card = CY_CARD(tp->t_dev);
654: int port = CY_PORT(tp->t_dev);
655: struct cy_softc *sc = cy_cd.cd_devs[card];
656: struct cy_port *cy = &sc->sc_ports[port];
657: int s;
658:
659: #ifdef CY_DEBUG
660: printf("%s port %d stop tty 0x%x flag 0x%x\n", sc->sc_dev.dv_xname,
661: port, tp, flag);
662: #endif
663:
664: s = spltty();
665:
666: if (ISSET(tp->t_state, TS_BUSY)) {
667: if (!ISSET(tp->t_state, TS_TTSTOP))
668: SET(tp->t_state, TS_FLUSH);
669:
670: /*
671: * the transmit interrupt routine will disable transmit when it
672: * notices that CYF_STOP has been set.
673: */
674: SET(cy->cy_flags, CYF_STOP);
675: }
676: splx(s);
677: return (0);
678: }
679:
680: /*
681: * parameter setting routine.
682: * returns 0 if successful, else returns error code
683: */
684: int
685: cyparam(tp, t)
686: struct tty *tp;
687: struct termios *t;
688: {
689: int card = CY_CARD(tp->t_dev);
690: int port = CY_PORT(tp->t_dev);
691: struct cy_softc *sc = cy_cd.cd_devs[card];
692: struct cy_port *cy = &sc->sc_ports[port];
693: int ibpr, obpr, i_clk_opt, o_clk_opt;
694: int s, opt;
695:
696: #ifdef CY_DEBUG
697: printf("%s port %d param tty 0x%x termios 0x%x\n", sc->sc_dev.dv_xname,
698: port, tp, t);
699: printf("ispeed %d ospeed %d\n", t->c_ispeed, t->c_ospeed);
700: #endif
701:
702: if (t->c_ospeed != 0 &&
703: cy_speed(t->c_ospeed, &o_clk_opt, &obpr, cy->cy_clock) < 0)
704: return (EINVAL);
705:
706: if (t->c_ispeed != 0 &&
707: cy_speed(t->c_ispeed, &i_clk_opt, &ibpr, cy->cy_clock) < 0)
708: return (EINVAL);
709:
710: s = spltty();
711:
712: /* hang up the line is ospeed is zero, else turn DTR on */
713: cy_modem_control(cy, TIOCM_DTR, (t->c_ospeed == 0 ? DMBIC : DMBIS));
714:
715: /* channel was selected by the above call to cy_modem_control() */
716: /* cd_write_reg(cy, CD1400_CAR, port & CD1400_CAR_CHAN); */
717:
718: /* set transmit speed */
719: if (t->c_ospeed != 0) {
720: cd_write_reg(cy, CD1400_TCOR, o_clk_opt);
721: cd_write_reg(cy, CD1400_TBPR, obpr);
722: }
723: /* set receive speed */
724: if (t->c_ispeed != 0) {
725: cd_write_reg(cy, CD1400_RCOR, i_clk_opt);
726: cd_write_reg(cy, CD1400_RBPR, ibpr);
727: }
728:
729: opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN
730: | (ISSET(t->c_cflag, CREAD) ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
731:
732: if (opt != cy->cy_channel_control) {
733: cy->cy_channel_control = opt;
734: cd1400_channel_cmd(cy, opt);
735: }
736:
737: /* compute COR1 contents */
738: opt = 0;
739: if (ISSET(t->c_cflag, PARENB)) {
740: if (ISSET(t->c_cflag, PARODD))
741: opt |= CD1400_COR1_PARODD;
742: opt |= CD1400_COR1_PARNORMAL;
743: }
744:
745: if (!ISSET(t->c_iflag, INPCK))
746: opt |= CD1400_COR1_NOINPCK; /* no parity checking */
747:
748: if (ISSET(t->c_cflag, CSTOPB))
749: opt |= CD1400_COR1_STOP2;
750:
751: switch (t->c_cflag & CSIZE) {
752: case CS5:
753: opt |= CD1400_COR1_CS5;
754: break;
755:
756: case CS6:
757: opt |= CD1400_COR1_CS6;
758: break;
759:
760: case CS7:
761: opt |= CD1400_COR1_CS7;
762: break;
763:
764: default:
765: opt |= CD1400_COR1_CS8;
766: break;
767: }
768:
769: cd_write_reg(cy, CD1400_COR1, opt);
770:
771: #ifdef CY_DEBUG
772: printf("cor1 = 0x%x...", opt);
773: #endif
774:
775: /*
776: * use the CD1400 automatic CTS flow control if CRTSCTS is set
777: *
778: * CD1400_COR2_ETC is used because breaks are generated with
779: * embedded transmit commands
780: */
781: cd_write_reg(cy, CD1400_COR2,
782: CD1400_COR2_ETC |
783: (ISSET(t->c_cflag, CRTSCTS) ? CD1400_COR2_CCTS_OFLOW : 0));
784:
785: cd_write_reg(cy, CD1400_COR3, RX_FIFO_THRESHOLD);
786:
787: cd1400_channel_cmd(cy,
788: CD1400_CCR_CMDCORCHG |
789: CD1400_CCR_COR1 | CD1400_CCR_COR2 | CD1400_CCR_COR3);
790:
791: cd_write_reg(cy, CD1400_COR4, CD1400_COR4_PFO_EXCEPTION);
792: cd_write_reg(cy, CD1400_COR5, 0);
793:
794: /*
795: * set modem change option registers to generate interrupts
796: * on carrier detect changes.
797: *
798: * if hardware RTS handshaking is used (CY_HW_RTS, DTR and RTS lines
799: * exchanged), also set the handshaking threshold.
800: */
801: #ifdef CY_HW_RTS
802: cd_write_reg(cy, CD1400_MCOR1, CD1400_MCOR1_CDzd |
803: (ISSET(t->c_cflag, CRTSCTS) ? RX_DTR_THRESHOLD : 0));
804: #else
805: cd_write_reg(cy, CD1400_MCOR1, CD1400_MCOR1_CDzd);
806: #endif /* CY_HW_RTS */
807:
808: cd_write_reg(cy, CD1400_MCOR2, CD1400_MCOR2_CDod);
809:
810: /*
811: * set receive timeout to approx. 2ms
812: * could use more complex logic here...
813: * (but is it actually needed or even useful?)
814: */
815: cd_write_reg(cy, CD1400_RTPR, 2);
816:
817: /*
818: * should do anything else here?
819: * XXX check MDMBUF handshaking like in com.c?
820: */
821:
822: splx(s);
823: return (0);
824: }
825:
826: /*
827: * set/get modem line status
828: *
829: * bits can be: TIOCM_DTR, TIOCM_RTS, TIOCM_CTS, TIOCM_CD, TIOCM_RI, TIOCM_DSR
830: *
831: * RTS and DTR are exchanged if CY_HW_RTS is set
832: *
833: */
834: int
835: cy_modem_control(cy, bits, howto)
836: struct cy_port *cy;
837: int bits;
838: int howto;
839: {
840: int s, msvr;
841:
842: s = spltty();
843:
844: /* select channel */
845: cd_write_reg(cy, CD1400_CAR, cy->cy_port_num & CD1400_CAR_CHAN);
846:
847: /* does not manipulate RTS if it is used for flow control */
848: switch (howto) {
849: case DMGET:
850: bits = 0;
851: if (cy->cy_channel_control & CD1400_CCR_RCVEN)
852: bits |= TIOCM_LE;
853: msvr = cd_read_reg(cy, CD1400_MSVR2);
854: #ifdef CY_HW_RTS
855: if (cd_read_reg(cy, CD1400_MSVR1) & CD1400_MSVR1_RTS)
856: bits |= TIOCM_DTR;
857: if (msvr & CD1400_MSVR2_DTR)
858: bits |= TIOCM_RTS;
859: #else
860: if (cd_read_reg(cy, CD1400_MSVR1) & CD1400_MSVR1_RTS)
861: bits |= TIOCM_RTS;
862: if (msvr & CD1400_MSVR2_DTR)
863: bits |= TIOCM_DTR;
864: #endif /* CY_HW_RTS */
865: if (msvr & CD1400_MSVR2_CTS)
866: bits |= TIOCM_CTS;
867: if (msvr & CD1400_MSVR2_CD)
868: bits |= TIOCM_CD;
869: if (msvr & CD1400_MSVR2_DSR) /* not connected on some
870: Cyclom cards? */
871: bits |= TIOCM_DSR;
872: if (msvr & CD1400_MSVR2_RI) /* not connected on
873: Cyclom-8Y cards? */
874: bits |= TIOCM_RI;
875: splx(s);
876: return (bits);
877:
878: case DMSET: /* replace old values with new ones */
879: #ifdef CY_HW_RTS
880: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS))
881: cd_write_reg(cy, CD1400_MSVR2,
882: ((bits & TIOCM_RTS) ? CD1400_MSVR2_DTR : 0));
883: cd_write_reg(cy, CD1400_MSVR1,
884: ((bits & TIOCM_DTR) ? CD1400_MSVR1_RTS : 0));
885: #else
886: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS))
887: cd_write_reg(cy, CD1400_MSVR1,
888: ((bits & TIOCM_RTS) ? CD1400_MSVR1_RTS : 0));
889: cd_write_reg(cy, CD1400_MSVR2,
890: ((bits & TIOCM_DTR) ? CD1400_MSVR2_DTR : 0));
891: #endif /* CY_HW_RTS */
892: break;
893:
894: case DMBIS: /* set bits */
895: #ifdef CY_HW_RTS
896: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
897: (bits & TIOCM_RTS) != 0)
898: cd_write_reg(cy, CD1400_MSVR2, CD1400_MSVR2_DTR);
899: if (bits & TIOCM_DTR)
900: cd_write_reg(cy, CD1400_MSVR1, CD1400_MSVR1_RTS);
901: #else
902: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
903: (bits & TIOCM_RTS) != 0)
904: cd_write_reg(cy, CD1400_MSVR1, CD1400_MSVR1_RTS);
905: if (bits & TIOCM_DTR)
906: cd_write_reg(cy, CD1400_MSVR2, CD1400_MSVR2_DTR);
907: #endif /* CY_HW_RTS */
908: break;
909:
910: case DMBIC: /* clear bits */
911: #ifdef CY_HW_RTS
912: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
913: (bits & TIOCM_RTS))
914: cd_write_reg(cy, CD1400_MSVR2, 0);
915: if (bits & TIOCM_DTR)
916: cd_write_reg(cy, CD1400_MSVR1, 0);
917: #else
918: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
919: (bits & TIOCM_RTS))
920: cd_write_reg(cy, CD1400_MSVR1, 0);
921: if (bits & TIOCM_DTR)
922: cd_write_reg(cy, CD1400_MSVR2, 0);
923: #endif /* CY_HW_RTS */
924: break;
925: }
926: splx(s);
927: return (0);
928: }
929:
930: /*
931: * Upper-level handler loop (called from timer interrupt?)
932: * This routine is common for multiple cards
933: */
934: void
935: cy_poll(void *arg)
936: {
937: int port;
938: struct cy_softc *sc = arg;
939: struct cy_port *cy;
940: struct tty *tp;
941: static int counter = 0;
942: #ifdef CY_DEBUG1
943: int did_something;
944: #endif
945:
946: int s;
947:
948: s = spltty();
949:
950: if (sc->sc_events == 0 && ++counter < 200) {
951: splx(s);
952: goto out;
953: }
954:
955: sc->sc_events = 0;
956: splx(s);
957:
958: #ifdef CY_DEBUG1
959: sc->sc_poll_count1++;
960: did_something = 0;
961: #endif
962:
963: for (port = 0; port < sc->sc_nports; port++) {
964: cy = &sc->sc_ports[port];
965: if ((tp = cy->cy_tty) == NULL || cy->cy_ibuf == NULL ||
966: !ISSET(tp->t_state, TS_ISOPEN | TS_WOPEN))
967: continue;
968:
969: /*
970: * handle received data
971: */
972: while (cy->cy_ibuf_rd_ptr != cy->cy_ibuf_wr_ptr) {
973: u_char line_stat;
974: int chr;
975:
976: line_stat = cy->cy_ibuf_rd_ptr[0];
977: chr = cy->cy_ibuf_rd_ptr[1];
978:
979: if (line_stat &
980: (CD1400_RDSR_BREAK|CD1400_RDSR_FE))
981: chr |= TTY_FE;
982: if (line_stat & CD1400_RDSR_PE)
983: chr |= TTY_PE;
984:
985: /*
986: * on an overrun error the data is treated as
987: * good just as it should be.
988: */
989:
990: #ifdef CY_DEBUG
991: printf("%s port %d ttyinput 0x%x\n",
992: sc->sc_dev.dv_xname, port, chr);
993: #endif
994:
995: (*linesw[tp->t_line].l_rint)(chr, tp);
996:
997: s = spltty(); /* really necessary? */
998: if ((cy->cy_ibuf_rd_ptr += 2) ==
999: cy->cy_ibuf_end)
1000: cy->cy_ibuf_rd_ptr = cy->cy_ibuf;
1001: splx(s);
1002:
1003: #ifdef CY_DEBUG1
1004: did_something = 1;
1005: #endif
1006: }
1007:
1008: #ifndef CY_HW_RTS
1009: /*
1010: * If we don't have any received data in ibuf and
1011: * CRTSCTS is on and RTS is turned off, it is time
1012: * to turn RTS back on
1013: */
1014: if (ISSET(tp->t_cflag, CRTSCTS)) {
1015: /* we can't use cy_modem_control() here as it
1016: doesn't change RTS if RTSCTS is on */
1017: cd_write_reg(cy, CD1400_CAR,
1018: port & CD1400_CAR_CHAN);
1019:
1020: if ((cd_read_reg(cy,
1021: CD1400_MSVR1) & CD1400_MSVR1_RTS) == 0) {
1022: cd_write_reg(cy, CD1400_MSVR1,
1023: CD1400_MSVR1_RTS);
1024: #ifdef CY_DEBUG1
1025: did_something = 1;
1026: #endif
1027: }
1028: }
1029: #endif /* CY_HW_RTS */
1030:
1031: /*
1032: * handle carrier changes
1033: */
1034: s = spltty();
1035: if (ISSET(cy->cy_flags, CYF_CARRIER_CHANGED)) {
1036: int carrier;
1037:
1038: CLR(cy->cy_flags, CYF_CARRIER_CHANGED);
1039: splx(s);
1040:
1041: carrier = ((cy->cy_carrier_stat &
1042: CD1400_MSVR2_CD) != 0);
1043:
1044: #ifdef CY_DEBUG
1045: printf("%s: cy_poll: carrier change "
1046: "(port %d, carrier %d)\n",
1047: sc->sc_dev.dv_xname, port, carrier);
1048: #endif
1049: if (CY_DIALIN(tp->t_dev) &&
1050: !(*linesw[tp->t_line].l_modem)(tp, carrier))
1051: cy_modem_control(cy, TIOCM_DTR, DMBIC);
1052:
1053: #ifdef CY_DEBUG1
1054: did_something = 1;
1055: #endif
1056: } else {
1057: splx(s);
1058: }
1059:
1060: s = spltty();
1061: if (ISSET(cy->cy_flags, CYF_START)) {
1062: CLR(cy->cy_flags, CYF_START);
1063: splx(s);
1064:
1065: (*linesw[tp->t_line].l_start)(tp);
1066:
1067: #ifdef CY_DEBUG1
1068: did_something = 1;
1069: #endif
1070: } else {
1071: splx(s);
1072: }
1073:
1074: /* could move this to even upper level... */
1075: if (cy->cy_fifo_overruns) {
1076: cy->cy_fifo_overruns = 0;
1077: /* doesn't report overrun count,
1078: but shouldn't really matter */
1079: log(LOG_WARNING, "%s: port %d fifo overrun\n",
1080: sc->sc_dev.dv_xname, port);
1081: }
1082: if (cy->cy_ibuf_overruns) {
1083: cy->cy_ibuf_overruns = 0;
1084: log(LOG_WARNING, "%s: port %d ibuf overrun\n",
1085: sc->sc_dev.dv_xname, port);
1086: }
1087: } /* for(port...) */
1088: #ifdef CY_DEBUG1
1089: if (did_something && counter >= 200)
1090: sc->sc_poll_count2++;
1091: #endif
1092:
1093: counter = 0;
1094:
1095: out:
1096: timeout_add(&sc->sc_poll_to, 1);
1097: }
1098:
1099: /*
1100: * hardware interrupt routine
1101: */
1102: int
1103: cy_intr(arg)
1104: void *arg;
1105: {
1106: struct cy_softc *sc = arg;
1107: struct cy_port *cy;
1108: int cy_chip, stat;
1109: int int_serviced = -1;
1110:
1111: /*
1112: * Check interrupt status of each CD1400 chip on this card
1113: * (multiple cards cannot share the same interrupt)
1114: */
1115: for (cy_chip = 0; cy_chip < sc->sc_nr_cd1400s; cy_chip++) {
1116:
1117: stat = cd_read_reg_sc(sc, cy_chip, CD1400_SVRR);
1118: if (stat == 0)
1119: continue;
1120:
1121: if (ISSET(stat, CD1400_SVRR_RXRDY)) {
1122: u_char save_car, save_rir, serv_type;
1123: u_char line_stat, recv_data, n_chars;
1124: u_char *buf_p;
1125:
1126: save_rir = cd_read_reg_sc(sc, cy_chip, CD1400_RIR);
1127: save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR);
1128: /* enter rx service */
1129: cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_rir);
1130:
1131: serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_RIVR);
1132: cy = &sc->sc_ports[serv_type >> 3];
1133:
1134: #ifdef CY_DEBUG1
1135: cy->cy_rx_int_count++;
1136: #endif
1137:
1138: buf_p = cy->cy_ibuf_wr_ptr;
1139:
1140: if (ISSET(serv_type, CD1400_RIVR_EXCEPTION)) {
1141: line_stat = cd_read_reg(cy, CD1400_RDSR);
1142: recv_data = cd_read_reg(cy, CD1400_RDSR);
1143:
1144: if (cy->cy_tty == NULL ||
1145: !ISSET(cy->cy_tty->t_state, TS_ISOPEN))
1146: goto end_rx_serv;
1147:
1148: #ifdef CY_DEBUG
1149: printf("%s port %d recv exception, "
1150: "line_stat 0x%x, char 0x%x\n",
1151: sc->sc_dev.dv_xname, cy->cy_port_num,
1152: line_stat, recv_data);
1153: #endif
1154: if (ISSET(line_stat, CD1400_RDSR_OE))
1155: cy->cy_fifo_overruns++;
1156:
1157: *buf_p++ = line_stat;
1158: *buf_p++ = recv_data;
1159: if (buf_p == cy->cy_ibuf_end)
1160: buf_p = cy->cy_ibuf;
1161:
1162: if (buf_p == cy->cy_ibuf_rd_ptr) {
1163: if (buf_p == cy->cy_ibuf)
1164: buf_p = cy->cy_ibuf_end;
1165: buf_p -= 2;
1166: cy->cy_ibuf_overruns++;
1167: }
1168: sc->sc_events = 1;
1169: } else { /* no exception, received data OK */
1170: n_chars = cd_read_reg(cy, CD1400_RDCR);
1171:
1172: /* If no tty or not open, discard data */
1173: if (cy->cy_tty == NULL ||
1174: !ISSET(cy->cy_tty->t_state, TS_ISOPEN)) {
1175: while (n_chars--)
1176: cd_read_reg(cy, CD1400_RDSR);
1177: goto end_rx_serv;
1178: }
1179:
1180: #ifdef CY_DEBUG
1181: printf("%s port %d receive ok %d chars\n",
1182: sc->sc_dev.dv_xname, cy->cy_port_num,
1183: n_chars);
1184: #endif
1185: while (n_chars--) {
1186: *buf_p++ = 0; /* status: OK */
1187: *buf_p++ = cd_read_reg(cy,
1188: CD1400_RDSR); /* data byte */
1189: if (buf_p == cy->cy_ibuf_end)
1190: buf_p = cy->cy_ibuf;
1191: if (buf_p == cy->cy_ibuf_rd_ptr) {
1192: if (buf_p == cy->cy_ibuf)
1193: buf_p = cy->cy_ibuf_end;
1194: buf_p -= 2;
1195: cy->cy_ibuf_overruns++;
1196: break;
1197: }
1198: }
1199: sc->sc_events = 1;
1200: }
1201:
1202: cy->cy_ibuf_wr_ptr = buf_p;
1203:
1204: #ifndef CY_HW_RTS
1205: /* RTS handshaking for incoming data */
1206: if (ISSET(cy->cy_tty->t_cflag, CRTSCTS)) {
1207: int bf;
1208:
1209: bf = buf_p - cy->cy_ibuf_rd_ptr;
1210: if (bf < 0)
1211: bf += IBUF_SIZE;
1212:
1213: if (bf > (IBUF_SIZE/2)) /* turn RTS off */
1214: cd_write_reg(cy, CD1400_MSVR1, 0);
1215: }
1216: #endif /* CY_HW_RTS */
1217:
1218: end_rx_serv:
1219: /* terminate service context */
1220: cd_write_reg(cy, CD1400_RIR, save_rir & 0x3f);
1221: cd_write_reg(cy, CD1400_CAR, save_car);
1222: int_serviced = 1;
1223: } /* if(rx_service...) */
1224:
1225: if (ISSET(stat, CD1400_SVRR_MDMCH)) {
1226: u_char save_car, save_mir, serv_type, modem_stat;
1227:
1228: save_mir = cd_read_reg_sc(sc, cy_chip, CD1400_MIR);
1229: save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR);
1230: /* enter modem service */
1231: cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_mir);
1232:
1233: serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_MIVR);
1234: cy = &sc->sc_ports[serv_type >> 3];
1235:
1236: #ifdef CY_DEBUG1
1237: cy->cy_modem_int_count++;
1238: #endif
1239:
1240: modem_stat = cd_read_reg(cy, CD1400_MSVR2);
1241:
1242: #ifdef CY_DEBUG
1243: printf("%s port %d modem line change, new stat 0x%x\n",
1244: sc->sc_dev.dv_xname, cy->cy_port_num, modem_stat);
1245: #endif
1246: if (ISSET((cy->cy_carrier_stat ^ modem_stat),
1247: CD1400_MSVR2_CD)) {
1248: SET(cy->cy_flags, CYF_CARRIER_CHANGED);
1249: sc->sc_events = 1;
1250: }
1251:
1252: cy->cy_carrier_stat = modem_stat;
1253:
1254: /* terminate service context */
1255: cd_write_reg(cy, CD1400_MIR, save_mir & 0x3f);
1256: cd_write_reg(cy, CD1400_CAR, save_car);
1257: int_serviced = 1;
1258: } /* if(modem_service...) */
1259:
1260: if (ISSET(stat, CD1400_SVRR_TXRDY)) {
1261: u_char save_car, save_tir, serv_type, count, ch;
1262: struct tty *tp;
1263:
1264: save_tir = cd_read_reg_sc(sc, cy_chip, CD1400_TIR);
1265: save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR);
1266: /* enter tx service */
1267: cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_tir);
1268:
1269: serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_TIVR);
1270: cy = &sc->sc_ports[serv_type >> 3];
1271:
1272: #ifdef CY_DEBUG1
1273: cy->cy_tx_int_count++;
1274: #endif
1275: #ifdef CY_DEBUG
1276: printf("%s port %d tx service\n", sc->sc_dev.dv_xname,
1277: cy->cy_port_num);
1278: #endif
1279:
1280: /* stop transmitting if no tty or CYF_STOP set */
1281: tp = cy->cy_tty;
1282: if (tp == NULL || ISSET(cy->cy_flags, CYF_STOP))
1283: goto txdone;
1284:
1285: count = 0;
1286: if (ISSET(cy->cy_flags, CYF_SEND_NUL)) {
1287: cd_write_reg(cy, CD1400_TDR, 0);
1288: cd_write_reg(cy, CD1400_TDR, 0);
1289: count += 2;
1290: CLR(cy->cy_flags, CYF_SEND_NUL);
1291: }
1292:
1293: if (tp->t_outq.c_cc > 0) {
1294: SET(tp->t_state, TS_BUSY);
1295: while (tp->t_outq.c_cc > 0 &&
1296: count < CD1400_TX_FIFO_SIZE) {
1297: ch = getc(&tp->t_outq);
1298: /* remember to double NUL characters
1299: because embedded transmit commands
1300: are enabled */
1301: if (ch == 0) {
1302: if (count >=
1303: CD1400_TX_FIFO_SIZE-2) {
1304: SET(cy->cy_flags,
1305: CYF_SEND_NUL);
1306: break;
1307: }
1308:
1309: cd_write_reg(cy, CD1400_TDR, ch);
1310: count++;
1311: }
1312:
1313: cd_write_reg(cy, CD1400_TDR, ch);
1314: count++;
1315: }
1316: } else {
1317: /* no data to send -- check if we should
1318: start/stop a break */
1319: /* XXX does this cause too much delay before
1320: breaks? */
1321: if (ISSET(cy->cy_flags, CYF_START_BREAK)) {
1322: cd_write_reg(cy, CD1400_TDR, 0);
1323: cd_write_reg(cy, CD1400_TDR, 0x81);
1324: CLR(cy->cy_flags, CYF_START_BREAK);
1325: }
1326: if (ISSET(cy->cy_flags, CYF_END_BREAK)) {
1327: cd_write_reg(cy, CD1400_TDR, 0);
1328: cd_write_reg(cy, CD1400_TDR, 0x83);
1329: CLR(cy->cy_flags, CYF_END_BREAK);
1330: }
1331: }
1332:
1333: if (tp->t_outq.c_cc == 0) {
1334: txdone:
1335: /*
1336: * No data to send or requested to stop.
1337: * Disable transmit interrupt
1338: */
1339: cd_write_reg(cy, CD1400_SRER,
1340: cd_read_reg(cy, CD1400_SRER)
1341: & ~CD1400_SRER_TXRDY);
1342: CLR(cy->cy_flags, CYF_STOP);
1343: CLR(tp->t_state, TS_BUSY);
1344: }
1345:
1346: if (tp->t_outq.c_cc <= tp->t_lowat) {
1347: SET(cy->cy_flags, CYF_START);
1348: sc->sc_events = 1;
1349: }
1350:
1351: /* terminate service context */
1352: cd_write_reg(cy, CD1400_TIR, save_tir & 0x3f);
1353: cd_write_reg(cy, CD1400_CAR, save_car);
1354: int_serviced = 1;
1355: } /* if(tx_service...) */
1356: } /* for(...all CD1400s on a card) */
1357:
1358: /* ensure an edge for next interrupt */
1359: bus_space_write_1(sc->sc_memt, sc->sc_memh,
1360: CY_CLEAR_INTR<<sc->sc_bustype, 0);
1361: return (int_serviced);
1362: }
1363:
1364: /*
1365: * subroutine to enable CD1400 transmitter
1366: */
1367: void
1368: cy_enable_transmitter(cy)
1369: struct cy_port *cy;
1370: {
1371: int s;
1372: s = spltty();
1373: cd_write_reg(cy, CD1400_CAR, cy->cy_port_num & CD1400_CAR_CHAN);
1374: cd_write_reg(cy, CD1400_SRER, cd_read_reg(cy, CD1400_SRER)
1375: | CD1400_SRER_TXRDY);
1376: splx(s);
1377: }
1378:
1379: /*
1380: * Execute a CD1400 channel command
1381: */
1382: void
1383: cd1400_channel_cmd(cy, cmd)
1384: struct cy_port *cy;
1385: int cmd;
1386: {
1387: u_int waitcnt = 5 * 8 * 1024; /* approx 5 ms */
1388:
1389: #ifdef CY_DEBUG
1390: printf("c1400_channel_cmd cy 0x%x command 0x%x\n", cy, cmd);
1391: #endif
1392:
1393: /* wait until cd1400 is ready to process a new command */
1394: while (cd_read_reg(cy, CD1400_CCR) != 0 && waitcnt-- > 0)
1395: ;
1396:
1397: if (waitcnt == 0)
1398: log(LOG_ERR, "cy: channel command timeout\n");
1399:
1400: cd_write_reg(cy, CD1400_CCR, cmd);
1401: }
1402:
1403: /*
1404: * Compute clock option register and baud rate register values
1405: * for a given speed. Return 0 on success, -1 on failure.
1406: *
1407: * The error between requested and actual speed seems
1408: * to be well within allowed limits (less than 3%)
1409: * with every speed value between 50 and 150000 bps.
1410: */
1411: int
1412: cy_speed(speed_t speed, int *cor, int *bpr, int cy_clock)
1413: {
1414: int c, co, br;
1415:
1416: if (speed < 50 || speed > 150000)
1417: return (-1);
1418:
1419: for (c = 0, co = 8; co <= 2048; co <<= 2, c++) {
1420: br = (cy_clock + (co * speed) / 2) / (co * speed);
1421: if (br < 0x100) {
1422: *bpr = br;
1423: *cor = c;
1424: return (0);
1425: }
1426: }
1427:
1428: return (-1);
1429: }
1430:
1431: #endif /* NCY > 0 */
CVSweb