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