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