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