ucom.c revision 1.13
1/* $NetBSD: ucom.c,v 1.13 2000/01/25 13:56:23 augustss Exp $ */ 2 3/* 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (augustss@carlstedt.se) at 9 * Carlstedt Research & Technology. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/ioctl.h> 44#include <sys/conf.h> 45#include <sys/tty.h> 46#include <sys/file.h> 47#include <sys/select.h> 48#include <sys/proc.h> 49#include <sys/vnode.h> 50#include <sys/device.h> 51#include <sys/poll.h> 52 53#include <dev/usb/usb.h> 54 55#include <dev/usb/usbdi.h> 56#include <dev/usb/usbdi_util.h> 57#include <dev/usb/usbdevs.h> 58#include <dev/usb/usb_quirks.h> 59 60#include <dev/usb/ucomvar.h> 61 62#include "ucom.h" 63 64#if NUCOM > 0 65 66#ifdef UCOM_DEBUG 67#define DPRINTFN(n, x) if (ucomdebug > (n)) logprintf x 68int ucomdebug = 0; 69#else 70#define DPRINTFN(n, x) 71#endif 72#define DPRINTF(x) DPRINTFN(0, x) 73 74#define UCOMUNIT_MASK 0x3ffff 75#define UCOMDIALOUT_MASK 0x80000 76#define UCOMCALLUNIT_MASK 0x40000 77 78#define UCOMUNIT(x) (minor(x) & UCOMUNIT_MASK) 79#define UCOMDIALOUT(x) (minor(x) & UCOMDIALOUT_MASK) 80#define UCOMCALLUNIT(x) (minor(x) & UCOMCALLUNIT_MASK) 81 82/* 83 * These are the maximum number of bytes transferred per frame. 84 * If some really high speed devices should use this driver they 85 * may need to be increased, but this is good enough for modems. 86 */ 87#define UCOMIBUFSIZE 64 88#define UCOMOBUFSIZE 256 89 90struct ucom_softc { 91 USBBASEDEVICE sc_dev; /* base device */ 92 93 usbd_device_handle sc_udev; /* USB device */ 94 95 usbd_interface_handle sc_iface; /* data interface */ 96 97 int sc_bulkin_no; /* bulk in endpoint address */ 98 usbd_pipe_handle sc_bulkin_pipe; /* bulk in pipe */ 99 usbd_xfer_handle sc_ixfer; /* read request */ 100 u_char *sc_ibuf; /* read buffer */ 101 102 int sc_bulkout_no; /* bulk out endpoint address */ 103 usbd_pipe_handle sc_bulkout_pipe;/* bulk out pipe */ 104 usbd_xfer_handle sc_oxfer; /* write request */ 105 u_char *sc_obuf; /* write buffer */ 106 107 struct ucom_methods *sc_methods; 108 void *sc_parent; 109 int sc_portno; 110 111 struct tty *sc_tty; /* our tty */ 112 u_char sc_lsr; 113 u_char sc_msr; 114 u_char sc_mcr; 115 u_char sc_tx_stopped; 116 int sc_swflags; 117 118 u_char sc_opening; /* lock during open */ 119 u_char sc_dying; /* disconnecting */ 120}; 121 122cdev_decl(ucom); 123 124static void ucom_cleanup __P((struct ucom_softc *)); 125static void ucom_hwiflow __P((struct ucom_softc *)); 126static int ucomparam __P((struct tty *, struct termios *)); 127static void ucomstart __P((struct tty *)); 128static void ucom_shutdown __P((struct ucom_softc *)); 129static void ucom_dtr __P((struct ucom_softc *, int)); 130static void ucom_rts __P((struct ucom_softc *, int)); 131static void ucom_break __P((struct ucom_softc *, int)); 132static usbd_status ucomstartread __P((struct ucom_softc *)); 133static void ucomreadcb __P((usbd_xfer_handle, usbd_private_handle, 134 usbd_status status)); 135static void ucomwritecb __P((usbd_xfer_handle, usbd_private_handle, 136 usbd_status status)); 137static void tiocm_to_ucom __P((struct ucom_softc *, int, int)); 138static int ucom_to_tiocm __P((struct ucom_softc *)); 139 140USB_DECLARE_DRIVER(ucom); 141 142USB_MATCH(ucom) 143{ 144 return (1); 145} 146 147USB_ATTACH(ucom) 148{ 149 struct ucom_softc *sc = (struct ucom_softc *)self; 150 struct ucom_attach_args *uca = aux; 151 struct tty *tp; 152 153 if (uca->portno != UCOM_UNK_PORTNO) 154 printf(": portno %d", uca->portno); 155 printf("\n"); 156 157 sc->sc_udev = uca->device; 158 sc->sc_iface = uca->iface; 159 sc->sc_bulkout_no = uca->bulkout; 160 sc->sc_bulkin_no = uca->bulkin; 161 sc->sc_methods = uca->methods; 162 sc->sc_parent = uca->arg; 163 sc->sc_portno = uca->portno; 164 165 tp = ttymalloc(); 166 tp->t_oproc = ucomstart; 167 tp->t_param = ucomparam; 168 sc->sc_tty = tp; 169 170 DPRINTF(("ucom_attach: tty_attach %p\n", tp)); 171 tty_attach(tp); 172 173 USB_ATTACH_SUCCESS_RETURN; 174} 175 176USB_DETACH(ucom) 177{ 178 struct ucom_softc *sc = (struct ucom_softc *)self; 179 int maj, mn; 180 181 DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p\n", 182 sc, flags, sc->sc_tty)); 183 184 sc->sc_dying = 1; 185 186#ifdef DIAGNOSTIC 187 if (sc->sc_tty == NULL) { 188 DPRINTF(("ucom_detach: no tty\n")); 189 return (0); 190 } 191#endif 192 193 /* XXX Use reference count? */ 194 195 /* locate the major number */ 196 for (maj = 0; maj < nchrdev; maj++) 197 if (cdevsw[maj].d_open == ucomopen) 198 break; 199 200 /* Nuke the vnodes for any open instances. */ 201 mn = self->dv_unit; 202 vdevgone(maj, mn, mn, VCHR); 203 vdevgone(maj, mn, mn | UCOMDIALOUT_MASK, VCHR); 204 vdevgone(maj, mn, mn | UCOMCALLUNIT_MASK, VCHR); 205 206 /* Detach and free the tty. */ 207 tty_detach(sc->sc_tty); 208 ttyfree(sc->sc_tty); 209 sc->sc_tty = 0; 210 211 return (0); 212} 213 214#if defined(__NetBSD__) || defined(__OpenBSD__) 215int 216ucom_activate(self, act) 217 device_ptr_t self; 218 enum devact act; 219{ 220 struct ucom_softc *sc = (struct ucom_softc *)self; 221 222 switch (act) { 223 case DVACT_ACTIVATE: 224 return (EOPNOTSUPP); 225 break; 226 227 case DVACT_DEACTIVATE: 228 sc->sc_dying = 1; 229 break; 230 } 231 return (0); 232} 233#endif 234 235void 236ucom_shutdown(sc) 237 struct ucom_softc *sc; 238{ 239 struct tty *tp = sc->sc_tty; 240 241 DPRINTF(("ucom_shutdown\n")); 242 /* 243 * Hang up if necessary. Wait a bit, so the other side has time to 244 * notice even if we immediately open the port again. 245 */ 246 if (ISSET(tp->t_cflag, HUPCL)) { 247 ucom_dtr(sc, 0); 248 (void)tsleep(sc, TTIPRI, ttclos, hz); 249 } 250} 251 252int 253ucomopen(dev, flag, mode, p) 254 dev_t dev; 255 int flag, mode; 256 struct proc *p; 257{ 258 int unit = UCOMUNIT(dev); 259 usbd_status err; 260 struct ucom_softc *sc; 261 struct tty *tp; 262 int s; 263 int error; 264 265 if (unit >= ucom_cd.cd_ndevs) 266 return (ENXIO); 267 sc = ucom_cd.cd_devs[unit]; 268 if (sc == NULL) 269 return (ENXIO); 270 271 if (sc->sc_dying) 272 return (EIO); 273 274 if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0) 275 return (ENXIO); 276 277 tp = sc->sc_tty; 278 279 DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp)); 280 281 if (ISSET(tp->t_state, TS_ISOPEN) && 282 ISSET(tp->t_state, TS_XCLUDE) && 283 p->p_ucred->cr_uid != 0) 284 return (EBUSY); 285 286 s = spltty(); 287 288 /* 289 * Do the following iff this is a first open. 290 */ 291 while (sc->sc_opening) 292 tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0); 293 sc->sc_opening = 1; 294 295 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 296 struct termios t; 297 298 tp->t_dev = dev; 299 300 ucom_status_change(sc); 301 302 /* 303 * Initialize the termios status to the defaults. Add in the 304 * sticky bits from TIOCSFLAGS. 305 */ 306 t.c_ispeed = 0; 307 t.c_ospeed = TTYDEF_SPEED; 308 t.c_cflag = TTYDEF_CFLAG; 309 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) 310 SET(t.c_cflag, CLOCAL); 311 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 312 SET(t.c_cflag, CRTSCTS); 313 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) 314 SET(t.c_cflag, MDMBUF); 315 /* Make sure ucomparam() will do something. */ 316 tp->t_ospeed = 0; 317 (void) ucomparam(tp, &t); 318 tp->t_iflag = TTYDEF_IFLAG; 319 tp->t_oflag = TTYDEF_OFLAG; 320 tp->t_lflag = TTYDEF_LFLAG; 321 ttychars(tp); 322 ttsetwater(tp); 323 324 /* 325 * Turn on DTR. We must always do this, even if carrier is not 326 * present, because otherwise we'd have to use TIOCSDTR 327 * immediately after setting CLOCAL, which applications do not 328 * expect. We always assert DTR while the device is open 329 * unless explicitly requested to deassert it. 330 */ 331 ucom_dtr(sc, 1); 332 333 // XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK); 334 ucom_hwiflow(sc); 335 336 DPRINTF(("ucomopen: open pipes in=%d out=%d\n", 337 sc->sc_bulkin_no, sc->sc_bulkout_no)); 338 339 /* Open the bulk pipes */ 340 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0, 341 &sc->sc_bulkin_pipe); 342 if (err) { 343 DPRINTF(("%s: open bulk out error (addr %d), err=%s\n", 344 USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no, 345 usbd_errstr(err))); 346 return (EIO); 347 } 348 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no, 349 USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe); 350 if (err) { 351 DPRINTF(("%s: open bulk in error (addr %d), err=%s\n", 352 USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no, 353 usbd_errstr(err))); 354 usbd_close_pipe(sc->sc_bulkin_pipe); 355 return (EIO); 356 } 357 358 /* Allocate a request and an input buffer and start reading. */ 359 sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev); 360 if (sc->sc_ixfer == NULL) { 361 usbd_close_pipe(sc->sc_bulkin_pipe); 362 usbd_close_pipe(sc->sc_bulkout_pipe); 363 return (ENOMEM); 364 } 365 sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer, UCOMIBUFSIZE); 366 if (sc->sc_ibuf == NULL) { 367 usbd_free_xfer(sc->sc_ixfer); 368 usbd_close_pipe(sc->sc_bulkin_pipe); 369 usbd_close_pipe(sc->sc_bulkout_pipe); 370 return (ENOMEM); 371 } 372 373 sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev); 374 if (sc->sc_oxfer == NULL) { 375 usbd_free_xfer(sc->sc_ixfer); 376 usbd_close_pipe(sc->sc_bulkin_pipe); 377 usbd_close_pipe(sc->sc_bulkout_pipe); 378 return (ENOMEM); 379 } 380 sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer, UCOMOBUFSIZE); 381 if (sc->sc_obuf == NULL) { 382 usbd_free_xfer(sc->sc_oxfer); 383 usbd_free_xfer(sc->sc_ixfer); 384 usbd_close_pipe(sc->sc_bulkin_pipe); 385 usbd_close_pipe(sc->sc_bulkout_pipe); 386 return (ENOMEM); 387 } 388 389 ucomstartread(sc); 390 } 391 sc->sc_opening = 0; 392 wakeup(&sc->sc_opening); 393 splx(s); 394 395 error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); 396 if (error) 397 goto bad; 398 399 error = (*linesw[tp->t_line].l_open)(dev, tp); 400 if (error) 401 goto bad; 402 403 return (0); 404 405bad: 406 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 407 /* 408 * We failed to open the device, and nobody else had it opened. 409 * Clean up the state as appropriate. 410 */ 411 ucom_cleanup(sc); 412 } 413 414 return (error); 415} 416 417int 418ucomclose(dev, flag, mode, p) 419 dev_t dev; 420 int flag, mode; 421 struct proc *p; 422{ 423 struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)]; 424 struct tty *tp = sc->sc_tty; 425 426 DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev))); 427 if (!ISSET(tp->t_state, TS_ISOPEN)) 428 return (0); 429 430 (*linesw[tp->t_line].l_close)(tp, flag); 431 ttyclose(tp); 432 433 if (sc->sc_dying) 434 return (0); 435 436 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 437 /* 438 * Although we got a last close, the device may still be in 439 * use; e.g. if this was the dialout node, and there are still 440 * processes waiting for carrier on the non-dialout node. 441 */ 442 ucom_cleanup(sc); 443 } 444 445 return (0); 446} 447 448int 449ucomread(dev, uio, flag) 450 dev_t dev; 451 struct uio *uio; 452 int flag; 453{ 454 struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)]; 455 struct tty *tp = sc->sc_tty; 456 457 if (sc->sc_dying) 458 return (EIO); 459 460 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 461} 462 463int 464ucomwrite(dev, uio, flag) 465 dev_t dev; 466 struct uio *uio; 467 int flag; 468{ 469 struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)]; 470 struct tty *tp = sc->sc_tty; 471 472 if (sc->sc_dying) 473 return (EIO); 474 475 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 476} 477 478struct tty * 479ucomtty(dev) 480 dev_t dev; 481{ 482 struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)]; 483 struct tty *tp = sc->sc_tty; 484 485 return (tp); 486} 487 488int 489ucomioctl(dev, cmd, data, flag, p) 490 dev_t dev; 491 u_long cmd; 492 caddr_t data; 493 int flag; 494 struct proc *p; 495{ 496 struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)]; 497 struct tty *tp = sc->sc_tty; 498 int error; 499 int s; 500 501 if (sc->sc_dying) 502 return (EIO); 503 504 DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd)); 505 506 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 507 if (error >= 0) 508 return (error); 509 510 error = ttioctl(tp, cmd, data, flag, p); 511 if (error >= 0) 512 return (error); 513 514 if (sc->sc_methods->ucom_ioctl != NULL) { 515 error = sc->sc_methods->ucom_ioctl(sc->sc_parent, 516 sc->sc_portno, cmd, data, flag, p); 517 if (error >= 0) 518 return (error); 519 } 520 521 error = 0; 522 523 DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd)); 524 s = spltty(); 525 526 switch (cmd) { 527 case TIOCSBRK: 528 ucom_break(sc, 1); 529 break; 530 531 case TIOCCBRK: 532 ucom_break(sc, 0); 533 break; 534 535 case TIOCSDTR: 536 ucom_dtr(sc, 1); 537 break; 538 539 case TIOCCDTR: 540 ucom_dtr(sc, 0); 541 break; 542 543 case TIOCGFLAGS: 544 *(int *)data = sc->sc_swflags; 545 break; 546 547 case TIOCSFLAGS: 548 error = suser(p->p_ucred, &p->p_acflag); 549 if (error) 550 break; 551 sc->sc_swflags = *(int *)data; 552 break; 553 554 case TIOCMSET: 555 case TIOCMBIS: 556 case TIOCMBIC: 557 tiocm_to_ucom(sc, cmd, *(int *)data); 558 break; 559 560 case TIOCMGET: 561 *(int *)data = ucom_to_tiocm(sc); 562 break; 563 564 default: 565 error = ENOTTY; 566 break; 567 } 568 569 splx(s); 570 571 return (error); 572} 573 574void 575tiocm_to_ucom(sc, how, ttybits) 576 struct ucom_softc *sc; 577 int how, ttybits; 578{ 579 u_char combits; 580 581 combits = 0; 582 if (ISSET(ttybits, TIOCM_DTR)) 583 SET(combits, UMCR_DTR); 584 if (ISSET(ttybits, TIOCM_RTS)) 585 SET(combits, UMCR_RTS); 586 587 switch (how) { 588 case TIOCMBIC: 589 CLR(sc->sc_mcr, combits); 590 break; 591 592 case TIOCMBIS: 593 SET(sc->sc_mcr, combits); 594 break; 595 596 case TIOCMSET: 597 CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS); 598 SET(sc->sc_mcr, combits); 599 break; 600 } 601 602 ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0); 603 ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0); 604} 605 606int 607ucom_to_tiocm(sc) 608 struct ucom_softc *sc; 609{ 610 u_char combits; 611 int ttybits = 0; 612 613 combits = sc->sc_mcr; 614 if (ISSET(combits, UMCR_DTR)) 615 SET(ttybits, TIOCM_DTR); 616 if (ISSET(combits, UMCR_RTS)) 617 SET(ttybits, TIOCM_RTS); 618 619 combits = sc->sc_msr; 620 if (ISSET(combits, UMSR_DCD)) 621 SET(ttybits, TIOCM_CD); 622 if (ISSET(combits, UMSR_CTS)) 623 SET(ttybits, TIOCM_CTS); 624 if (ISSET(combits, UMSR_DSR)) 625 SET(ttybits, TIOCM_DSR); 626 if (ISSET(combits, UMSR_RI | UMSR_TERI)) 627 SET(ttybits, TIOCM_RI); 628 629#if 0 630XXX; 631 if (sc->sc_ier != 0) 632 SET(ttybits, TIOCM_LE); 633#endif 634 635 return (ttybits); 636} 637 638void 639ucom_break(sc, onoff) 640 struct ucom_softc *sc; 641 int onoff; 642{ 643 DPRINTF(("ucom_break: onoff=%d\n", onoff)); 644 645 sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno, 646 UCOM_SET_BREAK, onoff); 647} 648 649void 650ucom_dtr(sc, onoff) 651 struct ucom_softc *sc; 652 int onoff; 653{ 654 DPRINTF(("ucom_dtr: onoff=%d\n", onoff)); 655 656 sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno, 657 UCOM_SET_DTR, onoff); 658} 659 660void 661ucom_rts(sc, onoff) 662 struct ucom_softc *sc; 663 int onoff; 664{ 665 DPRINTF(("ucom_rts: onoff=%d\n", onoff)); 666 667 sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno, 668 UCOM_SET_RTS, onoff); 669} 670 671void 672ucom_status_change(sc) 673 struct ucom_softc *sc; 674{ 675 sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno, 676 &sc->sc_lsr, &sc->sc_msr); 677} 678 679int 680ucomparam(tp, t) 681 struct tty *tp; 682 struct termios *t; 683{ 684 struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)]; 685 686 if (sc->sc_dying) 687 return (EIO); 688 689 /* Check requested parameters. */ 690 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 691 return (EINVAL); 692 693 /* 694 * For the console, always force CLOCAL and !HUPCL, so that the port 695 * is always active. 696 */ 697 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) { 698 SET(t->c_cflag, CLOCAL); 699 CLR(t->c_cflag, HUPCL); 700 } 701 702 /* 703 * If there were no changes, don't do anything. This avoids dropping 704 * input and improves performance when all we did was frob things like 705 * VMIN and VTIME. 706 */ 707 if (tp->t_ospeed == t->c_ospeed && 708 tp->t_cflag == t->c_cflag) 709 return (0); 710 711 //XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); 712 713 /* And copy to tty. */ 714 tp->t_ispeed = 0; 715 tp->t_ospeed = t->c_ospeed; 716 tp->t_cflag = t->c_cflag; 717 718 sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno, t); 719 720 // XXX worry about CHWFLOW 721 722 /* 723 * Update the tty layer's idea of the carrier bit, in case we changed 724 * CLOCAL or MDMBUF. We don't hang up here; we only do that by 725 * explicit request. 726 */ 727 DPRINTF(("ucomparam: l_modem\n")); 728 (void) (*linesw[tp->t_line].l_modem)(tp, 1 /* XXX carrier */ ); 729 730#if 0 731XXX what if the hardware is not open 732 if (!ISSET(t->c_cflag, CHWFLOW)) { 733 if (sc->sc_tx_stopped) { 734 sc->sc_tx_stopped = 0; 735 ucomstart(tp); 736 } 737 } 738#endif 739 740 return (0); 741} 742 743/* 744 * (un)block input via hw flowcontrol 745 */ 746void 747ucom_hwiflow(sc) 748 struct ucom_softc *sc; 749{ 750#if 0 751XXX 752 bus_space_tag_t iot = sc->sc_iot; 753 bus_space_handle_t ioh = sc->sc_ioh; 754 755 if (sc->sc_mcr_rts == 0) 756 return; 757 758 if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) { 759 CLR(sc->sc_mcr, sc->sc_mcr_rts); 760 CLR(sc->sc_mcr_active, sc->sc_mcr_rts); 761 } else { 762 SET(sc->sc_mcr, sc->sc_mcr_rts); 763 SET(sc->sc_mcr_active, sc->sc_mcr_rts); 764 } 765 bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr_active); 766#endif 767} 768 769void 770ucomstart(tp) 771 struct tty *tp; 772{ 773 struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)]; 774 usbd_status err; 775 int s; 776 u_char *data; 777 int cnt; 778 779 if (sc->sc_dying) 780 return; 781 782 s = spltty(); 783 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) { 784 DPRINTFN(4,("ucomstart: stopped\n")); 785 goto out; 786 } 787 if (sc->sc_tx_stopped) 788 goto out; 789 790 if (tp->t_outq.c_cc <= tp->t_lowat) { 791 if (ISSET(tp->t_state, TS_ASLEEP)) { 792 CLR(tp->t_state, TS_ASLEEP); 793 wakeup(&tp->t_outq); 794 } 795 selwakeup(&tp->t_wsel); 796 if (tp->t_outq.c_cc == 0) 797 goto out; 798 } 799 800 /* Grab the first contiguous region of buffer space. */ 801 data = tp->t_outq.c_cf; 802 cnt = ndqb(&tp->t_outq, 0); 803 804 if (cnt == 0) { 805 DPRINTF(("ucomstart: cnt==0\n")); 806 goto out; 807 } 808 809 SET(tp->t_state, TS_BUSY); 810 811 if (cnt > UCOMOBUFSIZE) { 812 DPRINTF(("ucomstart: big buffer %d chars\n", cnt)); 813 cnt = UCOMOBUFSIZE; 814 } 815 memcpy(sc->sc_obuf, data, cnt); 816 817 DPRINTFN(4,("ucomstart: %d chars\n", cnt)); 818 usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe, 819 (usbd_private_handle)sc, sc->sc_obuf, cnt, 820 USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb); 821 /* What can we do on error? */ 822 err = usbd_transfer(sc->sc_oxfer); 823#ifdef DIAGNOSTIC 824 if (err != USBD_IN_PROGRESS) 825 printf("ucomstart: err=%s\n", usbd_errstr(err)); 826#endif 827 828out: 829 splx(s); 830} 831 832void 833ucomstop(tp, flag) 834 struct tty *tp; 835 int flag; 836{ 837 struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)]; 838 int s; 839 840 DPRINTF(("ucomstop: %d\n", flag)); 841 s = spltty(); 842 if (ISSET(tp->t_state, TS_BUSY)) { 843 DPRINTF(("ucomstop: XXX\n")); 844 sc->sc_tx_stopped = 1; 845 if (!ISSET(tp->t_state, TS_TTSTOP)) 846 SET(tp->t_state, TS_FLUSH); 847 } 848 splx(s); 849} 850 851void 852ucomwritecb(xfer, p, status) 853 usbd_xfer_handle xfer; 854 usbd_private_handle p; 855 usbd_status status; 856{ 857 struct ucom_softc *sc = (struct ucom_softc *)p; 858 struct tty *tp = sc->sc_tty; 859 u_int32_t cc; 860 int s; 861 862 DPRINTFN(5,("ucomwritecb: status=%d\n", status)); 863 864 if (status == USBD_CANCELLED) 865 return; 866 867 if (status) { 868 DPRINTF(("ucomwritecb: status=%d\n", status)); 869 usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe); 870 /* XXX we should restart after some delay. */ 871 return; 872 } 873 874 usbd_get_xfer_status(xfer, 0, 0, &cc, 0); 875 DPRINTFN(5,("ucomwritecb: cc=%d\n", cc)); 876 877 s = spltty(); 878 CLR(tp->t_state, TS_BUSY); 879 if (ISSET(tp->t_state, TS_FLUSH)) 880 CLR(tp->t_state, TS_FLUSH); 881 else 882 ndflush(&tp->t_outq, cc); 883 (*linesw[tp->t_line].l_start)(tp); 884 splx(s); 885} 886 887usbd_status 888ucomstartread(sc) 889 struct ucom_softc *sc; 890{ 891 usbd_status err; 892 893 DPRINTFN(5,("ucomstartread: start\n")); 894 usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe, 895 (usbd_private_handle)sc, 896 sc->sc_ibuf, UCOMIBUFSIZE, 897 USBD_SHORT_XFER_OK | USBD_NO_COPY, 898 USBD_NO_TIMEOUT, ucomreadcb); 899 err = usbd_transfer(sc->sc_ixfer); 900 if (err != USBD_IN_PROGRESS) { 901 DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err))); 902 return (err); 903 } 904 return (USBD_NORMAL_COMPLETION); 905} 906 907void 908ucomreadcb(xfer, p, status) 909 usbd_xfer_handle xfer; 910 usbd_private_handle p; 911 usbd_status status; 912{ 913 struct ucom_softc *sc = (struct ucom_softc *)p; 914 struct tty *tp = sc->sc_tty; 915 int (*rint) __P((int c, struct tty *tp)) = linesw[tp->t_line].l_rint; 916 usbd_status err; 917 u_int32_t cc; 918 u_char *cp; 919 int s; 920 921 if (status == USBD_CANCELLED) 922 return; 923 924 if (status) { 925 DPRINTF(("ucomreadcb: status=%d\n", status)); 926 usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe); 927 /* XXX we should restart after some delay. */ 928 return; 929 } 930 931 usbd_get_xfer_status(xfer, 0, (void **)&cp, &cc, 0); 932 DPRINTFN(5,("ucomreadcb: got %d chars, tp=%p\n", cc, tp)); 933 s = spltty(); 934 /* Give characters to tty layer. */ 935 while (cc-- > 0) { 936 DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp)); 937 if ((*rint)(*cp++, tp) == -1) { 938 /* XXX what should we do? */ 939 break; 940 } 941 } 942 splx(s); 943 944 err = ucomstartread(sc); 945 if (err) { 946 printf("%s: read start failed\n", USBDEVNAME(sc->sc_dev)); 947 /* XXX what should we dow now? */ 948 } 949} 950 951void 952ucom_cleanup(sc) 953 struct ucom_softc *sc; 954{ 955 DPRINTF(("ucom_cleanup: closing pipes\n")); 956 957 ucom_shutdown(sc); 958 usbd_abort_pipe(sc->sc_bulkin_pipe); 959 usbd_close_pipe(sc->sc_bulkin_pipe); 960 usbd_abort_pipe(sc->sc_bulkout_pipe); 961 usbd_close_pipe(sc->sc_bulkout_pipe); 962 usbd_free_xfer(sc->sc_ixfer); 963 usbd_free_xfer(sc->sc_oxfer); 964} 965 966#endif /* NUCOM > 0 */ 967 968int 969ucomprint(aux, pnp) 970 void *aux; 971 const char *pnp; 972{ 973 974 if (pnp) 975 printf("ucom at %s\n", pnp); 976 return (UNCONF); 977} 978 979int 980ucomsubmatch(parent, cf, aux) 981 struct device *parent; 982 struct cfdata *cf; 983 void *aux; 984{ 985 struct ucom_attach_args *uca = aux; 986 987 if (uca->portno != UCOM_UNK_PORTNO && 988 cf->ucomcf_portno != UCOM_UNK_PORTNO && 989 cf->ucomcf_portno != uca->portno) 990 return (0); 991 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 992} 993