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