xref: /freebsd/sys/dev/usb/serial/usb_serial.c (revision 36a80f4264350a2f4f0686eb91ae7f5943d40327)
1 /*	$NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2001-2003, 2005, 2008
7  *	Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 /*-
34  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
35  * All rights reserved.
36  *
37  * This code is derived from software contributed to The NetBSD Foundation
38  * by Lennart Augustsson (lennart@augustsson.net) at
39  * Carlstedt Research & Technology.
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  *
50  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60  * POSSIBILITY OF SUCH DAMAGE.
61  */
62 
63 #include <sys/stdint.h>
64 #include <sys/stddef.h>
65 #include <sys/param.h>
66 #include <sys/queue.h>
67 #include <sys/types.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/bus.h>
71 #include <sys/module.h>
72 #include <sys/lock.h>
73 #include <sys/mutex.h>
74 #include <sys/condvar.h>
75 #include <sys/sysctl.h>
76 #include <sys/sx.h>
77 #include <sys/unistd.h>
78 #include <sys/callout.h>
79 #include <sys/malloc.h>
80 #include <sys/priv.h>
81 #include <sys/cons.h>
82 
83 #include <dev/uart/uart_ppstypes.h>
84 
85 #include <dev/usb/usb.h>
86 #include <dev/usb/usbdi.h>
87 #include <dev/usb/usbdi_util.h>
88 
89 #define	USB_DEBUG_VAR ucom_debug
90 #include <dev/usb/usb_debug.h>
91 #include <dev/usb/usb_busdma.h>
92 #include <dev/usb/usb_process.h>
93 
94 #include <dev/usb/serial/usb_serial.h>
95 
96 #include "opt_gdb.h"
97 
98 static SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
99     "USB ucom");
100 
101 static int ucom_pps_mode;
102 
103 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, pps_mode, CTLFLAG_RWTUN,
104     &ucom_pps_mode, 0,
105     "pulse capture mode: 0/1/2=disabled/CTS/DCD; add 0x10 to invert");
106 
107 static int ucom_device_mode_console = 1;
108 
109 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, device_mode_console, CTLFLAG_RW,
110     &ucom_device_mode_console, 0,
111     "set to 1 to mark terminals as consoles when in device mode");
112 
113 #ifdef USB_DEBUG
114 static int ucom_debug = 0;
115 
116 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RWTUN,
117     &ucom_debug, 0, "ucom debug level");
118 #endif
119 
120 #define	UCOM_CONS_BUFSIZE 1024
121 
122 static uint8_t ucom_cons_rx_buf[UCOM_CONS_BUFSIZE];
123 static uint8_t ucom_cons_tx_buf[UCOM_CONS_BUFSIZE];
124 
125 static unsigned ucom_cons_rx_low = 0;
126 static unsigned ucom_cons_rx_high = 0;
127 
128 static unsigned ucom_cons_tx_low = 0;
129 static unsigned ucom_cons_tx_high = 0;
130 
131 static int ucom_cons_unit = -1;
132 static int ucom_cons_subunit = 0;
133 static int ucom_cons_baud = 115200;
134 static struct ucom_softc *ucom_cons_softc = NULL;
135 
136 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RWTUN,
137     &ucom_cons_unit, 0, "console unit number");
138 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RWTUN,
139     &ucom_cons_subunit, 0, "console subunit number");
140 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RWTUN,
141     &ucom_cons_baud, 0, "console baud rate");
142 
143 static usb_proc_callback_t ucom_cfg_start_transfers;
144 static usb_proc_callback_t ucom_cfg_open;
145 static usb_proc_callback_t ucom_cfg_close;
146 static usb_proc_callback_t ucom_cfg_line_state;
147 static usb_proc_callback_t ucom_cfg_status_change;
148 static usb_proc_callback_t ucom_cfg_param;
149 
150 static int	ucom_unit_alloc(void);
151 static void	ucom_unit_free(int);
152 static int	ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *);
153 static void	ucom_detach_tty(struct ucom_super_softc *, struct ucom_softc *);
154 static int	ucom_queue_command(struct ucom_softc *,
155 		    usb_proc_callback_t *, struct termios *pt,
156 		    struct usb_proc_msg *t0, struct usb_proc_msg *t1, bool wait);
157 static void	ucom_shutdown(struct ucom_softc *);
158 static void	ucom_ring(struct ucom_softc *, uint8_t);
159 static void	ucom_break(struct ucom_softc *, uint8_t);
160 static void	ucom_dtr(struct ucom_softc *, uint8_t);
161 static void	ucom_rts(struct ucom_softc *, uint8_t);
162 
163 static tsw_open_t ucom_open;
164 static tsw_close_t ucom_close;
165 static tsw_ioctl_t ucom_ioctl;
166 static tsw_modem_t ucom_modem;
167 static tsw_param_t ucom_param;
168 static tsw_outwakeup_t ucom_outwakeup;
169 static tsw_inwakeup_t ucom_inwakeup;
170 static tsw_free_t ucom_free;
171 static tsw_busy_t ucom_busy;
172 
173 static struct ttydevsw ucom_class = {
174 	.tsw_flags = TF_INITLOCK | TF_CALLOUT,
175 	.tsw_open = ucom_open,
176 	.tsw_close = ucom_close,
177 	.tsw_outwakeup = ucom_outwakeup,
178 	.tsw_inwakeup = ucom_inwakeup,
179 	.tsw_ioctl = ucom_ioctl,
180 	.tsw_param = ucom_param,
181 	.tsw_modem = ucom_modem,
182 	.tsw_free = ucom_free,
183 	.tsw_busy = ucom_busy,
184 };
185 
186 MODULE_DEPEND(ucom, usb, 1, 1, 1);
187 MODULE_VERSION(ucom, 1);
188 
189 #define	UCOM_UNIT_MAX 		128	/* maximum number of units */
190 #define	UCOM_TTY_PREFIX		"U"
191 
192 static struct unrhdr *ucom_unrhdr;
193 static struct mtx ucom_mtx;
194 static int ucom_close_refs;
195 
196 static void
ucom_init(void * arg)197 ucom_init(void *arg)
198 {
199 	DPRINTF("\n");
200 	ucom_unrhdr = new_unrhdr(0, UCOM_UNIT_MAX - 1, NULL);
201 	mtx_init(&ucom_mtx, "UCOM MTX", NULL, MTX_DEF);
202 }
203 SYSINIT(ucom_init, SI_SUB_KLD - 1, SI_ORDER_ANY, ucom_init, NULL);
204 
205 static void
ucom_uninit(void * arg)206 ucom_uninit(void *arg)
207 {
208 	struct unrhdr *hdr;
209 	hdr = ucom_unrhdr;
210 	ucom_unrhdr = NULL;
211 
212 	DPRINTF("\n");
213 
214 	if (hdr != NULL)
215 		delete_unrhdr(hdr);
216 
217 	mtx_destroy(&ucom_mtx);
218 }
219 SYSUNINIT(ucom_uninit, SI_SUB_KLD - 3, SI_ORDER_ANY, ucom_uninit, NULL);
220 
221 /*
222  * Mark a unit number (the X in cuaUX) as in use.
223  *
224  * Note that devices using a different naming scheme (see ucom_tty_name()
225  * callback) still use this unit allocation.
226  */
227 static int
ucom_unit_alloc(void)228 ucom_unit_alloc(void)
229 {
230 	int unit;
231 
232 	/* sanity checks */
233 	if (ucom_unrhdr == NULL) {
234 		DPRINTF("ucom_unrhdr is NULL\n");
235 		return (-1);
236 	}
237 	unit = alloc_unr(ucom_unrhdr);
238 	DPRINTF("unit %d is allocated\n", unit);
239 	return (unit);
240 }
241 
242 /*
243  * Mark the unit number as not in use.
244  */
245 static void
ucom_unit_free(int unit)246 ucom_unit_free(int unit)
247 {
248 	/* sanity checks */
249 	if (unit < 0 || unit >= UCOM_UNIT_MAX || ucom_unrhdr == NULL) {
250 		DPRINTF("cannot free unit number\n");
251 		return;
252 	}
253 	DPRINTF("unit %d is freed\n", unit);
254 	free_unr(ucom_unrhdr, unit);
255 }
256 
257 /*
258  * Setup a group of one or more serial ports.
259  *
260  * The mutex pointed to by "mtx" is applied before all
261  * callbacks are called back. Also "mtx" must be applied
262  * before calling into the ucom-layer!
263  */
264 int
ucom_attach(struct ucom_super_softc * ssc,struct ucom_softc * sc,int subunits,void * parent,const struct ucom_callback * callback,struct mtx * mtx)265 ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
266     int subunits, void *parent,
267     const struct ucom_callback *callback, struct mtx *mtx)
268 {
269 	int subunit;
270 	int error = 0;
271 
272 	if ((sc == NULL) ||
273 	    (subunits <= 0) ||
274 	    (callback == NULL) ||
275 	    (mtx == NULL)) {
276 		return (EINVAL);
277 	}
278 
279 	/* allocate a uniq unit number */
280 	ssc->sc_unit = ucom_unit_alloc();
281 	if (ssc->sc_unit == -1)
282 		return (ENOMEM);
283 
284 	/* generate TTY name string */
285 	snprintf(ssc->sc_ttyname, sizeof(ssc->sc_ttyname),
286 	    UCOM_TTY_PREFIX "%d", ssc->sc_unit);
287 
288 	/* create USB request handling process */
289 	error = usb_proc_create(&ssc->sc_tq, mtx, "ucom", USB_PRI_MED);
290 	if (error) {
291 		ucom_unit_free(ssc->sc_unit);
292 		return (error);
293 	}
294 	ssc->sc_subunits = subunits;
295 	ssc->sc_flag = UCOM_FLAG_ATTACHED |
296 	    UCOM_FLAG_FREE_UNIT | (ssc->sc_flag & UCOM_FLAG_DEVICE_MODE);
297 
298 	if (callback->ucom_free == NULL)
299 		ssc->sc_flag |= UCOM_FLAG_WAIT_REFS;
300 
301 	/* increment reference count */
302 	ucom_ref(ssc);
303 
304 	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
305 		sc[subunit].sc_subunit = subunit;
306 		sc[subunit].sc_super = ssc;
307 		sc[subunit].sc_mtx = mtx;
308 		sc[subunit].sc_parent = parent;
309 		sc[subunit].sc_callback = callback;
310 
311 		error = ucom_attach_tty(ssc, &sc[subunit]);
312 		if (error) {
313 			ucom_detach(ssc, &sc[0]);
314 			return (error);
315 		}
316 		/* increment reference count */
317 		ucom_ref(ssc);
318 
319 		/* set subunit attached */
320 		sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED;
321 	}
322 
323 	DPRINTF("tp = %p, unit = %d, subunits = %d\n",
324 		sc->sc_tty, ssc->sc_unit, ssc->sc_subunits);
325 
326 	return (0);
327 }
328 
329 /*
330  * The following function will do nothing if the structure pointed to
331  * by "ssc" and "sc" is zero or has already been detached.
332  */
333 void
ucom_detach(struct ucom_super_softc * ssc,struct ucom_softc * sc)334 ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
335 {
336 	int subunit;
337 
338 	if (!(ssc->sc_flag & UCOM_FLAG_ATTACHED))
339 		return;		/* not initialized */
340 
341 	if (ssc->sc_sysctl_ttyname != NULL) {
342 		sysctl_remove_oid(ssc->sc_sysctl_ttyname, 1, 0);
343 		ssc->sc_sysctl_ttyname = NULL;
344 	}
345 
346 	if (ssc->sc_sysctl_ttyports != NULL) {
347 		sysctl_remove_oid(ssc->sc_sysctl_ttyports, 1, 0);
348 		ssc->sc_sysctl_ttyports = NULL;
349 	}
350 
351 	usb_proc_drain(&ssc->sc_tq);
352 
353 	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
354 		if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) {
355 			ucom_detach_tty(ssc, &sc[subunit]);
356 
357 			/* avoid duplicate detach */
358 			sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED;
359 		}
360 	}
361 	usb_proc_free(&ssc->sc_tq);
362 
363 	ucom_unref(ssc);
364 
365 	if (ssc->sc_flag & UCOM_FLAG_WAIT_REFS)
366 		ucom_drain(ssc);
367 
368 	/* make sure we don't detach twice */
369 	ssc->sc_flag &= ~UCOM_FLAG_ATTACHED;
370 }
371 
372 void
ucom_drain(struct ucom_super_softc * ssc)373 ucom_drain(struct ucom_super_softc *ssc)
374 {
375 	mtx_lock(&ucom_mtx);
376 	while (ssc->sc_refs > 0) {
377 		printf("ucom: Waiting for a TTY device to close.\n");
378 		usb_pause_mtx(&ucom_mtx, hz);
379 	}
380 	mtx_unlock(&ucom_mtx);
381 }
382 
383 void
ucom_drain_all(void * arg)384 ucom_drain_all(void *arg)
385 {
386 	mtx_lock(&ucom_mtx);
387 	while (ucom_close_refs > 0) {
388 		printf("ucom: Waiting for all detached TTY "
389 		    "devices to have open fds closed.\n");
390 		usb_pause_mtx(&ucom_mtx, hz);
391 	}
392 	mtx_unlock(&ucom_mtx);
393 }
394 
395 static cn_probe_t ucom_cnprobe;
396 static cn_init_t ucom_cninit;
397 static cn_term_t ucom_cnterm;
398 static cn_getc_t ucom_cngetc;
399 static cn_putc_t ucom_cnputc;
400 static cn_grab_t ucom_cngrab;
401 static cn_ungrab_t ucom_cnungrab;
402 
403 const struct consdev_ops ucom_cnops = {
404         .cn_probe       = ucom_cnprobe,
405         .cn_init        = ucom_cninit,
406         .cn_term        = ucom_cnterm,
407         .cn_getc        = ucom_cngetc,
408         .cn_putc        = ucom_cnputc,
409         .cn_grab        = ucom_cngrab,
410         .cn_ungrab      = ucom_cnungrab,
411 };
412 
413 static int
ucom_attach_tty(struct ucom_super_softc * ssc,struct ucom_softc * sc)414 ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
415 {
416 	struct tty *tp;
417 	char buf[32];			/* temporary TTY device name buffer */
418 
419 	tp = tty_alloc_mutex(&ucom_class, sc, sc->sc_mtx);
420 	if (tp == NULL)
421 		return (ENOMEM);
422 
423 	/* Check if the client has a custom TTY name */
424 	buf[0] = '\0';
425 	if (sc->sc_callback->ucom_tty_name) {
426 		sc->sc_callback->ucom_tty_name(sc, buf,
427 		    sizeof(buf), ssc->sc_unit, sc->sc_subunit);
428 	}
429 	if (buf[0] == 0) {
430 		/* Use default TTY name */
431 		if (ssc->sc_subunits > 1) {
432 			/* multiple modems in one */
433 			snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u.%u",
434 			    ssc->sc_unit, sc->sc_subunit);
435 		} else {
436 			/* single modem */
437 			snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u",
438 			    ssc->sc_unit);
439 		}
440 	}
441 	tty_makedev(tp, NULL, "%s", buf);
442 
443 	sc->sc_tty = tp;
444 
445 	sc->sc_pps.ppscap = PPS_CAPTUREBOTH;
446 	sc->sc_pps.driver_abi = PPS_ABI_VERSION;
447 	sc->sc_pps.driver_mtx = sc->sc_mtx;
448 	pps_init_abi(&sc->sc_pps);
449 
450 	DPRINTF("ttycreate: %s\n", buf);
451 
452 	/* Check if this device should be a console */
453 	if ((ucom_cons_softc == NULL) &&
454 	    (ssc->sc_unit == ucom_cons_unit) &&
455 	    (sc->sc_subunit == ucom_cons_subunit)) {
456 		DPRINTF("unit %d subunit %d is console",
457 		    ssc->sc_unit, sc->sc_subunit);
458 
459 		ucom_cons_softc = sc;
460 
461 		tty_init_console(tp, ucom_cons_baud);
462 
463 		UCOM_MTX_LOCK(ucom_cons_softc);
464 		ucom_cons_rx_low = 0;
465 		ucom_cons_rx_high = 0;
466 		ucom_cons_tx_low = 0;
467 		ucom_cons_tx_high = 0;
468 		sc->sc_flag |= UCOM_FLAG_CONSOLE;
469 		ucom_open(ucom_cons_softc->sc_tty);
470 		ucom_param(ucom_cons_softc->sc_tty, &tp->t_termios_init_in);
471 		UCOM_MTX_UNLOCK(ucom_cons_softc);
472 	}
473 
474 	if ((ssc->sc_flag & UCOM_FLAG_DEVICE_MODE) != 0 &&
475 	    ucom_device_mode_console > 0 &&
476 	    ucom_cons_softc == NULL) {
477 		struct consdev *cp;
478 
479 		cp = malloc(sizeof(struct consdev), M_USBDEV,
480 		    M_WAITOK|M_ZERO);
481 		cp->cn_ops = &ucom_cnops;
482 		cp->cn_arg = NULL;
483 		cp->cn_pri = CN_NORMAL;
484 		strlcpy(cp->cn_name, "tty", sizeof(cp->cn_name));
485 		strlcat(cp->cn_name, buf, sizeof(cp->cn_name));
486 
487 		sc->sc_consdev = cp;
488 
489 		cnadd(cp);
490 	}
491 
492 	return (0);
493 }
494 
495 static void
ucom_detach_tty(struct ucom_super_softc * ssc,struct ucom_softc * sc)496 ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
497 {
498 	struct tty *tp = sc->sc_tty;
499 
500 	DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty);
501 
502 	if (sc->sc_consdev != NULL) {
503 		cnremove(sc->sc_consdev);
504 		free(sc->sc_consdev, M_USBDEV);
505 		sc->sc_consdev = NULL;
506 	}
507 
508 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
509 		UCOM_MTX_LOCK(ucom_cons_softc);
510 		ucom_close(ucom_cons_softc->sc_tty);
511 		sc->sc_flag &= ~UCOM_FLAG_CONSOLE;
512 		UCOM_MTX_UNLOCK(ucom_cons_softc);
513 		ucom_cons_softc = NULL;
514 	}
515 
516 	/* the config thread has been stopped when we get here */
517 
518 	UCOM_MTX_LOCK(sc);
519 	sc->sc_flag |= UCOM_FLAG_GONE;
520 	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY);
521 	UCOM_MTX_UNLOCK(sc);
522 
523 	if (tp) {
524 		mtx_lock(&ucom_mtx);
525 		ucom_close_refs++;
526 		mtx_unlock(&ucom_mtx);
527 
528 		tty_lock(tp);
529 
530 		ucom_close(tp);	/* close, if any */
531 
532 		tty_rel_gone(tp);
533 
534 		UCOM_MTX_LOCK(sc);
535 		/*
536 		 * make sure that read and write transfers are stopped
537 		 */
538 		if (sc->sc_callback->ucom_stop_read)
539 			(sc->sc_callback->ucom_stop_read) (sc);
540 		if (sc->sc_callback->ucom_stop_write)
541 			(sc->sc_callback->ucom_stop_write) (sc);
542 		UCOM_MTX_UNLOCK(sc);
543 	}
544 }
545 
546 void
ucom_set_pnpinfo_usb(struct ucom_super_softc * ssc,device_t dev)547 ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev)
548 {
549 	char buf[64];
550 	uint8_t iface_index;
551 	struct usb_attach_arg *uaa;
552 
553 	snprintf(buf, sizeof(buf), "ttyname=" UCOM_TTY_PREFIX
554 	    "%d ttyports=%d", ssc->sc_unit, ssc->sc_subunits);
555 
556 	/* Store the PNP info in the first interface for the device */
557 	uaa = device_get_ivars(dev);
558 	iface_index = uaa->info.bIfaceIndex;
559 
560 	if (usbd_set_pnpinfo(uaa->device, iface_index, buf) != 0)
561 		device_printf(dev, "Could not set PNP info\n");
562 
563 	/*
564 	 * The following information is also replicated in the PNP-info
565 	 * string which is registered above:
566 	 */
567 	if (ssc->sc_sysctl_ttyname == NULL) {
568 		ssc->sc_sysctl_ttyname = SYSCTL_ADD_STRING(NULL,
569 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
570 		    OID_AUTO, "ttyname", CTLFLAG_RD, ssc->sc_ttyname, 0,
571 		    "TTY device basename");
572 	}
573 	if (ssc->sc_sysctl_ttyports == NULL) {
574 		ssc->sc_sysctl_ttyports = SYSCTL_ADD_INT(NULL,
575 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
576 		    OID_AUTO, "ttyports", CTLFLAG_RD,
577 		    NULL, ssc->sc_subunits, "Number of ports");
578 	}
579 }
580 
581 void
ucom_set_usb_mode(struct ucom_super_softc * ssc,enum usb_hc_mode usb_mode)582 ucom_set_usb_mode(struct ucom_super_softc *ssc, enum usb_hc_mode usb_mode)
583 {
584 
585 	switch (usb_mode) {
586 	case USB_MODE_DEVICE:
587 		ssc->sc_flag |= UCOM_FLAG_DEVICE_MODE;
588 		break;
589 	default:
590 		ssc->sc_flag &= ~UCOM_FLAG_DEVICE_MODE;
591 		break;
592 	}
593 }
594 
595 static void
ucom_command_barrier_cb(struct usb_proc_msg * msg __unused)596 ucom_command_barrier_cb(struct usb_proc_msg *msg __unused)
597 {
598 	/* NOP */
599 }
600 
601 /*
602  * ucom_command_barrier inserts a dummy task and waits for it so that we can be
603  * certain that previously enqueued tasks are finished before returning back to
604  * the tty layer.
605  */
606 static int
ucom_command_barrier(struct ucom_softc * sc)607 ucom_command_barrier(struct ucom_softc *sc)
608 {
609 	struct ucom_super_softc *ssc = sc->sc_super;
610 	struct usb_proc_msg dummy = { .pm_callback = ucom_command_barrier_cb };
611 	struct usb_proc_msg *task;
612 	int error;
613 
614 	UCOM_MTX_ASSERT(sc, MA_OWNED);
615 
616 	if (usb_proc_is_gone(&ssc->sc_tq)) {
617 		DPRINTF("proc is gone\n");
618 		return (ENXIO);         /* nothing to do */
619 	}
620 
621 	task = usb_proc_msignal(&ssc->sc_tq, &dummy, &dummy);
622 	error = usb_proc_mwait_sig(&ssc->sc_tq, task, task);
623 	if (error == 0 && sc->sc_tty != NULL && tty_gone(sc->sc_tty))
624 		error = ENXIO;
625 	return (error);
626 }
627 
628 static int
ucom_queue_command(struct ucom_softc * sc,usb_proc_callback_t * fn,struct termios * pt,struct usb_proc_msg * t0,struct usb_proc_msg * t1,bool wait)629 ucom_queue_command(struct ucom_softc *sc,
630     usb_proc_callback_t *fn, struct termios *pt,
631     struct usb_proc_msg *t0, struct usb_proc_msg *t1, bool wait)
632 {
633 	struct ucom_super_softc *ssc = sc->sc_super;
634 	struct ucom_param_task *task;
635 	int error;
636 
637 	UCOM_MTX_ASSERT(sc, MA_OWNED);
638 
639 	if (usb_proc_is_gone(&ssc->sc_tq)) {
640 		DPRINTF("proc is gone\n");
641 		return (ENXIO);         /* nothing to do */
642 	}
643 	/*
644 	 * NOTE: The task cannot get executed before we drop the
645 	 * "sc_mtx" mutex. It is safe to update fields in the message
646 	 * structure after that the message got queued.
647 	 */
648 	task = (struct ucom_param_task *)
649 	  usb_proc_msignal(&ssc->sc_tq, t0, t1);
650 
651 	/* Setup callback and softc pointers */
652 	task->hdr.pm_callback = fn;
653 	task->sc = sc;
654 
655 	/*
656 	 * Make a copy of the termios. This field is only present if
657 	 * the "pt" field is not NULL.
658 	 */
659 	if (pt != NULL)
660 		task->termios_copy = *pt;
661 
662 	/*
663 	 * Closing or opening the device should be synchronous.
664 	 */
665 	if (wait) {
666 		error = usb_proc_mwait_sig(&ssc->sc_tq, t0, t1);
667 
668 		/* usb_proc_mwait_sig may have dropped the tty lock. */
669 		if (error == 0 && sc->sc_tty != NULL && tty_gone(sc->sc_tty))
670 			error = ENXIO;
671 	} else {
672 		error = 0;
673 	}
674 
675 	/*
676 	 * In case of multiple configure requests,
677 	 * keep track of the last one!
678 	 */
679 	if (fn == ucom_cfg_start_transfers)
680 		sc->sc_last_start_xfer = &task->hdr;
681 
682 	return (error);
683 }
684 
685 static void
ucom_shutdown(struct ucom_softc * sc)686 ucom_shutdown(struct ucom_softc *sc)
687 {
688 	struct tty *tp = sc->sc_tty;
689 
690 	UCOM_MTX_ASSERT(sc, MA_OWNED);
691 
692 	DPRINTF("\n");
693 
694 	/*
695 	 * Hang up if necessary:
696 	 */
697 	if (tp->t_termios.c_cflag & HUPCL) {
698 		ucom_modem(tp, 0, SER_DTR);
699 	}
700 }
701 
702 /*
703  * Return values:
704  *    0: normal
705  * else: taskqueue is draining or gone
706  */
707 uint8_t
ucom_cfg_is_gone(struct ucom_softc * sc)708 ucom_cfg_is_gone(struct ucom_softc *sc)
709 {
710 	struct ucom_super_softc *ssc = sc->sc_super;
711 
712 	return (usb_proc_is_gone(&ssc->sc_tq));
713 }
714 
715 static void
ucom_cfg_start_transfers(struct usb_proc_msg * _task)716 ucom_cfg_start_transfers(struct usb_proc_msg *_task)
717 {
718 	struct ucom_cfg_task *task =
719 	    (struct ucom_cfg_task *)_task;
720 	struct ucom_softc *sc = task->sc;
721 
722 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
723 		return;
724 	}
725 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
726 		/* TTY device closed */
727 		return;
728 	}
729 
730 	if (_task == sc->sc_last_start_xfer)
731 		sc->sc_flag |= UCOM_FLAG_GP_DATA;
732 
733 	if (sc->sc_callback->ucom_start_read) {
734 		(sc->sc_callback->ucom_start_read) (sc);
735 	}
736 	if (sc->sc_callback->ucom_start_write) {
737 		(sc->sc_callback->ucom_start_write) (sc);
738 	}
739 }
740 
741 static void
ucom_start_transfers(struct ucom_softc * sc)742 ucom_start_transfers(struct ucom_softc *sc)
743 {
744 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
745 		return;
746 	}
747 	/*
748 	 * Make sure that data transfers are started in both
749 	 * directions:
750 	 */
751 	if (sc->sc_callback->ucom_start_read) {
752 		(sc->sc_callback->ucom_start_read) (sc);
753 	}
754 	if (sc->sc_callback->ucom_start_write) {
755 		(sc->sc_callback->ucom_start_write) (sc);
756 	}
757 }
758 
759 static void
ucom_cfg_open(struct usb_proc_msg * _task)760 ucom_cfg_open(struct usb_proc_msg *_task)
761 {
762 	struct ucom_cfg_task *task =
763 	    (struct ucom_cfg_task *)_task;
764 	struct ucom_softc *sc = task->sc;
765 
766 	DPRINTF("\n");
767 
768 	if (sc->sc_flag & UCOM_FLAG_LL_READY) {
769 		/* already opened */
770 
771 	} else {
772 		sc->sc_flag |= UCOM_FLAG_LL_READY;
773 
774 		if (sc->sc_callback->ucom_cfg_open) {
775 			(sc->sc_callback->ucom_cfg_open) (sc);
776 
777 			/* wait a little */
778 			usb_pause_mtx(sc->sc_mtx, hz / 10);
779 		}
780 	}
781 }
782 
783 static int
ucom_open(struct tty * tp)784 ucom_open(struct tty *tp)
785 {
786 	struct ucom_softc *sc = tty_softc(tp);
787 	int error;
788 
789 	UCOM_MTX_ASSERT(sc, MA_OWNED);
790 
791 	if (sc->sc_flag & UCOM_FLAG_GONE) {
792 		return (ENXIO);
793 	}
794 	if (sc->sc_flag & UCOM_FLAG_HL_READY) {
795 		/* already opened */
796 		return (0);
797 	}
798 	DPRINTF("tp = %p\n", tp);
799 
800 	if (sc->sc_callback->ucom_pre_open) {
801 		/*
802 		 * give the lower layer a chance to disallow TTY open, for
803 		 * example if the device is not present:
804 		 */
805 		error = (sc->sc_callback->ucom_pre_open) (sc);
806 		if (error != 0)
807 			goto out;
808 	}
809 	sc->sc_flag |= UCOM_FLAG_HL_READY;
810 
811 	/* Disable transfers */
812 	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
813 
814 	sc->sc_lsr = 0;
815 	sc->sc_msr = 0;
816 	sc->sc_mcr = 0;
817 
818 	/* reset programmed line state */
819 	sc->sc_pls_curr = 0;
820 	sc->sc_pls_set = 0;
821 	sc->sc_pls_clr = 0;
822 
823 	/* reset jitter buffer */
824 	sc->sc_jitterbuf_in = 0;
825 	sc->sc_jitterbuf_out = 0;
826 
827 	error = ucom_queue_command(sc, ucom_cfg_open, NULL,
828 	    &sc->sc_open_task[0].hdr,
829 	    &sc->sc_open_task[1].hdr, true);
830 	if (error != 0)
831 		goto out;
832 
833 	/*
834 	 * Queue transfer enable command last, we'll have a barrier later so we
835 	 * don't need to wait on this to complete specifically.
836 	 */
837 	error = ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
838 	    &sc->sc_start_task[0].hdr,
839 	    &sc->sc_start_task[1].hdr, true);
840 	if (error != 0)
841 		goto out;
842 
843 	if (sc->sc_tty == NULL || (sc->sc_tty->t_termios.c_cflag & CNO_RTSDTR) == 0)
844 		ucom_modem(tp, SER_DTR | SER_RTS, 0);
845 
846 	ucom_ring(sc, 0);
847 
848 	ucom_break(sc, 0);
849 
850 	ucom_status_change(sc);
851 
852 	error = ucom_command_barrier(sc);
853 out:
854 	return (error);
855 }
856 
857 static void
ucom_cfg_close(struct usb_proc_msg * _task)858 ucom_cfg_close(struct usb_proc_msg *_task)
859 {
860 	struct ucom_cfg_task *task =
861 	    (struct ucom_cfg_task *)_task;
862 	struct ucom_softc *sc = task->sc;
863 
864 	DPRINTF("\n");
865 
866 	if (sc->sc_flag & UCOM_FLAG_LL_READY) {
867 		sc->sc_flag &= ~UCOM_FLAG_LL_READY;
868 		if (sc->sc_callback->ucom_cfg_close)
869 			(sc->sc_callback->ucom_cfg_close) (sc);
870 	} else {
871 		/* already closed */
872 	}
873 }
874 
875 static void
ucom_close(struct tty * tp)876 ucom_close(struct tty *tp)
877 {
878 	struct ucom_softc *sc = tty_softc(tp);
879 
880 	UCOM_MTX_ASSERT(sc, MA_OWNED);
881 
882 	DPRINTF("tp=%p\n", tp);
883 
884 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
885 		DPRINTF("tp=%p already closed\n", tp);
886 		return;
887 	}
888 	ucom_shutdown(sc);
889 
890 	(void)ucom_queue_command(sc, ucom_cfg_close, NULL,
891 	    &sc->sc_close_task[0].hdr,
892 	    &sc->sc_close_task[1].hdr, true);
893 
894 	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_RTS_IFLOW);
895 
896 	if (sc->sc_callback->ucom_stop_read) {
897 		(sc->sc_callback->ucom_stop_read) (sc);
898 	}
899 }
900 
901 static void
ucom_inwakeup(struct tty * tp)902 ucom_inwakeup(struct tty *tp)
903 {
904 	struct ucom_softc *sc = tty_softc(tp);
905 	uint16_t pos;
906 
907 	if (sc == NULL)
908 		return;
909 
910 	UCOM_MTX_ASSERT(sc, MA_OWNED);
911 
912 	DPRINTF("tp=%p\n", tp);
913 
914 	if (ttydisc_can_bypass(tp) != 0 ||
915 	    (sc->sc_flag & UCOM_FLAG_HL_READY) == 0 ||
916 	    (sc->sc_flag & UCOM_FLAG_INWAKEUP) != 0) {
917 		return;
918 	}
919 
920 	/* prevent recursion */
921 	sc->sc_flag |= UCOM_FLAG_INWAKEUP;
922 
923 	pos = sc->sc_jitterbuf_out;
924 
925 	while (sc->sc_jitterbuf_in != pos) {
926 		int c;
927 
928 		c = (char)sc->sc_jitterbuf[pos];
929 
930 		if (ttydisc_rint(tp, c, 0) == -1)
931 			break;
932 		pos++;
933 		if (pos >= UCOM_JITTERBUF_SIZE)
934 			pos -= UCOM_JITTERBUF_SIZE;
935 	}
936 
937 	sc->sc_jitterbuf_out = pos;
938 
939 	/* clear RTS in async fashion */
940 	if ((sc->sc_jitterbuf_in == pos) &&
941 	    (sc->sc_flag & UCOM_FLAG_RTS_IFLOW))
942 		ucom_rts(sc, 0);
943 
944 	sc->sc_flag &= ~UCOM_FLAG_INWAKEUP;
945 }
946 
947 static int
ucom_ioctl(struct tty * tp,u_long cmd,caddr_t data,struct thread * td)948 ucom_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
949 {
950 	struct ucom_softc *sc = tty_softc(tp);
951 	int error;
952 
953 	UCOM_MTX_ASSERT(sc, MA_OWNED);
954 
955 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
956 		return (EIO);
957 	}
958 	DPRINTF("cmd = 0x%08lx\n", cmd);
959 
960 	switch (cmd) {
961 #if 0
962 	case TIOCSRING:
963 		ucom_ring(sc, 1);
964 		error = 0;
965 		break;
966 	case TIOCCRING:
967 		ucom_ring(sc, 0);
968 		error = 0;
969 		break;
970 #endif
971 	case TIOCSBRK:
972 		ucom_break(sc, 1);
973 		error = ucom_command_barrier(sc);
974 		if (error == ENXIO)
975 			error = ENODEV;
976 		break;
977 	case TIOCCBRK:
978 		ucom_break(sc, 0);
979 		error = ucom_command_barrier(sc);
980 		if (error == ENXIO)
981 			error = ENODEV;
982 		break;
983 	default:
984 		if (sc->sc_callback->ucom_ioctl) {
985 			error = (sc->sc_callback->ucom_ioctl)
986 			    (sc, cmd, data, 0, td);
987 		} else {
988 			error = ENOIOCTL;
989 		}
990 		if (error == ENOIOCTL)
991 			error = pps_ioctl(cmd, data, &sc->sc_pps);
992 		break;
993 	}
994 	return (error);
995 }
996 
997 static int
ucom_modem(struct tty * tp,int sigon,int sigoff)998 ucom_modem(struct tty *tp, int sigon, int sigoff)
999 {
1000 	struct ucom_softc *sc = tty_softc(tp);
1001 	uint8_t onoff;
1002 
1003 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1004 
1005 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1006 		return (0);
1007 	}
1008 	if ((sigon == 0) && (sigoff == 0)) {
1009 		if (sc->sc_mcr & SER_DTR) {
1010 			sigon |= SER_DTR;
1011 		}
1012 		if (sc->sc_mcr & SER_RTS) {
1013 			sigon |= SER_RTS;
1014 		}
1015 		if (sc->sc_msr & SER_CTS) {
1016 			sigon |= SER_CTS;
1017 		}
1018 		if (sc->sc_msr & SER_DCD) {
1019 			sigon |= SER_DCD;
1020 		}
1021 		if (sc->sc_msr & SER_DSR) {
1022 			sigon |= SER_DSR;
1023 		}
1024 		if (sc->sc_msr & SER_RI) {
1025 			sigon |= SER_RI;
1026 		}
1027 		return (sigon);
1028 	}
1029 	if (sigon & SER_DTR) {
1030 		sc->sc_mcr |= SER_DTR;
1031 	}
1032 	if (sigoff & SER_DTR) {
1033 		sc->sc_mcr &= ~SER_DTR;
1034 	}
1035 	if (sigon & SER_RTS) {
1036 		sc->sc_mcr |= SER_RTS;
1037 	}
1038 	if (sigoff & SER_RTS) {
1039 		sc->sc_mcr &= ~SER_RTS;
1040 	}
1041 	onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0;
1042 	ucom_dtr(sc, onoff);
1043 
1044 	onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0;
1045 	ucom_rts(sc, onoff);
1046 
1047 	return (0);
1048 }
1049 
1050 static void
ucom_cfg_line_state(struct usb_proc_msg * _task)1051 ucom_cfg_line_state(struct usb_proc_msg *_task)
1052 {
1053 	struct ucom_cfg_task *task =
1054 	    (struct ucom_cfg_task *)_task;
1055 	struct ucom_softc *sc = task->sc;
1056 	uint8_t notch_bits;
1057 	uint8_t any_bits;
1058 	uint8_t prev_value;
1059 	uint8_t last_value;
1060 	uint8_t mask;
1061 
1062 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1063 		return;
1064 	}
1065 
1066 	mask = 0;
1067 	/* compute callback mask */
1068 	if (sc->sc_callback->ucom_cfg_set_dtr)
1069 		mask |= UCOM_LS_DTR;
1070 	if (sc->sc_callback->ucom_cfg_set_rts)
1071 		mask |= UCOM_LS_RTS;
1072 	if (sc->sc_callback->ucom_cfg_set_break)
1073 		mask |= UCOM_LS_BREAK;
1074 	if (sc->sc_callback->ucom_cfg_set_ring)
1075 		mask |= UCOM_LS_RING;
1076 
1077 	/* compute the bits we are to program */
1078 	notch_bits = (sc->sc_pls_set & sc->sc_pls_clr) & mask;
1079 	any_bits = (sc->sc_pls_set | sc->sc_pls_clr) & mask;
1080 	prev_value = sc->sc_pls_curr ^ notch_bits;
1081 	last_value = sc->sc_pls_curr;
1082 
1083 	/* reset programmed line state */
1084 	sc->sc_pls_curr = 0;
1085 	sc->sc_pls_set = 0;
1086 	sc->sc_pls_clr = 0;
1087 
1088 	/* ensure that we don't lose any levels */
1089 	if (notch_bits & UCOM_LS_DTR)
1090 		sc->sc_callback->ucom_cfg_set_dtr(sc,
1091 		    (prev_value & UCOM_LS_DTR) ? 1 : 0);
1092 	if (notch_bits & UCOM_LS_RTS)
1093 		sc->sc_callback->ucom_cfg_set_rts(sc,
1094 		    (prev_value & UCOM_LS_RTS) ? 1 : 0);
1095 	if (notch_bits & UCOM_LS_BREAK)
1096 		sc->sc_callback->ucom_cfg_set_break(sc,
1097 		    (prev_value & UCOM_LS_BREAK) ? 1 : 0);
1098 	if (notch_bits & UCOM_LS_RING)
1099 		sc->sc_callback->ucom_cfg_set_ring(sc,
1100 		    (prev_value & UCOM_LS_RING) ? 1 : 0);
1101 
1102 	/* set last value */
1103 	if (any_bits & UCOM_LS_DTR)
1104 		sc->sc_callback->ucom_cfg_set_dtr(sc,
1105 		    (last_value & UCOM_LS_DTR) ? 1 : 0);
1106 	if (any_bits & UCOM_LS_RTS)
1107 		sc->sc_callback->ucom_cfg_set_rts(sc,
1108 		    (last_value & UCOM_LS_RTS) ? 1 : 0);
1109 	if (any_bits & UCOM_LS_BREAK)
1110 		sc->sc_callback->ucom_cfg_set_break(sc,
1111 		    (last_value & UCOM_LS_BREAK) ? 1 : 0);
1112 	if (any_bits & UCOM_LS_RING)
1113 		sc->sc_callback->ucom_cfg_set_ring(sc,
1114 		    (last_value & UCOM_LS_RING) ? 1 : 0);
1115 }
1116 
1117 static void
ucom_line_state(struct ucom_softc * sc,uint8_t set_bits,uint8_t clear_bits)1118 ucom_line_state(struct ucom_softc *sc,
1119     uint8_t set_bits, uint8_t clear_bits)
1120 {
1121 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1122 
1123 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1124 		return;
1125 	}
1126 
1127 	DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits);
1128 
1129 	/* update current programmed line state */
1130 	sc->sc_pls_curr |= set_bits;
1131 	sc->sc_pls_curr &= ~clear_bits;
1132 	sc->sc_pls_set |= set_bits;
1133 	sc->sc_pls_clr |= clear_bits;
1134 
1135 	/*
1136 	 * defer driver programming - we don't propagate any error from
1137 	 * this call because we'll catch such errors further up the call stack.
1138 	 */
1139 	(void)ucom_queue_command(sc, ucom_cfg_line_state, NULL,
1140 	    &sc->sc_line_state_task[0].hdr,
1141 	    &sc->sc_line_state_task[1].hdr, false);
1142 }
1143 
1144 static void
ucom_ring(struct ucom_softc * sc,uint8_t onoff)1145 ucom_ring(struct ucom_softc *sc, uint8_t onoff)
1146 {
1147 	DPRINTF("onoff = %d\n", onoff);
1148 
1149 	if (onoff)
1150 		ucom_line_state(sc, UCOM_LS_RING, 0);
1151 	else
1152 		ucom_line_state(sc, 0, UCOM_LS_RING);
1153 }
1154 
1155 static void
ucom_break(struct ucom_softc * sc,uint8_t onoff)1156 ucom_break(struct ucom_softc *sc, uint8_t onoff)
1157 {
1158 	DPRINTF("onoff = %d\n", onoff);
1159 
1160 	if (onoff)
1161 		ucom_line_state(sc, UCOM_LS_BREAK, 0);
1162 	else
1163 		ucom_line_state(sc, 0, UCOM_LS_BREAK);
1164 }
1165 
1166 static void
ucom_dtr(struct ucom_softc * sc,uint8_t onoff)1167 ucom_dtr(struct ucom_softc *sc, uint8_t onoff)
1168 {
1169 	DPRINTF("onoff = %d\n", onoff);
1170 
1171 	if (onoff)
1172 		ucom_line_state(sc, UCOM_LS_DTR, 0);
1173 	else
1174 		ucom_line_state(sc, 0, UCOM_LS_DTR);
1175 }
1176 
1177 static void
ucom_rts(struct ucom_softc * sc,uint8_t onoff)1178 ucom_rts(struct ucom_softc *sc, uint8_t onoff)
1179 {
1180 	DPRINTF("onoff = %d\n", onoff);
1181 
1182 	if (onoff)
1183 		ucom_line_state(sc, UCOM_LS_RTS, 0);
1184 	else
1185 		ucom_line_state(sc, 0, UCOM_LS_RTS);
1186 }
1187 
1188 static void
ucom_cfg_status_change(struct usb_proc_msg * _task)1189 ucom_cfg_status_change(struct usb_proc_msg *_task)
1190 {
1191 	struct ucom_cfg_task *task =
1192 	    (struct ucom_cfg_task *)_task;
1193 	struct ucom_softc *sc = task->sc;
1194 	struct tty *tp;
1195 	int onoff;
1196 	uint8_t new_msr;
1197 	uint8_t new_lsr;
1198 	uint8_t msr_delta;
1199 	uint8_t lsr_delta;
1200 	uint8_t pps_signal;
1201 
1202 	tp = sc->sc_tty;
1203 
1204 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1205 
1206 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1207 		return;
1208 	}
1209 	if (sc->sc_callback->ucom_cfg_get_status == NULL) {
1210 		return;
1211 	}
1212 	/* get status */
1213 
1214 	new_msr = 0;
1215 	new_lsr = 0;
1216 
1217 	(sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr);
1218 
1219 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1220 		/* TTY device closed */
1221 		return;
1222 	}
1223 	msr_delta = (sc->sc_msr ^ new_msr);
1224 	lsr_delta = (sc->sc_lsr ^ new_lsr);
1225 
1226 	sc->sc_msr = new_msr;
1227 	sc->sc_lsr = new_lsr;
1228 
1229 	/*
1230 	 * Time pulse counting support.
1231 	 */
1232 	switch(ucom_pps_mode & UART_PPS_SIGNAL_MASK) {
1233 	case UART_PPS_CTS:
1234 		pps_signal = SER_CTS;
1235 		break;
1236 	case UART_PPS_DCD:
1237 		pps_signal = SER_DCD;
1238 		break;
1239 	default:
1240 		pps_signal = 0;
1241 		break;
1242 	}
1243 
1244 	if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) &&
1245 	    (msr_delta & pps_signal)) {
1246 		pps_capture(&sc->sc_pps);
1247 		onoff = (sc->sc_msr & pps_signal) ? 1 : 0;
1248 		if (ucom_pps_mode & UART_PPS_INVERT_PULSE)
1249 			onoff = !onoff;
1250 		pps_event(&sc->sc_pps, onoff ? PPS_CAPTUREASSERT :
1251 		    PPS_CAPTURECLEAR);
1252 	}
1253 
1254 	if (msr_delta & SER_DCD) {
1255 		onoff = (sc->sc_msr & SER_DCD) ? 1 : 0;
1256 
1257 		DPRINTF("DCD changed to %d\n", onoff);
1258 
1259 		ttydisc_modem(tp, onoff);
1260 	}
1261 
1262 	if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) {
1263 		DPRINTF("BREAK detected\n");
1264 
1265 		ttydisc_rint(tp, 0, TRE_BREAK);
1266 		ttydisc_rint_done(tp);
1267 	}
1268 
1269 	if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) {
1270 		DPRINTF("Frame error detected\n");
1271 
1272 		ttydisc_rint(tp, 0, TRE_FRAMING);
1273 		ttydisc_rint_done(tp);
1274 	}
1275 
1276 	if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) {
1277 		DPRINTF("Parity error detected\n");
1278 
1279 		ttydisc_rint(tp, 0, TRE_PARITY);
1280 		ttydisc_rint_done(tp);
1281 	}
1282 }
1283 
1284 void
ucom_status_change(struct ucom_softc * sc)1285 ucom_status_change(struct ucom_softc *sc)
1286 {
1287 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1288 
1289 	if (sc->sc_flag & UCOM_FLAG_CONSOLE)
1290 		return;		/* not supported */
1291 
1292 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1293 		return;
1294 	}
1295 	DPRINTF("\n");
1296 
1297 	(void)ucom_queue_command(sc, ucom_cfg_status_change, NULL,
1298 	    &sc->sc_status_task[0].hdr,
1299 	    &sc->sc_status_task[1].hdr, true);
1300 }
1301 
1302 static void
ucom_cfg_param(struct usb_proc_msg * _task)1303 ucom_cfg_param(struct usb_proc_msg *_task)
1304 {
1305 	struct ucom_param_task *task =
1306 	    (struct ucom_param_task *)_task;
1307 	struct ucom_softc *sc = task->sc;
1308 
1309 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1310 		return;
1311 	}
1312 	if (sc->sc_callback->ucom_cfg_param == NULL) {
1313 		return;
1314 	}
1315 
1316 	(sc->sc_callback->ucom_cfg_param) (sc, &task->termios_copy);
1317 
1318 	/* wait a little */
1319 	usb_pause_mtx(sc->sc_mtx, hz / 10);
1320 }
1321 
1322 static int
ucom_param(struct tty * tp,struct termios * t)1323 ucom_param(struct tty *tp, struct termios *t)
1324 {
1325 	struct ucom_softc *sc = tty_softc(tp);
1326 	uint8_t opened;
1327 	int error;
1328 
1329 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1330 
1331 	opened = 0;
1332 	error = 0;
1333 
1334 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1335 		/* XXX the TTY layer should call "open()" first! */
1336 		/*
1337 		 * Not quite: Its ordering is partly backwards, but
1338 		 * some parameters must be set early in ttydev_open(),
1339 		 * possibly before calling ttydevsw_open().
1340 		 */
1341 		error = ucom_open(tp);
1342 		if (error)
1343 			goto done;
1344 
1345 		opened = 1;
1346 	}
1347 	DPRINTF("sc = %p\n", sc);
1348 
1349 	/* Check requested parameters. */
1350 	if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) {
1351 		/* XXX c_ospeed == 0 is perfectly valid. */
1352 		DPRINTF("mismatch ispeed and ospeed\n");
1353 		error = EINVAL;
1354 		goto done;
1355 	}
1356 	t->c_ispeed = t->c_ospeed;
1357 
1358 	if (sc->sc_callback->ucom_pre_param) {
1359 		/* Let the lower layer verify the parameters */
1360 		error = (sc->sc_callback->ucom_pre_param) (sc, t);
1361 		if (error) {
1362 			DPRINTF("callback error = %d\n", error);
1363 			goto done;
1364 		}
1365 	}
1366 
1367 	/* Disable transfers */
1368 	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
1369 
1370 	/* Queue baud rate programming command first */
1371 	error = ucom_queue_command(sc, ucom_cfg_param, t,
1372 	    &sc->sc_param_task[0].hdr,
1373 	    &sc->sc_param_task[1].hdr, true);
1374 	if (error != 0)
1375 		goto done;
1376 
1377 	/* Queue transfer enable command last */
1378 	error = ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
1379 	    &sc->sc_start_task[0].hdr,
1380 	    &sc->sc_start_task[1].hdr, true);
1381 	if (error != 0)
1382 		goto done;
1383 
1384 	if (t->c_cflag & CRTS_IFLOW) {
1385 		sc->sc_flag |= UCOM_FLAG_RTS_IFLOW;
1386 	} else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) {
1387 		sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW;
1388 		ucom_modem(tp, SER_RTS, 0);
1389 	}
1390 
1391 	error = ucom_command_barrier(sc);
1392 done:
1393 	if (error) {
1394 		if (opened) {
1395 			ucom_close(tp);
1396 		}
1397 	}
1398 	return (error);
1399 }
1400 
1401 static void
ucom_outwakeup(struct tty * tp)1402 ucom_outwakeup(struct tty *tp)
1403 {
1404 	struct ucom_softc *sc = tty_softc(tp);
1405 
1406 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1407 
1408 	DPRINTF("sc = %p\n", sc);
1409 
1410 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1411 		/* The higher layer is not ready */
1412 		return;
1413 	}
1414 	ucom_start_transfers(sc);
1415 }
1416 
1417 static bool
ucom_busy(struct tty * tp)1418 ucom_busy(struct tty *tp)
1419 {
1420 	struct ucom_softc *sc = tty_softc(tp);
1421 	const uint8_t txidle = ULSR_TXRDY | ULSR_TSRE;
1422 
1423 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1424 
1425 	DPRINTFN(3, "sc = %p lsr 0x%02x\n", sc, sc->sc_lsr);
1426 
1427 	/*
1428 	 * If the driver maintains the txidle bits in LSR, we can use them to
1429 	 * determine whether the transmitter is busy or idle.  Otherwise we have
1430 	 * to assume it is idle to avoid hanging forever on tcdrain(3).
1431 	 */
1432 	if (sc->sc_flag & UCOM_FLAG_LSRTXIDLE)
1433 		return ((sc->sc_lsr & txidle) != txidle);
1434 	else
1435 		return (false);
1436 }
1437 
1438 /*------------------------------------------------------------------------*
1439  *	ucom_get_data
1440  *
1441  * Return values:
1442  * 0: No data is available.
1443  * Else: Data is available.
1444  *------------------------------------------------------------------------*/
1445 uint8_t
ucom_get_data(struct ucom_softc * sc,struct usb_page_cache * pc,uint32_t offset,uint32_t len,uint32_t * actlen)1446 ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1447     uint32_t offset, uint32_t len, uint32_t *actlen)
1448 {
1449 	struct usb_page_search res;
1450 	struct tty *tp = sc->sc_tty;
1451 	uint32_t cnt;
1452 	uint32_t offset_orig;
1453 
1454 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1455 
1456 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1457 		unsigned temp;
1458 
1459 		/* get total TX length */
1460 
1461 		temp = ucom_cons_tx_high - ucom_cons_tx_low;
1462 		temp %= UCOM_CONS_BUFSIZE;
1463 
1464 		/* limit TX length */
1465 
1466 		if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low))
1467 			temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low);
1468 
1469 		if (temp > len)
1470 			temp = len;
1471 
1472 		/* copy in data */
1473 
1474 		usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp);
1475 
1476 		/* update counters */
1477 
1478 		ucom_cons_tx_low += temp;
1479 		ucom_cons_tx_low %= UCOM_CONS_BUFSIZE;
1480 
1481 		/* store actual length */
1482 
1483 		*actlen = temp;
1484 
1485 		return (temp ? 1 : 0);
1486 	}
1487 
1488 	if (tty_gone(tp) ||
1489 	    !(sc->sc_flag & UCOM_FLAG_GP_DATA)) {
1490 		actlen[0] = 0;
1491 		return (0);		/* multiport device polling */
1492 	}
1493 	offset_orig = offset;
1494 
1495 	while (len != 0) {
1496 		usbd_get_page(pc, offset, &res);
1497 
1498 		if (res.length > len) {
1499 			res.length = len;
1500 		}
1501 		/* copy data directly into USB buffer */
1502 		cnt = ttydisc_getc(tp, res.buffer, res.length);
1503 
1504 		offset += cnt;
1505 		len -= cnt;
1506 
1507 		if (cnt < res.length) {
1508 			/* end of buffer */
1509 			break;
1510 		}
1511 	}
1512 
1513 	actlen[0] = offset - offset_orig;
1514 
1515 	DPRINTF("cnt=%d\n", actlen[0]);
1516 
1517 	if (actlen[0] == 0) {
1518 		return (0);
1519 	}
1520 	return (1);
1521 }
1522 
1523 void
ucom_put_data(struct ucom_softc * sc,struct usb_page_cache * pc,uint32_t offset,uint32_t len)1524 ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1525     uint32_t offset, uint32_t len)
1526 {
1527 	struct usb_page_search res;
1528 	struct tty *tp = sc->sc_tty;
1529 	char *buf;
1530 	uint32_t cnt;
1531 
1532 	UCOM_MTX_ASSERT(sc, MA_OWNED);
1533 
1534 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1535 		unsigned temp;
1536 
1537 		/* get maximum RX length */
1538 
1539 		temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low;
1540 		temp %= UCOM_CONS_BUFSIZE;
1541 
1542 		/* limit RX length */
1543 
1544 		if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high))
1545 			temp = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high);
1546 
1547 		if (temp > len)
1548 			temp = len;
1549 
1550 		/* copy out data */
1551 
1552 		usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp);
1553 
1554 		/* update counters */
1555 
1556 		ucom_cons_rx_high += temp;
1557 		ucom_cons_rx_high %= UCOM_CONS_BUFSIZE;
1558 
1559 		return;
1560 	}
1561 
1562 	if (tty_gone(tp))
1563 		return;			/* multiport device polling */
1564 
1565 	if (len == 0)
1566 		return;			/* no data */
1567 
1568 	/* set a flag to prevent recursation ? */
1569 
1570 	while (len > 0) {
1571 		usbd_get_page(pc, offset, &res);
1572 
1573 		if (res.length > len) {
1574 			res.length = len;
1575 		}
1576 		len -= res.length;
1577 		offset += res.length;
1578 
1579 		/* pass characters to tty layer */
1580 
1581 		buf = res.buffer;
1582 		cnt = res.length;
1583 
1584 		/* first check if we can pass the buffer directly */
1585 
1586 		if (ttydisc_can_bypass(tp)) {
1587 			/* clear any jitter buffer */
1588 			sc->sc_jitterbuf_in = 0;
1589 			sc->sc_jitterbuf_out = 0;
1590 
1591 			if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) {
1592 				DPRINTF("tp=%p, data lost\n", tp);
1593 			}
1594 			continue;
1595 		}
1596 		/* need to loop */
1597 
1598 		for (cnt = 0; cnt != res.length; cnt++) {
1599 			if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out ||
1600 			    ttydisc_rint(tp, buf[cnt], 0) == -1) {
1601 				uint16_t end;
1602 				uint16_t pos;
1603 
1604 				pos = sc->sc_jitterbuf_in;
1605 				end = sc->sc_jitterbuf_out +
1606 				    UCOM_JITTERBUF_SIZE - 1;
1607 				if (end >= UCOM_JITTERBUF_SIZE)
1608 					end -= UCOM_JITTERBUF_SIZE;
1609 
1610 				for (; cnt != res.length; cnt++) {
1611 					if (pos == end)
1612 						break;
1613 					sc->sc_jitterbuf[pos] = buf[cnt];
1614 					pos++;
1615 					if (pos >= UCOM_JITTERBUF_SIZE)
1616 						pos -= UCOM_JITTERBUF_SIZE;
1617 				}
1618 
1619 				sc->sc_jitterbuf_in = pos;
1620 
1621 				/* set RTS in async fashion */
1622 				if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)
1623 					ucom_rts(sc, 1);
1624 
1625 				DPRINTF("tp=%p, lost %d "
1626 				    "chars\n", tp, res.length - cnt);
1627 				break;
1628 			}
1629 		}
1630 	}
1631 	ttydisc_rint_done(tp);
1632 }
1633 
1634 static void
ucom_free(void * xsc)1635 ucom_free(void *xsc)
1636 {
1637 	struct ucom_softc *sc = xsc;
1638 
1639 	if (sc->sc_callback->ucom_free != NULL)
1640 		sc->sc_callback->ucom_free(sc);
1641 	else
1642 		ucom_unref(sc->sc_super);
1643 
1644 	mtx_lock(&ucom_mtx);
1645 	ucom_close_refs--;
1646 	mtx_unlock(&ucom_mtx);
1647 }
1648 
1649 CONSOLE_DRIVER(ucom);
1650 
1651 static void
ucom_cnprobe(struct consdev * cp)1652 ucom_cnprobe(struct consdev  *cp)
1653 {
1654 	if (ucom_cons_unit != -1)
1655 		cp->cn_pri = CN_NORMAL;
1656 	else
1657 		cp->cn_pri = CN_DEAD;
1658 
1659 	strlcpy(cp->cn_name, "ucom", sizeof(cp->cn_name));
1660 }
1661 
1662 static void
ucom_cninit(struct consdev * cp)1663 ucom_cninit(struct consdev  *cp)
1664 {
1665 }
1666 
1667 static void
ucom_cnterm(struct consdev * cp)1668 ucom_cnterm(struct consdev  *cp)
1669 {
1670 }
1671 
1672 static void
ucom_cngrab(struct consdev * cp)1673 ucom_cngrab(struct consdev *cp)
1674 {
1675 }
1676 
1677 static void
ucom_cnungrab(struct consdev * cp)1678 ucom_cnungrab(struct consdev *cp)
1679 {
1680 }
1681 
1682 static int
ucom_cngetc(struct consdev * cd)1683 ucom_cngetc(struct consdev *cd)
1684 {
1685 	struct ucom_softc *sc = ucom_cons_softc;
1686 	int c;
1687 
1688 	if (sc == NULL)
1689 		return (-1);
1690 
1691 	UCOM_MTX_LOCK(sc);
1692 
1693 	if (ucom_cons_rx_low != ucom_cons_rx_high) {
1694 		c = ucom_cons_rx_buf[ucom_cons_rx_low];
1695 		ucom_cons_rx_low ++;
1696 		ucom_cons_rx_low %= UCOM_CONS_BUFSIZE;
1697 	} else {
1698 		c = -1;
1699 	}
1700 
1701 	/* start USB transfers */
1702 	ucom_outwakeup(sc->sc_tty);
1703 
1704 	UCOM_MTX_UNLOCK(sc);
1705 
1706 	/* poll if necessary */
1707 	if (USB_IN_POLLING_MODE_FUNC() && sc->sc_callback->ucom_poll)
1708 		(sc->sc_callback->ucom_poll) (sc);
1709 
1710 	return (c);
1711 }
1712 
1713 static void
ucom_cnputc(struct consdev * cd,int c)1714 ucom_cnputc(struct consdev *cd, int c)
1715 {
1716 	struct ucom_softc *sc = ucom_cons_softc;
1717 	unsigned temp;
1718 
1719 	if (sc == NULL)
1720 		return;
1721 
1722  repeat:
1723 
1724 	UCOM_MTX_LOCK(sc);
1725 
1726 	/* compute maximum TX length */
1727 
1728 	temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low;
1729 	temp %= UCOM_CONS_BUFSIZE;
1730 
1731 	if (temp) {
1732 		ucom_cons_tx_buf[ucom_cons_tx_high] = c;
1733 		ucom_cons_tx_high ++;
1734 		ucom_cons_tx_high %= UCOM_CONS_BUFSIZE;
1735 	}
1736 
1737 	/* start USB transfers */
1738 	ucom_outwakeup(sc->sc_tty);
1739 
1740 	UCOM_MTX_UNLOCK(sc);
1741 
1742 	/* poll if necessary */
1743 	if (USB_IN_POLLING_MODE_FUNC() && sc->sc_callback->ucom_poll) {
1744 		(sc->sc_callback->ucom_poll) (sc);
1745 		/* simple flow control */
1746 		if (temp == 0)
1747 			goto repeat;
1748 	}
1749 }
1750 
1751 /*------------------------------------------------------------------------*
1752  *	ucom_ref
1753  *
1754  * This function will increment the super UCOM reference count.
1755  *------------------------------------------------------------------------*/
1756 void
ucom_ref(struct ucom_super_softc * ssc)1757 ucom_ref(struct ucom_super_softc *ssc)
1758 {
1759 	mtx_lock(&ucom_mtx);
1760 	ssc->sc_refs++;
1761 	mtx_unlock(&ucom_mtx);
1762 }
1763 
1764 /*------------------------------------------------------------------------*
1765  *	ucom_free_unit
1766  *
1767  * This function will free the super UCOM's allocated unit
1768  * number. This function can be called on a zero-initialized
1769  * structure. This function can be called multiple times.
1770  *------------------------------------------------------------------------*/
1771 static void
ucom_free_unit(struct ucom_super_softc * ssc)1772 ucom_free_unit(struct ucom_super_softc *ssc)
1773 {
1774 	if (!(ssc->sc_flag & UCOM_FLAG_FREE_UNIT))
1775 		return;
1776 
1777 	ucom_unit_free(ssc->sc_unit);
1778 
1779 	ssc->sc_flag &= ~UCOM_FLAG_FREE_UNIT;
1780 }
1781 
1782 /*------------------------------------------------------------------------*
1783  *	ucom_unref
1784  *
1785  * This function will decrement the super UCOM reference count.
1786  *
1787  * Return values:
1788  * 0: UCOM structures are still referenced.
1789  * Else: UCOM structures are no longer referenced.
1790  *------------------------------------------------------------------------*/
1791 int
ucom_unref(struct ucom_super_softc * ssc)1792 ucom_unref(struct ucom_super_softc *ssc)
1793 {
1794 	int retval;
1795 
1796 	mtx_lock(&ucom_mtx);
1797 	retval = (ssc->sc_refs < 2);
1798 	ssc->sc_refs--;
1799 	mtx_unlock(&ucom_mtx);
1800 
1801 	if (retval)
1802 		ucom_free_unit(ssc);
1803 
1804 	return (retval);
1805 }
1806 
1807 #if defined(GDB)
1808 
1809 #include <gdb/gdb.h>
1810 
1811 static gdb_probe_f ucom_gdbprobe;
1812 static gdb_init_f ucom_gdbinit;
1813 static gdb_term_f ucom_gdbterm;
1814 static gdb_getc_f ucom_gdbgetc;
1815 static gdb_putc_f ucom_gdbputc;
1816 
1817 GDB_DBGPORT(ucom, ucom_gdbprobe, ucom_gdbinit, ucom_gdbterm, ucom_gdbgetc, ucom_gdbputc);
1818 
1819 static int
ucom_gdbprobe(void)1820 ucom_gdbprobe(void)
1821 {
1822 	return ((ucom_cons_softc != NULL) ? 0 : -1);
1823 }
1824 
1825 static void
ucom_gdbinit(void)1826 ucom_gdbinit(void)
1827 {
1828 }
1829 
1830 static void
ucom_gdbterm(void)1831 ucom_gdbterm(void)
1832 {
1833 }
1834 
1835 static void
ucom_gdbputc(int c)1836 ucom_gdbputc(int c)
1837 {
1838         ucom_cnputc(NULL, c);
1839 }
1840 
1841 static int
ucom_gdbgetc(void)1842 ucom_gdbgetc(void)
1843 {
1844         return (ucom_cngetc(NULL));
1845 }
1846 
1847 #endif
1848