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