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