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