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 /*- 31 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 32 * All rights reserved. 33 * 34 * This code is derived from software contributed to The NetBSD Foundation 35 * by Lennart Augustsson (lennart@augustsson.net) at 36 * Carlstedt Research & Technology. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by the NetBSD 49 * Foundation, Inc. and its contributors. 50 * 4. Neither the name of The NetBSD Foundation nor the names of its 51 * contributors may be used to endorse or promote products derived 52 * from this software without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 55 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 56 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 57 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 58 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 64 * POSSIBILITY OF SUCH DAMAGE. 65 */ 66 67 /* 68 * XXX profmakx 69 * This is a Frankenstein of FreeBSD's usb4bsd ucom and Dragonfly's old ucom 70 * module. There might be bugs lurking everywhere still 71 * 72 * In particular serial console on ucom is completely untested and likely broken 73 * as well as anyting that requires the modem control lines. 74 */ 75 76 #include <sys/stdint.h> 77 #include <sys/param.h> 78 #include <sys/queue.h> 79 #include <sys/types.h> 80 #include <sys/systm.h> 81 #include <sys/kernel.h> 82 #include <sys/bus.h> 83 #include <sys/module.h> 84 #include <sys/lock.h> 85 #include <sys/condvar.h> 86 #include <sys/sysctl.h> 87 #include <sys/unistd.h> 88 #include <sys/callout.h> 89 #include <sys/malloc.h> 90 #include <sys/priv.h> 91 #include <sys/cons.h> 92 #include <sys/serial.h> 93 #include <sys/thread2.h> 94 #include <sys/conf.h> 95 #include <sys/clist.h> 96 97 #include <bus/u4b/usb.h> 98 #include <bus/u4b/usbdi.h> 99 #include <bus/u4b/usbdi_util.h> 100 101 #define USB_DEBUG_VAR ucom_debug 102 #include <bus/u4b/usb_debug.h> 103 #include <bus/u4b/usb_busdma.h> 104 #include <bus/u4b/usb_process.h> 105 106 #include <bus/u4b/serial/usb_serial.h> 107 108 //#include "opt_gdb.h" 109 110 static SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom"); 111 112 static int ucom_pps_mode; 113 114 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, pps_mode, CTLFLAG_RW, 115 &ucom_pps_mode, 0, "pulse capturing mode - 0/1/2 - disabled/CTS/DCD"); 116 TUNABLE_INT("hw.usb.ucom.pss_mode", &ucom_pps_mode); 117 118 119 #ifdef USB_DEBUG 120 static int ucom_debug = 0; 121 122 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RW, 123 &ucom_debug, 0, "ucom debug level"); 124 #endif 125 126 #define UCOM_CONS_BUFSIZE 1024 127 128 static uint8_t ucom_cons_rx_buf[UCOM_CONS_BUFSIZE]; 129 static uint8_t ucom_cons_tx_buf[UCOM_CONS_BUFSIZE]; 130 131 static unsigned int ucom_cons_rx_low = 0; 132 static unsigned int ucom_cons_rx_high = 0; 133 134 static unsigned int ucom_cons_tx_low = 0; 135 static unsigned int ucom_cons_tx_high = 0; 136 137 static int ucom_cons_unit = -1; 138 static int ucom_cons_subunit = 0; 139 static int ucom_cons_baud = 9600; 140 static struct ucom_softc *ucom_cons_softc = NULL; 141 142 TUNABLE_INT("hw.usb.ucom.cons_unit", &ucom_cons_unit); 143 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RW, 144 &ucom_cons_unit, 0, "console unit number"); 145 TUNABLE_INT("hw.usb.ucom.cons_subunit", &ucom_cons_subunit); 146 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RW, 147 &ucom_cons_subunit, 0, "console subunit number"); 148 TUNABLE_INT("hw.usb.ucom.cons_baud", &ucom_cons_baud); 149 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RW, 150 &ucom_cons_baud, 0, "console baud rate"); 151 152 static usb_proc_callback_t ucom_cfg_start_transfers; 153 static usb_proc_callback_t ucom_cfg_open; 154 static usb_proc_callback_t ucom_cfg_close; 155 static usb_proc_callback_t ucom_cfg_line_state; 156 static usb_proc_callback_t ucom_cfg_status_change; 157 static usb_proc_callback_t ucom_cfg_param; 158 159 static int ucom_unit_alloc(void); 160 static void ucom_unit_free(int); 161 static int ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *); 162 static void ucom_detach_tty(struct ucom_super_softc *, struct ucom_softc *); 163 static void ucom_queue_command(struct ucom_softc *, 164 usb_proc_callback_t *, struct termios *pt, 165 struct usb_proc_msg *t0, struct usb_proc_msg *t1); 166 static void ucom_shutdown(struct ucom_softc *); 167 static void ucom_ring(struct ucom_softc *, uint8_t); 168 static void ucom_break(struct ucom_softc *, uint8_t); 169 static void ucom_dtr(struct ucom_softc *, uint8_t); 170 static void ucom_rts(struct ucom_softc *, uint8_t); 171 172 static int ucom_open(struct ucom_softc *sc); 173 static int ucom_close(struct ucom_softc *sc); 174 static void ucom_start(struct tty *tp); 175 static void ucom_stop(struct tty *tp, int); 176 static int ucom_param(struct tty *tp, struct termios *t); 177 static int ucom_modem(struct tty *tp, int sigon, int sigoff); 178 179 static int ucom_fromtio(int); 180 static int ucom_totio(int); 181 182 static void disc_optim(struct tty *, struct termios *, struct ucom_softc *); 183 184 static d_open_t ucom_dev_open; 185 static d_close_t ucom_dev_close; 186 static d_read_t ucom_dev_read; 187 static d_write_t ucom_dev_write; 188 static d_ioctl_t ucom_dev_ioctl; 189 190 static struct dev_ops ucom_ops = { 191 { "ucom", 0, D_MPSAFE | D_TTY }, 192 .d_open = ucom_dev_open, 193 .d_close = ucom_dev_close, 194 .d_read = ucom_dev_read, 195 .d_write = ucom_dev_write, 196 .d_ioctl = ucom_dev_ioctl, 197 .d_kqfilter = ttykqfilter, 198 .d_revoke = ttyrevoke 199 }; 200 201 static moduledata_t ucom_mod = { 202 "ucom", 203 NULL, 204 NULL 205 }; 206 207 DECLARE_MODULE(ucom, ucom_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 208 MODULE_DEPEND(ucom, usb, 1, 1, 1); 209 MODULE_VERSION(ucom, UCOM_MODVER); 210 211 /* XXXDF */ 212 #define tty_gone(tp) ((tp->t_state) & (TS_ZOMBIE)) 213 214 #define UCOM_UNIT_MAX 128 /* maximum number of units */ 215 #define UCOM_TTY_PREFIX "ucom" 216 217 218 #define CALLOUT_MASK 0x80 219 #define CONTROL_MASK 0x60 220 #define CONTROL_INIT_STATE 0x20 221 #define CONTROL_LOCK_STATE 0x40 222 223 static struct unrhdr *ucom_unrhdr; 224 static struct lock ucom_lock; 225 static int ucom_close_refs; 226 227 static void 228 ucom_init(void *arg) 229 { 230 DPRINTF("\n"); 231 ucom_unrhdr = new_unrhdr(0, UCOM_UNIT_MAX - 1, NULL); 232 lockinit(&ucom_lock, "UCOM LOCK", 0, 0); 233 } 234 SYSINIT(ucom_init, SI_BOOT2_KLD - 1, SI_ORDER_ANY, ucom_init, NULL); 235 236 static void 237 ucom_uninit(void *arg) 238 { 239 struct unrhdr *hdr; 240 hdr = ucom_unrhdr; 241 ucom_unrhdr = NULL; 242 243 DPRINTF("\n"); 244 245 if (hdr != NULL) 246 delete_unrhdr(hdr); 247 248 lockuninit(&ucom_lock); 249 } 250 SYSUNINIT(ucom_uninit, SI_BOOT2_KLD - 2, SI_ORDER_ANY, ucom_uninit, NULL); 251 252 /* 253 * Mark a unit number (the X in cuaUX) as in use. 254 * 255 * Note that devices using a different naming scheme (see ucom_tty_name() 256 * callback) still use this unit allocation. 257 */ 258 static int 259 ucom_unit_alloc(void) 260 { 261 int unit; 262 263 /* sanity checks */ 264 if (ucom_unrhdr == NULL) { 265 DPRINTF("ucom_unrhdr is NULL\n"); 266 return (-1); 267 } 268 unit = alloc_unr(ucom_unrhdr); 269 DPRINTF("unit %d is allocated\n", unit); 270 return (unit); 271 } 272 273 /* 274 * Mark the unit number as not in use. 275 */ 276 static void 277 ucom_unit_free(int unit) 278 { 279 /* sanity checks */ 280 if (unit < 0 || unit >= UCOM_UNIT_MAX || ucom_unrhdr == NULL) { 281 DPRINTF("cannot free unit number\n"); 282 return; 283 } 284 DPRINTF("unit %d is freed\n", unit); 285 free_unr(ucom_unrhdr, unit); 286 } 287 288 /* 289 * Setup a group of one or more serial ports. 290 * 291 * The lock pointed to by "lock" is applied before all 292 * callbacks are called back. Also "lock" must be applied 293 * before calling into the ucom-layer! 294 */ 295 int 296 ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc, 297 int subunits, void *parent, 298 const struct ucom_callback *callback, struct lock *lock) 299 { 300 int subunit; 301 int error = 0; 302 303 if ((sc == NULL) || 304 (subunits <= 0) || 305 (callback == NULL) || 306 (lock == NULL)) { 307 return (EINVAL); 308 } 309 310 /* XXX Do we want our own lock here maybe */ 311 sc->sc_lock = lock; 312 313 /* allocate a uniq unit number */ 314 ssc->sc_unit = ucom_unit_alloc(); 315 if (ssc->sc_unit == -1) 316 return (ENOMEM); 317 318 /* generate TTY name string */ 319 ksnprintf(ssc->sc_ttyname, sizeof(ssc->sc_ttyname), 320 UCOM_TTY_PREFIX "%d", ssc->sc_unit); 321 322 /* create USB request handling process */ 323 error = usb_proc_create(&ssc->sc_tq, lock, "ucom", USB_PRI_MED); 324 if (error) { 325 ucom_unit_free(ssc->sc_unit); 326 return (error); 327 } 328 ssc->sc_subunits = subunits; 329 ssc->sc_flag = UCOM_FLAG_ATTACHED | 330 UCOM_FLAG_FREE_UNIT; 331 332 if (callback->ucom_free == NULL) 333 ssc->sc_flag |= UCOM_FLAG_WAIT_REFS; 334 335 /* increment reference count */ 336 ucom_ref(ssc); 337 338 for (subunit = 0; subunit < ssc->sc_subunits; subunit++) { 339 sc[subunit].sc_subunit = subunit; 340 sc[subunit].sc_super = ssc; 341 sc[subunit].sc_lock = lock; 342 sc[subunit].sc_parent = parent; 343 sc[subunit].sc_callback = callback; 344 345 error = ucom_attach_tty(ssc, &sc[subunit]); 346 if (error) { 347 ucom_detach(ssc, &sc[0]); 348 return (error); 349 } 350 /* increment reference count */ 351 ucom_ref(ssc); 352 353 /* set subunit attached */ 354 sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED; 355 } 356 357 DPRINTF("tp = %p, unit = %d, subunits = %d\n", 358 sc->sc_tty, ssc->sc_unit, ssc->sc_subunits); 359 360 return (0); 361 } 362 363 /* 364 * The following function will do nothing if the structure pointed to 365 * by "ssc" and "sc" is zero or has already been detached. 366 */ 367 void 368 ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc) 369 { 370 int subunit; 371 372 if (!(ssc->sc_flag & UCOM_FLAG_ATTACHED)) 373 return; /* not initialized */ 374 375 destroy_dev(sc->sc_cdev); 376 destroy_dev(sc->sc_cdev_init); 377 destroy_dev(sc->sc_cdev_lock); 378 destroy_dev(sc->sc_cdev2); 379 destroy_dev(sc->sc_cdev2_init); 380 destroy_dev(sc->sc_cdev2_lock); 381 382 lwkt_gettoken(&tty_token); 383 384 if (ssc->sc_sysctl_ttyname != NULL) { 385 sysctl_remove_oid(ssc->sc_sysctl_ttyname, 1, 0); 386 ssc->sc_sysctl_ttyname = NULL; 387 } 388 389 if (ssc->sc_sysctl_ttyports != NULL) { 390 sysctl_remove_oid(ssc->sc_sysctl_ttyports, 1, 0); 391 ssc->sc_sysctl_ttyports = NULL; 392 } 393 394 usb_proc_drain(&ssc->sc_tq); 395 396 for (subunit = 0; subunit < ssc->sc_subunits; subunit++) { 397 if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) { 398 ucom_detach_tty(ssc, &sc[subunit]); 399 400 /* avoid duplicate detach */ 401 sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED; 402 } 403 } 404 usb_proc_free(&ssc->sc_tq); 405 406 ucom_unref(ssc); 407 408 if (ssc->sc_flag & UCOM_FLAG_WAIT_REFS) 409 ucom_drain(ssc); 410 411 /* make sure we don't detach twice */ 412 ssc->sc_flag &= ~UCOM_FLAG_ATTACHED; 413 414 lwkt_reltoken(&tty_token); 415 } 416 417 void 418 ucom_drain(struct ucom_super_softc *ssc) 419 { 420 lockmgr(&ucom_lock, LK_EXCLUSIVE); 421 while (ssc->sc_refs > 0) { 422 kprintf("ucom: Waiting for a TTY device to close.\n"); 423 usb_pause_mtx(&ucom_lock, hz); 424 } 425 lockmgr(&ucom_lock, LK_RELEASE); 426 } 427 428 void 429 ucom_drain_all(void *arg) 430 { 431 lockmgr(&ucom_lock, LK_EXCLUSIVE); 432 while (ucom_close_refs > 0) { 433 kprintf("ucom: Waiting for all detached TTY " 434 "devices to have open fds closed.\n"); 435 usb_pause_mtx(&ucom_lock, hz); 436 } 437 lockmgr(&ucom_lock, LK_RELEASE); 438 } 439 440 static int 441 ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) 442 { 443 struct tty *tp; 444 char buf[32]; /* temporary TTY device name buffer */ 445 446 lwkt_gettoken(&tty_token); 447 448 sc->sc_tty = tp = ttymalloc(sc->sc_tty); 449 450 if (tp == NULL) { 451 lwkt_reltoken(&tty_token); 452 return (ENOMEM); 453 } 454 455 tp->t_sc = (void *)sc; 456 457 tp->t_oproc = ucom_start; 458 tp->t_param = ucom_param; 459 tp->t_stop = ucom_stop; 460 461 /* Check if the client has a custom TTY name */ 462 buf[0] = '\0'; 463 if (sc->sc_callback->ucom_tty_name) { 464 sc->sc_callback->ucom_tty_name(sc, buf, 465 sizeof(buf), ssc->sc_unit, sc->sc_subunit); 466 } 467 if (buf[0] == 0) { 468 /* Use default TTY name */ 469 if (ssc->sc_subunits > 1) { 470 /* multiple modems in one */ 471 ksnprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u.%u", 472 ssc->sc_unit, sc->sc_subunit); 473 } else { 474 /* single modem */ 475 ksnprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u", 476 ssc->sc_unit); 477 } 478 } 479 480 sc->sc_cdev = make_dev(&ucom_ops, ssc->sc_unit, 481 UID_ROOT, GID_WHEEL, 0600, "ttyU%r", ssc->sc_unit); 482 sc->sc_cdev_init = make_dev(&ucom_ops, ssc->sc_unit | CONTROL_INIT_STATE, 483 UID_ROOT, GID_WHEEL, 0600, "ttyiU%r", ssc->sc_unit); 484 sc->sc_cdev_lock = make_dev(&ucom_ops, ssc->sc_unit | CONTROL_LOCK_STATE, 485 UID_ROOT, GID_WHEEL, 0600, "ttylU%r", ssc->sc_unit); 486 sc->sc_cdev2 = make_dev(&ucom_ops, ssc->sc_unit | CALLOUT_MASK, 487 UID_UUCP, GID_DIALER, 0660, "cuaU%r", ssc->sc_unit); 488 sc->sc_cdev2_init = make_dev(&ucom_ops, ssc->sc_unit | CALLOUT_MASK | CONTROL_INIT_STATE, 489 UID_UUCP, GID_DIALER, 0660, "cuaiU%r", ssc->sc_unit); 490 sc->sc_cdev2_lock = make_dev(&ucom_ops, ssc->sc_unit | CALLOUT_MASK | CONTROL_LOCK_STATE, 491 UID_UUCP, GID_DIALER, 0660, "cualU%r", ssc->sc_unit); 492 493 sc->sc_cdev->si_tty = tp; 494 sc->sc_cdev_init->si_tty = tp; 495 sc->sc_cdev_lock->si_tty = tp; 496 497 sc->sc_cdev->si_drv1 = sc; 498 sc->sc_cdev_init->si_drv1 = sc; 499 sc->sc_cdev_lock->si_drv1 = sc; 500 501 sc->sc_cdev2->si_drv1 = sc; 502 sc->sc_cdev2_init->si_drv1 = sc; 503 sc->sc_cdev2_lock->si_drv1 = sc; 504 505 sc->sc_tty = tp; 506 507 DPRINTF("ttycreate: %s\n", buf); 508 509 /* Check if this device should be a console */ 510 if ((ucom_cons_softc == NULL) && 511 (ssc->sc_unit == ucom_cons_unit) && 512 (sc->sc_subunit == ucom_cons_subunit)) { 513 514 DPRINTF("unit %d subunit %d is console", 515 ssc->sc_unit, sc->sc_subunit); 516 517 ucom_cons_softc = sc; 518 519 /* XXXDF 520 tty_init_console(tp, ucom_cons_baud); 521 */ 522 tp->t_termios.c_ispeed = ucom_cons_baud; 523 tp->t_termios.c_ospeed = ucom_cons_baud; 524 525 UCOM_MTX_LOCK(ucom_cons_softc); 526 ucom_cons_rx_low = 0; 527 ucom_cons_rx_high = 0; 528 ucom_cons_tx_low = 0; 529 ucom_cons_tx_high = 0; 530 sc->sc_flag |= UCOM_FLAG_CONSOLE; 531 532 ucom_open(ucom_cons_softc); 533 ucom_param(tp, &tp->t_termios); 534 UCOM_MTX_UNLOCK(ucom_cons_softc); 535 } 536 537 lwkt_reltoken(&tty_token); 538 return (0); 539 } 540 541 static void 542 ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) 543 { 544 struct tty *tp = sc->sc_tty; 545 546 DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty); 547 548 if (sc->sc_flag & UCOM_FLAG_CONSOLE) { 549 UCOM_MTX_LOCK(ucom_cons_softc); 550 ucom_close(ucom_cons_softc); 551 sc->sc_flag &= ~UCOM_FLAG_CONSOLE; 552 UCOM_MTX_UNLOCK(ucom_cons_softc); 553 ucom_cons_softc = NULL; 554 } 555 556 /* the config thread has been stopped when we get here */ 557 558 UCOM_MTX_LOCK(sc); 559 sc->sc_flag |= UCOM_FLAG_GONE; 560 sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY); 561 UCOM_MTX_UNLOCK(sc); 562 563 lwkt_gettoken(&tty_token); 564 if (tp != NULL) { 565 ucom_close_refs++; 566 567 UCOM_MTX_LOCK(sc); 568 if (tp->t_state & TS_ISOPEN) { 569 kprintf("device still open, forcing close\n"); 570 (*linesw[tp->t_line].l_close)(tp, 0); 571 ttyclose(tp); 572 } 573 ucom_close(sc); /* close, if any */ 574 575 /* 576 * make sure that read and write transfers are stopped 577 */ 578 if (sc->sc_callback->ucom_stop_read) { 579 (sc->sc_callback->ucom_stop_read) (sc); 580 } 581 if (sc->sc_callback->ucom_stop_write) { 582 (sc->sc_callback->ucom_stop_write) (sc); 583 } 584 UCOM_MTX_UNLOCK(sc); 585 } else { 586 DPRINTF("no tty\n"); 587 } 588 589 dev_ops_remove_minor(&ucom_ops,ssc->sc_unit); 590 591 lwkt_reltoken(&tty_token); 592 ucom_unref(ssc); 593 } 594 595 void 596 ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev) 597 { 598 char buf[64]; 599 uint8_t iface_index; 600 struct usb_attach_arg *uaa; 601 602 ksnprintf(buf, sizeof(buf), "ttyname=" UCOM_TTY_PREFIX 603 "%d ttyports=%d", ssc->sc_unit, ssc->sc_subunits); 604 605 /* Store the PNP info in the first interface for the device */ 606 uaa = device_get_ivars(dev); 607 iface_index = uaa->info.bIfaceIndex; 608 609 if (usbd_set_pnpinfo(uaa->device, iface_index, buf) != 0) 610 device_printf(dev, "Could not set PNP info\n"); 611 612 /* 613 * The following information is also replicated in the PNP-info 614 * string which is registered above: 615 */ 616 if (ssc->sc_sysctl_ttyname == NULL) { 617 /* 618 ssc->sc_sysctl_ttyname = SYSCTL_ADD_STRING(NULL, 619 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 620 OID_AUTO, "ttyname", CTLFLAG_RD, ssc->sc_ttyname, 0, 621 "TTY device basename"); 622 */ 623 } 624 if (ssc->sc_sysctl_ttyports == NULL) { 625 /* 626 ssc->sc_sysctl_ttyports = SYSCTL_ADD_INT(NULL, 627 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 628 OID_AUTO, "ttyports", CTLFLAG_RD, 629 NULL, ssc->sc_subunits, "Number of ports"); 630 */ 631 } 632 } 633 634 static void 635 ucom_queue_command(struct ucom_softc *sc, 636 usb_proc_callback_t *fn, struct termios *pt, 637 struct usb_proc_msg *t0, struct usb_proc_msg *t1) 638 { 639 struct ucom_super_softc *ssc = sc->sc_super; 640 struct ucom_param_task *task; 641 642 UCOM_MTX_ASSERT(sc, MA_OWNED); 643 644 if (usb_proc_is_gone(&ssc->sc_tq)) { 645 DPRINTF("proc is gone\n"); 646 return; /* nothing to do */ 647 } 648 /* 649 * NOTE: The task cannot get executed before we drop the 650 * "sc_lock" lock. It is safe to update fields in the message 651 * structure after that the message got queued. 652 */ 653 task = (struct ucom_param_task *) 654 usb_proc_msignal(&ssc->sc_tq, t0, t1); 655 656 /* Setup callback and softc pointers */ 657 task->hdr.pm_callback = fn; 658 task->sc = sc; 659 660 /* 661 * Make a copy of the termios. This field is only present if 662 * the "pt" field is not NULL. 663 */ 664 if (pt != NULL) 665 task->termios_copy = *pt; 666 667 /* 668 * Closing the device should be synchronous. 669 */ 670 if (fn == ucom_cfg_close) 671 usb_proc_mwait(&ssc->sc_tq, t0, t1); 672 673 /* 674 * In case of multiple configure requests, 675 * keep track of the last one! 676 */ 677 if (fn == ucom_cfg_start_transfers) 678 sc->sc_last_start_xfer = &task->hdr; 679 } 680 681 static void 682 ucom_shutdown(struct ucom_softc *sc) 683 { 684 struct tty *tp = sc->sc_tty; 685 686 UCOM_MTX_ASSERT(sc, MA_OWNED); 687 688 DPRINTF("\n"); 689 690 /* 691 * Hang up if necessary: 692 */ 693 if (tp->t_termios.c_cflag & HUPCL) { 694 ucom_modem(tp, 0, SER_DTR); 695 } 696 } 697 698 /* 699 * Return values: 700 * 0: normal 701 * else: taskqueue is draining or gone 702 */ 703 uint8_t 704 ucom_cfg_is_gone(struct ucom_softc *sc) 705 { 706 struct ucom_super_softc *ssc = sc->sc_super; 707 708 return (usb_proc_is_gone(&ssc->sc_tq)); 709 } 710 711 static void 712 ucom_cfg_start_transfers(struct usb_proc_msg *_task) 713 { 714 struct ucom_cfg_task *task = 715 (struct ucom_cfg_task *)_task; 716 struct ucom_softc *sc = task->sc; 717 718 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 719 return; 720 } 721 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 722 /* TTY device closed */ 723 return; 724 } 725 726 if (_task == sc->sc_last_start_xfer) 727 sc->sc_flag |= UCOM_FLAG_GP_DATA; 728 729 if (sc->sc_callback->ucom_start_read) { 730 (sc->sc_callback->ucom_start_read) (sc); 731 } 732 if (sc->sc_callback->ucom_start_write) { 733 (sc->sc_callback->ucom_start_write) (sc); 734 } 735 } 736 737 static void 738 ucom_start_transfers(struct ucom_softc *sc) 739 { 740 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 741 return; 742 } 743 /* 744 * Make sure that data transfers are started in both 745 * directions: 746 */ 747 if (sc->sc_callback->ucom_start_read) { 748 (sc->sc_callback->ucom_start_read) (sc); 749 } 750 if (sc->sc_callback->ucom_start_write) { 751 (sc->sc_callback->ucom_start_write) (sc); 752 } 753 } 754 755 static void 756 ucom_cfg_open(struct usb_proc_msg *_task) 757 { 758 struct ucom_cfg_task *task = 759 (struct ucom_cfg_task *)_task; 760 struct ucom_softc *sc = task->sc; 761 762 DPRINTF("\n"); 763 764 if (sc->sc_flag & UCOM_FLAG_LL_READY) { 765 766 /* already opened */ 767 768 } else { 769 770 sc->sc_flag |= UCOM_FLAG_LL_READY; 771 772 if (sc->sc_callback->ucom_cfg_open) { 773 (sc->sc_callback->ucom_cfg_open) (sc); 774 775 /* wait a little */ 776 usb_pause_mtx(sc->sc_lock, hz / 10); 777 } 778 } 779 } 780 781 static int 782 ucom_dev_open(struct dev_open_args *ap) 783 { 784 cdev_t dev = ap->a_head.a_dev; 785 struct ucom_softc *sc = (struct ucom_softc *)dev->si_drv1; 786 int error; 787 int mynor; 788 789 error = 0; 790 mynor = minor(dev); 791 792 if (!(mynor & CALLOUT_MASK)) { 793 UCOM_MTX_LOCK(sc); 794 error = ucom_open(sc); 795 UCOM_MTX_UNLOCK(sc); 796 } 797 return error; 798 } 799 800 static int 801 ucom_open(struct ucom_softc *sc) 802 { 803 int error; 804 struct tty *tp; 805 806 int mynor; 807 808 mynor = minor(sc->sc_cdev); 809 810 if (sc->sc_flag & UCOM_FLAG_GONE) { 811 return (ENXIO); 812 } 813 if (sc->sc_flag & UCOM_FLAG_HL_READY) { 814 /* already opened */ 815 return (0); 816 } 817 DPRINTF("tp = %p\n", sc->sc_tty); 818 819 if (sc->sc_callback->ucom_pre_open) { 820 /* 821 * give the lower layer a chance to disallow TTY open, for 822 * example if the device is not present: 823 */ 824 error = (sc->sc_callback->ucom_pre_open) (sc); 825 if (error) { 826 return (error); 827 } 828 } 829 sc->sc_flag |= UCOM_FLAG_HL_READY; 830 831 lwkt_gettoken(&tty_token); 832 tp = sc->sc_tty; 833 834 crit_enter(); 835 836 if (!ISSET(tp->t_state, TS_ISOPEN)) { 837 struct termios t; 838 839 tp->t_dev = reference_dev(sc->sc_cdev); 840 841 t = mynor & CALLOUT_MASK ? sc->sc_it_out : sc->sc_it_in; 842 843 tp->t_ospeed = 0; 844 ucom_param(tp, &t); 845 tp->t_iflag = TTYDEF_IFLAG; 846 tp->t_oflag = TTYDEF_OFLAG; 847 tp->t_lflag = TTYDEF_LFLAG; 848 ttychars(tp); 849 ttsetwater(tp); 850 851 /* Disable transfers */ 852 sc->sc_flag &= ~UCOM_FLAG_GP_DATA; 853 854 sc->sc_lsr = 0; 855 sc->sc_msr = 0; 856 sc->sc_mcr = 0; 857 858 /* reset programmed line state */ 859 sc->sc_pls_curr = 0; 860 sc->sc_pls_set = 0; 861 sc->sc_pls_clr = 0; 862 863 /* reset jitter buffer */ 864 sc->sc_jitterbuf_in = 0; 865 sc->sc_jitterbuf_out = 0; 866 867 ucom_queue_command(sc, ucom_cfg_open, NULL, 868 &sc->sc_open_task[0].hdr, 869 &sc->sc_open_task[1].hdr); 870 871 /* Queue transfer enable command last */ 872 ucom_queue_command(sc, ucom_cfg_start_transfers, NULL, 873 &sc->sc_start_task[0].hdr, 874 &sc->sc_start_task[1].hdr); 875 876 ucom_modem(sc->sc_tty, SER_DTR | SER_RTS, 0); 877 878 ucom_ring(sc, 0); 879 880 ucom_break(sc, 0); 881 882 ucom_status_change(sc); 883 884 if (ISSET(sc->sc_msr, SER_DCD)) { 885 (*linesw[tp->t_line].l_modem)(tp, 1); 886 } 887 } 888 crit_exit(); 889 890 error = ttyopen(sc->sc_cdev, tp); 891 if (error) { 892 lwkt_reltoken(&tty_token); 893 return (error); 894 } 895 896 error = (*linesw[tp->t_line].l_open)(sc->sc_cdev, tp); 897 if (error) { 898 lwkt_reltoken(&tty_token); 899 return (error); 900 } 901 902 disc_optim(tp, &tp->t_termios, sc); 903 904 lwkt_reltoken(&tty_token); 905 906 return (0); 907 } 908 909 static void 910 ucom_cfg_close(struct usb_proc_msg *_task) 911 { 912 struct ucom_cfg_task *task = 913 (struct ucom_cfg_task *)_task; 914 struct ucom_softc *sc = task->sc; 915 916 DPRINTF("\n"); 917 918 if (sc->sc_flag & UCOM_FLAG_LL_READY) { 919 sc->sc_flag &= ~UCOM_FLAG_LL_READY; 920 if (sc->sc_callback->ucom_cfg_close) 921 (sc->sc_callback->ucom_cfg_close) (sc); 922 } else { 923 /* already closed */ 924 } 925 } 926 927 static int 928 ucom_dev_close(struct dev_close_args *ap) 929 { 930 cdev_t dev = ap->a_head.a_dev; 931 struct ucom_softc *sc = (struct ucom_softc *)dev->si_drv1; 932 int error; 933 934 UCOM_MTX_LOCK(sc); 935 error = ucom_close(sc); 936 UCOM_MTX_UNLOCK(sc); 937 938 return error; 939 } 940 941 static int 942 ucom_close(struct ucom_softc *sc) 943 { 944 struct tty *tp = sc->sc_tty; 945 int error = 0; 946 947 DPRINTF("tp=%p\n", tp); 948 949 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 950 DPRINTF("tp=%p already closed\n", tp); 951 return (error); 952 } 953 if (!ISSET(tp->t_state, TS_ISOPEN)) { 954 return(error); 955 } 956 ucom_shutdown(sc); 957 958 ucom_queue_command(sc, ucom_cfg_close, NULL, 959 &sc->sc_close_task[0].hdr, 960 &sc->sc_close_task[1].hdr); 961 962 sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_RTS_IFLOW); 963 964 if (sc->sc_callback->ucom_stop_read) { 965 (sc->sc_callback->ucom_stop_read) (sc); 966 } 967 968 lwkt_gettoken(&tty_token); 969 crit_enter(); 970 (*linesw[tp->t_line].l_close)(tp, 0); /* XXX: flags */ 971 disc_optim(tp, &tp->t_termios, sc); 972 ttyclose(tp); 973 crit_exit(); 974 975 if (tp->t_dev) { 976 release_dev(tp->t_dev); 977 tp->t_dev = NULL; 978 } 979 /* XXX: Detach wakeup */ 980 lwkt_reltoken(&tty_token); 981 982 return (error); 983 } 984 985 #if 0 /* XXX */ 986 static void 987 ucom_inwakeup(struct tty *tp) 988 { 989 struct ucom_softc *sc = tty_softc(tp); 990 uint16_t pos; 991 992 if (sc == NULL) 993 return; 994 995 UCOM_MTX_ASSERT(sc, MA_OWNED); 996 997 DPRINTF("tp=%p\n", tp); 998 999 if (ttydisc_can_bypass(tp) != 0 || 1000 (sc->sc_flag & UCOM_FLAG_HL_READY) == 0 || 1001 (sc->sc_flag & UCOM_FLAG_INWAKEUP) != 0) { 1002 return; 1003 } 1004 1005 /* prevent recursion */ 1006 sc->sc_flag |= UCOM_FLAG_INWAKEUP; 1007 1008 pos = sc->sc_jitterbuf_out; 1009 1010 while (sc->sc_jitterbuf_in != pos) { 1011 int c; 1012 1013 c = (char)sc->sc_jitterbuf[pos]; 1014 1015 if (ttydisc_rint(tp, c, 0) == -1) 1016 break; 1017 pos++; 1018 if (pos >= UCOM_JITTERBUF_SIZE) 1019 pos -= UCOM_JITTERBUF_SIZE; 1020 } 1021 1022 sc->sc_jitterbuf_out = pos; 1023 1024 /* clear RTS in async fashion */ 1025 if ((sc->sc_jitterbuf_in == pos) && 1026 (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)) 1027 ucom_rts(sc, 0); 1028 1029 sc->sc_flag &= ~UCOM_FLAG_INWAKEUP; 1030 } 1031 #endif 1032 1033 static int 1034 ucom_dev_read(struct dev_read_args *ap) 1035 { 1036 cdev_t dev = ap->a_head.a_dev; 1037 struct ucom_softc *sc; 1038 struct tty *tp; 1039 int error; 1040 1041 sc = 0; 1042 1043 lwkt_gettoken(&tty_token); 1044 1045 tp = dev->si_tty; 1046 KKASSERT(tp!=NULL); 1047 sc = tp->t_sc; 1048 KKASSERT(sc!=NULL); 1049 1050 DPRINTF("tp = %p, flag = 0x%x\n", tp, ap->a_ioflag); 1051 1052 UCOM_MTX_LOCK(sc); 1053 error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag); 1054 UCOM_MTX_UNLOCK(sc); 1055 1056 DPRINTF("error = %d\n", error); 1057 1058 lwkt_reltoken(&tty_token); 1059 return (error); 1060 } 1061 1062 static int 1063 ucom_dev_write(struct dev_write_args *ap) 1064 { 1065 cdev_t dev = ap->a_head.a_dev; 1066 struct ucom_softc *sc; 1067 struct tty *tp; 1068 int error; 1069 1070 lwkt_gettoken(&tty_token); 1071 tp = dev->si_tty; 1072 KKASSERT(tp!=NULL); 1073 sc = tp->t_sc; 1074 KKASSERT(sc!=NULL); 1075 1076 DPRINTF("tp = %p, flag = 0x%x\n", tp, ap->a_ioflag); 1077 1078 UCOM_MTX_LOCK(sc); 1079 error = (*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag); 1080 UCOM_MTX_UNLOCK(sc); 1081 1082 DPRINTF("ucomwrite: error = %d\n", error); 1083 1084 lwkt_reltoken(&tty_token); 1085 return (error); 1086 } 1087 1088 static int 1089 ucom_dev_ioctl(struct dev_ioctl_args *ap) 1090 { 1091 cdev_t dev = ap->a_head.a_dev; 1092 struct ucom_softc *sc = (struct ucom_softc *)dev->si_drv1; 1093 u_long cmd = ap->a_cmd; 1094 caddr_t data = ap->a_data; 1095 struct tty *tp = sc->sc_tty; 1096 int d; 1097 int error; 1098 int mynor; 1099 1100 UCOM_MTX_LOCK(sc); 1101 lwkt_gettoken(&tty_token); 1102 1103 mynor = minor(dev); 1104 1105 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 1106 lwkt_reltoken(&tty_token); 1107 return (EIO); 1108 } 1109 DPRINTF("cmd = 0x%08lx\n", cmd); 1110 if (mynor & CONTROL_MASK) { 1111 struct termios *ct; 1112 1113 switch (mynor & CONTROL_MASK) { 1114 case CONTROL_INIT_STATE: 1115 ct = mynor & CALLOUT_MASK ? &sc->sc_it_out : &sc->sc_it_in; 1116 break; 1117 case CONTROL_LOCK_STATE: 1118 ct = mynor & CALLOUT_MASK ? &sc->sc_lt_out : &sc->sc_lt_in; 1119 break; 1120 default: 1121 lwkt_reltoken(&tty_token); 1122 return (ENODEV); /* /dev/nodev */ 1123 } 1124 switch (ap->a_cmd) { 1125 case TIOCSETA: 1126 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0); 1127 if (error != 0) { 1128 lwkt_reltoken(&tty_token); 1129 return (error); 1130 } 1131 *ct = *(struct termios *)data; 1132 lwkt_reltoken(&tty_token); 1133 return (0); 1134 case TIOCGETA: 1135 *(struct termios *)data = *ct; 1136 lwkt_reltoken(&tty_token); 1137 return (0); 1138 case TIOCGETD: 1139 *(int *)data = TTYDISC; 1140 lwkt_reltoken(&tty_token); 1141 return (0); 1142 case TIOCGWINSZ: 1143 bzero(data, sizeof(struct winsize)); 1144 lwkt_reltoken(&tty_token); 1145 return (0); 1146 default: 1147 lwkt_reltoken(&tty_token); 1148 return (ENOTTY); 1149 } 1150 } 1151 1152 error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data, 1153 ap->a_fflag, ap->a_cred); 1154 1155 if (error != ENOIOCTL) { 1156 DPRINTF("ucomioctl: l_ioctl: error = %d\n", error); 1157 lwkt_reltoken(&tty_token); 1158 UCOM_MTX_UNLOCK(sc); 1159 return (error); 1160 } 1161 1162 crit_enter(); 1163 1164 error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag); 1165 disc_optim(tp, &tp->t_termios, sc); 1166 if (error != ENOIOCTL) { 1167 crit_exit(); 1168 DPRINTF("ucomioctl: ttioctl: error = %d\n", error); 1169 lwkt_reltoken(&tty_token); 1170 UCOM_MTX_UNLOCK(sc); 1171 1172 return (error); 1173 } 1174 1175 error = 0; 1176 1177 switch (cmd) { 1178 #if 0 /* XXXDF */ 1179 case TIOCSRING: 1180 ucom_ring(sc, 1); 1181 error = 0; 1182 break; 1183 case TIOCCRING: 1184 ucom_ring(sc, 0); 1185 error = 0; 1186 break; 1187 #endif 1188 case TIOCSBRK: 1189 ucom_break(sc, 1); 1190 error = 0; 1191 break; 1192 case TIOCCBRK: 1193 ucom_break(sc, 0); 1194 error = 0; 1195 break; 1196 case TIOCSDTR: 1197 ucom_dtr(sc, 1); 1198 break; 1199 case TIOCCDTR: 1200 ucom_dtr(sc, 0); 1201 break; 1202 case TIOCMSET: 1203 d = *(int *)ap->a_data; 1204 DPRINTF("ucomioctl: TIOCMSET, 0x%x\n", d); 1205 ucom_modem(tp, ucom_fromtio(d), 0); 1206 break; 1207 case TIOCMGET: 1208 d = ucom_modem(tp, 0, 0); 1209 DPRINTF("ucomioctl: TIOCMGET, 0x%x\n", d); 1210 *(int *)ap->a_data = ucom_totio(d); 1211 break; 1212 case TIOCMBIS: 1213 d = *(int *)ap->a_data; 1214 ucom_modem(tp, ucom_fromtio(d), 0); 1215 break; 1216 case TIOCMBIC: 1217 d = *(int *)ap->a_data; 1218 ucom_modem(tp, 0, ucom_fromtio(d)); 1219 break; 1220 default: 1221 if (sc->sc_callback->ucom_ioctl) { 1222 error = (sc->sc_callback->ucom_ioctl) 1223 (sc, cmd, data, 0, curthread); 1224 if (error>=0) { 1225 crit_exit(); 1226 1227 lwkt_reltoken(&tty_token); 1228 UCOM_MTX_UNLOCK(sc); 1229 1230 return(error); 1231 } 1232 } else { 1233 error = ENOIOCTL; 1234 } 1235 if (error == ENOIOCTL) 1236 error = pps_ioctl(cmd, data, &sc->sc_pps); 1237 break; 1238 } 1239 crit_exit(); 1240 1241 lwkt_reltoken(&tty_token); 1242 UCOM_MTX_UNLOCK(sc); 1243 1244 return (error); 1245 } 1246 1247 static int 1248 ucom_totio(int bits) 1249 { 1250 int rbits = 0; 1251 1252 SET(bits, TIOCM_LE); 1253 1254 if (ISSET(bits, SER_DTR)) { 1255 SET(rbits, TIOCM_DTR); 1256 } 1257 if (ISSET(bits, SER_RTS)) { 1258 SET(rbits, TIOCM_RTS); 1259 } 1260 if (ISSET(bits, SER_CTS)) { 1261 SET(rbits, TIOCM_CTS); 1262 } 1263 if (ISSET(bits, SER_DCD)) { 1264 SET(rbits, TIOCM_CD); 1265 } 1266 if (ISSET(bits, SER_DSR)) { 1267 SET(rbits, TIOCM_DSR); 1268 } 1269 if (ISSET(bits, SER_RI)) { 1270 SET(rbits, TIOCM_RI); 1271 } 1272 1273 return (rbits); 1274 } 1275 1276 static int 1277 ucom_fromtio(int bits) 1278 { 1279 int rbits = 0; 1280 1281 if (ISSET(bits, TIOCM_DTR)) { 1282 SET(rbits, SER_DTR); 1283 } 1284 if (ISSET(bits, TIOCM_RTS)) { 1285 SET(rbits, SER_RTS); 1286 } 1287 if (ISSET(bits, TIOCM_CTS)) { 1288 SET(rbits, SER_CTS); 1289 } 1290 if (ISSET(bits, TIOCM_CD)) { 1291 SET(rbits, SER_DCD); 1292 } 1293 if (ISSET(bits, TIOCM_DSR)) { 1294 SET(rbits, SER_DSR); 1295 } 1296 if (ISSET(bits, TIOCM_RI)) { 1297 SET(rbits, SER_RI); 1298 } 1299 1300 return (rbits); 1301 } 1302 1303 static int 1304 ucom_modem(struct tty *tp, int sigon, int sigoff) 1305 { 1306 struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc; 1307 uint8_t onoff; 1308 1309 UCOM_MTX_ASSERT(sc, MA_OWNED); 1310 1311 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 1312 return (0); 1313 } 1314 if ((sigon == 0) && (sigoff == 0)) { 1315 1316 if (sc->sc_mcr & SER_DTR) { 1317 sigon |= SER_DTR; 1318 } 1319 if (sc->sc_mcr & SER_RTS) { 1320 sigon |= SER_RTS; 1321 } 1322 if (sc->sc_msr & SER_CTS) { 1323 sigon |= SER_CTS; 1324 } 1325 if (sc->sc_msr & SER_DCD) { 1326 sigon |= SER_DCD; 1327 } 1328 if (sc->sc_msr & SER_DSR) { 1329 sigon |= SER_DSR; 1330 } 1331 if (sc->sc_msr & SER_RI) { 1332 sigon |= SER_RI; 1333 } 1334 return (sigon); 1335 } 1336 if (sigon & SER_DTR) { 1337 sc->sc_mcr |= SER_DTR; 1338 } 1339 if (sigoff & SER_DTR) { 1340 sc->sc_mcr &= ~SER_DTR; 1341 } 1342 if (sigon & SER_RTS) { 1343 sc->sc_mcr |= SER_RTS; 1344 } 1345 if (sigoff & SER_RTS) { 1346 sc->sc_mcr &= ~SER_RTS; 1347 } 1348 onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0; 1349 ucom_dtr(sc, onoff); 1350 1351 onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0; 1352 ucom_rts(sc, onoff); 1353 1354 return (0); 1355 } 1356 1357 static void 1358 ucom_cfg_line_state(struct usb_proc_msg *_task) 1359 { 1360 struct ucom_cfg_task *task = 1361 (struct ucom_cfg_task *)_task; 1362 struct ucom_softc *sc = task->sc; 1363 uint8_t notch_bits; 1364 uint8_t any_bits; 1365 uint8_t prev_value; 1366 uint8_t last_value; 1367 uint8_t mask; 1368 1369 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 1370 return; 1371 } 1372 1373 mask = 0; 1374 /* compute callback mask */ 1375 if (sc->sc_callback->ucom_cfg_set_dtr) 1376 mask |= UCOM_LS_DTR; 1377 if (sc->sc_callback->ucom_cfg_set_rts) 1378 mask |= UCOM_LS_RTS; 1379 if (sc->sc_callback->ucom_cfg_set_break) 1380 mask |= UCOM_LS_BREAK; 1381 if (sc->sc_callback->ucom_cfg_set_ring) 1382 mask |= UCOM_LS_RING; 1383 1384 /* compute the bits we are to program */ 1385 notch_bits = (sc->sc_pls_set & sc->sc_pls_clr) & mask; 1386 any_bits = (sc->sc_pls_set | sc->sc_pls_clr) & mask; 1387 prev_value = sc->sc_pls_curr ^ notch_bits; 1388 last_value = sc->sc_pls_curr; 1389 1390 /* reset programmed line state */ 1391 sc->sc_pls_curr = 0; 1392 sc->sc_pls_set = 0; 1393 sc->sc_pls_clr = 0; 1394 1395 /* ensure that we don't lose any levels */ 1396 if (notch_bits & UCOM_LS_DTR) 1397 sc->sc_callback->ucom_cfg_set_dtr(sc, 1398 (prev_value & UCOM_LS_DTR) ? 1 : 0); 1399 if (notch_bits & UCOM_LS_RTS) 1400 sc->sc_callback->ucom_cfg_set_rts(sc, 1401 (prev_value & UCOM_LS_RTS) ? 1 : 0); 1402 if (notch_bits & UCOM_LS_BREAK) 1403 sc->sc_callback->ucom_cfg_set_break(sc, 1404 (prev_value & UCOM_LS_BREAK) ? 1 : 0); 1405 if (notch_bits & UCOM_LS_RING) 1406 sc->sc_callback->ucom_cfg_set_ring(sc, 1407 (prev_value & UCOM_LS_RING) ? 1 : 0); 1408 1409 /* set last value */ 1410 if (any_bits & UCOM_LS_DTR) 1411 sc->sc_callback->ucom_cfg_set_dtr(sc, 1412 (last_value & UCOM_LS_DTR) ? 1 : 0); 1413 if (any_bits & UCOM_LS_RTS) 1414 sc->sc_callback->ucom_cfg_set_rts(sc, 1415 (last_value & UCOM_LS_RTS) ? 1 : 0); 1416 if (any_bits & UCOM_LS_BREAK) 1417 sc->sc_callback->ucom_cfg_set_break(sc, 1418 (last_value & UCOM_LS_BREAK) ? 1 : 0); 1419 if (any_bits & UCOM_LS_RING) 1420 sc->sc_callback->ucom_cfg_set_ring(sc, 1421 (last_value & UCOM_LS_RING) ? 1 : 0); 1422 } 1423 1424 static void 1425 ucom_line_state(struct ucom_softc *sc, 1426 uint8_t set_bits, uint8_t clear_bits) 1427 { 1428 UCOM_MTX_ASSERT(sc, MA_OWNED); 1429 1430 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 1431 return; 1432 } 1433 1434 DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits); 1435 1436 /* update current programmed line state */ 1437 sc->sc_pls_curr |= set_bits; 1438 sc->sc_pls_curr &= ~clear_bits; 1439 sc->sc_pls_set |= set_bits; 1440 sc->sc_pls_clr |= clear_bits; 1441 1442 /* defer driver programming */ 1443 ucom_queue_command(sc, ucom_cfg_line_state, NULL, 1444 &sc->sc_line_state_task[0].hdr, 1445 &sc->sc_line_state_task[1].hdr); 1446 } 1447 1448 static void 1449 ucom_ring(struct ucom_softc *sc, uint8_t onoff) 1450 { 1451 DPRINTF("onoff = %d\n", onoff); 1452 1453 if (onoff) 1454 ucom_line_state(sc, UCOM_LS_RING, 0); 1455 else 1456 ucom_line_state(sc, 0, UCOM_LS_RING); 1457 } 1458 1459 static void 1460 ucom_break(struct ucom_softc *sc, uint8_t onoff) 1461 { 1462 DPRINTF("onoff = %d\n", onoff); 1463 1464 if (onoff) 1465 ucom_line_state(sc, UCOM_LS_BREAK, 0); 1466 else 1467 ucom_line_state(sc, 0, UCOM_LS_BREAK); 1468 } 1469 1470 static void 1471 ucom_dtr(struct ucom_softc *sc, uint8_t onoff) 1472 { 1473 DPRINTF("onoff = %d\n", onoff); 1474 1475 if (onoff) 1476 ucom_line_state(sc, UCOM_LS_DTR, 0); 1477 else 1478 ucom_line_state(sc, 0, UCOM_LS_DTR); 1479 } 1480 1481 static void 1482 ucom_rts(struct ucom_softc *sc, uint8_t onoff) 1483 { 1484 DPRINTF("onoff = %d\n", onoff); 1485 1486 if (onoff) 1487 ucom_line_state(sc, UCOM_LS_RTS, 0); 1488 else 1489 ucom_line_state(sc, 0, UCOM_LS_RTS); 1490 } 1491 1492 static void 1493 ucom_cfg_status_change(struct usb_proc_msg *_task) 1494 { 1495 struct ucom_cfg_task *task = 1496 (struct ucom_cfg_task *)_task; 1497 struct ucom_softc *sc = task->sc; 1498 struct tty *tp; 1499 uint8_t new_msr; 1500 uint8_t new_lsr; 1501 uint8_t msr_delta; 1502 uint8_t lsr_delta; 1503 1504 tp = sc->sc_tty; 1505 1506 UCOM_MTX_ASSERT(sc, MA_OWNED); 1507 1508 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 1509 return; 1510 } 1511 if (sc->sc_callback->ucom_cfg_get_status == NULL) { 1512 return; 1513 } 1514 /* get status */ 1515 1516 new_msr = 0; 1517 new_lsr = 0; 1518 1519 (sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr); 1520 1521 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 1522 /* TTY device closed */ 1523 return; 1524 } 1525 msr_delta = (sc->sc_msr ^ new_msr); 1526 lsr_delta = (sc->sc_lsr ^ new_lsr); 1527 1528 sc->sc_msr = new_msr; 1529 sc->sc_lsr = new_lsr; 1530 1531 #if 0 /* missing pps_capture */ 1532 /* 1533 * Time pulse counting support. Note that both CTS and DCD are 1534 * active-low signals. The status bit is high to indicate that 1535 * the signal on the line is low, which corresponds to a PPS 1536 * clear event. 1537 */ 1538 switch(ucom_pps_mode) { 1539 case 1: 1540 if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) && 1541 (msr_delta & SER_CTS)) { 1542 pps_capture(&sc->sc_pps); 1543 pps_event(&sc->sc_pps, (sc->sc_msr & SER_CTS) ? 1544 PPS_CAPTURECLEAR : PPS_CAPTUREASSERT); 1545 } 1546 break; 1547 case 2: 1548 if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) && 1549 (msr_delta & SER_DCD)) { 1550 pps_capture(&sc->sc_pps); 1551 pps_event(&sc->sc_pps, (sc->sc_msr & SER_DCD) ? 1552 PPS_CAPTURECLEAR : PPS_CAPTUREASSERT); 1553 } 1554 break; 1555 default: 1556 break; 1557 } 1558 #endif 1559 1560 if (msr_delta & SER_DCD) { 1561 1562 int onoff = (sc->sc_msr & SER_DCD) ? 1 : 0; 1563 1564 DPRINTF("DCD changed to %d\n", onoff); 1565 1566 (*linesw[tp->t_line].l_modem)(tp, onoff); 1567 } 1568 1569 if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) { 1570 1571 DPRINTF("BREAK detected\n"); 1572 (*linesw[tp->t_line].l_rint)(0, tp); 1573 1574 /* 1575 ttydisc_rint(tp, 0, TRE_BREAK); 1576 ttydisc_rint_done(tp); 1577 */ 1578 } 1579 1580 if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) { 1581 1582 DPRINTF("Frame error detected\n"); 1583 (*linesw[tp->t_line].l_rint)(0, tp); 1584 1585 /* 1586 ttydisc_rint(tp, 0, TRE_FRAMING); 1587 ttydisc_rint_done(tp); 1588 */ 1589 } 1590 1591 if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) { 1592 1593 DPRINTF("Parity error detected\n"); 1594 (*linesw[tp->t_line].l_rint)(0, tp); 1595 /* 1596 ttydisc_rint(tp, 0, TRE_PARITY); 1597 ttydisc_rint_done(tp); 1598 */ 1599 } 1600 } 1601 1602 void 1603 ucom_status_change(struct ucom_softc *sc) 1604 { 1605 UCOM_MTX_ASSERT(sc, MA_OWNED); 1606 1607 if (sc->sc_flag & UCOM_FLAG_CONSOLE) 1608 return; /* not supported */ 1609 1610 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 1611 return; 1612 } 1613 DPRINTF("\n"); 1614 1615 ucom_queue_command(sc, ucom_cfg_status_change, NULL, 1616 &sc->sc_status_task[0].hdr, 1617 &sc->sc_status_task[1].hdr); 1618 } 1619 1620 static void 1621 ucom_cfg_param(struct usb_proc_msg *_task) 1622 { 1623 struct ucom_param_task *task = 1624 (struct ucom_param_task *)_task; 1625 struct ucom_softc *sc = task->sc; 1626 1627 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 1628 return; 1629 } 1630 if (sc->sc_callback->ucom_cfg_param == NULL) { 1631 return; 1632 } 1633 1634 (sc->sc_callback->ucom_cfg_param) (sc, &task->termios_copy); 1635 1636 /* wait a little */ 1637 usb_pause_mtx(sc->sc_lock, hz / 10); 1638 } 1639 1640 static int 1641 ucom_param(struct tty *tp, struct termios *t) 1642 { 1643 struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc; 1644 uint8_t opened; 1645 int error; 1646 1647 lwkt_gettoken(&tty_token); 1648 UCOM_MTX_ASSERT(sc, MA_OWNED); 1649 1650 opened = 0; 1651 error = 0; 1652 1653 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 1654 1655 /* XXX the TTY layer should call "open()" first! */ 1656 /* 1657 * Not quite: Its ordering is partly backwards, but 1658 * some parameters must be set early in ttydev_open(), 1659 * possibly before calling ttydevsw_open(). 1660 */ 1661 error = ucom_open(sc); 1662 1663 if (error) { 1664 goto done; 1665 } 1666 opened = 1; 1667 } 1668 DPRINTF("sc = %p\n", sc); 1669 1670 /* Check requested parameters. */ 1671 if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) { 1672 /* XXX c_ospeed == 0 is perfectly valid. */ 1673 DPRINTF("mismatch ispeed and ospeed\n"); 1674 error = EINVAL; 1675 goto done; 1676 } 1677 t->c_ispeed = t->c_ospeed; 1678 1679 if (sc->sc_callback->ucom_pre_param) { 1680 /* Let the lower layer verify the parameters */ 1681 error = (sc->sc_callback->ucom_pre_param) (sc, t); 1682 if (error) { 1683 DPRINTF("callback error = %d\n", error); 1684 goto done; 1685 } 1686 } 1687 1688 /* Disable transfers */ 1689 sc->sc_flag &= ~UCOM_FLAG_GP_DATA; 1690 1691 /* Queue baud rate programming command first */ 1692 ucom_queue_command(sc, ucom_cfg_param, t, 1693 &sc->sc_param_task[0].hdr, 1694 &sc->sc_param_task[1].hdr); 1695 1696 /* Queue transfer enable command last */ 1697 ucom_queue_command(sc, ucom_cfg_start_transfers, NULL, 1698 &sc->sc_start_task[0].hdr, 1699 &sc->sc_start_task[1].hdr); 1700 1701 if (t->c_cflag & CRTS_IFLOW) { 1702 sc->sc_flag |= UCOM_FLAG_RTS_IFLOW; 1703 } else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) { 1704 sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW; 1705 ucom_modem(tp, SER_RTS, 0); 1706 } 1707 done: 1708 if (error) { 1709 if (opened) { 1710 ucom_close(sc); 1711 } 1712 } 1713 1714 lwkt_reltoken(&tty_token); 1715 return (error); 1716 } 1717 1718 static void 1719 ucom_start(struct tty *tp) 1720 { 1721 struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc; 1722 1723 UCOM_MTX_ASSERT(sc, MA_OWNED); 1724 1725 DPRINTF("sc = %p\n", sc); 1726 1727 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 1728 /* The higher layer is not ready */ 1729 return; 1730 } 1731 1732 lwkt_gettoken(&tty_token); 1733 crit_enter(); 1734 1735 if (tp->t_state & TS_TBLOCK) { 1736 if (ISSET(sc->sc_mcr, SER_RTS) && 1737 ISSET(sc->sc_flag, UCOM_FLAG_RTS_IFLOW)) { 1738 DPRINTF("ucom_start: clear RTS\n"); 1739 (void)ucom_modem(tp, 0, SER_RTS); 1740 } 1741 } else { 1742 if (!ISSET(sc->sc_mcr, SER_RTS) && 1743 tp->t_rawq.c_cc <= tp->t_ilowat && 1744 ISSET(sc->sc_flag, UCOM_FLAG_RTS_IFLOW)) { 1745 DPRINTF("ucom_start: set RTS\n"); 1746 (void)ucom_modem(tp, SER_RTS, 0); 1747 } 1748 } 1749 1750 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) { 1751 ttwwakeup(tp); 1752 DPRINTF("ucom_start: stopped\n"); 1753 goto out; 1754 } 1755 1756 if (tp->t_outq.c_cc <= tp->t_olowat) { 1757 if (ISSET(tp->t_state, TS_SO_OLOWAT)) { 1758 CLR(tp->t_state, TS_SO_OLOWAT); 1759 wakeup(TSA_OLOWAT(tp)); 1760 } 1761 KNOTE(&tp->t_wkq.ki_note, 0); 1762 if (tp->t_outq.c_cc == 0) { 1763 if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) == 1764 TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) { 1765 CLR(tp->t_state, TS_SO_OCOMPLETE); 1766 wakeup(TSA_OCOMPLETE(tp)); 1767 } 1768 goto out; 1769 } 1770 } 1771 1772 DPRINTF("about to start write?\n"); 1773 ucom_start_transfers(sc); 1774 1775 ttwwakeup(tp); 1776 1777 out: 1778 crit_exit(); 1779 lwkt_reltoken(&tty_token); 1780 } 1781 1782 static void 1783 ucom_stop(struct tty *tp, int flag) 1784 { 1785 struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc; 1786 1787 DPRINTF("sc = %p, x = 0x%x\n", sc, flag); 1788 1789 lwkt_gettoken(&tty_token); 1790 if (flag & FREAD) { 1791 /* 1792 * This is just supposed to flush pending receive data, 1793 * not stop the reception of data entirely! 1794 */ 1795 DPRINTF("read\n"); 1796 if (sc->sc_callback->ucom_stop_read) { 1797 (sc->sc_callback->ucom_stop_read) (sc); 1798 } 1799 if (sc->sc_callback->ucom_start_read) { 1800 (sc->sc_callback->ucom_start_read) (sc); 1801 } 1802 /* ucomstopread(sc); 1803 ucomstartread(sc); 1804 */ } 1805 1806 if (flag & FWRITE) { 1807 DPRINTF("write\n"); 1808 crit_enter(); 1809 if (ISSET(tp->t_state, TS_BUSY)) { 1810 /* XXX do what? */ 1811 if (!ISSET(tp->t_state, TS_TTSTOP)) 1812 SET(tp->t_state, TS_FLUSH); 1813 } 1814 crit_exit(); 1815 } 1816 1817 DPRINTF("done\n"); 1818 lwkt_reltoken(&tty_token); 1819 } 1820 1821 /*------------------------------------------------------------------------* 1822 * ucom_get_data 1823 * Input values: 1824 * len: maximum length of data to get 1825 * 1826 * Get data from the TTY layer 1827 * 1828 * Return values: 1829 * 0: No data is available. 1830 * Else: Data is available. 1831 *------------------------------------------------------------------------*/ 1832 1833 /* Copy data from the tty layer to usb */ 1834 uint8_t 1835 ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc, 1836 uint32_t offset, uint32_t len, uint32_t *actlen) 1837 { 1838 struct usb_page_search res; 1839 struct tty *tp = sc->sc_tty; 1840 uint32_t cnt; 1841 uint32_t offset_orig; 1842 1843 DPRINTF("\n"); 1844 1845 UCOM_MTX_ASSERT(sc, MA_OWNED); 1846 if (sc->sc_flag & UCOM_FLAG_CONSOLE) { 1847 unsigned int temp; 1848 1849 /* get total TX length */ 1850 1851 temp = ucom_cons_tx_high - ucom_cons_tx_low; 1852 temp %= UCOM_CONS_BUFSIZE; 1853 1854 /* limit TX length */ 1855 1856 if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low)) 1857 temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low); 1858 1859 if (temp > len) 1860 temp = len; 1861 1862 /* copy in data */ 1863 1864 usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp); 1865 1866 /* update counters */ 1867 1868 ucom_cons_tx_low += temp; 1869 ucom_cons_tx_low %= UCOM_CONS_BUFSIZE; 1870 1871 /* store actual length */ 1872 1873 *actlen = temp; 1874 1875 return (temp ? 1 : 0); 1876 } 1877 1878 if (tty_gone(tp) || 1879 !(sc->sc_flag & UCOM_FLAG_GP_DATA)) { 1880 actlen[0] = 0; 1881 return (0); /* multiport device polling */ 1882 } 1883 1884 offset_orig = offset; 1885 1886 lwkt_gettoken(&tty_token); 1887 crit_enter(); 1888 while (len != 0) { 1889 usbd_get_page(pc, offset, &res); 1890 1891 /* Buffer bigger than max requested data */ 1892 if (res.length > len) { 1893 res.length = len; 1894 } 1895 /* copy data directly into USB buffer */ 1896 SET(tp->t_state, TS_BUSY); 1897 cnt = q_to_b(&tp->t_outq, res.buffer, len); 1898 if (cnt == 0) { 1899 DPRINTF("ucom_get_data: cnt == 0\n"); 1900 CLR(tp->t_state, TS_BUSY); 1901 break; 1902 } 1903 1904 CLR(tp->t_state, TS_BUSY); 1905 1906 /* XXX mp: This breaks avrdude, 1907 does the flush need to happen 1908 elsewhere? 1909 if (ISSET(tp->t_state, TS_FLUSH)) 1910 CLR(tp->t_state, TS_FLUSH); 1911 else 1912 ndflush(&tp->t_outq,cnt); 1913 */ 1914 1915 offset += cnt; 1916 len -= cnt; 1917 1918 if (cnt < res.length) { 1919 /* end of buffer */ 1920 break; 1921 } 1922 } 1923 crit_exit(); 1924 lwkt_reltoken(&tty_token); 1925 1926 actlen[0] = offset - offset_orig; 1927 1928 DPRINTF("cnt=%d\n", actlen[0]); 1929 1930 if (actlen[0] == 0) { 1931 return (0); 1932 } 1933 return (1); 1934 } 1935 1936 /* 1937 * Write data to the tty layer 1938 */ 1939 1940 void 1941 ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc, 1942 uint32_t offset, uint32_t len) 1943 { 1944 struct usb_page_search res; 1945 struct tty *tp = sc->sc_tty; 1946 char *buf; 1947 uint32_t cnt; 1948 int lostcc; 1949 1950 DPRINTF("\n"); 1951 1952 UCOM_MTX_ASSERT(sc, MA_OWNED); 1953 lwkt_gettoken(&tty_token); 1954 1955 if (sc->sc_flag & UCOM_FLAG_CONSOLE) { 1956 unsigned int temp; 1957 1958 /* get maximum RX length */ 1959 1960 temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low; 1961 temp %= UCOM_CONS_BUFSIZE; 1962 1963 /* limit RX length */ 1964 1965 if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high)) 1966 temp = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high); 1967 1968 if (temp > len) 1969 temp = len; 1970 1971 /* copy out data */ 1972 1973 usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp); 1974 1975 /* update counters */ 1976 1977 ucom_cons_rx_high += temp; 1978 ucom_cons_rx_high %= UCOM_CONS_BUFSIZE; 1979 1980 lwkt_reltoken(&tty_token); 1981 return; 1982 } 1983 1984 if (tty_gone(tp)) { 1985 lwkt_reltoken(&tty_token); 1986 return; /* multiport device polling */ 1987 } 1988 if (len == 0) { 1989 lwkt_reltoken(&tty_token); 1990 return; /* no data */ 1991 } 1992 1993 /* set a flag to prevent recursation ? */ 1994 1995 crit_enter(); 1996 while (len > 0) { 1997 usbd_get_page(pc, offset, &res); 1998 1999 if (res.length > len) { 2000 res.length = len; 2001 } 2002 len -= res.length; 2003 offset += res.length; 2004 2005 /* pass characters to tty layer */ 2006 2007 buf = res.buffer; 2008 cnt = res.length; 2009 2010 /* first check if we can pass the buffer directly */ 2011 2012 if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 2013 /* clear any jitter buffer */ 2014 sc->sc_jitterbuf_in = 0; 2015 sc->sc_jitterbuf_out = 0; 2016 2017 if (tp->t_rawq.c_cc + cnt > tp->t_ihiwat 2018 && (sc->sc_flag & UCOM_FLAG_RTS_IFLOW 2019 || tp->t_iflag & IXOFF) 2020 && !(tp->t_state & TS_TBLOCK)) 2021 ttyblock(tp); 2022 lostcc = b_to_q((char *)buf, cnt, &tp->t_rawq); 2023 tp->t_rawcc += cnt; 2024 if (sc->hotchar) { 2025 while (cnt) { 2026 if (*buf == sc->hotchar) 2027 break; 2028 --cnt; 2029 ++buf; 2030 } 2031 if (cnt) 2032 setsofttty(); 2033 } 2034 ttwakeup(tp); 2035 if (tp->t_state & TS_TTSTOP 2036 && (tp->t_iflag & IXANY 2037 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 2038 tp->t_state &= ~TS_TTSTOP; 2039 tp->t_lflag &= ~FLUSHO; 2040 ucom_start(tp); 2041 } 2042 if (lostcc > 0) 2043 kprintf("lost %d chars\n", lostcc); 2044 2045 /* 2046 if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) { 2047 DPRINTF("tp=%p, data lost\n", tp); 2048 } 2049 */ 2050 continue; 2051 } else { 2052 /* need to loop */ 2053 for (cnt = 0; cnt != res.length; cnt++) { 2054 if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out || 2055 (*linesw[tp->t_line].l_rint)(buf[cnt], tp) == -1) { 2056 uint16_t end; 2057 uint16_t pos; 2058 2059 pos = sc->sc_jitterbuf_in; 2060 end = sc->sc_jitterbuf_out + 2061 UCOM_JITTERBUF_SIZE - 1; 2062 2063 if (end >= UCOM_JITTERBUF_SIZE) 2064 end -= UCOM_JITTERBUF_SIZE; 2065 2066 for (; cnt != res.length; cnt++) { 2067 if (pos == end) 2068 break; 2069 sc->sc_jitterbuf[pos] = buf[cnt]; 2070 pos++; 2071 if (pos >= UCOM_JITTERBUF_SIZE) 2072 pos -= UCOM_JITTERBUF_SIZE; 2073 } 2074 2075 sc->sc_jitterbuf_in = pos; 2076 2077 /* set RTS in async fashion */ 2078 if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) 2079 ucom_rts(sc, 1); 2080 2081 DPRINTF("tp=%p, lost %d " 2082 "chars\n", tp, res.length - cnt); 2083 break; 2084 } 2085 } 2086 } 2087 } 2088 crit_exit(); 2089 lwkt_reltoken(&tty_token); 2090 /* 2091 ttydisc_rint_done(tp); 2092 */ 2093 } 2094 2095 #if 0 /* XXX */ 2096 static void 2097 ucom_free(void *xsc) 2098 { 2099 struct ucom_softc *sc = xsc; 2100 2101 if (sc->sc_callback->ucom_free != NULL) 2102 sc->sc_callback->ucom_free(sc); 2103 else 2104 /*ucom_unref(sc->sc_super) XXX hack, see end of ucom_detach_tty() */; 2105 2106 lockmgr(&ucom_lock, LK_EXCLUSIVE); 2107 ucom_close_refs--; 2108 lockmgr(&ucom_lock, LK_RELEASE); 2109 } 2110 2111 static cn_probe_t ucom_cnprobe; 2112 static cn_init_t ucom_cninit; 2113 static cn_term_t ucom_cnterm; 2114 static cn_getc_t ucom_cngetc; 2115 static cn_putc_t ucom_cnputc; 2116 2117 /* 2118 static cn_grab_t ucom_cngrab; 2119 static cn_ungrab_t ucom_cnungrab; 2120 CONSOLE_DRIVER(ucom); 2121 */ 2122 2123 static void 2124 ucom_cnprobe(struct consdev *cp) 2125 { 2126 if (ucom_cons_unit != -1) 2127 cp->cn_pri = CN_NORMAL; 2128 else 2129 cp->cn_pri = CN_DEAD; 2130 2131 /* 2132 strlcpy(cp->cn_name, "ucom", sizeof(cp->cn_name)); 2133 */ 2134 } 2135 2136 static void 2137 ucom_cninit(struct consdev *cp) 2138 { 2139 } 2140 2141 static void 2142 ucom_cnterm(struct consdev *cp) 2143 { 2144 } 2145 2146 static void 2147 ucom_cngrab(struct consdev *cp) 2148 { 2149 } 2150 2151 static void 2152 ucom_cnungrab(struct consdev *cp) 2153 { 2154 } 2155 2156 static int 2157 ucom_cngetc(struct consdev *cd) 2158 { 2159 struct ucom_softc *sc = ucom_cons_softc; 2160 int c; 2161 2162 if (sc == NULL) 2163 return (-1); 2164 2165 UCOM_MTX_LOCK(sc); 2166 2167 if (ucom_cons_rx_low != ucom_cons_rx_high) { 2168 c = ucom_cons_rx_buf[ucom_cons_rx_low]; 2169 ucom_cons_rx_low ++; 2170 ucom_cons_rx_low %= UCOM_CONS_BUFSIZE; 2171 } else { 2172 c = -1; 2173 } 2174 2175 /* start USB transfers */ 2176 ucom_outwakeup(sc->sc_tty); 2177 2178 UCOM_MTX_UNLOCK(sc); 2179 2180 /* poll if necessary */ 2181 /* 2182 if (kdb_active && sc->sc_callback->ucom_poll) 2183 (sc->sc_callback->ucom_poll) (sc); 2184 */ 2185 return (c); 2186 } 2187 2188 static void 2189 ucom_cnputc(void *cd, int c) 2190 /* 2191 ucom_cnputc(struct consdev *cd, int c) 2192 */ 2193 2194 { 2195 struct ucom_softc *sc = ucom_cons_softc; 2196 unsigned int temp; 2197 2198 if (sc == NULL) 2199 return; 2200 2201 repeat: 2202 2203 UCOM_MTX_LOCK(sc); 2204 2205 /* compute maximum TX length */ 2206 2207 temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low; 2208 temp %= UCOM_CONS_BUFSIZE; 2209 2210 if (temp) { 2211 ucom_cons_tx_buf[ucom_cons_tx_high] = c; 2212 ucom_cons_tx_high ++; 2213 ucom_cons_tx_high %= UCOM_CONS_BUFSIZE; 2214 } 2215 2216 /* start USB transfers */ 2217 ucom_outwakeup(sc->sc_tty); 2218 2219 UCOM_MTX_UNLOCK(sc); 2220 2221 /* poll if necessary */ 2222 #if 0 /* XXX */ 2223 if (kdb_active && sc->sc_callback->ucom_poll) { 2224 (sc->sc_callback->ucom_poll) (sc); 2225 /* simple flow control */ 2226 if (temp == 0) 2227 goto repeat; 2228 } 2229 #endif 2230 } 2231 #endif 2232 /*------------------------------------------------------------------------* 2233 * ucom_ref 2234 * 2235 * This function will increment the super UCOM reference count. 2236 *------------------------------------------------------------------------*/ 2237 void 2238 ucom_ref(struct ucom_super_softc *ssc) 2239 { 2240 lockmgr(&ucom_lock, LK_EXCLUSIVE); 2241 ssc->sc_refs++; 2242 lockmgr(&ucom_lock, LK_RELEASE); 2243 } 2244 2245 /*------------------------------------------------------------------------* 2246 * ucom_free_unit 2247 * 2248 * This function will free the super UCOM's allocated unit 2249 * number. This function can be called on a zero-initialized 2250 * structure. This function can be called multiple times. 2251 *------------------------------------------------------------------------*/ 2252 static void 2253 ucom_free_unit(struct ucom_super_softc *ssc) 2254 { 2255 if (!(ssc->sc_flag & UCOM_FLAG_FREE_UNIT)) 2256 return; 2257 2258 ucom_unit_free(ssc->sc_unit); 2259 2260 ssc->sc_flag &= ~UCOM_FLAG_FREE_UNIT; 2261 } 2262 2263 /*------------------------------------------------------------------------* 2264 * ucom_unref 2265 * 2266 * This function will decrement the super UCOM reference count. 2267 * 2268 * Return values: 2269 * 0: UCOM structures are still referenced. 2270 * Else: UCOM structures are no longer referenced. 2271 *------------------------------------------------------------------------*/ 2272 int 2273 ucom_unref(struct ucom_super_softc *ssc) 2274 { 2275 int retval; 2276 2277 lockmgr(&ucom_lock, LK_EXCLUSIVE); 2278 retval = (ssc->sc_refs < 2); 2279 ssc->sc_refs--; 2280 lockmgr(&ucom_lock, LK_RELEASE); 2281 2282 if (retval) 2283 ucom_free_unit(ssc); 2284 2285 return (retval); 2286 } 2287 2288 /* 2289 * NOTE: Must be called with tty_token held. 2290 */ 2291 static void 2292 disc_optim(struct tty *tp, struct termios *t, struct ucom_softc *sc) 2293 { 2294 ASSERT_LWKT_TOKEN_HELD(&tty_token); 2295 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 2296 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 2297 && (!(t->c_iflag & PARMRK) 2298 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 2299 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 2300 && linesw[tp->t_line].l_rint == ttyinput) { 2301 DPRINTF("disc_optim: bypass l_rint\n"); 2302 tp->t_state |= TS_CAN_BYPASS_L_RINT; 2303 } else { 2304 DPRINTF("disc_optim: can't bypass l_rint\n"); 2305 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 2306 } 2307 sc->hotchar = linesw[tp->t_line].l_hotchar; 2308 } 2309 2310 #if defined(GDB) 2311 2312 #include <gdb/gdb.h> 2313 2314 static gdb_probe_f ucom_gdbprobe; 2315 static gdb_init_f ucom_gdbinit; 2316 static gdb_term_f ucom_gdbterm; 2317 static gdb_getc_f ucom_gdbgetc; 2318 static gdb_putc_f ucom_gdbputc; 2319 2320 GDB_DBGPORT(sio, ucom_gdbprobe, ucom_gdbinit, ucom_gdbterm, ucom_gdbgetc, ucom_gdbputc); 2321 2322 static int 2323 ucom_gdbprobe(void) 2324 { 2325 return ((ucom_cons_softc != NULL) ? 0 : -1); 2326 } 2327 2328 static void 2329 ucom_gdbinit(void) 2330 { 2331 } 2332 2333 static void 2334 ucom_gdbterm(void) 2335 { 2336 } 2337 2338 static void 2339 ucom_gdbputc(int c) 2340 { 2341 ucom_cnputc(NULL, c); 2342 } 2343 2344 static int 2345 ucom_gdbgetc(void) 2346 { 2347 return (ucom_cngetc(NULL)); 2348 } 2349 2350 #endif 2351 2352 2353