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