Annotation of sys/dev/usb/ucom.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ucom.c,v 1.41 2007/06/14 10:11:15 mbalmer 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/rwlock.h>
! 48: #include <sys/ioctl.h>
! 49: #include <sys/conf.h>
! 50: #include <sys/tty.h>
! 51: #include <sys/file.h>
! 52: #include <sys/selinfo.h>
! 53: #include <sys/proc.h>
! 54: #include <sys/vnode.h>
! 55: #include <sys/device.h>
! 56: #include <sys/poll.h>
! 57:
! 58: #include <dev/usb/usb.h>
! 59:
! 60: #include <dev/usb/usbdi.h>
! 61: #include <dev/usb/usbdi_util.h>
! 62: #include <dev/usb/uhidev.h>
! 63: #include <dev/usb/usbdevs.h>
! 64: #include <dev/usb/usb_quirks.h>
! 65:
! 66: #include <dev/usb/ucomvar.h>
! 67:
! 68: #include "ucom.h"
! 69:
! 70: #if NUCOM > 0
! 71:
! 72: #ifdef UCOM_DEBUG
! 73: #define DPRINTFN(n, x) do { if (ucomdebug > (n)) printf x; } while (0)
! 74: int ucomdebug = 0;
! 75: #else
! 76: #define DPRINTFN(n, x)
! 77: #endif
! 78: #define DPRINTF(x) DPRINTFN(0, x)
! 79:
! 80: #define UCOMUNIT_MASK 0x7f
! 81: #define UCOMCUA_MASK 0x80
! 82:
! 83: #define LINESW(tp, func) (linesw[(tp)->t_line].func)
! 84:
! 85: #define UCOMUNIT(x) (minor(x) & UCOMUNIT_MASK)
! 86: #define UCOMCUA(x) (minor(x) & UCOMCUA_MASK)
! 87:
! 88: struct ucom_softc {
! 89: struct device sc_dev; /* base device */
! 90:
! 91: usbd_device_handle sc_udev; /* USB device */
! 92: struct uhidev_softc *sc_uhidev; /* hid device (if deeper) */
! 93:
! 94: usbd_interface_handle sc_iface; /* data interface */
! 95:
! 96: int sc_bulkin_no; /* bulk in endpoint address */
! 97: usbd_pipe_handle sc_bulkin_pipe; /* bulk in pipe */
! 98: usbd_xfer_handle sc_ixfer; /* read request */
! 99: u_char *sc_ibuf; /* read buffer */
! 100: u_int sc_ibufsize; /* read buffer size */
! 101: u_int sc_ibufsizepad; /* read buffer size padded */
! 102:
! 103: int sc_bulkout_no; /* bulk out endpoint address */
! 104: usbd_pipe_handle sc_bulkout_pipe;/* bulk out pipe */
! 105: usbd_xfer_handle sc_oxfer; /* write request */
! 106: u_char *sc_obuf; /* write buffer */
! 107: u_int sc_obufsize; /* write buffer size */
! 108: u_int sc_opkthdrlen; /* header length of
! 109: * output packet */
! 110:
! 111: usbd_pipe_handle sc_ipipe; /* hid interrupt input pipe */
! 112: usbd_pipe_handle sc_opipe; /* hid interrupt pipe */
! 113:
! 114: struct ucom_methods *sc_methods;
! 115: void *sc_parent;
! 116: int sc_portno;
! 117:
! 118: struct tty *sc_tty; /* our tty */
! 119: u_char sc_lsr;
! 120: u_char sc_msr;
! 121: u_char sc_mcr;
! 122: u_char sc_tx_stopped;
! 123: int sc_swflags;
! 124:
! 125: u_char sc_cua;
! 126:
! 127: struct rwlock sc_lock; /* lock during open */
! 128: int sc_open;
! 129: int sc_refcnt;
! 130: u_char sc_dying; /* disconnecting */
! 131: };
! 132:
! 133: void ucom_cleanup(struct ucom_softc *);
! 134: void ucom_hwiflow(struct ucom_softc *);
! 135: int ucomparam(struct tty *, struct termios *);
! 136: void ucomstart(struct tty *);
! 137: void ucom_shutdown(struct ucom_softc *);
! 138: int ucom_do_ioctl(struct ucom_softc *, u_long, caddr_t,
! 139: int, struct proc *);
! 140: void ucom_dtr(struct ucom_softc *, int);
! 141: void ucom_rts(struct ucom_softc *, int);
! 142: void ucom_break(struct ucom_softc *, int);
! 143: usbd_status ucomstartread(struct ucom_softc *);
! 144: void ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 145: void ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 146: void tiocm_to_ucom(struct ucom_softc *, u_long, int);
! 147: int ucom_to_tiocm(struct ucom_softc *);
! 148: void ucom_lock(struct ucom_softc *);
! 149: void ucom_unlock(struct ucom_softc *);
! 150:
! 151: int ucom_match(struct device *, void *, void *);
! 152: void ucom_attach(struct device *, struct device *, void *);
! 153: int ucom_detach(struct device *, int);
! 154: int ucom_activate(struct device *, enum devact);
! 155:
! 156: struct cfdriver ucom_cd = {
! 157: NULL, "ucom", DV_DULL
! 158: };
! 159:
! 160: const struct cfattach ucom_ca = {
! 161: sizeof(struct ucom_softc),
! 162: ucom_match,
! 163: ucom_attach,
! 164: ucom_detach,
! 165: ucom_activate,
! 166: };
! 167:
! 168: void
! 169: ucom_lock(struct ucom_softc *sc)
! 170: {
! 171: sc->sc_refcnt++;
! 172: rw_enter_write(&sc->sc_lock);
! 173: }
! 174:
! 175: void
! 176: ucom_unlock(struct ucom_softc *sc)
! 177: {
! 178: rw_exit_write(&sc->sc_lock);
! 179: if (--sc->sc_refcnt < 0)
! 180: usb_detach_wakeup(&sc->sc_dev);
! 181: }
! 182:
! 183: int
! 184: ucom_match(struct device *parent, void *match, void *aux)
! 185: {
! 186: return (1);
! 187: }
! 188:
! 189: void
! 190: ucom_attach(struct device *parent, struct device *self, void *aux)
! 191: {
! 192: struct ucom_softc *sc = (struct ucom_softc *)self;
! 193: struct ucom_attach_args *uca = aux;
! 194: struct tty *tp;
! 195:
! 196: if (uca->info != NULL)
! 197: printf(", %s", uca->info);
! 198: printf("\n");
! 199:
! 200: sc->sc_udev = uca->device;
! 201: sc->sc_iface = uca->iface;
! 202: sc->sc_bulkout_no = uca->bulkout;
! 203: sc->sc_bulkin_no = uca->bulkin;
! 204: sc->sc_uhidev = uca->uhidev;
! 205: sc->sc_ibufsize = uca->ibufsize;
! 206: sc->sc_ibufsizepad = uca->ibufsizepad;
! 207: sc->sc_obufsize = uca->obufsize;
! 208: sc->sc_opkthdrlen = uca->opkthdrlen;
! 209: sc->sc_methods = uca->methods;
! 210: sc->sc_parent = uca->arg;
! 211: sc->sc_portno = uca->portno;
! 212:
! 213: tp = ttymalloc();
! 214: tp->t_oproc = ucomstart;
! 215: tp->t_param = ucomparam;
! 216: sc->sc_tty = tp;
! 217: sc->sc_cua = 0;
! 218:
! 219: rw_init(&sc->sc_lock, "ucomlk");
! 220:
! 221: sc->sc_open = 0;
! 222: }
! 223:
! 224: int
! 225: ucom_detach(struct device *self, int flags)
! 226: {
! 227: struct ucom_softc *sc = (struct ucom_softc *)self;
! 228: struct tty *tp = sc->sc_tty;
! 229: int maj, mn;
! 230: int s;
! 231:
! 232: DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",
! 233: sc, flags, tp, sc->sc_bulkin_no, sc->sc_bulkout_no));
! 234:
! 235: sc->sc_dying = 1;
! 236:
! 237: if (sc->sc_bulkin_pipe != NULL)
! 238: usbd_abort_pipe(sc->sc_bulkin_pipe);
! 239: if (sc->sc_bulkout_pipe != NULL)
! 240: usbd_abort_pipe(sc->sc_bulkout_pipe);
! 241:
! 242: s = splusb();
! 243: if (--sc->sc_refcnt >= 0) {
! 244: /* Wake up anyone waiting */
! 245: if (tp != NULL) {
! 246: CLR(tp->t_state, TS_CARR_ON);
! 247: CLR(tp->t_cflag, CLOCAL | MDMBUF);
! 248: ttyflush(tp, FREAD|FWRITE);
! 249: }
! 250: /* Wait for processes to go away. */
! 251: usb_detach_wait(&sc->sc_dev);
! 252: }
! 253: splx(s);
! 254:
! 255: /* locate the major number */
! 256: for (maj = 0; maj < nchrdev; maj++)
! 257: if (cdevsw[maj].d_open == ucomopen)
! 258: break;
! 259:
! 260: /* Nuke the vnodes for any open instances. */
! 261: mn = self->dv_unit;
! 262: DPRINTF(("ucom_detach: maj=%d mn=%d\n", maj, mn));
! 263: vdevgone(maj, mn, mn, VCHR);
! 264: vdevgone(maj, mn | UCOMCUA_MASK, mn | UCOMCUA_MASK, VCHR);
! 265:
! 266: /* Detach and free the tty. */
! 267: if (tp != NULL) {
! 268: ttyfree(tp);
! 269: sc->sc_tty = NULL;
! 270: }
! 271:
! 272: return (0);
! 273: }
! 274:
! 275: int
! 276: ucom_activate(struct device *self, enum devact act)
! 277: {
! 278: struct ucom_softc *sc = (struct ucom_softc *)self;
! 279:
! 280: DPRINTFN(5,("ucom_activate: %d\n", act));
! 281:
! 282: switch (act) {
! 283: case DVACT_ACTIVATE:
! 284: break;
! 285:
! 286: case DVACT_DEACTIVATE:
! 287: sc->sc_dying = 1;
! 288: break;
! 289: }
! 290: return (0);
! 291: }
! 292:
! 293: void
! 294: ucom_shutdown(struct ucom_softc *sc)
! 295: {
! 296: struct tty *tp = sc->sc_tty;
! 297:
! 298: DPRINTF(("ucom_shutdown\n"));
! 299: /*
! 300: * Hang up if necessary. Wait a bit, so the other side has time to
! 301: * notice even if we immediately open the port again.
! 302: */
! 303: if (ISSET(tp->t_cflag, HUPCL)) {
! 304: ucom_dtr(sc, 0);
! 305: (void)tsleep(sc, TTIPRI, ttclos, hz);
! 306: }
! 307: }
! 308:
! 309: int
! 310: ucomopen(dev_t dev, int flag, int mode, struct proc *p)
! 311: {
! 312: int unit = UCOMUNIT(dev);
! 313: usbd_status err;
! 314: struct ucom_softc *sc;
! 315: struct tty *tp;
! 316: struct termios t;
! 317: int s;
! 318: int error;
! 319:
! 320: if (unit >= ucom_cd.cd_ndevs)
! 321: return (ENXIO);
! 322: sc = ucom_cd.cd_devs[unit];
! 323: if (sc == NULL)
! 324: return (ENXIO);
! 325:
! 326: if (sc->sc_dying)
! 327: return (EIO);
! 328:
! 329: if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
! 330: return (ENXIO);
! 331:
! 332: /* open the pipes if this is the first open */
! 333: ucom_lock(sc);
! 334: if (sc->sc_open++ == 0) {
! 335: s = splusb();
! 336:
! 337: DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
! 338: sc->sc_bulkin_no, sc->sc_bulkout_no));
! 339: DPRINTF(("ucomopen: hid %p pipes in=%p out=%p\n",
! 340: sc->sc_uhidev, sc->sc_ipipe, sc->sc_opipe));
! 341:
! 342: if (sc->sc_bulkin_no != -1) {
! 343:
! 344: /* Open the bulk pipes */
! 345: err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
! 346: &sc->sc_bulkin_pipe);
! 347: if (err) {
! 348: DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
! 349: sc->sc_dev.dv_xname, sc->sc_bulkin_no,
! 350: usbd_errstr(err)));
! 351: error = EIO;
! 352: goto fail_0;
! 353: }
! 354: err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
! 355: USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
! 356: if (err) {
! 357: DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
! 358: sc->sc_dev.dv_xname, sc->sc_bulkout_no,
! 359: usbd_errstr(err)));
! 360: error = EIO;
! 361: goto fail_1;
! 362: }
! 363:
! 364: /* Allocate a request and an input buffer and start reading. */
! 365: sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
! 366: if (sc->sc_ixfer == NULL) {
! 367: error = ENOMEM;
! 368: goto fail_2;
! 369: }
! 370:
! 371: sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
! 372: sc->sc_ibufsizepad);
! 373: if (sc->sc_ibuf == NULL) {
! 374: error = ENOMEM;
! 375: goto fail_2;
! 376: }
! 377:
! 378: sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
! 379: if (sc->sc_oxfer == NULL) {
! 380: error = ENOMEM;
! 381: goto fail_3;
! 382: }
! 383: } else {
! 384: /*
! 385: * input/output pipes and xfers already allocated
! 386: * as is the input buffer.
! 387: */
! 388: sc->sc_ipipe = sc->sc_uhidev->sc_ipipe;
! 389: sc->sc_ixfer = sc->sc_uhidev->sc_ixfer;
! 390: sc->sc_opipe = sc->sc_uhidev->sc_opipe;
! 391: sc->sc_oxfer = sc->sc_uhidev->sc_oxfer;
! 392: }
! 393:
! 394: sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
! 395: sc->sc_obufsize + sc->sc_opkthdrlen);
! 396: if (sc->sc_obuf == NULL) {
! 397: error = ENOMEM;
! 398: goto fail_4;
! 399: }
! 400:
! 401: if (sc->sc_methods->ucom_open != NULL) {
! 402: error = sc->sc_methods->ucom_open(sc->sc_parent,
! 403: sc->sc_portno);
! 404: if (error) {
! 405: ucom_cleanup(sc);
! 406: splx(s);
! 407: ucom_unlock(sc);
! 408: return (error);
! 409: }
! 410: }
! 411:
! 412: ucom_status_change(sc);
! 413:
! 414: ucomstartread(sc);
! 415:
! 416: splx(s);
! 417: }
! 418: ucom_unlock(sc);
! 419:
! 420: s = spltty();
! 421: tp = sc->sc_tty;
! 422: splx(s);
! 423:
! 424: DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp));
! 425:
! 426: tp->t_dev = dev;
! 427: if (!ISSET(tp->t_state, TS_ISOPEN)) {
! 428: SET(tp->t_state, TS_WOPEN);
! 429: ttychars(tp);
! 430:
! 431: /*
! 432: * Initialize the termios status to the defaults. Add in the
! 433: * sticky bits from TIOCSFLAGS.
! 434: */
! 435: t.c_ispeed = 0;
! 436: t.c_ospeed = TTYDEF_SPEED;
! 437: t.c_cflag = TTYDEF_CFLAG;
! 438: if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
! 439: SET(t.c_cflag, CLOCAL);
! 440: if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
! 441: SET(t.c_cflag, CRTSCTS);
! 442: if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
! 443: SET(t.c_cflag, MDMBUF);
! 444:
! 445: /* Make sure ucomparam() will do something. */
! 446: tp->t_ospeed = 0;
! 447: (void) ucomparam(tp, &t);
! 448: tp->t_iflag = TTYDEF_IFLAG;
! 449: tp->t_oflag = TTYDEF_OFLAG;
! 450: tp->t_lflag = TTYDEF_LFLAG;
! 451:
! 452: s = spltty();
! 453: ttsetwater(tp);
! 454:
! 455: /*
! 456: * Turn on DTR. We must always do this, even if carrier is not
! 457: * present, because otherwise we'd have to use TIOCSDTR
! 458: * immediately after setting CLOCAL, which applications do not
! 459: * expect. We always assert DTR while the device is open
! 460: * unless explicitly requested to deassert it.
! 461: */
! 462: ucom_dtr(sc, 1);
! 463:
! 464: /* XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK);*/
! 465: ucom_hwiflow(sc);
! 466:
! 467: if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || UCOMCUA(dev) ||
! 468: ISSET(sc->sc_msr, UMSR_DCD) || ISSET(tp->t_cflag, MDMBUF))
! 469: SET(tp->t_state, TS_CARR_ON);
! 470: else
! 471: CLR(tp->t_state, TS_CARR_ON);
! 472: } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) {
! 473: error = EBUSY;
! 474: goto bad;
! 475: } else
! 476: s = spltty();
! 477:
! 478: if (UCOMCUA(dev)) {
! 479: if (ISSET(tp->t_state, TS_ISOPEN)) {
! 480: /* Someone is already dialed in */
! 481: error = EBUSY;
! 482: goto bad1;
! 483: }
! 484: sc->sc_cua = 1;
! 485: } else {
! 486: /* tty (not cua) device, wait for carrier */
! 487: if (ISSET(flag, O_NONBLOCK)) {
! 488: if (sc->sc_cua) {
! 489: error = EBUSY;
! 490: goto bad1;
! 491: }
! 492: } else {
! 493: while (sc->sc_cua || (!ISSET(tp->t_cflag, CLOCAL) &&
! 494: !ISSET(tp->t_state, TS_CARR_ON))) {
! 495: SET(tp->t_state, TS_WOPEN);
! 496: error = ttysleep(tp, &tp->t_rawq,
! 497: TTIPRI | PCATCH, ttopen, 0);
! 498: /*
! 499: * If TS_WOPEN has been reset, that means the
! 500: * cua device has been closed. We don't want
! 501: * to fail in that case, so just go around
! 502: * again.
! 503: */
! 504: if (error && ISSET(tp->t_state, TS_WOPEN)) {
! 505: CLR(tp->t_state, TS_WOPEN);
! 506: goto bad1;
! 507: }
! 508: }
! 509: }
! 510: }
! 511: splx(s);
! 512:
! 513: error = ttyopen(UCOMUNIT(dev), tp);
! 514: if (error)
! 515: goto bad;
! 516:
! 517: error = (*LINESW(tp, l_open))(dev, tp);
! 518: if (error)
! 519: goto bad;
! 520:
! 521: return (0);
! 522:
! 523: fail_4:
! 524: if (sc->sc_uhidev == NULL)
! 525: usbd_free_xfer(sc->sc_oxfer);
! 526: sc->sc_oxfer = NULL;
! 527: fail_3:
! 528: usbd_free_xfer(sc->sc_ixfer);
! 529: sc->sc_ixfer = NULL;
! 530: fail_2:
! 531: usbd_close_pipe(sc->sc_bulkout_pipe);
! 532: sc->sc_bulkout_pipe = NULL;
! 533: fail_1:
! 534: usbd_close_pipe(sc->sc_bulkin_pipe);
! 535: sc->sc_bulkin_pipe = NULL;
! 536: fail_0:
! 537: splx(s);
! 538: ucom_unlock(sc);
! 539: return (error);
! 540:
! 541: bad1:
! 542: splx(s);
! 543: bad:
! 544: ucom_lock(sc);
! 545: ucom_cleanup(sc);
! 546: ucom_unlock(sc);
! 547:
! 548: return (error);
! 549: }
! 550:
! 551: int
! 552: ucomclose(dev_t dev, int flag, int mode, struct proc *p)
! 553: {
! 554: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
! 555: struct tty *tp = sc->sc_tty;
! 556: int s;
! 557:
! 558: if (!ISSET(tp->t_state, TS_ISOPEN))
! 559: return (0);
! 560:
! 561: DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
! 562: ucom_lock(sc);
! 563:
! 564: (*LINESW(tp, l_close))(tp, flag);
! 565: s = spltty();
! 566: CLR(tp->t_state, TS_BUSY | TS_FLUSH);
! 567: sc->sc_cua = 0;
! 568: ttyclose(tp);
! 569: ucom_cleanup(sc);
! 570: splx(s);
! 571:
! 572: if (sc->sc_methods->ucom_close != NULL)
! 573: sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
! 574:
! 575: ucom_unlock(sc);
! 576:
! 577: return (0);
! 578: }
! 579:
! 580: int
! 581: ucomread(dev_t dev, struct uio *uio, int flag)
! 582: {
! 583: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
! 584: struct tty *tp = sc->sc_tty;
! 585: int error;
! 586:
! 587: if (sc->sc_dying)
! 588: return (EIO);
! 589:
! 590: sc->sc_refcnt++;
! 591: error = (*LINESW(tp, l_read))(tp, uio, flag);
! 592: if (--sc->sc_refcnt < 0)
! 593: usb_detach_wakeup(&sc->sc_dev);
! 594: return (error);
! 595: }
! 596:
! 597: int
! 598: ucomwrite(dev_t dev, struct uio *uio, int flag)
! 599: {
! 600: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
! 601: struct tty *tp = sc->sc_tty;
! 602: int error;
! 603:
! 604: if (sc->sc_dying)
! 605: return (EIO);
! 606:
! 607: sc->sc_refcnt++;
! 608: error = (*LINESW(tp, l_write))(tp, uio, flag);
! 609: if (--sc->sc_refcnt < 0)
! 610: usb_detach_wakeup(&sc->sc_dev);
! 611: return (error);
! 612: }
! 613:
! 614: struct tty *
! 615: ucomtty(dev_t dev)
! 616: {
! 617: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
! 618: struct tty *tp = sc->sc_tty;
! 619:
! 620: return (tp);
! 621: }
! 622:
! 623: int
! 624: ucomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 625: {
! 626: struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
! 627: int error;
! 628:
! 629: sc->sc_refcnt++;
! 630: error = ucom_do_ioctl(sc, cmd, data, flag, p);
! 631: if (--sc->sc_refcnt < 0)
! 632: usb_detach_wakeup(&sc->sc_dev);
! 633: return (error);
! 634: }
! 635:
! 636: int
! 637: ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, caddr_t data,
! 638: int flag, struct proc *p)
! 639: {
! 640: struct tty *tp = sc->sc_tty;
! 641: int error;
! 642: int s;
! 643:
! 644: if (sc->sc_dying)
! 645: return (EIO);
! 646:
! 647: DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd));
! 648:
! 649: error = (*LINESW(tp, l_ioctl))(tp, cmd, data, flag, p);
! 650: if (error >= 0)
! 651: return (error);
! 652:
! 653: error = ttioctl(tp, cmd, data, flag, p);
! 654: if (error >= 0)
! 655: return (error);
! 656:
! 657: if (sc->sc_methods->ucom_ioctl != NULL) {
! 658: error = sc->sc_methods->ucom_ioctl(sc->sc_parent,
! 659: sc->sc_portno, cmd, data, flag, p);
! 660: if (error >= 0)
! 661: return (error);
! 662: }
! 663:
! 664: error = 0;
! 665:
! 666: DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd));
! 667: s = spltty();
! 668:
! 669: switch (cmd) {
! 670: case TIOCSBRK:
! 671: ucom_break(sc, 1);
! 672: break;
! 673:
! 674: case TIOCCBRK:
! 675: ucom_break(sc, 0);
! 676: break;
! 677:
! 678: case TIOCSDTR:
! 679: ucom_dtr(sc, 1);
! 680: break;
! 681:
! 682: case TIOCCDTR:
! 683: ucom_dtr(sc, 0);
! 684: break;
! 685:
! 686: case TIOCGFLAGS:
! 687: *(int *)data = sc->sc_swflags;
! 688: break;
! 689:
! 690: case TIOCSFLAGS:
! 691: error = suser(p, 0);
! 692: if (error)
! 693: break;
! 694: sc->sc_swflags = *(int *)data;
! 695: break;
! 696:
! 697: case TIOCMSET:
! 698: case TIOCMBIS:
! 699: case TIOCMBIC:
! 700: tiocm_to_ucom(sc, cmd, *(int *)data);
! 701: break;
! 702:
! 703: case TIOCMGET:
! 704: *(int *)data = ucom_to_tiocm(sc);
! 705: break;
! 706:
! 707: default:
! 708: error = ENOTTY;
! 709: break;
! 710: }
! 711:
! 712: splx(s);
! 713:
! 714: return (error);
! 715: }
! 716:
! 717: void
! 718: tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)
! 719: {
! 720: u_char combits;
! 721:
! 722: combits = 0;
! 723: if (ISSET(ttybits, TIOCM_DTR))
! 724: SET(combits, UMCR_DTR);
! 725: if (ISSET(ttybits, TIOCM_RTS))
! 726: SET(combits, UMCR_RTS);
! 727:
! 728: switch (how) {
! 729: case TIOCMBIC:
! 730: CLR(sc->sc_mcr, combits);
! 731: break;
! 732:
! 733: case TIOCMBIS:
! 734: SET(sc->sc_mcr, combits);
! 735: break;
! 736:
! 737: case TIOCMSET:
! 738: CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS);
! 739: SET(sc->sc_mcr, combits);
! 740: break;
! 741: }
! 742:
! 743: if (how == TIOCMSET || ISSET(combits, UMCR_DTR))
! 744: ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
! 745: if (how == TIOCMSET || ISSET(combits, UMCR_RTS))
! 746: ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
! 747: }
! 748:
! 749: int
! 750: ucom_to_tiocm(struct ucom_softc *sc)
! 751: {
! 752: u_char combits;
! 753: int ttybits = 0;
! 754:
! 755: combits = sc->sc_mcr;
! 756: if (ISSET(combits, UMCR_DTR))
! 757: SET(ttybits, TIOCM_DTR);
! 758: if (ISSET(combits, UMCR_RTS))
! 759: SET(ttybits, TIOCM_RTS);
! 760:
! 761: combits = sc->sc_msr;
! 762: if (ISSET(combits, UMSR_DCD))
! 763: SET(ttybits, TIOCM_CD);
! 764: if (ISSET(combits, UMSR_CTS))
! 765: SET(ttybits, TIOCM_CTS);
! 766: if (ISSET(combits, UMSR_DSR))
! 767: SET(ttybits, TIOCM_DSR);
! 768: if (ISSET(combits, UMSR_RI | UMSR_TERI))
! 769: SET(ttybits, TIOCM_RI);
! 770:
! 771: #if 0
! 772: XXX;
! 773: if (sc->sc_ier != 0)
! 774: SET(ttybits, TIOCM_LE);
! 775: #endif
! 776:
! 777: return (ttybits);
! 778: }
! 779:
! 780: void
! 781: ucom_break(sc, onoff)
! 782: struct ucom_softc *sc;
! 783: int onoff;
! 784: {
! 785: DPRINTF(("ucom_break: onoff=%d\n", onoff));
! 786:
! 787: if (sc->sc_methods->ucom_set != NULL)
! 788: sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
! 789: UCOM_SET_BREAK, onoff);
! 790: }
! 791:
! 792: void
! 793: ucom_dtr(struct ucom_softc *sc, int onoff)
! 794: {
! 795: DPRINTF(("ucom_dtr: onoff=%d\n", onoff));
! 796:
! 797: if (sc->sc_methods->ucom_set != NULL) {
! 798: sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
! 799: UCOM_SET_DTR, onoff);
! 800: /* When not using CRTSCTS, RTS follows DTR. */
! 801: if (!(sc->sc_swflags & TIOCFLAG_CRTSCTS))
! 802: ucom_rts(sc, onoff);
! 803: }
! 804: }
! 805:
! 806: void
! 807: ucom_rts(struct ucom_softc *sc, int onoff)
! 808: {
! 809: DPRINTF(("ucom_rts: onoff=%d\n", onoff));
! 810:
! 811: if (sc->sc_methods->ucom_set != NULL)
! 812: sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
! 813: UCOM_SET_RTS, onoff);
! 814: }
! 815:
! 816: void
! 817: ucom_status_change(struct ucom_softc *sc)
! 818: {
! 819: struct tty *tp = sc->sc_tty;
! 820: u_char old_msr;
! 821:
! 822: if (sc->sc_methods->ucom_get_status != NULL) {
! 823: old_msr = sc->sc_msr;
! 824: sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
! 825: &sc->sc_lsr, &sc->sc_msr);
! 826:
! 827: ttytstamp(tp, old_msr & UMSR_CTS, sc->sc_msr & UMSR_CTS,
! 828: old_msr & UMSR_DCD, sc->sc_msr & UMSR_DCD);
! 829:
! 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: 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: 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: 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: #ifdef DIAGNOSTIC
! 986: if (sc->sc_oxfer == NULL) {
! 987: printf("ucomstart: null oxfer\n");
! 988: goto out;
! 989: }
! 990: #endif
! 991: if (sc->sc_bulkout_pipe != NULL) {
! 992: usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
! 993: (usbd_private_handle)sc, sc->sc_obuf, cnt,
! 994: USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
! 995: } else {
! 996: usbd_setup_xfer(sc->sc_oxfer, sc->sc_opipe,
! 997: (usbd_private_handle)sc, sc->sc_obuf, cnt,
! 998: USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
! 999: }
! 1000: /* What can we do on error? */
! 1001: err = usbd_transfer(sc->sc_oxfer);
! 1002: #ifdef DIAGNOSTIC
! 1003: if (err != USBD_IN_PROGRESS)
! 1004: printf("ucomstart: err=%s\n", usbd_errstr(err));
! 1005: #endif
! 1006:
! 1007: out:
! 1008: splx(s);
! 1009: }
! 1010:
! 1011: int
! 1012: ucomstop(struct tty *tp, int flag)
! 1013: {
! 1014: DPRINTF(("ucomstop: flag=%d\n", flag));
! 1015: #if 0
! 1016: /*struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];*/
! 1017: int s;
! 1018:
! 1019: s = spltty();
! 1020: if (ISSET(tp->t_state, TS_BUSY)) {
! 1021: DPRINTF(("ucomstop: XXX\n"));
! 1022: /* sc->sc_tx_stopped = 1; */
! 1023: if (!ISSET(tp->t_state, TS_TTSTOP))
! 1024: SET(tp->t_state, TS_FLUSH);
! 1025: }
! 1026: splx(s);
! 1027: #endif
! 1028: return (0);
! 1029: }
! 1030:
! 1031: void
! 1032: ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
! 1033: {
! 1034: struct ucom_softc *sc = (struct ucom_softc *)p;
! 1035: struct tty *tp = sc->sc_tty;
! 1036: u_int32_t cc;
! 1037: int s;
! 1038:
! 1039: DPRINTFN(5,("ucomwritecb: %p %p status=%d\n", xfer, p, status));
! 1040:
! 1041: if (status == USBD_CANCELLED || sc->sc_dying)
! 1042: goto error;
! 1043:
! 1044: if (sc->sc_bulkin_pipe != NULL) {
! 1045: if (status) {
! 1046: usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
! 1047: /* XXX we should restart after some delay. */
! 1048: goto error;
! 1049: }
! 1050: usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
! 1051: } else {
! 1052: usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
! 1053: // XXX above gives me wrong cc, no?
! 1054: }
! 1055:
! 1056: DPRINTFN(5,("ucomwritecb: cc=%d\n", cc));
! 1057: /* convert from USB bytes to tty bytes */
! 1058: cc -= sc->sc_opkthdrlen;
! 1059:
! 1060: s = spltty();
! 1061: CLR(tp->t_state, TS_BUSY);
! 1062: if (ISSET(tp->t_state, TS_FLUSH))
! 1063: CLR(tp->t_state, TS_FLUSH);
! 1064: else
! 1065: ndflush(&tp->t_outq, cc);
! 1066: (*LINESW(tp, l_start))(tp);
! 1067: splx(s);
! 1068: return;
! 1069:
! 1070: error:
! 1071: s = spltty();
! 1072: CLR(tp->t_state, TS_BUSY);
! 1073: splx(s);
! 1074: }
! 1075:
! 1076: usbd_status
! 1077: ucomstartread(struct ucom_softc *sc)
! 1078: {
! 1079: usbd_status err;
! 1080:
! 1081: DPRINTFN(5,("ucomstartread: start\n"));
! 1082: #ifdef DIAGNOSTIC
! 1083: if (sc->sc_ixfer == NULL) {
! 1084: DPRINTF(("ucomstartread: null ixfer\n"));
! 1085: return (USBD_INVAL);
! 1086: }
! 1087: #endif
! 1088:
! 1089: if (sc->sc_bulkin_pipe != NULL) {
! 1090: usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
! 1091: (usbd_private_handle)sc,
! 1092: sc->sc_ibuf, sc->sc_ibufsize,
! 1093: USBD_SHORT_XFER_OK | USBD_NO_COPY,
! 1094: USBD_NO_TIMEOUT, ucomreadcb);
! 1095: err = usbd_transfer(sc->sc_ixfer);
! 1096: if (err != USBD_IN_PROGRESS) {
! 1097: DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err)));
! 1098: return (err);
! 1099: }
! 1100: }
! 1101:
! 1102: return (USBD_NORMAL_COMPLETION);
! 1103: }
! 1104:
! 1105: void
! 1106: ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
! 1107: {
! 1108: struct ucom_softc *sc = (struct ucom_softc *)p;
! 1109: struct tty *tp = sc->sc_tty;
! 1110: int (*rint)(int c, struct tty *tp) = LINESW(tp, l_rint);
! 1111: usbd_status err;
! 1112: u_int32_t cc;
! 1113: u_char *cp;
! 1114: int s;
! 1115:
! 1116: DPRINTFN(5,("ucomreadcb: status=%d\n", status));
! 1117:
! 1118: if (status == USBD_CANCELLED || status == USBD_IOERROR ||
! 1119: sc->sc_dying) {
! 1120: DPRINTF(("ucomreadcb: dying\n"));
! 1121: /* Send something to wake upper layer */
! 1122: s = spltty();
! 1123: (*rint)('\n', tp);
! 1124: ttwakeup(tp);
! 1125: splx(s);
! 1126: return;
! 1127: }
! 1128:
! 1129: if (status) {
! 1130: if (sc->sc_bulkin_pipe != NULL) {
! 1131: usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
! 1132: /* XXX we should restart after some delay. */
! 1133: return;
! 1134: }
! 1135: }
! 1136:
! 1137: usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
! 1138: DPRINTFN(5,("ucomreadcb: got %d chars, tp=%p\n", cc, tp));
! 1139: if (sc->sc_methods->ucom_read != NULL)
! 1140: sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno,
! 1141: &cp, &cc);
! 1142:
! 1143: s = spltty();
! 1144: /* Give characters to tty layer. */
! 1145: while (cc-- > 0) {
! 1146: DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp));
! 1147: if ((*rint)(*cp++, tp) == -1) {
! 1148: /* XXX what should we do? */
! 1149: printf("%s: lost %d chars\n", sc->sc_dev.dv_xname,
! 1150: cc);
! 1151: break;
! 1152: }
! 1153: }
! 1154: splx(s);
! 1155:
! 1156: err = ucomstartread(sc);
! 1157: if (err) {
! 1158: printf("%s: read start failed\n", sc->sc_dev.dv_xname);
! 1159: /* XXX what should we dow now? */
! 1160: }
! 1161: }
! 1162:
! 1163: void
! 1164: ucom_cleanup(struct ucom_softc *sc)
! 1165: {
! 1166: if (--sc->sc_open == 0) {
! 1167: DPRINTF(("ucom_cleanup: closing pipes\n"));
! 1168:
! 1169: ucom_shutdown(sc);
! 1170: if (sc->sc_bulkin_pipe != NULL) {
! 1171: usbd_abort_pipe(sc->sc_bulkin_pipe);
! 1172: usbd_close_pipe(sc->sc_bulkin_pipe);
! 1173: sc->sc_bulkin_pipe = NULL;
! 1174: }
! 1175: if (sc->sc_bulkout_pipe != NULL) {
! 1176: usbd_abort_pipe(sc->sc_bulkout_pipe);
! 1177: usbd_close_pipe(sc->sc_bulkout_pipe);
! 1178: sc->sc_bulkout_pipe = NULL;
! 1179: }
! 1180: if (sc->sc_ixfer != NULL) {
! 1181: if (sc->sc_uhidev == NULL)
! 1182: usbd_free_xfer(sc->sc_ixfer);
! 1183: sc->sc_ixfer = NULL;
! 1184: }
! 1185: if (sc->sc_oxfer != NULL) {
! 1186: usbd_free_buffer(sc->sc_oxfer);
! 1187: if (sc->sc_uhidev == NULL)
! 1188: usbd_free_xfer(sc->sc_oxfer);
! 1189: sc->sc_oxfer = NULL;
! 1190: }
! 1191: }
! 1192: }
! 1193:
! 1194: #endif /* NUCOM > 0 */
! 1195:
! 1196: int
! 1197: ucomprint(void *aux, const char *pnp)
! 1198: {
! 1199: struct ucom_attach_args *uca = aux;
! 1200:
! 1201: if (pnp)
! 1202: printf("ucom at %s", pnp);
! 1203: if (uca->portno != UCOM_UNK_PORTNO)
! 1204: printf(" portno %d", uca->portno);
! 1205: return (UNCONF);
! 1206: }
! 1207:
! 1208: int
! 1209: ucomsubmatch(struct device *parent, void *match, void *aux)
! 1210: {
! 1211: struct ucom_attach_args *uca = aux;
! 1212: struct cfdata *cf = match;
! 1213:
! 1214: if (uca->portno != UCOM_UNK_PORTNO &&
! 1215: cf->ucomcf_portno != UCOM_UNK_PORTNO &&
! 1216: cf->ucomcf_portno != uca->portno)
! 1217: return (0);
! 1218: return ((*cf->cf_attach->ca_match)(parent, cf, aux));
! 1219: }
CVSweb