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