| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ser.c,v 1.42 2009/03/14 21:04:06 dsl Exp $ */ | | 1 | /* $NetBSD: ser.c,v 1.43 2009/07/03 17:05:54 tsutsui Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1997 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1997 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Leo Weppelman. | | 8 | * by Leo Weppelman. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -83,27 +83,27 @@ | | | @@ -83,27 +83,27 @@ |
83 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 83 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
84 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 84 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
85 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 85 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
86 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 86 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
87 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 87 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
88 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 88 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
89 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 89 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
90 | * SUCH DAMAGE. | | 90 | * SUCH DAMAGE. |
91 | * | | 91 | * |
92 | * @(#)com.c 7.5 (Berkeley) 5/16/91 | | 92 | * @(#)com.c 7.5 (Berkeley) 5/16/91 |
93 | */ | | 93 | */ |
94 | | | 94 | |
95 | #include <sys/cdefs.h> | | 95 | #include <sys/cdefs.h> |
96 | __KERNEL_RCSID(0, "$NetBSD: ser.c,v 1.42 2009/03/14 21:04:06 dsl Exp $"); | | 96 | __KERNEL_RCSID(0, "$NetBSD: ser.c,v 1.43 2009/07/03 17:05:54 tsutsui Exp $"); |
97 | | | 97 | |
98 | #include "opt_ddb.h" | | 98 | #include "opt_ddb.h" |
99 | #include "opt_mbtype.h" | | 99 | #include "opt_mbtype.h" |
100 | #include "opt_serconsole.h" | | 100 | #include "opt_serconsole.h" |
101 | | | 101 | |
102 | #include <sys/param.h> | | 102 | #include <sys/param.h> |
103 | #include <sys/systm.h> | | 103 | #include <sys/systm.h> |
104 | #include <sys/ioctl.h> | | 104 | #include <sys/ioctl.h> |
105 | #include <sys/select.h> | | 105 | #include <sys/select.h> |
106 | #include <sys/tty.h> | | 106 | #include <sys/tty.h> |
107 | #include <sys/proc.h> | | 107 | #include <sys/proc.h> |
108 | #include <sys/user.h> | | 108 | #include <sys/user.h> |
109 | #include <sys/conf.h> | | 109 | #include <sys/conf.h> |
| @@ -190,26 +190,28 @@ struct ser_softc { | | | @@ -190,26 +190,28 @@ struct ser_softc { |
190 | | | 190 | |
191 | volatile u_char sc_rx_blocked; | | 191 | volatile u_char sc_rx_blocked; |
192 | volatile u_char sc_rx_ready; | | 192 | volatile u_char sc_rx_ready; |
193 | volatile u_char sc_tx_busy; | | 193 | volatile u_char sc_tx_busy; |
194 | volatile u_char sc_tx_done; | | 194 | volatile u_char sc_tx_done; |
195 | volatile u_char sc_tx_stopped; | | 195 | volatile u_char sc_tx_stopped; |
196 | volatile u_char sc_st_check; | | 196 | volatile u_char sc_st_check; |
197 | | | 197 | |
198 | u_char *sc_tba; | | 198 | u_char *sc_tba; |
199 | int sc_tbc; | | 199 | int sc_tbc; |
200 | int sc_heldtbc; | | 200 | int sc_heldtbc; |
201 | | | 201 | |
202 | volatile u_char sc_heldchange; | | 202 | volatile u_char sc_heldchange; |
| | | 203 | |
| | | 204 | void *sc_sicookie; |
203 | }; | | 205 | }; |
204 | | | 206 | |
205 | /* | | 207 | /* |
206 | * For sc_hwflags: | | 208 | * For sc_hwflags: |
207 | */ | | 209 | */ |
208 | #define SER_HW_CONSOLE 0x01 | | 210 | #define SER_HW_CONSOLE 0x01 |
209 | | | 211 | |
210 | void ser_break(struct ser_softc *, int); | | 212 | void ser_break(struct ser_softc *, int); |
211 | void ser_hwiflow(struct ser_softc *, int); | | 213 | void ser_hwiflow(struct ser_softc *, int); |
212 | void ser_iflush(struct ser_softc *); | | 214 | void ser_iflush(struct ser_softc *); |
213 | void ser_loadchannelregs(struct ser_softc *); | | 215 | void ser_loadchannelregs(struct ser_softc *); |
214 | void ser_modem(struct ser_softc *, int); | | 216 | void ser_modem(struct ser_softc *, int); |
215 | void serdiag(void *); | | 217 | void serdiag(void *); |
| @@ -225,28 +227,26 @@ struct consdev; | | | @@ -225,28 +227,26 @@ struct consdev; |
225 | void sercnprobe(struct consdev *); | | 227 | void sercnprobe(struct consdev *); |
226 | void sercninit(struct consdev *); | | 228 | void sercninit(struct consdev *); |
227 | int sercngetc(dev_t); | | 229 | int sercngetc(dev_t); |
228 | void sercnputc(dev_t, int); | | 230 | void sercnputc(dev_t, int); |
229 | void sercnpollc(dev_t, int); | | 231 | void sercnpollc(dev_t, int); |
230 | | | 232 | |
231 | static void sermsrint(struct ser_softc *, struct tty*); | | 233 | static void sermsrint(struct ser_softc *, struct tty*); |
232 | static void serrxint(struct ser_softc *, struct tty*); | | 234 | static void serrxint(struct ser_softc *, struct tty*); |
233 | static void ser_shutdown(struct ser_softc *); | | 235 | static void ser_shutdown(struct ser_softc *); |
234 | static int serspeed(long); | | 236 | static int serspeed(long); |
235 | static void sersoft(void *); | | 237 | static void sersoft(void *); |
236 | static void sertxint(struct ser_softc *, struct tty*); | | 238 | static void sertxint(struct ser_softc *, struct tty*); |
237 | | | 239 | |
238 | static volatile int ser_softintr_scheduled = 0; | | | |
239 | | | | |
240 | /* | | 240 | /* |
241 | * Autoconfig stuff | | 241 | * Autoconfig stuff |
242 | */ | | 242 | */ |
243 | static void serattach(struct device *, struct device *, void *); | | 243 | static void serattach(struct device *, struct device *, void *); |
244 | static int sermatch(struct device *, struct cfdata *, void *); | | 244 | static int sermatch(struct device *, struct cfdata *, void *); |
245 | | | 245 | |
246 | CFATTACH_DECL(ser, sizeof(struct ser_softc), | | 246 | CFATTACH_DECL(ser, sizeof(struct ser_softc), |
247 | sermatch, serattach, NULL, NULL); | | 247 | sermatch, serattach, NULL, NULL); |
248 | | | 248 | |
249 | extern struct cfdriver ser_cd; | | 249 | extern struct cfdriver ser_cd; |
250 | | | 250 | |
251 | dev_type_open(seropen); | | 251 | dev_type_open(seropen); |
252 | dev_type_close(serclose); | | 252 | dev_type_close(serclose); |
| @@ -287,26 +287,28 @@ serattach(struct device *pdp, struct dev | | | @@ -287,26 +287,28 @@ serattach(struct device *pdp, struct dev |
287 | if (intr_establish(2, USER_VEC, 0, (hw_ifun_t)sermintr, sc) == NULL) | | 287 | if (intr_establish(2, USER_VEC, 0, (hw_ifun_t)sermintr, sc) == NULL) |
288 | printf("serattach: Can't establish interrupt (2)\n"); | | 288 | printf("serattach: Can't establish interrupt (2)\n"); |
289 | if (intr_establish(14, USER_VEC, 0, (hw_ifun_t)sermintr, sc) == NULL) | | 289 | if (intr_establish(14, USER_VEC, 0, (hw_ifun_t)sermintr, sc) == NULL) |
290 | printf("serattach: Can't establish interrupt (14)\n"); | | 290 | printf("serattach: Can't establish interrupt (14)\n"); |
291 | if (intr_establish(9, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) | | 291 | if (intr_establish(9, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) |
292 | printf("serattach: Can't establish interrupt (9)\n"); | | 292 | printf("serattach: Can't establish interrupt (9)\n"); |
293 | if (intr_establish(10, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) | | 293 | if (intr_establish(10, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) |
294 | printf("serattach: Can't establish interrupt (10)\n"); | | 294 | printf("serattach: Can't establish interrupt (10)\n"); |
295 | if (intr_establish(11, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) | | 295 | if (intr_establish(11, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) |
296 | printf("serattach: Can't establish interrupt (11)\n"); | | 296 | printf("serattach: Can't establish interrupt (11)\n"); |
297 | if (intr_establish(12, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) | | 297 | if (intr_establish(12, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) |
298 | printf("serattach: Can't establish interrupt (12)\n"); | | 298 | printf("serattach: Can't establish interrupt (12)\n"); |
299 | | | 299 | |
| | | 300 | sc->sc_sicookie = softint_establish(SOFTINT_SERIAL, sersoft, sc); |
| | | 301 | |
300 | ym2149_rts(1); | | 302 | ym2149_rts(1); |
301 | ym2149_dtr(1); | | 303 | ym2149_dtr(1); |
302 | | | 304 | |
303 | /* | | 305 | /* |
304 | * Enable but mask interrupts... | | 306 | * Enable but mask interrupts... |
305 | * XXX: Look at edge-sensitivity for DCD/CTS interrupts. | | 307 | * XXX: Look at edge-sensitivity for DCD/CTS interrupts. |
306 | */ | | 308 | */ |
307 | MFP->mf_ierb |= IB_SCTS|IB_SDCD; | | 309 | MFP->mf_ierb |= IB_SCTS|IB_SDCD; |
308 | MFP->mf_iera |= IA_RRDY|IA_RERR|IA_TRDY|IA_TERR; | | 310 | MFP->mf_iera |= IA_RRDY|IA_RERR|IA_TRDY|IA_TERR; |
309 | MFP->mf_imrb &= ~(IB_SCTS|IB_SDCD); | | 311 | MFP->mf_imrb &= ~(IB_SCTS|IB_SDCD); |
310 | MFP->mf_imra &= ~(IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); | | 312 | MFP->mf_imra &= ~(IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); |
311 | | | 313 | |
312 | callout_init(&sc->sc_diag_ch, 0); | | 314 | callout_init(&sc->sc_diag_ch, 0); |
| @@ -1142,28 +1144,26 @@ sermsrint(struct ser_softc *sc, struct t | | | @@ -1142,28 +1144,26 @@ sermsrint(struct ser_softc *sc, struct t |
1142 | } | | 1144 | } |
1143 | | | 1145 | |
1144 | #ifdef SER_DEBUG | | 1146 | #ifdef SER_DEBUG |
1145 | serstatus(sc, "sermsrint"); | | 1147 | serstatus(sc, "sermsrint"); |
1146 | #endif | | 1148 | #endif |
1147 | } | | 1149 | } |
1148 | | | 1150 | |
1149 | void | | 1151 | void |
1150 | sersoft(void *arg) | | 1152 | sersoft(void *arg) |
1151 | { | | 1153 | { |
1152 | struct ser_softc *sc = arg; | | 1154 | struct ser_softc *sc = arg; |
1153 | struct tty *tp; | | 1155 | struct tty *tp; |
1154 | | | 1156 | |
1155 | ser_softintr_scheduled = 0; | | | |
1156 | | | | |
1157 | tp = sc->sc_tty; | | 1157 | tp = sc->sc_tty; |
1158 | if (tp == NULL) | | 1158 | if (tp == NULL) |
1159 | return; | | 1159 | return; |
1160 | | | 1160 | |
1161 | if (!ISSET(tp->t_state, TS_ISOPEN) && (tp->t_wopen == 0)) | | 1161 | if (!ISSET(tp->t_state, TS_ISOPEN) && (tp->t_wopen == 0)) |
1162 | return; | | 1162 | return; |
1163 | | | 1163 | |
1164 | if (sc->sc_rx_ready) { | | 1164 | if (sc->sc_rx_ready) { |
1165 | sc->sc_rx_ready = 0; | | 1165 | sc->sc_rx_ready = 0; |
1166 | serrxint(sc, tp); | | 1166 | serrxint(sc, tp); |
1167 | } | | 1167 | } |
1168 | | | 1168 | |
1169 | if (sc->sc_st_check) { | | 1169 | if (sc->sc_st_check) { |
| @@ -1195,28 +1195,27 @@ sermintr(void *arg) | | | @@ -1195,28 +1195,27 @@ sermintr(void *arg) |
1195 | * Stop output immediately if we lose the output | | 1195 | * Stop output immediately if we lose the output |
1196 | * flow control signal or carrier detect. | | 1196 | * flow control signal or carrier detect. |
1197 | */ | | 1197 | */ |
1198 | if (ISSET(~msr, sc->sc_msr_mask)) { | | 1198 | if (ISSET(~msr, sc->sc_msr_mask)) { |
1199 | sc->sc_tbc = 0; | | 1199 | sc->sc_tbc = 0; |
1200 | sc->sc_heldtbc = 0; | | 1200 | sc->sc_heldtbc = 0; |
1201 | #ifdef SER_DEBUG | | 1201 | #ifdef SER_DEBUG |
1202 | serstatus(sc, "sermintr "); | | 1202 | serstatus(sc, "sermintr "); |
1203 | #endif | | 1203 | #endif |
1204 | } | | 1204 | } |
1205 | | | 1205 | |
1206 | sc->sc_st_check = 1; | | 1206 | sc->sc_st_check = 1; |
1207 | } | | 1207 | } |
1208 | if (!ser_softintr_scheduled) | | 1208 | softint_schedule(sc->sc_sicookie); |
1209 | add_sicallback((si_farg)sersoft, sc, 0); | | | |
1210 | return 1; | | 1209 | return 1; |
1211 | } | | 1210 | } |
1212 | | | 1211 | |
1213 | int | | 1212 | int |
1214 | sertrintr(void *arg) | | 1213 | sertrintr(void *arg) |
1215 | { | | 1214 | { |
1216 | struct ser_softc *sc = arg; | | 1215 | struct ser_softc *sc = arg; |
1217 | u_int put, cc; | | 1216 | u_int put, cc; |
1218 | u_char rsr, tsr; | | 1217 | u_char rsr, tsr; |
1219 | | | 1218 | |
1220 | put = sc->sc_rbput; | | 1219 | put = sc->sc_rbput; |
1221 | cc = sc->sc_rbavail; | | 1220 | cc = sc->sc_rbavail; |
1222 | | | 1221 | |
| @@ -1276,29 +1275,27 @@ sertrintr(void *arg) | | | @@ -1276,29 +1275,27 @@ sertrintr(void *arg) |
1276 | sc->sc_tbc = sc->sc_heldtbc; | | 1275 | sc->sc_tbc = sc->sc_heldtbc; |
1277 | sc->sc_heldtbc = 0; | | 1276 | sc->sc_heldtbc = 0; |
1278 | } | | 1277 | } |
1279 | /* Output the next character, if any. */ | | 1278 | /* Output the next character, if any. */ |
1280 | if (sc->sc_tbc > 0) { | | 1279 | if (sc->sc_tbc > 0) { |
1281 | MFP->mf_udr = *sc->sc_tba; | | 1280 | MFP->mf_udr = *sc->sc_tba; |
1282 | sc->sc_tbc--; | | 1281 | sc->sc_tbc--; |
1283 | sc->sc_tba++; | | 1282 | sc->sc_tba++; |
1284 | } else if (sc->sc_tx_busy) { | | 1283 | } else if (sc->sc_tx_busy) { |
1285 | sc->sc_tx_busy = 0; | | 1284 | sc->sc_tx_busy = 0; |
1286 | sc->sc_tx_done = 1; | | 1285 | sc->sc_tx_done = 1; |
1287 | } | | 1286 | } |
1288 | } | | 1287 | } |
1289 | | | 1288 | softint_schedule(sc->sc_sicookie); |
1290 | if (!ser_softintr_scheduled) | | | |
1291 | add_sicallback((si_farg)sersoft, sc, 0); | | | |
1292 | return 1; | | 1289 | return 1; |
1293 | } | | 1290 | } |
1294 | | | 1291 | |
1295 | static int | | 1292 | static int |
1296 | serspeed(long speed) | | 1293 | serspeed(long speed) |
1297 | { | | 1294 | { |
1298 | #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ | | 1295 | #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ |
1299 | | | 1296 | |
1300 | int div, x, err; | | 1297 | int div, x, err; |
1301 | | | 1298 | |
1302 | if (speed <= 0) | | 1299 | if (speed <= 0) |
1303 | return (-1); | | 1300 | return (-1); |
1304 | | | 1301 | |