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