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 void 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);
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_queue_command(struct ucom_softc * sc,usb_proc_callback_t * fn,struct termios * pt,struct usb_proc_msg * t0,struct usb_proc_msg * t1)596 ucom_queue_command(struct ucom_softc *sc,
597 usb_proc_callback_t *fn, struct termios *pt,
598 struct usb_proc_msg *t0, struct usb_proc_msg *t1)
599 {
600 struct ucom_super_softc *ssc = sc->sc_super;
601 struct ucom_param_task *task;
602
603 UCOM_MTX_ASSERT(sc, MA_OWNED);
604
605 if (usb_proc_is_gone(&ssc->sc_tq)) {
606 DPRINTF("proc is gone\n");
607 return; /* nothing to do */
608 }
609 /*
610 * NOTE: The task cannot get executed before we drop the
611 * "sc_mtx" mutex. It is safe to update fields in the message
612 * structure after that the message got queued.
613 */
614 task = (struct ucom_param_task *)
615 usb_proc_msignal(&ssc->sc_tq, t0, t1);
616
617 /* Setup callback and softc pointers */
618 task->hdr.pm_callback = fn;
619 task->sc = sc;
620
621 /*
622 * Make a copy of the termios. This field is only present if
623 * the "pt" field is not NULL.
624 */
625 if (pt != NULL)
626 task->termios_copy = *pt;
627
628 /*
629 * Closing or opening the device should be synchronous.
630 */
631 if (fn == ucom_cfg_close || fn == ucom_cfg_open)
632 usb_proc_mwait(&ssc->sc_tq, t0, t1);
633
634 /*
635 * In case of multiple configure requests,
636 * keep track of the last one!
637 */
638 if (fn == ucom_cfg_start_transfers)
639 sc->sc_last_start_xfer = &task->hdr;
640 }
641
642 static void
ucom_shutdown(struct ucom_softc * sc)643 ucom_shutdown(struct ucom_softc *sc)
644 {
645 struct tty *tp = sc->sc_tty;
646
647 UCOM_MTX_ASSERT(sc, MA_OWNED);
648
649 DPRINTF("\n");
650
651 /*
652 * Hang up if necessary:
653 */
654 if (tp->t_termios.c_cflag & HUPCL) {
655 ucom_modem(tp, 0, SER_DTR);
656 }
657 }
658
659 /*
660 * Return values:
661 * 0: normal
662 * else: taskqueue is draining or gone
663 */
664 uint8_t
ucom_cfg_is_gone(struct ucom_softc * sc)665 ucom_cfg_is_gone(struct ucom_softc *sc)
666 {
667 struct ucom_super_softc *ssc = sc->sc_super;
668
669 return (usb_proc_is_gone(&ssc->sc_tq));
670 }
671
672 static void
ucom_cfg_start_transfers(struct usb_proc_msg * _task)673 ucom_cfg_start_transfers(struct usb_proc_msg *_task)
674 {
675 struct ucom_cfg_task *task =
676 (struct ucom_cfg_task *)_task;
677 struct ucom_softc *sc = task->sc;
678
679 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
680 return;
681 }
682 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
683 /* TTY device closed */
684 return;
685 }
686
687 if (_task == sc->sc_last_start_xfer)
688 sc->sc_flag |= UCOM_FLAG_GP_DATA;
689
690 if (sc->sc_callback->ucom_start_read) {
691 (sc->sc_callback->ucom_start_read) (sc);
692 }
693 if (sc->sc_callback->ucom_start_write) {
694 (sc->sc_callback->ucom_start_write) (sc);
695 }
696 }
697
698 static void
ucom_start_transfers(struct ucom_softc * sc)699 ucom_start_transfers(struct ucom_softc *sc)
700 {
701 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
702 return;
703 }
704 /*
705 * Make sure that data transfers are started in both
706 * directions:
707 */
708 if (sc->sc_callback->ucom_start_read) {
709 (sc->sc_callback->ucom_start_read) (sc);
710 }
711 if (sc->sc_callback->ucom_start_write) {
712 (sc->sc_callback->ucom_start_write) (sc);
713 }
714 }
715
716 static void
ucom_cfg_open(struct usb_proc_msg * _task)717 ucom_cfg_open(struct usb_proc_msg *_task)
718 {
719 struct ucom_cfg_task *task =
720 (struct ucom_cfg_task *)_task;
721 struct ucom_softc *sc = task->sc;
722
723 DPRINTF("\n");
724
725 if (sc->sc_flag & UCOM_FLAG_LL_READY) {
726 /* already opened */
727
728 } else {
729 sc->sc_flag |= UCOM_FLAG_LL_READY;
730
731 if (sc->sc_callback->ucom_cfg_open) {
732 (sc->sc_callback->ucom_cfg_open) (sc);
733
734 /* wait a little */
735 usb_pause_mtx(sc->sc_mtx, hz / 10);
736 }
737 }
738 }
739
740 static int
ucom_open(struct tty * tp)741 ucom_open(struct tty *tp)
742 {
743 struct ucom_softc *sc = tty_softc(tp);
744 int error;
745
746 UCOM_MTX_ASSERT(sc, MA_OWNED);
747
748 if (sc->sc_flag & UCOM_FLAG_GONE) {
749 return (ENXIO);
750 }
751 if (sc->sc_flag & UCOM_FLAG_HL_READY) {
752 /* already opened */
753 return (0);
754 }
755 DPRINTF("tp = %p\n", tp);
756
757 if (sc->sc_callback->ucom_pre_open) {
758 /*
759 * give the lower layer a chance to disallow TTY open, for
760 * example if the device is not present:
761 */
762 error = (sc->sc_callback->ucom_pre_open) (sc);
763 if (error) {
764 return (error);
765 }
766 }
767 sc->sc_flag |= UCOM_FLAG_HL_READY;
768
769 /* Disable transfers */
770 sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
771
772 sc->sc_lsr = 0;
773 sc->sc_msr = 0;
774 sc->sc_mcr = 0;
775
776 /* reset programmed line state */
777 sc->sc_pls_curr = 0;
778 sc->sc_pls_set = 0;
779 sc->sc_pls_clr = 0;
780
781 /* reset jitter buffer */
782 sc->sc_jitterbuf_in = 0;
783 sc->sc_jitterbuf_out = 0;
784
785 ucom_queue_command(sc, ucom_cfg_open, NULL,
786 &sc->sc_open_task[0].hdr,
787 &sc->sc_open_task[1].hdr);
788
789 /* Queue transfer enable command last */
790 ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
791 &sc->sc_start_task[0].hdr,
792 &sc->sc_start_task[1].hdr);
793
794 if (sc->sc_tty == NULL || (sc->sc_tty->t_termios.c_cflag & CNO_RTSDTR) == 0)
795 ucom_modem(tp, SER_DTR | SER_RTS, 0);
796
797 ucom_ring(sc, 0);
798
799 ucom_break(sc, 0);
800
801 ucom_status_change(sc);
802
803 return (0);
804 }
805
806 static void
ucom_cfg_close(struct usb_proc_msg * _task)807 ucom_cfg_close(struct usb_proc_msg *_task)
808 {
809 struct ucom_cfg_task *task =
810 (struct ucom_cfg_task *)_task;
811 struct ucom_softc *sc = task->sc;
812
813 DPRINTF("\n");
814
815 if (sc->sc_flag & UCOM_FLAG_LL_READY) {
816 sc->sc_flag &= ~UCOM_FLAG_LL_READY;
817 if (sc->sc_callback->ucom_cfg_close)
818 (sc->sc_callback->ucom_cfg_close) (sc);
819 } else {
820 /* already closed */
821 }
822 }
823
824 static void
ucom_close(struct tty * tp)825 ucom_close(struct tty *tp)
826 {
827 struct ucom_softc *sc = tty_softc(tp);
828
829 UCOM_MTX_ASSERT(sc, MA_OWNED);
830
831 DPRINTF("tp=%p\n", tp);
832
833 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
834 DPRINTF("tp=%p already closed\n", tp);
835 return;
836 }
837 ucom_shutdown(sc);
838
839 ucom_queue_command(sc, ucom_cfg_close, NULL,
840 &sc->sc_close_task[0].hdr,
841 &sc->sc_close_task[1].hdr);
842
843 sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_RTS_IFLOW);
844
845 if (sc->sc_callback->ucom_stop_read) {
846 (sc->sc_callback->ucom_stop_read) (sc);
847 }
848 }
849
850 static void
ucom_inwakeup(struct tty * tp)851 ucom_inwakeup(struct tty *tp)
852 {
853 struct ucom_softc *sc = tty_softc(tp);
854 uint16_t pos;
855
856 if (sc == NULL)
857 return;
858
859 UCOM_MTX_ASSERT(sc, MA_OWNED);
860
861 DPRINTF("tp=%p\n", tp);
862
863 if (ttydisc_can_bypass(tp) != 0 ||
864 (sc->sc_flag & UCOM_FLAG_HL_READY) == 0 ||
865 (sc->sc_flag & UCOM_FLAG_INWAKEUP) != 0) {
866 return;
867 }
868
869 /* prevent recursion */
870 sc->sc_flag |= UCOM_FLAG_INWAKEUP;
871
872 pos = sc->sc_jitterbuf_out;
873
874 while (sc->sc_jitterbuf_in != pos) {
875 int c;
876
877 c = (char)sc->sc_jitterbuf[pos];
878
879 if (ttydisc_rint(tp, c, 0) == -1)
880 break;
881 pos++;
882 if (pos >= UCOM_JITTERBUF_SIZE)
883 pos -= UCOM_JITTERBUF_SIZE;
884 }
885
886 sc->sc_jitterbuf_out = pos;
887
888 /* clear RTS in async fashion */
889 if ((sc->sc_jitterbuf_in == pos) &&
890 (sc->sc_flag & UCOM_FLAG_RTS_IFLOW))
891 ucom_rts(sc, 0);
892
893 sc->sc_flag &= ~UCOM_FLAG_INWAKEUP;
894 }
895
896 static int
ucom_ioctl(struct tty * tp,u_long cmd,caddr_t data,struct thread * td)897 ucom_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
898 {
899 struct ucom_softc *sc = tty_softc(tp);
900 int error;
901
902 UCOM_MTX_ASSERT(sc, MA_OWNED);
903
904 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
905 return (EIO);
906 }
907 DPRINTF("cmd = 0x%08lx\n", cmd);
908
909 switch (cmd) {
910 #if 0
911 case TIOCSRING:
912 ucom_ring(sc, 1);
913 error = 0;
914 break;
915 case TIOCCRING:
916 ucom_ring(sc, 0);
917 error = 0;
918 break;
919 #endif
920 case TIOCSBRK:
921 ucom_break(sc, 1);
922 error = 0;
923 break;
924 case TIOCCBRK:
925 ucom_break(sc, 0);
926 error = 0;
927 break;
928 default:
929 if (sc->sc_callback->ucom_ioctl) {
930 error = (sc->sc_callback->ucom_ioctl)
931 (sc, cmd, data, 0, td);
932 } else {
933 error = ENOIOCTL;
934 }
935 if (error == ENOIOCTL)
936 error = pps_ioctl(cmd, data, &sc->sc_pps);
937 break;
938 }
939 return (error);
940 }
941
942 static int
ucom_modem(struct tty * tp,int sigon,int sigoff)943 ucom_modem(struct tty *tp, int sigon, int sigoff)
944 {
945 struct ucom_softc *sc = tty_softc(tp);
946 uint8_t onoff;
947
948 UCOM_MTX_ASSERT(sc, MA_OWNED);
949
950 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
951 return (0);
952 }
953 if ((sigon == 0) && (sigoff == 0)) {
954 if (sc->sc_mcr & SER_DTR) {
955 sigon |= SER_DTR;
956 }
957 if (sc->sc_mcr & SER_RTS) {
958 sigon |= SER_RTS;
959 }
960 if (sc->sc_msr & SER_CTS) {
961 sigon |= SER_CTS;
962 }
963 if (sc->sc_msr & SER_DCD) {
964 sigon |= SER_DCD;
965 }
966 if (sc->sc_msr & SER_DSR) {
967 sigon |= SER_DSR;
968 }
969 if (sc->sc_msr & SER_RI) {
970 sigon |= SER_RI;
971 }
972 return (sigon);
973 }
974 if (sigon & SER_DTR) {
975 sc->sc_mcr |= SER_DTR;
976 }
977 if (sigoff & SER_DTR) {
978 sc->sc_mcr &= ~SER_DTR;
979 }
980 if (sigon & SER_RTS) {
981 sc->sc_mcr |= SER_RTS;
982 }
983 if (sigoff & SER_RTS) {
984 sc->sc_mcr &= ~SER_RTS;
985 }
986 onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0;
987 ucom_dtr(sc, onoff);
988
989 onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0;
990 ucom_rts(sc, onoff);
991
992 return (0);
993 }
994
995 static void
ucom_cfg_line_state(struct usb_proc_msg * _task)996 ucom_cfg_line_state(struct usb_proc_msg *_task)
997 {
998 struct ucom_cfg_task *task =
999 (struct ucom_cfg_task *)_task;
1000 struct ucom_softc *sc = task->sc;
1001 uint8_t notch_bits;
1002 uint8_t any_bits;
1003 uint8_t prev_value;
1004 uint8_t last_value;
1005 uint8_t mask;
1006
1007 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1008 return;
1009 }
1010
1011 mask = 0;
1012 /* compute callback mask */
1013 if (sc->sc_callback->ucom_cfg_set_dtr)
1014 mask |= UCOM_LS_DTR;
1015 if (sc->sc_callback->ucom_cfg_set_rts)
1016 mask |= UCOM_LS_RTS;
1017 if (sc->sc_callback->ucom_cfg_set_break)
1018 mask |= UCOM_LS_BREAK;
1019 if (sc->sc_callback->ucom_cfg_set_ring)
1020 mask |= UCOM_LS_RING;
1021
1022 /* compute the bits we are to program */
1023 notch_bits = (sc->sc_pls_set & sc->sc_pls_clr) & mask;
1024 any_bits = (sc->sc_pls_set | sc->sc_pls_clr) & mask;
1025 prev_value = sc->sc_pls_curr ^ notch_bits;
1026 last_value = sc->sc_pls_curr;
1027
1028 /* reset programmed line state */
1029 sc->sc_pls_curr = 0;
1030 sc->sc_pls_set = 0;
1031 sc->sc_pls_clr = 0;
1032
1033 /* ensure that we don't lose any levels */
1034 if (notch_bits & UCOM_LS_DTR)
1035 sc->sc_callback->ucom_cfg_set_dtr(sc,
1036 (prev_value & UCOM_LS_DTR) ? 1 : 0);
1037 if (notch_bits & UCOM_LS_RTS)
1038 sc->sc_callback->ucom_cfg_set_rts(sc,
1039 (prev_value & UCOM_LS_RTS) ? 1 : 0);
1040 if (notch_bits & UCOM_LS_BREAK)
1041 sc->sc_callback->ucom_cfg_set_break(sc,
1042 (prev_value & UCOM_LS_BREAK) ? 1 : 0);
1043 if (notch_bits & UCOM_LS_RING)
1044 sc->sc_callback->ucom_cfg_set_ring(sc,
1045 (prev_value & UCOM_LS_RING) ? 1 : 0);
1046
1047 /* set last value */
1048 if (any_bits & UCOM_LS_DTR)
1049 sc->sc_callback->ucom_cfg_set_dtr(sc,
1050 (last_value & UCOM_LS_DTR) ? 1 : 0);
1051 if (any_bits & UCOM_LS_RTS)
1052 sc->sc_callback->ucom_cfg_set_rts(sc,
1053 (last_value & UCOM_LS_RTS) ? 1 : 0);
1054 if (any_bits & UCOM_LS_BREAK)
1055 sc->sc_callback->ucom_cfg_set_break(sc,
1056 (last_value & UCOM_LS_BREAK) ? 1 : 0);
1057 if (any_bits & UCOM_LS_RING)
1058 sc->sc_callback->ucom_cfg_set_ring(sc,
1059 (last_value & UCOM_LS_RING) ? 1 : 0);
1060 }
1061
1062 static void
ucom_line_state(struct ucom_softc * sc,uint8_t set_bits,uint8_t clear_bits)1063 ucom_line_state(struct ucom_softc *sc,
1064 uint8_t set_bits, uint8_t clear_bits)
1065 {
1066 UCOM_MTX_ASSERT(sc, MA_OWNED);
1067
1068 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1069 return;
1070 }
1071
1072 DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits);
1073
1074 /* update current programmed line state */
1075 sc->sc_pls_curr |= set_bits;
1076 sc->sc_pls_curr &= ~clear_bits;
1077 sc->sc_pls_set |= set_bits;
1078 sc->sc_pls_clr |= clear_bits;
1079
1080 /* defer driver programming */
1081 ucom_queue_command(sc, ucom_cfg_line_state, NULL,
1082 &sc->sc_line_state_task[0].hdr,
1083 &sc->sc_line_state_task[1].hdr);
1084 }
1085
1086 static void
ucom_ring(struct ucom_softc * sc,uint8_t onoff)1087 ucom_ring(struct ucom_softc *sc, uint8_t onoff)
1088 {
1089 DPRINTF("onoff = %d\n", onoff);
1090
1091 if (onoff)
1092 ucom_line_state(sc, UCOM_LS_RING, 0);
1093 else
1094 ucom_line_state(sc, 0, UCOM_LS_RING);
1095 }
1096
1097 static void
ucom_break(struct ucom_softc * sc,uint8_t onoff)1098 ucom_break(struct ucom_softc *sc, uint8_t onoff)
1099 {
1100 DPRINTF("onoff = %d\n", onoff);
1101
1102 if (onoff)
1103 ucom_line_state(sc, UCOM_LS_BREAK, 0);
1104 else
1105 ucom_line_state(sc, 0, UCOM_LS_BREAK);
1106 }
1107
1108 static void
ucom_dtr(struct ucom_softc * sc,uint8_t onoff)1109 ucom_dtr(struct ucom_softc *sc, uint8_t onoff)
1110 {
1111 DPRINTF("onoff = %d\n", onoff);
1112
1113 if (onoff)
1114 ucom_line_state(sc, UCOM_LS_DTR, 0);
1115 else
1116 ucom_line_state(sc, 0, UCOM_LS_DTR);
1117 }
1118
1119 static void
ucom_rts(struct ucom_softc * sc,uint8_t onoff)1120 ucom_rts(struct ucom_softc *sc, uint8_t onoff)
1121 {
1122 DPRINTF("onoff = %d\n", onoff);
1123
1124 if (onoff)
1125 ucom_line_state(sc, UCOM_LS_RTS, 0);
1126 else
1127 ucom_line_state(sc, 0, UCOM_LS_RTS);
1128 }
1129
1130 static void
ucom_cfg_status_change(struct usb_proc_msg * _task)1131 ucom_cfg_status_change(struct usb_proc_msg *_task)
1132 {
1133 struct ucom_cfg_task *task =
1134 (struct ucom_cfg_task *)_task;
1135 struct ucom_softc *sc = task->sc;
1136 struct tty *tp;
1137 int onoff;
1138 uint8_t new_msr;
1139 uint8_t new_lsr;
1140 uint8_t msr_delta;
1141 uint8_t lsr_delta;
1142 uint8_t pps_signal;
1143
1144 tp = sc->sc_tty;
1145
1146 UCOM_MTX_ASSERT(sc, MA_OWNED);
1147
1148 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1149 return;
1150 }
1151 if (sc->sc_callback->ucom_cfg_get_status == NULL) {
1152 return;
1153 }
1154 /* get status */
1155
1156 new_msr = 0;
1157 new_lsr = 0;
1158
1159 (sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr);
1160
1161 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1162 /* TTY device closed */
1163 return;
1164 }
1165 msr_delta = (sc->sc_msr ^ new_msr);
1166 lsr_delta = (sc->sc_lsr ^ new_lsr);
1167
1168 sc->sc_msr = new_msr;
1169 sc->sc_lsr = new_lsr;
1170
1171 /*
1172 * Time pulse counting support.
1173 */
1174 switch(ucom_pps_mode & UART_PPS_SIGNAL_MASK) {
1175 case UART_PPS_CTS:
1176 pps_signal = SER_CTS;
1177 break;
1178 case UART_PPS_DCD:
1179 pps_signal = SER_DCD;
1180 break;
1181 default:
1182 pps_signal = 0;
1183 break;
1184 }
1185
1186 if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) &&
1187 (msr_delta & pps_signal)) {
1188 pps_capture(&sc->sc_pps);
1189 onoff = (sc->sc_msr & pps_signal) ? 1 : 0;
1190 if (ucom_pps_mode & UART_PPS_INVERT_PULSE)
1191 onoff = !onoff;
1192 pps_event(&sc->sc_pps, onoff ? PPS_CAPTUREASSERT :
1193 PPS_CAPTURECLEAR);
1194 }
1195
1196 if (msr_delta & SER_DCD) {
1197 onoff = (sc->sc_msr & SER_DCD) ? 1 : 0;
1198
1199 DPRINTF("DCD changed to %d\n", onoff);
1200
1201 ttydisc_modem(tp, onoff);
1202 }
1203
1204 if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) {
1205 DPRINTF("BREAK detected\n");
1206
1207 ttydisc_rint(tp, 0, TRE_BREAK);
1208 ttydisc_rint_done(tp);
1209 }
1210
1211 if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) {
1212 DPRINTF("Frame error detected\n");
1213
1214 ttydisc_rint(tp, 0, TRE_FRAMING);
1215 ttydisc_rint_done(tp);
1216 }
1217
1218 if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) {
1219 DPRINTF("Parity error detected\n");
1220
1221 ttydisc_rint(tp, 0, TRE_PARITY);
1222 ttydisc_rint_done(tp);
1223 }
1224 }
1225
1226 void
ucom_status_change(struct ucom_softc * sc)1227 ucom_status_change(struct ucom_softc *sc)
1228 {
1229 UCOM_MTX_ASSERT(sc, MA_OWNED);
1230
1231 if (sc->sc_flag & UCOM_FLAG_CONSOLE)
1232 return; /* not supported */
1233
1234 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1235 return;
1236 }
1237 DPRINTF("\n");
1238
1239 ucom_queue_command(sc, ucom_cfg_status_change, NULL,
1240 &sc->sc_status_task[0].hdr,
1241 &sc->sc_status_task[1].hdr);
1242 }
1243
1244 static void
ucom_cfg_param(struct usb_proc_msg * _task)1245 ucom_cfg_param(struct usb_proc_msg *_task)
1246 {
1247 struct ucom_param_task *task =
1248 (struct ucom_param_task *)_task;
1249 struct ucom_softc *sc = task->sc;
1250
1251 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1252 return;
1253 }
1254 if (sc->sc_callback->ucom_cfg_param == NULL) {
1255 return;
1256 }
1257
1258 (sc->sc_callback->ucom_cfg_param) (sc, &task->termios_copy);
1259
1260 /* wait a little */
1261 usb_pause_mtx(sc->sc_mtx, hz / 10);
1262 }
1263
1264 static int
ucom_param(struct tty * tp,struct termios * t)1265 ucom_param(struct tty *tp, struct termios *t)
1266 {
1267 struct ucom_softc *sc = tty_softc(tp);
1268 uint8_t opened;
1269 int error;
1270
1271 UCOM_MTX_ASSERT(sc, MA_OWNED);
1272
1273 opened = 0;
1274 error = 0;
1275
1276 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1277 /* XXX the TTY layer should call "open()" first! */
1278 /*
1279 * Not quite: Its ordering is partly backwards, but
1280 * some parameters must be set early in ttydev_open(),
1281 * possibly before calling ttydevsw_open().
1282 */
1283 error = ucom_open(tp);
1284 if (error)
1285 goto done;
1286
1287 opened = 1;
1288 }
1289 DPRINTF("sc = %p\n", sc);
1290
1291 /* Check requested parameters. */
1292 if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) {
1293 /* XXX c_ospeed == 0 is perfectly valid. */
1294 DPRINTF("mismatch ispeed and ospeed\n");
1295 error = EINVAL;
1296 goto done;
1297 }
1298 t->c_ispeed = t->c_ospeed;
1299
1300 if (sc->sc_callback->ucom_pre_param) {
1301 /* Let the lower layer verify the parameters */
1302 error = (sc->sc_callback->ucom_pre_param) (sc, t);
1303 if (error) {
1304 DPRINTF("callback error = %d\n", error);
1305 goto done;
1306 }
1307 }
1308
1309 /* Disable transfers */
1310 sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
1311
1312 /* Queue baud rate programming command first */
1313 ucom_queue_command(sc, ucom_cfg_param, t,
1314 &sc->sc_param_task[0].hdr,
1315 &sc->sc_param_task[1].hdr);
1316
1317 /* Queue transfer enable command last */
1318 ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
1319 &sc->sc_start_task[0].hdr,
1320 &sc->sc_start_task[1].hdr);
1321
1322 if (t->c_cflag & CRTS_IFLOW) {
1323 sc->sc_flag |= UCOM_FLAG_RTS_IFLOW;
1324 } else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) {
1325 sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW;
1326 ucom_modem(tp, SER_RTS, 0);
1327 }
1328 done:
1329 if (error) {
1330 if (opened) {
1331 ucom_close(tp);
1332 }
1333 }
1334 return (error);
1335 }
1336
1337 static void
ucom_outwakeup(struct tty * tp)1338 ucom_outwakeup(struct tty *tp)
1339 {
1340 struct ucom_softc *sc = tty_softc(tp);
1341
1342 UCOM_MTX_ASSERT(sc, MA_OWNED);
1343
1344 DPRINTF("sc = %p\n", sc);
1345
1346 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1347 /* The higher layer is not ready */
1348 return;
1349 }
1350 ucom_start_transfers(sc);
1351 }
1352
1353 static bool
ucom_busy(struct tty * tp)1354 ucom_busy(struct tty *tp)
1355 {
1356 struct ucom_softc *sc = tty_softc(tp);
1357 const uint8_t txidle = ULSR_TXRDY | ULSR_TSRE;
1358
1359 UCOM_MTX_ASSERT(sc, MA_OWNED);
1360
1361 DPRINTFN(3, "sc = %p lsr 0x%02x\n", sc, sc->sc_lsr);
1362
1363 /*
1364 * If the driver maintains the txidle bits in LSR, we can use them to
1365 * determine whether the transmitter is busy or idle. Otherwise we have
1366 * to assume it is idle to avoid hanging forever on tcdrain(3).
1367 */
1368 if (sc->sc_flag & UCOM_FLAG_LSRTXIDLE)
1369 return ((sc->sc_lsr & txidle) != txidle);
1370 else
1371 return (false);
1372 }
1373
1374 /*------------------------------------------------------------------------*
1375 * ucom_get_data
1376 *
1377 * Return values:
1378 * 0: No data is available.
1379 * Else: Data is available.
1380 *------------------------------------------------------------------------*/
1381 uint8_t
ucom_get_data(struct ucom_softc * sc,struct usb_page_cache * pc,uint32_t offset,uint32_t len,uint32_t * actlen)1382 ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1383 uint32_t offset, uint32_t len, uint32_t *actlen)
1384 {
1385 struct usb_page_search res;
1386 struct tty *tp = sc->sc_tty;
1387 uint32_t cnt;
1388 uint32_t offset_orig;
1389
1390 UCOM_MTX_ASSERT(sc, MA_OWNED);
1391
1392 if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1393 unsigned temp;
1394
1395 /* get total TX length */
1396
1397 temp = ucom_cons_tx_high - ucom_cons_tx_low;
1398 temp %= UCOM_CONS_BUFSIZE;
1399
1400 /* limit TX length */
1401
1402 if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low))
1403 temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low);
1404
1405 if (temp > len)
1406 temp = len;
1407
1408 /* copy in data */
1409
1410 usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp);
1411
1412 /* update counters */
1413
1414 ucom_cons_tx_low += temp;
1415 ucom_cons_tx_low %= UCOM_CONS_BUFSIZE;
1416
1417 /* store actual length */
1418
1419 *actlen = temp;
1420
1421 return (temp ? 1 : 0);
1422 }
1423
1424 if (tty_gone(tp) ||
1425 !(sc->sc_flag & UCOM_FLAG_GP_DATA)) {
1426 actlen[0] = 0;
1427 return (0); /* multiport device polling */
1428 }
1429 offset_orig = offset;
1430
1431 while (len != 0) {
1432 usbd_get_page(pc, offset, &res);
1433
1434 if (res.length > len) {
1435 res.length = len;
1436 }
1437 /* copy data directly into USB buffer */
1438 cnt = ttydisc_getc(tp, res.buffer, res.length);
1439
1440 offset += cnt;
1441 len -= cnt;
1442
1443 if (cnt < res.length) {
1444 /* end of buffer */
1445 break;
1446 }
1447 }
1448
1449 actlen[0] = offset - offset_orig;
1450
1451 DPRINTF("cnt=%d\n", actlen[0]);
1452
1453 if (actlen[0] == 0) {
1454 return (0);
1455 }
1456 return (1);
1457 }
1458
1459 void
ucom_put_data(struct ucom_softc * sc,struct usb_page_cache * pc,uint32_t offset,uint32_t len)1460 ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1461 uint32_t offset, uint32_t len)
1462 {
1463 struct usb_page_search res;
1464 struct tty *tp = sc->sc_tty;
1465 char *buf;
1466 uint32_t cnt;
1467
1468 UCOM_MTX_ASSERT(sc, MA_OWNED);
1469
1470 if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1471 unsigned temp;
1472
1473 /* get maximum RX length */
1474
1475 temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low;
1476 temp %= UCOM_CONS_BUFSIZE;
1477
1478 /* limit RX length */
1479
1480 if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high))
1481 temp = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high);
1482
1483 if (temp > len)
1484 temp = len;
1485
1486 /* copy out data */
1487
1488 usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp);
1489
1490 /* update counters */
1491
1492 ucom_cons_rx_high += temp;
1493 ucom_cons_rx_high %= UCOM_CONS_BUFSIZE;
1494
1495 return;
1496 }
1497
1498 if (tty_gone(tp))
1499 return; /* multiport device polling */
1500
1501 if (len == 0)
1502 return; /* no data */
1503
1504 /* set a flag to prevent recursation ? */
1505
1506 while (len > 0) {
1507 usbd_get_page(pc, offset, &res);
1508
1509 if (res.length > len) {
1510 res.length = len;
1511 }
1512 len -= res.length;
1513 offset += res.length;
1514
1515 /* pass characters to tty layer */
1516
1517 buf = res.buffer;
1518 cnt = res.length;
1519
1520 /* first check if we can pass the buffer directly */
1521
1522 if (ttydisc_can_bypass(tp)) {
1523 /* clear any jitter buffer */
1524 sc->sc_jitterbuf_in = 0;
1525 sc->sc_jitterbuf_out = 0;
1526
1527 if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) {
1528 DPRINTF("tp=%p, data lost\n", tp);
1529 }
1530 continue;
1531 }
1532 /* need to loop */
1533
1534 for (cnt = 0; cnt != res.length; cnt++) {
1535 if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out ||
1536 ttydisc_rint(tp, buf[cnt], 0) == -1) {
1537 uint16_t end;
1538 uint16_t pos;
1539
1540 pos = sc->sc_jitterbuf_in;
1541 end = sc->sc_jitterbuf_out +
1542 UCOM_JITTERBUF_SIZE - 1;
1543 if (end >= UCOM_JITTERBUF_SIZE)
1544 end -= UCOM_JITTERBUF_SIZE;
1545
1546 for (; cnt != res.length; cnt++) {
1547 if (pos == end)
1548 break;
1549 sc->sc_jitterbuf[pos] = buf[cnt];
1550 pos++;
1551 if (pos >= UCOM_JITTERBUF_SIZE)
1552 pos -= UCOM_JITTERBUF_SIZE;
1553 }
1554
1555 sc->sc_jitterbuf_in = pos;
1556
1557 /* set RTS in async fashion */
1558 if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)
1559 ucom_rts(sc, 1);
1560
1561 DPRINTF("tp=%p, lost %d "
1562 "chars\n", tp, res.length - cnt);
1563 break;
1564 }
1565 }
1566 }
1567 ttydisc_rint_done(tp);
1568 }
1569
1570 static void
ucom_free(void * xsc)1571 ucom_free(void *xsc)
1572 {
1573 struct ucom_softc *sc = xsc;
1574
1575 if (sc->sc_callback->ucom_free != NULL)
1576 sc->sc_callback->ucom_free(sc);
1577 else
1578 ucom_unref(sc->sc_super);
1579
1580 mtx_lock(&ucom_mtx);
1581 ucom_close_refs--;
1582 mtx_unlock(&ucom_mtx);
1583 }
1584
1585 CONSOLE_DRIVER(ucom);
1586
1587 static void
ucom_cnprobe(struct consdev * cp)1588 ucom_cnprobe(struct consdev *cp)
1589 {
1590 if (ucom_cons_unit != -1)
1591 cp->cn_pri = CN_NORMAL;
1592 else
1593 cp->cn_pri = CN_DEAD;
1594
1595 strlcpy(cp->cn_name, "ucom", sizeof(cp->cn_name));
1596 }
1597
1598 static void
ucom_cninit(struct consdev * cp)1599 ucom_cninit(struct consdev *cp)
1600 {
1601 }
1602
1603 static void
ucom_cnterm(struct consdev * cp)1604 ucom_cnterm(struct consdev *cp)
1605 {
1606 }
1607
1608 static void
ucom_cngrab(struct consdev * cp)1609 ucom_cngrab(struct consdev *cp)
1610 {
1611 }
1612
1613 static void
ucom_cnungrab(struct consdev * cp)1614 ucom_cnungrab(struct consdev *cp)
1615 {
1616 }
1617
1618 static int
ucom_cngetc(struct consdev * cd)1619 ucom_cngetc(struct consdev *cd)
1620 {
1621 struct ucom_softc *sc = ucom_cons_softc;
1622 int c;
1623
1624 if (sc == NULL)
1625 return (-1);
1626
1627 UCOM_MTX_LOCK(sc);
1628
1629 if (ucom_cons_rx_low != ucom_cons_rx_high) {
1630 c = ucom_cons_rx_buf[ucom_cons_rx_low];
1631 ucom_cons_rx_low ++;
1632 ucom_cons_rx_low %= UCOM_CONS_BUFSIZE;
1633 } else {
1634 c = -1;
1635 }
1636
1637 /* start USB transfers */
1638 ucom_outwakeup(sc->sc_tty);
1639
1640 UCOM_MTX_UNLOCK(sc);
1641
1642 /* poll if necessary */
1643 if (USB_IN_POLLING_MODE_FUNC() && sc->sc_callback->ucom_poll)
1644 (sc->sc_callback->ucom_poll) (sc);
1645
1646 return (c);
1647 }
1648
1649 static void
ucom_cnputc(struct consdev * cd,int c)1650 ucom_cnputc(struct consdev *cd, int c)
1651 {
1652 struct ucom_softc *sc = ucom_cons_softc;
1653 unsigned temp;
1654
1655 if (sc == NULL)
1656 return;
1657
1658 repeat:
1659
1660 UCOM_MTX_LOCK(sc);
1661
1662 /* compute maximum TX length */
1663
1664 temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low;
1665 temp %= UCOM_CONS_BUFSIZE;
1666
1667 if (temp) {
1668 ucom_cons_tx_buf[ucom_cons_tx_high] = c;
1669 ucom_cons_tx_high ++;
1670 ucom_cons_tx_high %= UCOM_CONS_BUFSIZE;
1671 }
1672
1673 /* start USB transfers */
1674 ucom_outwakeup(sc->sc_tty);
1675
1676 UCOM_MTX_UNLOCK(sc);
1677
1678 /* poll if necessary */
1679 if (USB_IN_POLLING_MODE_FUNC() && sc->sc_callback->ucom_poll) {
1680 (sc->sc_callback->ucom_poll) (sc);
1681 /* simple flow control */
1682 if (temp == 0)
1683 goto repeat;
1684 }
1685 }
1686
1687 /*------------------------------------------------------------------------*
1688 * ucom_ref
1689 *
1690 * This function will increment the super UCOM reference count.
1691 *------------------------------------------------------------------------*/
1692 void
ucom_ref(struct ucom_super_softc * ssc)1693 ucom_ref(struct ucom_super_softc *ssc)
1694 {
1695 mtx_lock(&ucom_mtx);
1696 ssc->sc_refs++;
1697 mtx_unlock(&ucom_mtx);
1698 }
1699
1700 /*------------------------------------------------------------------------*
1701 * ucom_free_unit
1702 *
1703 * This function will free the super UCOM's allocated unit
1704 * number. This function can be called on a zero-initialized
1705 * structure. This function can be called multiple times.
1706 *------------------------------------------------------------------------*/
1707 static void
ucom_free_unit(struct ucom_super_softc * ssc)1708 ucom_free_unit(struct ucom_super_softc *ssc)
1709 {
1710 if (!(ssc->sc_flag & UCOM_FLAG_FREE_UNIT))
1711 return;
1712
1713 ucom_unit_free(ssc->sc_unit);
1714
1715 ssc->sc_flag &= ~UCOM_FLAG_FREE_UNIT;
1716 }
1717
1718 /*------------------------------------------------------------------------*
1719 * ucom_unref
1720 *
1721 * This function will decrement the super UCOM reference count.
1722 *
1723 * Return values:
1724 * 0: UCOM structures are still referenced.
1725 * Else: UCOM structures are no longer referenced.
1726 *------------------------------------------------------------------------*/
1727 int
ucom_unref(struct ucom_super_softc * ssc)1728 ucom_unref(struct ucom_super_softc *ssc)
1729 {
1730 int retval;
1731
1732 mtx_lock(&ucom_mtx);
1733 retval = (ssc->sc_refs < 2);
1734 ssc->sc_refs--;
1735 mtx_unlock(&ucom_mtx);
1736
1737 if (retval)
1738 ucom_free_unit(ssc);
1739
1740 return (retval);
1741 }
1742
1743 #if defined(GDB)
1744
1745 #include <gdb/gdb.h>
1746
1747 static gdb_probe_f ucom_gdbprobe;
1748 static gdb_init_f ucom_gdbinit;
1749 static gdb_term_f ucom_gdbterm;
1750 static gdb_getc_f ucom_gdbgetc;
1751 static gdb_putc_f ucom_gdbputc;
1752
1753 GDB_DBGPORT(ucom, ucom_gdbprobe, ucom_gdbinit, ucom_gdbterm, ucom_gdbgetc, ucom_gdbputc);
1754
1755 static int
ucom_gdbprobe(void)1756 ucom_gdbprobe(void)
1757 {
1758 return ((ucom_cons_softc != NULL) ? 0 : -1);
1759 }
1760
1761 static void
ucom_gdbinit(void)1762 ucom_gdbinit(void)
1763 {
1764 }
1765
1766 static void
ucom_gdbterm(void)1767 ucom_gdbterm(void)
1768 {
1769 }
1770
1771 static void
ucom_gdbputc(int c)1772 ucom_gdbputc(int c)
1773 {
1774 ucom_cnputc(NULL, c);
1775 }
1776
1777 static int
ucom_gdbgetc(void)1778 ucom_gdbgetc(void)
1779 {
1780 return (ucom_cngetc(NULL));
1781 }
1782
1783 #endif
1784