1/* $NetBSD: uhso.c,v 1.37 2022/10/26 23:53:03 riastradh Exp $ */ 2 3/*- 4 * Copyright (c) 2009 Iain Hibbert 5 * Copyright (c) 2008 Fredrik Lindberg 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * This driver originated as the hso module for FreeBSD written by 31 * Fredrik Lindberg[1]. It has been rewritten almost completely for 32 * NetBSD, and to support more devices with information extracted from 33 * the Linux hso driver provided by Option N.V.[2] 34 * 35 * [1] http://www.shapeshifter.se/code/hso 36 * [2] http://www.pharscape.org/hso.htm 37 */ 38 39#include <sys/cdefs.h> 40__KERNEL_RCSID(0, "$NetBSD: uhso.c,v 1.37 2022/10/26 23:53:03 riastradh Exp $"); 41 42#ifdef _KERNEL_OPT 43#include "opt_inet.h" 44#include "opt_usb.h" 45#endif 46 47#include <sys/param.h> 48#include <sys/conf.h> 49#include <sys/fcntl.h> 50#include <sys/kauth.h> 51#include <sys/kernel.h> 52#include <sys/kmem.h> 53#include <sys/mbuf.h> 54#include <sys/poll.h> 55#include <sys/queue.h> 56#include <sys/socket.h> 57#include <sys/sysctl.h> 58#include <sys/systm.h> 59#include <sys/tty.h> 60#include <sys/vnode.h> 61#include <sys/lwp.h> 62 63#include <net/bpf.h> 64#include <net/if.h> 65#include <net/if_dl.h> 66#include <net/if_types.h> 67 68#include <netinet/in.h> 69#include <netinet/in_systm.h> 70#include <netinet/in_var.h> 71#include <netinet/ip.h> 72 73#include <dev/usb/usb.h> 74#include <dev/usb/usbcdc.h> 75#include <dev/usb/usbdi.h> 76#include <dev/usb/usbdi_util.h> 77#include <dev/usb/umassvar.h> 78 79#include <dev/scsipi/scsi_disk.h> 80 81#include "usbdevs.h" 82#include "ioconf.h" 83 84#undef DPRINTF 85#ifdef UHSO_DEBUG 86/* 87 * defined levels 88 * 0 warnings only 89 * 1 informational 90 * 5 really chatty 91 */ 92int uhso_debug = 0; 93 94#define DPRINTF(n, ...) do { \ 95 if (uhso_debug >= (n)) { \ 96 printf("%s: ", __func__); \ 97 printf(__VA_ARGS__); \ 98 } \ 99} while (/* CONSTCOND */0) 100#else 101#define DPRINTF(...) ((void)0) 102#endif 103 104/* 105 * When first attached, the device class will be 0 and the modem 106 * will attach as UMASS until a SCSI REZERO_UNIT command is sent, 107 * in which case it will detach and reattach with device class set 108 * to UDCLASS_VENDOR (0xff) and provide the serial interfaces. 109 * 110 * If autoswitch is set (the default) this will happen automatically. 111 */ 112Static int uhso_autoswitch = 1; 113 114SYSCTL_SETUP(sysctl_hw_uhso_setup, "uhso sysctl setup") 115{ 116 const struct sysctlnode *node = NULL; 117 118 sysctl_createv(clog, 0, NULL, &node, 119 CTLFLAG_PERMANENT, 120 CTLTYPE_NODE, "uhso", 121 NULL, 122 NULL, 0, 123 NULL, 0, 124 CTL_HW, CTL_CREATE, CTL_EOL); 125 126 if (node == NULL) 127 return; 128 129#ifdef UHSO_DEBUG 130 sysctl_createv(clog, 0, &node, NULL, 131 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 132 CTLTYPE_INT, "debug", 133 SYSCTL_DESCR("uhso debug level (0, 1, 5)"), 134 NULL, 0, 135 &uhso_debug, sizeof(uhso_debug), 136 CTL_CREATE, CTL_EOL); 137#endif 138 139 sysctl_createv(clog, 0, &node, NULL, 140 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 141 CTLTYPE_INT, "autoswitch", 142 SYSCTL_DESCR("automatically switch device into modem mode"), 143 NULL, 0, 144 &uhso_autoswitch, sizeof(uhso_autoswitch), 145 CTL_CREATE, CTL_EOL); 146} 147 148/* 149 * The uhso modems have a number of interfaces providing a variety of 150 * IO ports using the bulk endpoints, or multiplexed on the control 151 * endpoints. We separate the ports by function and provide each with 152 * a predictable index number used to construct the device minor number. 153 * 154 * The Network port is configured as a network interface rather than 155 * a tty as it provides raw IPv4 packets. 156 */ 157 158Static const char *uhso_port_name[] = { 159 "Control", 160 "Diagnostic", 161 "Diagnostic2", 162 "Application", 163 "Application2", 164 "GPS", 165 "GPS Control", 166 "PC Smartcard", 167 "Modem", 168 "MSD", /* "Modem Sharing Device" ? */ 169 "Voice", 170 "Network", 171}; 172 173#define UHSO_PORT_CONTROL 0x00 174#define UHSO_PORT_DIAG 0x01 175#define UHSO_PORT_DIAG2 0x02 176#define UHSO_PORT_APP 0x03 177#define UHSO_PORT_APP2 0x04 178#define UHSO_PORT_GPS 0x05 179#define UHSO_PORT_GPS_CONTROL 0x06 180#define UHSO_PORT_PCSC 0x07 181#define UHSO_PORT_MODEM 0x08 182#define UHSO_PORT_MSD 0x09 183#define UHSO_PORT_VOICE 0x0a 184#define UHSO_PORT_NETWORK 0x0b 185 186#define UHSO_PORT_MAX __arraycount(uhso_port_name) 187 188#define UHSO_IFACE_MUX 0x20 189#define UHSO_IFACE_BULK 0x40 190#define UHSO_IFACE_IFNET 0x80 191 192/* 193 * The interface specification can sometimes be deduced from the device 194 * type and interface number, or some modems support a vendor specific 195 * way to read config info which we can translate to the port index. 196 */ 197Static const uint8_t uhso_spec_default[] = { 198 UHSO_IFACE_IFNET | UHSO_PORT_NETWORK | UHSO_IFACE_MUX, 199 UHSO_IFACE_BULK | UHSO_PORT_DIAG, 200 UHSO_IFACE_BULK | UHSO_PORT_MODEM, 201}; 202 203Static const uint8_t uhso_spec_icon321[] = { 204 UHSO_IFACE_IFNET | UHSO_PORT_NETWORK | UHSO_IFACE_MUX, 205 UHSO_IFACE_BULK | UHSO_PORT_DIAG2, 206 UHSO_IFACE_BULK | UHSO_PORT_MODEM, 207 UHSO_IFACE_BULK | UHSO_PORT_DIAG, 208}; 209 210Static const uint8_t uhso_spec_config[] = { 211 0, 212 UHSO_IFACE_BULK | UHSO_PORT_DIAG, 213 UHSO_IFACE_BULK | UHSO_PORT_GPS, 214 UHSO_IFACE_BULK | UHSO_PORT_GPS_CONTROL, 215 UHSO_IFACE_BULK | UHSO_PORT_APP, 216 UHSO_IFACE_BULK | UHSO_PORT_APP2, 217 UHSO_IFACE_BULK | UHSO_PORT_CONTROL, 218 UHSO_IFACE_IFNET | UHSO_PORT_NETWORK, 219 UHSO_IFACE_BULK | UHSO_PORT_MODEM, 220 UHSO_IFACE_BULK | UHSO_PORT_MSD, 221 UHSO_IFACE_BULK | UHSO_PORT_PCSC, 222 UHSO_IFACE_BULK | UHSO_PORT_VOICE, 223}; 224 225struct uhso_dev { 226 uint16_t vendor; 227 uint16_t product; 228 uint16_t type; 229}; 230 231#define UHSOTYPE_DEFAULT 1 232#define UHSOTYPE_ICON321 2 233#define UHSOTYPE_CONFIG 3 234 235Static const struct uhso_dev uhso_devs[] = { 236 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GSICON72, UHSOTYPE_DEFAULT }, 237 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_ICON225, UHSOTYPE_DEFAULT }, 238 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GEHSUPA, UHSOTYPE_DEFAULT }, 239 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GTHSUPA, UHSOTYPE_DEFAULT }, 240 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GSHSUPA, UHSOTYPE_DEFAULT }, 241 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GE40X1, UHSOTYPE_CONFIG }, 242 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GE40X2, UHSOTYPE_CONFIG }, 243 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GE40X3, UHSOTYPE_CONFIG }, 244 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_ICON401, UHSOTYPE_CONFIG }, 245 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GTM382, UHSOTYPE_CONFIG }, 246 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GE40X4, UHSOTYPE_CONFIG }, 247 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GTHSUPAM, UHSOTYPE_CONFIG }, 248 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_ICONEDGE, UHSOTYPE_DEFAULT }, 249 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_MODHSXPA, UHSOTYPE_ICON321 }, 250 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_ICON321, UHSOTYPE_ICON321 }, 251 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_ICON322, UHSOTYPE_ICON321 }, 252 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_ICON505, UHSOTYPE_CONFIG }, 253}; 254 255#define uhso_lookup(p, v) ((const struct uhso_dev *)usb_lookup(uhso_devs, (p), (v))) 256 257/* IO buffer sizes */ 258#define UHSO_MUX_WSIZE 64 259#define UHSO_MUX_RSIZE 1024 260#define UHSO_BULK_WSIZE 8192 261#define UHSO_BULK_RSIZE 4096 262#define UHSO_IFNET_MTU 1500 263 264/* 265 * Each IO port provided by the modem can be mapped to a network 266 * interface (when hp_ifp != NULL) or a tty (when hp_tp != NULL) 267 * which may be multiplexed and sharing interrupt and control endpoints 268 * from an interface, or using the dedicated bulk endpoints. 269 */ 270 271struct uhso_port; 272struct uhso_softc; 273 274/* uhso callback functions return errno on failure */ 275typedef int (*uhso_callback)(struct uhso_port *); 276 277struct uhso_port { 278 struct uhso_softc *hp_sc; /* master softc */ 279 struct tty *hp_tp; /* tty pointer */ 280 struct ifnet *hp_ifp; /* ifnet pointer */ 281 unsigned int hp_flags; /* see below */ 282 int hp_swflags; /* persistent tty flags */ 283 int hp_status; /* modem status */ 284 285 /* port type specific handlers */ 286 uhso_callback hp_abort; /* abort any transfers */ 287 uhso_callback hp_detach; /* detach port completely */ 288 uhso_callback hp_init; /* init port (first open) */ 289 uhso_callback hp_clean; /* clean port (last close) */ 290 uhso_callback hp_write; /* write data */ 291 usbd_callback hp_write_cb; /* write callback */ 292 uhso_callback hp_read; /* read data */ 293 usbd_callback hp_read_cb; /* read callback */ 294 uhso_callback hp_control; /* set control lines */ 295 296 struct usbd_interface *hp_ifh; /* interface handle */ 297 unsigned int hp_index; /* usb request index */ 298 299 int hp_iaddr; /* interrupt endpoint */ 300 struct usbd_pipe *hp_ipipe; /* interrupt pipe */ 301 void *hp_ibuf; /* interrupt buffer */ 302 size_t hp_isize; /* allocated size */ 303 304 int hp_raddr; /* bulk in endpoint */ 305 struct usbd_pipe *hp_rpipe; /* bulk in pipe */ 306 struct usbd_xfer *hp_rxfer; /* input xfer */ 307 void *hp_rbuf; /* input buffer */ 308 size_t hp_rlen; /* fill length */ 309 size_t hp_rsize; /* allocated size */ 310 311 int hp_waddr; /* bulk out endpoint */ 312 struct usbd_pipe *hp_wpipe; /* bulk out pipe */ 313 struct usbd_xfer *hp_wxfer; /* output xfer */ 314 void *hp_wbuf; /* output buffer */ 315 size_t hp_wlen; /* fill length */ 316 size_t hp_wsize; /* allocated size */ 317 318 struct mbuf *hp_mbuf; /* partial packet */ 319}; 320 321/* hp_flags */ 322#define UHSO_PORT_MUXPIPE __BIT(0) /* duplicate ipipe/ibuf references */ 323#define UHSO_PORT_MUXREADY __BIT(1) /* input is ready */ 324#define UHSO_PORT_MUXBUSY __BIT(2) /* read in progress */ 325 326struct uhso_softc { 327 device_t sc_dev; /* self */ 328 struct usbd_device *sc_udev; 329 int sc_refcnt; 330 struct uhso_port *sc_port[UHSO_PORT_MAX]; 331}; 332 333#define UHSO_CONFIG_NO 1 334 335static int uhso_match(device_t, cfdata_t, void *); 336static void uhso_attach(device_t, device_t, void *); 337static int uhso_detach(device_t, int); 338 339 340 341CFATTACH_DECL_NEW(uhso, sizeof(struct uhso_softc), uhso_match, uhso_attach, 342 uhso_detach, NULL); 343 344Static int uhso_switch_mode(struct usbd_device *); 345Static int uhso_get_iface_spec(struct usb_attach_arg *, uint8_t, uint8_t *); 346Static usb_endpoint_descriptor_t *uhso_get_endpoint(struct usbd_interface *, 347 int, int); 348 349Static void uhso_mux_attach(struct uhso_softc *, struct usbd_interface *, int); 350Static int uhso_mux_abort(struct uhso_port *); 351Static int uhso_mux_detach(struct uhso_port *); 352Static int uhso_mux_init(struct uhso_port *); 353Static int uhso_mux_clean(struct uhso_port *); 354Static int uhso_mux_write(struct uhso_port *); 355Static int uhso_mux_read(struct uhso_port *); 356Static int uhso_mux_control(struct uhso_port *); 357Static void uhso_mux_intr(struct usbd_xfer *, void *, usbd_status); 358 359Static void uhso_bulk_attach(struct uhso_softc *, struct usbd_interface *, int); 360Static int uhso_bulk_abort(struct uhso_port *); 361Static int uhso_bulk_detach(struct uhso_port *); 362Static int uhso_bulk_init(struct uhso_port *); 363Static int uhso_bulk_clean(struct uhso_port *); 364Static int uhso_bulk_write(struct uhso_port *); 365Static int uhso_bulk_read(struct uhso_port *); 366Static int uhso_bulk_control(struct uhso_port *); 367Static void uhso_bulk_intr(struct usbd_xfer *, void *, usbd_status); 368 369Static void uhso_tty_attach(struct uhso_port *); 370Static void uhso_tty_detach(struct uhso_port *); 371Static void uhso_tty_read_cb(struct usbd_xfer *, void *, usbd_status); 372Static void uhso_tty_write_cb(struct usbd_xfer *, void *, usbd_status); 373 374static dev_type_open(uhso_tty_open); 375static dev_type_close(uhso_tty_close); 376static dev_type_read(uhso_tty_read); 377static dev_type_write(uhso_tty_write); 378static dev_type_ioctl(uhso_tty_ioctl); 379static dev_type_stop(uhso_tty_stop); 380static dev_type_tty(uhso_tty_tty); 381static dev_type_poll(uhso_tty_poll); 382 383const struct cdevsw uhso_cdevsw = { 384 .d_open = uhso_tty_open, 385 .d_close = uhso_tty_close, 386 .d_read = uhso_tty_read, 387 .d_write = uhso_tty_write, 388 .d_ioctl = uhso_tty_ioctl, 389 .d_stop = uhso_tty_stop, 390 .d_tty = uhso_tty_tty, 391 .d_poll = uhso_tty_poll, 392 .d_mmap = nommap, 393 .d_kqfilter = ttykqfilter, 394 .d_discard = nodiscard, 395 .d_flag = D_TTY 396}; 397 398Static int uhso_tty_init(struct uhso_port *); 399Static void uhso_tty_clean(struct uhso_port *); 400Static int uhso_tty_do_ioctl(struct uhso_port *, u_long, void *, int, struct lwp *); 401Static void uhso_tty_start(struct tty *); 402Static int uhso_tty_param(struct tty *, struct termios *); 403Static int uhso_tty_control(struct uhso_port *, u_long, int); 404 405#define UHSO_UNIT_MASK TTUNIT_MASK 406#define UHSO_PORT_MASK 0x0000f 407#define UHSO_DIALOUT_MASK TTDIALOUT_MASK 408#define UHSO_CALLUNIT_MASK TTCALLUNIT_MASK 409 410#define UHSOUNIT(x) (TTUNIT(x) >> 4) 411#define UHSOPORT(x) (TTUNIT(x) & UHSO_PORT_MASK) 412#define UHSODIALOUT(x) TTDIALOUT(x) 413#define UHSOMINOR(u, p) ((((u) << 4) & UHSO_UNIT_MASK) | ((p) & UHSO_UNIT_MASK)) 414 415Static void uhso_ifnet_attach(struct uhso_softc *, struct usbd_interface *, 416 int); 417Static int uhso_ifnet_abort(struct uhso_port *); 418Static int uhso_ifnet_detach(struct uhso_port *); 419Static void uhso_ifnet_read_cb(struct usbd_xfer *, void *, usbd_status); 420Static void uhso_ifnet_input(struct ifnet *, struct mbuf **, uint8_t *, size_t); 421Static void uhso_ifnet_write_cb(struct usbd_xfer *, void *, usbd_status); 422 423Static int uhso_ifnet_ioctl(struct ifnet *, u_long, void *); 424Static int uhso_ifnet_init(struct uhso_port *); 425Static void uhso_ifnet_clean(struct uhso_port *); 426Static void uhso_ifnet_start(struct ifnet *); 427Static int uhso_ifnet_output(struct ifnet *, struct mbuf *, 428 const struct sockaddr *, const struct rtentry *); 429 430 431/******************************************************************************* 432 * 433 * USB autoconfig 434 * 435 */ 436 437static int 438uhso_match(device_t parent, cfdata_t match, void *aux) 439{ 440 struct usb_attach_arg *uaa = aux; 441 442 /* 443 * don't claim this device if autoswitch is disabled 444 * and it is not in modem mode already 445 */ 446 if (!uhso_autoswitch && uaa->uaa_class != UDCLASS_VENDOR) 447 return UMATCH_NONE; 448 449 if (uhso_lookup(uaa->uaa_vendor, uaa->uaa_product)) 450 return UMATCH_VENDOR_PRODUCT; 451 452 return UMATCH_NONE; 453} 454 455static void 456uhso_attach(device_t parent, device_t self, void *aux) 457{ 458 struct uhso_softc *sc = device_private(self); 459 struct usb_attach_arg *uaa = aux; 460 struct usbd_interface *ifh; 461 char *devinfop; 462 uint8_t count, i, spec; 463 usbd_status status; 464 465 DPRINTF(1, ": sc = %p, self=%p", sc, self); 466 467 sc->sc_dev = self; 468 sc->sc_udev = uaa->uaa_device; 469 470 aprint_naive("\n"); 471 aprint_normal("\n"); 472 473 devinfop = usbd_devinfo_alloc(uaa->uaa_device, 0); 474 aprint_normal_dev(self, "%s\n", devinfop); 475 usbd_devinfo_free(devinfop); 476 477 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); 478 479 status = usbd_set_config_no(sc->sc_udev, UHSO_CONFIG_NO, 1); 480 if (status != USBD_NORMAL_COMPLETION) { 481 aprint_error_dev(self, "failed to set configuration" 482 ", err=%s\n", usbd_errstr(status)); 483 return; 484 } 485 486 if (uaa->uaa_class != UDCLASS_VENDOR) { 487 aprint_verbose_dev(self, 488 "Switching device into modem mode..\n"); 489 if (uhso_switch_mode(uaa->uaa_device) != 0) 490 aprint_error_dev(self, "modem switch failed\n"); 491 492 return; 493 } 494 495 count = 0; 496 (void)usbd_interface_count(sc->sc_udev, &count); 497 DPRINTF(1, "interface count %d\n", count); 498 499 for (i = 0; i < count; i++) { 500 status = usbd_device2interface_handle(sc->sc_udev, i, &ifh); 501 if (status != USBD_NORMAL_COMPLETION) { 502 aprint_error_dev(self, 503 "could not get interface %d: %s\n", 504 i, usbd_errstr(status)); 505 506 return; 507 } 508 509 if (!uhso_get_iface_spec(uaa, i, &spec)) { 510 aprint_error_dev(self, 511 "could not get interface %d specification\n", i); 512 513 return; 514 } 515 516 if (ISSET(spec, UHSO_IFACE_MUX)) 517 uhso_mux_attach(sc, ifh, UHSOPORT(spec)); 518 519 if (ISSET(spec, UHSO_IFACE_BULK)) 520 uhso_bulk_attach(sc, ifh, UHSOPORT(spec)); 521 522 if (ISSET(spec, UHSO_IFACE_IFNET)) 523 uhso_ifnet_attach(sc, ifh, UHSOPORT(spec)); 524 } 525 526 if (!pmf_device_register(self, NULL, NULL)) 527 aprint_error_dev(self, "couldn't establish power handler\n"); 528} 529 530static int 531uhso_detach(device_t self, int flags) 532{ 533 struct uhso_softc *sc = device_private(self); 534 struct uhso_port *hp; 535 devmajor_t major; 536 devminor_t minor; 537 unsigned int i; 538 int s; 539 540 pmf_device_deregister(self); 541 542 for (i = 0; i < UHSO_PORT_MAX; i++) { 543 hp = sc->sc_port[i]; 544 if (hp != NULL) 545 (*hp->hp_abort)(hp); 546 } 547 548 s = splusb(); 549 if (sc->sc_refcnt-- > 0) { 550 DPRINTF(1, "waiting for refcnt (%d)..\n", sc->sc_refcnt); 551 usb_detach_waitold(sc->sc_dev); 552 } 553 splx(s); 554 555 /* 556 * XXX the tty close routine increases/decreases refcnt causing 557 * XXX another usb_detach_wakeupold() does it matter, should these 558 * XXX be before the detach_wait? or before the abort? 559 */ 560 561 /* Nuke the vnodes for any open instances (calls close). */ 562 major = cdevsw_lookup_major(&uhso_cdevsw); 563 minor = UHSOMINOR(device_unit(sc->sc_dev), 0); 564 vdevgone(major, minor, minor + UHSO_PORT_MAX, VCHR); 565 minor = UHSOMINOR(device_unit(sc->sc_dev), 0) | UHSO_DIALOUT_MASK; 566 vdevgone(major, minor, minor + UHSO_PORT_MAX, VCHR); 567 minor = UHSOMINOR(device_unit(sc->sc_dev), 0) | UHSO_CALLUNIT_MASK; 568 vdevgone(major, minor, minor + UHSO_PORT_MAX, VCHR); 569 570 for (i = 0; i < UHSO_PORT_MAX; i++) { 571 hp = sc->sc_port[i]; 572 if (hp != NULL) 573 (*hp->hp_detach)(hp); 574 } 575 576 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); 577 578 return 0; 579} 580 581/* 582 * Send SCSI REZERO_UNIT command to switch device into modem mode 583 */ 584Static int 585uhso_switch_mode(struct usbd_device *udev) 586{ 587 umass_bbb_cbw_t cmd; 588 usb_endpoint_descriptor_t *ed; 589 struct usbd_interface *ifh; 590 struct usbd_pipe *pipe; 591 struct usbd_xfer *xfer; 592 usbd_status status; 593 594 status = usbd_device2interface_handle(udev, 0, &ifh); 595 if (status != USBD_NORMAL_COMPLETION) 596 return EIO; 597 598 ed = uhso_get_endpoint(ifh, UE_BULK, UE_DIR_OUT); 599 if (ed == NULL) 600 return ENODEV; 601 602 status = usbd_open_pipe(ifh, ed->bEndpointAddress, 0, &pipe); 603 if (status != USBD_NORMAL_COMPLETION) 604 return EIO; 605 606 int error = usbd_create_xfer(pipe, sizeof(cmd), 0, 0, &xfer); 607 if (error) 608 return error; 609 610 USETDW(cmd.dCBWSignature, CBWSIGNATURE); 611 USETDW(cmd.dCBWTag, 1); 612 USETDW(cmd.dCBWDataTransferLength, 0); 613 cmd.bCBWFlags = CBWFLAGS_OUT; 614 cmd.bCBWLUN = 0; 615 cmd.bCDBLength = 6; 616 617 memset(&cmd.CBWCDB, 0, CBWCDBLENGTH); 618 cmd.CBWCDB[0] = SCSI_REZERO_UNIT; 619 620 usbd_setup_xfer(xfer, NULL, &cmd, sizeof(cmd), 621 USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL); 622 623 status = usbd_transfer(xfer); 624 625 usbd_destroy_xfer(xfer); 626 usbd_close_pipe(pipe); 627 628 return status == USBD_NORMAL_COMPLETION ? 0 : EIO; 629} 630 631Static int 632uhso_get_iface_spec(struct usb_attach_arg *uaa, uint8_t ifnum, uint8_t *spec) 633{ 634 const struct uhso_dev *hd; 635 uint8_t config[17]; 636 usb_device_request_t req; 637 usbd_status status; 638 639 hd = uhso_lookup(uaa->uaa_vendor, uaa->uaa_product); 640 KASSERT(hd != NULL); 641 642 switch (hd->type) { 643 case UHSOTYPE_DEFAULT: 644 if (ifnum >= __arraycount(uhso_spec_default)) 645 break; 646 647 *spec = uhso_spec_default[ifnum]; 648 return 1; 649 650 case UHSOTYPE_ICON321: 651 if (ifnum >= __arraycount(uhso_spec_icon321)) 652 break; 653 654 *spec = uhso_spec_icon321[ifnum]; 655 return 1; 656 657 case UHSOTYPE_CONFIG: 658 req.bmRequestType = UT_READ_VENDOR_DEVICE; 659 req.bRequest = 0x86; /* "Config Info" */ 660 USETW(req.wValue, 0); 661 USETW(req.wIndex, 0); 662 USETW(req.wLength, sizeof(config)); 663 664 status = usbd_do_request(uaa->uaa_device, &req, config); 665 if (status != USBD_NORMAL_COMPLETION) 666 break; 667 668 if (ifnum >= __arraycount(config) 669 || config[ifnum] >= __arraycount(uhso_spec_config)) 670 break; 671 672 *spec = uhso_spec_config[config[ifnum]]; 673 674 /* 675 * Apparently some modems also have a CRC bug that is 676 * indicated by ISSET(config[16], __BIT(0)) but we dont 677 * handle it at this time. 678 */ 679 return 1; 680 681 default: 682 DPRINTF(0, "unknown interface type\n"); 683 break; 684 } 685 686 return 0; 687} 688 689Static usb_endpoint_descriptor_t * 690uhso_get_endpoint(struct usbd_interface *ifh, int type, int dir) 691{ 692 usb_endpoint_descriptor_t *ed; 693 uint8_t count, i; 694 695 count = 0; 696 (void)usbd_endpoint_count(ifh, &count); 697 698 for (i = 0; i < count; i++) { 699 ed = usbd_interface2endpoint_descriptor(ifh, i); 700 if (ed != NULL 701 && UE_GET_XFERTYPE(ed->bmAttributes) == type 702 && UE_GET_DIR(ed->bEndpointAddress) == dir) 703 return ed; 704 } 705 706 return NULL; 707} 708 709 710/****************************************************************************** 711 * 712 * Multiplexed ports signal with the interrupt endpoint to indicate 713 * when data is available for reading, and a separate request is made on 714 * the control endpoint to read or write on each port. The offsets in the 715 * table below relate to bit numbers in the mux mask, identifying each port. 716 */ 717 718Static const int uhso_mux_port[] = { 719 UHSO_PORT_CONTROL, 720 UHSO_PORT_APP, 721 UHSO_PORT_PCSC, 722 UHSO_PORT_GPS, 723 UHSO_PORT_APP2, 724}; 725 726Static void 727uhso_mux_attach(struct uhso_softc *sc, struct usbd_interface *ifh, int index) 728{ 729 usbd_desc_iter_t iter; 730 const usb_descriptor_t *desc; 731 usb_endpoint_descriptor_t *ed; 732 struct usbd_pipe *pipe; 733 struct uhso_port *hp; 734 uint8_t *buf; 735 size_t size; 736 unsigned int i, mux, flags; 737 int addr; 738 usbd_status status; 739 740 ed = uhso_get_endpoint(ifh, UE_INTERRUPT, UE_DIR_IN); 741 if (ed == NULL) { 742 aprint_error_dev(sc->sc_dev, "no interrupt endpoint\n"); 743 return; 744 } 745 addr = ed->bEndpointAddress; 746 size = UGETW(ed->wMaxPacketSize); 747 748 /* 749 * There should be an additional "Class Specific" descriptor on 750 * the mux interface containing a single byte with a bitmask of 751 * enabled ports. We need to look through the device descriptor 752 * to find it and the port index is found from the uhso_mux_port 753 * array, above. 754 */ 755 usb_desc_iter_init(sc->sc_udev, &iter); 756 757 /* skip past the current interface descriptor */ 758 iter.cur = (const uByte *)usbd_get_interface_descriptor(ifh); 759 desc = usb_desc_iter_next(&iter); 760 761 for (;;) { 762 desc = usb_desc_iter_next(&iter); 763 if (desc == NULL 764 || desc->bDescriptorType == UDESC_INTERFACE) { 765 mux = 0; 766 break; /* not found */ 767 } 768 769 if (desc->bDescriptorType == UDESC_CS_INTERFACE 770 && desc->bLength == 3) { 771 mux = ((const uint8_t *)desc)[2]; 772 break; 773 } 774 } 775 776 DPRINTF(1, "addr=%d, size=%zd, mux=0x%02x\n", addr, size, mux); 777 778 buf = kmem_alloc(size, KM_SLEEP); 779 status = usbd_open_pipe_intr(ifh, addr, USBD_SHORT_XFER_OK, &pipe, 780 sc, buf, size, uhso_mux_intr, USBD_DEFAULT_INTERVAL); 781 782 if (status != USBD_NORMAL_COMPLETION) { 783 aprint_error_dev(sc->sc_dev, 784 "failed to open interrupt pipe: %s", usbd_errstr(status)); 785 786 kmem_free(buf, size); 787 return; 788 } 789 790 flags = 0; 791 for (i = 0; i < __arraycount(uhso_mux_port); i++) { 792 if (ISSET(mux, __BIT(i))) { 793 if (sc->sc_port[uhso_mux_port[i]] != NULL) { 794 aprint_error_dev(sc->sc_dev, 795 "mux port %d is duplicate!\n", i); 796 797 continue; 798 } 799 800 hp = kmem_zalloc(sizeof(struct uhso_port), KM_SLEEP); 801 sc->sc_port[uhso_mux_port[i]] = hp; 802 803 hp->hp_sc = sc; 804 hp->hp_index = i; 805 hp->hp_ipipe = pipe; 806 hp->hp_ibuf = buf; 807 hp->hp_isize = size; 808 hp->hp_flags = flags; 809 hp->hp_abort = uhso_mux_abort; 810 hp->hp_detach = uhso_mux_detach; 811 hp->hp_init = uhso_mux_init; 812 hp->hp_clean = uhso_mux_clean; 813 hp->hp_write = uhso_mux_write; 814 hp->hp_write_cb = uhso_tty_write_cb; 815 hp->hp_read = uhso_mux_read; 816 hp->hp_read_cb = uhso_tty_read_cb; 817 hp->hp_control = uhso_mux_control; 818 hp->hp_wsize = UHSO_MUX_WSIZE; 819 hp->hp_rsize = UHSO_MUX_RSIZE; 820 821 uhso_tty_attach(hp); 822 823 aprint_normal_dev(sc->sc_dev, 824 "%s (port %d) attached as mux tty\n", 825 uhso_port_name[uhso_mux_port[i]], uhso_mux_port[i]); 826 827 /* 828 * As the pipe handle is stored in each mux, mark 829 * secondary references so they don't get released 830 */ 831 flags = UHSO_PORT_MUXPIPE; 832 } 833 } 834 835 if (flags == 0) { 836 /* for whatever reasons, nothing was attached */ 837 usbd_abort_pipe(pipe); 838 usbd_close_pipe(pipe); 839 kmem_free(buf, size); 840 } 841} 842 843Static int 844uhso_mux_abort(struct uhso_port *hp) 845{ 846 struct uhso_softc *sc = hp->hp_sc; 847 848 DPRINTF(1, "hp=%p\n", hp); 849 850 if (!ISSET(hp->hp_flags, UHSO_PORT_MUXPIPE)) 851 usbd_abort_pipe(hp->hp_ipipe); 852 853 usbd_abort_default_pipe(sc->sc_udev); 854 855 return (*hp->hp_clean)(hp); 856} 857 858Static int 859uhso_mux_detach(struct uhso_port *hp) 860{ 861 862 DPRINTF(1, "hp=%p\n", hp); 863 864 if (!ISSET(hp->hp_flags, UHSO_PORT_MUXPIPE)) { 865 DPRINTF(1, "interrupt pipe closed\n"); 866 usbd_abort_pipe(hp->hp_ipipe); 867 usbd_close_pipe(hp->hp_ipipe); 868 kmem_free(hp->hp_ibuf, hp->hp_isize); 869 } 870 871 uhso_tty_detach(hp); 872 kmem_free(hp, sizeof(struct uhso_port)); 873 return 0; 874} 875 876Static int 877uhso_mux_init(struct uhso_port *hp) 878{ 879 880 DPRINTF(1, "hp=%p\n", hp); 881 882 CLR(hp->hp_flags, UHSO_PORT_MUXBUSY | UHSO_PORT_MUXREADY); 883 SET(hp->hp_status, TIOCM_DSR | TIOCM_CAR); 884 885 struct uhso_softc *sc = hp->hp_sc; 886 struct usbd_pipe *pipe0 = usbd_get_pipe0(sc->sc_udev); 887 int error; 888 889 error = usbd_create_xfer(pipe0, hp->hp_rsize, 0, 0, &hp->hp_rxfer); 890 if (error) 891 return error; 892 893 hp->hp_rbuf = usbd_get_buffer(hp->hp_rxfer); 894 895 error = usbd_create_xfer(pipe0, hp->hp_wsize, 0, 0, &hp->hp_wxfer); 896 if (error) 897 return error; 898 899 hp->hp_wbuf = usbd_get_buffer(hp->hp_wxfer); 900 901 return 0; 902} 903 904Static int 905uhso_mux_clean(struct uhso_port *hp) 906{ 907 908 DPRINTF(1, "hp=%p\n", hp); 909 910 CLR(hp->hp_flags, UHSO_PORT_MUXREADY); 911 CLR(hp->hp_status, TIOCM_DTR | TIOCM_DSR | TIOCM_CAR); 912 return 0; 913} 914 915Static int 916uhso_mux_write(struct uhso_port *hp) 917{ 918 struct uhso_softc *sc = hp->hp_sc; 919 usb_device_request_t req; 920 usbd_status status; 921 922 DPRINTF(5, "hp=%p, index=%d, wlen=%zd\n", hp, hp->hp_index, 923 hp->hp_wlen); 924 925 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 926 req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND; 927 USETW(req.wValue, 0); 928 USETW(req.wIndex, hp->hp_index); 929 USETW(req.wLength, hp->hp_wlen); 930 931 usbd_setup_default_xfer(hp->hp_wxfer, sc->sc_udev, hp, USBD_NO_TIMEOUT, 932 &req, hp->hp_wbuf, hp->hp_wlen, 0, hp->hp_write_cb); 933 934 status = usbd_transfer(hp->hp_wxfer); 935 if (status != USBD_IN_PROGRESS) { 936 DPRINTF(0, "non-normal status %s\n", usbd_errstr(status)); 937 return EIO; 938 } 939 940 sc->sc_refcnt++; 941 return 0; 942} 943 944Static int 945uhso_mux_read(struct uhso_port *hp) 946{ 947 struct uhso_softc *sc = hp->hp_sc; 948 usb_device_request_t req; 949 usbd_status status; 950 951 CLR(hp->hp_flags, UHSO_PORT_MUXBUSY); 952 953 if (hp->hp_rlen == 0 && !ISSET(hp->hp_flags, UHSO_PORT_MUXREADY)) 954 return 0; 955 956 SET(hp->hp_flags, UHSO_PORT_MUXBUSY); 957 CLR(hp->hp_flags, UHSO_PORT_MUXREADY); 958 959 DPRINTF(5, "hp=%p, index=%d\n", hp, hp->hp_index); 960 961 req.bmRequestType = UT_READ_CLASS_INTERFACE; 962 req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE; 963 USETW(req.wValue, 0); 964 USETW(req.wIndex, hp->hp_index); 965 USETW(req.wLength, hp->hp_rsize); 966 967 usbd_setup_default_xfer(hp->hp_rxfer, sc->sc_udev, hp, USBD_NO_TIMEOUT, 968 &req, hp->hp_rbuf, hp->hp_rsize, USBD_SHORT_XFER_OK, 969 hp->hp_read_cb); 970 971 status = usbd_transfer(hp->hp_rxfer); 972 if (status != USBD_IN_PROGRESS) { 973 DPRINTF(0, "non-normal status %s\n", usbd_errstr(status)); 974 CLR(hp->hp_flags, UHSO_PORT_MUXBUSY); 975 return EIO; 976 } 977 978 sc->sc_refcnt++; 979 return 0; 980} 981 982Static int 983uhso_mux_control(struct uhso_port *hp) 984{ 985 986 DPRINTF(1, "hp=%p\n", hp); 987 988 return 0; 989} 990 991Static void 992uhso_mux_intr(struct usbd_xfer *xfer, void * p, usbd_status status) 993{ 994 struct uhso_softc *sc = p; 995 struct uhso_port *hp; 996 uint32_t cc; 997 uint8_t *buf; 998 unsigned int i; 999 1000 if (status != USBD_NORMAL_COMPLETION) { 1001 DPRINTF(0, "non-normal status %s\n", usbd_errstr(status)); 1002 return; 1003 } 1004 1005 usbd_get_xfer_status(xfer, NULL, (void **)&buf, &cc, NULL); 1006 if (cc == 0) 1007 return; 1008 1009 DPRINTF(5, "mux mask 0x%02x, cc=%u\n", buf[0], cc); 1010 1011 for (i = 0; i < __arraycount(uhso_mux_port); i++) { 1012 if (!ISSET(buf[0], __BIT(i))) 1013 continue; 1014 1015 DPRINTF(5, "mux %d port %d\n", i, uhso_mux_port[i]); 1016 hp = sc->sc_port[uhso_mux_port[i]]; 1017 if (hp == NULL 1018 || hp->hp_tp == NULL 1019 || !ISSET(hp->hp_status, TIOCM_DTR)) 1020 continue; 1021 1022 SET(hp->hp_flags, UHSO_PORT_MUXREADY); 1023 if (ISSET(hp->hp_flags, UHSO_PORT_MUXBUSY)) 1024 continue; 1025 1026 uhso_mux_read(hp); 1027 } 1028} 1029 1030 1031/****************************************************************************** 1032 * 1033 * Bulk ports operate using the bulk endpoints on an interface, though 1034 * the Modem port (at least) may have an interrupt endpoint that will pass 1035 * CDC Notification messages with the modem status. 1036 */ 1037 1038Static void 1039uhso_bulk_attach(struct uhso_softc *sc, struct usbd_interface *ifh, int index) 1040{ 1041 usb_endpoint_descriptor_t *ed; 1042 usb_interface_descriptor_t *id; 1043 struct uhso_port *hp; 1044 int in, out; 1045 1046 ed = uhso_get_endpoint(ifh, UE_BULK, UE_DIR_IN); 1047 if (ed == NULL) { 1048 aprint_error_dev(sc->sc_dev, "bulk-in endpoint not found\n"); 1049 return; 1050 } 1051 in = ed->bEndpointAddress; 1052 1053 ed = uhso_get_endpoint(ifh, UE_BULK, UE_DIR_OUT); 1054 if (ed == NULL) { 1055 aprint_error_dev(sc->sc_dev, "bulk-out endpoint not found\n"); 1056 return; 1057 } 1058 out = ed->bEndpointAddress; 1059 1060 id = usbd_get_interface_descriptor(ifh); 1061 if (id == NULL) { 1062 aprint_error_dev(sc->sc_dev, 1063 "interface descriptor not found\n"); 1064 return; 1065 } 1066 1067 DPRINTF(1, "bulk endpoints in=%x, out=%x\n", in, out); 1068 1069 if (sc->sc_port[index] != NULL) { 1070 aprint_error_dev(sc->sc_dev, "bulk port %d is duplicate!\n", 1071 index); 1072 1073 return; 1074 } 1075 1076 hp = kmem_zalloc(sizeof(struct uhso_port), KM_SLEEP); 1077 sc->sc_port[index] = hp; 1078 1079 hp->hp_sc = sc; 1080 hp->hp_ifh = ifh; 1081 hp->hp_index = id->bInterfaceNumber; 1082 hp->hp_raddr = in; 1083 hp->hp_waddr = out; 1084 hp->hp_abort = uhso_bulk_abort; 1085 hp->hp_detach = uhso_bulk_detach; 1086 hp->hp_init = uhso_bulk_init; 1087 hp->hp_clean = uhso_bulk_clean; 1088 hp->hp_write = uhso_bulk_write; 1089 hp->hp_write_cb = uhso_tty_write_cb; 1090 hp->hp_read = uhso_bulk_read; 1091 hp->hp_read_cb = uhso_tty_read_cb; 1092 hp->hp_control = uhso_bulk_control; 1093 hp->hp_wsize = UHSO_BULK_WSIZE; 1094 hp->hp_rsize = UHSO_BULK_RSIZE; 1095 1096 if (index == UHSO_PORT_MODEM) { 1097 ed = uhso_get_endpoint(ifh, UE_INTERRUPT, UE_DIR_IN); 1098 if (ed != NULL) { 1099 hp->hp_iaddr = ed->bEndpointAddress; 1100 hp->hp_isize = UGETW(ed->wMaxPacketSize); 1101 } 1102 } 1103 1104 uhso_tty_attach(hp); 1105 1106 aprint_normal_dev(sc->sc_dev, 1107 "%s (port %d) attached as bulk tty\n", 1108 uhso_port_name[index], index); 1109} 1110 1111Static int 1112uhso_bulk_abort(struct uhso_port *hp) 1113{ 1114 1115 DPRINTF(1, "hp=%p\n", hp); 1116 1117 return (*hp->hp_clean)(hp); 1118} 1119 1120Static int 1121uhso_bulk_detach(struct uhso_port *hp) 1122{ 1123 1124 DPRINTF(1, "hp=%p\n", hp); 1125 1126 uhso_tty_detach(hp); 1127 kmem_free(hp, sizeof(struct uhso_port)); 1128 return 0; 1129} 1130 1131Static int 1132uhso_bulk_init(struct uhso_port *hp) 1133{ 1134 usbd_status status; 1135 1136 DPRINTF(1, "hp=%p\n", hp); 1137 1138 if (hp->hp_isize > 0) { 1139 hp->hp_ibuf = kmem_alloc(hp->hp_isize, KM_SLEEP); 1140 1141 status = usbd_open_pipe_intr(hp->hp_ifh, hp->hp_iaddr, 1142 USBD_SHORT_XFER_OK, &hp->hp_ipipe, hp, hp->hp_ibuf, 1143 hp->hp_isize, uhso_bulk_intr, USBD_DEFAULT_INTERVAL); 1144 1145 if (status != USBD_NORMAL_COMPLETION) { 1146 DPRINTF(0, "interrupt pipe open failed: %s\n", 1147 usbd_errstr(status)); 1148 1149 return EIO; 1150 } 1151 } 1152 1153 status = usbd_open_pipe(hp->hp_ifh, hp->hp_raddr, 0, &hp->hp_rpipe); 1154 if (status != USBD_NORMAL_COMPLETION) { 1155 DPRINTF(0, "read pipe open failed: %s\n", usbd_errstr(status)); 1156 return EIO; 1157 } 1158 1159 status = usbd_open_pipe(hp->hp_ifh, hp->hp_waddr, 0, &hp->hp_wpipe); 1160 if (status != USBD_NORMAL_COMPLETION) { 1161 DPRINTF(0, "write pipe open failed: %s\n", usbd_errstr(status)); 1162 return EIO; 1163 } 1164 1165 int error = usbd_create_xfer(hp->hp_rpipe, hp->hp_rsize, 1166 0, 0, &hp->hp_rxfer); 1167 if (error) 1168 return error; 1169 1170 hp->hp_rbuf = usbd_get_buffer(hp->hp_rxfer); 1171 1172 error = usbd_create_xfer(hp->hp_wpipe, hp->hp_wsize, 0, 0, 1173 &hp->hp_wxfer); 1174 if (error) 1175 return error; 1176 hp->hp_wbuf = usbd_get_buffer(hp->hp_wxfer); 1177 1178 return 0; 1179} 1180 1181Static int 1182uhso_bulk_clean(struct uhso_port *hp) 1183{ 1184 1185 DPRINTF(1, "hp=%p\n", hp); 1186 1187 if (hp->hp_ipipe != NULL) { 1188 usbd_abort_pipe(hp->hp_ipipe); 1189 usbd_close_pipe(hp->hp_ipipe); 1190 hp->hp_ipipe = NULL; 1191 } 1192 1193 if (hp->hp_ibuf != NULL) { 1194 kmem_free(hp->hp_ibuf, hp->hp_isize); 1195 hp->hp_ibuf = NULL; 1196 } 1197 1198 if (hp->hp_rpipe != NULL) { 1199 usbd_abort_pipe(hp->hp_rpipe); 1200 } 1201 1202 if (hp->hp_wpipe != NULL) { 1203 usbd_abort_pipe(hp->hp_wpipe); 1204 } 1205 1206 if (hp->hp_rxfer != NULL) { 1207 usbd_destroy_xfer(hp->hp_rxfer); 1208 hp->hp_rxfer = NULL; 1209 hp->hp_rbuf = NULL; 1210 } 1211 1212 if (hp->hp_wxfer != NULL) { 1213 usbd_destroy_xfer(hp->hp_wxfer); 1214 hp->hp_wxfer = NULL; 1215 hp->hp_wbuf = NULL; 1216 } 1217 1218 if (hp->hp_rpipe != NULL) { 1219 usbd_close_pipe(hp->hp_rpipe); 1220 hp->hp_rpipe = NULL; 1221 } 1222 1223 if (hp->hp_wpipe != NULL) { 1224 usbd_close_pipe(hp->hp_wpipe); 1225 hp->hp_wpipe = NULL; 1226 } 1227 1228 return 0; 1229} 1230 1231Static int 1232uhso_bulk_write(struct uhso_port *hp) 1233{ 1234 struct uhso_softc *sc = hp->hp_sc; 1235 usbd_status status; 1236 1237 DPRINTF(5, "hp=%p, wlen=%zd\n", hp, hp->hp_wlen); 1238 1239 usbd_setup_xfer(hp->hp_wxfer, hp, hp->hp_wbuf, hp->hp_wlen, 0, 1240 USBD_NO_TIMEOUT, hp->hp_write_cb); 1241 1242 status = usbd_transfer(hp->hp_wxfer); 1243 if (status != USBD_IN_PROGRESS) { 1244 DPRINTF(0, "non-normal status %s\n", usbd_errstr(status)); 1245 return EIO; 1246 } 1247 1248 sc->sc_refcnt++; 1249 return 0; 1250} 1251 1252Static int 1253uhso_bulk_read(struct uhso_port *hp) 1254{ 1255 struct uhso_softc *sc = hp->hp_sc; 1256 usbd_status status; 1257 1258 DPRINTF(5, "hp=%p\n", hp); 1259 1260 usbd_setup_xfer(hp->hp_rxfer, hp, hp->hp_rbuf, hp->hp_rsize, 1261 USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, hp->hp_read_cb); 1262 1263 status = usbd_transfer(hp->hp_rxfer); 1264 if (status != USBD_IN_PROGRESS) { 1265 DPRINTF(0, "non-normal status %s\n", usbd_errstr(status)); 1266 return EIO; 1267 } 1268 1269 sc->sc_refcnt++; 1270 return 0; 1271} 1272 1273Static int 1274uhso_bulk_control(struct uhso_port *hp) 1275{ 1276 struct uhso_softc *sc = hp->hp_sc; 1277 usb_device_request_t req; 1278 usbd_status status; 1279 int val; 1280 1281 DPRINTF(1, "hp=%p\n", hp); 1282 1283 if (hp->hp_isize == 0) 1284 return 0; 1285 1286 val = 0; 1287 if (ISSET(hp->hp_status, TIOCM_DTR)) 1288 SET(val, UCDC_LINE_DTR); 1289 if (ISSET(hp->hp_status, TIOCM_RTS)) 1290 SET(val, UCDC_LINE_RTS); 1291 1292 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1293 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 1294 USETW(req.wValue, val); 1295 USETW(req.wIndex, hp->hp_index); 1296 USETW(req.wLength, 0); 1297 1298 sc->sc_refcnt++; 1299 1300 status = usbd_do_request(sc->sc_udev, &req, NULL); 1301 1302 if (--sc->sc_refcnt < 0) 1303 usb_detach_wakeupold(sc->sc_dev); 1304 1305 if (status != USBD_NORMAL_COMPLETION) { 1306 DPRINTF(0, "non-normal status %s\n", usbd_errstr(status)); 1307 return EIO; 1308 } 1309 1310 return 0; 1311} 1312 1313Static void 1314uhso_bulk_intr(struct usbd_xfer *xfer, void * p, usbd_status status) 1315{ 1316 struct uhso_port *hp = p; 1317 struct tty *tp = hp->hp_tp; 1318 usb_cdc_notification_t *msg; 1319 uint32_t cc; 1320 int s, old; 1321 1322 if (status != USBD_NORMAL_COMPLETION) { 1323 DPRINTF(0, "non-normal status %s\n", usbd_errstr(status)); 1324 return; 1325 } 1326 1327 usbd_get_xfer_status(xfer, NULL, (void **)&msg, &cc, NULL); 1328 1329 if (cc < UCDC_NOTIFICATION_LENGTH 1330 || msg->bmRequestType != UCDC_NOTIFICATION 1331 || msg->bNotification != UCDC_N_SERIAL_STATE 1332 || UGETW(msg->wValue) != 0 1333 || UGETW(msg->wIndex) != hp->hp_index 1334 || UGETW(msg->wLength) < 1) 1335 return; 1336 1337 DPRINTF(5, "state=%02x\n", msg->data[0]); 1338 1339 old = hp->hp_status; 1340 CLR(hp->hp_status, TIOCM_RNG | TIOCM_DSR | TIOCM_CAR); 1341 if (ISSET(msg->data[0], UCDC_N_SERIAL_RI)) 1342 SET(hp->hp_status, TIOCM_RNG); 1343 if (ISSET(msg->data[0], UCDC_N_SERIAL_DSR)) 1344 SET(hp->hp_status, TIOCM_DSR); 1345 if (ISSET(msg->data[0], UCDC_N_SERIAL_DCD)) 1346 SET(hp->hp_status, TIOCM_CAR); 1347 1348 if (ISSET(hp->hp_status ^ old, TIOCM_CAR)) { 1349 s = spltty(); 1350 tp->t_linesw->l_modem(tp, ISSET(hp->hp_status, TIOCM_CAR)); 1351 splx(s); 1352 } 1353 1354 if (ISSET((hp->hp_status ^ old), TIOCM_RNG | TIOCM_DSR | TIOCM_CAR)) 1355 DPRINTF(1, "RNG %s, DSR %s, DCD %s\n", 1356 (ISSET(hp->hp_status, TIOCM_RNG) ? "on" : "off"), 1357 (ISSET(hp->hp_status, TIOCM_DSR) ? "on" : "off"), 1358 (ISSET(hp->hp_status, TIOCM_CAR) ? "on" : "off")); 1359} 1360 1361 1362/****************************************************************************** 1363 * 1364 * TTY management 1365 * 1366 */ 1367 1368Static void 1369uhso_tty_attach(struct uhso_port *hp) 1370{ 1371 struct tty *tp; 1372 1373 tp = tty_alloc(); 1374 tp->t_oproc = uhso_tty_start; 1375 tp->t_param = uhso_tty_param; 1376 1377 hp->hp_tp = tp; 1378 tty_attach(tp); 1379 1380 DPRINTF(1, "hp=%p, tp=%p\n", hp, tp); 1381} 1382 1383Static void 1384uhso_tty_detach(struct uhso_port *hp) 1385{ 1386 1387 DPRINTF(1, "hp=%p\n", hp); 1388 1389 uhso_tty_clean(hp); 1390 1391 tty_detach(hp->hp_tp); 1392 tty_free(hp->hp_tp); 1393 hp->hp_tp = NULL; 1394} 1395 1396Static void 1397uhso_tty_write_cb(struct usbd_xfer *xfer, void * p, usbd_status status) 1398{ 1399 struct uhso_port *hp = p; 1400 struct uhso_softc *sc = hp->hp_sc; 1401 struct tty *tp = hp->hp_tp; 1402 uint32_t cc; 1403 int s; 1404 1405 if (--sc->sc_refcnt < 0) 1406 usb_detach_wakeupold(sc->sc_dev); 1407 1408 if (status != USBD_NORMAL_COMPLETION) { 1409 DPRINTF(0, "non-normal status %s\n", usbd_errstr(status)); 1410 1411 if (status == USBD_STALLED && hp->hp_wpipe != NULL) 1412 usbd_clear_endpoint_stall_async(hp->hp_wpipe); 1413 else 1414 return; 1415 } else { 1416 usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL); 1417 1418 DPRINTF(5, "wrote %d bytes (of %zd)\n", cc, hp->hp_wlen); 1419 if (cc != hp->hp_wlen) 1420 DPRINTF(0, "cc=%u, wlen=%zd\n", cc, hp->hp_wlen); 1421 } 1422 1423 s = spltty(); 1424 CLR(tp->t_state, TS_BUSY); 1425 tp->t_linesw->l_start(tp); 1426 splx(s); 1427} 1428 1429Static void 1430uhso_tty_read_cb(struct usbd_xfer *xfer, void * p, usbd_status status) 1431{ 1432 struct uhso_port *hp = p; 1433 struct uhso_softc *sc = hp->hp_sc; 1434 struct tty *tp = hp->hp_tp; 1435 uint8_t *cp; 1436 uint32_t cc; 1437 int s; 1438 1439 if (--sc->sc_refcnt < 0) 1440 usb_detach_wakeupold(sc->sc_dev); 1441 1442 if (status != USBD_NORMAL_COMPLETION) { 1443 DPRINTF(0, "non-normal status: %s\n", usbd_errstr(status)); 1444 1445 if (status == USBD_STALLED && hp->hp_rpipe != NULL) 1446 usbd_clear_endpoint_stall_async(hp->hp_rpipe); 1447 else 1448 return; 1449 1450 hp->hp_rlen = 0; 1451 } else { 1452 usbd_get_xfer_status(xfer, NULL, (void **)&cp, &cc, NULL); 1453 1454 hp->hp_rlen = cc; 1455 DPRINTF(5, "read %d bytes\n", cc); 1456 1457 s = spltty(); 1458 while (cc > 0) { 1459 if (tp->t_linesw->l_rint(*cp++, tp) == -1) { 1460 DPRINTF(0, "lost %d bytes\n", cc); 1461 break; 1462 } 1463 1464 cc--; 1465 } 1466 splx(s); 1467 } 1468 1469 (*hp->hp_read)(hp); 1470} 1471 1472 1473/****************************************************************************** 1474 * 1475 * TTY subsystem 1476 * 1477 */ 1478 1479static int 1480uhso_tty_open(dev_t dev, int flag, int mode, struct lwp *l) 1481{ 1482 struct uhso_softc *sc; 1483 struct uhso_port *hp; 1484 struct tty *tp; 1485 int error, s; 1486 1487 DPRINTF(1, "unit %d port %d\n", UHSOUNIT(dev), UHSOPORT(dev)); 1488 1489 sc = device_lookup_private(&uhso_cd, UHSOUNIT(dev)); 1490 if (sc == NULL 1491 || !device_is_active(sc->sc_dev) 1492 || UHSOPORT(dev) >= UHSO_PORT_MAX) 1493 return ENXIO; 1494 1495 hp = sc->sc_port[UHSOPORT(dev)]; 1496 if (hp == NULL || hp->hp_tp == NULL) 1497 return ENXIO; 1498 1499 tp = hp->hp_tp; 1500 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 1501 return EBUSY; 1502 1503 error = 0; 1504 s = spltty(); 1505 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 1506 tp->t_dev = dev; 1507 error = uhso_tty_init(hp); 1508 } 1509 splx(s); 1510 1511 if (error == 0) { 1512 error = ttyopen(tp, UHSODIALOUT(dev), ISSET(flag, O_NONBLOCK)); 1513 if (error == 0) { 1514 error = tp->t_linesw->l_open(dev, tp); 1515 } 1516 } 1517 1518 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) 1519 uhso_tty_clean(hp); 1520 1521 DPRINTF(1, "sc=%p, hp=%p, tp=%p, error=%d\n", sc, hp, tp, error); 1522 1523 return error; 1524} 1525 1526Static int 1527uhso_tty_init(struct uhso_port *hp) 1528{ 1529 struct tty *tp = hp->hp_tp; 1530 struct termios t; 1531 int error; 1532 1533 DPRINTF(1, "sc=%p, hp=%p, tp=%p\n", sc, hp, tp); 1534 1535 /* 1536 * Initialize the termios status to the defaults. Add in the 1537 * sticky bits from TIOCSFLAGS. 1538 */ 1539 t.c_ispeed = 0; 1540 t.c_ospeed = TTYDEF_SPEED; 1541 t.c_cflag = TTYDEF_CFLAG; 1542 if (ISSET(hp->hp_swflags, TIOCFLAG_CLOCAL)) 1543 SET(t.c_cflag, CLOCAL); 1544 if (ISSET(hp->hp_swflags, TIOCFLAG_CRTSCTS)) 1545 SET(t.c_cflag, CRTSCTS); 1546 if (ISSET(hp->hp_swflags, TIOCFLAG_MDMBUF)) 1547 SET(t.c_cflag, MDMBUF); 1548 1549 /* Ensure uhso_tty_param() will do something. */ 1550 tp->t_ospeed = 0; 1551 (void)uhso_tty_param(tp, &t); 1552 1553 tp->t_iflag = TTYDEF_IFLAG; 1554 tp->t_oflag = TTYDEF_OFLAG; 1555 tp->t_lflag = TTYDEF_LFLAG; 1556 ttychars(tp); 1557 ttsetwater(tp); 1558 1559 hp->hp_status = 0; 1560 error = (*hp->hp_init)(hp); 1561 if (error != 0) 1562 return error; 1563 1564 /* 1565 * Turn on DTR. We must always do this, even if carrier is not 1566 * present, because otherwise we'd have to use TIOCSDTR 1567 * immediately after setting CLOCAL, which applications do not 1568 * expect. We always assert DTR while the port is open 1569 * unless explicitly requested to deassert it. Ditto RTS. 1570 */ 1571 uhso_tty_control(hp, TIOCMBIS, TIOCM_DTR | TIOCM_RTS); 1572 1573 /* and start reading */ 1574 error = (*hp->hp_read)(hp); 1575 if (error != 0) 1576 return error; 1577 1578 return 0; 1579} 1580 1581static int 1582uhso_tty_close(dev_t dev, int flag, int mode, struct lwp *l) 1583{ 1584 struct uhso_softc *sc = device_lookup_private(&uhso_cd, UHSOUNIT(dev)); 1585 struct uhso_port *hp = sc->sc_port[UHSOPORT(dev)]; 1586 struct tty *tp = hp->hp_tp; 1587 1588 if (!ISSET(tp->t_state, TS_ISOPEN)) 1589 return 0; 1590 1591 DPRINTF(1, "sc=%p, hp=%p, tp=%p\n", sc, hp, tp); 1592 1593 sc->sc_refcnt++; 1594 1595 tp->t_linesw->l_close(tp, flag); 1596 ttyclose(tp); 1597 1598 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) 1599 uhso_tty_clean(hp); 1600 1601 if (--sc->sc_refcnt < 0) 1602 usb_detach_wakeupold(sc->sc_dev); 1603 1604 return 0; 1605} 1606 1607Static void 1608uhso_tty_clean(struct uhso_port *hp) 1609{ 1610 1611 DPRINTF(1, "hp=%p\n", hp); 1612 1613 if (ISSET(hp->hp_status, TIOCM_DTR) 1614 && ISSET(hp->hp_tp->t_cflag, HUPCL)) 1615 uhso_tty_control(hp, TIOCMBIC, TIOCM_DTR); 1616 1617 (*hp->hp_clean)(hp); 1618 1619 if (hp->hp_rxfer != NULL) { 1620 usbd_destroy_xfer(hp->hp_rxfer); 1621 hp->hp_rxfer = NULL; 1622 hp->hp_rbuf = NULL; 1623 } 1624 1625 if (hp->hp_wxfer != NULL) { 1626 usbd_destroy_xfer(hp->hp_wxfer); 1627 hp->hp_wxfer = NULL; 1628 hp->hp_wbuf = NULL; 1629 } 1630} 1631 1632static int 1633uhso_tty_read(dev_t dev, struct uio *uio, int flag) 1634{ 1635 struct uhso_softc *sc = device_lookup_private(&uhso_cd, UHSOUNIT(dev)); 1636 struct uhso_port *hp = sc->sc_port[UHSOPORT(dev)]; 1637 struct tty *tp = hp->hp_tp; 1638 int error; 1639 1640 if (!device_is_active(sc->sc_dev)) 1641 return EIO; 1642 1643 DPRINTF(5, "sc=%p, hp=%p, tp=%p\n", sc, hp, tp); 1644 1645 sc->sc_refcnt++; 1646 1647 error = tp->t_linesw->l_read(tp, uio, flag); 1648 1649 if (--sc->sc_refcnt < 0) 1650 usb_detach_wakeupold(sc->sc_dev); 1651 1652 return error; 1653} 1654 1655static int 1656uhso_tty_write(dev_t dev, struct uio *uio, int flag) 1657{ 1658 struct uhso_softc *sc = device_lookup_private(&uhso_cd, UHSOUNIT(dev)); 1659 struct uhso_port *hp = sc->sc_port[UHSOPORT(dev)]; 1660 struct tty *tp = hp->hp_tp; 1661 int error; 1662 1663 if (!device_is_active(sc->sc_dev)) 1664 return EIO; 1665 1666 DPRINTF(5, "sc=%p, hp=%p, tp=%p\n", sc, hp, tp); 1667 1668 sc->sc_refcnt++; 1669 1670 error = tp->t_linesw->l_write(tp, uio, flag); 1671 1672 if (--sc->sc_refcnt < 0) 1673 usb_detach_wakeupold(sc->sc_dev); 1674 1675 return error; 1676} 1677 1678static int 1679uhso_tty_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1680{ 1681 struct uhso_softc *sc = device_lookup_private(&uhso_cd, UHSOUNIT(dev)); 1682 struct uhso_port *hp = sc->sc_port[UHSOPORT(dev)]; 1683 int error; 1684 1685 if (!device_is_active(sc->sc_dev)) 1686 return EIO; 1687 1688 DPRINTF(1, "sc=%p, hp=%p\n", sc, hp); 1689 1690 sc->sc_refcnt++; 1691 1692 error = uhso_tty_do_ioctl(hp, cmd, data, flag, l); 1693 1694 if (--sc->sc_refcnt < 0) 1695 usb_detach_wakeupold(sc->sc_dev); 1696 1697 return error; 1698} 1699 1700Static int 1701uhso_tty_do_ioctl(struct uhso_port *hp, u_long cmd, void *data, int flag, 1702 struct lwp *l) 1703{ 1704 struct tty *tp = hp->hp_tp; 1705 int error, s; 1706 1707 error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, l); 1708 if (error != EPASSTHROUGH) 1709 return error; 1710 1711 error = ttioctl(tp, cmd, data, flag, l); 1712 if (error != EPASSTHROUGH) 1713 return error; 1714 1715 error = 0; 1716 1717 s = spltty(); 1718 1719 switch (cmd) { 1720 case TIOCSDTR: 1721 error = uhso_tty_control(hp, TIOCMBIS, TIOCM_DTR); 1722 break; 1723 1724 case TIOCCDTR: 1725 error = uhso_tty_control(hp, TIOCMBIC, TIOCM_DTR); 1726 break; 1727 1728 case TIOCGFLAGS: 1729 *(int *)data = hp->hp_swflags; 1730 break; 1731 1732 case TIOCSFLAGS: 1733 error = kauth_authorize_device_tty(l->l_cred, 1734 KAUTH_DEVICE_TTY_PRIVSET, tp); 1735 1736 if (error) 1737 break; 1738 1739 hp->hp_swflags = *(int *)data; 1740 break; 1741 1742 case TIOCMSET: 1743 case TIOCMBIS: 1744 case TIOCMBIC: 1745 error = uhso_tty_control(hp, cmd, *(int *)data); 1746 break; 1747 1748 case TIOCMGET: 1749 *(int *)data = hp->hp_status; 1750 break; 1751 1752 default: 1753 error = EPASSTHROUGH; 1754 break; 1755 } 1756 1757 splx(s); 1758 1759 return error; 1760} 1761 1762static void 1763uhso_tty_stop(struct tty *tp, int flag) 1764{ 1765#if 0 1766 struct uhso_softc *sc = device_lookup_private(&uhso_cd, 1767 UHSOUNIT(tp->t_dev)); 1768 struct uhso_port *hp = sc->sc_port[UHSOPORT(tp->t_dev)]; 1769#endif 1770 1771 KASSERT(ttylocked(tp)); 1772} 1773 1774static struct tty * 1775uhso_tty_tty(dev_t dev) 1776{ 1777 struct uhso_softc *sc = device_lookup_private(&uhso_cd, UHSOUNIT(dev)); 1778 struct uhso_port *hp = sc->sc_port[UHSOPORT(dev)]; 1779 1780 return hp->hp_tp; 1781} 1782 1783static int 1784uhso_tty_poll(dev_t dev, int events, struct lwp *l) 1785{ 1786 struct uhso_softc *sc = device_lookup_private(&uhso_cd, UHSOUNIT(dev)); 1787 struct uhso_port *hp = sc->sc_port[UHSOPORT(dev)]; 1788 struct tty *tp = hp->hp_tp; 1789 int revents; 1790 1791 if (!device_is_active(sc->sc_dev)) 1792 return POLLHUP; 1793 1794 sc->sc_refcnt++; 1795 1796 revents = tp->t_linesw->l_poll(tp, events, l); 1797 1798 if (--sc->sc_refcnt < 0) 1799 usb_detach_wakeupold(sc->sc_dev); 1800 1801 return revents; 1802} 1803 1804Static int 1805uhso_tty_param(struct tty *tp, struct termios *t) 1806{ 1807 struct uhso_softc *sc = device_lookup_private(&uhso_cd, 1808 UHSOUNIT(tp->t_dev)); 1809 struct uhso_port *hp = sc->sc_port[UHSOPORT(tp->t_dev)]; 1810 1811 if (!device_is_active(sc->sc_dev)) 1812 return EIO; 1813 1814 DPRINTF(1, "hp=%p, tp=%p, termios iflag=%x, oflag=%x, cflag=%x\n", 1815 hp, tp, t->c_iflag, t->c_oflag, t->c_cflag); 1816 1817 /* Check requested parameters. */ 1818 if (t->c_ispeed != 0 1819 && t->c_ispeed != t->c_ospeed) 1820 return EINVAL; 1821 1822 /* force CLOCAL and !HUPCL for console */ 1823 if (ISSET(hp->hp_swflags, TIOCFLAG_SOFTCAR)) { 1824 SET(t->c_cflag, CLOCAL); 1825 CLR(t->c_cflag, HUPCL); 1826 } 1827 1828 /* If there were no changes, don't do anything. */ 1829 if (tp->t_ospeed == t->c_ospeed 1830 && tp->t_cflag == t->c_cflag) 1831 return 0; 1832 1833 tp->t_ispeed = 0; 1834 tp->t_ospeed = t->c_ospeed; 1835 tp->t_cflag = t->c_cflag; 1836 1837 /* update tty layers idea of carrier bit */ 1838 tp->t_linesw->l_modem(tp, ISSET(hp->hp_status, TIOCM_CAR)); 1839 return 0; 1840} 1841 1842Static void 1843uhso_tty_start(struct tty *tp) 1844{ 1845 struct uhso_softc *sc = device_lookup_private(&uhso_cd, 1846 UHSOUNIT(tp->t_dev)); 1847 struct uhso_port *hp = sc->sc_port[UHSOPORT(tp->t_dev)]; 1848 int s; 1849 1850 KASSERT(ttylocked(tp)); 1851 1852 if (!device_is_active(sc->sc_dev)) 1853 return; 1854 1855 s = spltty(); 1856 1857 if (!ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP) 1858 && ttypull(tp) != 0) { 1859 hp->hp_wlen = q_to_b(&tp->t_outq, hp->hp_wbuf, hp->hp_wsize); 1860 if (hp->hp_wlen > 0) { 1861 SET(tp->t_state, TS_BUSY); 1862 (*hp->hp_write)(hp); 1863 } 1864 } 1865 1866 splx(s); 1867} 1868 1869Static int 1870uhso_tty_control(struct uhso_port *hp, u_long cmd, int bits) 1871{ 1872 1873 bits &= (TIOCM_DTR | TIOCM_RTS); 1874 DPRINTF(1, "cmd %s, DTR=%d, RTS=%d\n", 1875 (cmd == TIOCMBIC ? "BIC" : (cmd == TIOCMBIS ? "BIS" : "SET")), 1876 (bits & TIOCM_DTR) ? 1 : 0, 1877 (bits & TIOCM_RTS) ? 1 : 0); 1878 1879 switch (cmd) { 1880 case TIOCMBIC: 1881 CLR(hp->hp_status, bits); 1882 break; 1883 1884 case TIOCMBIS: 1885 SET(hp->hp_status, bits); 1886 break; 1887 1888 case TIOCMSET: 1889 CLR(hp->hp_status, TIOCM_DTR | TIOCM_RTS); 1890 SET(hp->hp_status, bits); 1891 break; 1892 } 1893 1894 return (*hp->hp_control)(hp); 1895} 1896 1897 1898/****************************************************************************** 1899 * 1900 * Network Interface 1901 * 1902 */ 1903 1904Static void 1905uhso_ifnet_attach(struct uhso_softc *sc, struct usbd_interface *ifh, int index) 1906{ 1907 usb_endpoint_descriptor_t *ed; 1908 struct uhso_port *hp; 1909 struct ifnet *ifp; 1910 int in, out; 1911 1912 ed = uhso_get_endpoint(ifh, UE_BULK, UE_DIR_IN); 1913 if (ed == NULL) { 1914 aprint_error_dev(sc->sc_dev, 1915 "could not find bulk-in endpoint\n"); 1916 1917 return; 1918 } 1919 in = ed->bEndpointAddress; 1920 1921 ed = uhso_get_endpoint(ifh, UE_BULK, UE_DIR_OUT); 1922 if (ed == NULL) { 1923 aprint_error_dev(sc->sc_dev, 1924 "could not find bulk-out endpoint\n"); 1925 1926 return; 1927 } 1928 out = ed->bEndpointAddress; 1929 1930 DPRINTF(1, "in=%d, out=%d\n", in, out); 1931 1932 if (sc->sc_port[index] != NULL) { 1933 aprint_error_dev(sc->sc_dev, 1934 "ifnet port %d is duplicate!\n", index); 1935 1936 return; 1937 } 1938 1939 hp = kmem_zalloc(sizeof(struct uhso_port), KM_SLEEP); 1940 sc->sc_port[index] = hp; 1941 1942 ifp = if_alloc(IFT_IP); 1943 strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 1944 ifp->if_softc = hp; 1945 ifp->if_mtu = UHSO_IFNET_MTU; 1946 ifp->if_dlt = DLT_RAW; 1947 ifp->if_type = IFT_IP; 1948 ifp->if_flags = IFF_NOARP | IFF_SIMPLEX; 1949 ifp->if_ioctl = uhso_ifnet_ioctl; 1950 ifp->if_start = uhso_ifnet_start; 1951 ifp->if_output = uhso_ifnet_output; 1952 IFQ_SET_READY(&ifp->if_snd); 1953 1954 hp->hp_sc = sc; 1955 hp->hp_ifp = ifp; 1956 hp->hp_ifh = ifh; 1957 hp->hp_raddr = in; 1958 hp->hp_waddr = out; 1959 hp->hp_abort = uhso_ifnet_abort; 1960 hp->hp_detach = uhso_ifnet_detach; 1961 hp->hp_init = uhso_bulk_init; 1962 hp->hp_clean = uhso_bulk_clean; 1963 hp->hp_write = uhso_bulk_write; 1964 hp->hp_write_cb = uhso_ifnet_write_cb; 1965 hp->hp_read = uhso_bulk_read; 1966 hp->hp_read_cb = uhso_ifnet_read_cb; 1967 hp->hp_wsize = MCLBYTES; 1968 hp->hp_rsize = MCLBYTES; 1969 1970 if_attach(ifp); 1971 if_alloc_sadl(ifp); 1972 bpf_attach(ifp, DLT_RAW, 0); 1973 1974 aprint_normal_dev(sc->sc_dev, "%s (port %d) attached as ifnet\n", 1975 uhso_port_name[index], index); 1976} 1977 1978Static int 1979uhso_ifnet_abort(struct uhso_port *hp) 1980{ 1981 struct ifnet *ifp = hp->hp_ifp; 1982 1983 /* All ifnet IO will abort when IFF_RUNNING is not set */ 1984 CLR(ifp->if_flags, IFF_RUNNING); 1985 1986 return (*hp->hp_clean)(hp); 1987} 1988 1989Static int 1990uhso_ifnet_detach(struct uhso_port *hp) 1991{ 1992 struct ifnet *ifp = hp->hp_ifp; 1993 int s; 1994 1995 s = splnet(); 1996 bpf_detach(ifp); 1997 if_detach(ifp); 1998 if_free(ifp); 1999 splx(s); 2000 2001 kmem_free(hp, sizeof(struct uhso_port)); 2002 return 0; 2003} 2004 2005Static void 2006uhso_ifnet_write_cb(struct usbd_xfer *xfer, void * p, usbd_status status) 2007{ 2008 struct uhso_port *hp = p; 2009 struct uhso_softc *sc= hp->hp_sc; 2010 struct ifnet *ifp = hp->hp_ifp; 2011 uint32_t cc; 2012 int s; 2013 2014 if (--sc->sc_refcnt < 0) 2015 usb_detach_wakeupold(sc->sc_dev); 2016 2017 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 2018 return; 2019 2020 if (status != USBD_NORMAL_COMPLETION) { 2021 DPRINTF(0, "non-normal status %s\n", usbd_errstr(status)); 2022 2023 if (status == USBD_STALLED && hp->hp_wpipe != NULL) 2024 usbd_clear_endpoint_stall_async(hp->hp_wpipe); 2025 else 2026 return; 2027 2028 if_statinc(ifp, if_oerrors); 2029 } else { 2030 usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL); 2031 DPRINTF(5, "wrote %d bytes (of %zd)\n", cc, hp->hp_wlen); 2032 2033 if (cc != hp->hp_wlen) 2034 DPRINTF(0, "cc=%u, wlen=%zd\n", cc, hp->hp_wlen); 2035 2036 if_statinc(ifp, if_opackets); 2037 } 2038 2039 s = splnet(); 2040 CLR(ifp->if_flags, IFF_OACTIVE); 2041 ifp->if_start(ifp); 2042 splx(s); 2043} 2044 2045Static void 2046uhso_ifnet_read_cb(struct usbd_xfer *xfer, void * p, 2047 usbd_status status) 2048{ 2049 struct uhso_port *hp = p; 2050 struct uhso_softc *sc= hp->hp_sc; 2051 struct ifnet *ifp = hp->hp_ifp; 2052 void *cp; 2053 uint32_t cc; 2054 2055 if (--sc->sc_refcnt < 0) 2056 usb_detach_wakeupold(sc->sc_dev); 2057 2058 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 2059 return; 2060 2061 if (status != USBD_NORMAL_COMPLETION) { 2062 DPRINTF(0, "non-normal status: %s\n", usbd_errstr(status)); 2063 2064 if (status == USBD_STALLED && hp->hp_rpipe != NULL) 2065 usbd_clear_endpoint_stall_async(hp->hp_rpipe); 2066 else 2067 return; 2068 2069 if_statinc(ifp, if_ierrors); 2070 hp->hp_rlen = 0; 2071 } else { 2072 usbd_get_xfer_status(xfer, NULL, (void **)&cp, &cc, NULL); 2073 2074 hp->hp_rlen = cc; 2075 DPRINTF(5, "read %d bytes\n", cc); 2076 2077 uhso_ifnet_input(ifp, &hp->hp_mbuf, cp, cc); 2078 } 2079 2080 (*hp->hp_read)(hp); 2081} 2082 2083Static void 2084uhso_ifnet_input(struct ifnet *ifp, struct mbuf **mb, uint8_t *cp, size_t cc) 2085{ 2086 struct mbuf *m; 2087 size_t got, len, want; 2088 int s; 2089 2090 /* 2091 * Several IP packets might be in the same buffer, we need to 2092 * separate them before handing it to the ip-stack. We might 2093 * also receive partial packets which we need to defer until 2094 * we get more data. 2095 */ 2096 while (cc > 0) { 2097 if (*mb == NULL) { 2098 MGETHDR(m, M_DONTWAIT, MT_DATA); 2099 if (m == NULL) { 2100 aprint_error_ifnet(ifp, "no mbufs\n"); 2101 if_statinc(ifp, if_ierrors); 2102 break; 2103 } 2104 2105 MCLGET(m, M_DONTWAIT); 2106 if (!ISSET(m->m_flags, M_EXT)) { 2107 aprint_error_ifnet(ifp, "no mbuf clusters\n"); 2108 if_statinc(ifp, if_ierrors); 2109 m_freem(m); 2110 break; 2111 } 2112 2113 got = 0; 2114 } else { 2115 m = *mb; 2116 *mb = NULL; 2117 got = m->m_pkthdr.len; 2118 } 2119 2120 /* make sure that the incoming packet is ok */ 2121 if (got == 0) 2122 mtod(m, uint8_t *)[0] = cp[0]; 2123 2124 want = mtod(m, struct ip *)->ip_hl << 2; 2125 if (mtod(m, struct ip *)->ip_v != 4 2126 || want != sizeof(struct ip)) { 2127 aprint_error_ifnet(ifp, 2128 "bad IP header (v=%d, hl=%zd)\n", 2129 mtod(m, struct ip *)->ip_v, want); 2130 2131 if_statinc(ifp, if_ierrors); 2132 m_freem(m); 2133 break; 2134 } 2135 2136 /* ensure we have the IP header.. */ 2137 if (got < want) { 2138 len = MIN(want - got, cc); 2139 memcpy(mtod(m, uint8_t *) + got, cp, len); 2140 got += len; 2141 cc -= len; 2142 cp += len; 2143 2144 if (got < want) { 2145 DPRINTF(5, "waiting for IP header " 2146 "(got %zd want %zd)\n", got, want); 2147 2148 m->m_pkthdr.len = got; 2149 *mb = m; 2150 break; 2151 } 2152 } 2153 2154 /* ..and the packet body */ 2155 want = ntohs(mtod(m, struct ip *)->ip_len); 2156 if (got < want) { 2157 len = MIN(want - got, cc); 2158 memcpy(mtod(m, uint8_t *) + got, cp, len); 2159 got += len; 2160 cc -= len; 2161 cp += len; 2162 2163 if (got < want) { 2164 DPRINTF(5, "waiting for IP packet " 2165 "(got %zd want %zd)\n", got, want); 2166 2167 m->m_pkthdr.len = got; 2168 *mb = m; 2169 break; 2170 } 2171 } 2172 2173 m_set_rcvif(m, ifp); 2174 m->m_pkthdr.len = m->m_len = got; 2175 2176 s = splnet(); 2177 2178 bpf_mtap(ifp, m, BPF_D_IN); 2179 2180 if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) { 2181 m_freem(m); 2182 } else { 2183 if_statadd2(ifp, if_ipackets, 1, if_ibytes, got); 2184 } 2185 splx(s); 2186 } 2187} 2188 2189Static int 2190uhso_ifnet_ioctl(struct ifnet *ifp, u_long cmd, void *data) 2191{ 2192 struct uhso_port *hp = ifp->if_softc; 2193 int error, s; 2194 2195 s = splnet(); 2196 2197 switch (cmd) { 2198 case SIOCINITIFADDR: 2199 switch (((struct ifaddr *)data)->ifa_addr->sa_family) { 2200#ifdef INET 2201 case AF_INET: 2202 if (!ISSET(ifp->if_flags, IFF_RUNNING)) { 2203 SET(ifp->if_flags, IFF_UP); 2204 error = uhso_ifnet_init(hp); 2205 if (error != 0) { 2206 uhso_ifnet_clean(hp); 2207 break; 2208 } 2209 2210 SET(ifp->if_flags, IFF_RUNNING); 2211 DPRINTF(1, "hp=%p, ifp=%p INITIFADDR\n", hp, 2212 ifp); 2213 break; 2214 } 2215 2216 error = 0; 2217 break; 2218#endif 2219 2220 default: 2221 error = EAFNOSUPPORT; 2222 break; 2223 } 2224 break; 2225 2226 case SIOCSIFMTU: 2227 if (((struct ifreq *)data)->ifr_mtu > hp->hp_wsize) { 2228 error = EINVAL; 2229 break; 2230 } 2231 2232 error = ifioctl_common(ifp, cmd, data); 2233 if (error == ENETRESET) 2234 error = 0; 2235 2236 break; 2237 2238 case SIOCSIFFLAGS: 2239 error = ifioctl_common(ifp, cmd, data); 2240 if (error != 0) 2241 break; 2242 2243 switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { 2244 case IFF_UP: 2245 error = uhso_ifnet_init(hp); 2246 if (error != 0) { 2247 uhso_ifnet_clean(hp); 2248 break; 2249 } 2250 2251 SET(ifp->if_flags, IFF_RUNNING); 2252 DPRINTF(1, "hp=%p, ifp=%p RUNNING\n", hp, ifp); 2253 break; 2254 2255 case IFF_RUNNING: 2256 uhso_ifnet_clean(hp); 2257 CLR(ifp->if_flags, IFF_RUNNING); 2258 DPRINTF(1, "hp=%p, ifp=%p STOPPED\n", hp, ifp); 2259 break; 2260 2261 default: 2262 break; 2263 } 2264 break; 2265 2266 default: 2267 error = ifioctl_common(ifp, cmd, data); 2268 break; 2269 } 2270 2271 splx(s); 2272 2273 return error; 2274} 2275 2276/* is only called if IFF_RUNNING not set */ 2277Static int 2278uhso_ifnet_init(struct uhso_port *hp) 2279{ 2280 struct uhso_softc *sc = hp->hp_sc; 2281 int error; 2282 2283 DPRINTF(1, "sc=%p, hp=%p\n", sc, hp); 2284 2285 if (!device_is_active(sc->sc_dev)) 2286 return EIO; 2287 2288 error = (*hp->hp_init)(hp); 2289 if (error != 0) 2290 return error; 2291 2292 error = (*hp->hp_read)(hp); 2293 if (error != 0) 2294 return error; 2295 2296 return 0; 2297} 2298 2299Static void 2300uhso_ifnet_clean(struct uhso_port *hp) 2301{ 2302 2303 DPRINTF(1, "hp=%p\n", hp); 2304 2305 (*hp->hp_clean)(hp); 2306} 2307 2308/* called at splnet() with IFF_OACTIVE not set */ 2309Static void 2310uhso_ifnet_start(struct ifnet *ifp) 2311{ 2312 struct uhso_port *hp = ifp->if_softc; 2313 struct mbuf *m; 2314 2315 KASSERT(!ISSET(ifp->if_flags, IFF_OACTIVE)); 2316 2317 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 2318 return; 2319 2320 if (IFQ_IS_EMPTY(&ifp->if_snd)) { 2321 DPRINTF(5, "finished sending\n"); 2322 return; 2323 } 2324 2325 SET(ifp->if_flags, IFF_OACTIVE); 2326 IFQ_DEQUEUE(&ifp->if_snd, m); 2327 hp->hp_wlen = m->m_pkthdr.len; 2328 if (hp->hp_wlen > hp->hp_wsize) { 2329 aprint_error_ifnet(ifp, 2330 "packet too long (%zd > %zd), truncating\n", 2331 hp->hp_wlen, hp->hp_wsize); 2332 2333 hp->hp_wlen = hp->hp_wsize; 2334 } 2335 2336 bpf_mtap(ifp, m, BPF_D_OUT); 2337 2338 m_copydata(m, 0, hp->hp_wlen, hp->hp_wbuf); 2339 m_freem(m); 2340 2341 if ((*hp->hp_write)(hp) != 0) { 2342 if_statinc(ifp, if_oerrors); 2343 CLR(ifp->if_flags, IFF_OACTIVE); 2344 } 2345} 2346 2347Static int 2348uhso_ifnet_output(struct ifnet *ifp, struct mbuf *m, 2349 const struct sockaddr *dst, const struct rtentry *rt0) 2350{ 2351 int error; 2352 2353 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 2354 return EIO; 2355 2356 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); 2357 2358 switch (dst->sa_family) { 2359#ifdef INET 2360 case AF_INET: 2361 error = ifq_enqueue(ifp, m); 2362 break; 2363#endif 2364 2365 default: 2366 DPRINTF(0, "unsupported address family %d\n", dst->sa_family); 2367 error = EAFNOSUPPORT; 2368 m_freem(m); 2369 break; 2370 } 2371 2372 return error; 2373} 2374