1 /* $NetBSD: umodem.c,v 1.19 1999/11/26 09:12:50 augustss Exp $ */ 2 3 /* 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (augustss@carlstedt.se) at 9 * Carlstedt Research & Technology. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Comm Class spec: http://www.usb.org/developers/data/usbcdc11.pdf 42 */ 43 44 /* 45 * TODO: 46 * - Add error recovery in various places; the big problem is what 47 * to do in a callback if there is an error. 48 * - Implement a Call Device for modems without multiplexed commands. 49 * 50 */ 51 52 #include <sys/param.h> 53 #include <sys/systm.h> 54 #include <sys/kernel.h> 55 #include <sys/malloc.h> 56 #include <sys/ioctl.h> 57 #include <sys/conf.h> 58 #include <sys/tty.h> 59 #include <sys/file.h> 60 #include <sys/select.h> 61 #include <sys/proc.h> 62 #include <sys/vnode.h> 63 #include <sys/device.h> 64 #include <sys/poll.h> 65 66 #include <dev/usb/usb.h> 67 #include <dev/usb/usbcdc.h> 68 69 #include <dev/usb/usbdi.h> 70 #include <dev/usb/usbdi_util.h> 71 #include <dev/usb/usbdevs.h> 72 #include <dev/usb/usb_quirks.h> 73 74 #include <dev/usb/usbdevs.h> 75 76 #ifdef USB_DEBUG 77 #define DPRINTFN(n, x) if (umodemdebug > (n)) logprintf x 78 int umodemdebug = 0; 79 #else 80 #define DPRINTFN(n, x) 81 #endif 82 #define DPRINTF(x) DPRINTFN(0, x) 83 84 /* Macros to clear/set/test flags. */ 85 #define SET(t, f) (t) |= (f) 86 #define CLR(t, f) (t) &= ~((unsigned)(f)) 87 #define ISSET(t, f) ((t) & (f)) 88 89 #define UMODEMUNIT_MASK 0x3ffff 90 #define UMODEMDIALOUT_MASK 0x80000 91 #define UMODEMCALLUNIT_MASK 0x40000 92 93 #define UMODEMUNIT(x) (minor(x) & UMODEMUNIT_MASK) 94 #define UMODEMDIALOUT(x) (minor(x) & UMODEMDIALOUT_MASK) 95 #define UMODEMCALLUNIT(x) (minor(x) & UMODEMCALLUNIT_MASK) 96 97 /* 98 * These are the maximum number of bytes transferred per frame. 99 * If some really high speed devices should use this driver they 100 * may need to be increased, but this is good enough for modems. 101 */ 102 #define UMODEMIBUFSIZE 64 103 #define UMODEMOBUFSIZE 256 104 105 struct umodem_softc { 106 USBBASEDEVICE sc_dev; /* base device */ 107 108 usbd_device_handle sc_udev; /* USB device */ 109 110 int sc_ctl_iface_no; 111 usbd_interface_handle sc_ctl_iface; /* control interface */ 112 int sc_data_iface_no; 113 usbd_interface_handle sc_data_iface; /* data interface */ 114 115 int sc_bulkin_no; /* bulk in endpoint address */ 116 usbd_pipe_handle sc_bulkin_pipe; /* bulk in pipe */ 117 usbd_xfer_handle sc_ixfer; /* read request */ 118 u_char *sc_ibuf; /* read buffer */ 119 120 int sc_bulkout_no; /* bulk out endpoint address */ 121 usbd_pipe_handle sc_bulkout_pipe;/* bulk out pipe */ 122 usbd_xfer_handle sc_oxfer; /* write request */ 123 u_char *sc_obuf; /* write buffer */ 124 125 int sc_cm_cap; /* CM capabilities */ 126 int sc_acm_cap; /* ACM capabilities */ 127 128 int sc_cm_over_data; 129 130 struct tty *sc_tty; /* our tty */ 131 132 usb_cdc_line_state_t sc_line_state; /* current line state */ 133 u_char sc_dtr; /* current DTR state */ 134 135 u_char sc_opening; /* lock during open */ 136 u_char sc_dying; /* disconnecting */ 137 }; 138 139 cdev_decl(umodem); 140 141 void *umodem_get_desc 142 __P((usbd_device_handle dev, int type, int subtype)); 143 usbd_status umodem_set_comm_feature 144 __P((struct umodem_softc *sc, int feature, int state)); 145 usbd_status umodem_set_line_coding 146 __P((struct umodem_softc *sc, usb_cdc_line_state_t *state)); 147 148 void umodem_get_caps __P((usbd_device_handle, int *, int *)); 149 void umodem_cleanup __P((struct umodem_softc *)); 150 int umodemparam __P((struct tty *, struct termios *)); 151 void umodemstart __P((struct tty *)); 152 void umodem_shutdown __P((struct umodem_softc *)); 153 void umodem_modem __P((struct umodem_softc *, int)); 154 void umodem_break __P((struct umodem_softc *, int)); 155 usbd_status umodemstartread __P((struct umodem_softc *)); 156 void umodemreadcb __P((usbd_xfer_handle, usbd_private_handle, 157 usbd_status status)); 158 void umodemwritecb __P((usbd_xfer_handle, usbd_private_handle, 159 usbd_status status)); 160 161 USB_DECLARE_DRIVER(umodem); 162 163 USB_MATCH(umodem) 164 { 165 USB_MATCH_START(umodem, uaa); 166 usb_interface_descriptor_t *id; 167 int cm, acm; 168 169 if (!uaa->iface) 170 return (UMATCH_NONE); 171 172 id = usbd_get_interface_descriptor(uaa->iface); 173 if (id == 0 || 174 id->bInterfaceClass != UCLASS_CDC || 175 id->bInterfaceSubClass != USUBCLASS_ABSTRACT_CONTROL_MODEL || 176 id->bInterfaceProtocol != UPROTO_CDC_AT) 177 return (UMATCH_NONE); 178 179 umodem_get_caps(uaa->device, &cm, &acm); 180 if (!(cm & USB_CDC_CM_DOES_CM) || 181 !(cm & USB_CDC_CM_OVER_DATA) || 182 !(acm & USB_CDC_ACM_HAS_LINE)) 183 return (UMATCH_NONE); 184 185 return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); 186 } 187 188 USB_ATTACH(umodem) 189 { 190 USB_ATTACH_START(umodem, sc, uaa); 191 usbd_device_handle dev = uaa->device; 192 usb_interface_descriptor_t *id; 193 usb_endpoint_descriptor_t *ed; 194 usb_cdc_cm_descriptor_t *cmd; 195 char devinfo[1024]; 196 usbd_status err; 197 int data_ifaceno; 198 int i; 199 struct tty *tp; 200 201 usbd_devinfo(uaa->device, 0, devinfo); 202 USB_ATTACH_SETUP; 203 204 sc->sc_udev = dev; 205 206 sc->sc_ctl_iface = uaa->iface; 207 id = usbd_get_interface_descriptor(sc->sc_ctl_iface); 208 printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), 209 devinfo, id->bInterfaceClass, id->bInterfaceSubClass); 210 sc->sc_ctl_iface_no = id->bInterfaceNumber; 211 212 umodem_get_caps(dev, &sc->sc_cm_cap, &sc->sc_acm_cap); 213 214 /* Get the data interface no. */ 215 cmd = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); 216 if (cmd == NULL) { 217 DPRINTF(("%s: no CM desc\n", USBDEVNAME(sc->sc_dev))); 218 goto bad; 219 } 220 sc->sc_data_iface_no = data_ifaceno = cmd->bDataInterface; 221 222 printf("%s: data interface %d, has %sCM over data, has %sbreak\n", 223 USBDEVNAME(sc->sc_dev), data_ifaceno, 224 sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", 225 sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); 226 227 228 /* Get the data interface too. */ 229 for (i = 0; i < uaa->nifaces; i++) { 230 if (uaa->ifaces[i]) { 231 id = usbd_get_interface_descriptor(uaa->ifaces[i]); 232 if (id->bInterfaceNumber == data_ifaceno) { 233 sc->sc_data_iface = uaa->ifaces[i]; 234 uaa->ifaces[i] = 0; 235 } 236 } 237 } 238 if (sc->sc_data_iface == NULL) { 239 printf("%s: no data interface\n", USBDEVNAME(sc->sc_dev)); 240 goto bad; 241 } 242 243 /* 244 * Find the bulk endpoints. 245 * Iterate over all endpoints in the data interface and take note. 246 */ 247 sc->sc_bulkin_no = sc->sc_bulkout_no = -1; 248 249 id = usbd_get_interface_descriptor(sc->sc_data_iface); 250 for (i = 0; i < id->bNumEndpoints; i++) { 251 ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i); 252 if (ed == NULL) { 253 printf("%s: no endpoint descriptor for %d\n", 254 USBDEVNAME(sc->sc_dev), i); 255 goto bad; 256 } 257 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 258 (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { 259 sc->sc_bulkin_no = ed->bEndpointAddress; 260 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 261 (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { 262 sc->sc_bulkout_no = ed->bEndpointAddress; 263 } 264 } 265 266 if (sc->sc_bulkin_no == -1) { 267 DPRINTF(("%s: Could not find data bulk in\n", 268 USBDEVNAME(sc->sc_dev))); 269 goto bad; 270 } 271 if (sc->sc_bulkout_no == -1) { 272 DPRINTF(("%s: Could not find data bulk out\n", 273 USBDEVNAME(sc->sc_dev))); 274 goto bad; 275 } 276 277 if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) { 278 err = umodem_set_comm_feature(sc, UCDC_ABSTRACT_STATE, 279 UCDC_DATA_MULTIPLEXED); 280 if (err) 281 goto bad; 282 sc->sc_cm_over_data = 1; 283 } 284 285 tp = ttymalloc(); 286 tp->t_oproc = umodemstart; 287 tp->t_param = umodemparam; 288 sc->sc_tty = tp; 289 DPRINTF(("umodem_attach: tty_attach %p\n", tp)); 290 tty_attach(tp); 291 292 sc->sc_dtr = -1; 293 294 USB_ATTACH_SUCCESS_RETURN; 295 296 bad: 297 sc->sc_dying = 1; 298 USB_ATTACH_ERROR_RETURN; 299 } 300 301 void 302 umodem_get_caps(dev, cm, acm) 303 usbd_device_handle dev; 304 int *cm, *acm; 305 { 306 usb_cdc_cm_descriptor_t *cmd; 307 usb_cdc_acm_descriptor_t *cad; 308 309 *cm = *acm = 0; 310 311 cmd = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); 312 if (!cmd) { 313 DPRINTF(("umodem_get_desc: no CM desc\n")); 314 return; 315 } 316 *cm = cmd->bmCapabilities; 317 318 cad = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM); 319 if (!cad) { 320 DPRINTF(("umodem_get_desc: no ACM desc\n")); 321 return; 322 } 323 *acm = cad->bmCapabilities; 324 } 325 326 void 327 umodemstart(tp) 328 struct tty *tp; 329 { 330 struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(tp->t_dev)]; 331 int s; 332 u_char *data; 333 int cnt; 334 335 if (sc->sc_dying) 336 return; 337 338 s = spltty(); 339 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) { 340 DPRINTFN(4,("umodemstart: stopped\n")); 341 goto out; 342 } 343 344 if (tp->t_outq.c_cc <= tp->t_lowat) { 345 if (ISSET(tp->t_state, TS_ASLEEP)) { 346 CLR(tp->t_state, TS_ASLEEP); 347 wakeup(&tp->t_outq); 348 } 349 selwakeup(&tp->t_wsel); 350 if (tp->t_outq.c_cc == 0) 351 goto out; 352 } 353 354 /* Grab the first contiguous region of buffer space. */ 355 data = tp->t_outq.c_cf; 356 cnt = ndqb(&tp->t_outq, 0); 357 358 if (cnt == 0) { 359 DPRINTF(("umodemstart: cnt==0\n")); 360 splx(s); 361 return; 362 } 363 364 SET(tp->t_state, TS_BUSY); 365 366 /* XXX Is it really correct not to transfer all of the buffer? */ 367 if (cnt > UMODEMOBUFSIZE) { 368 DPRINTF(("umodemstart: big buffer %d chars\n", cnt)); 369 cnt = UMODEMOBUFSIZE; 370 } 371 372 memcpy(sc->sc_obuf, data, cnt); 373 374 DPRINTFN(4,("umodemstart: %d chars\n", cnt)); 375 /* XXX what can we do on error? */ 376 usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe, 377 (usbd_private_handle)sc, sc->sc_obuf, cnt, 378 USBD_NO_COPY, USBD_NO_TIMEOUT, umodemwritecb); 379 (void)usbd_transfer(sc->sc_oxfer); 380 381 out: 382 splx(s); 383 } 384 385 void 386 umodemwritecb(xfer, p, status) 387 usbd_xfer_handle xfer; 388 usbd_private_handle p; 389 usbd_status status; 390 { 391 struct umodem_softc *sc = (struct umodem_softc *)p; 392 struct tty *tp = sc->sc_tty; 393 u_int32_t cc; 394 int s; 395 396 DPRINTFN(5,("umodemwritecb: status=%d\n", status)); 397 398 if (status == USBD_CANCELLED) 399 return; 400 401 if (status != USBD_NORMAL_COMPLETION) { 402 DPRINTF(("umodemwritecb: status=%d\n", status)); 403 usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe); 404 /* XXX we should restart after some delay. */ 405 return; 406 } 407 408 usbd_get_xfer_status(xfer, 0, 0, &cc, 0); 409 DPRINTFN(5,("umodemwritecb: cc=%d\n", cc)); 410 411 s = spltty(); 412 CLR(tp->t_state, TS_BUSY); 413 if (ISSET(tp->t_state, TS_FLUSH)) 414 CLR(tp->t_state, TS_FLUSH); 415 else 416 ndflush(&tp->t_outq, cc); 417 (*linesw[tp->t_line].l_start)(tp); 418 splx(s); 419 } 420 421 int 422 umodemparam(tp, t) 423 struct tty *tp; 424 struct termios *t; 425 { 426 struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(tp->t_dev)]; 427 usb_cdc_line_state_t ls; 428 429 if (sc->sc_dying) 430 return (EIO); 431 432 /* Check requested parameters. */ 433 if (t->c_ospeed < 0) 434 return (EINVAL); 435 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 436 return (EINVAL); 437 438 /* 439 * If there were no changes, don't do anything. This avoids dropping 440 * input and improves performance when all we did was frob things like 441 * VMIN and VTIME. 442 */ 443 if (tp->t_ospeed == t->c_ospeed && 444 tp->t_cflag == t->c_cflag) 445 return (0); 446 447 /* And copy to tty. */ 448 tp->t_ispeed = 0; 449 tp->t_ospeed = t->c_ospeed; 450 tp->t_cflag = t->c_cflag; 451 452 USETDW(ls.dwDTERate, t->c_ospeed); 453 if (ISSET(t->c_cflag, CSTOPB)) 454 ls.bCharFormat = UCDC_STOP_BIT_2; 455 else 456 ls.bCharFormat = UCDC_STOP_BIT_1; 457 if (ISSET(t->c_cflag, PARENB)) { 458 if (ISSET(t->c_cflag, PARODD)) 459 ls.bParityType = UCDC_PARITY_ODD; 460 else 461 ls.bParityType = UCDC_PARITY_EVEN; 462 } else 463 ls.bParityType = UCDC_PARITY_NONE; 464 switch (ISSET(t->c_cflag, CSIZE)) { 465 case CS5: 466 ls.bDataBits = 5; 467 break; 468 case CS6: 469 ls.bDataBits = 6; 470 break; 471 case CS7: 472 ls.bDataBits = 7; 473 break; 474 case CS8: 475 ls.bDataBits = 8; 476 break; 477 } 478 /* XXX what can we if it fails? */ 479 (void)umodem_set_line_coding(sc, &ls); 480 481 /* 482 * Update the tty layer's idea of the carrier bit, in case we changed 483 * CLOCAL or MDMBUF. We don't hang up here; we only do that by 484 * explicit request. 485 */ 486 (void) (*linesw[tp->t_line].l_modem)(tp, 1 /* XXX carrier */ ); 487 488 return (0); 489 } 490 491 int 492 umodemopen(dev, flag, mode, p) 493 dev_t dev; 494 int flag, mode; 495 struct proc *p; 496 { 497 int unit = UMODEMUNIT(dev); 498 usbd_status err; 499 struct umodem_softc *sc; 500 struct tty *tp; 501 int s; 502 int error; 503 504 if (unit >= umodem_cd.cd_ndevs) 505 return (ENXIO); 506 sc = umodem_cd.cd_devs[unit]; 507 if (sc == NULL) 508 return (ENXIO); 509 510 if (sc->sc_dying) 511 return (EIO); 512 513 if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0) 514 return (ENXIO); 515 516 tp = sc->sc_tty; 517 518 DPRINTF(("umodemopen: unit=%d, tp=%p\n", unit, tp)); 519 520 if (ISSET(tp->t_state, TS_ISOPEN) && 521 ISSET(tp->t_state, TS_XCLUDE) && 522 p->p_ucred->cr_uid != 0) 523 return (EBUSY); 524 525 /* 526 * Do the following iff this is a first open. 527 */ 528 s = spltty(); 529 while (sc->sc_opening) 530 tsleep(&sc->sc_opening, PRIBIO, "umdmop", 0); 531 sc->sc_opening = 1; 532 533 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 534 struct termios t; 535 536 tp->t_dev = dev; 537 538 /* 539 * Initialize the termios status to the defaults. Add in the 540 * sticky bits from TIOCSFLAGS. 541 */ 542 t.c_ispeed = 0; 543 t.c_ospeed = TTYDEF_SPEED; 544 t.c_cflag = TTYDEF_CFLAG; 545 /* Make sure umodemparam() will do something. */ 546 tp->t_ospeed = 0; 547 (void) umodemparam(tp, &t); 548 tp->t_iflag = TTYDEF_IFLAG; 549 tp->t_oflag = TTYDEF_OFLAG; 550 tp->t_lflag = TTYDEF_LFLAG; 551 ttychars(tp); 552 ttsetwater(tp); 553 554 /* 555 * Turn on DTR. We must always do this, even if carrier is not 556 * present, because otherwise we'd have to use TIOCSDTR 557 * immediately after setting CLOCAL, which applications do not 558 * expect. We always assert DTR while the device is open 559 * unless explicitly requested to deassert it. 560 */ 561 umodem_modem(sc, 1); 562 563 DPRINTF(("umodemopen: open pipes\n")); 564 565 /* Open the bulk pipes */ 566 err = usbd_open_pipe(sc->sc_data_iface, sc->sc_bulkin_no, 0, 567 &sc->sc_bulkin_pipe); 568 if (err) { 569 DPRINTF(("%s: cannot open bulk out pipe (addr %d)\n", 570 USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no)); 571 return (EIO); 572 } 573 err = usbd_open_pipe(sc->sc_data_iface, sc->sc_bulkout_no, 574 USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe); 575 if (err) { 576 DPRINTF(("%s: cannot open bulk in pipe (addr %d)\n", 577 USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no)); 578 usbd_close_pipe(sc->sc_bulkin_pipe); 579 return (EIO); 580 } 581 582 /* Allocate a request and an input buffer and start reading. */ 583 sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev); 584 if (sc->sc_ixfer == NULL) { 585 usbd_close_pipe(sc->sc_bulkin_pipe); 586 usbd_close_pipe(sc->sc_bulkout_pipe); 587 return (ENOMEM); 588 } 589 sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer, UMODEMIBUFSIZE); 590 if (sc->sc_ibuf == NULL) { 591 usbd_free_xfer(sc->sc_ixfer); 592 usbd_close_pipe(sc->sc_bulkin_pipe); 593 usbd_close_pipe(sc->sc_bulkout_pipe); 594 return (ENOMEM); 595 } 596 597 sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev); 598 if (sc->sc_oxfer == NULL) { 599 usbd_free_xfer(sc->sc_ixfer); 600 usbd_close_pipe(sc->sc_bulkin_pipe); 601 usbd_close_pipe(sc->sc_bulkout_pipe); 602 return (ENOMEM); 603 } 604 sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer, UMODEMOBUFSIZE); 605 if (sc->sc_obuf == NULL) { 606 usbd_free_xfer(sc->sc_oxfer); 607 usbd_free_xfer(sc->sc_ixfer); 608 usbd_close_pipe(sc->sc_bulkin_pipe); 609 usbd_close_pipe(sc->sc_bulkout_pipe); 610 return (ENOMEM); 611 } 612 613 (void)umodemstartread(sc); 614 } 615 sc->sc_opening = 0; 616 wakeup(&sc->sc_opening); 617 splx(s); 618 619 error = ttyopen(tp, UMODEMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); 620 if (error) 621 goto bad; 622 623 error = (*linesw[tp->t_line].l_open)(dev, tp); 624 if (error) 625 goto bad; 626 627 return (0); 628 629 bad: 630 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 631 /* 632 * We failed to open the device, and nobody else had it opened. 633 * Clean up the state as appropriate. 634 */ 635 umodem_cleanup(sc); 636 } 637 638 return (error); 639 } 640 641 usbd_status 642 umodemstartread(sc) 643 struct umodem_softc *sc; 644 { 645 usbd_status err; 646 647 DPRINTFN(5,("umodemstartread: start\n")); 648 usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe, 649 (usbd_private_handle)sc, 650 sc->sc_ibuf, UMODEMIBUFSIZE, 651 USBD_SHORT_XFER_OK | USBD_NO_COPY, 652 USBD_NO_TIMEOUT, umodemreadcb); 653 err = usbd_transfer(sc->sc_ixfer); 654 if (err != USBD_IN_PROGRESS) { 655 printf("%s: start read failed, err=%s\n", 656 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 657 return (err); 658 } 659 return (USBD_NORMAL_COMPLETION); 660 } 661 662 void 663 umodemreadcb(xfer, p, status) 664 usbd_xfer_handle xfer; 665 usbd_private_handle p; 666 usbd_status status; 667 { 668 struct umodem_softc *sc = (struct umodem_softc *)p; 669 struct tty *tp = sc->sc_tty; 670 int (*rint) __P((int c, struct tty *tp)) = linesw[tp->t_line].l_rint; 671 u_int32_t cc; 672 u_char *cp; 673 int s; 674 675 if (status == USBD_CANCELLED) 676 return; 677 678 if (status != USBD_NORMAL_COMPLETION) { 679 DPRINTF(("umodemreadcb: status=%d\n", status)); 680 usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe); 681 /* XXX we should restart after some delay. */ 682 return; 683 } 684 685 usbd_get_xfer_status(xfer, 0, (void **)&cp, &cc, 0); 686 DPRINTFN(5,("umodemreadcb: got %d chars, tp=%p\n", cc, tp)); 687 s = spltty(); 688 /* Give characters to tty layer. */ 689 while (cc-- > 0) { 690 DPRINTFN(7,("umodemreadcb: char=0x%02x\n", *cp)); 691 if ((*rint)(*cp++, tp) == -1) { 692 /* XXX what should we do? */ 693 break; 694 } 695 } 696 splx(s); 697 698 (void)umodemstartread(sc); 699 } 700 701 int 702 umodemclose(dev, flag, mode, p) 703 dev_t dev; 704 int flag, mode; 705 struct proc *p; 706 { 707 struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(dev)]; 708 struct tty *tp = sc->sc_tty; 709 710 DPRINTF(("umodemclose: unit=%d\n", UMODEMUNIT(dev))); 711 if (!ISSET(tp->t_state, TS_ISOPEN)) 712 return (0); 713 714 (*linesw[tp->t_line].l_close)(tp, flag); 715 ttyclose(tp); 716 717 if (sc->sc_dying) 718 return (0); 719 720 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 721 /* 722 * Although we got a last close, the device may still be in 723 * use; e.g. if this was the dialout node, and there are still 724 * processes waiting for carrier on the non-dialout node. 725 */ 726 umodem_cleanup(sc); 727 } 728 729 return (0); 730 } 731 732 void 733 umodem_cleanup(sc) 734 struct umodem_softc *sc; 735 { 736 umodem_shutdown(sc); 737 DPRINTF(("umodem_cleanup: closing pipes\n")); 738 usbd_abort_pipe(sc->sc_bulkin_pipe); 739 usbd_close_pipe(sc->sc_bulkin_pipe); 740 usbd_abort_pipe(sc->sc_bulkout_pipe); 741 usbd_close_pipe(sc->sc_bulkout_pipe); 742 usbd_free_xfer(sc->sc_ixfer); 743 usbd_free_xfer(sc->sc_oxfer); 744 } 745 746 int 747 umodemread(dev, uio, flag) 748 dev_t dev; 749 struct uio *uio; 750 int flag; 751 { 752 struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(dev)]; 753 struct tty *tp = sc->sc_tty; 754 755 if (sc->sc_dying) 756 return (EIO); 757 758 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 759 } 760 761 int 762 umodemwrite(dev, uio, flag) 763 dev_t dev; 764 struct uio *uio; 765 int flag; 766 { 767 struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(dev)]; 768 struct tty *tp = sc->sc_tty; 769 770 if (sc->sc_dying) 771 return (EIO); 772 773 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 774 } 775 776 void 777 umodemstop(tp, flag) 778 struct tty *tp; 779 int flag; 780 { 781 /*struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(tp->t_dev)];*/ 782 int s; 783 784 DPRINTF(("umodemstop: %d\n", flag)); 785 s = spltty(); 786 if (ISSET(tp->t_state, TS_BUSY)) { 787 DPRINTF(("umodemstop: XXX\n")); 788 /* XXX do what? */ 789 if (!ISSET(tp->t_state, TS_TTSTOP)) 790 SET(tp->t_state, TS_FLUSH); 791 } 792 splx(s); 793 } 794 795 struct tty * 796 umodemtty(dev) 797 dev_t dev; 798 { 799 struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(dev)]; 800 struct tty *tp = sc->sc_tty; 801 802 return (tp); 803 } 804 805 int 806 umodemioctl(dev, cmd, data, flag, p) 807 dev_t dev; 808 u_long cmd; 809 caddr_t data; 810 int flag; 811 struct proc *p; 812 { 813 struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(dev)]; 814 struct tty *tp = sc->sc_tty; 815 int error; 816 int s; 817 818 if (sc->sc_dying) 819 return (EIO); 820 821 DPRINTF(("umodemioctl: cmd=0x%08lx\n", cmd)); 822 823 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 824 if (error >= 0) 825 return (error); 826 827 error = ttioctl(tp, cmd, data, flag, p); 828 if (error >= 0) 829 return (error); 830 831 error = 0; 832 833 DPRINTF(("umodemioctl: our cmd=0x%08lx\n", cmd)); 834 s = spltty(); 835 836 switch (cmd) { 837 case TIOCSBRK: 838 umodem_break(sc, 1); 839 break; 840 841 case TIOCCBRK: 842 umodem_break(sc, 0); 843 break; 844 845 case TIOCSDTR: 846 umodem_modem(sc, 1); 847 break; 848 849 case TIOCCDTR: 850 umodem_modem(sc, 0); 851 break; 852 853 case USB_GET_CM_OVER_DATA: 854 *(int *)data = sc->sc_cm_over_data; 855 break; 856 857 case USB_SET_CM_OVER_DATA: 858 if (*(int *)data != sc->sc_cm_over_data) { 859 /* XXX change it */ 860 } 861 break; 862 863 default: 864 DPRINTF(("umodemioctl: unknown\n")); 865 error = ENOTTY; 866 break; 867 } 868 869 splx(s); 870 871 return (error); 872 } 873 874 void 875 umodem_shutdown(sc) 876 struct umodem_softc *sc; 877 { 878 struct tty *tp = sc->sc_tty; 879 880 DPRINTF(("umodem_shutdown\n")); 881 /* 882 * Hang up if necessary. Wait a bit, so the other side has time to 883 * notice even if we immediately open the port again. 884 */ 885 if (ISSET(tp->t_cflag, HUPCL)) { 886 umodem_modem(sc, 0); 887 (void) tsleep(sc, TTIPRI, ttclos, hz); 888 } 889 } 890 891 void 892 umodem_modem(sc, onoff) 893 struct umodem_softc *sc; 894 int onoff; 895 { 896 usb_device_request_t req; 897 898 DPRINTF(("umodem_modem: onoff=%d\n", onoff)); 899 900 if (sc->sc_dtr == onoff) 901 return; 902 903 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 904 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 905 USETW(req.wValue, onoff ? UCDC_LINE_DTR : 0); 906 USETW(req.wIndex, sc->sc_ctl_iface_no); 907 USETW(req.wLength, 0); 908 909 (void)usbd_do_request(sc->sc_udev, &req, 0); 910 911 sc->sc_dtr = onoff; 912 } 913 914 void 915 umodem_break(sc, onoff) 916 struct umodem_softc *sc; 917 int onoff; 918 { 919 usb_device_request_t req; 920 921 DPRINTF(("umodem_break: onoff=%d\n", onoff)); 922 923 if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK)) 924 return; 925 926 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 927 req.bRequest = UCDC_SEND_BREAK; 928 USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF); 929 USETW(req.wIndex, sc->sc_ctl_iface_no); 930 USETW(req.wLength, 0); 931 932 (void)usbd_do_request(sc->sc_udev, &req, 0); 933 } 934 935 void * 936 umodem_get_desc(dev, type, subtype) 937 usbd_device_handle dev; 938 int type; 939 int subtype; 940 { 941 usb_descriptor_t *desc; 942 usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev); 943 uByte *p = (uByte *)cd; 944 uByte *end = p + UGETW(cd->wTotalLength); 945 946 while (p < end) { 947 desc = (usb_descriptor_t *)p; 948 if (desc->bDescriptorType == type && 949 desc->bDescriptorSubtype == subtype) 950 return (desc); 951 p += desc->bLength; 952 } 953 954 return (0); 955 } 956 957 usbd_status 958 umodem_set_comm_feature(sc, feature, state) 959 struct umodem_softc *sc; 960 int feature; 961 int state; 962 { 963 usb_device_request_t req; 964 usbd_status err; 965 usb_cdc_abstract_state_t ast; 966 967 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 968 req.bRequest = UCDC_SET_COMM_FEATURE; 969 USETW(req.wValue, feature); 970 USETW(req.wIndex, sc->sc_ctl_iface_no); 971 USETW(req.wLength, UCDC_ABSTRACT_STATE_LENGTH); 972 USETW(ast.wState, state); 973 974 err = usbd_do_request(sc->sc_udev, &req, &ast); 975 if (err) { 976 DPRINTF(("umodem_set_comm_feature: feature=%d failed, r=%d\n", 977 feature, err)); 978 return (err); 979 } 980 981 return (USBD_NORMAL_COMPLETION); 982 } 983 984 usbd_status 985 umodem_set_line_coding(sc, state) 986 struct umodem_softc *sc; 987 usb_cdc_line_state_t *state; 988 { 989 usb_device_request_t req; 990 usbd_status err; 991 992 DPRINTF(("umodem_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n", 993 UGETDW(state->dwDTERate), state->bCharFormat, 994 state->bParityType, state->bDataBits)); 995 996 if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) { 997 DPRINTF(("umodem_set_line_coding: already set\n")); 998 return (USBD_NORMAL_COMPLETION); 999 } 1000 1001 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1002 req.bRequest = UCDC_SET_LINE_CODING; 1003 USETW(req.wValue, 0); 1004 USETW(req.wIndex, sc->sc_ctl_iface_no); 1005 USETW(req.wLength, UCDC_LINE_STATE_LENGTH); 1006 1007 err = usbd_do_request(sc->sc_udev, &req, state); 1008 if (err) { 1009 DPRINTF(("umodem_set_line_coding: failed, err=%d\n", err)); 1010 return (err); 1011 } 1012 1013 sc->sc_line_state = *state; 1014 1015 return (USBD_NORMAL_COMPLETION); 1016 } 1017 1018 int 1019 umodem_activate(self, act) 1020 device_ptr_t self; 1021 enum devact act; 1022 { 1023 struct umodem_softc *sc = (struct umodem_softc *)self; 1024 1025 switch (act) { 1026 case DVACT_ACTIVATE: 1027 return (EOPNOTSUPP); 1028 break; 1029 1030 case DVACT_DEACTIVATE: 1031 sc->sc_dying = 1; 1032 break; 1033 } 1034 return (0); 1035 } 1036 1037 int 1038 umodem_detach(self, flags) 1039 device_ptr_t self; 1040 int flags; 1041 { 1042 struct umodem_softc *sc = (struct umodem_softc *)self; 1043 int maj, mn; 1044 1045 DPRINTF(("umodem_detach: sc=%p flags=%d tp=%p\n", 1046 sc, flags, sc->sc_tty)); 1047 1048 sc->sc_dying = 1; 1049 1050 #ifdef DIAGNOSTIC 1051 if (sc->sc_tty == 0) { 1052 DPRINTF(("umodem_detach: no tty\n")); 1053 return (0); 1054 } 1055 #endif 1056 1057 /* use refernce count? XXX */ 1058 1059 /* locate the major number */ 1060 for (maj = 0; maj < nchrdev; maj++) 1061 if (cdevsw[maj].d_open == umodemopen) 1062 break; 1063 1064 /* Nuke the vnodes for any open instances. */ 1065 mn = self->dv_unit; 1066 vdevgone(maj, mn, mn, VCHR); 1067 vdevgone(maj, mn, mn | UMODEMDIALOUT_MASK, VCHR); 1068 vdevgone(maj, mn, mn | UMODEMCALLUNIT_MASK, VCHR); 1069 1070 /* Detach and free the tty. */ 1071 tty_detach(sc->sc_tty); 1072 ttyfree(sc->sc_tty); 1073 sc->sc_tty = 0; 1074 1075 return (0); 1076 } 1077