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