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