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