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