1 /* $NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 2001-2003, 2005, 2008 5 * Shunsuke Akiyama <akiyama@jp.FreeBSD.org>. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 /*- 34 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 35 * All rights reserved. 36 * 37 * This code is derived from software contributed to The NetBSD Foundation 38 * by Lennart Augustsson (lennart@augustsson.net) at 39 * Carlstedt Research & Technology. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 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 <dev/usb/usb.h> 71 #include <dev/usb/usb_mfunc.h> 72 #include <dev/usb/usb_error.h> 73 #include <dev/usb/usb_cdc.h> 74 #include <dev/usb/usb_ioctl.h> 75 76 #define USB_DEBUG_VAR usb2_com_debug 77 78 #include <dev/usb/usb_core.h> 79 #include <dev/usb/usb_debug.h> 80 #include <dev/usb/usb_process.h> 81 #include <dev/usb/usb_request.h> 82 #include <dev/usb/usb_busdma.h> 83 #include <dev/usb/usb_util.h> 84 85 #include <dev/usb/serial/usb_serial.h> 86 87 #if USB_DEBUG 88 static int usb2_com_debug = 0; 89 90 SYSCTL_NODE(_hw_usb2, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom"); 91 SYSCTL_INT(_hw_usb2_ucom, OID_AUTO, debug, CTLFLAG_RW, 92 &usb2_com_debug, 0, "ucom debug level"); 93 #endif 94 95 static usb2_proc_callback_t usb2_com_cfg_start_transfers; 96 static usb2_proc_callback_t usb2_com_cfg_open; 97 static usb2_proc_callback_t usb2_com_cfg_close; 98 static usb2_proc_callback_t usb2_com_cfg_line_state; 99 static usb2_proc_callback_t usb2_com_cfg_status_change; 100 static usb2_proc_callback_t usb2_com_cfg_param; 101 102 static uint8_t usb2_com_units_alloc(uint32_t, uint32_t *); 103 static void usb2_com_units_free(uint32_t, uint32_t); 104 static int usb2_com_attach_tty(struct usb2_com_softc *, uint32_t); 105 static void usb2_com_detach_tty(struct usb2_com_softc *); 106 static void usb2_com_queue_command(struct usb2_com_softc *, 107 usb2_proc_callback_t *, struct termios *pt, 108 struct usb2_proc_msg *t0, struct usb2_proc_msg *t1); 109 static void usb2_com_shutdown(struct usb2_com_softc *); 110 static void usb2_com_break(struct usb2_com_softc *, uint8_t); 111 static void usb2_com_dtr(struct usb2_com_softc *, uint8_t); 112 static void usb2_com_rts(struct usb2_com_softc *, uint8_t); 113 114 static tsw_open_t usb2_com_open; 115 static tsw_close_t usb2_com_close; 116 static tsw_ioctl_t usb2_com_ioctl; 117 static tsw_modem_t usb2_com_modem; 118 static tsw_param_t usb2_com_param; 119 static tsw_outwakeup_t usb2_com_outwakeup; 120 static tsw_free_t usb2_com_free; 121 122 static struct ttydevsw usb2_com_class = { 123 .tsw_flags = TF_INITLOCK | TF_CALLOUT, 124 .tsw_open = usb2_com_open, 125 .tsw_close = usb2_com_close, 126 .tsw_outwakeup = usb2_com_outwakeup, 127 .tsw_ioctl = usb2_com_ioctl, 128 .tsw_param = usb2_com_param, 129 .tsw_modem = usb2_com_modem, 130 .tsw_free = usb2_com_free, 131 }; 132 133 MODULE_DEPEND(ucom, usb, 1, 1, 1); 134 MODULE_VERSION(ucom, 1); 135 136 #define UCOM_UNIT_MAX 0x1000 /* exclusive */ 137 #define UCOM_SUB_UNIT_MAX 0x100 /* exclusive */ 138 139 static uint8_t usb2_com_bitmap[(UCOM_UNIT_MAX + 7) / 8]; 140 141 static uint8_t 142 usb2_com_units_alloc(uint32_t sub_units, uint32_t *p_root_unit) 143 { 144 uint32_t n; 145 uint32_t o; 146 uint32_t x; 147 uint32_t max = UCOM_UNIT_MAX - (UCOM_UNIT_MAX % sub_units); 148 uint8_t error = 1; 149 150 mtx_lock(&Giant); 151 152 for (n = 0; n < max; n += sub_units) { 153 154 /* check for free consecutive bits */ 155 156 for (o = 0; o < sub_units; o++) { 157 158 x = n + o; 159 160 if (usb2_com_bitmap[x / 8] & (1 << (x % 8))) { 161 goto skip; 162 } 163 } 164 165 /* allocate */ 166 167 for (o = 0; o < sub_units; o++) { 168 169 x = n + o; 170 171 usb2_com_bitmap[x / 8] |= (1 << (x % 8)); 172 } 173 174 error = 0; 175 176 break; 177 178 skip: ; 179 } 180 181 mtx_unlock(&Giant); 182 183 /* 184 * Always set the variable pointed to by "p_root_unit" so that 185 * the compiler does not think that it is used uninitialised: 186 */ 187 *p_root_unit = n; 188 189 return (error); 190 } 191 192 static void 193 usb2_com_units_free(uint32_t root_unit, uint32_t sub_units) 194 { 195 uint32_t x; 196 197 mtx_lock(&Giant); 198 199 while (sub_units--) { 200 x = root_unit + sub_units; 201 usb2_com_bitmap[x / 8] &= ~(1 << (x % 8)); 202 } 203 204 mtx_unlock(&Giant); 205 } 206 207 /* 208 * "N" sub_units are setup at a time. All sub-units will 209 * be given sequential unit numbers. The number of 210 * sub-units can be used to differentiate among 211 * different types of devices. 212 * 213 * The mutex pointed to by "mtx" is applied before all 214 * callbacks are called back. Also "mtx" must be applied 215 * before calling into the ucom-layer! 216 */ 217 int 218 usb2_com_attach(struct usb2_com_super_softc *ssc, struct usb2_com_softc *sc, 219 uint32_t sub_units, void *parent, 220 const struct usb2_com_callback *callback, struct mtx *mtx) 221 { 222 uint32_t n; 223 uint32_t root_unit; 224 int error = 0; 225 226 if ((sc == NULL) || 227 (sub_units == 0) || 228 (sub_units > UCOM_SUB_UNIT_MAX) || 229 (callback == NULL)) { 230 return (EINVAL); 231 } 232 233 /* XXX unit management does not really belong here */ 234 if (usb2_com_units_alloc(sub_units, &root_unit)) { 235 return (ENOMEM); 236 } 237 238 error = usb2_proc_create(&ssc->sc_tq, mtx, "ucom", USB_PRI_MED); 239 if (error) { 240 usb2_com_units_free(root_unit, sub_units); 241 return (error); 242 } 243 244 for (n = 0; n != sub_units; n++, sc++) { 245 sc->sc_unit = root_unit + n; 246 sc->sc_local_unit = n; 247 sc->sc_super = ssc; 248 sc->sc_mtx = mtx; 249 sc->sc_parent = parent; 250 sc->sc_callback = callback; 251 252 error = usb2_com_attach_tty(sc, sub_units); 253 if (error) { 254 usb2_com_detach(ssc, sc - n, n); 255 usb2_com_units_free(root_unit + n, sub_units - n); 256 return (error); 257 } 258 sc->sc_flag |= UCOM_FLAG_ATTACHED; 259 } 260 return (0); 261 } 262 263 /* 264 * NOTE: the following function will do nothing if 265 * the structure pointed to by "ssc" and "sc" is zero. 266 */ 267 void 268 usb2_com_detach(struct usb2_com_super_softc *ssc, struct usb2_com_softc *sc, 269 uint32_t sub_units) 270 { 271 uint32_t n; 272 273 usb2_proc_drain(&ssc->sc_tq); 274 275 for (n = 0; n != sub_units; n++, sc++) { 276 if (sc->sc_flag & UCOM_FLAG_ATTACHED) { 277 278 usb2_com_detach_tty(sc); 279 280 usb2_com_units_free(sc->sc_unit, 1); 281 282 /* avoid duplicate detach: */ 283 sc->sc_flag &= ~UCOM_FLAG_ATTACHED; 284 } 285 } 286 usb2_proc_free(&ssc->sc_tq); 287 } 288 289 static int 290 usb2_com_attach_tty(struct usb2_com_softc *sc, uint32_t sub_units) 291 { 292 struct tty *tp; 293 int error = 0; 294 char buf[32]; /* temporary TTY device name buffer */ 295 296 tp = tty_alloc(&usb2_com_class, sc, sc->sc_mtx); 297 if (tp == NULL) { 298 error = ENOMEM; 299 goto done; 300 } 301 DPRINTF("tp = %p, unit = %d\n", tp, sc->sc_unit); 302 303 buf[0] = 0; /* set some default value */ 304 305 /* Check if the client has a custom TTY name */ 306 if (sc->sc_callback->usb2_com_tty_name) { 307 sc->sc_callback->usb2_com_tty_name(sc, buf, 308 sizeof(buf), sc->sc_local_unit); 309 } 310 if (buf[0] == 0) { 311 /* Use default TTY name */ 312 if (sub_units > 1) { 313 /* multiple modems in one */ 314 if (snprintf(buf, sizeof(buf), "U%u.%u", 315 sc->sc_unit - sc->sc_local_unit, 316 sc->sc_local_unit)) { 317 /* ignore */ 318 } 319 } else { 320 /* single modem */ 321 if (snprintf(buf, sizeof(buf), "U%u", sc->sc_unit)) { 322 /* ignore */ 323 } 324 } 325 } 326 tty_makedev(tp, NULL, "%s", buf); 327 328 sc->sc_tty = tp; 329 330 DPRINTF("ttycreate: %s\n", buf); 331 usb2_cv_init(&sc->sc_cv, "usb2_com"); 332 333 done: 334 return (error); 335 } 336 337 static void 338 usb2_com_detach_tty(struct usb2_com_softc *sc) 339 { 340 struct tty *tp = sc->sc_tty; 341 342 DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty); 343 344 /* the config thread has been stopped when we get here */ 345 346 mtx_lock(sc->sc_mtx); 347 sc->sc_flag |= UCOM_FLAG_GONE; 348 sc->sc_flag &= ~(UCOM_FLAG_HL_READY | 349 UCOM_FLAG_LL_READY); 350 mtx_unlock(sc->sc_mtx); 351 if (tp) { 352 tty_lock(tp); 353 354 usb2_com_close(tp); /* close, if any */ 355 356 tty_rel_gone(tp); 357 358 mtx_lock(sc->sc_mtx); 359 /* Wait for the callback after the TTY is torn down */ 360 while (sc->sc_ttyfreed == 0) 361 usb2_cv_wait(&sc->sc_cv, sc->sc_mtx); 362 /* 363 * make sure that read and write transfers are stopped 364 */ 365 if (sc->sc_callback->usb2_com_stop_read) { 366 (sc->sc_callback->usb2_com_stop_read) (sc); 367 } 368 if (sc->sc_callback->usb2_com_stop_write) { 369 (sc->sc_callback->usb2_com_stop_write) (sc); 370 } 371 mtx_unlock(sc->sc_mtx); 372 } 373 usb2_cv_destroy(&sc->sc_cv); 374 } 375 376 static void 377 usb2_com_queue_command(struct usb2_com_softc *sc, 378 usb2_proc_callback_t *fn, struct termios *pt, 379 struct usb2_proc_msg *t0, struct usb2_proc_msg *t1) 380 { 381 struct usb2_com_super_softc *ssc = sc->sc_super; 382 struct usb2_com_param_task *task; 383 384 mtx_assert(sc->sc_mtx, MA_OWNED); 385 386 if (usb2_proc_is_gone(&ssc->sc_tq)) { 387 DPRINTF("proc is gone\n"); 388 return; /* nothing to do */ 389 } 390 /* 391 * NOTE: The task cannot get executed before we drop the 392 * "sc_mtx" mutex. It is safe to update fields in the message 393 * structure after that the message got queued. 394 */ 395 task = (struct usb2_com_param_task *) 396 usb2_proc_msignal(&ssc->sc_tq, t0, t1); 397 398 /* Setup callback and softc pointers */ 399 task->hdr.pm_callback = fn; 400 task->sc = sc; 401 402 /* 403 * Make a copy of the termios. This field is only present if 404 * the "pt" field is not NULL. 405 */ 406 if (pt != NULL) 407 task->termios_copy = *pt; 408 409 /* 410 * Closing the device should be synchronous. 411 */ 412 if (fn == usb2_com_cfg_close) 413 usb2_proc_mwait(&ssc->sc_tq, t0, t1); 414 415 } 416 417 static void 418 usb2_com_shutdown(struct usb2_com_softc *sc) 419 { 420 struct tty *tp = sc->sc_tty; 421 422 mtx_assert(sc->sc_mtx, MA_OWNED); 423 424 DPRINTF("\n"); 425 426 /* 427 * Hang up if necessary: 428 */ 429 if (tp->t_termios.c_cflag & HUPCL) { 430 usb2_com_modem(tp, 0, SER_DTR); 431 } 432 } 433 434 /* 435 * Return values: 436 * 0: normal 437 * else: taskqueue is draining or gone 438 */ 439 uint8_t 440 usb2_com_cfg_is_gone(struct usb2_com_softc *sc) 441 { 442 struct usb2_com_super_softc *ssc = sc->sc_super; 443 444 return (usb2_proc_is_gone(&ssc->sc_tq)); 445 } 446 447 static void 448 usb2_com_cfg_start_transfers(struct usb2_proc_msg *_task) 449 { 450 struct usb2_com_cfg_task *task = 451 (struct usb2_com_cfg_task *)_task; 452 struct usb2_com_softc *sc = task->sc; 453 454 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 455 return; 456 } 457 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 458 /* TTY device closed */ 459 return; 460 } 461 sc->sc_flag |= UCOM_FLAG_GP_DATA; 462 463 if (sc->sc_callback->usb2_com_start_read) { 464 (sc->sc_callback->usb2_com_start_read) (sc); 465 } 466 if (sc->sc_callback->usb2_com_start_write) { 467 (sc->sc_callback->usb2_com_start_write) (sc); 468 } 469 } 470 471 static void 472 usb2_com_start_transfers(struct usb2_com_softc *sc) 473 { 474 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 475 return; 476 } 477 /* 478 * Make sure that data transfers are started in both 479 * directions: 480 */ 481 if (sc->sc_callback->usb2_com_start_read) { 482 (sc->sc_callback->usb2_com_start_read) (sc); 483 } 484 if (sc->sc_callback->usb2_com_start_write) { 485 (sc->sc_callback->usb2_com_start_write) (sc); 486 } 487 } 488 489 static void 490 usb2_com_cfg_open(struct usb2_proc_msg *_task) 491 { 492 struct usb2_com_cfg_task *task = 493 (struct usb2_com_cfg_task *)_task; 494 struct usb2_com_softc *sc = task->sc; 495 496 DPRINTF("\n"); 497 498 if (sc->sc_flag & UCOM_FLAG_LL_READY) { 499 500 /* already opened */ 501 502 } else { 503 504 sc->sc_flag |= UCOM_FLAG_LL_READY; 505 506 if (sc->sc_callback->usb2_com_cfg_open) { 507 (sc->sc_callback->usb2_com_cfg_open) (sc); 508 509 /* wait a little */ 510 usb2_pause_mtx(sc->sc_mtx, hz / 10); 511 } 512 } 513 } 514 515 static int 516 usb2_com_open(struct tty *tp) 517 { 518 struct usb2_com_softc *sc = tty_softc(tp); 519 int error; 520 521 mtx_assert(sc->sc_mtx, MA_OWNED); 522 523 if (sc->sc_flag & UCOM_FLAG_GONE) { 524 return (ENXIO); 525 } 526 if (sc->sc_flag & UCOM_FLAG_HL_READY) { 527 /* already opened */ 528 return (0); 529 } 530 DPRINTF("tp = %p\n", tp); 531 532 if (sc->sc_callback->usb2_com_pre_open) { 533 /* 534 * give the lower layer a chance to disallow TTY open, for 535 * example if the device is not present: 536 */ 537 error = (sc->sc_callback->usb2_com_pre_open) (sc); 538 if (error) { 539 return (error); 540 } 541 } 542 sc->sc_flag |= UCOM_FLAG_HL_READY; 543 544 /* Disable transfers */ 545 sc->sc_flag &= ~UCOM_FLAG_GP_DATA; 546 547 sc->sc_lsr = 0; 548 sc->sc_msr = 0; 549 sc->sc_mcr = 0; 550 551 /* reset programmed line state */ 552 sc->sc_pls_curr = 0; 553 sc->sc_pls_set = 0; 554 sc->sc_pls_clr = 0; 555 556 usb2_com_queue_command(sc, usb2_com_cfg_open, NULL, 557 &sc->sc_open_task[0].hdr, 558 &sc->sc_open_task[1].hdr); 559 560 /* Queue transfer enable command last */ 561 usb2_com_queue_command(sc, usb2_com_cfg_start_transfers, NULL, 562 &sc->sc_start_task[0].hdr, 563 &sc->sc_start_task[1].hdr); 564 565 usb2_com_modem(tp, SER_DTR | SER_RTS, 0); 566 567 usb2_com_break(sc, 0); 568 569 usb2_com_status_change(sc); 570 571 return (0); 572 } 573 574 static void 575 usb2_com_cfg_close(struct usb2_proc_msg *_task) 576 { 577 struct usb2_com_cfg_task *task = 578 (struct usb2_com_cfg_task *)_task; 579 struct usb2_com_softc *sc = task->sc; 580 581 DPRINTF("\n"); 582 583 if (sc->sc_flag & UCOM_FLAG_LL_READY) { 584 585 sc->sc_flag &= ~(UCOM_FLAG_LL_READY | 586 UCOM_FLAG_GP_DATA); 587 588 if (sc->sc_callback->usb2_com_cfg_close) { 589 (sc->sc_callback->usb2_com_cfg_close) (sc); 590 } 591 } else { 592 /* already closed */ 593 } 594 } 595 596 static void 597 usb2_com_close(struct tty *tp) 598 { 599 struct usb2_com_softc *sc = tty_softc(tp); 600 601 mtx_assert(sc->sc_mtx, MA_OWNED); 602 603 DPRINTF("tp=%p\n", tp); 604 605 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 606 DPRINTF("tp=%p already closed\n", tp); 607 return; 608 } 609 usb2_com_shutdown(sc); 610 611 usb2_com_queue_command(sc, usb2_com_cfg_close, NULL, 612 &sc->sc_close_task[0].hdr, 613 &sc->sc_close_task[1].hdr); 614 615 sc->sc_flag &= ~(UCOM_FLAG_HL_READY | 616 UCOM_FLAG_WR_START | 617 UCOM_FLAG_RTS_IFLOW); 618 619 if (sc->sc_callback->usb2_com_stop_read) { 620 (sc->sc_callback->usb2_com_stop_read) (sc); 621 } 622 if (sc->sc_callback->usb2_com_stop_write) { 623 (sc->sc_callback->usb2_com_stop_write) (sc); 624 } 625 } 626 627 static int 628 usb2_com_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) 629 { 630 struct usb2_com_softc *sc = tty_softc(tp); 631 int error; 632 633 mtx_assert(sc->sc_mtx, MA_OWNED); 634 635 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 636 return (EIO); 637 } 638 DPRINTF("cmd = 0x%08lx\n", cmd); 639 640 switch (cmd) { 641 case TIOCSBRK: 642 usb2_com_break(sc, 1); 643 error = 0; 644 break; 645 case TIOCCBRK: 646 usb2_com_break(sc, 0); 647 error = 0; 648 break; 649 default: 650 if (sc->sc_callback->usb2_com_ioctl) { 651 error = (sc->sc_callback->usb2_com_ioctl) 652 (sc, cmd, data, 0, td); 653 } else { 654 error = ENOIOCTL; 655 } 656 break; 657 } 658 return (error); 659 } 660 661 static int 662 usb2_com_modem(struct tty *tp, int sigon, int sigoff) 663 { 664 struct usb2_com_softc *sc = tty_softc(tp); 665 uint8_t onoff; 666 667 mtx_assert(sc->sc_mtx, MA_OWNED); 668 669 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 670 return (0); 671 } 672 if ((sigon == 0) && (sigoff == 0)) { 673 674 if (sc->sc_mcr & SER_DTR) { 675 sigon |= SER_DTR; 676 } 677 if (sc->sc_mcr & SER_RTS) { 678 sigon |= SER_RTS; 679 } 680 if (sc->sc_msr & SER_CTS) { 681 sigon |= SER_CTS; 682 } 683 if (sc->sc_msr & SER_DCD) { 684 sigon |= SER_DCD; 685 } 686 if (sc->sc_msr & SER_DSR) { 687 sigon |= SER_DSR; 688 } 689 if (sc->sc_msr & SER_RI) { 690 sigon |= SER_RI; 691 } 692 return (sigon); 693 } 694 if (sigon & SER_DTR) { 695 sc->sc_mcr |= SER_DTR; 696 } 697 if (sigoff & SER_DTR) { 698 sc->sc_mcr &= ~SER_DTR; 699 } 700 if (sigon & SER_RTS) { 701 sc->sc_mcr |= SER_RTS; 702 } 703 if (sigoff & SER_RTS) { 704 sc->sc_mcr &= ~SER_RTS; 705 } 706 onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0; 707 usb2_com_dtr(sc, onoff); 708 709 onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0; 710 usb2_com_rts(sc, onoff); 711 712 return (0); 713 } 714 715 static void 716 usb2_com_cfg_line_state(struct usb2_proc_msg *_task) 717 { 718 struct usb2_com_cfg_task *task = 719 (struct usb2_com_cfg_task *)_task; 720 struct usb2_com_softc *sc = task->sc; 721 uint8_t notch_bits; 722 uint8_t any_bits; 723 uint8_t prev_value; 724 uint8_t last_value; 725 uint8_t mask; 726 727 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 728 return; 729 } 730 731 mask = 0; 732 /* compute callback mask */ 733 if (sc->sc_callback->usb2_com_cfg_set_dtr) 734 mask |= UCOM_LS_DTR; 735 if (sc->sc_callback->usb2_com_cfg_set_rts) 736 mask |= UCOM_LS_RTS; 737 if (sc->sc_callback->usb2_com_cfg_set_break) 738 mask |= UCOM_LS_BREAK; 739 740 /* compute the bits we are to program */ 741 notch_bits = (sc->sc_pls_set & sc->sc_pls_clr) & mask; 742 any_bits = (sc->sc_pls_set | sc->sc_pls_clr) & mask; 743 prev_value = sc->sc_pls_curr ^ notch_bits; 744 last_value = sc->sc_pls_curr; 745 746 /* reset programmed line state */ 747 sc->sc_pls_curr = 0; 748 sc->sc_pls_set = 0; 749 sc->sc_pls_clr = 0; 750 751 /* ensure that we don't loose any levels */ 752 if (notch_bits & UCOM_LS_DTR) 753 sc->sc_callback->usb2_com_cfg_set_dtr(sc, 754 (prev_value & UCOM_LS_DTR) ? 1 : 0); 755 if (notch_bits & UCOM_LS_RTS) 756 sc->sc_callback->usb2_com_cfg_set_rts(sc, 757 (prev_value & UCOM_LS_RTS) ? 1 : 0); 758 if (notch_bits & UCOM_LS_BREAK) 759 sc->sc_callback->usb2_com_cfg_set_break(sc, 760 (prev_value & UCOM_LS_BREAK) ? 1 : 0); 761 762 /* set last value */ 763 if (any_bits & UCOM_LS_DTR) 764 sc->sc_callback->usb2_com_cfg_set_dtr(sc, 765 (last_value & UCOM_LS_DTR) ? 1 : 0); 766 if (any_bits & UCOM_LS_RTS) 767 sc->sc_callback->usb2_com_cfg_set_rts(sc, 768 (last_value & UCOM_LS_RTS) ? 1 : 0); 769 if (any_bits & UCOM_LS_BREAK) 770 sc->sc_callback->usb2_com_cfg_set_break(sc, 771 (last_value & UCOM_LS_BREAK) ? 1 : 0); 772 } 773 774 static void 775 usb2_com_line_state(struct usb2_com_softc *sc, 776 uint8_t set_bits, uint8_t clear_bits) 777 { 778 mtx_assert(sc->sc_mtx, MA_OWNED); 779 780 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 781 return; 782 } 783 784 DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits); 785 786 /* update current programmed line state */ 787 sc->sc_pls_curr |= set_bits; 788 sc->sc_pls_curr &= ~clear_bits; 789 sc->sc_pls_set |= set_bits; 790 sc->sc_pls_clr |= clear_bits; 791 792 /* defer driver programming */ 793 usb2_com_queue_command(sc, usb2_com_cfg_line_state, NULL, 794 &sc->sc_line_state_task[0].hdr, 795 &sc->sc_line_state_task[1].hdr); 796 } 797 798 static void 799 usb2_com_break(struct usb2_com_softc *sc, uint8_t onoff) 800 { 801 DPRINTF("onoff = %d\n", onoff); 802 803 if (onoff) 804 usb2_com_line_state(sc, UCOM_LS_BREAK, 0); 805 else 806 usb2_com_line_state(sc, 0, UCOM_LS_BREAK); 807 } 808 809 static void 810 usb2_com_dtr(struct usb2_com_softc *sc, uint8_t onoff) 811 { 812 DPRINTF("onoff = %d\n", onoff); 813 814 if (onoff) 815 usb2_com_line_state(sc, UCOM_LS_DTR, 0); 816 else 817 usb2_com_line_state(sc, 0, UCOM_LS_DTR); 818 } 819 820 static void 821 usb2_com_rts(struct usb2_com_softc *sc, uint8_t onoff) 822 { 823 DPRINTF("onoff = %d\n", onoff); 824 825 if (onoff) 826 usb2_com_line_state(sc, UCOM_LS_RTS, 0); 827 else 828 usb2_com_line_state(sc, 0, UCOM_LS_RTS); 829 } 830 831 static void 832 usb2_com_cfg_status_change(struct usb2_proc_msg *_task) 833 { 834 struct usb2_com_cfg_task *task = 835 (struct usb2_com_cfg_task *)_task; 836 struct usb2_com_softc *sc = task->sc; 837 struct tty *tp; 838 uint8_t new_msr; 839 uint8_t new_lsr; 840 uint8_t onoff; 841 842 tp = sc->sc_tty; 843 844 mtx_assert(sc->sc_mtx, MA_OWNED); 845 846 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 847 return; 848 } 849 if (sc->sc_callback->usb2_com_cfg_get_status == NULL) { 850 return; 851 } 852 /* get status */ 853 854 new_msr = 0; 855 new_lsr = 0; 856 857 (sc->sc_callback->usb2_com_cfg_get_status) (sc, &new_lsr, &new_msr); 858 859 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 860 /* TTY device closed */ 861 return; 862 } 863 onoff = ((sc->sc_msr ^ new_msr) & SER_DCD); 864 865 sc->sc_msr = new_msr; 866 sc->sc_lsr = new_lsr; 867 868 if (onoff) { 869 870 onoff = (sc->sc_msr & SER_DCD) ? 1 : 0; 871 872 DPRINTF("DCD changed to %d\n", onoff); 873 874 ttydisc_modem(tp, onoff); 875 } 876 } 877 878 void 879 usb2_com_status_change(struct usb2_com_softc *sc) 880 { 881 mtx_assert(sc->sc_mtx, MA_OWNED); 882 883 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 884 return; 885 } 886 DPRINTF("\n"); 887 888 usb2_com_queue_command(sc, usb2_com_cfg_status_change, NULL, 889 &sc->sc_status_task[0].hdr, 890 &sc->sc_status_task[1].hdr); 891 } 892 893 static void 894 usb2_com_cfg_param(struct usb2_proc_msg *_task) 895 { 896 struct usb2_com_param_task *task = 897 (struct usb2_com_param_task *)_task; 898 struct usb2_com_softc *sc = task->sc; 899 900 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 901 return; 902 } 903 if (sc->sc_callback->usb2_com_cfg_param == NULL) { 904 return; 905 } 906 907 (sc->sc_callback->usb2_com_cfg_param) (sc, &task->termios_copy); 908 909 /* wait a little */ 910 usb2_pause_mtx(sc->sc_mtx, hz / 10); 911 } 912 913 static int 914 usb2_com_param(struct tty *tp, struct termios *t) 915 { 916 struct usb2_com_softc *sc = tty_softc(tp); 917 uint8_t opened; 918 int error; 919 920 mtx_assert(sc->sc_mtx, MA_OWNED); 921 922 opened = 0; 923 error = 0; 924 925 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 926 927 /* XXX the TTY layer should call "open()" first! */ 928 929 error = usb2_com_open(tp); 930 if (error) { 931 goto done; 932 } 933 opened = 1; 934 } 935 DPRINTF("sc = %p\n", sc); 936 937 /* Check requested parameters. */ 938 if (t->c_ospeed < 0) { 939 DPRINTF("negative ospeed\n"); 940 error = EINVAL; 941 goto done; 942 } 943 if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) { 944 DPRINTF("mismatch ispeed and ospeed\n"); 945 error = EINVAL; 946 goto done; 947 } 948 t->c_ispeed = t->c_ospeed; 949 950 if (sc->sc_callback->usb2_com_pre_param) { 951 /* Let the lower layer verify the parameters */ 952 error = (sc->sc_callback->usb2_com_pre_param) (sc, t); 953 if (error) { 954 DPRINTF("callback error = %d\n", error); 955 goto done; 956 } 957 } 958 959 /* Disable transfers */ 960 sc->sc_flag &= ~UCOM_FLAG_GP_DATA; 961 962 /* Queue baud rate programming command first */ 963 usb2_com_queue_command(sc, usb2_com_cfg_param, t, 964 &sc->sc_param_task[0].hdr, 965 &sc->sc_param_task[1].hdr); 966 967 /* Queue transfer enable command last */ 968 usb2_com_queue_command(sc, usb2_com_cfg_start_transfers, NULL, 969 &sc->sc_start_task[0].hdr, 970 &sc->sc_start_task[1].hdr); 971 972 if (t->c_cflag & CRTS_IFLOW) { 973 sc->sc_flag |= UCOM_FLAG_RTS_IFLOW; 974 } else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) { 975 sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW; 976 usb2_com_modem(tp, SER_RTS, 0); 977 } 978 done: 979 if (error) { 980 if (opened) { 981 usb2_com_close(tp); 982 } 983 } 984 return (error); 985 } 986 987 static void 988 usb2_com_outwakeup(struct tty *tp) 989 { 990 struct usb2_com_softc *sc = tty_softc(tp); 991 992 mtx_assert(sc->sc_mtx, MA_OWNED); 993 994 DPRINTF("sc = %p\n", sc); 995 996 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 997 /* The higher layer is not ready */ 998 return; 999 } 1000 sc->sc_flag |= UCOM_FLAG_WR_START; 1001 1002 usb2_com_start_transfers(sc); 1003 } 1004 1005 /*------------------------------------------------------------------------* 1006 * usb2_com_get_data 1007 * 1008 * Return values: 1009 * 0: No data is available. 1010 * Else: Data is available. 1011 *------------------------------------------------------------------------*/ 1012 uint8_t 1013 usb2_com_get_data(struct usb2_com_softc *sc, struct usb2_page_cache *pc, 1014 uint32_t offset, uint32_t len, uint32_t *actlen) 1015 { 1016 struct usb2_page_search res; 1017 struct tty *tp = sc->sc_tty; 1018 uint32_t cnt; 1019 uint32_t offset_orig; 1020 1021 mtx_assert(sc->sc_mtx, MA_OWNED); 1022 1023 if ((!(sc->sc_flag & UCOM_FLAG_HL_READY)) || 1024 (!(sc->sc_flag & UCOM_FLAG_GP_DATA)) || 1025 (!(sc->sc_flag & UCOM_FLAG_WR_START))) { 1026 actlen[0] = 0; 1027 return (0); /* multiport device polling */ 1028 } 1029 offset_orig = offset; 1030 1031 while (len != 0) { 1032 1033 usb2_get_page(pc, offset, &res); 1034 1035 if (res.length > len) { 1036 res.length = len; 1037 } 1038 /* copy data directly into USB buffer */ 1039 cnt = ttydisc_getc(tp, res.buffer, res.length); 1040 1041 offset += cnt; 1042 len -= cnt; 1043 1044 if (cnt < res.length) { 1045 /* end of buffer */ 1046 break; 1047 } 1048 } 1049 1050 actlen[0] = offset - offset_orig; 1051 1052 DPRINTF("cnt=%d\n", actlen[0]); 1053 1054 if (actlen[0] == 0) { 1055 return (0); 1056 } 1057 return (1); 1058 } 1059 1060 void 1061 usb2_com_put_data(struct usb2_com_softc *sc, struct usb2_page_cache *pc, 1062 uint32_t offset, uint32_t len) 1063 { 1064 struct usb2_page_search res; 1065 struct tty *tp = sc->sc_tty; 1066 char *buf; 1067 uint32_t cnt; 1068 1069 mtx_assert(sc->sc_mtx, MA_OWNED); 1070 1071 if ((!(sc->sc_flag & UCOM_FLAG_HL_READY)) || 1072 (!(sc->sc_flag & UCOM_FLAG_GP_DATA))) { 1073 return; /* multiport device polling */ 1074 } 1075 if (len == 0) 1076 return; /* no data */ 1077 1078 /* set a flag to prevent recursation ? */ 1079 1080 while (len > 0) { 1081 1082 usb2_get_page(pc, offset, &res); 1083 1084 if (res.length > len) { 1085 res.length = len; 1086 } 1087 len -= res.length; 1088 offset += res.length; 1089 1090 /* pass characters to tty layer */ 1091 1092 buf = res.buffer; 1093 cnt = res.length; 1094 1095 /* first check if we can pass the buffer directly */ 1096 1097 if (ttydisc_can_bypass(tp)) { 1098 if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) { 1099 DPRINTF("tp=%p, data lost\n", tp); 1100 } 1101 continue; 1102 } 1103 /* need to loop */ 1104 1105 for (cnt = 0; cnt != res.length; cnt++) { 1106 if (ttydisc_rint(tp, buf[cnt], 0) == -1) { 1107 /* XXX what should we do? */ 1108 1109 DPRINTF("tp=%p, lost %d " 1110 "chars\n", tp, res.length - cnt); 1111 break; 1112 } 1113 } 1114 } 1115 ttydisc_rint_done(tp); 1116 } 1117 1118 static void 1119 usb2_com_free(void *xsc) 1120 { 1121 struct usb2_com_softc *sc = xsc; 1122 1123 mtx_lock(sc->sc_mtx); 1124 sc->sc_ttyfreed = 1; 1125 usb2_cv_signal(&sc->sc_cv); 1126 mtx_unlock(sc->sc_mtx); 1127 } 1128