uhso.c revision 202181
1202181Sthompsa/*- 2202181Sthompsa * Copyright (c) 2009 Fredrik Lindberg 3202181Sthompsa * All rights reserved. 4202181Sthompsa * 5202181Sthompsa * Redistribution and use in source and binary forms, with or without 6202181Sthompsa * modification, are permitted provided that the following conditions 7202181Sthompsa * are met: 8202181Sthompsa * 1. Redistributions of source code must retain the above copyright 9202181Sthompsa * notice, this list of conditions and the following disclaimer. 10202181Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 11202181Sthompsa * notice, this list of conditions and the following disclaimer in the 12202181Sthompsa * documentation and/or other materials provided with the distribution. 13202181Sthompsa * 14202181Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15202181Sthompsa * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16202181Sthompsa * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17202181Sthompsa * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18202181Sthompsa * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19202181Sthompsa * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20202181Sthompsa * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21202181Sthompsa * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22202181Sthompsa * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23202181Sthompsa * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24202181Sthompsa * 25202181Sthompsa */ 26202181Sthompsa#include <sys/cdefs.h> 27202181Sthompsa__FBSDID("$FreeBSD: head/sys/dev/usb/net/uhso.c 202181 2010-01-13 03:16:31Z thompsa $"); 28202181Sthompsa 29202181Sthompsa#include <sys/param.h> 30202181Sthompsa#include <sys/types.h> 31202181Sthompsa#include <sys/sockio.h> 32202181Sthompsa#include <sys/mbuf.h> 33202181Sthompsa#include <sys/malloc.h> 34202181Sthompsa#include <sys/kernel.h> 35202181Sthompsa#include <sys/module.h> 36202181Sthompsa#include <sys/socket.h> 37202181Sthompsa#include <sys/tty.h> 38202181Sthompsa#include <sys/sysctl.h> 39202181Sthompsa#include <sys/condvar.h> 40202181Sthompsa#include <sys/sx.h> 41202181Sthompsa#include <sys/proc.h> 42202181Sthompsa#include <sys/conf.h> 43202181Sthompsa#include <sys/bus.h> 44202181Sthompsa#include <sys/systm.h> 45202181Sthompsa 46202181Sthompsa#include <machine/bus.h> 47202181Sthompsa 48202181Sthompsa#include <net/if.h> 49202181Sthompsa#include <net/if_types.h> 50202181Sthompsa#include <net/netisr.h> 51202181Sthompsa#include <net/bpf.h> 52202181Sthompsa#include <netinet/in.h> 53202181Sthompsa#include <netinet/ip.h> 54202181Sthompsa#include <netinet/ip6.h> 55202181Sthompsa 56202181Sthompsa#include <dev/usb/usb.h> 57202181Sthompsa#include <dev/usb/usbdi.h> 58202181Sthompsa#include <dev/usb/usbdi_util.h> 59202181Sthompsa#include <dev/usb/usb_cdc.h> 60202181Sthompsa#include "usbdevs.h" 61202181Sthompsa#define USB_DEBUG_VAR uhso_debug 62202181Sthompsa#include <dev/usb/usb_debug.h> 63202181Sthompsa#include <dev/usb/usb_process.h> 64202181Sthompsa#include <dev/usb/usb_device.h> 65202181Sthompsa#include <dev/usb/usb_busdma.h> 66202181Sthompsa#include <dev/usb/serial/usb_serial.h> 67202181Sthompsa#include <dev/usb/usb_msctest.h> 68202181Sthompsa 69202181Sthompsastruct uhso_tty { 70202181Sthompsa struct uhso_softc *ht_sc; 71202181Sthompsa struct usb_xfer *ht_xfer[3]; 72202181Sthompsa int ht_muxport; 73202181Sthompsa int ht_open; 74202181Sthompsa char ht_name[32]; 75202181Sthompsa}; 76202181Sthompsa 77202181Sthompsastruct uhso_softc { 78202181Sthompsa device_t sc_dev; 79202181Sthompsa struct usb_device *sc_udev; 80202181Sthompsa struct mtx sc_mtx; 81202181Sthompsa uint32_t sc_type; 82202181Sthompsa 83202181Sthompsa struct usb_xfer *sc_xfer[3]; 84202181Sthompsa uint8_t sc_iface_no; 85202181Sthompsa uint8_t sc_iface_index; 86202181Sthompsa 87202181Sthompsa /* Control pipe */ 88202181Sthompsa struct usb_xfer * sc_ctrl_xfer[2]; 89202181Sthompsa uint8_t sc_ctrl_iface_no; 90202181Sthompsa 91202181Sthompsa /* Network */ 92202181Sthompsa struct usb_xfer *sc_if_xfer[2]; 93202181Sthompsa struct ifnet *sc_ifp; 94202181Sthompsa struct mbuf *sc_mwait; /* partial packet */ 95202181Sthompsa size_t sc_waitlen; /* no. of outstanding bytes */ 96202181Sthompsa struct ifqueue sc_rxq; 97202181Sthompsa struct callout sc_c; 98202181Sthompsa 99202181Sthompsa /* TTY related structures */ 100202181Sthompsa struct ucom_super_softc sc_super_ucom; 101202181Sthompsa int sc_ttys; 102202181Sthompsa struct uhso_tty *sc_tty; 103202181Sthompsa struct ucom_softc *sc_ucom; 104202181Sthompsa int sc_msr; 105202181Sthompsa int sc_lsr; 106202181Sthompsa int sc_line; 107202181Sthompsa}; 108202181Sthompsa 109202181Sthompsa 110202181Sthompsa#define UHSO_MAX_MTU 2048 111202181Sthompsa 112202181Sthompsa/* 113202181Sthompsa * There are mainly two type of cards floating around. 114202181Sthompsa * The first one has 2,3 or 4 interfaces with a multiplexed serial port 115202181Sthompsa * and packet interface on the first interface and bulk serial ports 116202181Sthompsa * on the others. 117202181Sthompsa * The second type of card has several other interfaces, their purpose 118202181Sthompsa * can be detected during run-time. 119202181Sthompsa */ 120202181Sthompsa#define UHSO_IFACE_SPEC(usb_type, port, port_type) \ 121202181Sthompsa (((usb_type) << 24) | ((port) << 16) | (port_type)) 122202181Sthompsa 123202181Sthompsa#define UHSO_IFACE_USB_TYPE(x) ((x >> 24) & 0xff) 124202181Sthompsa#define UHSO_IFACE_PORT(x) ((x >> 16) & 0xff) 125202181Sthompsa#define UHSO_IFACE_PORT_TYPE(x) (x & 0xff) 126202181Sthompsa 127202181Sthompsa/* 128202181Sthompsa * USB interface types 129202181Sthompsa */ 130202181Sthompsa#define UHSO_IF_NET 0x01 /* Network packet interface */ 131202181Sthompsa#define UHSO_IF_MUX 0x02 /* Multiplexed serial port */ 132202181Sthompsa#define UHSO_IF_BULK 0x04 /* Bulk interface */ 133202181Sthompsa 134202181Sthompsa/* 135202181Sthompsa * Port types 136202181Sthompsa */ 137202181Sthompsa#define UHSO_PORT_UNKNOWN 0x00 138202181Sthompsa#define UHSO_PORT_SERIAL 0x01 /* Serial port */ 139202181Sthompsa#define UHSO_PORT_NETWORK 0x02 /* Network packet interface */ 140202181Sthompsa 141202181Sthompsa/* 142202181Sthompsa * Multiplexed serial port destination sub-port names 143202181Sthompsa */ 144202181Sthompsa#define UHSO_MPORT_TYPE_CTL 0x00 /* Control port */ 145202181Sthompsa#define UHSO_MPORT_TYPE_APP 0x01 /* Application */ 146202181Sthompsa#define UHSO_MPORT_TYPE_PCSC 0x02 147202181Sthompsa#define UHSO_MPORT_TYPE_GPS 0x03 148202181Sthompsa#define UHSO_MPORT_TYPE_APP2 0x04 149202181Sthompsa#define UHSO_MPORT_TYPE_MAX UHSO_MPORT_TYPE_APP2 150202181Sthompsa#define UHSO_MPORT_TYPE_NOMAX 8 /* Max number of mux ports */ 151202181Sthompsa 152202181Sthompsa/* 153202181Sthompsa * Port definitions 154202181Sthompsa */ 155202181Sthompsa#define UHSO_PORT_TYPE_CTL 0x01 156202181Sthompsa#define UHSO_PORT_TYPE_APP 0x02 157202181Sthompsa#define UHSO_PORT_TYPE_APP2 0x03 158202181Sthompsa#define UHSO_PORT_TYPE_MODEM 0x04 159202181Sthompsa#define UHSO_PORT_TYPE_NETWORK 0x05 160202181Sthompsa#define UHSO_PORT_TYPE_DIAG 0x06 161202181Sthompsa#define UHSO_PORT_TYPE_DIAG2 0x07 162202181Sthompsa#define UHSO_PORT_TYPE_GPS 0x08 163202181Sthompsa#define UHSO_PORT_TYPE_GPSCTL 0x09 164202181Sthompsa#define UHSO_PORT_TYPE_PCSC 0x0a 165202181Sthompsa#define UHSO_PORT_TYPE_MSD 0x0b 166202181Sthompsa#define UHSO_PORT_TYPE_VOICE 0x0c 167202181Sthompsa#define UHSO_PORT_TYPE_MAX 0x0c 168202181Sthompsa 169202181Sthompsastatic eventhandler_tag uhso_etag; 170202181Sthompsa 171202181Sthompsa/* Overall port type */ 172202181Sthompsastatic char *uhso_port[] = { 173202181Sthompsa "Unknown", 174202181Sthompsa "Serial", 175202181Sthompsa "Network", 176202181Sthompsa "Network/Serial" 177202181Sthompsa}; 178202181Sthompsa 179202181Sthompsa/* Map between interface port type read from device and description type */ 180202181Sthompsastatic char uhso_port_map[] = { 181202181Sthompsa 0, 182202181Sthompsa UHSO_PORT_TYPE_DIAG, 183202181Sthompsa UHSO_PORT_TYPE_GPS, 184202181Sthompsa UHSO_PORT_TYPE_GPSCTL, 185202181Sthompsa UHSO_PORT_TYPE_APP, 186202181Sthompsa UHSO_PORT_TYPE_APP2, 187202181Sthompsa UHSO_PORT_TYPE_CTL, 188202181Sthompsa UHSO_PORT_TYPE_NETWORK, 189202181Sthompsa UHSO_PORT_TYPE_MODEM, 190202181Sthompsa UHSO_PORT_TYPE_MSD, 191202181Sthompsa UHSO_PORT_TYPE_PCSC, 192202181Sthompsa UHSO_PORT_TYPE_VOICE 193202181Sthompsa}; 194202181Sthompsastatic char uhso_port_map_max = sizeof(uhso_port_map) / sizeof(char); 195202181Sthompsa 196202181Sthompsastatic char uhso_mux_port_map[] = { 197202181Sthompsa UHSO_PORT_TYPE_CTL, 198202181Sthompsa UHSO_PORT_TYPE_APP, 199202181Sthompsa UHSO_PORT_TYPE_PCSC, 200202181Sthompsa UHSO_PORT_TYPE_GPS, 201202181Sthompsa UHSO_PORT_TYPE_APP2 202202181Sthompsa}; 203202181Sthompsa 204202181Sthompsastatic char *uhso_port_type[] = { 205202181Sthompsa "Unknown", 206202181Sthompsa "Control", 207202181Sthompsa "Application", 208202181Sthompsa "Application (Secondary)", 209202181Sthompsa "Modem", 210202181Sthompsa "Network", 211202181Sthompsa "Diagnostic", 212202181Sthompsa "Diagnostic (Secondary)", 213202181Sthompsa "GPS", 214202181Sthompsa "GPS Control", 215202181Sthompsa "PC Smartcard", 216202181Sthompsa "MSD", 217202181Sthompsa "Voice", 218202181Sthompsa}; 219202181Sthompsa 220202181Sthompsastatic char *uhso_port_type_sysctl[] = { 221202181Sthompsa "unknown", 222202181Sthompsa "control", 223202181Sthompsa "application", 224202181Sthompsa "application", 225202181Sthompsa "modem", 226202181Sthompsa "network", 227202181Sthompsa "diagnostic", 228202181Sthompsa "diagnostic", 229202181Sthompsa "gps", 230202181Sthompsa "gps_control", 231202181Sthompsa "pcsc", 232202181Sthompsa "msd", 233202181Sthompsa "voice", 234202181Sthompsa}; 235202181Sthompsa 236202181Sthompsa 237202181Sthompsa#define UHSO_STATIC_IFACE 0x01 238202181Sthompsa#define UHSO_AUTO_IFACE 0x02 239202181Sthompsa 240202181Sthompsastatic const struct usb_device_id uhso_devs[] = { 241202181Sthompsa#define UHSO_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } 242202181Sthompsa /* Option GlobeSurfer iCON 7.2 */ 243202181Sthompsa UHSO_DEV(OPTION, GSICON72, UHSO_STATIC_IFACE), 244202181Sthompsa /* Option iCON 225 */ 245202181Sthompsa UHSO_DEV(OPTION, GTHSDPA, UHSO_STATIC_IFACE), 246202181Sthompsa /* Option GlobeSurfer iCON HSUPA */ 247202181Sthompsa UHSO_DEV(OPTION, GSICONHSUPA, UHSO_STATIC_IFACE), 248202181Sthompsa /* Option GlobeTrotter HSUPA */ 249202181Sthompsa UHSO_DEV(OPTION, GTHSUPA, UHSO_STATIC_IFACE), 250202181Sthompsa /* GE40x */ 251202181Sthompsa UHSO_DEV(OPTION, GE40X, UHSO_AUTO_IFACE), 252202181Sthompsa UHSO_DEV(OPTION, GE40X_1, UHSO_AUTO_IFACE), 253202181Sthompsa UHSO_DEV(OPTION, GE40X_2, UHSO_AUTO_IFACE), 254202181Sthompsa UHSO_DEV(OPTION, GE40X_3, UHSO_AUTO_IFACE), 255202181Sthompsa /* Option GlobeSurfer iCON 401 */ 256202181Sthompsa UHSO_DEV(OPTION, ICON401, UHSO_AUTO_IFACE), 257202181Sthompsa /* Option GlobeTrotter Module 382 */ 258202181Sthompsa UHSO_DEV(OPTION, GMT382, UHSO_AUTO_IFACE), 259202181Sthompsa /* Option iCON EDGE */ 260202181Sthompsa UHSO_DEV(OPTION, ICONEDGE, UHSO_STATIC_IFACE), 261202181Sthompsa /* Option Module HSxPA */ 262202181Sthompsa UHSO_DEV(OPTION, MODHSXPA, UHSO_STATIC_IFACE), 263202181Sthompsa /* Option iCON 321 */ 264202181Sthompsa UHSO_DEV(OPTION, ICON321, UHSO_STATIC_IFACE), 265202181Sthompsa /* Option iCON 322 */ 266202181Sthompsa UHSO_DEV(OPTION, GTICON322, UHSO_STATIC_IFACE) 267202181Sthompsa#undef UHSO_DEV 268202181Sthompsa}; 269202181Sthompsa 270202181SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, uhso, CTLFLAG_RW, 0, "USB uhso"); 271202181Sthompsa 272202181Sthompsa#ifdef USB_DEBUG 273202181Sthompsa#ifdef UHSO_DEBUG 274202181Sthompsastatic int uhso_debug = UHSO_DEBUG; 275202181Sthompsa#else 276202181Sthompsastatic int uhso_debug = -1; 277202181Sthompsa#endif 278202181Sthompsa 279202181SthompsaSYSCTL_INT(_hw_usb_uhso, OID_AUTO, debug, CTLFLAG_RW, 280202181Sthompsa &uhso_debug, 0, "Debug level"); 281202181Sthompsa 282202181Sthompsa#define UHSO_DPRINTF(n, x, ...) {\ 283202181Sthompsa if (uhso_debug >= n) {\ 284202181Sthompsa printf("%s: " x, __func__, ##__VA_ARGS__);\ 285202181Sthompsa }\ 286202181Sthompsa} 287202181Sthompsa#else 288202181Sthompsa#define UHSO_DPRINTF(n, x, ...) 289202181Sthompsa#endif 290202181Sthompsa 291202181Sthompsa#ifdef UHSO_DEBUG_HEXDUMP 292202181Sthompsa# define UHSO_HEXDUMP(_buf, _len) do { \ 293202181Sthompsa { \ 294202181Sthompsa size_t __tmp; \ 295202181Sthompsa const char *__buf = (const char *)_buf; \ 296202181Sthompsa for (__tmp = 0; __tmp < _len; __tmp++) \ 297202181Sthompsa printf("%02hhx ", *__buf++); \ 298202181Sthompsa printf("\n"); \ 299202181Sthompsa } \ 300202181Sthompsa} while(0) 301202181Sthompsa#else 302202181Sthompsa# define UHSO_HEXDUMP(_buf, _len) 303202181Sthompsa#endif 304202181Sthompsa 305202181Sthompsaenum { 306202181Sthompsa UHSO_MUX_ENDPT_INTR = 0, 307202181Sthompsa UHSO_MUX_ENDPT_MAX 308202181Sthompsa}; 309202181Sthompsa 310202181Sthompsaenum { 311202181Sthompsa UHSO_CTRL_READ = 0, 312202181Sthompsa UHSO_CTRL_WRITE, 313202181Sthompsa UHSO_CTRL_MAX 314202181Sthompsa}; 315202181Sthompsa 316202181Sthompsaenum { 317202181Sthompsa UHSO_IFNET_READ = 0, 318202181Sthompsa UHSO_IFNET_WRITE, 319202181Sthompsa UHSO_IFNET_MAX 320202181Sthompsa}; 321202181Sthompsa 322202181Sthompsaenum { 323202181Sthompsa UHSO_BULK_ENDPT_READ = 0, 324202181Sthompsa UHSO_BULK_ENDPT_WRITE, 325202181Sthompsa UHSO_BULK_ENDPT_INTR, 326202181Sthompsa UHSO_BULK_ENDPT_MAX 327202181Sthompsa}; 328202181Sthompsa 329202181Sthompsastatic usb_callback_t uhso_mux_intr_callback; 330202181Sthompsastatic usb_callback_t uhso_mux_read_callback; 331202181Sthompsastatic usb_callback_t uhso_mux_write_callback; 332202181Sthompsastatic usb_callback_t uhso_bs_read_callback; 333202181Sthompsastatic usb_callback_t uhso_bs_write_callback; 334202181Sthompsastatic usb_callback_t uhso_bs_intr_callback; 335202181Sthompsastatic usb_callback_t uhso_ifnet_read_callback; 336202181Sthompsastatic usb_callback_t uhso_ifnet_write_callback; 337202181Sthompsa 338202181Sthompsastatic const struct usb_config uhso_ctrl_config[UHSO_CTRL_MAX] = { 339202181Sthompsa [UHSO_CTRL_READ] = { 340202181Sthompsa .type = UE_CONTROL, 341202181Sthompsa .endpoint = 0x00, 342202181Sthompsa .direction = UE_DIR_ANY, 343202181Sthompsa .flags = { .pipe_bof = 1, .short_xfer_ok = 1 }, 344202181Sthompsa .bufsize = sizeof(struct usb_device_request) + 1024, 345202181Sthompsa .callback = &uhso_mux_read_callback 346202181Sthompsa }, 347202181Sthompsa 348202181Sthompsa [UHSO_CTRL_WRITE] = { 349202181Sthompsa .type = UE_CONTROL, 350202181Sthompsa .endpoint = 0x00, 351202181Sthompsa .direction = UE_DIR_ANY, 352202181Sthompsa .flags = { .pipe_bof = 1, .force_short_xfer = 1 }, 353202181Sthompsa .bufsize = sizeof(struct usb_device_request) + 1024, 354202181Sthompsa .timeout = 1000, 355202181Sthompsa .callback = &uhso_mux_write_callback 356202181Sthompsa } 357202181Sthompsa}; 358202181Sthompsa 359202181Sthompsastatic const struct usb_config uhso_mux_config[UHSO_MUX_ENDPT_MAX] = { 360202181Sthompsa [UHSO_MUX_ENDPT_INTR] = { 361202181Sthompsa .type = UE_INTERRUPT, 362202181Sthompsa .endpoint = UE_ADDR_ANY, 363202181Sthompsa .direction = UE_DIR_IN, 364202181Sthompsa .flags = { .short_xfer_ok = 1 }, 365202181Sthompsa .bufsize = 0, 366202181Sthompsa .callback = &uhso_mux_intr_callback, 367202181Sthompsa } 368202181Sthompsa}; 369202181Sthompsa 370202181Sthompsastatic const struct usb_config uhso_ifnet_config[UHSO_IFNET_MAX] = { 371202181Sthompsa [UHSO_IFNET_READ] = { 372202181Sthompsa .type = UE_BULK, 373202181Sthompsa .endpoint = UE_ADDR_ANY, 374202181Sthompsa .direction = UE_DIR_IN, 375202181Sthompsa .flags = { .pipe_bof = 1, .short_xfer_ok = 1 }, 376202181Sthompsa .bufsize = MCLBYTES, 377202181Sthompsa .callback = &uhso_ifnet_read_callback 378202181Sthompsa }, 379202181Sthompsa [UHSO_IFNET_WRITE] = { 380202181Sthompsa .type = UE_BULK, 381202181Sthompsa .endpoint = UE_ADDR_ANY, 382202181Sthompsa .direction = UE_DIR_OUT, 383202181Sthompsa .flags = { .pipe_bof = 1, .force_short_xfer = 1 }, 384202181Sthompsa .bufsize = MCLBYTES, 385202181Sthompsa .timeout = 5 * USB_MS_HZ, 386202181Sthompsa .callback = &uhso_ifnet_write_callback 387202181Sthompsa } 388202181Sthompsa}; 389202181Sthompsa 390202181Sthompsastatic const struct usb_config uhso_bs_config[UHSO_BULK_ENDPT_MAX] = { 391202181Sthompsa [UHSO_BULK_ENDPT_READ] = { 392202181Sthompsa .type = UE_BULK, 393202181Sthompsa .endpoint = UE_ADDR_ANY, 394202181Sthompsa .direction = UE_DIR_IN, 395202181Sthompsa .flags = { .pipe_bof = 1, .short_xfer_ok = 1 }, 396202181Sthompsa .bufsize = 4096, 397202181Sthompsa .callback = &uhso_bs_read_callback 398202181Sthompsa }, 399202181Sthompsa 400202181Sthompsa [UHSO_BULK_ENDPT_WRITE] = { 401202181Sthompsa .type = UE_BULK, 402202181Sthompsa .endpoint = UE_ADDR_ANY, 403202181Sthompsa .direction = UE_DIR_OUT, 404202181Sthompsa .flags = { .pipe_bof = 1, .force_short_xfer = 1 }, 405202181Sthompsa .bufsize = 8192, 406202181Sthompsa .callback = &uhso_bs_write_callback 407202181Sthompsa }, 408202181Sthompsa 409202181Sthompsa [UHSO_BULK_ENDPT_INTR] = { 410202181Sthompsa .type = UE_INTERRUPT, 411202181Sthompsa .endpoint = UE_ADDR_ANY, 412202181Sthompsa .direction = UE_DIR_IN, 413202181Sthompsa .flags = { .short_xfer_ok = 1 }, 414202181Sthompsa .bufsize = 0, 415202181Sthompsa .callback = &uhso_bs_intr_callback, 416202181Sthompsa } 417202181Sthompsa}; 418202181Sthompsa 419202181Sthompsastatic int uhso_probe_iface(struct uhso_softc *, int, 420202181Sthompsa int (*probe)(struct uhso_softc *, int)); 421202181Sthompsastatic int uhso_probe_iface_auto(struct uhso_softc *, int); 422202181Sthompsastatic int uhso_probe_iface_static(struct uhso_softc *, int); 423202181Sthompsa 424202181Sthompsastatic int uhso_attach_muxserial(struct uhso_softc *, struct usb_interface *, 425202181Sthompsa int type); 426202181Sthompsastatic int uhso_attach_bulkserial(struct uhso_softc *, struct usb_interface *, 427202181Sthompsa int type); 428202181Sthompsastatic int uhso_attach_ifnet(struct uhso_softc *, struct usb_interface *, 429202181Sthompsa int type); 430202181Sthompsastatic void uhso_test_autoinst(void *, struct usb_device *, 431202181Sthompsa struct usb_attach_arg *); 432202181Sthompsastatic int uhso_driver_loaded(struct module *, int, void *); 433202181Sthompsa 434202181Sthompsastatic void uhso_ucom_start_read(struct ucom_softc *); 435202181Sthompsastatic void uhso_ucom_stop_read(struct ucom_softc *); 436202181Sthompsastatic void uhso_ucom_start_write(struct ucom_softc *); 437202181Sthompsastatic void uhso_ucom_stop_write(struct ucom_softc *); 438202181Sthompsastatic void uhso_ucom_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *); 439202181Sthompsastatic void uhso_ucom_cfg_set_dtr(struct ucom_softc *, uint8_t); 440202181Sthompsastatic void uhso_ucom_cfg_set_rts(struct ucom_softc *, uint8_t); 441202181Sthompsa 442202181Sthompsastatic void uhso_if_init(void *); 443202181Sthompsastatic void uhso_if_start(struct ifnet *); 444202181Sthompsastatic void uhso_if_stop(struct uhso_softc *); 445202181Sthompsastatic int uhso_if_ioctl(struct ifnet *, u_long, caddr_t); 446202181Sthompsastatic int uhso_if_output(struct ifnet *, struct mbuf *, struct sockaddr *, 447202181Sthompsa struct route *); 448202181Sthompsastatic void uhso_if_rxflush(void *); 449202181Sthompsa 450202181Sthompsastatic device_probe_t uhso_probe; 451202181Sthompsastatic device_attach_t uhso_attach; 452202181Sthompsastatic device_detach_t uhso_detach; 453202181Sthompsa 454202181Sthompsastatic device_method_t uhso_methods[] = { 455202181Sthompsa DEVMETHOD(device_probe, uhso_probe), 456202181Sthompsa DEVMETHOD(device_attach, uhso_attach), 457202181Sthompsa DEVMETHOD(device_detach, uhso_detach), 458202181Sthompsa { 0, 0 } 459202181Sthompsa}; 460202181Sthompsa 461202181Sthompsastatic driver_t uhso_driver = { 462202181Sthompsa "uhso", 463202181Sthompsa uhso_methods, 464202181Sthompsa sizeof(struct uhso_softc) 465202181Sthompsa}; 466202181Sthompsa 467202181Sthompsastatic devclass_t uhso_devclass; 468202181SthompsaDRIVER_MODULE(uhso, uhub, uhso_driver, uhso_devclass, uhso_driver_loaded, 0); 469202181SthompsaMODULE_DEPEND(uhso, ucom, 1, 1, 1); 470202181SthompsaMODULE_DEPEND(uhso, usb, 1, 1, 1); 471202181SthompsaMODULE_VERSION(uhso, 1); 472202181Sthompsa 473202181Sthompsastatic struct ucom_callback uhso_ucom_callback = { 474202181Sthompsa .ucom_cfg_get_status = &uhso_ucom_cfg_get_status, 475202181Sthompsa .ucom_cfg_set_dtr = &uhso_ucom_cfg_set_dtr, 476202181Sthompsa .ucom_cfg_set_rts = &uhso_ucom_cfg_set_rts, 477202181Sthompsa .ucom_start_read = uhso_ucom_start_read, 478202181Sthompsa .ucom_stop_read = uhso_ucom_stop_read, 479202181Sthompsa .ucom_start_write = uhso_ucom_start_write, 480202181Sthompsa .ucom_stop_write = uhso_ucom_stop_write 481202181Sthompsa}; 482202181Sthompsa 483202181Sthompsastatic int 484202181Sthompsauhso_probe(device_t self) 485202181Sthompsa{ 486202181Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 487202181Sthompsa 488202181Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 489202181Sthompsa return (ENXIO); 490202181Sthompsa if (uaa->info.bConfigIndex != 0) 491202181Sthompsa return (ENXIO); 492202181Sthompsa if (uaa->device->ddesc.bDeviceClass != 0xff) 493202181Sthompsa return (ENXIO); 494202181Sthompsa 495202181Sthompsa return (usbd_lookup_id_by_uaa(uhso_devs, sizeof(uhso_devs), uaa)); 496202181Sthompsa} 497202181Sthompsa 498202181Sthompsastatic int 499202181Sthompsauhso_attach(device_t self) 500202181Sthompsa{ 501202181Sthompsa struct uhso_softc *sc = device_get_softc(self); 502202181Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 503202181Sthompsa struct usb_config_descriptor *cd; 504202181Sthompsa struct usb_interface_descriptor *id; 505202181Sthompsa struct sysctl_ctx_list *sctx; 506202181Sthompsa struct sysctl_oid *soid; 507202181Sthompsa struct sysctl_oid *tree, *tty_node; 508202181Sthompsa struct ucom_softc *ucom; 509202181Sthompsa struct uhso_tty *ht; 510202181Sthompsa int i, error, port; 511202181Sthompsa void *probe_f; 512202181Sthompsa usb_error_t uerr; 513202181Sthompsa char *desc; 514202181Sthompsa 515202181Sthompsa device_set_usb_desc(self); 516202181Sthompsa 517202181Sthompsa UHSO_DPRINTF(0, "Device is in modem mode, devClass=%x\n", 518202181Sthompsa uaa->device->ddesc.bDeviceClass); 519202181Sthompsa 520202181Sthompsa sc->sc_dev = self; 521202181Sthompsa sc->sc_udev = uaa->device; 522202181Sthompsa mtx_init(&sc->sc_mtx, "uhso", NULL, MTX_DEF); 523202181Sthompsa 524202181Sthompsa sc->sc_ucom = NULL; 525202181Sthompsa sc->sc_ttys = 0; 526202181Sthompsa 527202181Sthompsa cd = usbd_get_config_descriptor(uaa->device); 528202181Sthompsa id = usbd_get_interface_descriptor(uaa->iface); 529202181Sthompsa sc->sc_ctrl_iface_no = id->bInterfaceNumber; 530202181Sthompsa 531202181Sthompsa sc->sc_iface_no = uaa->info.bIfaceNum; 532202181Sthompsa sc->sc_iface_index = uaa->info.bIfaceIndex; 533202181Sthompsa 534202181Sthompsa /* Setup control pipe */ 535202181Sthompsa uerr = usbd_transfer_setup(uaa->device, 536202181Sthompsa &sc->sc_iface_index, sc->sc_ctrl_xfer, 537202181Sthompsa uhso_ctrl_config, UHSO_CTRL_MAX, sc, &sc->sc_mtx); 538202181Sthompsa if (uerr) { 539202181Sthompsa device_printf(self, "Failed to setup control pipe: %s\n", 540202181Sthompsa usbd_errstr(uerr)); 541202181Sthompsa goto out; 542202181Sthompsa } 543202181Sthompsa 544202181Sthompsa if (USB_GET_DRIVER_INFO(uaa) == UHSO_STATIC_IFACE) 545202181Sthompsa probe_f = uhso_probe_iface_static; 546202181Sthompsa else if (USB_GET_DRIVER_INFO(uaa) == UHSO_AUTO_IFACE) 547202181Sthompsa probe_f = uhso_probe_iface_auto; 548202181Sthompsa else 549202181Sthompsa goto out; 550202181Sthompsa 551202181Sthompsa error = uhso_probe_iface(sc, uaa->info.bIfaceNum, probe_f); 552202181Sthompsa if (error != 0) 553202181Sthompsa goto out; 554202181Sthompsa 555202181Sthompsa 556202181Sthompsa sctx = device_get_sysctl_ctx(sc->sc_dev); 557202181Sthompsa soid = device_get_sysctl_tree(sc->sc_dev); 558202181Sthompsa 559202181Sthompsa SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "type", 560202181Sthompsa CTLFLAG_RD, uhso_port[UHSO_IFACE_PORT(sc->sc_type)], 0, 561202181Sthompsa "Port available at this interface"); 562202181Sthompsa 563202181Sthompsa if (sc->sc_ttys > 0) { 564202181Sthompsa SYSCTL_ADD_INT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "ports", 565202181Sthompsa CTLFLAG_RD, &sc->sc_ttys, 0, "Number of attached serial ports"); 566202181Sthompsa 567202181Sthompsa tree = SYSCTL_ADD_NODE(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, 568202181Sthompsa "port", CTLFLAG_RD, NULL, "Serial ports"); 569202181Sthompsa } 570202181Sthompsa 571202181Sthompsa for (i = 0; i < sc->sc_ttys; i++) { 572202181Sthompsa ht = &sc->sc_tty[i]; 573202181Sthompsa ucom = &sc->sc_ucom[i]; 574202181Sthompsa 575202181Sthompsa 576202181Sthompsa if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_MUX) 577202181Sthompsa port = uhso_mux_port_map[ht->ht_muxport]; 578202181Sthompsa else 579202181Sthompsa port = UHSO_IFACE_PORT_TYPE(sc->sc_type); 580202181Sthompsa 581202181Sthompsa desc = uhso_port_type_sysctl[port]; 582202181Sthompsa 583202181Sthompsa tty_node = SYSCTL_ADD_NODE(sctx, SYSCTL_CHILDREN(tree), OID_AUTO, 584202181Sthompsa desc, CTLFLAG_RD, NULL, ""); 585202181Sthompsa 586202181Sthompsa ht->ht_name[0] = 0; 587202181Sthompsa if (sc->sc_ttys == 1) 588202181Sthompsa snprintf(ht->ht_name, 32, "cuaU%d", ucom->sc_unit); 589202181Sthompsa else { 590202181Sthompsa snprintf(ht->ht_name, 32, "cuaU%d.%d", 591202181Sthompsa ucom->sc_unit - ucom->sc_local_unit, 592202181Sthompsa ucom->sc_local_unit); 593202181Sthompsa } 594202181Sthompsa 595202181Sthompsa desc = uhso_port_type[port]; 596202181Sthompsa SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(tty_node), OID_AUTO, 597202181Sthompsa "tty", CTLFLAG_RD, ht->ht_name, 0, ""); 598202181Sthompsa SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(tty_node), OID_AUTO, 599202181Sthompsa "desc", CTLFLAG_RD, desc, 0, ""); 600202181Sthompsa 601202181Sthompsa if (bootverbose) 602202181Sthompsa device_printf(sc->sc_dev, 603202181Sthompsa "\"%s\" port at %s\n", desc, ht->ht_name); 604202181Sthompsa } 605202181Sthompsa 606202181Sthompsa return (0); 607202181Sthompsaout: 608202181Sthompsa uhso_detach(sc->sc_dev); 609202181Sthompsa return (ENXIO); 610202181Sthompsa 611202181Sthompsa} 612202181Sthompsa 613202181Sthompsastatic int 614202181Sthompsauhso_detach(device_t self) 615202181Sthompsa{ 616202181Sthompsa struct uhso_softc *sc = device_get_softc(self); 617202181Sthompsa int i; 618202181Sthompsa 619202181Sthompsa usbd_transfer_unsetup(sc->sc_xfer, 3); 620202181Sthompsa usbd_transfer_unsetup(sc->sc_ctrl_xfer, UHSO_CTRL_MAX); 621202181Sthompsa if (sc->sc_ttys > 0) { 622202181Sthompsa ucom_detach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_ttys); 623202181Sthompsa 624202181Sthompsa for (i = 0; i < sc->sc_ttys; i++) { 625202181Sthompsa if (sc->sc_tty[i].ht_muxport != -1) { 626202181Sthompsa usbd_transfer_unsetup(sc->sc_tty[i].ht_xfer, 627202181Sthompsa UHSO_CTRL_MAX); 628202181Sthompsa } 629202181Sthompsa } 630202181Sthompsa 631202181Sthompsa free(sc->sc_tty, M_USBDEV); 632202181Sthompsa free(sc->sc_ucom, M_USBDEV); 633202181Sthompsa } 634202181Sthompsa 635202181Sthompsa if (sc->sc_ifp != NULL) { 636202181Sthompsa 637202181Sthompsa callout_drain(&sc->sc_c); 638202181Sthompsa 639202181Sthompsa mtx_lock(&sc->sc_mtx); 640202181Sthompsa uhso_if_stop(sc); 641202181Sthompsa bpfdetach(sc->sc_ifp); 642202181Sthompsa if_detach(sc->sc_ifp); 643202181Sthompsa if_free(sc->sc_ifp); 644202181Sthompsa mtx_unlock(&sc->sc_mtx); 645202181Sthompsa 646202181Sthompsa usbd_transfer_unsetup(sc->sc_if_xfer, UHSO_IFNET_MAX); 647202181Sthompsa } 648202181Sthompsa 649202181Sthompsa mtx_destroy(&sc->sc_mtx); 650202181Sthompsa 651202181Sthompsa return (0); 652202181Sthompsa} 653202181Sthompsa 654202181Sthompsastatic void 655202181Sthompsauhso_test_autoinst(void *arg, struct usb_device *udev, 656202181Sthompsa struct usb_attach_arg *uaa) 657202181Sthompsa{ 658202181Sthompsa struct usb_interface *iface; 659202181Sthompsa struct usb_interface_descriptor *id; 660202181Sthompsa 661202181Sthompsa if (uaa->dev_state != UAA_DEV_READY) 662202181Sthompsa return; 663202181Sthompsa 664202181Sthompsa iface = usbd_get_iface(udev, 0); 665202181Sthompsa if (iface == NULL) 666202181Sthompsa return; 667202181Sthompsa id = iface->idesc; 668202181Sthompsa if (id == NULL || id->bInterfaceClass != UICLASS_MASS) 669202181Sthompsa return; 670202181Sthompsa if (usbd_lookup_id_by_uaa(uhso_devs, sizeof(uhso_devs), uaa)) 671202181Sthompsa return; /* no device match */ 672202181Sthompsa 673202181Sthompsa if (usb_msc_eject(udev, 0, MSC_EJECT_REZERO) == 0) { 674202181Sthompsa /* success, mark the udev as disappearing */ 675202181Sthompsa uaa->dev_state = UAA_DEV_EJECTING; 676202181Sthompsa } 677202181Sthompsa} 678202181Sthompsa 679202181Sthompsastatic int 680202181Sthompsauhso_driver_loaded(struct module *mod, int what, void *arg) 681202181Sthompsa{ 682202181Sthompsa switch (what) { 683202181Sthompsa case MOD_LOAD: 684202181Sthompsa /* register our autoinstall handler */ 685202181Sthompsa uhso_etag = EVENTHANDLER_REGISTER(usb_dev_configured, 686202181Sthompsa uhso_test_autoinst, NULL, EVENTHANDLER_PRI_ANY); 687202181Sthompsa break; 688202181Sthompsa case MOD_UNLOAD: 689202181Sthompsa EVENTHANDLER_DEREGISTER(usb_dev_configured, uhso_etag); 690202181Sthompsa break; 691202181Sthompsa default: 692202181Sthompsa return (EOPNOTSUPP); 693202181Sthompsa } 694202181Sthompsa return (0); 695202181Sthompsa} 696202181Sthompsa 697202181Sthompsastatic int uhso_probe_iface_auto(struct uhso_softc *sc, int index) 698202181Sthompsa{ 699202181Sthompsa struct usb_device_request req; 700202181Sthompsa usb_error_t uerr; 701202181Sthompsa uint16_t actlen = 0; 702202181Sthompsa char port; 703202181Sthompsa char buf[17] = {0}; 704202181Sthompsa 705202181Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 706202181Sthompsa req.bRequest = 0x86; 707202181Sthompsa USETW(req.wValue, 0); 708202181Sthompsa USETW(req.wIndex, 0); 709202181Sthompsa USETW(req.wLength, 17); 710202181Sthompsa 711202181Sthompsa uerr = usbd_do_request_flags(sc->sc_udev, NULL, &req, buf, 712202181Sthompsa 0, &actlen, USB_MS_HZ); 713202181Sthompsa if (uerr != 0) { 714202181Sthompsa device_printf(sc->sc_dev, "usbd_do_request_flags failed: %s\n", 715202181Sthompsa usbd_errstr(uerr)); 716202181Sthompsa return (0); 717202181Sthompsa } 718202181Sthompsa 719202181Sthompsa UHSO_DPRINTF(3, "actlen=%d\n", actlen); 720202181Sthompsa UHSO_HEXDUMP(buf, 17); 721202181Sthompsa 722202181Sthompsa if (index < 0 || index > 16) { 723202181Sthompsa UHSO_DPRINTF(0, "Index %d out of range\n", index); 724202181Sthompsa return (0); 725202181Sthompsa } 726202181Sthompsa 727202181Sthompsa UHSO_DPRINTF(3, "index=%d, type=%x\n", index, buf[index]); 728202181Sthompsa 729202181Sthompsa if (buf[index] >= uhso_port_map_max) 730202181Sthompsa port = 0; 731202181Sthompsa else 732202181Sthompsa port = uhso_port_map[(int)buf[index]]; 733202181Sthompsa 734202181Sthompsa if (port == UHSO_PORT_TYPE_NETWORK) 735202181Sthompsa return (UHSO_IFACE_SPEC(UHSO_IF_BULK, 736202181Sthompsa UHSO_PORT_NETWORK, port)); 737202181Sthompsa else if (port == UHSO_PORT_TYPE_VOICE) 738202181Sthompsa return (0); 739202181Sthompsa else 740202181Sthompsa return (UHSO_IFACE_SPEC(UHSO_IF_BULK, 741202181Sthompsa UHSO_PORT_SERIAL, port)); 742202181Sthompsa 743202181Sthompsa return (0); 744202181Sthompsa} 745202181Sthompsa 746202181Sthompsastatic int 747202181Sthompsauhso_probe_iface_static(struct uhso_softc *sc, int index) 748202181Sthompsa{ 749202181Sthompsa struct usb_config_descriptor *cd; 750202181Sthompsa 751202181Sthompsa cd = usbd_get_config_descriptor(sc->sc_udev); 752202181Sthompsa if (cd->bNumInterface <= 3) { 753202181Sthompsa switch (index) { 754202181Sthompsa case 0: 755202181Sthompsa return UHSO_IFACE_SPEC(UHSO_IF_NET | UHSO_IF_MUX, 756202181Sthompsa UHSO_PORT_SERIAL | UHSO_PORT_NETWORK, 0); 757202181Sthompsa case 1: 758202181Sthompsa return UHSO_IFACE_SPEC(UHSO_IF_BULK, 759202181Sthompsa UHSO_PORT_SERIAL, UHSO_PORT_TYPE_DIAG); 760202181Sthompsa case 2: 761202181Sthompsa return UHSO_IFACE_SPEC(UHSO_IF_BULK, 762202181Sthompsa UHSO_PORT_SERIAL, UHSO_PORT_TYPE_MODEM); 763202181Sthompsa } 764202181Sthompsa } 765202181Sthompsa else { 766202181Sthompsa switch (index) { 767202181Sthompsa case 0: 768202181Sthompsa return UHSO_IFACE_SPEC(UHSO_IF_NET | UHSO_IF_MUX, 769202181Sthompsa UHSO_PORT_SERIAL | UHSO_PORT_NETWORK, 0); 770202181Sthompsa case 1: 771202181Sthompsa return UHSO_IFACE_SPEC(UHSO_IF_BULK, 772202181Sthompsa UHSO_PORT_SERIAL, UHSO_PORT_TYPE_DIAG2); 773202181Sthompsa case 2: 774202181Sthompsa return UHSO_IFACE_SPEC(UHSO_IF_BULK, 775202181Sthompsa UHSO_PORT_SERIAL, UHSO_PORT_TYPE_MODEM); 776202181Sthompsa case 3: 777202181Sthompsa return UHSO_IFACE_SPEC(UHSO_IF_BULK, 778202181Sthompsa UHSO_PORT_SERIAL, UHSO_PORT_TYPE_DIAG); 779202181Sthompsa } 780202181Sthompsa } 781202181Sthompsa return (0); 782202181Sthompsa} 783202181Sthompsa 784202181Sthompsastatic int 785202181Sthompsauhso_probe_iface(struct uhso_softc *sc, int index, 786202181Sthompsa int (*probe)(struct uhso_softc *, int)) 787202181Sthompsa{ 788202181Sthompsa struct usb_interface *iface; 789202181Sthompsa int type, error, error0; 790202181Sthompsa 791202181Sthompsa UHSO_DPRINTF(1, "Probing for interface %d, cb=%p\n", index, probe); 792202181Sthompsa 793202181Sthompsa type = probe(sc, index); 794202181Sthompsa UHSO_DPRINTF(1, "Probe result %x\n", type); 795202181Sthompsa if (type <= 0) 796202181Sthompsa return (ENXIO); 797202181Sthompsa 798202181Sthompsa sc->sc_type = type; 799202181Sthompsa iface = usbd_get_iface(sc->sc_udev, index); 800202181Sthompsa 801202181Sthompsa if (UHSO_IFACE_USB_TYPE(type) & (UHSO_IF_MUX | UHSO_IF_NET)) { 802202181Sthompsa error0 = uhso_attach_muxserial(sc, iface, type); 803202181Sthompsa error = uhso_attach_ifnet(sc, iface, type); 804202181Sthompsa 805202181Sthompsa if (error0 && error) 806202181Sthompsa return (ENXIO); 807202181Sthompsa 808202181Sthompsa if (sc->sc_ttys > 0) { 809202181Sthompsa error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom, 810202181Sthompsa sc->sc_ttys, sc, &uhso_ucom_callback, &sc->sc_mtx); 811202181Sthompsa if (error) { 812202181Sthompsa device_printf(sc->sc_dev, "ucom_attach failed\n"); 813202181Sthompsa return (ENXIO); 814202181Sthompsa } 815202181Sthompsa } 816202181Sthompsa 817202181Sthompsa mtx_lock(&sc->sc_mtx); 818202181Sthompsa usbd_transfer_start(sc->sc_xfer[UHSO_MUX_ENDPT_INTR]); 819202181Sthompsa mtx_unlock(&sc->sc_mtx); 820202181Sthompsa } 821202181Sthompsa else if ((UHSO_IFACE_USB_TYPE(type) & UHSO_IF_BULK) && 822202181Sthompsa UHSO_IFACE_PORT(type) & UHSO_PORT_SERIAL) { 823202181Sthompsa 824202181Sthompsa error = uhso_attach_bulkserial(sc, iface, type); 825202181Sthompsa if (error) 826202181Sthompsa return (ENXIO); 827202181Sthompsa 828202181Sthompsa error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom, 829202181Sthompsa sc->sc_ttys, sc, &uhso_ucom_callback, &sc->sc_mtx); 830202181Sthompsa if (error) { 831202181Sthompsa device_printf(sc->sc_dev, "ucom_attach failed\n"); 832202181Sthompsa return (ENXIO); 833202181Sthompsa } 834202181Sthompsa } 835202181Sthompsa else { 836202181Sthompsa return (ENXIO); 837202181Sthompsa } 838202181Sthompsa 839202181Sthompsa return (0); 840202181Sthompsa} 841202181Sthompsa 842202181Sthompsastatic int 843202181Sthompsauhso_alloc_tty(struct uhso_softc *sc) 844202181Sthompsa{ 845202181Sthompsa 846202181Sthompsa sc->sc_ttys++; 847202181Sthompsa sc->sc_tty = reallocf(sc->sc_tty, sizeof(struct uhso_tty) * sc->sc_ttys, 848202181Sthompsa M_USBDEV, M_WAITOK | M_ZERO); 849202181Sthompsa if (sc->sc_tty == NULL) 850202181Sthompsa return (-1); 851202181Sthompsa 852202181Sthompsa sc->sc_ucom = reallocf(sc->sc_ucom, 853202181Sthompsa sizeof(struct ucom_softc) * sc->sc_ttys, M_USBDEV, M_WAITOK | M_ZERO); 854202181Sthompsa if (sc->sc_ucom == NULL) 855202181Sthompsa return (-1); 856202181Sthompsa 857202181Sthompsa sc->sc_tty[sc->sc_ttys - 1].ht_sc = sc; 858202181Sthompsa 859202181Sthompsa UHSO_DPRINTF(2, "Allocated TTY %d\n", sc->sc_ttys - 1); 860202181Sthompsa return (sc->sc_ttys - 1); 861202181Sthompsa} 862202181Sthompsa 863202181Sthompsa 864202181Sthompsastatic int 865202181Sthompsauhso_attach_muxserial(struct uhso_softc *sc, struct usb_interface *iface, 866202181Sthompsa int type) 867202181Sthompsa{ 868202181Sthompsa struct usb_descriptor *desc; 869202181Sthompsa int i, port, tty; 870202181Sthompsa usb_error_t uerr; 871202181Sthompsa 872202181Sthompsa /* 873202181Sthompsa * The class specific interface (type 0x24) descriptor subtype field 874202181Sthompsa * contains a bitmask that specifies which (and how many) ports that 875202181Sthompsa * are available through this multiplexed serial port. 876202181Sthompsa */ 877202181Sthompsa desc = usbd_find_descriptor(sc->sc_udev, NULL, 878202181Sthompsa iface->idesc->bInterfaceNumber, UDESC_CS_INTERFACE, 0xff, 0, 0); 879202181Sthompsa if (desc == NULL) { 880202181Sthompsa UHSO_DPRINTF(0, "Failed to find UDESC_CS_INTERFACE\n"); 881202181Sthompsa return (ENXIO); 882202181Sthompsa } 883202181Sthompsa 884202181Sthompsa UHSO_DPRINTF(1, "Mux port mask %x\n", desc->bDescriptorSubtype); 885202181Sthompsa if (desc->bDescriptorSubtype == 0) 886202181Sthompsa return (ENXIO); 887202181Sthompsa 888202181Sthompsa for (i = 0; i < 8; i++) { 889202181Sthompsa port = (1 << i); 890202181Sthompsa if ((port & desc->bDescriptorSubtype) == port) { 891202181Sthompsa UHSO_DPRINTF(2, "Found mux port %x (%d)\n", port, i); 892202181Sthompsa tty = uhso_alloc_tty(sc); 893202181Sthompsa if (tty < 0) 894202181Sthompsa return (ENOMEM); 895202181Sthompsa sc->sc_tty[tty].ht_muxport = i; 896202181Sthompsa uerr = usbd_transfer_setup(sc->sc_udev, 897202181Sthompsa &sc->sc_iface_index, sc->sc_tty[tty].ht_xfer, 898202181Sthompsa uhso_ctrl_config, UHSO_CTRL_MAX, sc, &sc->sc_mtx); 899202181Sthompsa if (uerr) { 900202181Sthompsa device_printf(sc->sc_dev, 901202181Sthompsa "Failed to setup control pipe: %s\n", 902202181Sthompsa usbd_errstr(uerr)); 903202181Sthompsa return (ENXIO); 904202181Sthompsa } 905202181Sthompsa } 906202181Sthompsa } 907202181Sthompsa 908202181Sthompsa uerr = usbd_transfer_setup(sc->sc_udev, 909202181Sthompsa &iface->idesc->bInterfaceNumber, sc->sc_xfer, 910202181Sthompsa uhso_mux_config, 1, sc, &sc->sc_mtx); 911202181Sthompsa if (uerr) 912202181Sthompsa return (ENXIO); 913202181Sthompsa 914202181Sthompsa return (0); 915202181Sthompsa} 916202181Sthompsa 917202181Sthompsastatic void 918202181Sthompsauhso_mux_intr_callback(struct usb_xfer *xfer, usb_error_t error) 919202181Sthompsa{ 920202181Sthompsa struct usb_page_cache *pc; 921202181Sthompsa struct usb_page_search res; 922202181Sthompsa struct uhso_softc *sc = usbd_xfer_softc(xfer); 923202181Sthompsa unsigned int i, mux; 924202181Sthompsa 925202181Sthompsa UHSO_DPRINTF(3, "status %d\n", USB_GET_STATE(xfer)); 926202181Sthompsa 927202181Sthompsa switch (USB_GET_STATE(xfer)) { 928202181Sthompsa case USB_ST_TRANSFERRED: 929202181Sthompsa /* 930202181Sthompsa * The multiplexed port number can be found at the first byte. 931202181Sthompsa * It contains a bit mask, we transform this in to an integer. 932202181Sthompsa */ 933202181Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 934202181Sthompsa usbd_get_page(pc, 0, &res); 935202181Sthompsa 936202181Sthompsa i = *((unsigned char *)res.buffer); 937202181Sthompsa mux = 0; 938202181Sthompsa while (i >>= 1) { 939202181Sthompsa mux++; 940202181Sthompsa } 941202181Sthompsa 942202181Sthompsa UHSO_DPRINTF(3, "mux port %d (%d)\n", mux, i); 943202181Sthompsa if (mux > UHSO_MPORT_TYPE_NOMAX) 944202181Sthompsa break; 945202181Sthompsa 946202181Sthompsa usbd_xfer_set_priv( 947202181Sthompsa sc->sc_tty[mux].ht_xfer[UHSO_CTRL_READ], 948202181Sthompsa &sc->sc_tty[mux]); 949202181Sthompsa usbd_transfer_start(sc->sc_tty[mux].ht_xfer[UHSO_CTRL_READ]); 950202181Sthompsa 951202181Sthompsa break; 952202181Sthompsa case USB_ST_SETUP: 953202181Sthompsatr_setup: 954202181Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 955202181Sthompsa usbd_transfer_submit(xfer); 956202181Sthompsa break; 957202181Sthompsa default: 958202181Sthompsa UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); 959202181Sthompsa if (error == USB_ERR_CANCELLED) 960202181Sthompsa break; 961202181Sthompsa 962202181Sthompsa usbd_xfer_set_stall(xfer); 963202181Sthompsa goto tr_setup; 964202181Sthompsa } 965202181Sthompsa 966202181Sthompsa} 967202181Sthompsa 968202181Sthompsastatic void 969202181Sthompsauhso_mux_read_callback(struct usb_xfer *xfer, usb_error_t error) 970202181Sthompsa{ 971202181Sthompsa struct uhso_softc *sc = usbd_xfer_softc(xfer); 972202181Sthompsa struct usb_page_cache *pc; 973202181Sthompsa struct usb_device_request req; 974202181Sthompsa struct uhso_tty *ht; 975202181Sthompsa int actlen, len; 976202181Sthompsa 977202181Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 978202181Sthompsa 979202181Sthompsa UHSO_DPRINTF(3, "status %d\n", USB_GET_STATE(xfer)); 980202181Sthompsa 981202181Sthompsa ht = usbd_xfer_get_priv(xfer); 982202181Sthompsa UHSO_DPRINTF(3, "ht=%p open=%d\n", ht, ht->ht_open); 983202181Sthompsa 984202181Sthompsa switch (USB_GET_STATE(xfer)) { 985202181Sthompsa case USB_ST_TRANSFERRED: 986202181Sthompsa /* Got data, send to ucom */ 987202181Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 988202181Sthompsa len = usbd_xfer_frame_len(xfer, 1); 989202181Sthompsa 990202181Sthompsa UHSO_DPRINTF(3, "got %d bytes on mux port %d\n", len, 991202181Sthompsa ht->ht_muxport); 992202181Sthompsa if (len <= 0) { 993202181Sthompsa usbd_transfer_start(sc->sc_xfer[UHSO_MUX_ENDPT_INTR]); 994202181Sthompsa break; 995202181Sthompsa } 996202181Sthompsa 997202181Sthompsa /* Deliver data if the TTY is open, discard otherwise */ 998202181Sthompsa if (ht->ht_open) 999202181Sthompsa ucom_put_data(&sc->sc_ucom[ht->ht_muxport], pc, 0, len); 1000202181Sthompsa /* FALLTHROUGH */ 1001202181Sthompsa case USB_ST_SETUP: 1002202181Sthompsatr_setup: 1003202181Sthompsa bzero(&req, sizeof(struct usb_device_request)); 1004202181Sthompsa req.bmRequestType = UT_READ_CLASS_INTERFACE; 1005202181Sthompsa req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE; 1006202181Sthompsa USETW(req.wValue, 0); 1007202181Sthompsa USETW(req.wIndex, ht->ht_muxport); 1008202181Sthompsa USETW(req.wLength, 1024); 1009202181Sthompsa 1010202181Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1011202181Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 1012202181Sthompsa 1013202181Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 1014202181Sthompsa usbd_xfer_set_frame_len(xfer, 1, 1024); 1015202181Sthompsa usbd_xfer_set_frames(xfer, 2); 1016202181Sthompsa usbd_transfer_submit(xfer); 1017202181Sthompsa break; 1018202181Sthompsa default: 1019202181Sthompsa UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); 1020202181Sthompsa if (error == USB_ERR_CANCELLED) 1021202181Sthompsa break; 1022202181Sthompsa usbd_xfer_set_stall(xfer); 1023202181Sthompsa goto tr_setup; 1024202181Sthompsa } 1025202181Sthompsa} 1026202181Sthompsa 1027202181Sthompsastatic void 1028202181Sthompsauhso_mux_write_callback(struct usb_xfer *xfer, usb_error_t error) 1029202181Sthompsa{ 1030202181Sthompsa struct uhso_softc *sc = usbd_xfer_softc(xfer); 1031202181Sthompsa struct uhso_tty *ht; 1032202181Sthompsa struct usb_page_cache *pc; 1033202181Sthompsa struct usb_device_request req; 1034202181Sthompsa int actlen; 1035202181Sthompsa struct usb_page_search res; 1036202181Sthompsa 1037202181Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 1038202181Sthompsa 1039202181Sthompsa ht = usbd_xfer_get_priv(xfer); 1040202181Sthompsa UHSO_DPRINTF(3, "status=%d, using mux port %d\n", 1041202181Sthompsa USB_GET_STATE(xfer), ht->ht_muxport); 1042202181Sthompsa 1043202181Sthompsa switch (USB_GET_STATE(xfer)) { 1044202181Sthompsa case USB_ST_TRANSFERRED: 1045202181Sthompsa UHSO_DPRINTF(3, "wrote %zd data bytes to muxport %d\n", 1046202181Sthompsa actlen - sizeof(struct usb_device_request) , 1047202181Sthompsa ht->ht_muxport); 1048202181Sthompsa /* FALLTHROUGH */ 1049202181Sthompsa case USB_ST_SETUP: 1050202181Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 1051202181Sthompsa if (ucom_get_data(&sc->sc_ucom[ht->ht_muxport], pc, 1052202181Sthompsa 0, 32, &actlen)) { 1053202181Sthompsa 1054202181Sthompsa usbd_get_page(pc, 0, &res); 1055202181Sthompsa 1056202181Sthompsa bzero(&req, sizeof(struct usb_device_request)); 1057202181Sthompsa req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1058202181Sthompsa req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND; 1059202181Sthompsa USETW(req.wValue, 0); 1060202181Sthompsa USETW(req.wIndex, ht->ht_muxport); 1061202181Sthompsa USETW(req.wLength, actlen); 1062202181Sthompsa 1063202181Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1064202181Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 1065202181Sthompsa 1066202181Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 1067202181Sthompsa usbd_xfer_set_frame_len(xfer, 1, actlen); 1068202181Sthompsa usbd_xfer_set_frames(xfer, 2); 1069202181Sthompsa 1070202181Sthompsa UHSO_DPRINTF(3, "Prepared %d bytes for transmit " 1071202181Sthompsa "on muxport %d\n", actlen, ht->ht_muxport); 1072202181Sthompsa 1073202181Sthompsa usbd_transfer_submit(xfer); 1074202181Sthompsa } 1075202181Sthompsa break; 1076202181Sthompsa default: 1077202181Sthompsa UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); 1078202181Sthompsa if (error == USB_ERR_CANCELLED) 1079202181Sthompsa break; 1080202181Sthompsa break; 1081202181Sthompsa } 1082202181Sthompsa 1083202181Sthompsa} 1084202181Sthompsa 1085202181Sthompsastatic int 1086202181Sthompsauhso_attach_bulkserial(struct uhso_softc *sc, struct usb_interface *iface, 1087202181Sthompsa int type) 1088202181Sthompsa{ 1089202181Sthompsa usb_error_t uerr; 1090202181Sthompsa int tty; 1091202181Sthompsa 1092202181Sthompsa /* 1093202181Sthompsa * Try attaching RD/WR/INTR first 1094202181Sthompsa */ 1095202181Sthompsa uerr = usbd_transfer_setup(sc->sc_udev, 1096202181Sthompsa &iface->idesc->bInterfaceNumber, sc->sc_xfer, 1097202181Sthompsa uhso_bs_config, UHSO_BULK_ENDPT_MAX, sc, &sc->sc_mtx); 1098202181Sthompsa if (uerr) { 1099202181Sthompsa /* Try only RD/WR */ 1100202181Sthompsa uerr = usbd_transfer_setup(sc->sc_udev, 1101202181Sthompsa &iface->idesc->bInterfaceNumber, sc->sc_xfer, 1102202181Sthompsa uhso_bs_config, UHSO_BULK_ENDPT_MAX - 1, sc, &sc->sc_mtx); 1103202181Sthompsa } 1104202181Sthompsa if (uerr) { 1105202181Sthompsa UHSO_DPRINTF(0, "usbd_transfer_setup failed"); 1106202181Sthompsa return (-1); 1107202181Sthompsa } 1108202181Sthompsa 1109202181Sthompsa tty = uhso_alloc_tty(sc); 1110202181Sthompsa if (tty < 0) { 1111202181Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UHSO_BULK_ENDPT_MAX); 1112202181Sthompsa return (ENOMEM); 1113202181Sthompsa } 1114202181Sthompsa 1115202181Sthompsa sc->sc_tty[tty].ht_muxport = -1; 1116202181Sthompsa return (0); 1117202181Sthompsa} 1118202181Sthompsa 1119202181Sthompsastatic void 1120202181Sthompsauhso_bs_read_callback(struct usb_xfer *xfer, usb_error_t error) 1121202181Sthompsa{ 1122202181Sthompsa struct uhso_softc *sc = usbd_xfer_softc(xfer); 1123202181Sthompsa struct usb_page_cache *pc; 1124202181Sthompsa int actlen; 1125202181Sthompsa 1126202181Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 1127202181Sthompsa 1128202181Sthompsa UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen); 1129202181Sthompsa 1130202181Sthompsa switch (USB_GET_STATE(xfer)) { 1131202181Sthompsa case USB_ST_TRANSFERRED: 1132202181Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1133202181Sthompsa ucom_put_data(&sc->sc_ucom[0], pc, 0, actlen); 1134202181Sthompsa /* FALLTHROUGH */ 1135202181Sthompsa case USB_ST_SETUP: 1136202181Sthompsatr_setup: 1137202181Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 1138202181Sthompsa usbd_transfer_submit(xfer); 1139202181Sthompsa break; 1140202181Sthompsa default: 1141202181Sthompsa UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); 1142202181Sthompsa if (error == USB_ERR_CANCELLED) 1143202181Sthompsa break; 1144202181Sthompsa usbd_xfer_set_stall(xfer); 1145202181Sthompsa goto tr_setup; 1146202181Sthompsa } 1147202181Sthompsa} 1148202181Sthompsa 1149202181Sthompsa 1150202181Sthompsastatic void 1151202181Sthompsauhso_bs_write_callback(struct usb_xfer *xfer, usb_error_t error) 1152202181Sthompsa{ 1153202181Sthompsa struct uhso_softc *sc = usbd_xfer_softc(xfer); 1154202181Sthompsa struct usb_page_cache *pc; 1155202181Sthompsa int actlen; 1156202181Sthompsa 1157202181Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 1158202181Sthompsa 1159202181Sthompsa UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen); 1160202181Sthompsa 1161202181Sthompsa switch (USB_GET_STATE(xfer)) { 1162202181Sthompsa case USB_ST_TRANSFERRED: 1163202181Sthompsa case USB_ST_SETUP: 1164202181Sthompsatr_setup: 1165202181Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1166202181Sthompsa if (ucom_get_data(&sc->sc_ucom[0], pc, 0, 8192, &actlen)) { 1167202181Sthompsa usbd_xfer_set_frame_len(xfer, 0, actlen); 1168202181Sthompsa usbd_transfer_submit(xfer); 1169202181Sthompsa } 1170202181Sthompsa break; 1171202181Sthompsa break; 1172202181Sthompsa default: 1173202181Sthompsa UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); 1174202181Sthompsa if (error == USB_ERR_CANCELLED) 1175202181Sthompsa break; 1176202181Sthompsa usbd_xfer_set_stall(xfer); 1177202181Sthompsa goto tr_setup; 1178202181Sthompsa } 1179202181Sthompsa} 1180202181Sthompsa 1181202181Sthompsastatic void 1182202181Sthompsauhso_bs_cfg(struct uhso_softc *sc) 1183202181Sthompsa{ 1184202181Sthompsa struct usb_device_request req; 1185202181Sthompsa usb_error_t uerr; 1186202181Sthompsa 1187202181Sthompsa if (!(UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK)) 1188202181Sthompsa return; 1189202181Sthompsa 1190202181Sthompsa req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1191202181Sthompsa req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 1192202181Sthompsa USETW(req.wValue, sc->sc_line); 1193202181Sthompsa USETW(req.wIndex, sc->sc_iface_no); 1194202181Sthompsa USETW(req.wLength, 0); 1195202181Sthompsa 1196202181Sthompsa uerr = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom[0], &req, NULL, 0, 1000); 1197202181Sthompsa if (uerr != 0) { 1198202181Sthompsa device_printf(sc->sc_dev, "failed to set ctrl line state to " 1199202181Sthompsa "0x%02x: %s\n", sc->sc_line, usbd_errstr(uerr)); 1200202181Sthompsa } 1201202181Sthompsa} 1202202181Sthompsa 1203202181Sthompsastatic void 1204202181Sthompsauhso_bs_intr_callback(struct usb_xfer *xfer, usb_error_t error) 1205202181Sthompsa{ 1206202181Sthompsa struct uhso_softc *sc = usbd_xfer_softc(xfer); 1207202181Sthompsa struct usb_page_cache *pc; 1208202181Sthompsa int actlen; 1209202181Sthompsa struct usb_cdc_notification cdc; 1210202181Sthompsa 1211202181Sthompsa 1212202181Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 1213202181Sthompsa 1214202181Sthompsa UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen); 1215202181Sthompsa 1216202181Sthompsa switch (USB_GET_STATE(xfer)) { 1217202181Sthompsa case USB_ST_TRANSFERRED: 1218202181Sthompsa if (actlen < UCDC_NOTIFICATION_LENGTH) { 1219202181Sthompsa UHSO_DPRINTF(0, "UCDC notification too short: %d\n", actlen); 1220202181Sthompsa goto tr_setup; 1221202181Sthompsa } 1222202181Sthompsa else if (actlen > sizeof(struct usb_cdc_notification)) { 1223202181Sthompsa UHSO_DPRINTF(0, "UCDC notification too large: %d\n", actlen); 1224202181Sthompsa actlen = sizeof(struct usb_cdc_notification); 1225202181Sthompsa } 1226202181Sthompsa 1227202181Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1228202181Sthompsa usbd_copy_out(pc, 0, &cdc, actlen); 1229202181Sthompsa 1230202181Sthompsa if (UGETW(cdc.wIndex) != sc->sc_iface_no) { 1231202181Sthompsa UHSO_DPRINTF(0, "Interface missmatch, got %d expected %d\n", 1232202181Sthompsa UGETW(cdc.wIndex), sc->sc_iface_no); 1233202181Sthompsa goto tr_setup; 1234202181Sthompsa } 1235202181Sthompsa 1236202181Sthompsa if (cdc.bmRequestType == UCDC_NOTIFICATION && 1237202181Sthompsa cdc.bNotification == UCDC_N_SERIAL_STATE) { 1238202181Sthompsa UHSO_DPRINTF(1, "notify = 0x%02x\n", cdc.data[0]); 1239202181Sthompsa 1240202181Sthompsa sc->sc_msr = 0; 1241202181Sthompsa sc->sc_lsr = 0; 1242202181Sthompsa if (cdc.data[0] & UCDC_N_SERIAL_RI) 1243202181Sthompsa sc->sc_msr |= SER_RI; 1244202181Sthompsa if (cdc.data[0] & UCDC_N_SERIAL_DSR) 1245202181Sthompsa sc->sc_msr |= SER_DSR; 1246202181Sthompsa if (cdc.data[0] & UCDC_N_SERIAL_DCD) 1247202181Sthompsa sc->sc_msr |= SER_DCD; 1248202181Sthompsa 1249202181Sthompsa ucom_status_change(&sc->sc_ucom[0]); 1250202181Sthompsa } 1251202181Sthompsa case USB_ST_SETUP: 1252202181Sthompsatr_setup: 1253202181Sthompsa default: 1254202181Sthompsa if (error == USB_ERR_CANCELLED) 1255202181Sthompsa break; 1256202181Sthompsa usbd_xfer_set_stall(xfer); 1257202181Sthompsa goto tr_setup; 1258202181Sthompsa } 1259202181Sthompsa} 1260202181Sthompsa 1261202181Sthompsastatic void 1262202181Sthompsauhso_ucom_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 1263202181Sthompsa{ 1264202181Sthompsa struct uhso_softc *sc = ucom->sc_parent; 1265202181Sthompsa 1266202181Sthompsa *lsr = sc->sc_lsr; 1267202181Sthompsa *msr = sc->sc_msr; 1268202181Sthompsa} 1269202181Sthompsa 1270202181Sthompsastatic void 1271202181Sthompsauhso_ucom_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 1272202181Sthompsa{ 1273202181Sthompsa struct uhso_softc *sc = ucom->sc_parent; 1274202181Sthompsa 1275202181Sthompsa if (!(UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK)) 1276202181Sthompsa return; 1277202181Sthompsa 1278202181Sthompsa if (onoff) 1279202181Sthompsa sc->sc_line |= UCDC_LINE_DTR; 1280202181Sthompsa else 1281202181Sthompsa sc->sc_line &= UCDC_LINE_DTR; 1282202181Sthompsa 1283202181Sthompsa uhso_bs_cfg(sc); 1284202181Sthompsa} 1285202181Sthompsa 1286202181Sthompsastatic void 1287202181Sthompsauhso_ucom_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) 1288202181Sthompsa{ 1289202181Sthompsa struct uhso_softc *sc = ucom->sc_parent; 1290202181Sthompsa 1291202181Sthompsa if (!(UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK)) 1292202181Sthompsa return; 1293202181Sthompsa 1294202181Sthompsa if (onoff) 1295202181Sthompsa sc->sc_line |= UCDC_LINE_RTS; 1296202181Sthompsa else 1297202181Sthompsa sc->sc_line &= UCDC_LINE_DTR; 1298202181Sthompsa 1299202181Sthompsa uhso_bs_cfg(sc); 1300202181Sthompsa} 1301202181Sthompsa 1302202181Sthompsa 1303202181Sthompsastatic void 1304202181Sthompsauhso_ucom_start_read(struct ucom_softc *ucom) 1305202181Sthompsa{ 1306202181Sthompsa struct uhso_softc *sc = ucom->sc_parent; 1307202181Sthompsa 1308202181Sthompsa UHSO_DPRINTF(3, "unit=%d, local_unit=%d\n", 1309202181Sthompsa ucom->sc_unit, ucom->sc_local_unit); 1310202181Sthompsa 1311202181Sthompsa if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_MUX) { 1312202181Sthompsa sc->sc_tty[ucom->sc_local_unit].ht_open = 1; 1313202181Sthompsa usbd_transfer_start(sc->sc_xfer[UHSO_MUX_ENDPT_INTR]); 1314202181Sthompsa } 1315202181Sthompsa else if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK) { 1316202181Sthompsa sc->sc_tty[0].ht_open = 1; 1317202181Sthompsa usbd_transfer_start(sc->sc_xfer[UHSO_BULK_ENDPT_READ]); 1318202181Sthompsa if (sc->sc_xfer[UHSO_BULK_ENDPT_INTR] != NULL) 1319202181Sthompsa usbd_transfer_start(sc->sc_xfer[UHSO_BULK_ENDPT_INTR]); 1320202181Sthompsa } 1321202181Sthompsa} 1322202181Sthompsa 1323202181Sthompsastatic void 1324202181Sthompsauhso_ucom_stop_read(struct ucom_softc *ucom) 1325202181Sthompsa{ 1326202181Sthompsa 1327202181Sthompsa struct uhso_softc *sc = ucom->sc_parent; 1328202181Sthompsa 1329202181Sthompsa if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_MUX) { 1330202181Sthompsa sc->sc_tty[ucom->sc_local_unit].ht_open = 0; 1331202181Sthompsa usbd_transfer_stop( 1332202181Sthompsa sc->sc_tty[ucom->sc_local_unit].ht_xfer[UHSO_CTRL_READ]); 1333202181Sthompsa } 1334202181Sthompsa else if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK) { 1335202181Sthompsa sc->sc_tty[0].ht_open = 0; 1336202181Sthompsa usbd_transfer_start(sc->sc_xfer[UHSO_BULK_ENDPT_READ]); 1337202181Sthompsa if (sc->sc_xfer[UHSO_BULK_ENDPT_INTR] != NULL) 1338202181Sthompsa usbd_transfer_stop(sc->sc_xfer[UHSO_BULK_ENDPT_INTR]); 1339202181Sthompsa } 1340202181Sthompsa} 1341202181Sthompsa 1342202181Sthompsastatic void 1343202181Sthompsauhso_ucom_start_write(struct ucom_softc *ucom) 1344202181Sthompsa{ 1345202181Sthompsa struct uhso_softc *sc = ucom->sc_parent; 1346202181Sthompsa 1347202181Sthompsa if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_MUX) { 1348202181Sthompsa UHSO_DPRINTF(3, "local unit %d\n", ucom->sc_local_unit); 1349202181Sthompsa 1350202181Sthompsa usbd_transfer_start(sc->sc_xfer[UHSO_MUX_ENDPT_INTR]); 1351202181Sthompsa 1352202181Sthompsa usbd_xfer_set_priv( 1353202181Sthompsa sc->sc_tty[ucom->sc_local_unit].ht_xfer[UHSO_CTRL_WRITE], 1354202181Sthompsa &sc->sc_tty[ucom->sc_local_unit]); 1355202181Sthompsa usbd_transfer_start( 1356202181Sthompsa sc->sc_tty[ucom->sc_local_unit].ht_xfer[UHSO_CTRL_WRITE]); 1357202181Sthompsa 1358202181Sthompsa } 1359202181Sthompsa else if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK) { 1360202181Sthompsa usbd_transfer_start(sc->sc_xfer[UHSO_BULK_ENDPT_WRITE]); 1361202181Sthompsa } 1362202181Sthompsa} 1363202181Sthompsa 1364202181Sthompsastatic void 1365202181Sthompsauhso_ucom_stop_write(struct ucom_softc *ucom) 1366202181Sthompsa{ 1367202181Sthompsa struct uhso_softc *sc = ucom->sc_parent; 1368202181Sthompsa 1369202181Sthompsa if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_MUX) { 1370202181Sthompsa usbd_transfer_stop( 1371202181Sthompsa sc->sc_tty[ucom->sc_local_unit].ht_xfer[UHSO_CTRL_WRITE]); 1372202181Sthompsa } 1373202181Sthompsa else if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK) { 1374202181Sthompsa usbd_transfer_stop(sc->sc_xfer[UHSO_BULK_ENDPT_WRITE]); 1375202181Sthompsa } 1376202181Sthompsa 1377202181Sthompsa} 1378202181Sthompsa 1379202181Sthompsastatic int uhso_attach_ifnet(struct uhso_softc *sc, struct usb_interface *iface, 1380202181Sthompsa int type) 1381202181Sthompsa{ 1382202181Sthompsa struct ifnet *ifp; 1383202181Sthompsa usb_error_t uerr; 1384202181Sthompsa struct sysctl_ctx_list *sctx; 1385202181Sthompsa struct sysctl_oid *soid; 1386202181Sthompsa 1387202181Sthompsa uerr = usbd_transfer_setup(sc->sc_udev, 1388202181Sthompsa &iface->idesc->bInterfaceNumber, sc->sc_if_xfer, 1389202181Sthompsa uhso_ifnet_config, UHSO_IFNET_MAX, sc, &sc->sc_mtx); 1390202181Sthompsa if (uerr) { 1391202181Sthompsa UHSO_DPRINTF(0, "usbd_transfer_setup failed: %s\n", 1392202181Sthompsa usbd_errstr(uerr)); 1393202181Sthompsa return (-1); 1394202181Sthompsa } 1395202181Sthompsa 1396202181Sthompsa sc->sc_ifp = ifp = if_alloc(IFT_PPP); 1397202181Sthompsa if (sc->sc_ifp == NULL) { 1398202181Sthompsa device_printf(sc->sc_dev, "if_alloc() failed\n"); 1399202181Sthompsa return (-1); 1400202181Sthompsa } 1401202181Sthompsa 1402202181Sthompsa callout_init_mtx(&sc->sc_c, &sc->sc_mtx, 0); 1403202181Sthompsa mtx_lock(&sc->sc_mtx); 1404202181Sthompsa callout_reset(&sc->sc_c, 1, uhso_if_rxflush, sc); 1405202181Sthompsa mtx_unlock(&sc->sc_mtx); 1406202181Sthompsa 1407202181Sthompsa if_initname(ifp, device_get_name(sc->sc_dev), device_get_unit(sc->sc_dev)); 1408202181Sthompsa ifp->if_mtu = UHSO_MAX_MTU; 1409202181Sthompsa 1410202181Sthompsa ifp->if_ioctl = uhso_if_ioctl; 1411202181Sthompsa ifp->if_init = uhso_if_init; 1412202181Sthompsa ifp->if_start = uhso_if_start; 1413202181Sthompsa ifp->if_output = uhso_if_output; 1414202181Sthompsa ifp->if_flags = 0; 1415202181Sthompsa ifp->if_softc = sc; 1416202181Sthompsa IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 1417202181Sthompsa ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 1418202181Sthompsa IFQ_SET_READY(&ifp->if_snd); 1419202181Sthompsa 1420202181Sthompsa if_attach(ifp); 1421202181Sthompsa bpfattach(ifp, DLT_RAW, 0); 1422202181Sthompsa 1423202181Sthompsa sctx = device_get_sysctl_ctx(sc->sc_dev); 1424202181Sthompsa soid = device_get_sysctl_tree(sc->sc_dev); 1425202181Sthompsa /* Unlocked read... */ 1426202181Sthompsa SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "netif", 1427202181Sthompsa CTLFLAG_RD, ifp->if_xname, 0, "Attached network interface"); 1428202181Sthompsa 1429202181Sthompsa return (0); 1430202181Sthompsa} 1431202181Sthompsa 1432202181Sthompsastatic void 1433202181Sthompsauhso_ifnet_read_callback(struct usb_xfer *xfer, usb_error_t error) 1434202181Sthompsa{ 1435202181Sthompsa struct uhso_softc *sc = usbd_xfer_softc(xfer); 1436202181Sthompsa struct mbuf *m; 1437202181Sthompsa struct usb_page_cache *pc; 1438202181Sthompsa int actlen; 1439202181Sthompsa 1440202181Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 1441202181Sthompsa 1442202181Sthompsa UHSO_DPRINTF(3, "status=%d, actlen=%d\n", USB_GET_STATE(xfer), actlen); 1443202181Sthompsa 1444202181Sthompsa switch (USB_GET_STATE(xfer)) { 1445202181Sthompsa case USB_ST_TRANSFERRED: 1446202181Sthompsa if (actlen > 0 && (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1447202181Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1448202181Sthompsa m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1449202181Sthompsa usbd_copy_out(pc, 0, mtod(m, uint8_t *), actlen); 1450202181Sthompsa m->m_pkthdr.len = m->m_len = actlen; 1451202181Sthompsa _IF_ENQUEUE(&sc->sc_rxq, m); 1452202181Sthompsa if (!callout_pending(&sc->sc_c) || 1453202181Sthompsa !callout_active(&sc->sc_c)) { 1454202181Sthompsa callout_schedule(&sc->sc_c, 1); 1455202181Sthompsa } 1456202181Sthompsa } 1457202181Sthompsa /* FALLTHROUGH */ 1458202181Sthompsa case USB_ST_SETUP: 1459202181Sthompsatr_setup: 1460202181Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 1461202181Sthompsa usbd_transfer_submit(xfer); 1462202181Sthompsa break; 1463202181Sthompsa default: 1464202181Sthompsa UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); 1465202181Sthompsa if (error == USB_ERR_CANCELLED) 1466202181Sthompsa break; 1467202181Sthompsa usbd_xfer_set_stall(xfer); 1468202181Sthompsa goto tr_setup; 1469202181Sthompsa } 1470202181Sthompsa} 1471202181Sthompsa 1472202181Sthompsa/* 1473202181Sthompsa * Defered RX processing, called with mutex locked. 1474202181Sthompsa */ 1475202181Sthompsastatic void 1476202181Sthompsauhso_if_rxflush(void *arg) 1477202181Sthompsa{ 1478202181Sthompsa struct uhso_softc *sc = arg; 1479202181Sthompsa struct ifnet *ifp = sc->sc_ifp; 1480202181Sthompsa uint8_t *cp; 1481202181Sthompsa struct mbuf *m, *m0, *mwait; 1482202181Sthompsa struct ip *ip; 1483202181Sthompsa#ifdef INET6 1484202181Sthompsa struct ip6_hdr *ip6; 1485202181Sthompsa#endif 1486202181Sthompsa uint16_t iplen; 1487202181Sthompsa int len, isr; 1488202181Sthompsa 1489202181Sthompsa m = NULL; 1490202181Sthompsa mwait = sc->sc_mwait; 1491202181Sthompsa for (;;) { 1492202181Sthompsa if (m == NULL) { 1493202181Sthompsa _IF_DEQUEUE(&sc->sc_rxq, m); 1494202181Sthompsa if (m == NULL) 1495202181Sthompsa break; 1496202181Sthompsa UHSO_DPRINTF(2, "dequeue m=%p, len=%d\n", m, m->m_len); 1497202181Sthompsa } 1498202181Sthompsa mtx_unlock(&sc->sc_mtx); 1499202181Sthompsa 1500202181Sthompsa /* Do we have a partial packet waiting? */ 1501202181Sthompsa if (mwait != NULL) { 1502202181Sthompsa m0 = mwait; 1503202181Sthompsa mwait = NULL; 1504202181Sthompsa 1505202181Sthompsa UHSO_DPRINTF(1, "partial m0=%p(%d), concat w/ m=%p(%d)\n", 1506202181Sthompsa m0, m0->m_len, m, m->m_len); 1507202181Sthompsa len = m->m_len + m0->m_len; 1508202181Sthompsa 1509202181Sthompsa /* Concat mbufs and fix headers */ 1510202181Sthompsa m_cat(m0, m); 1511202181Sthompsa m0->m_pkthdr.len = len; 1512202181Sthompsa m->m_flags &= ~M_PKTHDR; 1513202181Sthompsa 1514202181Sthompsa m = m_pullup(m0, sizeof(struct ip)); 1515202181Sthompsa if (m == NULL) { 1516202181Sthompsa ifp->if_ierrors++; 1517202181Sthompsa UHSO_DPRINTF(0, "m_pullup failed\n"); 1518202181Sthompsa mtx_lock(&sc->sc_mtx); 1519202181Sthompsa continue; 1520202181Sthompsa } 1521202181Sthompsa UHSO_DPRINTF(2, "Constructed mbuf=%p, len=%d\n", 1522202181Sthompsa m, m->m_pkthdr.len); 1523202181Sthompsa } 1524202181Sthompsa 1525202181Sthompsa cp = mtod(m, uint8_t *); 1526202181Sthompsa ip = (struct ip *)cp; 1527202181Sthompsa#ifdef INET6 1528202181Sthompsa ip6 = (struct ip6_hdr *)cp; 1529202181Sthompsa#endif 1530202181Sthompsa 1531202181Sthompsa /* Check for IPv4 */ 1532202181Sthompsa if (ip->ip_v == IPVERSION) { 1533202181Sthompsa iplen = htons(ip->ip_len); 1534202181Sthompsa isr = NETISR_IP; 1535202181Sthompsa } 1536202181Sthompsa#ifdef INET6 1537202181Sthompsa /* Check for IPv6 */ 1538202181Sthompsa else if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION) { 1539202181Sthompsa iplen = htons(ip6->ip6_plen); 1540202181Sthompsa isr = NETISR_IPV6; 1541202181Sthompsa } 1542202181Sthompsa#endif 1543202181Sthompsa else { 1544202181Sthompsa UHSO_DPRINTF(0, "got unexpected ip version %d, " 1545202181Sthompsa "m=%p, len=%d\n", (*cp & 0xf0) >> 4, m, m->m_len); 1546202181Sthompsa ifp->if_ierrors++; 1547202181Sthompsa UHSO_HEXDUMP(cp, 4); 1548202181Sthompsa m_freem(m); 1549202181Sthompsa m = NULL; 1550202181Sthompsa mtx_lock(&sc->sc_mtx); 1551202181Sthompsa continue; 1552202181Sthompsa } 1553202181Sthompsa 1554202181Sthompsa if (iplen == 0) { 1555202181Sthompsa UHSO_DPRINTF(0, "Zero IP length\n"); 1556202181Sthompsa ifp->if_ierrors++; 1557202181Sthompsa m_freem(m); 1558202181Sthompsa m = NULL; 1559202181Sthompsa mtx_lock(&sc->sc_mtx); 1560202181Sthompsa continue; 1561202181Sthompsa } 1562202181Sthompsa 1563202181Sthompsa UHSO_DPRINTF(1, "m=%p, len=%d, cp=%p, iplen=%d\n", 1564202181Sthompsa m, m->m_pkthdr.len, cp, iplen); 1565202181Sthompsa 1566202181Sthompsa m0 = NULL; 1567202181Sthompsa 1568202181Sthompsa /* More IP packets in this mbuf */ 1569202181Sthompsa if (iplen < m->m_pkthdr.len) { 1570202181Sthompsa m0 = m; 1571202181Sthompsa 1572202181Sthompsa /* 1573202181Sthompsa * Allocate a new mbuf for this IP packet and 1574202181Sthompsa * copy the IP-packet into it. 1575202181Sthompsa */ 1576202181Sthompsa m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1577202181Sthompsa bcopy(mtod(m0, uint8_t *), mtod(m, uint8_t *), iplen); 1578202181Sthompsa m->m_pkthdr.len = m->m_len = iplen; 1579202181Sthompsa 1580202181Sthompsa /* Adjust the size of the original mbuf */ 1581202181Sthompsa m_adj(m0, iplen); 1582202181Sthompsa m0 = m_defrag(m0, M_WAIT); 1583202181Sthompsa 1584202181Sthompsa UHSO_DPRINTF(1, "New mbuf=%p, len=%d/%d, m0=%p, " 1585202181Sthompsa "m0_len=%d/%d\n", m, m->m_pkthdr.len, m->m_len, 1586202181Sthompsa m0, m0->m_pkthdr.len, m0->m_len); 1587202181Sthompsa } 1588202181Sthompsa else if (iplen > m->m_pkthdr.len) { 1589202181Sthompsa UHSO_DPRINTF(1, "Defered mbuf=%p, len=%d\n", 1590202181Sthompsa m, m->m_pkthdr.len); 1591202181Sthompsa mwait = m; 1592202181Sthompsa m = NULL; 1593202181Sthompsa mtx_lock(&sc->sc_mtx); 1594202181Sthompsa continue; 1595202181Sthompsa } 1596202181Sthompsa 1597202181Sthompsa ifp->if_ipackets++; 1598202181Sthompsa m->m_pkthdr.rcvif = ifp; 1599202181Sthompsa 1600202181Sthompsa /* Dispatch to IP layer */ 1601202181Sthompsa BPF_MTAP(sc->sc_ifp, m); 1602202181Sthompsa netisr_dispatch(isr, m); 1603202181Sthompsa m = m0 != NULL ? m0 : NULL; 1604202181Sthompsa mtx_lock(&sc->sc_mtx); 1605202181Sthompsa } 1606202181Sthompsa sc->sc_mwait = mwait; 1607202181Sthompsa} 1608202181Sthompsa 1609202181Sthompsastatic void 1610202181Sthompsauhso_ifnet_write_callback(struct usb_xfer *xfer, usb_error_t error) 1611202181Sthompsa{ 1612202181Sthompsa struct uhso_softc *sc = usbd_xfer_softc(xfer); 1613202181Sthompsa struct ifnet *ifp = sc->sc_ifp; 1614202181Sthompsa struct usb_page_cache *pc; 1615202181Sthompsa struct mbuf *m; 1616202181Sthompsa int actlen; 1617202181Sthompsa 1618202181Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 1619202181Sthompsa 1620202181Sthompsa UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen); 1621202181Sthompsa 1622202181Sthompsa switch (USB_GET_STATE(xfer)) { 1623202181Sthompsa case USB_ST_TRANSFERRED: 1624202181Sthompsa ifp->if_opackets++; 1625202181Sthompsa ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1626202181Sthompsa case USB_ST_SETUP: 1627202181Sthompsatr_setup: 1628202181Sthompsa IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1629202181Sthompsa if (m == NULL) 1630202181Sthompsa break; 1631202181Sthompsa 1632202181Sthompsa ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1633202181Sthompsa 1634202181Sthompsa if (m->m_pkthdr.len > MCLBYTES) 1635202181Sthompsa m->m_pkthdr.len = MCLBYTES; 1636202181Sthompsa 1637202181Sthompsa usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len); 1638202181Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1639202181Sthompsa usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 1640202181Sthompsa usbd_transfer_submit(xfer); 1641202181Sthompsa 1642202181Sthompsa BPF_MTAP(ifp, m); 1643202181Sthompsa m_freem(m); 1644202181Sthompsa break; 1645202181Sthompsa default: 1646202181Sthompsa UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); 1647202181Sthompsa if (error == USB_ERR_CANCELLED) 1648202181Sthompsa break; 1649202181Sthompsa usbd_xfer_set_stall(xfer); 1650202181Sthompsa goto tr_setup; 1651202181Sthompsa } 1652202181Sthompsa 1653202181Sthompsa} 1654202181Sthompsa 1655202181Sthompsastatic int 1656202181Sthompsauhso_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1657202181Sthompsa{ 1658202181Sthompsa struct uhso_softc *sc; 1659202181Sthompsa 1660202181Sthompsa sc = ifp->if_softc; 1661202181Sthompsa 1662202181Sthompsa switch (cmd) { 1663202181Sthompsa case SIOCSIFFLAGS: 1664202181Sthompsa if (ifp->if_flags & IFF_UP) { 1665202181Sthompsa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1666202181Sthompsa uhso_if_init(sc); 1667202181Sthompsa } 1668202181Sthompsa } 1669202181Sthompsa else { 1670202181Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1671202181Sthompsa mtx_lock(&sc->sc_mtx); 1672202181Sthompsa uhso_if_stop(sc); 1673202181Sthompsa mtx_unlock(&sc->sc_mtx); 1674202181Sthompsa } 1675202181Sthompsa } 1676202181Sthompsa break; 1677202181Sthompsa case SIOCSIFADDR: 1678202181Sthompsa case SIOCSIFDSTADDR: 1679202181Sthompsa case SIOCADDMULTI: 1680202181Sthompsa case SIOCDELMULTI: 1681202181Sthompsa break; 1682202181Sthompsa default: 1683202181Sthompsa return (EINVAL); 1684202181Sthompsa } 1685202181Sthompsa return (0); 1686202181Sthompsa} 1687202181Sthompsa 1688202181Sthompsastatic void 1689202181Sthompsauhso_if_init(void *priv) 1690202181Sthompsa{ 1691202181Sthompsa struct uhso_softc *sc = priv; 1692202181Sthompsa struct ifnet *ifp = sc->sc_ifp; 1693202181Sthompsa 1694202181Sthompsa mtx_lock(&sc->sc_mtx); 1695202181Sthompsa uhso_if_stop(sc); 1696202181Sthompsa ifp = sc->sc_ifp; 1697202181Sthompsa ifp->if_flags |= IFF_UP; 1698202181Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 1699202181Sthompsa mtx_unlock(&sc->sc_mtx); 1700202181Sthompsa 1701202181Sthompsa UHSO_DPRINTF(3, "ifnet initialized\n"); 1702202181Sthompsa} 1703202181Sthompsa 1704202181Sthompsastatic int 1705202181Sthompsauhso_if_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, 1706202181Sthompsa struct route *ro) 1707202181Sthompsa{ 1708202181Sthompsa int error; 1709202181Sthompsa 1710202181Sthompsa /* Only IPv4/6 support */ 1711202181Sthompsa if (dst->sa_family != AF_INET 1712202181Sthompsa#ifdef INET6 1713202181Sthompsa && dst->sa_family != AF_INET6 1714202181Sthompsa#endif 1715202181Sthompsa ) { 1716202181Sthompsa return (EAFNOSUPPORT); 1717202181Sthompsa } 1718202181Sthompsa 1719202181Sthompsa error = (ifp->if_transmit)(ifp, m0); 1720202181Sthompsa if (error) { 1721202181Sthompsa ifp->if_oerrors++; 1722202181Sthompsa return (ENOBUFS); 1723202181Sthompsa } 1724202181Sthompsa ifp->if_opackets++; 1725202181Sthompsa 1726202181Sthompsa return (0); 1727202181Sthompsa} 1728202181Sthompsa 1729202181Sthompsastatic void 1730202181Sthompsauhso_if_start(struct ifnet *ifp) 1731202181Sthompsa{ 1732202181Sthompsa struct uhso_softc *sc = ifp->if_softc; 1733202181Sthompsa 1734202181Sthompsa if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1735202181Sthompsa UHSO_DPRINTF(1, "Not running\n"); 1736202181Sthompsa return; 1737202181Sthompsa } 1738202181Sthompsa 1739202181Sthompsa mtx_lock(&sc->sc_mtx); 1740202181Sthompsa usbd_transfer_start(sc->sc_if_xfer[UHSO_IFNET_READ]); 1741202181Sthompsa usbd_transfer_start(sc->sc_if_xfer[UHSO_IFNET_WRITE]); 1742202181Sthompsa mtx_unlock(&sc->sc_mtx); 1743202181Sthompsa UHSO_DPRINTF(3, "interface started\n"); 1744202181Sthompsa} 1745202181Sthompsa 1746202181Sthompsastatic void 1747202181Sthompsauhso_if_stop(struct uhso_softc *sc) 1748202181Sthompsa{ 1749202181Sthompsa 1750202181Sthompsa usbd_transfer_stop(sc->sc_if_xfer[UHSO_IFNET_READ]); 1751202181Sthompsa usbd_transfer_stop(sc->sc_if_xfer[UHSO_IFNET_WRITE]); 1752202181Sthompsa 1753202181Sthompsa sc->sc_ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1754202181Sthompsa} 1755