1 /* $NetBSD: clmpcc.c,v 1.42 2009/03/14 21:04:19 dsl Exp $ */
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Steve C. Woodford.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Cirrus Logic CD2400/CD2401 Four Channel Multi-Protocol Comms. Controller.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: clmpcc.c,v 1.42 2009/03/14 21:04:19 dsl Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/ioctl.h>
44 #include <sys/select.h>
50 #include <sys/kernel.h>
51 #include <sys/syslog.h>
52 #include <sys/device.h>
53 #include <sys/malloc.h>
54 #include <sys/kauth.h>
58 #include <machine/param.h>
60 #include <dev/ic/clmpccreg.h>
61 #include <dev/ic/clmpccvar.h>
65 #if defined(CLMPCC_ONLY_BYTESWAP_LOW) && defined(CLMPCC_ONLY_BYTESWAP_HIGH)
66 #error "CLMPCC_ONLY_BYTESWAP_LOW and CLMPCC_ONLY_BYTESWAP_HIGH are mutually exclusive."
70 static int clmpcc_init(struct clmpcc_softc
*sc
);
71 static void clmpcc_shutdown(struct clmpcc_chan
*);
72 static int clmpcc_speed(struct clmpcc_softc
*, speed_t
, int *, int *);
73 static int clmpcc_param(struct tty
*, struct termios
*);
74 static void clmpcc_set_params(struct clmpcc_chan
*);
75 static void clmpcc_start(struct tty
*);
76 static int clmpcc_modem_control(struct clmpcc_chan
*, int, int);
78 #define CLMPCCUNIT(x) (minor(x) & 0x7fffc)
79 #define CLMPCCCHAN(x) (minor(x) & 0x00003)
80 #define CLMPCCDIALOUT(x) (minor(x) & 0x80000)
83 * These should be in a header file somewhere...
85 #define ISCLR(v, f) (((v) & (f)) == 0)
87 extern struct cfdriver clmpcc_cd
;
89 dev_type_open(clmpccopen
);
90 dev_type_close(clmpccclose
);
91 dev_type_read(clmpccread
);
92 dev_type_write(clmpccwrite
);
93 dev_type_ioctl(clmpccioctl
);
94 dev_type_stop(clmpccstop
);
95 dev_type_tty(clmpcctty
);
96 dev_type_poll(clmpccpoll
);
98 const struct cdevsw clmpcc_cdevsw
= {
99 clmpccopen
, clmpccclose
, clmpccread
, clmpccwrite
, clmpccioctl
,
100 clmpccstop
, clmpcctty
, clmpccpoll
, nommap
, ttykqfilter
, D_TTY
104 * Make this an option variable one can patch.
106 u_int clmpcc_ibuf_size
= CLMPCC_RING_SIZE
;
110 * Things needed when the device is used as a console
112 static struct clmpcc_softc
*cons_sc
= NULL
;
113 static int cons_chan
;
114 static int cons_rate
;
116 static int clmpcc_common_getc(struct clmpcc_softc
*, int);
117 static void clmpcc_common_putc(struct clmpcc_softc
*, int, int);
118 int clmpcccngetc(dev_t
);
119 void clmpcccnputc(dev_t
, int);
123 * Convenience functions, inlined for speed
125 #define integrate static inline
126 integrate u_int8_t
clmpcc_rdreg(struct clmpcc_softc
*, u_int
);
127 integrate
void clmpcc_wrreg(struct clmpcc_softc
*, u_int
, u_int
);
128 integrate u_int8_t
clmpcc_rdreg_odd(struct clmpcc_softc
*, u_int
);
129 integrate
void clmpcc_wrreg_odd(struct clmpcc_softc
*, u_int
, u_int
);
130 integrate
void clmpcc_wrtx_multi(struct clmpcc_softc
*, u_int8_t
*,
132 integrate u_int8_t
clmpcc_select_channel(struct clmpcc_softc
*, u_int
);
133 integrate
void clmpcc_channel_cmd(struct clmpcc_softc
*,int,int);
134 integrate
void clmpcc_enable_transmitter(struct clmpcc_chan
*);
136 #define clmpcc_rd_msvr(s) clmpcc_rdreg_odd(s,CLMPCC_REG_MSVR)
137 #define clmpcc_wr_msvr(s,r,v) clmpcc_wrreg_odd(s,r,v)
138 #define clmpcc_wr_pilr(s,r,v) clmpcc_wrreg_odd(s,r,v)
139 #define clmpcc_rd_rxdata(s) clmpcc_rdreg_odd(s,CLMPCC_REG_RDR)
140 #define clmpcc_wr_txdata(s,v) clmpcc_wrreg_odd(s,CLMPCC_REG_TDR,v)
144 clmpcc_rdreg(struct clmpcc_softc
*sc
, u_int offset
)
146 #if !defined(CLMPCC_ONLY_BYTESWAP_LOW) && !defined(CLMPCC_ONLY_BYTESWAP_HIGH)
147 offset
^= sc
->sc_byteswap
;
148 #elif defined(CLMPCC_ONLY_BYTESWAP_HIGH)
149 offset
^= CLMPCC_BYTESWAP_HIGH
;
151 return bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, offset
);
155 clmpcc_wrreg(struct clmpcc_softc
*sc
, u_int offset
, u_int val
)
157 #if !defined(CLMPCC_ONLY_BYTESWAP_LOW) && !defined(CLMPCC_ONLY_BYTESWAP_HIGH)
158 offset
^= sc
->sc_byteswap
;
159 #elif defined(CLMPCC_ONLY_BYTESWAP_HIGH)
160 offset
^= CLMPCC_BYTESWAP_HIGH
;
162 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, offset
, val
);
166 clmpcc_rdreg_odd(struct clmpcc_softc
*sc
, u_int offset
)
168 #if !defined(CLMPCC_ONLY_BYTESWAP_LOW) && !defined(CLMPCC_ONLY_BYTESWAP_HIGH)
169 offset
^= (sc
->sc_byteswap
& 2);
170 #elif defined(CLMPCC_ONLY_BYTESWAP_HIGH)
171 offset
^= (CLMPCC_BYTESWAP_HIGH
& 2);
173 return bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, offset
);
177 clmpcc_wrreg_odd(struct clmpcc_softc
*sc
, u_int offset
, u_int val
)
179 #if !defined(CLMPCC_ONLY_BYTESWAP_LOW) && !defined(CLMPCC_ONLY_BYTESWAP_HIGH)
180 offset
^= (sc
->sc_byteswap
& 2);
181 #elif defined(CLMPCC_ONLY_BYTESWAP_HIGH)
182 offset
^= (CLMPCC_BYTESWAP_HIGH
& 2);
184 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, offset
, val
);
188 clmpcc_wrtx_multi(struct clmpcc_softc
*sc
, u_int8_t
*buff
, u_int count
)
190 u_int offset
= CLMPCC_REG_TDR
;
192 #if !defined(CLMPCC_ONLY_BYTESWAP_LOW) && !defined(CLMPCC_ONLY_BYTESWAP_HIGH)
193 offset
^= (sc
->sc_byteswap
& 2);
194 #elif defined(CLMPCC_ONLY_BYTESWAP_HIGH)
195 offset
^= (CLMPCC_BYTESWAP_HIGH
& 2);
197 bus_space_write_multi_1(sc
->sc_iot
, sc
->sc_ioh
, offset
, buff
, count
);
201 clmpcc_select_channel(struct clmpcc_softc
*sc
, u_int new_chan
)
203 u_int old_chan
= clmpcc_rdreg_odd(sc
, CLMPCC_REG_CAR
);
205 clmpcc_wrreg_odd(sc
, CLMPCC_REG_CAR
, new_chan
);
211 clmpcc_channel_cmd(struct clmpcc_softc
*sc
, int chan
, int cmd
)
215 for (i
= 5000; i
; i
--) {
216 if ( clmpcc_rdreg(sc
, CLMPCC_REG_CCR
) == 0 )
222 printf("%s: channel %d command timeout (idle)\n",
223 device_xname(&sc
->sc_dev
), chan
);
225 clmpcc_wrreg(sc
, CLMPCC_REG_CCR
, cmd
);
229 clmpcc_enable_transmitter(struct clmpcc_chan
*ch
)
234 old
= clmpcc_select_channel(ch
->ch_sc
, ch
->ch_car
);
237 clmpcc_wrreg(ch
->ch_sc
, CLMPCC_REG_IER
,
238 clmpcc_rdreg(ch
->ch_sc
, CLMPCC_REG_IER
) | CLMPCC_IER_TX_EMPTY
);
239 SET(ch
->ch_tty
->t_state
, TS_BUSY
);
242 clmpcc_select_channel(ch
->ch_sc
, old
);
246 clmpcc_speed(struct clmpcc_softc
*sc
, speed_t speed
, int *cor
, int *bpr
)
250 for (co
= 0, c
= 8; c
<= 2048; co
++, c
*= 4) {
251 br
= ((sc
->sc_clk
/ c
) / speed
) - 1;
263 clmpcc_attach(struct clmpcc_softc
*sc
)
265 struct clmpcc_chan
*ch
;
269 if ( cons_sc
!= NULL
&&
270 sc
->sc_iot
== cons_sc
->sc_iot
&& sc
->sc_ioh
== cons_sc
->sc_ioh
)
273 /* Initialise the chip */
276 printf(": Cirrus Logic CD240%c Serial Controller\n",
277 (clmpcc_rd_msvr(sc
) & CLMPCC_MSVR_PORT_ID
) ? '0' : '1');
279 sc
->sc_softintr_cookie
=
280 softint_establish(SOFTINT_SERIAL
, clmpcc_softintr
, sc
);
281 if (sc
->sc_softintr_cookie
== NULL
)
282 panic("clmpcc_attach: softintr_establish");
283 memset(&(sc
->sc_chans
[0]), 0, sizeof(sc
->sc_chans
));
285 for (chan
= 0; chan
< CLMPCC_NUM_CHANS
; chan
++) {
286 ch
= &sc
->sc_chans
[chan
];
292 tp
->t_oproc
= clmpcc_start
;
293 tp
->t_param
= clmpcc_param
;
297 ch
->ch_ibuf
= malloc(clmpcc_ibuf_size
* 2, M_DEVBUF
, M_NOWAIT
);
298 if ( ch
->ch_ibuf
== NULL
) {
299 aprint_error_dev(&sc
->sc_dev
, "(%d): unable to allocate ring buffer\n",
304 ch
->ch_ibuf_end
= &(ch
->ch_ibuf
[clmpcc_ibuf_size
* 2]);
305 ch
->ch_ibuf_rd
= ch
->ch_ibuf_wr
= ch
->ch_ibuf
;
310 aprint_error_dev(&sc
->sc_dev
, "%d channels available",
312 if ( cons_sc
== sc
) {
313 printf(", console on channel %d.\n", cons_chan
);
314 SET(sc
->sc_chans
[cons_chan
].ch_flags
, CLMPCC_FLG_IS_CONSOLE
);
315 SET(sc
->sc_chans
[cons_chan
].ch_openflags
, TIOCFLAG_SOFTCAR
);
321 clmpcc_init(struct clmpcc_softc
*sc
)
325 u_int msvr_rts
, msvr_dtr
;
331 * All we're really concerned about here is putting the chip
332 * into a quiescent state so that it won't do anything until
333 * clmpccopen() is called. (Except the console channel.)
337 * If the chip is acting as console, set all channels to the supplied
338 * console baud rate. Otherwise, plump for 9600.
341 sc
->sc_ioh
== cons_sc
->sc_ioh
&& sc
->sc_iot
== cons_sc
->sc_iot
) {
342 clmpcc_speed(sc
, cons_rate
, &tcor
, &tbpr
);
343 clmpcc_speed(sc
, cons_rate
, &rcor
, &rbpr
);
346 clmpcc_speed(sc
, 9600, &tcor
, &tbpr
);
347 clmpcc_speed(sc
, 9600, &rcor
, &rbpr
);
351 /* Allow any pending output to be sent */
354 /* Send the Reset All command to channel 0 (resets all channels!) */
355 clmpcc_channel_cmd(sc
, 0, CLMPCC_CCR_T0_RESET_ALL
);
360 * The chip will set it's firmware revision register to a non-zero
361 * value to indicate completion of reset.
363 for (i
= 10000; clmpcc_rdreg(sc
, CLMPCC_REG_GFRCR
) == 0 && i
; i
--)
368 * Watch out... If this chip is console, the message
369 * probably won't be sent since we just reset it!
371 aprint_error_dev(&sc
->sc_dev
, "Failed to reset chip\n");
375 for (i
= 0; i
< CLMPCC_NUM_CHANS
; i
++) {
376 clmpcc_select_channel(sc
, i
);
378 /* All interrupts are disabled to begin with */
379 clmpcc_wrreg(sc
, CLMPCC_REG_IER
, 0);
381 /* Make sure the channel interrupts on the correct vectors */
382 clmpcc_wrreg(sc
, CLMPCC_REG_LIVR
, sc
->sc_vector_base
);
383 clmpcc_wr_pilr(sc
, CLMPCC_REG_RPILR
, sc
->sc_rpilr
);
384 clmpcc_wr_pilr(sc
, CLMPCC_REG_TPILR
, sc
->sc_tpilr
);
385 clmpcc_wr_pilr(sc
, CLMPCC_REG_MPILR
, sc
->sc_mpilr
);
387 /* Receive timer prescaler set to 1ms */
388 clmpcc_wrreg(sc
, CLMPCC_REG_TPR
,
389 CLMPCC_MSEC_TO_TPR(sc
->sc_clk
, 1));
391 /* We support Async mode only */
392 clmpcc_wrreg(sc
, CLMPCC_REG_CMR
, CLMPCC_CMR_ASYNC
);
394 /* Set the required baud rate */
395 clmpcc_wrreg(sc
, CLMPCC_REG_TCOR
, CLMPCC_TCOR_CLK(tcor
));
396 clmpcc_wrreg(sc
, CLMPCC_REG_TBPR
, tbpr
);
397 clmpcc_wrreg(sc
, CLMPCC_REG_RCOR
, CLMPCC_RCOR_CLK(rcor
));
398 clmpcc_wrreg(sc
, CLMPCC_REG_RBPR
, rbpr
);
400 /* Always default to 8N1 (XXX what about console?) */
401 clmpcc_wrreg(sc
, CLMPCC_REG_COR1
, CLMPCC_COR1_CHAR_8BITS
|
402 CLMPCC_COR1_NO_PARITY
|
403 CLMPCC_COR1_IGNORE_PAR
);
405 clmpcc_wrreg(sc
, CLMPCC_REG_COR2
, 0);
407 clmpcc_wrreg(sc
, CLMPCC_REG_COR3
, CLMPCC_COR3_STOP_1
);
409 clmpcc_wrreg(sc
, CLMPCC_REG_COR4
, CLMPCC_COR4_DSRzd
|
413 clmpcc_wrreg(sc
, CLMPCC_REG_COR5
, CLMPCC_COR5_DSRod
|
416 CLMPCC_COR5_FLOW_NORM
);
418 clmpcc_wrreg(sc
, CLMPCC_REG_COR6
, 0);
419 clmpcc_wrreg(sc
, CLMPCC_REG_COR7
, 0);
421 /* Set the receive FIFO timeout */
422 clmpcc_wrreg(sc
, CLMPCC_REG_RTPRl
, CLMPCC_RTPR_DEFAULT
);
423 clmpcc_wrreg(sc
, CLMPCC_REG_RTPRh
, 0);
425 /* At this point, we set up the console differently */
426 if ( is_console
&& i
== cons_chan
) {
427 msvr_rts
= CLMPCC_MSVR_RTS
;
428 msvr_dtr
= CLMPCC_MSVR_DTR
;
429 ccr
= CLMPCC_CCR_T0_RX_EN
| CLMPCC_CCR_T0_TX_EN
;
433 ccr
= CLMPCC_CCR_T0_RX_DIS
| CLMPCC_CCR_T0_TX_DIS
;
436 clmpcc_wrreg(sc
, CLMPCC_REG_MSVR_RTS
, msvr_rts
);
437 clmpcc_wrreg(sc
, CLMPCC_REG_MSVR_DTR
, msvr_dtr
);
438 clmpcc_channel_cmd(sc
, i
, CLMPCC_CCR_T0_INIT
| ccr
);
446 clmpcc_shutdown(struct clmpcc_chan
*ch
)
450 oldch
= clmpcc_select_channel(ch
->ch_sc
, ch
->ch_car
);
452 /* Turn off interrupts. */
453 clmpcc_wrreg(ch
->ch_sc
, CLMPCC_REG_IER
, 0);
455 if ( ISCLR(ch
->ch_flags
, CLMPCC_FLG_IS_CONSOLE
) ) {
456 /* Disable the transmitter and receiver */
457 clmpcc_channel_cmd(ch
->ch_sc
, ch
->ch_car
, CLMPCC_CCR_T0_RX_DIS
|
458 CLMPCC_CCR_T0_TX_DIS
);
460 /* Drop RTS and DTR */
461 clmpcc_modem_control(ch
, TIOCM_RTS
| TIOCM_DTR
, DMBIS
);
464 clmpcc_select_channel(ch
->ch_sc
, oldch
);
468 clmpccopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
470 struct clmpcc_softc
*sc
;
471 struct clmpcc_chan
*ch
;
476 sc
= device_lookup_private(&clmpcc_cd
, CLMPCCUNIT(dev
));
480 ch
= &sc
->sc_chans
[CLMPCCCHAN(dev
)];
484 if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
, tp
))
488 * Do the following iff this is a first open.
490 if ( ISCLR(tp
->t_state
, TS_ISOPEN
) && tp
->t_wopen
== 0 ) {
495 tp
->t_iflag
= TTYDEF_IFLAG
;
496 tp
->t_oflag
= TTYDEF_OFLAG
;
497 tp
->t_lflag
= TTYDEF_LFLAG
;
498 tp
->t_cflag
= TTYDEF_CFLAG
;
499 tp
->t_ospeed
= tp
->t_ispeed
= TTYDEF_SPEED
;
501 if ( ISSET(ch
->ch_openflags
, TIOCFLAG_CLOCAL
) )
502 SET(tp
->t_cflag
, CLOCAL
);
503 if ( ISSET(ch
->ch_openflags
, TIOCFLAG_CRTSCTS
) )
504 SET(tp
->t_cflag
, CRTSCTS
);
505 if ( ISSET(ch
->ch_openflags
, TIOCFLAG_MDMBUF
) )
506 SET(tp
->t_cflag
, MDMBUF
);
509 * Override some settings if the channel is being
510 * used as the console.
512 if ( ISSET(ch
->ch_flags
, CLMPCC_FLG_IS_CONSOLE
) ) {
513 tp
->t_ospeed
= tp
->t_ispeed
= cons_rate
;
514 SET(tp
->t_cflag
, CLOCAL
);
515 CLR(tp
->t_cflag
, CRTSCTS
);
516 CLR(tp
->t_cflag
, HUPCL
);
521 clmpcc_param(tp
, &tp
->t_termios
);
524 /* Clear the input ring */
525 ch
->ch_ibuf_rd
= ch
->ch_ibuf_wr
= ch
->ch_ibuf
;
527 /* Select the channel */
528 oldch
= clmpcc_select_channel(sc
, ch
->ch_car
);
531 clmpcc_channel_cmd(sc
, ch
->ch_car
, CLMPCC_CCR_T0_CLEAR
|
532 CLMPCC_CCR_T0_RX_EN
|
533 CLMPCC_CCR_T0_TX_EN
);
535 /* Enable receiver and modem change interrupts. */
536 clmpcc_wrreg(sc
, CLMPCC_REG_IER
, CLMPCC_IER_MODEM
|
540 /* Raise RTS and DTR */
541 clmpcc_modem_control(ch
, TIOCM_RTS
| TIOCM_DTR
, DMBIS
);
543 clmpcc_select_channel(sc
, oldch
);
546 error
= ttyopen(tp
, CLMPCCDIALOUT(dev
), ISSET(flag
, O_NONBLOCK
));
550 error
= (*tp
->t_linesw
->l_open
)(dev
, tp
);
557 if ( ISCLR(tp
->t_state
, TS_ISOPEN
) && tp
->t_wopen
== 0 ) {
559 * We failed to open the device, and nobody else had it opened.
560 * Clean up the state as appropriate.
569 clmpccclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
571 struct clmpcc_softc
*sc
=
572 device_lookup_private(&clmpcc_cd
, CLMPCCUNIT(dev
));
573 struct clmpcc_chan
*ch
= &sc
->sc_chans
[CLMPCCCHAN(dev
)];
574 struct tty
*tp
= ch
->ch_tty
;
577 if ( ISCLR(tp
->t_state
, TS_ISOPEN
) )
580 (*tp
->t_linesw
->l_close
)(tp
, flag
);
584 if ( ISCLR(tp
->t_state
, TS_ISOPEN
) && tp
->t_wopen
== 0 ) {
586 * Although we got a last close, the device may still be in
587 * use; e.g. if this was the dialout node, and there are still
588 * processes waiting for carrier on the non-dialout node.
601 clmpccread(dev_t dev
, struct uio
*uio
, int flag
)
603 struct clmpcc_softc
*sc
= device_lookup_private(&clmpcc_cd
, CLMPCCUNIT(dev
));
604 struct tty
*tp
= sc
->sc_chans
[CLMPCCCHAN(dev
)].ch_tty
;
606 return ((*tp
->t_linesw
->l_read
)(tp
, uio
, flag
));
610 clmpccwrite(dev_t dev
, struct uio
*uio
, int flag
)
612 struct clmpcc_softc
*sc
= device_lookup_private(&clmpcc_cd
, CLMPCCUNIT(dev
));
613 struct tty
*tp
= sc
->sc_chans
[CLMPCCCHAN(dev
)].ch_tty
;
615 return ((*tp
->t_linesw
->l_write
)(tp
, uio
, flag
));
619 clmpccpoll(dev_t dev
, int events
, struct lwp
*l
)
621 struct clmpcc_softc
*sc
= device_lookup_private(&clmpcc_cd
, CLMPCCUNIT(dev
));
622 struct tty
*tp
= sc
->sc_chans
[CLMPCCCHAN(dev
)].ch_tty
;
624 return ((*tp
->t_linesw
->l_poll
)(tp
, events
, l
));
630 struct clmpcc_softc
*sc
= device_lookup_private(&clmpcc_cd
, CLMPCCUNIT(dev
));
632 return (sc
->sc_chans
[CLMPCCCHAN(dev
)].ch_tty
);
636 clmpccioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
638 struct clmpcc_softc
*sc
= device_lookup_private(&clmpcc_cd
, CLMPCCUNIT(dev
));
639 struct clmpcc_chan
*ch
= &sc
->sc_chans
[CLMPCCCHAN(dev
)];
640 struct tty
*tp
= ch
->ch_tty
;
643 error
= (*tp
->t_linesw
->l_ioctl
)(tp
, cmd
, data
, flag
, l
);
644 if (error
!= EPASSTHROUGH
)
647 error
= ttioctl(tp
, cmd
, data
, flag
, l
);
648 if (error
!= EPASSTHROUGH
)
655 SET(ch
->ch_flags
, CLMPCC_FLG_START_BREAK
);
656 clmpcc_enable_transmitter(ch
);
660 SET(ch
->ch_flags
, CLMPCC_FLG_END_BREAK
);
661 clmpcc_enable_transmitter(ch
);
665 clmpcc_modem_control(ch
, TIOCM_DTR
, DMBIS
);
669 clmpcc_modem_control(ch
, TIOCM_DTR
, DMBIC
);
673 clmpcc_modem_control(ch
, *((int *)data
), DMSET
);
677 clmpcc_modem_control(ch
, *((int *)data
), DMBIS
);
681 clmpcc_modem_control(ch
, *((int *)data
), DMBIC
);
685 *((int *)data
) = clmpcc_modem_control(ch
, 0, DMGET
);
689 *((int *)data
) = ch
->ch_openflags
;
693 error
= kauth_authorize_device_tty(l
->l_cred
,
694 KAUTH_DEVICE_TTY_PRIVSET
, tp
);
697 ch
->ch_openflags
= *((int *)data
) &
698 (TIOCFLAG_SOFTCAR
| TIOCFLAG_CLOCAL
|
699 TIOCFLAG_CRTSCTS
| TIOCFLAG_MDMBUF
);
700 if ( ISSET(ch
->ch_flags
, CLMPCC_FLG_IS_CONSOLE
) )
701 SET(ch
->ch_openflags
, TIOCFLAG_SOFTCAR
);
705 error
= EPASSTHROUGH
;
713 clmpcc_modem_control(struct clmpcc_chan
*ch
, int bits
, int howto
)
715 struct clmpcc_softc
*sc
= ch
->ch_sc
;
716 struct tty
*tp
= ch
->ch_tty
;
721 oldch
= clmpcc_select_channel(sc
, ch
->ch_car
);
725 msvr
= clmpcc_rd_msvr(sc
);
727 if ( sc
->sc_swaprtsdtr
) {
728 rbits
|= (msvr
& CLMPCC_MSVR_RTS
) ? TIOCM_DTR
: 0;
729 rbits
|= (msvr
& CLMPCC_MSVR_DTR
) ? TIOCM_RTS
: 0;
731 rbits
|= (msvr
& CLMPCC_MSVR_RTS
) ? TIOCM_RTS
: 0;
732 rbits
|= (msvr
& CLMPCC_MSVR_DTR
) ? TIOCM_DTR
: 0;
735 rbits
|= (msvr
& CLMPCC_MSVR_CTS
) ? TIOCM_CTS
: 0;
736 rbits
|= (msvr
& CLMPCC_MSVR_CD
) ? TIOCM_CD
: 0;
737 rbits
|= (msvr
& CLMPCC_MSVR_DSR
) ? TIOCM_DSR
: 0;
741 if ( sc
->sc_swaprtsdtr
) {
742 if ( ISCLR(tp
->t_cflag
, CRTSCTS
) )
743 clmpcc_wr_msvr(sc
, CLMPCC_REG_MSVR_DTR
,
744 bits
& TIOCM_RTS
? CLMPCC_MSVR_DTR
: 0);
745 clmpcc_wr_msvr(sc
, CLMPCC_REG_MSVR_RTS
,
746 bits
& TIOCM_DTR
? CLMPCC_MSVR_RTS
: 0);
748 if ( ISCLR(tp
->t_cflag
, CRTSCTS
) )
749 clmpcc_wr_msvr(sc
, CLMPCC_REG_MSVR_RTS
,
750 bits
& TIOCM_RTS
? CLMPCC_MSVR_RTS
: 0);
751 clmpcc_wr_msvr(sc
, CLMPCC_REG_MSVR_DTR
,
752 bits
& TIOCM_DTR
? CLMPCC_MSVR_DTR
: 0);
757 if ( sc
->sc_swaprtsdtr
) {
758 if ( ISCLR(tp
->t_cflag
, CRTSCTS
) && ISSET(bits
, TIOCM_RTS
) )
759 clmpcc_wr_msvr(sc
,CLMPCC_REG_MSVR_DTR
, CLMPCC_MSVR_DTR
);
760 if ( ISSET(bits
, TIOCM_DTR
) )
761 clmpcc_wr_msvr(sc
,CLMPCC_REG_MSVR_RTS
, CLMPCC_MSVR_RTS
);
763 if ( ISCLR(tp
->t_cflag
, CRTSCTS
) && ISSET(bits
, TIOCM_RTS
) )
764 clmpcc_wr_msvr(sc
,CLMPCC_REG_MSVR_RTS
, CLMPCC_MSVR_RTS
);
765 if ( ISSET(bits
, TIOCM_DTR
) )
766 clmpcc_wr_msvr(sc
,CLMPCC_REG_MSVR_DTR
, CLMPCC_MSVR_DTR
);
771 if ( sc
->sc_swaprtsdtr
) {
772 if ( ISCLR(tp
->t_cflag
, CRTSCTS
) && ISCLR(bits
, TIOCM_RTS
) )
773 clmpcc_wr_msvr(sc
, CLMPCC_REG_MSVR_DTR
, 0);
774 if ( ISCLR(bits
, TIOCM_DTR
) )
775 clmpcc_wr_msvr(sc
, CLMPCC_REG_MSVR_RTS
, 0);
777 if ( ISCLR(tp
->t_cflag
, CRTSCTS
) && ISCLR(bits
, TIOCM_RTS
) )
778 clmpcc_wr_msvr(sc
, CLMPCC_REG_MSVR_RTS
, 0);
779 if ( ISCLR(bits
, TIOCM_DTR
) )
780 clmpcc_wr_msvr(sc
, CLMPCC_REG_MSVR_DTR
, 0);
785 clmpcc_select_channel(sc
, oldch
);
791 clmpcc_param(struct tty
*tp
, struct termios
*t
)
793 struct clmpcc_softc
*sc
=
794 device_lookup_private(&clmpcc_cd
, CLMPCCUNIT(tp
->t_dev
));
795 struct clmpcc_chan
*ch
= &sc
->sc_chans
[CLMPCCCHAN(tp
->t_dev
)];
802 /* Check requested parameters. */
803 if ( t
->c_ospeed
&& clmpcc_speed(sc
, t
->c_ospeed
, &oclk
, &obpr
) < 0 )
806 if ( t
->c_ispeed
&& clmpcc_speed(sc
, t
->c_ispeed
, &iclk
, &ibpr
) < 0 )
810 * For the console, always force CLOCAL and !HUPCL, so that the port
813 if ( ISSET(ch
->ch_openflags
, TIOCFLAG_SOFTCAR
) ||
814 ISSET(ch
->ch_flags
, CLMPCC_FLG_IS_CONSOLE
) ) {
815 SET(t
->c_cflag
, CLOCAL
);
816 CLR(t
->c_cflag
, HUPCL
);
819 CLR(ch
->ch_flags
, CLMPCC_FLG_UPDATE_PARMS
);
821 /* If ospeed it zero, hangup the line */
822 clmpcc_modem_control(ch
, TIOCM_DTR
, t
->c_ospeed
== 0 ? DMBIC
: DMBIS
);
825 ch
->ch_tcor
= CLMPCC_TCOR_CLK(oclk
);
833 ch
->ch_rcor
= CLMPCC_RCOR_CLK(iclk
);
840 /* Work out value to use for COR1 */
842 if ( ISSET(t
->c_cflag
, PARENB
) ) {
843 cor
|= CLMPCC_COR1_NORM_PARITY
;
844 if ( ISSET(t
->c_cflag
, PARODD
) )
845 cor
|= CLMPCC_COR1_ODD_PARITY
;
848 if ( ISCLR(t
->c_cflag
, INPCK
) )
849 cor
|= CLMPCC_COR1_IGNORE_PAR
;
851 switch ( t
->c_cflag
& CSIZE
) {
853 cor
|= CLMPCC_COR1_CHAR_5BITS
;
857 cor
|= CLMPCC_COR1_CHAR_6BITS
;
861 cor
|= CLMPCC_COR1_CHAR_7BITS
;
865 cor
|= CLMPCC_COR1_CHAR_8BITS
;
872 * The only interesting bit in COR2 is 'CTS Automatic Enable'
873 * when hardware flow control is in effect.
875 ch
->ch_cor2
= ISSET(t
->c_cflag
, CRTSCTS
) ? CLMPCC_COR2_CtsAE
: 0;
877 /* COR3 needs to be set to the number of stop bits... */
878 ch
->ch_cor3
= ISSET(t
->c_cflag
, CSTOPB
) ? CLMPCC_COR3_STOP_2
:
882 * COR4 contains the FIFO threshold setting.
883 * We adjust the threshold depending on the input speed...
885 if ( t
->c_ispeed
<= 1200 )
886 ch
->ch_cor4
= CLMPCC_COR4_FIFO_LOW
;
887 else if ( t
->c_ispeed
<= 19200 )
888 ch
->ch_cor4
= CLMPCC_COR4_FIFO_MED
;
890 ch
->ch_cor4
= CLMPCC_COR4_FIFO_HIGH
;
893 * If chip is used with CTS and DTR swapped, we can enable
894 * automatic hardware flow control.
896 if ( sc
->sc_swaprtsdtr
&& ISSET(t
->c_cflag
, CRTSCTS
) )
897 ch
->ch_cor5
= CLMPCC_COR5_FLOW_NORM
;
902 oldch
= clmpcc_select_channel(sc
, ch
->ch_car
);
905 * COR2 needs to be set immediately otherwise we might never get
906 * a Tx EMPTY interrupt to change the other parameters.
908 if ( clmpcc_rdreg(sc
, CLMPCC_REG_COR2
) != ch
->ch_cor2
)
909 clmpcc_wrreg(sc
, CLMPCC_REG_COR2
, ch
->ch_cor2
);
911 if ( ISCLR(ch
->ch_tty
->t_state
, TS_BUSY
) )
912 clmpcc_set_params(ch
);
914 SET(ch
->ch_flags
, CLMPCC_FLG_UPDATE_PARMS
);
916 clmpcc_select_channel(sc
, oldch
);
924 clmpcc_set_params(struct clmpcc_chan
*ch
)
926 struct clmpcc_softc
*sc
= ch
->ch_sc
;
930 if ( ch
->ch_tcor
|| ch
->ch_tbpr
) {
931 r1
= clmpcc_rdreg(sc
, CLMPCC_REG_TCOR
);
932 r2
= clmpcc_rdreg(sc
, CLMPCC_REG_TBPR
);
933 /* Only write Tx rate if it really has changed */
934 if ( ch
->ch_tcor
!= r1
|| ch
->ch_tbpr
!= r2
) {
935 clmpcc_wrreg(sc
, CLMPCC_REG_TCOR
, ch
->ch_tcor
);
936 clmpcc_wrreg(sc
, CLMPCC_REG_TBPR
, ch
->ch_tbpr
);
940 if ( ch
->ch_rcor
|| ch
->ch_rbpr
) {
941 r1
= clmpcc_rdreg(sc
, CLMPCC_REG_RCOR
);
942 r2
= clmpcc_rdreg(sc
, CLMPCC_REG_RBPR
);
943 /* Only write Rx rate if it really has changed */
944 if ( ch
->ch_rcor
!= r1
|| ch
->ch_rbpr
!= r2
) {
945 clmpcc_wrreg(sc
, CLMPCC_REG_RCOR
, ch
->ch_rcor
);
946 clmpcc_wrreg(sc
, CLMPCC_REG_RBPR
, ch
->ch_rbpr
);
950 if ( clmpcc_rdreg(sc
, CLMPCC_REG_COR1
) != ch
->ch_cor1
) {
951 clmpcc_wrreg(sc
, CLMPCC_REG_COR1
, ch
->ch_cor1
);
952 /* Any change to COR1 requires an INIT command */
953 SET(ch
->ch_flags
, CLMPCC_FLG_NEED_INIT
);
956 if ( clmpcc_rdreg(sc
, CLMPCC_REG_COR3
) != ch
->ch_cor3
)
957 clmpcc_wrreg(sc
, CLMPCC_REG_COR3
, ch
->ch_cor3
);
959 r1
= clmpcc_rdreg(sc
, CLMPCC_REG_COR4
);
960 if ( ch
->ch_cor4
!= (r1
& CLMPCC_COR4_FIFO_MASK
) ) {
962 * Note: If the FIFO has changed, we always set it to
963 * zero here and disable the Receive Timeout interrupt.
964 * It's up to the Rx Interrupt handler to pick the
965 * appropriate moment to write the new FIFO length.
967 clmpcc_wrreg(sc
, CLMPCC_REG_COR4
, r1
& ~CLMPCC_COR4_FIFO_MASK
);
968 r1
= clmpcc_rdreg(sc
, CLMPCC_REG_IER
);
969 clmpcc_wrreg(sc
, CLMPCC_REG_IER
, r1
& ~CLMPCC_IER_RET
);
970 SET(ch
->ch_flags
, CLMPCC_FLG_FIFO_CLEAR
);
973 r1
= clmpcc_rdreg(sc
, CLMPCC_REG_COR5
);
974 if ( ch
->ch_cor5
!= (r1
& CLMPCC_COR5_FLOW_MASK
) ) {
975 r1
&= ~CLMPCC_COR5_FLOW_MASK
;
976 clmpcc_wrreg(sc
, CLMPCC_REG_COR5
, r1
| ch
->ch_cor5
);
981 clmpcc_start(struct tty
*tp
)
983 struct clmpcc_softc
*sc
=
984 device_lookup_private(&clmpcc_cd
, CLMPCCUNIT(tp
->t_dev
));
985 struct clmpcc_chan
*ch
= &sc
->sc_chans
[CLMPCCCHAN(tp
->t_dev
)];
991 if ( ISCLR(tp
->t_state
, TS_TTSTOP
| TS_TIMEOUT
| TS_BUSY
) ) {
993 if ( ISSET(ch
->ch_flags
, CLMPCC_FLG_START_BREAK
|
994 CLMPCC_FLG_END_BREAK
) ||
995 tp
->t_outq
.c_cc
> 0 ) {
997 if ( ISCLR(ch
->ch_flags
, CLMPCC_FLG_START_BREAK
|
998 CLMPCC_FLG_END_BREAK
) ) {
999 ch
->ch_obuf_addr
= tp
->t_outq
.c_cf
;
1000 ch
->ch_obuf_size
= ndqb(&tp
->t_outq
, 0);
1003 /* Enable TX empty interrupts */
1004 oldch
= clmpcc_select_channel(ch
->ch_sc
, ch
->ch_car
);
1005 clmpcc_wrreg(ch
->ch_sc
, CLMPCC_REG_IER
,
1006 clmpcc_rdreg(ch
->ch_sc
, CLMPCC_REG_IER
) |
1007 CLMPCC_IER_TX_EMPTY
);
1008 clmpcc_select_channel(ch
->ch_sc
, oldch
);
1009 SET(tp
->t_state
, TS_BUSY
);
1017 * Stop output on a line.
1020 clmpccstop(struct tty
*tp
, int flag
)
1022 struct clmpcc_softc
*sc
=
1023 device_lookup_private(&clmpcc_cd
, CLMPCCUNIT(tp
->t_dev
));
1024 struct clmpcc_chan
*ch
= &sc
->sc_chans
[CLMPCCCHAN(tp
->t_dev
)];
1029 if ( ISSET(tp
->t_state
, TS_BUSY
) ) {
1030 if ( ISCLR(tp
->t_state
, TS_TTSTOP
) )
1031 SET(tp
->t_state
, TS_FLUSH
);
1032 ch
->ch_obuf_size
= 0;
1038 * RX interrupt routine
1041 clmpcc_rxintr(void *arg
)
1043 struct clmpcc_softc
*sc
= (struct clmpcc_softc
*)arg
;
1044 struct clmpcc_chan
*ch
;
1045 u_int8_t
*put
, *end
, rxd
;
1054 /* Receive interrupt active? */
1055 rir
= clmpcc_rdreg(sc
, CLMPCC_REG_RIR
);
1058 * If we're using auto-vectored interrupts, we have to
1059 * verify if the chip is generating the interrupt.
1061 if ( sc
->sc_vector_base
== 0 && (rir
& CLMPCC_RIR_RACT
) == 0 )
1064 /* Get pointer to interrupting channel's data structure */
1065 ch
= &sc
->sc_chans
[rir
& CLMPCC_RIR_RCN_MASK
];
1067 /* Get the interrupt status register */
1068 risr
= clmpcc_rdreg(sc
, CLMPCC_REG_RISRl
);
1069 if ( risr
& CLMPCC_RISR_TIMEOUT
) {
1072 * Set the FIFO threshold to zero, and disable
1073 * further receive timeout interrupts.
1075 reg
= clmpcc_rdreg(sc
, CLMPCC_REG_COR4
);
1076 clmpcc_wrreg(sc
, CLMPCC_REG_COR4
, reg
& ~CLMPCC_COR4_FIFO_MASK
);
1077 reg
= clmpcc_rdreg(sc
, CLMPCC_REG_IER
);
1078 clmpcc_wrreg(sc
, CLMPCC_REG_IER
, reg
& ~CLMPCC_IER_RET
);
1079 clmpcc_wrreg(sc
, CLMPCC_REG_REOIR
, CLMPCC_REOIR_NO_TRANS
);
1080 SET(ch
->ch_flags
, CLMPCC_FLG_FIFO_CLEAR
);
1084 /* How many bytes are waiting in the FIFO? */
1085 fc
= tc
= clmpcc_rdreg(sc
, CLMPCC_REG_RFOC
) & CLMPCC_RFOC_MASK
;
1089 * Allow BREAK on the console to drop to the debugger.
1091 if ( ISSET(ch
->ch_flags
, CLMPCC_FLG_IS_CONSOLE
) &&
1092 risr
& CLMPCC_RISR_BREAK
) {
1097 if ( ISCLR(ch
->ch_tty
->t_state
, TS_ISOPEN
) && fc
) {
1098 /* Just get rid of the data */
1100 (void) clmpcc_rd_rxdata(sc
);
1104 put
= ch
->ch_ibuf_wr
;
1105 end
= ch
->ch_ibuf_end
;
1108 * Note: The chip is completely hosed WRT these error
1109 * conditions; there seems to be no way to associate
1110 * the error with the correct character in the FIFO.
1111 * We compromise by tagging the first character we read
1112 * with the error. Not perfect, but there's no other way.
1115 if ( risr
& CLMPCC_RISR_PARITY
)
1117 if ( risr
& (CLMPCC_RISR_FRAMING
| CLMPCC_RISR_BREAK
) )
1121 * As long as there are characters in the FIFO, and we
1122 * have space for them...
1126 *put
++ = rxd
= clmpcc_rd_rxdata(sc
);
1132 if ( put
== ch
->ch_ibuf_rd
) {
1134 if ( put
< ch
->ch_ibuf
)
1142 ch
->ch_ibuf_wr
= put
;
1145 if ( sc
->sc_swaprtsdtr
== 0 &&
1146 ISSET(cy
->cy_tty
->t_cflag
, CRTSCTS
) && cc
< ch
->ch_r_hiwat
) {
1148 * If RTS/DTR are not physically swapped, we have to
1149 * do hardware flow control manually
1151 clmpcc_wr_msvr(sc
, CLMPCC_MSVR_RTS
, 0);
1157 if ( ISSET(ch
->ch_flags
, CLMPCC_FLG_FIFO_CLEAR
) ) {
1160 * Set the FIFO threshold to the preset value,
1161 * and enable receive timeout interrupts.
1163 reg
= clmpcc_rdreg(sc
, CLMPCC_REG_COR4
);
1164 reg
= (reg
& ~CLMPCC_COR4_FIFO_MASK
) | ch
->ch_cor4
;
1165 clmpcc_wrreg(sc
, CLMPCC_REG_COR4
, reg
);
1166 reg
= clmpcc_rdreg(sc
, CLMPCC_REG_IER
);
1167 clmpcc_wrreg(sc
, CLMPCC_REG_IER
, reg
| CLMPCC_IER_RET
);
1168 CLR(ch
->ch_flags
, CLMPCC_FLG_FIFO_CLEAR
);
1171 clmpcc_wrreg(sc
, CLMPCC_REG_REOIR
, 0);
1172 softint_schedule(sc
->sc_softintr_cookie
);
1174 clmpcc_wrreg(sc
, CLMPCC_REG_REOIR
, CLMPCC_REOIR_NO_TRANS
);
1178 * Only =after= we write REOIR is it safe to drop to the debugger.
1188 * Tx interrupt routine
1191 clmpcc_txintr(void *arg
)
1193 struct clmpcc_softc
*sc
= (struct clmpcc_softc
*)arg
;
1194 struct clmpcc_chan
*ch
;
1200 /* Tx interrupt active? */
1201 tir
= clmpcc_rdreg(sc
, CLMPCC_REG_TIR
);
1204 * If we're using auto-vectored interrupts, we have to
1205 * verify if the chip is generating the interrupt.
1207 if ( sc
->sc_vector_base
== 0 && (tir
& CLMPCC_TIR_TACT
) == 0 )
1210 /* Get pointer to interrupting channel's data structure */
1211 ch
= &sc
->sc_chans
[tir
& CLMPCC_TIR_TCN_MASK
];
1214 /* Dummy read of the interrupt status register */
1215 (void) clmpcc_rdreg(sc
, CLMPCC_REG_TISR
);
1217 /* Make sure embedded transmit commands are disabled */
1218 clmpcc_wrreg(sc
, CLMPCC_REG_COR2
, ch
->ch_cor2
);
1220 ftc
= oftc
= clmpcc_rdreg(sc
, CLMPCC_REG_TFTC
);
1222 /* Handle a delayed parameter change */
1223 if ( ISSET(ch
->ch_flags
, CLMPCC_FLG_UPDATE_PARMS
) ) {
1224 CLR(ch
->ch_flags
, CLMPCC_FLG_UPDATE_PARMS
);
1225 clmpcc_set_params(ch
);
1228 if ( ch
->ch_obuf_size
> 0 ) {
1229 u_int n
= min(ch
->ch_obuf_size
, ftc
);
1231 clmpcc_wrtx_multi(sc
, ch
->ch_obuf_addr
, n
);
1234 ch
->ch_obuf_size
-= n
;
1235 ch
->ch_obuf_addr
+= n
;
1239 * Check if we should start/stop a break
1241 if ( ISSET(ch
->ch_flags
, CLMPCC_FLG_START_BREAK
) ) {
1242 CLR(ch
->ch_flags
, CLMPCC_FLG_START_BREAK
);
1243 /* Enable embedded transmit commands */
1244 clmpcc_wrreg(sc
, CLMPCC_REG_COR2
,
1245 ch
->ch_cor2
| CLMPCC_COR2_ETC
);
1246 clmpcc_wr_txdata(sc
, CLMPCC_ETC_MAGIC
);
1247 clmpcc_wr_txdata(sc
, CLMPCC_ETC_SEND_BREAK
);
1252 if ( ISSET(ch
->ch_flags
, CLMPCC_FLG_END_BREAK
) ) {
1253 CLR(ch
->ch_flags
, CLMPCC_FLG_END_BREAK
);
1254 /* Enable embedded transmit commands */
1255 clmpcc_wrreg(sc
, CLMPCC_REG_COR2
,
1256 ch
->ch_cor2
| CLMPCC_COR2_ETC
);
1257 clmpcc_wr_txdata(sc
, CLMPCC_ETC_MAGIC
);
1258 clmpcc_wr_txdata(sc
, CLMPCC_ETC_STOP_BREAK
);
1264 tir
= clmpcc_rdreg(sc
, CLMPCC_REG_IER
);
1266 if ( ftc
!= oftc
) {
1268 * Enable/disable the Tx FIFO threshold interrupt
1269 * according to how much data is in the FIFO.
1270 * However, always disable the FIFO threshold if
1271 * we've left the channel in 'Embedded Transmit
1274 if ( etcmode
|| ftc
>= ch
->ch_cor4
)
1275 tir
&= ~CLMPCC_IER_TX_FIFO
;
1277 tir
|= CLMPCC_IER_TX_FIFO
;
1282 * Disable transmit interrupt.
1284 tir
&= ~(CLMPCC_IER_TX_EMPTY
|CLMPCC_IER_TX_FIFO
);
1285 teoir
= CLMPCC_TEOIR_NO_TRANS
;
1288 * Request Tx processing in the soft interrupt handler
1291 softint_schedule(sc
->sc_softintr_cookie
);
1294 clmpcc_wrreg(sc
, CLMPCC_REG_IER
, tir
);
1295 clmpcc_wrreg(sc
, CLMPCC_REG_TEOIR
, teoir
);
1301 * Modem change interrupt routine
1304 clmpcc_mdintr(void *arg
)
1306 struct clmpcc_softc
*sc
= (struct clmpcc_softc
*)arg
;
1309 /* Modem status interrupt active? */
1310 mir
= clmpcc_rdreg(sc
, CLMPCC_REG_MIR
);
1313 * If we're using auto-vectored interrupts, we have to
1314 * verify if the chip is generating the interrupt.
1316 if ( sc
->sc_vector_base
== 0 && (mir
& CLMPCC_MIR_MACT
) == 0 )
1319 /* Dummy read of the interrupt status register */
1320 (void) clmpcc_rdreg(sc
, CLMPCC_REG_MISR
);
1322 /* Retrieve current status of modem lines. */
1323 sc
->sc_chans
[mir
& CLMPCC_MIR_MCN_MASK
].ch_control
|=
1324 clmpcc_rd_msvr(sc
) & CLMPCC_MSVR_CD
;
1326 clmpcc_wrreg(sc
, CLMPCC_REG_MEOIR
, 0);
1327 softint_schedule(sc
->sc_softintr_cookie
);
1333 clmpcc_softintr(void *arg
)
1335 struct clmpcc_softc
*sc
= (struct clmpcc_softc
*)arg
;
1336 struct clmpcc_chan
*ch
;
1338 int (*rint
)(int, struct tty
*);
1344 /* Handle Modem state changes too... */
1346 for (chan
= 0; chan
< CLMPCC_NUM_CHANS
; chan
++) {
1347 ch
= &sc
->sc_chans
[chan
];
1350 get
= ch
->ch_ibuf_rd
;
1351 rint
= tp
->t_linesw
->l_rint
;
1353 /* Squirt buffered incoming data into the tty layer */
1354 while ( get
!= ch
->ch_ibuf_wr
) {
1356 c
|= ((u_int
)get
[1]) << 8;
1357 if ( (rint
)(c
, tp
) == -1 ) {
1358 ch
->ch_ibuf_rd
= ch
->ch_ibuf_wr
;
1363 if ( get
== ch
->ch_ibuf_end
)
1366 ch
->ch_ibuf_rd
= get
;
1370 * Is the transmitter idle and in need of attention?
1372 if ( ch
->ch_tx_done
) {
1375 if ( ISSET(ch
->ch_flags
, CLMPCC_FLG_NEED_INIT
) ) {
1376 clmpcc_channel_cmd(sc
, ch
->ch_car
,
1377 CLMPCC_CCR_T0_INIT
|
1378 CLMPCC_CCR_T0_RX_EN
|
1379 CLMPCC_CCR_T0_TX_EN
);
1380 CLR(ch
->ch_flags
, CLMPCC_FLG_NEED_INIT
);
1383 * Allow time for the channel to initialise.
1384 * (Empirically derived duration; there must
1385 * be another way to determine the command
1386 * has completed without busy-waiting...)
1391 * Update the tty layer's idea of the carrier
1392 * bit, in case we changed CLOCAL or MDMBUF.
1393 * We don't hang up here; we only do that by
1396 reg
= clmpcc_rd_msvr(sc
) & CLMPCC_MSVR_CD
;
1397 (*tp
->t_linesw
->l_modem
)(tp
, reg
!= 0);
1400 CLR(tp
->t_state
, TS_BUSY
);
1401 if ( ISSET(tp
->t_state
, TS_FLUSH
) )
1402 CLR(tp
->t_state
, TS_FLUSH
);
1404 ndflush(&tp
->t_outq
,
1405 (int)(ch
->ch_obuf_addr
- tp
->t_outq
.c_cf
));
1407 (*tp
->t_linesw
->l_start
)(tp
);
1413 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
1414 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
1415 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
1417 * Following are all routines needed for a cd240x channel to act as console
1420 clmpcc_cnattach(struct clmpcc_softc
*sc
, int chan
, int rate
)
1426 return (clmpcc_init(sc
));
1430 * The following functions are polled getc and putc routines, for console use.
1433 clmpcc_common_getc(struct clmpcc_softc
*sc
, int chan
)
1437 u_char ch
, rir
, risr
;
1442 /* Save the currently active channel */
1443 old_chan
= clmpcc_select_channel(sc
, chan
);
1446 * We have to put the channel into RX interrupt mode before
1447 * trying to read the Rx data register. So save the previous
1450 old_ier
= clmpcc_rdreg(sc
, CLMPCC_REG_IER
);
1451 clmpcc_wrreg(sc
, CLMPCC_REG_IER
, CLMPCC_IER_RX_FIFO
);
1453 /* Loop until we get a character */
1456 * The REN bit will be set in the Receive Interrupt Register
1457 * when the CD240x has a character to process. Remember,
1458 * the RACT bit won't be set until we generate an interrupt
1459 * acknowledge cycle via the MD front-end.
1461 rir
= clmpcc_rdreg(sc
, CLMPCC_REG_RIR
);
1462 if ( (rir
& CLMPCC_RIR_REN
) == 0 )
1465 /* Acknowledge the request */
1466 if ( sc
->sc_iackhook
)
1467 (sc
->sc_iackhook
)(sc
, CLMPCC_IACK_RX
);
1470 * Determine if the interrupt is for the required channel
1471 * and if valid data is available.
1473 rir
= clmpcc_rdreg(sc
, CLMPCC_REG_RIR
);
1474 risr
= clmpcc_rdreg(sc
, CLMPCC_REG_RISR
);
1475 if ( (rir
& CLMPCC_RIR_RCN_MASK
) != chan
||
1477 /* Rx error, or BREAK */
1478 clmpcc_wrreg(sc
, CLMPCC_REG_REOIR
,
1479 CLMPCC_REOIR_NO_TRANS
);
1481 /* Dummy read of the FIFO count register */
1482 (void) clmpcc_rdreg(sc
, CLMPCC_REG_RFOC
);
1484 /* Fetch the received character */
1485 ch
= clmpcc_rd_rxdata(sc
);
1487 clmpcc_wrreg(sc
, CLMPCC_REG_REOIR
, 0);
1492 /* Restore the original IER and CAR register contents */
1493 clmpcc_wrreg(sc
, CLMPCC_REG_IER
, old_ier
);
1494 clmpcc_select_channel(sc
, old_chan
);
1502 clmpcc_common_putc(struct clmpcc_softc
*sc
, int chan
, int c
)
1507 /* Save the currently active channel */
1508 old_chan
= clmpcc_select_channel(sc
, chan
);
1511 * Since we can only access the Tx Data register from within
1512 * the interrupt handler, the easiest way to get console data
1513 * onto the wire is using one of the Special Transmit Character
1516 clmpcc_wrreg(sc
, CLMPCC_REG_SCHR4
, c
);
1517 clmpcc_wrreg(sc
, CLMPCC_REG_STCR
, CLMPCC_STCR_SSPC(4) |
1518 CLMPCC_STCR_SND_SPC
);
1520 /* Wait until the "Send Special Character" command is accepted */
1521 while ( clmpcc_rdreg(sc
, CLMPCC_REG_STCR
) != 0 )
1524 /* Restore the previous channel selected */
1525 clmpcc_select_channel(sc
, old_chan
);
1531 clmpcccngetc(dev_t dev
)
1533 return clmpcc_common_getc(cons_sc
, cons_chan
);
1537 * Console kernel output character routine.
1540 clmpcccnputc(dev_t dev
, int c
)
1543 clmpcc_common_putc(cons_sc
, cons_chan
, '\r');
1545 clmpcc_common_putc(cons_sc
, cons_chan
, c
);