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