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