xref: /netbsd/sys/dev/usb/uhso.c (revision 10fbbe4a)
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  */
92 int 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  */
112 Static int uhso_autoswitch = 1;
113 
114 SYSCTL_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 
158 Static 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  */
197 Static 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 
203 Static 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 
210 Static 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 
225 struct 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 
235 Static 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 
271 struct uhso_port;
272 struct uhso_softc;
273 
274 /* uhso callback functions return errno on failure */
275 typedef int (*uhso_callback)(struct uhso_port *);
276 
277 struct 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 
326 struct 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 
335 static int uhso_match(device_t, cfdata_t, void *);
336 static void uhso_attach(device_t, device_t, void *);
337 static int uhso_detach(device_t, int);
338 
339 
340 
341 CFATTACH_DECL_NEW(uhso, sizeof(struct uhso_softc), uhso_match, uhso_attach,
342     uhso_detach, NULL);
343 
344 Static int uhso_switch_mode(struct usbd_device *);
345 Static int uhso_get_iface_spec(struct usb_attach_arg *, uint8_t, uint8_t *);
346 Static usb_endpoint_descriptor_t *uhso_get_endpoint(struct usbd_interface *,
347     int, int);
348 
349 Static void uhso_mux_attach(struct uhso_softc *, struct usbd_interface *, int);
350 Static int  uhso_mux_abort(struct uhso_port *);
351 Static int  uhso_mux_detach(struct uhso_port *);
352 Static int  uhso_mux_init(struct uhso_port *);
353 Static int  uhso_mux_clean(struct uhso_port *);
354 Static int  uhso_mux_write(struct uhso_port *);
355 Static int  uhso_mux_read(struct uhso_port *);
356 Static int  uhso_mux_control(struct uhso_port *);
357 Static void uhso_mux_intr(struct usbd_xfer *, void *, usbd_status);
358 
359 Static void uhso_bulk_attach(struct uhso_softc *, struct usbd_interface *, int);
360 Static int  uhso_bulk_abort(struct uhso_port *);
361 Static int  uhso_bulk_detach(struct uhso_port *);
362 Static int  uhso_bulk_init(struct uhso_port *);
363 Static int  uhso_bulk_clean(struct uhso_port *);
364 Static int  uhso_bulk_write(struct uhso_port *);
365 Static int  uhso_bulk_read(struct uhso_port *);
366 Static int  uhso_bulk_control(struct uhso_port *);
367 Static void uhso_bulk_intr(struct usbd_xfer *, void *, usbd_status);
368 
369 Static void uhso_tty_attach(struct uhso_port *);
370 Static void uhso_tty_detach(struct uhso_port *);
371 Static void uhso_tty_read_cb(struct usbd_xfer *, void *, usbd_status);
372 Static void uhso_tty_write_cb(struct usbd_xfer *, void *, usbd_status);
373 
374 static dev_type_open(uhso_tty_open);
375 static dev_type_close(uhso_tty_close);
376 static dev_type_read(uhso_tty_read);
377 static dev_type_write(uhso_tty_write);
378 static dev_type_ioctl(uhso_tty_ioctl);
379 static dev_type_stop(uhso_tty_stop);
380 static dev_type_tty(uhso_tty_tty);
381 static dev_type_poll(uhso_tty_poll);
382 
383 const 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 
398 Static int  uhso_tty_init(struct uhso_port *);
399 Static void uhso_tty_clean(struct uhso_port *);
400 Static int  uhso_tty_do_ioctl(struct uhso_port *, u_long, void *, int, struct lwp *);
401 Static void uhso_tty_start(struct tty *);
402 Static int  uhso_tty_param(struct tty *, struct termios *);
403 Static 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 
415 Static void uhso_ifnet_attach(struct uhso_softc *, struct usbd_interface *,
416     int);
417 Static int  uhso_ifnet_abort(struct uhso_port *);
418 Static int  uhso_ifnet_detach(struct uhso_port *);
419 Static void uhso_ifnet_read_cb(struct usbd_xfer *, void *, usbd_status);
420 Static void uhso_ifnet_input(struct ifnet *, struct mbuf **, uint8_t *, size_t);
421 Static void uhso_ifnet_write_cb(struct usbd_xfer *, void *, usbd_status);
422 
423 Static int  uhso_ifnet_ioctl(struct ifnet *, u_long, void *);
424 Static int  uhso_ifnet_init(struct uhso_port *);
425 Static void uhso_ifnet_clean(struct uhso_port *);
426 Static void uhso_ifnet_start(struct ifnet *);
427 Static 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 
437 static int
uhso_match(device_t parent,cfdata_t match,void * aux)438 uhso_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 
455 static void
uhso_attach(device_t parent,device_t self,void * aux)456 uhso_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 
530 static int
uhso_detach(device_t self,int flags)531 uhso_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  */
584 Static int
uhso_switch_mode(struct usbd_device * udev)585 uhso_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 
631 Static int
uhso_get_iface_spec(struct usb_attach_arg * uaa,uint8_t ifnum,uint8_t * spec)632 uhso_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 
689 Static usb_endpoint_descriptor_t *
uhso_get_endpoint(struct usbd_interface * ifh,int type,int dir)690 uhso_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 
718 Static 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 
726 Static void
uhso_mux_attach(struct uhso_softc * sc,struct usbd_interface * ifh,int index)727 uhso_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 
843 Static int
uhso_mux_abort(struct uhso_port * hp)844 uhso_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 
858 Static int
uhso_mux_detach(struct uhso_port * hp)859 uhso_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 
876 Static int
uhso_mux_init(struct uhso_port * hp)877 uhso_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 
904 Static int
uhso_mux_clean(struct uhso_port * hp)905 uhso_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 
915 Static int
uhso_mux_write(struct uhso_port * hp)916 uhso_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 
944 Static int
uhso_mux_read(struct uhso_port * hp)945 uhso_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 
982 Static int
uhso_mux_control(struct uhso_port * hp)983 uhso_mux_control(struct uhso_port *hp)
984 {
985 
986 	DPRINTF(1, "hp=%p\n", hp);
987 
988 	return 0;
989 }
990 
991 Static void
uhso_mux_intr(struct usbd_xfer * xfer,void * p,usbd_status status)992 uhso_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 
1038 Static void
uhso_bulk_attach(struct uhso_softc * sc,struct usbd_interface * ifh,int index)1039 uhso_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 
1111 Static int
uhso_bulk_abort(struct uhso_port * hp)1112 uhso_bulk_abort(struct uhso_port *hp)
1113 {
1114 
1115 	DPRINTF(1, "hp=%p\n", hp);
1116 
1117 	return (*hp->hp_clean)(hp);
1118 }
1119 
1120 Static int
uhso_bulk_detach(struct uhso_port * hp)1121 uhso_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 
1131 Static int
uhso_bulk_init(struct uhso_port * hp)1132 uhso_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 
1181 Static int
uhso_bulk_clean(struct uhso_port * hp)1182 uhso_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 
1231 Static int
uhso_bulk_write(struct uhso_port * hp)1232 uhso_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 
1252 Static int
uhso_bulk_read(struct uhso_port * hp)1253 uhso_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 
1273 Static int
uhso_bulk_control(struct uhso_port * hp)1274 uhso_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 
1313 Static void
uhso_bulk_intr(struct usbd_xfer * xfer,void * p,usbd_status status)1314 uhso_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 
1368 Static void
uhso_tty_attach(struct uhso_port * hp)1369 uhso_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 
1383 Static void
uhso_tty_detach(struct uhso_port * hp)1384 uhso_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 
1396 Static void
uhso_tty_write_cb(struct usbd_xfer * xfer,void * p,usbd_status status)1397 uhso_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 
1429 Static void
uhso_tty_read_cb(struct usbd_xfer * xfer,void * p,usbd_status status)1430 uhso_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 
1479 static int
uhso_tty_open(dev_t dev,int flag,int mode,struct lwp * l)1480 uhso_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 
1526 Static int
uhso_tty_init(struct uhso_port * hp)1527 uhso_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 
1581 static int
uhso_tty_close(dev_t dev,int flag,int mode,struct lwp * l)1582 uhso_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 
1607 Static void
uhso_tty_clean(struct uhso_port * hp)1608 uhso_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 
1632 static int
uhso_tty_read(dev_t dev,struct uio * uio,int flag)1633 uhso_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 
1655 static int
uhso_tty_write(dev_t dev,struct uio * uio,int flag)1656 uhso_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 
1678 static int
uhso_tty_ioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)1679 uhso_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 
1700 Static int
uhso_tty_do_ioctl(struct uhso_port * hp,u_long cmd,void * data,int flag,struct lwp * l)1701 uhso_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 
1762 static void
uhso_tty_stop(struct tty * tp,int flag)1763 uhso_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 
1774 static struct tty *
uhso_tty_tty(dev_t dev)1775 uhso_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 
1783 static int
uhso_tty_poll(dev_t dev,int events,struct lwp * l)1784 uhso_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 
1804 Static int
uhso_tty_param(struct tty * tp,struct termios * t)1805 uhso_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 
1842 Static void
uhso_tty_start(struct tty * tp)1843 uhso_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 
1869 Static int
uhso_tty_control(struct uhso_port * hp,u_long cmd,int bits)1870 uhso_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 
1904 Static void
uhso_ifnet_attach(struct uhso_softc * sc,struct usbd_interface * ifh,int index)1905 uhso_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 
1978 Static int
uhso_ifnet_abort(struct uhso_port * hp)1979 uhso_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 
1989 Static int
uhso_ifnet_detach(struct uhso_port * hp)1990 uhso_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 
2005 Static void
uhso_ifnet_write_cb(struct usbd_xfer * xfer,void * p,usbd_status status)2006 uhso_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 
2045 Static void
uhso_ifnet_read_cb(struct usbd_xfer * xfer,void * p,usbd_status status)2046 uhso_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 
2083 Static void
uhso_ifnet_input(struct ifnet * ifp,struct mbuf ** mb,uint8_t * cp,size_t cc)2084 uhso_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 
2189 Static int
uhso_ifnet_ioctl(struct ifnet * ifp,u_long cmd,void * data)2190 uhso_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 */
2277 Static int
uhso_ifnet_init(struct uhso_port * hp)2278 uhso_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 
2299 Static void
uhso_ifnet_clean(struct uhso_port * hp)2300 uhso_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 */
2309 Static void
uhso_ifnet_start(struct ifnet * ifp)2310 uhso_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 
2347 Static int
uhso_ifnet_output(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,const struct rtentry * rt0)2348 uhso_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