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