usb_serial.c revision 184736
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/usb2/serial/usb2_serial.c 184736 2008-11-06 17:26:12Z imp $"); 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/* 71 * NOTE: all function names beginning like "usb2_com_cfg_" can only 72 * be called from within the config thread function ! 73 */ 74 75#include <dev/usb2/include/usb2_standard.h> 76#include <dev/usb2/include/usb2_mfunc.h> 77#include <dev/usb2/include/usb2_error.h> 78#include <dev/usb2/include/usb2_cdc.h> 79 80#define USB_DEBUG_VAR usb2_com_debug 81#define usb2_config_td_cc usb2_com_config_copy 82#define usb2_config_td_softc usb2_com_softc 83 84#include <dev/usb2/core/usb2_core.h> 85#include <dev/usb2/core/usb2_debug.h> 86#include <dev/usb2/core/usb2_process.h> 87#include <dev/usb2/core/usb2_config_td.h> 88#include <dev/usb2/core/usb2_request.h> 89#include <dev/usb2/core/usb2_busdma.h> 90#include <dev/usb2/core/usb2_util.h> 91 92#include <dev/usb2/serial/usb2_serial.h> 93 94#if USB_DEBUG 95static int usb2_com_debug = 0; 96 97SYSCTL_NODE(_hw_usb2, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom"); 98SYSCTL_INT(_hw_usb2_ucom, OID_AUTO, debug, CTLFLAG_RW, 99 &usb2_com_debug, 0, "ucom debug level"); 100#endif 101 102struct usb2_com_config_copy { 103 struct usb2_com_softc *cc_softc; 104 uint8_t cc_flag0; 105 uint8_t cc_flag1; 106 uint8_t cc_flag2; 107 uint8_t cc_flag3; 108}; 109 110static usb2_config_td_command_t usb2_com_config_copy; 111static usb2_config_td_command_t usb2_com_cfg_start_transfers; 112static usb2_config_td_command_t usb2_com_cfg_open; 113static usb2_config_td_command_t usb2_com_cfg_close; 114static usb2_config_td_command_t usb2_com_cfg_break; 115static usb2_config_td_command_t usb2_com_cfg_dtr; 116static usb2_config_td_command_t usb2_com_cfg_rts; 117static usb2_config_td_command_t usb2_com_cfg_status_change; 118static usb2_config_td_command_t usb2_com_cfg_param; 119 120static uint8_t usb2_com_units_alloc(uint32_t sub_units, uint32_t *p_root_unit); 121static void usb2_com_units_free(uint32_t root_unit, uint32_t sub_units); 122static int usb2_com_attach_sub(struct usb2_com_softc *sc); 123static void usb2_com_detach_sub(struct usb2_com_softc *sc); 124static void usb2_com_queue_command(struct usb2_com_softc *sc, usb2_config_td_command_t *cmd, int flag); 125static void usb2_com_shutdown(struct usb2_com_softc *sc); 126static void usb2_com_start_transfers(struct usb2_com_softc *sc); 127static void usb2_com_break(struct usb2_com_softc *sc, uint8_t onoff); 128static void usb2_com_dtr(struct usb2_com_softc *sc, uint8_t onoff); 129static void usb2_com_rts(struct usb2_com_softc *sc, uint8_t onoff); 130 131static tsw_open_t usb2_com_open; 132static tsw_close_t usb2_com_close; 133static tsw_ioctl_t usb2_com_ioctl; 134static tsw_modem_t usb2_com_modem; 135static tsw_param_t usb2_com_param; 136static tsw_outwakeup_t usb2_com_start_write; 137static tsw_free_t usb2_com_free; 138 139static struct ttydevsw usb2_com_class = { 140 .tsw_flags = TF_INITLOCK | TF_CALLOUT, 141 .tsw_open = usb2_com_open, 142 .tsw_close = usb2_com_close, 143 .tsw_outwakeup = usb2_com_start_write, 144 .tsw_ioctl = usb2_com_ioctl, 145 .tsw_param = usb2_com_param, 146 .tsw_modem = usb2_com_modem, 147 .tsw_free = usb2_com_free, 148}; 149 150MODULE_DEPEND(usb2_serial, usb2_core, 1, 1, 1); 151MODULE_VERSION(usb2_serial, 1); 152 153#define UCOM_UNIT_MAX 0x1000 /* exclusive */ 154#define UCOM_SUB_UNIT_MAX 0x100 /* exclusive */ 155 156static uint8_t usb2_com_bitmap[(UCOM_UNIT_MAX + 7) / 8]; 157 158static uint8_t 159usb2_com_units_alloc(uint32_t sub_units, uint32_t *p_root_unit) 160{ 161 uint32_t n; 162 uint32_t o; 163 uint32_t x; 164 uint32_t max = UCOM_UNIT_MAX - (UCOM_UNIT_MAX % sub_units); 165 uint8_t error = 1; 166 167 mtx_lock(&Giant); 168 169 for (n = 0; n < max; n += sub_units) { 170 171 /* check for free consecutive bits */ 172 173 for (o = 0; o < sub_units; o++) { 174 175 x = n + o; 176 177 if (usb2_com_bitmap[x / 8] & (1 << (x % 8))) { 178 goto skip; 179 } 180 } 181 182 /* allocate */ 183 184 for (o = 0; o < sub_units; o++) { 185 186 x = n + o; 187 188 usb2_com_bitmap[x / 8] |= (1 << (x % 8)); 189 } 190 191 error = 0; 192 193 break; 194 195skip: ; 196 } 197 198 mtx_unlock(&Giant); 199 200 /* 201 * Always set the variable pointed to by "p_root_unit" so that 202 * the compiler does not think that it is used uninitialised: 203 */ 204 *p_root_unit = n; 205 206 return (error); 207} 208 209static void 210usb2_com_units_free(uint32_t root_unit, uint32_t sub_units) 211{ 212 uint32_t x; 213 214 mtx_lock(&Giant); 215 216 while (sub_units--) { 217 x = root_unit + sub_units; 218 usb2_com_bitmap[x / 8] &= ~(1 << (x % 8)); 219 } 220 221 mtx_unlock(&Giant); 222 223 return; 224} 225 226/* 227 * "N" sub_units are setup at a time. All sub-units will 228 * be given sequential unit numbers. The number of 229 * sub-units can be used to differentiate among 230 * different types of devices. 231 * 232 * The mutex pointed to by "p_mtx" is applied before all 233 * callbacks are called back. Also "p_mtx" must be applied 234 * before calling into the ucom-layer! Currently only Giant 235 * is supported. 236 */ 237int 238usb2_com_attach(struct usb2_com_super_softc *ssc, struct usb2_com_softc *sc, 239 uint32_t sub_units, void *parent, 240 const struct usb2_com_callback *callback, struct mtx *p_mtx) 241{ 242 uint32_t n; 243 uint32_t root_unit; 244 int error = 0; 245 246 if ((sc == NULL) || 247 (sub_units == 0) || 248 (sub_units > UCOM_SUB_UNIT_MAX) || 249 (callback == NULL)) { 250 return (EINVAL); 251 } 252 if (usb2_com_units_alloc(sub_units, &root_unit)) { 253 return (ENOMEM); 254 } 255 if (usb2_config_td_setup 256 (&ssc->sc_config_td, sc, p_mtx, NULL, 257 sizeof(struct usb2_com_config_copy), 24 * sub_units)) { 258 usb2_com_units_free(root_unit, sub_units); 259 return (ENOMEM); 260 } 261 for (n = 0; n < sub_units; n++, sc++) { 262 sc->sc_unit = root_unit + n; 263 sc->sc_local_unit = n; 264 sc->sc_super = ssc; 265 sc->sc_parent_mtx = p_mtx; 266 sc->sc_parent = parent; 267 sc->sc_callback = callback; 268 269 error = usb2_com_attach_sub(sc); 270 if (error) { 271 usb2_com_detach(ssc, sc - n, n); 272 usb2_com_units_free(root_unit + n, sub_units - n); 273 break; 274 } 275 sc->sc_flag |= UCOM_FLAG_ATTACHED; 276 } 277 return (error); 278} 279 280/* NOTE: the following function will do nothing if 281 * the structure pointed to by "ssc" and "sc" is zero. 282 */ 283void 284usb2_com_detach(struct usb2_com_super_softc *ssc, struct usb2_com_softc *sc, 285 uint32_t sub_units) 286{ 287 uint32_t n; 288 289 usb2_config_td_drain(&ssc->sc_config_td); 290 291 for (n = 0; n < sub_units; n++, sc++) { 292 if (sc->sc_flag & UCOM_FLAG_ATTACHED) { 293 294 usb2_com_detach_sub(sc); 295 296 usb2_com_units_free(sc->sc_unit, 1); 297 298 /* avoid duplicate detach: */ 299 sc->sc_flag &= ~UCOM_FLAG_ATTACHED; 300 } 301 } 302 303 usb2_config_td_unsetup(&ssc->sc_config_td); 304 305 return; 306} 307 308static int 309usb2_com_attach_sub(struct usb2_com_softc *sc) 310{ 311 struct tty *tp; 312 int error = 0; 313 char buf[32]; /* temporary TTY device name buffer */ 314 315 tp = tty_alloc(&usb2_com_class, sc, sc->sc_parent_mtx); 316 if (tp == NULL) { 317 error = ENOMEM; 318 goto done; 319 } 320 DPRINTF("tp = %p, unit = %d\n", tp, sc->sc_unit); 321 322 buf[0] = 0; /* set some default value */ 323 324 /* Check if the client has a custom TTY name */ 325 if (sc->sc_callback->usb2_com_tty_name) { 326 sc->sc_callback->usb2_com_tty_name(sc, buf, 327 sizeof(buf), sc->sc_local_unit); 328 } 329 if (buf[0] == 0) { 330 /* Use default TTY name */ 331 if (snprintf(buf, sizeof(buf), "U%u", sc->sc_unit)) { 332 /* ignore */ 333 } 334 } 335 tty_makedev(tp, NULL, "%s", buf); 336 337 sc->sc_tty = tp; 338 339 DPRINTF("ttycreate: %s\n", buf); 340 usb2_cv_init(&sc->sc_cv, "usb2_com"); 341 342done: 343 return (error); 344} 345 346static void 347usb2_com_detach_sub(struct usb2_com_softc *sc) 348{ 349 struct tty *tp = sc->sc_tty; 350 351 DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty); 352 353 /* the config thread has been stopped when we get here */ 354 355 mtx_lock(sc->sc_parent_mtx); 356 sc->sc_flag |= UCOM_FLAG_GONE; 357 sc->sc_flag &= ~(UCOM_FLAG_HL_READY | 358 UCOM_FLAG_LL_READY); 359 mtx_unlock(sc->sc_parent_mtx); 360 if (tp) { 361 tty_lock(tp); 362 363 usb2_com_close(tp); /* close, if any */ 364 365 tty_rel_gone(tp); 366 367 mtx_lock(sc->sc_parent_mtx); 368 /* Wait for the callback after the TTY is torn down */ 369 while (sc->sc_ttyfreed == 0) 370 usb2_cv_wait(&sc->sc_cv, sc->sc_parent_mtx); 371 /* 372 * make sure that read and write transfers are stopped 373 */ 374 if (sc->sc_callback->usb2_com_stop_read) { 375 (sc->sc_callback->usb2_com_stop_read) (sc); 376 } 377 if (sc->sc_callback->usb2_com_stop_write) { 378 (sc->sc_callback->usb2_com_stop_write) (sc); 379 } 380 mtx_unlock(sc->sc_parent_mtx); 381 } 382 usb2_cv_destroy(&sc->sc_cv); 383 return; 384} 385 386static void 387usb2_com_config_copy(struct usb2_com_softc *sc, struct usb2_com_config_copy *cc, 388 uint16_t refcount) 389{ 390 cc->cc_softc = sc + (refcount % UCOM_SUB_UNIT_MAX); 391 cc->cc_flag0 = (refcount / (1 * UCOM_SUB_UNIT_MAX)) % 2; 392 cc->cc_flag1 = (refcount / (2 * UCOM_SUB_UNIT_MAX)) % 2; 393 cc->cc_flag2 = (refcount / (4 * UCOM_SUB_UNIT_MAX)) % 2; 394 cc->cc_flag3 = (refcount / (8 * UCOM_SUB_UNIT_MAX)) % 2; 395 return; 396} 397 398static void 399usb2_com_queue_command(struct usb2_com_softc *sc, usb2_config_td_command_t *cmd, int flag) 400{ 401 struct usb2_com_super_softc *ssc = sc->sc_super; 402 403 usb2_config_td_queue_command 404 (&ssc->sc_config_td, &usb2_com_config_copy, 405 cmd, (cmd == &usb2_com_cfg_status_change) ? 1 : 0, 406 ((sc->sc_local_unit % UCOM_SUB_UNIT_MAX) + 407 (flag ? UCOM_SUB_UNIT_MAX : 0))); 408 return; 409} 410 411static void 412usb2_com_shutdown(struct usb2_com_softc *sc) 413{ 414 struct tty *tp = sc->sc_tty; 415 416 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 417 418 DPRINTF("\n"); 419 420 /* 421 * Hang up if necessary: 422 */ 423 if (tp->t_termios.c_cflag & HUPCL) { 424 usb2_com_modem(tp, 0, SER_DTR); 425 } 426 return; 427} 428 429/* 430 * Return values: 431 * 0: normal delay 432 * else: config thread is gone 433 */ 434uint8_t 435usb2_com_cfg_sleep(struct usb2_com_softc *sc, uint32_t timeout) 436{ 437 struct usb2_com_super_softc *ssc = sc->sc_super; 438 439 return (usb2_config_td_sleep(&ssc->sc_config_td, timeout)); 440} 441 442/* 443 * Return values: 444 * 0: normal 445 * else: config thread is gone 446 */ 447uint8_t 448usb2_com_cfg_is_gone(struct usb2_com_softc *sc) 449{ 450 struct usb2_com_super_softc *ssc = sc->sc_super; 451 452 return (usb2_config_td_is_gone(&ssc->sc_config_td)); 453} 454 455static void 456usb2_com_cfg_start_transfers(struct usb2_com_softc *sc, struct usb2_com_config_copy *cc, 457 uint16_t refcount) 458{ 459 sc = cc->cc_softc; 460 461 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 462 return; 463 } 464 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 465 /* TTY device closed */ 466 return; 467 } 468 sc->sc_flag |= UCOM_FLAG_GP_DATA; 469 470 if (sc->sc_callback->usb2_com_start_read) { 471 (sc->sc_callback->usb2_com_start_read) (sc); 472 } 473 if (sc->sc_callback->usb2_com_start_write) { 474 (sc->sc_callback->usb2_com_start_write) (sc); 475 } 476 return; 477} 478 479static void 480usb2_com_start_transfers(struct usb2_com_softc *sc) 481{ 482 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 483 return; 484 } 485 /* 486 * do a direct call first, to get hardware buffers flushed 487 */ 488 489 if (sc->sc_callback->usb2_com_start_read) { 490 (sc->sc_callback->usb2_com_start_read) (sc); 491 } 492 if (sc->sc_callback->usb2_com_start_write) { 493 (sc->sc_callback->usb2_com_start_write) (sc); 494 } 495 if (!(sc->sc_flag & UCOM_FLAG_GP_DATA)) { 496 usb2_com_queue_command(sc, &usb2_com_cfg_start_transfers, 0); 497 } 498 return; 499} 500 501static void 502usb2_com_cfg_open(struct usb2_com_softc *sc, struct usb2_com_config_copy *cc, 503 uint16_t refcount) 504{ 505 sc = cc->cc_softc; 506 507 DPRINTF("\n"); 508 509 if (sc->sc_flag & UCOM_FLAG_LL_READY) { 510 511 /* already opened */ 512 513 } else { 514 515 sc->sc_flag |= UCOM_FLAG_LL_READY; 516 517 if (sc->sc_callback->usb2_com_cfg_open) { 518 (sc->sc_callback->usb2_com_cfg_open) (sc); 519 520 /* wait a little */ 521 usb2_com_cfg_sleep(sc, hz / 10); 522 } 523 } 524 return; 525} 526 527static int 528usb2_com_open(struct tty *tp) 529{ 530 struct usb2_com_softc *sc = tty_softc(tp); 531 int error; 532 533 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 534 535 if (sc->sc_flag & UCOM_FLAG_GONE) { 536 return (ENXIO); 537 } 538 if (sc->sc_flag & UCOM_FLAG_HL_READY) { 539 /* already opened */ 540 return (0); 541 } 542 DPRINTF("tp = %p\n", tp); 543 544 if (sc->sc_callback->usb2_com_pre_open) { 545 /* 546 * give the lower layer a chance to disallow TTY open, for 547 * example if the device is not present: 548 */ 549 error = (sc->sc_callback->usb2_com_pre_open) (sc); 550 if (error) { 551 return (error); 552 } 553 } 554 sc->sc_flag |= UCOM_FLAG_HL_READY; 555 556 /* Disable transfers */ 557 sc->sc_flag &= ~UCOM_FLAG_GP_DATA; 558 559 sc->sc_lsr = 0; 560 sc->sc_msr = 0; 561 sc->sc_mcr = 0; 562 563 usb2_com_queue_command(sc, &usb2_com_cfg_open, 0); 564 565 usb2_com_start_transfers(sc); 566 567 usb2_com_modem(tp, SER_DTR | SER_RTS, 0); 568 569 usb2_com_break(sc, 0); 570 571 usb2_com_status_change(sc); 572 573 return (0); 574} 575 576static void 577usb2_com_cfg_close(struct usb2_com_softc *sc, struct usb2_com_config_copy *cc, 578 uint16_t refcount) 579{ 580 sc = cc->cc_softc; 581 582 DPRINTF("\n"); 583 584 if (sc->sc_flag & UCOM_FLAG_LL_READY) { 585 586 sc->sc_flag &= ~(UCOM_FLAG_LL_READY | 587 UCOM_FLAG_GP_DATA); 588 589 if (sc->sc_callback->usb2_com_cfg_close) { 590 (sc->sc_callback->usb2_com_cfg_close) (sc); 591 } 592 } else { 593 /* already closed */ 594 } 595 return; 596} 597 598static void 599usb2_com_close(struct tty *tp) 600{ 601 struct usb2_com_softc *sc = tty_softc(tp); 602 603 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 604 605 DPRINTF("tp=%p\n", tp); 606 607 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 608 DPRINTF("tp=%p already closed\n", tp); 609 return; 610 } 611 usb2_com_shutdown(sc); 612 613 usb2_com_queue_command(sc, &usb2_com_cfg_close, 0); 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 return; 626} 627 628static int 629usb2_com_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) 630{ 631 struct usb2_com_softc *sc = tty_softc(tp); 632 int error; 633 634 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 635 636 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 637 return (EIO); 638 } 639 DPRINTF("cmd = 0x%08lx\n", cmd); 640 641 switch (cmd) { 642 case TIOCSBRK: 643 usb2_com_break(sc, 1); 644 error = 0; 645 break; 646 case TIOCCBRK: 647 usb2_com_break(sc, 0); 648 error = 0; 649 break; 650 default: 651 if (sc->sc_callback->usb2_com_ioctl) { 652 error = (sc->sc_callback->usb2_com_ioctl) 653 (sc, cmd, data, 0, td); 654 } else { 655 error = ENOIOCTL; 656 } 657 break; 658 } 659 return (error); 660} 661 662static int 663usb2_com_modem(struct tty *tp, int sigon, int sigoff) 664{ 665 struct usb2_com_softc *sc = tty_softc(tp); 666 uint8_t onoff; 667 668 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 669 670 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 671 return (0); 672 } 673 if ((sigon == 0) && (sigoff == 0)) { 674 675 if (sc->sc_mcr & SER_DTR) { 676 sigon |= SER_DTR; 677 } 678 if (sc->sc_mcr & SER_RTS) { 679 sigon |= SER_RTS; 680 } 681 if (sc->sc_msr & SER_CTS) { 682 sigon |= SER_CTS; 683 } 684 if (sc->sc_msr & SER_DCD) { 685 sigon |= SER_DCD; 686 } 687 if (sc->sc_msr & SER_DSR) { 688 sigon |= SER_DSR; 689 } 690 if (sc->sc_msr & SER_RI) { 691 sigon |= SER_RI; 692 } 693 return (sigon); 694 } 695 if (sigon & SER_DTR) { 696 sc->sc_mcr |= SER_DTR; 697 } 698 if (sigoff & SER_DTR) { 699 sc->sc_mcr &= ~SER_DTR; 700 } 701 if (sigon & SER_RTS) { 702 sc->sc_mcr |= SER_RTS; 703 } 704 if (sigoff & SER_RTS) { 705 sc->sc_mcr &= ~SER_RTS; 706 } 707 onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0; 708 usb2_com_dtr(sc, onoff); 709 710 onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0; 711 usb2_com_rts(sc, onoff); 712 713 return (0); 714} 715 716static void 717usb2_com_cfg_break(struct usb2_com_softc *sc, struct usb2_com_config_copy *cc, 718 uint16_t refcount) 719{ 720 sc = cc->cc_softc; 721 722 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 723 return; 724 } 725 DPRINTF("onoff=%d\n", cc->cc_flag0); 726 727 if (sc->sc_callback->usb2_com_cfg_set_break) { 728 (sc->sc_callback->usb2_com_cfg_set_break) (sc, cc->cc_flag0); 729 } 730 return; 731} 732 733static void 734usb2_com_break(struct usb2_com_softc *sc, uint8_t onoff) 735{ 736 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 737 738 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 739 return; 740 } 741 DPRINTF("onoff = %d\n", onoff); 742 743 usb2_com_queue_command(sc, &usb2_com_cfg_break, onoff); 744 return; 745} 746 747static void 748usb2_com_cfg_dtr(struct usb2_com_softc *sc, struct usb2_com_config_copy *cc, 749 uint16_t refcount) 750{ 751 sc = cc->cc_softc; 752 753 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 754 return; 755 } 756 DPRINTF("onoff=%d\n", cc->cc_flag0); 757 758 if (sc->sc_callback->usb2_com_cfg_set_dtr) { 759 (sc->sc_callback->usb2_com_cfg_set_dtr) (sc, cc->cc_flag0); 760 } 761 return; 762} 763 764static void 765usb2_com_dtr(struct usb2_com_softc *sc, uint8_t onoff) 766{ 767 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 768 769 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 770 return; 771 } 772 DPRINTF("onoff = %d\n", onoff); 773 774 usb2_com_queue_command(sc, &usb2_com_cfg_dtr, onoff); 775 return; 776} 777 778static void 779usb2_com_cfg_rts(struct usb2_com_softc *sc, struct usb2_com_config_copy *cc, 780 uint16_t refcount) 781{ 782 sc = cc->cc_softc; 783 784 DPRINTF("onoff=%d\n", cc->cc_flag0); 785 786 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 787 return; 788 } 789 if (sc->sc_callback->usb2_com_cfg_set_rts) { 790 (sc->sc_callback->usb2_com_cfg_set_rts) (sc, cc->cc_flag0); 791 } 792 return; 793} 794 795static void 796usb2_com_rts(struct usb2_com_softc *sc, uint8_t onoff) 797{ 798 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 799 800 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 801 return; 802 } 803 DPRINTF("onoff = %d\n", onoff); 804 805 usb2_com_queue_command(sc, &usb2_com_cfg_rts, onoff); 806 807 return; 808} 809 810static void 811usb2_com_cfg_status_change(struct usb2_com_softc *sc, 812 struct usb2_com_config_copy *cc, uint16_t refcount) 813{ 814 struct tty *tp; 815 816 uint8_t new_msr; 817 uint8_t new_lsr; 818 uint8_t onoff; 819 820 sc = cc->cc_softc; 821 tp = sc->sc_tty; 822 823 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 824 825 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 826 return; 827 } 828 if (sc->sc_callback->usb2_com_cfg_get_status == NULL) { 829 return; 830 } 831 /* get status */ 832 833 new_msr = 0; 834 new_lsr = 0; 835 836 (sc->sc_callback->usb2_com_cfg_get_status) (sc, &new_lsr, &new_msr); 837 838 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 839 /* TTY device closed */ 840 return; 841 } 842 onoff = ((sc->sc_msr ^ new_msr) & SER_DCD); 843 844 sc->sc_msr = new_msr; 845 sc->sc_lsr = new_lsr; 846 847 if (onoff) { 848 849 onoff = (sc->sc_msr & SER_DCD) ? 1 : 0; 850 851 DPRINTF("DCD changed to %d\n", onoff); 852 853 ttydisc_modem(tp, onoff); 854 } 855 return; 856} 857 858void 859usb2_com_status_change(struct usb2_com_softc *sc) 860{ 861 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 862 863 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 864 return; 865 } 866 DPRINTF("\n"); 867 868 usb2_com_queue_command(sc, &usb2_com_cfg_status_change, 0); 869 return; 870} 871 872static void 873usb2_com_cfg_param(struct usb2_com_softc *sc, struct usb2_com_config_copy *cc, 874 uint16_t refcount) 875{ 876 struct termios t_copy; 877 878 sc = cc->cc_softc; 879 880 if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { 881 return; 882 } 883 if (sc->sc_callback->usb2_com_cfg_param == NULL) { 884 return; 885 } 886 t_copy = sc->sc_termios_copy; 887 888 (sc->sc_callback->usb2_com_cfg_param) (sc, &t_copy); 889 890 /* wait a little */ 891 usb2_com_cfg_sleep(sc, hz / 10); 892 893 return; 894} 895 896static int 897usb2_com_param(struct tty *tp, struct termios *t) 898{ 899 struct usb2_com_softc *sc = tty_softc(tp); 900 uint8_t opened; 901 int error; 902 903 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 904 905 opened = 0; 906 error = 0; 907 908 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 909 910 /* XXX the TTY layer should call "open()" first! */ 911 912 error = usb2_com_open(tp); 913 if (error) { 914 goto done; 915 } 916 opened = 1; 917 } 918 DPRINTF("sc = %p\n", sc); 919 920 /* Check requested parameters. */ 921 if (t->c_ospeed < 0) { 922 DPRINTF("negative ospeed\n"); 923 error = EINVAL; 924 goto done; 925 } 926 if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) { 927 DPRINTF("mismatch ispeed and ospeed\n"); 928 error = EINVAL; 929 goto done; 930 } 931 t->c_ispeed = t->c_ospeed; 932 933 if (sc->sc_callback->usb2_com_pre_param) { 934 /* Let the lower layer verify the parameters */ 935 error = (sc->sc_callback->usb2_com_pre_param) (sc, t); 936 if (error) { 937 DPRINTF("callback error = %d\n", error); 938 goto done; 939 } 940 } 941 /* Make a copy of the termios parameters */ 942 sc->sc_termios_copy = *t; 943 944 /* Disable transfers */ 945 sc->sc_flag &= ~UCOM_FLAG_GP_DATA; 946 947 /* Queue baud rate programming command first */ 948 usb2_com_queue_command(sc, &usb2_com_cfg_param, 0); 949 950 /* Queue transfer enable command last */ 951 usb2_com_start_transfers(sc); 952 953 if (t->c_cflag & CRTS_IFLOW) { 954 sc->sc_flag |= UCOM_FLAG_RTS_IFLOW; 955 } else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) { 956 sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW; 957 usb2_com_modem(tp, SER_RTS, 0); 958 } 959done: 960 if (error) { 961 if (opened) { 962 usb2_com_close(tp); 963 } 964 } 965 return (error); 966} 967 968static void 969usb2_com_start_write(struct tty *tp) 970{ 971 struct usb2_com_softc *sc = tty_softc(tp); 972 973 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 974 975 DPRINTF("sc = %p\n", sc); 976 977 if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { 978 /* The higher layer is not ready */ 979 return; 980 } 981 sc->sc_flag |= UCOM_FLAG_WR_START; 982 983 usb2_com_start_transfers(sc); 984 985 return; 986} 987 988/*------------------------------------------------------------------------* 989 * usb2_com_get_data 990 * 991 * Return values: 992 * 0: No data is available. 993 * Else: Data is available. 994 *------------------------------------------------------------------------*/ 995uint8_t 996usb2_com_get_data(struct usb2_com_softc *sc, struct usb2_page_cache *pc, 997 uint32_t offset, uint32_t len, uint32_t *actlen) 998{ 999 struct usb2_page_search res; 1000 struct tty *tp = sc->sc_tty; 1001 uint32_t cnt; 1002 uint32_t offset_orig; 1003 1004 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 1005 1006 if ((!(sc->sc_flag & UCOM_FLAG_HL_READY)) || 1007 (!(sc->sc_flag & UCOM_FLAG_GP_DATA)) || 1008 (!(sc->sc_flag & UCOM_FLAG_WR_START))) { 1009 actlen[0] = 0; 1010 return (0); /* multiport device polling */ 1011 } 1012 offset_orig = offset; 1013 1014 while (len != 0) { 1015 1016 usb2_get_page(pc, offset, &res); 1017 1018 if (res.length > len) { 1019 res.length = len; 1020 } 1021 /* copy data directly into USB buffer */ 1022 cnt = ttydisc_getc(tp, res.buffer, res.length); 1023 1024 offset += cnt; 1025 len -= cnt; 1026 1027 if (cnt < res.length) { 1028 /* end of buffer */ 1029 break; 1030 } 1031 } 1032 1033 actlen[0] = offset - offset_orig; 1034 1035 DPRINTF("cnt=%d\n", actlen[0]); 1036 1037 if (actlen[0] == 0) { 1038 return (0); 1039 } 1040 return (1); 1041} 1042 1043void 1044usb2_com_put_data(struct usb2_com_softc *sc, struct usb2_page_cache *pc, 1045 uint32_t offset, uint32_t len) 1046{ 1047 struct usb2_page_search res; 1048 struct tty *tp = sc->sc_tty; 1049 char *buf; 1050 uint32_t cnt; 1051 1052 mtx_assert(sc->sc_parent_mtx, MA_OWNED); 1053 1054 if ((!(sc->sc_flag & UCOM_FLAG_HL_READY)) || 1055 (!(sc->sc_flag & UCOM_FLAG_GP_DATA))) { 1056 return; /* multiport device polling */ 1057 } 1058 if (len == 0) 1059 return; /* no data */ 1060 1061 /* set a flag to prevent recursation ? */ 1062 1063 while (len > 0) { 1064 1065 usb2_get_page(pc, offset, &res); 1066 1067 if (res.length > len) { 1068 res.length = len; 1069 } 1070 len -= res.length; 1071 offset += res.length; 1072 1073 /* pass characters to tty layer */ 1074 1075 buf = res.buffer; 1076 cnt = res.length; 1077 1078 /* first check if we can pass the buffer directly */ 1079 1080 if (ttydisc_can_bypass(tp)) { 1081 if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) { 1082 DPRINTF("tp=%p, data lost\n", tp); 1083 } 1084 continue; 1085 } 1086 /* need to loop */ 1087 1088 for (cnt = 0; cnt != res.length; cnt++) { 1089 if (ttydisc_rint(tp, buf[cnt], 0) == -1) { 1090 /* XXX what should we do? */ 1091 1092 DPRINTF("tp=%p, lost %d " 1093 "chars\n", tp, res.length - cnt); 1094 break; 1095 } 1096 } 1097 } 1098 ttydisc_rint_done(tp); 1099 return; 1100} 1101 1102static void 1103usb2_com_free(void *xsc) 1104{ 1105 struct usb2_com_softc *sc = xsc; 1106 1107 mtx_lock(sc->sc_parent_mtx); 1108 sc->sc_ttyfreed = 1; 1109 usb2_cv_signal(&sc->sc_cv); 1110 mtx_unlock(sc->sc_parent_mtx); 1111} 1112