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