FreeBSD kernel usb device Code
uhso.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010 Fredrik Lindberg <fli@shapeshifter.se>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <sys/param.h>
32#include <sys/eventhandler.h>
33#include <sys/sockio.h>
34#include <sys/mbuf.h>
35#include <sys/malloc.h>
36#include <sys/kernel.h>
37#include <sys/module.h>
38#include <sys/socket.h>
39#include <sys/tty.h>
40#include <sys/sysctl.h>
41#include <sys/condvar.h>
42#include <sys/sx.h>
43#include <sys/proc.h>
44#include <sys/conf.h>
45#include <sys/bus.h>
46#include <sys/systm.h>
47#include <sys/limits.h>
48
49#include <machine/bus.h>
50
51#include <net/if.h>
52#include <net/if_var.h>
53#include <net/if_types.h>
54#include <net/netisr.h>
55#include <net/bpf.h>
56#include <netinet/in.h>
57#include <netinet/ip.h>
58#include <netinet/ip6.h>
59
60#include <dev/usb/usb.h>
61#include <dev/usb/usbdi.h>
62#include <dev/usb/usbdi_util.h>
63#include <dev/usb/usb_cdc.h>
64#include "usbdevs.h"
65#define USB_DEBUG_VAR uhso_debug
66#include <dev/usb/usb_debug.h>
67#include <dev/usb/usb_process.h>
68#include <dev/usb/usb_busdma.h>
69#include <dev/usb/usb_msctest.h>
70
72
73struct uhso_tty {
75 struct usb_xfer *ht_xfer[3];
76 int ht_muxport; /* Mux. port no */
78 char ht_name[32];
79};
80
81struct uhso_softc {
82 device_t sc_dev;
84 struct mtx sc_mtx;
85 uint32_t sc_type; /* Interface definition */
87
88 struct usb_xfer *sc_xfer[3];
89 uint8_t sc_iface_no;
91
92 /* Control pipe */
95
96 /* Network */
97 struct usb_xfer *sc_if_xfer[2];
98 struct ifnet *sc_ifp;
99 struct mbuf *sc_mwait; /* Partial packet */
100 size_t sc_waitlen; /* No. of outstanding bytes */
101 struct mbufq sc_rxq;
102 struct callout sc_c;
103
104 /* TTY related structures */
112};
113
114#define UHSO_MAX_MTU 2048
115
116/*
117 * There are mainly two type of cards floating around.
118 * The first one has 2,3 or 4 interfaces with a multiplexed serial port
119 * and packet interface on the first interface and bulk serial ports
120 * on the others.
121 * The second type of card has several other interfaces, their purpose
122 * can be detected during run-time.
123 */
124#define UHSO_IFACE_SPEC(usb_type, port, port_type) \
125 (((usb_type) << 24) | ((port) << 16) | (port_type))
126
127#define UHSO_IFACE_USB_TYPE(x) ((x >> 24) & 0xff)
128#define UHSO_IFACE_PORT(x) ((x >> 16) & 0xff)
129#define UHSO_IFACE_PORT_TYPE(x) (x & 0xff)
130
131/*
132 * USB interface types
133 */
134#define UHSO_IF_NET 0x01 /* Network packet interface */
135#define UHSO_IF_MUX 0x02 /* Multiplexed serial port */
136#define UHSO_IF_BULK 0x04 /* Bulk interface */
137
138/*
139 * Port types
140 */
141#define UHSO_PORT_UNKNOWN 0x00
142#define UHSO_PORT_SERIAL 0x01 /* Serial port */
143#define UHSO_PORT_NETWORK 0x02 /* Network packet interface */
144
145/*
146 * Multiplexed serial port destination sub-port names
147 */
148#define UHSO_MPORT_TYPE_CTL 0x00 /* Control port */
149#define UHSO_MPORT_TYPE_APP 0x01 /* Application */
150#define UHSO_MPORT_TYPE_PCSC 0x02
151#define UHSO_MPORT_TYPE_GPS 0x03
152#define UHSO_MPORT_TYPE_APP2 0x04 /* Secondary application */
153#define UHSO_MPORT_TYPE_MAX UHSO_MPORT_TYPE_APP2
154#define UHSO_MPORT_TYPE_NOMAX 8 /* Max number of mux ports */
155
156/*
157 * Port definitions
158 * Note that these definitions are arbitrary and do not match the values
159 * returned by the auto config descriptor.
160 */
161#define UHSO_PORT_TYPE_UNKNOWN 0x00
162#define UHSO_PORT_TYPE_CTL 0x01
163#define UHSO_PORT_TYPE_APP 0x02
164#define UHSO_PORT_TYPE_APP2 0x03
165#define UHSO_PORT_TYPE_MODEM 0x04
166#define UHSO_PORT_TYPE_NETWORK 0x05
167#define UHSO_PORT_TYPE_DIAG 0x06
168#define UHSO_PORT_TYPE_DIAG2 0x07
169#define UHSO_PORT_TYPE_GPS 0x08
170#define UHSO_PORT_TYPE_GPSCTL 0x09
171#define UHSO_PORT_TYPE_PCSC 0x0a
172#define UHSO_PORT_TYPE_MSD 0x0b
173#define UHSO_PORT_TYPE_VOICE 0x0c
174#define UHSO_PORT_TYPE_MAX 0x0c
175
176static eventhandler_tag uhso_etag;
177
178/* Overall port type */
179static char *uhso_port[] = {
180 "Unknown",
181 "Serial",
182 "Network",
183 "Network/Serial"
184};
185
186/*
187 * Map between interface port type read from device and description type.
188 * The position in this array is a direct map to the auto config
189 * descriptor values.
190 */
191static unsigned char uhso_port_map[] = {
204};
205static char uhso_port_map_max = sizeof(uhso_port_map) / sizeof(char);
206
207static unsigned char uhso_mux_port_map[] = {
213};
214
215static char *uhso_port_type[] = {
216 "Unknown", /* Not a valid port */
217 "Control",
218 "Application",
219 "Application (Secondary)",
220 "Modem",
221 "Network",
222 "Diagnostic",
223 "Diagnostic (Secondary)",
224 "GPS",
225 "GPS Control",
226 "PC Smartcard",
227 "MSD",
228 "Voice",
229};
230
231static char *uhso_port_type_sysctl[] = {
232 "unknown",
233 "control",
234 "application",
235 "application",
236 "modem",
237 "network",
238 "diagnostic",
239 "diagnostic",
240 "gps",
241 "gps_control",
242 "pcsc",
243 "msd",
244 "voice",
245};
246
247#define UHSO_STATIC_IFACE 0x01
248#define UHSO_AUTO_IFACE 0x02
249
250/* ifnet device unit allocations */
251static struct unrhdr *uhso_ifnet_unit = NULL;
252
254#define UHSO_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
255 /* Option GlobeTrotter MAX 7.2 with upgraded firmware */
256 UHSO_DEV(OPTION, GTMAX72, UHSO_STATIC_IFACE),
257 /* Option GlobeSurfer iCON 7.2 */
258 UHSO_DEV(OPTION, GSICON72, UHSO_STATIC_IFACE),
259 /* Option iCON 225 */
260 UHSO_DEV(OPTION, GTHSDPA, UHSO_STATIC_IFACE),
261 /* Option GlobeSurfer iCON HSUPA */
262 UHSO_DEV(OPTION, GSICONHSUPA, UHSO_STATIC_IFACE),
263 /* Option GlobeTrotter HSUPA */
264 UHSO_DEV(OPTION, GTHSUPA, UHSO_STATIC_IFACE),
265 /* GE40x */
266 UHSO_DEV(OPTION, GE40X, UHSO_AUTO_IFACE),
267 UHSO_DEV(OPTION, GE40X_1, UHSO_AUTO_IFACE),
268 UHSO_DEV(OPTION, GE40X_2, UHSO_AUTO_IFACE),
269 UHSO_DEV(OPTION, GE40X_3, UHSO_AUTO_IFACE),
270 /* Option GlobeSurfer iCON 401 */
271 UHSO_DEV(OPTION, ICON401, UHSO_AUTO_IFACE),
272 /* Option GlobeTrotter Module 382 */
273 UHSO_DEV(OPTION, GMT382, UHSO_AUTO_IFACE),
274 /* Option GTM661W */
275 UHSO_DEV(OPTION, GTM661W, UHSO_AUTO_IFACE),
276 /* Option iCON EDGE */
277 UHSO_DEV(OPTION, ICONEDGE, UHSO_STATIC_IFACE),
278 /* Option Module HSxPA */
279 UHSO_DEV(OPTION, MODHSXPA, UHSO_STATIC_IFACE),
280 /* Option iCON 321 */
281 UHSO_DEV(OPTION, ICON321, UHSO_STATIC_IFACE),
282 /* Option iCON 322 */
283 UHSO_DEV(OPTION, GTICON322, UHSO_STATIC_IFACE),
284 /* Option iCON 505 */
285 UHSO_DEV(OPTION, ICON505, UHSO_AUTO_IFACE),
286 /* Option iCON 452 */
287 UHSO_DEV(OPTION, ICON505, UHSO_AUTO_IFACE),
288#undef UHSO_DEV
289};
290
291static SYSCTL_NODE(_hw_usb, OID_AUTO, uhso, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
292 "USB uhso");
293static int uhso_autoswitch = 1;
294SYSCTL_INT(_hw_usb_uhso, OID_AUTO, auto_switch, CTLFLAG_RWTUN,
295 &uhso_autoswitch, 0, "Automatically switch to modem mode");
296
297#ifdef USB_DEBUG
298#ifdef UHSO_DEBUG
299static int uhso_debug = UHSO_DEBUG;
300#else
301static int uhso_debug = -1;
302#endif
303
304SYSCTL_INT(_hw_usb_uhso, OID_AUTO, debug, CTLFLAG_RWTUN,
305 &uhso_debug, 0, "Debug level");
306
307#define UHSO_DPRINTF(n, x, ...) {\
308 if (uhso_debug >= n) {\
309 printf("%s: " x, __func__, ##__VA_ARGS__);\
310 }\
311}
312#else
313#define UHSO_DPRINTF(n, x, ...)
314#endif
315
316#ifdef UHSO_DEBUG_HEXDUMP
317# define UHSO_HEXDUMP(_buf, _len) do { \
318 { \
319 size_t __tmp; \
320 const char *__buf = (const char *)_buf; \
321 for (__tmp = 0; __tmp < _len; __tmp++) \
322 printf("%02hhx ", *__buf++); \
323 printf("\n"); \
324 } \
325} while(0)
326#else
327# define UHSO_HEXDUMP(_buf, _len)
328#endif
329
330enum {
334
335enum {
340
341enum {
346
347enum {
353
362
363/* Config used for the default control pipes */
365 [UHSO_CTRL_READ] = {
366 .type = UE_CONTROL,
367 .endpoint = 0x00,
368 .direction = UE_DIR_ANY,
369 .flags = { .pipe_bof = 1, .short_xfer_ok = 1 },
370 .bufsize = sizeof(struct usb_device_request) + 1024,
371 .callback = &uhso_mux_read_callback
372 },
373
374 [UHSO_CTRL_WRITE] = {
375 .type = UE_CONTROL,
376 .endpoint = 0x00,
377 .direction = UE_DIR_ANY,
378 .flags = { .pipe_bof = 1, .force_short_xfer = 1 },
379 .bufsize = sizeof(struct usb_device_request) + 1024,
380 .timeout = 1000,
381 .callback = &uhso_mux_write_callback
382 }
383};
384
385/* Config for the multiplexed serial ports */
389 .endpoint = UE_ADDR_ANY,
390 .direction = UE_DIR_IN,
391 .flags = { .short_xfer_ok = 1 },
392 .bufsize = 0,
393 .callback = &uhso_mux_intr_callback,
394 }
395};
396
397/* Config for the raw IP-packet interface */
399 [UHSO_IFNET_READ] = {
400 .type = UE_BULK,
401 .endpoint = UE_ADDR_ANY,
402 .direction = UE_DIR_IN,
403 .flags = { .pipe_bof = 1, .short_xfer_ok = 1 },
404 .bufsize = MCLBYTES,
405 .callback = &uhso_ifnet_read_callback
406 },
407 [UHSO_IFNET_WRITE] = {
408 .type = UE_BULK,
409 .endpoint = UE_ADDR_ANY,
410 .direction = UE_DIR_OUT,
411 .flags = { .pipe_bof = 1, .force_short_xfer = 1 },
412 .bufsize = MCLBYTES,
413 .timeout = 5 * USB_MS_HZ,
414 .callback = &uhso_ifnet_write_callback
415 }
416};
417
418/* Config for interfaces with normal bulk serial ports */
421 .type = UE_BULK,
422 .endpoint = UE_ADDR_ANY,
423 .direction = UE_DIR_IN,
424 .flags = { .pipe_bof = 1, .short_xfer_ok = 1 },
425 .bufsize = 4096,
426 .callback = &uhso_bs_read_callback
427 },
428
430 .type = UE_BULK,
431 .endpoint = UE_ADDR_ANY,
432 .direction = UE_DIR_OUT,
433 .flags = { .pipe_bof = 1, .force_short_xfer = 1 },
434 .bufsize = 8192,
435 .callback = &uhso_bs_write_callback
436 },
437
439 .type = UE_INTERRUPT,
440 .endpoint = UE_ADDR_ANY,
441 .direction = UE_DIR_IN,
442 .flags = { .short_xfer_ok = 1 },
443 .bufsize = 0,
444 .callback = &uhso_bs_intr_callback,
445 }
446};
447
448static int uhso_probe_iface(struct uhso_softc *, int,
449 int (*probe)(struct usb_device *, int));
450static int uhso_probe_iface_auto(struct usb_device *, int);
451static int uhso_probe_iface_static(struct usb_device *, int);
452static int uhso_attach_muxserial(struct uhso_softc *, struct usb_interface *,
453 int type);
454static int uhso_attach_bulkserial(struct uhso_softc *, struct usb_interface *,
455 int type);
456static int uhso_attach_ifnet(struct uhso_softc *, struct usb_interface *,
457 int type);
458static void uhso_test_autoinst(void *, struct usb_device *,
459 struct usb_attach_arg *);
460static int uhso_driver_loaded(struct module *, int, void *);
461static int uhso_radio_sysctl(SYSCTL_HANDLER_ARGS);
462static int uhso_radio_ctrl(struct uhso_softc *, int);
463
464static void uhso_free(struct ucom_softc *);
465static void uhso_ucom_start_read(struct ucom_softc *);
466static void uhso_ucom_stop_read(struct ucom_softc *);
467static void uhso_ucom_start_write(struct ucom_softc *);
468static void uhso_ucom_stop_write(struct ucom_softc *);
469static void uhso_ucom_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *);
470static void uhso_ucom_cfg_set_dtr(struct ucom_softc *, uint8_t);
471static void uhso_ucom_cfg_set_rts(struct ucom_softc *, uint8_t);
472static void uhso_if_init(void *);
473static void uhso_if_start(struct ifnet *);
474static void uhso_if_stop(struct uhso_softc *);
475static int uhso_if_ioctl(struct ifnet *, u_long, caddr_t);
476static int uhso_if_output(struct ifnet *, struct mbuf *,
477 const struct sockaddr *, struct route *);
478static void uhso_if_rxflush(void *);
479
480static device_probe_t uhso_probe;
481static device_attach_t uhso_attach;
482static device_detach_t uhso_detach;
483static void uhso_free_softc(struct uhso_softc *);
484
485static device_method_t uhso_methods[] = {
486 DEVMETHOD(device_probe, uhso_probe),
487 DEVMETHOD(device_attach, uhso_attach),
488 DEVMETHOD(device_detach, uhso_detach),
489 { 0, 0 }
490};
491
492static driver_t uhso_driver = {
493 .name = "uhso",
494 .methods = uhso_methods,
495 .size = sizeof(struct uhso_softc)
496};
497
498static devclass_t uhso_devclass;
500MODULE_DEPEND(uhso, ucom, 1, 1, 1);
501MODULE_DEPEND(uhso, usb, 1, 1, 1);
504
507 .ucom_cfg_set_dtr = &uhso_ucom_cfg_set_dtr,
508 .ucom_cfg_set_rts = &uhso_ucom_cfg_set_rts,
509 .ucom_start_read = uhso_ucom_start_read,
510 .ucom_stop_read = uhso_ucom_stop_read,
511 .ucom_start_write = uhso_ucom_start_write,
512 .ucom_stop_write = uhso_ucom_stop_write,
513 .ucom_free = &uhso_free,
514};
515
516static int
517uhso_probe(device_t self)
518{
519 struct usb_attach_arg *uaa = device_get_ivars(self);
520 int error;
521
522 if (uaa->usb_mode != USB_MODE_HOST)
523 return (ENXIO);
524 if (uaa->info.bConfigIndex != 0)
525 return (ENXIO);
526 if (uaa->info.bDeviceClass != 0xff)
527 return (ENXIO);
528
530 if (error != 0)
531 return (error);
532
533 /*
534 * Probe device to see if we are able to attach
535 * to this interface or not.
536 */
539 uaa->info.bIfaceNum) == 0)
540 return (ENXIO);
541 }
542 return (error);
543}
544
545static int
546uhso_attach(device_t self)
547{
548 struct uhso_softc *sc = device_get_softc(self);
549 struct usb_attach_arg *uaa = device_get_ivars(self);
551 struct sysctl_ctx_list *sctx;
552 struct sysctl_oid *soid;
553 struct sysctl_oid *tree = NULL, *tty_node;
554 struct ucom_softc *ucom;
555 struct uhso_tty *ht;
556 int i, error, port;
557 void *probe_f;
558 usb_error_t uerr;
559 char *desc;
560
561 sc->sc_dev = self;
562 sc->sc_udev = uaa->device;
563 mtx_init(&sc->sc_mtx, "uhso", NULL, MTX_DEF);
564 mbufq_init(&sc->sc_rxq, INT_MAX); /* XXXGL: sane maximum */
566
567 sc->sc_radio = 1;
568
570 sc->sc_ctrl_iface_no = id->bInterfaceNumber;
571
572 sc->sc_iface_no = uaa->info.bIfaceNum;
574
575 /* Setup control pipe */
576 uerr = usbd_transfer_setup(uaa->device,
579 if (uerr) {
580 device_printf(self, "Failed to setup control pipe: %s\n",
581 usbd_errstr(uerr));
582 goto out;
583 }
584
586 probe_f = uhso_probe_iface_static;
587 else if (USB_GET_DRIVER_INFO(uaa) == UHSO_AUTO_IFACE)
588 probe_f = uhso_probe_iface_auto;
589 else
590 goto out;
591
592 error = uhso_probe_iface(sc, uaa->info.bIfaceNum, probe_f);
593 if (error != 0)
594 goto out;
595
596 sctx = device_get_sysctl_ctx(sc->sc_dev);
597 soid = device_get_sysctl_tree(sc->sc_dev);
598
599 SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "type",
600 CTLFLAG_RD, uhso_port[UHSO_IFACE_PORT(sc->sc_type)], 0,
601 "Port available at this interface");
602 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "radio",
603 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, sc, 0,
604 uhso_radio_sysctl, "I", "Enable radio");
605
606 /*
607 * The default interface description on most Option devices isn't
608 * very helpful. So we skip device_set_usb_desc and set the
609 * device description manually.
610 */
611 device_set_desc_copy(self, uhso_port_type[UHSO_IFACE_PORT_TYPE(sc->sc_type)]);
612 /* Announce device */
613 device_printf(self, "<%s port> at <%s %s> on %s\n",
617 device_get_nameunit(device_get_parent(self)));
618
619 if (sc->sc_ttys > 0) {
620 SYSCTL_ADD_INT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "ports",
621 CTLFLAG_RD, &sc->sc_ttys, 0, "Number of attached serial ports");
622
623 tree = SYSCTL_ADD_NODE(sctx, SYSCTL_CHILDREN(soid), OID_AUTO,
624 "port", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Serial ports");
625 }
626
627 /*
628 * Loop through the number of found TTYs and create sysctl
629 * nodes for them.
630 */
631 for (i = 0; i < sc->sc_ttys; i++) {
632 ht = &sc->sc_tty[i];
633 ucom = &sc->sc_ucom[i];
634
636 port = uhso_mux_port_map[ht->ht_muxport];
637 else
638 port = UHSO_IFACE_PORT_TYPE(sc->sc_type);
639
641
642 tty_node = SYSCTL_ADD_NODE(sctx, SYSCTL_CHILDREN(tree), OID_AUTO,
643 desc, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
644
645 ht->ht_name[0] = 0;
646 if (sc->sc_ttys == 1)
647 snprintf(ht->ht_name, 32, "cuaU%d", ucom->sc_super->sc_unit);
648 else {
649 snprintf(ht->ht_name, 32, "cuaU%d.%d",
650 ucom->sc_super->sc_unit, ucom->sc_subunit);
651 }
652
653 desc = uhso_port_type[port];
654 SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(tty_node), OID_AUTO,
655 "tty", CTLFLAG_RD, ht->ht_name, 0, "");
656 SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(tty_node), OID_AUTO,
657 "desc", CTLFLAG_RD, desc, 0, "");
658
659 if (bootverbose)
660 device_printf(sc->sc_dev,
661 "\"%s\" port at %s\n", desc, ht->ht_name);
662 }
663
664 return (0);
665out:
666 uhso_detach(sc->sc_dev);
667 return (ENXIO);
668}
669
670static int
671uhso_detach(device_t self)
672{
673 struct uhso_softc *sc = device_get_softc(self);
674 int i;
675
678 if (sc->sc_ttys > 0) {
680
681 for (i = 0; i < sc->sc_ttys; i++) {
682 if (sc->sc_tty[i].ht_muxport != -1) {
685 }
686 }
687 }
688
689 if (sc->sc_ifp != NULL) {
690 callout_drain(&sc->sc_c);
691 free_unr(uhso_ifnet_unit, sc->sc_ifp->if_dunit);
692 mtx_lock(&sc->sc_mtx);
693 uhso_if_stop(sc);
694 mtx_unlock(&sc->sc_mtx);
695 bpfdetach(sc->sc_ifp);
696 if_detach(sc->sc_ifp);
697 if_free(sc->sc_ifp);
699 }
700
701 device_claim_softc(self);
702
703 uhso_free_softc(sc);
704
705 return (0);
706}
707
709
710static void
712{
713 if (ucom_unref(&sc->sc_super_ucom)) {
714 free(sc->sc_tty, M_USBDEV);
715 free(sc->sc_ucom, M_USBDEV);
716 mtx_destroy(&sc->sc_mtx);
717 device_free_softc(sc);
718 }
719}
720
721static void
723{
725}
726
727static void
728uhso_test_autoinst(void *arg, struct usb_device *udev,
729 struct usb_attach_arg *uaa)
730{
731 struct usb_interface *iface;
733
735 return;
736
737 iface = usbd_get_iface(udev, 0);
738 if (iface == NULL)
739 return;
740 id = iface->idesc;
741 if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
742 return;
743 if (usbd_lookup_id_by_uaa(uhso_devs, sizeof(uhso_devs), uaa))
744 return; /* no device match */
745
746 if (usb_msc_eject(udev, 0, MSC_EJECT_REZERO) == 0) {
747 /* success, mark the udev as disappearing */
749 }
750}
751
752static int
753uhso_driver_loaded(struct module *mod, int what, void *arg)
754{
755 switch (what) {
756 case MOD_LOAD:
757 /* register our autoinstall handler */
758 uhso_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
759 uhso_test_autoinst, NULL, EVENTHANDLER_PRI_ANY);
760 /* create our unit allocator for inet devs */
761 uhso_ifnet_unit = new_unrhdr(0, INT_MAX, NULL);
762 break;
763 case MOD_UNLOAD:
764 EVENTHANDLER_DEREGISTER(usb_dev_configured, uhso_etag);
765 delete_unrhdr(uhso_ifnet_unit);
766 break;
767 default:
768 return (EOPNOTSUPP);
769 }
770 return (0);
771}
772
773/*
774 * Probe the interface type by querying the device. The elements
775 * of an array indicates the capabilities of a particular interface.
776 * Returns a bit mask with the interface capabilities.
777 */
778static int
779uhso_probe_iface_auto(struct usb_device *udev, int index)
780{
781 struct usb_device_request req;
782 usb_error_t uerr;
783 uint16_t actlen = 0;
784 char port;
785 char buf[17] = {0};
786
787 req.bmRequestType = UT_READ_VENDOR_DEVICE;
788 req.bRequest = 0x86;
789 USETW(req.wValue, 0);
790 USETW(req.wIndex, 0);
791 USETW(req.wLength, 17);
792
793 uerr = usbd_do_request_flags(udev, NULL, &req, buf,
794 0, &actlen, USB_MS_HZ);
795 if (uerr != 0) {
796 printf("%s: usbd_do_request_flags failed, %s\n",
797 __func__, usbd_errstr(uerr));
798 return (0);
799 }
800
801 UHSO_DPRINTF(1, "actlen=%d\n", actlen);
802 UHSO_HEXDUMP(buf, 17);
803
804 if (index < 0 || index > 16) {
805 UHSO_DPRINTF(0, "Index %d out of range\n", index);
806 return (0);
807 }
808
809 UHSO_DPRINTF(1, "index=%d, type=%x[%s]\n", index, buf[index],
810 uhso_port_type[(int)uhso_port_map[(int)buf[index]]]);
811
812 if (buf[index] >= uhso_port_map_max)
813 port = 0;
814 else
815 port = uhso_port_map[(int)buf[index]];
816
817 switch (port) {
830 UHSO_PORT_SERIAL, port));
832 return (0);
834 default:
835 return (0);
836 }
837
838 return (0);
839}
840
841/*
842 * Returns the capabilities of interfaces for devices that don't
843 * support the automatic query.
844 * Returns a bit mask with the interface capabilities.
845 */
846static int
847uhso_probe_iface_static(struct usb_device *udev, int index)
848{
849 struct usb_config_descriptor *cd;
850
852 if (cd->bNumInterface <= 3) {
853 /* Cards with 3 or less interfaces */
854 switch (index) {
855 case 0:
859 case 1:
862 case 2:
865 }
866 } else {
867 /* Cards with 4 interfaces */
868 switch (index) {
869 case 0:
873 case 1:
876 case 2:
879 case 3:
882 }
883 }
884 return (0);
885}
886
887/*
888 * Probes an interface for its particular capabilities and attaches if
889 * it's a supported interface.
890 */
891static int
892uhso_probe_iface(struct uhso_softc *sc, int index,
893 int (*probe)(struct usb_device *, int))
894{
895 struct usb_interface *iface;
896 int type, error;
897
898 UHSO_DPRINTF(1, "Probing for interface %d, probe_func=%p\n", index, probe);
899
900 type = probe(sc->sc_udev, index);
901 UHSO_DPRINTF(1, "Probe result %x\n", type);
902 if (type <= 0)
903 return (ENXIO);
904
905 sc->sc_type = type;
906 iface = usbd_get_iface(sc->sc_udev, index);
907
909 error = uhso_attach_ifnet(sc, iface, type);
910 if (error) {
911 UHSO_DPRINTF(1, "uhso_attach_ifnet failed");
912 return (ENXIO);
913 }
914
915 /*
916 * If there is an additional interrupt endpoint on this
917 * interface then we most likely have a multiplexed serial port
918 * available.
919 */
920 if (iface->idesc->bNumEndpoints < 3) {
925 return (0);
926 }
927
928 UHSO_DPRINTF(1, "Trying to attach mux. serial\n");
929 error = uhso_attach_muxserial(sc, iface, type);
930 if (error == 0 && sc->sc_ttys > 0) {
932 sc->sc_ttys, sc, &uhso_ucom_callback, &sc->sc_mtx);
933 if (error) {
934 device_printf(sc->sc_dev, "ucom_attach failed\n");
935 return (ENXIO);
936 }
938
939 mtx_lock(&sc->sc_mtx);
941 mtx_unlock(&sc->sc_mtx);
942 }
943 } else if ((UHSO_IFACE_USB_TYPE(type) & UHSO_IF_BULK) &&
945 error = uhso_attach_bulkserial(sc, iface, type);
946 if (error)
947 return (ENXIO);
948
950 sc->sc_ttys, sc, &uhso_ucom_callback, &sc->sc_mtx);
951 if (error) {
952 device_printf(sc->sc_dev, "ucom_attach failed\n");
953 return (ENXIO);
954 }
956 }
957 else {
958 UHSO_DPRINTF(0, "Unknown type %x\n", type);
959 return (ENXIO);
960 }
961
962 return (0);
963}
964
965static int
966uhso_radio_ctrl(struct uhso_softc *sc, int onoff)
967{
968 struct usb_device_request req;
969 usb_error_t uerr;
970
971 req.bmRequestType = UT_VENDOR;
972 req.bRequest = onoff ? 0x82 : 0x81;
973 USETW(req.wValue, 0);
974 USETW(req.wIndex, 0);
975 USETW(req.wLength, 0);
976
977 uerr = usbd_do_request(sc->sc_udev, NULL, &req, NULL);
978 if (uerr != 0) {
979 device_printf(sc->sc_dev, "usbd_do_request_flags failed: %s\n",
980 usbd_errstr(uerr));
981 return (-1);
982 }
983 return (onoff);
984}
985
986static int
987uhso_radio_sysctl(SYSCTL_HANDLER_ARGS)
988{
989 struct uhso_softc *sc = arg1;
990 int error, radio;
991
992 radio = sc->sc_radio;
993 error = sysctl_handle_int(oidp, &radio, 0, req);
994 if (error)
995 return (error);
996 if (radio != sc->sc_radio) {
997 radio = radio != 0 ? 1 : 0;
998 error = uhso_radio_ctrl(sc, radio);
999 if (error != -1)
1000 sc->sc_radio = radio;
1001
1002 }
1003 return (0);
1004}
1005
1006/*
1007 * Expands allocated memory to fit an additional TTY.
1008 * Two arrays are kept with matching indexes, one for ucom and one
1009 * for our private data.
1010 */
1011static int
1013{
1014
1015 sc->sc_ttys++;
1016 sc->sc_tty = reallocf(sc->sc_tty, sizeof(struct uhso_tty) * sc->sc_ttys,
1017 M_USBDEV, M_WAITOK | M_ZERO);
1018 if (sc->sc_tty == NULL)
1019 return (-1);
1020
1021 sc->sc_ucom = reallocf(sc->sc_ucom,
1022 sizeof(struct ucom_softc) * sc->sc_ttys, M_USBDEV, M_WAITOK | M_ZERO);
1023 if (sc->sc_ucom == NULL)
1024 return (-1);
1025
1026 sc->sc_tty[sc->sc_ttys - 1].ht_sc = sc;
1027
1028 UHSO_DPRINTF(1, "Allocated TTY %d\n", sc->sc_ttys - 1);
1029 return (sc->sc_ttys - 1);
1030}
1031
1032/*
1033 * Attach a multiplexed serial port
1034 * Data is read/written with requests on the default control pipe. An interrupt
1035 * endpoint returns when there is new data to be read.
1036 */
1037static int
1039 int type)
1040{
1041 struct usb_descriptor *desc;
1042 int i, port, tty;
1043 usb_error_t uerr;
1044
1045 /*
1046 * The class specific interface (type 0x24) descriptor subtype field
1047 * contains a bitmask that specifies which (and how many) ports that
1048 * are available through this multiplexed serial port.
1049 */
1050 desc = usbd_find_descriptor(sc->sc_udev, NULL,
1051 iface->idesc->bInterfaceNumber, UDESC_CS_INTERFACE, 0xff, 0, 0);
1052 if (desc == NULL) {
1053 UHSO_DPRINTF(0, "Failed to find UDESC_CS_INTERFACE\n");
1054 return (ENXIO);
1055 }
1056
1057 UHSO_DPRINTF(1, "Mux port mask %x\n", desc->bDescriptorSubtype);
1058 if (desc->bDescriptorSubtype == 0)
1059 return (ENXIO);
1060
1061 /*
1062 * The bitmask is one octet, loop through the number of
1063 * bits that are set and create a TTY for each.
1064 */
1065 for (i = 0; i < 8; i++) {
1066 port = (1 << i);
1067 if ((port & desc->bDescriptorSubtype) == port) {
1068 UHSO_DPRINTF(2, "Found mux port %x (%d)\n", port, i);
1069 tty = uhso_alloc_tty(sc);
1070 if (tty < 0)
1071 return (ENOMEM);
1072 sc->sc_tty[tty].ht_muxport = i;
1073 uerr = usbd_transfer_setup(sc->sc_udev,
1074 &sc->sc_iface_index, sc->sc_tty[tty].ht_xfer,
1076 if (uerr) {
1077 device_printf(sc->sc_dev,
1078 "Failed to setup control pipe: %s\n",
1079 usbd_errstr(uerr));
1080 return (ENXIO);
1081 }
1082 }
1083 }
1084
1085 /* Setup the intr. endpoint */
1086 uerr = usbd_transfer_setup(sc->sc_udev,
1087 &iface->idesc->bInterfaceNumber, sc->sc_xfer,
1088 uhso_mux_config, 1, sc, &sc->sc_mtx);
1089 if (uerr)
1090 return (ENXIO);
1091
1092 return (0);
1093}
1094
1095/*
1096 * Interrupt callback for the multiplexed serial port. Indicates
1097 * which serial port has data waiting.
1098 */
1099static void
1101{
1102 struct usb_page_cache *pc;
1103 struct usb_page_search res;
1104 struct uhso_softc *sc = usbd_xfer_softc(xfer);
1105 unsigned int i, mux;
1106
1107 UHSO_DPRINTF(3, "status %d\n", USB_GET_STATE(xfer));
1108
1109 switch (USB_GET_STATE(xfer)) {
1110 case USB_ST_TRANSFERRED:
1111 /*
1112 * The multiplexed port number can be found at the first byte.
1113 * It contains a bit mask, we transform this in to an integer.
1114 */
1115 pc = usbd_xfer_get_frame(xfer, 0);
1116 usbd_get_page(pc, 0, &res);
1117
1118 i = *((unsigned char *)res.buffer);
1119 mux = 0;
1120 while (i >>= 1) {
1121 mux++;
1122 }
1123
1124 UHSO_DPRINTF(3, "mux port %d (%d)\n", mux, i);
1125 if (mux > UHSO_MPORT_TYPE_NOMAX)
1126 break;
1127
1128 /* Issue a read for this serial port */
1130 sc->sc_tty[mux].ht_xfer[UHSO_CTRL_READ],
1131 &sc->sc_tty[mux]);
1133
1134 break;
1135 case USB_ST_SETUP:
1136tr_setup:
1139 break;
1140 default:
1141 UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error));
1142 if (error == USB_ERR_CANCELLED)
1143 break;
1144
1145 usbd_xfer_set_stall(xfer);
1146 goto tr_setup;
1147 }
1148}
1149
1150static void
1152{
1153 struct uhso_softc *sc = usbd_xfer_softc(xfer);
1154 struct usb_page_cache *pc;
1155 struct usb_device_request req;
1156 struct uhso_tty *ht;
1157 int actlen, len;
1158
1159 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1160
1161 UHSO_DPRINTF(3, "status %d\n", USB_GET_STATE(xfer));
1162
1163 ht = usbd_xfer_get_priv(xfer);
1164 UHSO_DPRINTF(3, "ht=%p open=%d\n", ht, ht->ht_open);
1165
1166 switch (USB_GET_STATE(xfer)) {
1167 case USB_ST_TRANSFERRED:
1168 /* Got data, send to ucom */
1169 pc = usbd_xfer_get_frame(xfer, 1);
1170 len = usbd_xfer_frame_len(xfer, 1);
1171
1172 UHSO_DPRINTF(3, "got %d bytes on mux port %d\n", len,
1173 ht->ht_muxport);
1174 if (len <= 0) {
1176 break;
1177 }
1178
1179 /* Deliver data if the TTY is open, discard otherwise */
1180 if (ht->ht_open)
1181 ucom_put_data(&sc->sc_ucom[ht->ht_muxport], pc, 0, len);
1182 /* FALLTHROUGH */
1183 case USB_ST_SETUP:
1184tr_setup:
1185 memset(&req, 0, sizeof(struct usb_device_request));
1186 req.bmRequestType = UT_READ_CLASS_INTERFACE;
1188 USETW(req.wValue, 0);
1189 USETW(req.wIndex, ht->ht_muxport);
1190 USETW(req.wLength, 1024);
1191
1192 pc = usbd_xfer_get_frame(xfer, 0);
1193 usbd_copy_in(pc, 0, &req, sizeof(req));
1194
1195 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1196 usbd_xfer_set_frame_len(xfer, 1, 1024);
1197 usbd_xfer_set_frames(xfer, 2);
1199 break;
1200 default:
1201 UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error));
1202 if (error == USB_ERR_CANCELLED)
1203 break;
1204 usbd_xfer_set_stall(xfer);
1205 goto tr_setup;
1206 }
1207}
1208
1209static void
1211{
1212 struct uhso_softc *sc = usbd_xfer_softc(xfer);
1213 struct uhso_tty *ht;
1214 struct usb_page_cache *pc;
1215 struct usb_device_request req;
1216 int actlen;
1217 struct usb_page_search res;
1218
1219 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1220
1221 ht = usbd_xfer_get_priv(xfer);
1222 UHSO_DPRINTF(3, "status=%d, using mux port %d\n",
1223 USB_GET_STATE(xfer), ht->ht_muxport);
1224
1225 switch (USB_GET_STATE(xfer)) {
1226 case USB_ST_TRANSFERRED:
1227 UHSO_DPRINTF(3, "wrote %zd data bytes to muxport %d\n",
1228 actlen - sizeof(struct usb_device_request) ,
1229 ht->ht_muxport);
1230 /* FALLTHROUGH */
1231 case USB_ST_SETUP:
1232tr_setup:
1233 pc = usbd_xfer_get_frame(xfer, 1);
1234 if (ucom_get_data(&sc->sc_ucom[ht->ht_muxport], pc,
1235 0, 32, &actlen)) {
1236 usbd_get_page(pc, 0, &res);
1237
1238 memset(&req, 0, sizeof(struct usb_device_request));
1239 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1241 USETW(req.wValue, 0);
1242 USETW(req.wIndex, ht->ht_muxport);
1243 USETW(req.wLength, actlen);
1244
1245 pc = usbd_xfer_get_frame(xfer, 0);
1246 usbd_copy_in(pc, 0, &req, sizeof(req));
1247
1248 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1249 usbd_xfer_set_frame_len(xfer, 1, actlen);
1250 usbd_xfer_set_frames(xfer, 2);
1251
1252 UHSO_DPRINTF(3, "Prepared %d bytes for transmit "
1253 "on muxport %d\n", actlen, ht->ht_muxport);
1254
1256 }
1257 break;
1258 default:
1259 UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error));
1260 if (error == USB_ERR_CANCELLED)
1261 break;
1262 usbd_xfer_set_stall(xfer);
1263 goto tr_setup;
1264 }
1265}
1266
1267static int
1269 int type)
1270{
1271 usb_error_t uerr;
1272 int tty;
1273
1274 /* Try attaching RD/WR/INTR first */
1275 uerr = usbd_transfer_setup(sc->sc_udev,
1276 &iface->idesc->bInterfaceNumber, sc->sc_xfer,
1278 if (uerr) {
1279 /* Try only RD/WR */
1280 uerr = usbd_transfer_setup(sc->sc_udev,
1281 &iface->idesc->bInterfaceNumber, sc->sc_xfer,
1283 }
1284 if (uerr) {
1285 UHSO_DPRINTF(0, "usbd_transfer_setup failed");
1286 return (-1);
1287 }
1288
1289 tty = uhso_alloc_tty(sc);
1290 if (tty < 0) {
1292 return (ENOMEM);
1293 }
1294
1295 sc->sc_tty[tty].ht_muxport = -1;
1296 return (0);
1297}
1298
1299static void
1301{
1302 struct uhso_softc *sc = usbd_xfer_softc(xfer);
1303 struct usb_page_cache *pc;
1304 int actlen;
1305
1306 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1307
1308 UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen);
1309
1310 switch (USB_GET_STATE(xfer)) {
1311 case USB_ST_TRANSFERRED:
1312 pc = usbd_xfer_get_frame(xfer, 0);
1313 ucom_put_data(&sc->sc_ucom[0], pc, 0, actlen);
1314 /* FALLTHROUGH */
1315 case USB_ST_SETUP:
1316tr_setup:
1319 break;
1320 default:
1321 UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error));
1322 if (error == USB_ERR_CANCELLED)
1323 break;
1324 usbd_xfer_set_stall(xfer);
1325 goto tr_setup;
1326 }
1327}
1328
1329static void
1331{
1332 struct uhso_softc *sc = usbd_xfer_softc(xfer);
1333 struct usb_page_cache *pc;
1334 int actlen;
1335
1336 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1337
1338 UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen);
1339
1340 switch (USB_GET_STATE(xfer)) {
1341 case USB_ST_TRANSFERRED:
1342 case USB_ST_SETUP:
1343tr_setup:
1344 pc = usbd_xfer_get_frame(xfer, 0);
1345 if (ucom_get_data(&sc->sc_ucom[0], pc, 0, 8192, &actlen)) {
1346 usbd_xfer_set_frame_len(xfer, 0, actlen);
1348 }
1349 break;
1350 break;
1351 default:
1352 UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error));
1353 if (error == USB_ERR_CANCELLED)
1354 break;
1355 usbd_xfer_set_stall(xfer);
1356 goto tr_setup;
1357 }
1358}
1359
1360static void
1362{
1363 struct usb_device_request req;
1364 usb_error_t uerr;
1365
1367 return;
1368
1369 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1371 USETW(req.wValue, sc->sc_line);
1372 USETW(req.wIndex, sc->sc_iface_no);
1373 USETW(req.wLength, 0);
1374
1375 uerr = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom[0], &req, NULL, 0, 1000);
1376 if (uerr != 0) {
1377 device_printf(sc->sc_dev, "failed to set ctrl line state to "
1378 "0x%02x: %s\n", sc->sc_line, usbd_errstr(uerr));
1379 }
1380}
1381
1382static void
1384{
1385 struct uhso_softc *sc = usbd_xfer_softc(xfer);
1386 struct usb_page_cache *pc;
1387 int actlen;
1388 struct usb_cdc_notification cdc;
1389
1390 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1391 UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen);
1392
1393 switch (USB_GET_STATE(xfer)) {
1394 case USB_ST_TRANSFERRED:
1395 if (actlen < UCDC_NOTIFICATION_LENGTH) {
1396 UHSO_DPRINTF(0, "UCDC notification too short: %d\n", actlen);
1397 goto tr_setup;
1398 }
1399 else if (actlen > (int)sizeof(struct usb_cdc_notification)) {
1400 UHSO_DPRINTF(0, "UCDC notification too large: %d\n", actlen);
1401 actlen = sizeof(struct usb_cdc_notification);
1402 }
1403
1404 pc = usbd_xfer_get_frame(xfer, 0);
1405 usbd_copy_out(pc, 0, &cdc, actlen);
1406
1407 if (UGETW(cdc.wIndex) != sc->sc_iface_no) {
1408 UHSO_DPRINTF(0, "Interface mismatch, got %d expected %d\n",
1409 UGETW(cdc.wIndex), sc->sc_iface_no);
1410 goto tr_setup;
1411 }
1412
1413 if (cdc.bmRequestType == UCDC_NOTIFICATION &&
1415 UHSO_DPRINTF(2, "notify = 0x%02x\n", cdc.data[0]);
1416
1417 sc->sc_msr = 0;
1418 sc->sc_lsr = 0;
1419 if (cdc.data[0] & UCDC_N_SERIAL_RI)
1420 sc->sc_msr |= SER_RI;
1421 if (cdc.data[0] & UCDC_N_SERIAL_DSR)
1422 sc->sc_msr |= SER_DSR;
1423 if (cdc.data[0] & UCDC_N_SERIAL_DCD)
1424 sc->sc_msr |= SER_DCD;
1425
1426 ucom_status_change(&sc->sc_ucom[0]);
1427 }
1428 case USB_ST_SETUP:
1429tr_setup:
1430 default:
1431 if (error == USB_ERR_CANCELLED)
1432 break;
1433 usbd_xfer_set_stall(xfer);
1434 goto tr_setup;
1435 }
1436}
1437
1438static void
1439uhso_ucom_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
1440{
1441 struct uhso_softc *sc = ucom->sc_parent;
1442
1443 *lsr = sc->sc_lsr;
1444 *msr = sc->sc_msr;
1445}
1446
1447static void
1448uhso_ucom_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
1449{
1450 struct uhso_softc *sc = ucom->sc_parent;
1451
1453 return;
1454
1455 if (onoff)
1456 sc->sc_line |= UCDC_LINE_DTR;
1457 else
1458 sc->sc_line &= ~UCDC_LINE_DTR;
1459
1460 uhso_bs_cfg(sc);
1461}
1462
1463static void
1464uhso_ucom_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
1465{
1466 struct uhso_softc *sc = ucom->sc_parent;
1467
1469 return;
1470
1471 if (onoff)
1472 sc->sc_line |= UCDC_LINE_RTS;
1473 else
1474 sc->sc_line &= ~UCDC_LINE_RTS;
1475
1476 uhso_bs_cfg(sc);
1477}
1478
1479static void
1481{
1482 struct uhso_softc *sc = ucom->sc_parent;
1483
1484 UHSO_DPRINTF(3, "unit=%d, subunit=%d\n",
1485 ucom->sc_super->sc_unit, ucom->sc_subunit);
1486
1488 sc->sc_tty[ucom->sc_subunit].ht_open = 1;
1490 }
1491 else if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK) {
1492 sc->sc_tty[0].ht_open = 1;
1494 if (sc->sc_xfer[UHSO_BULK_ENDPT_INTR] != NULL)
1496 }
1497}
1498
1499static void
1501{
1502
1503 struct uhso_softc *sc = ucom->sc_parent;
1504
1506 sc->sc_tty[ucom->sc_subunit].ht_open = 0;
1509 }
1510 else if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK) {
1511 sc->sc_tty[0].ht_open = 0;
1513 if (sc->sc_xfer[UHSO_BULK_ENDPT_INTR] != NULL)
1515 }
1516}
1517
1518static void
1520{
1521 struct uhso_softc *sc = ucom->sc_parent;
1522
1524 UHSO_DPRINTF(3, "local unit %d\n", ucom->sc_subunit);
1525
1527
1530 &sc->sc_tty[ucom->sc_subunit]);
1533 }
1534 else if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK) {
1536 }
1537}
1538
1539static void
1541{
1542 struct uhso_softc *sc = ucom->sc_parent;
1543
1547 }
1548 else if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK) {
1550 }
1551}
1552
1553static int
1554uhso_attach_ifnet(struct uhso_softc *sc, struct usb_interface *iface, int type)
1555{
1556 struct ifnet *ifp;
1557 usb_error_t uerr;
1558 struct sysctl_ctx_list *sctx;
1559 struct sysctl_oid *soid;
1560 unsigned int devunit;
1561
1562 uerr = usbd_transfer_setup(sc->sc_udev,
1563 &iface->idesc->bInterfaceNumber, sc->sc_if_xfer,
1565 if (uerr) {
1566 UHSO_DPRINTF(0, "usbd_transfer_setup failed: %s\n",
1567 usbd_errstr(uerr));
1568 return (-1);
1569 }
1570
1571 sc->sc_ifp = ifp = if_alloc(IFT_OTHER);
1572 if (sc->sc_ifp == NULL) {
1573 device_printf(sc->sc_dev, "if_alloc() failed\n");
1574 return (-1);
1575 }
1576
1577 callout_init_mtx(&sc->sc_c, &sc->sc_mtx, 0);
1578 mtx_lock(&sc->sc_mtx);
1579 callout_reset(&sc->sc_c, 1, uhso_if_rxflush, sc);
1580 mtx_unlock(&sc->sc_mtx);
1581
1582 /*
1583 * We create our own unit numbers for ifnet devices because the
1584 * USB interface unit numbers can be at arbitrary positions yielding
1585 * odd looking device names.
1586 */
1587 devunit = alloc_unr(uhso_ifnet_unit);
1588
1589 if_initname(ifp, device_get_name(sc->sc_dev), devunit);
1590 ifp->if_mtu = UHSO_MAX_MTU;
1591 ifp->if_ioctl = uhso_if_ioctl;
1592 ifp->if_init = uhso_if_init;
1593 ifp->if_start = uhso_if_start;
1594 ifp->if_output = uhso_if_output;
1595 ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_NOARP;
1596 ifp->if_softc = sc;
1597 IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
1598 ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
1599 IFQ_SET_READY(&ifp->if_snd);
1600
1601 if_attach(ifp);
1602 bpfattach(ifp, DLT_RAW, 0);
1603
1604 sctx = device_get_sysctl_ctx(sc->sc_dev);
1605 soid = device_get_sysctl_tree(sc->sc_dev);
1606 /* Unlocked read... */
1607 SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "netif",
1608 CTLFLAG_RD, ifp->if_xname, 0, "Attached network interface");
1609
1610 return (0);
1611}
1612
1613static void
1615{
1616 struct uhso_softc *sc = usbd_xfer_softc(xfer);
1617 struct mbuf *m;
1618 struct usb_page_cache *pc;
1619 int actlen;
1620
1621 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1622
1623 UHSO_DPRINTF(3, "status=%d, actlen=%d\n", USB_GET_STATE(xfer), actlen);
1624
1625 switch (USB_GET_STATE(xfer)) {
1626 case USB_ST_TRANSFERRED:
1627 if (actlen > 0 && (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1628 pc = usbd_xfer_get_frame(xfer, 0);
1629 if (mbufq_full(&sc->sc_rxq))
1630 break;
1631 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1632 usbd_copy_out(pc, 0, mtod(m, uint8_t *), actlen);
1633 m->m_pkthdr.len = m->m_len = actlen;
1634 /* Enqueue frame for further processing */
1635 mbufq_enqueue(&sc->sc_rxq, m);
1636 if (!callout_pending(&sc->sc_c) ||
1637 !callout_active(&sc->sc_c)) {
1638 callout_schedule(&sc->sc_c, 1);
1639 }
1640 }
1641 /* FALLTHROUGH */
1642 case USB_ST_SETUP:
1643tr_setup:
1646 break;
1647 default:
1648 UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error));
1649 if (error == USB_ERR_CANCELLED)
1650 break;
1651 usbd_xfer_set_stall(xfer);
1652 goto tr_setup;
1653 }
1654}
1655
1656/*
1657 * Deferred RX processing, called with mutex locked.
1658 *
1659 * Each frame we receive might contain several small ip-packets as well
1660 * as partial ip-packets. We need to separate/assemble them into individual
1661 * packets before sending them to the ip-layer.
1662 */
1663static void
1665{
1666 struct epoch_tracker et;
1667 struct uhso_softc *sc = arg;
1668 struct ifnet *ifp = sc->sc_ifp;
1669 uint8_t *cp;
1670 struct mbuf *m, *m0, *mwait;
1671 struct ip *ip;
1672#ifdef INET6
1673 struct ip6_hdr *ip6;
1674#endif
1675 uint16_t iplen;
1676 int isr;
1677
1678 m = NULL;
1679 mwait = sc->sc_mwait;
1680 NET_EPOCH_ENTER(et);
1681 for (;;) {
1682 if (m == NULL) {
1683 if ((m = mbufq_dequeue(&sc->sc_rxq)) == NULL)
1684 break;
1685 UHSO_DPRINTF(3, "dequeue m=%p, len=%d\n", m, m->m_len);
1686 }
1687 mtx_unlock(&sc->sc_mtx);
1688
1689 /* Do we have a partial packet waiting? */
1690 if (mwait != NULL) {
1691 m0 = mwait;
1692 mwait = NULL;
1693
1694 UHSO_DPRINTF(3, "partial m0=%p(%d), concat w/ m=%p(%d)\n",
1695 m0, m0->m_len, m, m->m_len);
1696
1697 m_catpkt(m0, m);
1698 m = m_pullup(m0, sizeof(struct ip));
1699 if (m == NULL) {
1700 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1701 UHSO_DPRINTF(0, "m_pullup failed\n");
1702 mtx_lock(&sc->sc_mtx);
1703 continue;
1704 }
1705 UHSO_DPRINTF(3, "Constructed mbuf=%p, len=%d\n",
1706 m, m->m_pkthdr.len);
1707 }
1708
1709 cp = mtod(m, uint8_t *);
1710 ip = (struct ip *)cp;
1711#ifdef INET6
1712 ip6 = (struct ip6_hdr *)cp;
1713#endif
1714
1715 /* Check for IPv4 */
1716 if (ip->ip_v == IPVERSION) {
1717 iplen = htons(ip->ip_len);
1718 isr = NETISR_IP;
1719 }
1720#ifdef INET6
1721 /* Check for IPv6 */
1722 else if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION) {
1723 iplen = htons(ip6->ip6_plen);
1724 isr = NETISR_IPV6;
1725 }
1726#endif
1727 else {
1728 UHSO_DPRINTF(0, "got unexpected ip version %d, "
1729 "m=%p, len=%d\n", (*cp & 0xf0) >> 4, m, m->m_len);
1730 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1731 UHSO_HEXDUMP(cp, 4);
1732 m_freem(m);
1733 m = NULL;
1734 mtx_lock(&sc->sc_mtx);
1735 continue;
1736 }
1737
1738 if (iplen == 0) {
1739 UHSO_DPRINTF(0, "Zero IP length\n");
1740 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1741 m_freem(m);
1742 m = NULL;
1743 mtx_lock(&sc->sc_mtx);
1744 continue;
1745 }
1746
1747 UHSO_DPRINTF(3, "m=%p, len=%d, cp=%p, iplen=%d\n",
1748 m, m->m_pkthdr.len, cp, iplen);
1749
1750 m0 = NULL;
1751
1752 /* More IP packets in this mbuf */
1753 if (iplen < m->m_pkthdr.len) {
1754 m0 = m;
1755
1756 /*
1757 * Allocate a new mbuf for this IP packet and
1758 * copy the IP-packet into it.
1759 */
1760 m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
1761 memcpy(mtod(m, uint8_t *), mtod(m0, uint8_t *), iplen);
1762 m->m_pkthdr.len = m->m_len = iplen;
1763
1764 /* Adjust the size of the original mbuf */
1765 m_adj(m0, iplen);
1766 m0 = m_defrag(m0, M_WAITOK);
1767
1768 UHSO_DPRINTF(3, "New mbuf=%p, len=%d/%d, m0=%p, "
1769 "m0_len=%d/%d\n", m, m->m_pkthdr.len, m->m_len,
1770 m0, m0->m_pkthdr.len, m0->m_len);
1771 }
1772 else if (iplen > m->m_pkthdr.len) {
1773 UHSO_DPRINTF(3, "Deferred mbuf=%p, len=%d\n",
1774 m, m->m_pkthdr.len);
1775 mwait = m;
1776 m = NULL;
1777 mtx_lock(&sc->sc_mtx);
1778 continue;
1779 }
1780
1781 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
1782 m->m_pkthdr.rcvif = ifp;
1783
1784 /* Dispatch to IP layer */
1785 BPF_MTAP(sc->sc_ifp, m);
1786 M_SETFIB(m, ifp->if_fib);
1787 netisr_dispatch(isr, m);
1788 m = m0 != NULL ? m0 : NULL;
1789 mtx_lock(&sc->sc_mtx);
1790 }
1791 NET_EPOCH_EXIT(et);
1792 sc->sc_mwait = mwait;
1793}
1794
1795static void
1797{
1798 struct uhso_softc *sc = usbd_xfer_softc(xfer);
1799 struct ifnet *ifp = sc->sc_ifp;
1800 struct usb_page_cache *pc;
1801 struct mbuf *m;
1802 int actlen;
1803
1804 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1805
1806 UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen);
1807
1808 switch (USB_GET_STATE(xfer)) {
1809 case USB_ST_TRANSFERRED:
1810 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
1811 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1812 case USB_ST_SETUP:
1813tr_setup:
1814 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
1815 if (m == NULL)
1816 break;
1817
1818 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1819
1820 if (m->m_pkthdr.len > MCLBYTES)
1821 m->m_pkthdr.len = MCLBYTES;
1822
1823 usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
1824 pc = usbd_xfer_get_frame(xfer, 0);
1825 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
1827
1828 BPF_MTAP(ifp, m);
1829 m_freem(m);
1830 break;
1831 default:
1832 UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error));
1833 if (error == USB_ERR_CANCELLED)
1834 break;
1835 usbd_xfer_set_stall(xfer);
1836 goto tr_setup;
1837 }
1838}
1839
1840static int
1841uhso_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1842{
1843 struct uhso_softc *sc;
1844
1845 sc = ifp->if_softc;
1846
1847 switch (cmd) {
1848 case SIOCSIFFLAGS:
1849 if (ifp->if_flags & IFF_UP) {
1850 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1851 uhso_if_init(sc);
1852 }
1853 }
1854 else {
1855 if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1856 mtx_lock(&sc->sc_mtx);
1857 uhso_if_stop(sc);
1858 mtx_unlock(&sc->sc_mtx);
1859 }
1860 }
1861 break;
1862 case SIOCSIFADDR:
1863 case SIOCADDMULTI:
1864 case SIOCDELMULTI:
1865 break;
1866 default:
1867 return (EINVAL);
1868 }
1869 return (0);
1870}
1871
1872static void
1873uhso_if_init(void *priv)
1874{
1875 struct uhso_softc *sc = priv;
1876 struct ifnet *ifp = sc->sc_ifp;
1877
1878 mtx_lock(&sc->sc_mtx);
1879 uhso_if_stop(sc);
1880 ifp = sc->sc_ifp;
1881 ifp->if_flags |= IFF_UP;
1882 ifp->if_drv_flags |= IFF_DRV_RUNNING;
1883 mtx_unlock(&sc->sc_mtx);
1884
1885 UHSO_DPRINTF(2, "ifnet initialized\n");
1886}
1887
1888static int
1889uhso_if_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
1890 struct route *ro)
1891{
1892 int error;
1893
1894 /* Only IPv4/6 support */
1895 if (dst->sa_family != AF_INET
1896#ifdef INET6
1897 && dst->sa_family != AF_INET6
1898#endif
1899 ) {
1900 return (EAFNOSUPPORT);
1901 }
1902
1903 error = (ifp->if_transmit)(ifp, m0);
1904 if (error) {
1905 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1906 return (ENOBUFS);
1907 }
1908 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
1909 return (0);
1910}
1911
1912static void
1913uhso_if_start(struct ifnet *ifp)
1914{
1915 struct uhso_softc *sc = ifp->if_softc;
1916
1917 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1918 UHSO_DPRINTF(1, "Not running\n");
1919 return;
1920 }
1921
1922 mtx_lock(&sc->sc_mtx);
1925 mtx_unlock(&sc->sc_mtx);
1926 UHSO_DPRINTF(3, "interface started\n");
1927}
1928
1929static void
1931{
1932
1935 sc->sc_ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1936}
static int debug
Definition: cfumass.c:73
uint16_t len
Definition: ehci.h:41
struct @109 error
uint8_t id
Definition: if_usievar.h:4
u_int index
enum pci_id_type type
void(* ucom_cfg_get_status)(struct ucom_softc *, uint8_t *plsr, uint8_t *pmsr)
Definition: usb_serial.h:90
void * sc_parent
Definition: usb_serial.h:170
struct ucom_super_softc * sc_super
Definition: usb_serial.h:166
int sc_subunit
Definition: usb_serial.h:171
device_t sc_dev
Definition: uhso.c:82
uint8_t sc_iface_index
Definition: uhso.c:90
struct ucom_softc * sc_ucom
Definition: uhso.c:108
uint8_t sc_ctrl_iface_no
Definition: uhso.c:94
int sc_radio
Definition: uhso.c:86
struct usb_device * sc_udev
Definition: uhso.c:83
struct mtx sc_mtx
Definition: uhso.c:84
uint8_t sc_iface_no
Definition: uhso.c:89
struct ifnet * sc_ifp
Definition: uhso.c:98
struct usb_xfer * sc_ctrl_xfer[2]
Definition: uhso.c:93
struct uhso_tty * sc_tty
Definition: uhso.c:107
struct mbufq sc_rxq
Definition: uhso.c:101
struct ucom_super_softc sc_super_ucom
Definition: uhso.c:105
int sc_line
Definition: uhso.c:111
uint32_t sc_type
Definition: uhso.c:85
int sc_msr
Definition: uhso.c:109
struct mbuf * sc_mwait
Definition: uhso.c:99
struct usb_xfer * sc_if_xfer[2]
Definition: uhso.c:97
int sc_ttys
Definition: uhso.c:106
int sc_lsr
Definition: uhso.c:110
struct callout sc_c
Definition: uhso.c:102
size_t sc_waitlen
Definition: uhso.c:100
struct usb_xfer * sc_xfer[3]
Definition: uhso.c:88
Definition: uhso.c:73
int ht_muxport
Definition: uhso.c:76
struct usb_xfer * ht_xfer[3]
Definition: uhso.c:75
int ht_open
Definition: uhso.c:77
char ht_name[32]
Definition: uhso.c:78
struct uhso_softc * ht_sc
Definition: uhso.c:74
enum usb_hc_mode usb_mode
Definition: usbdi.h:432
uint8_t dev_state
Definition: usbdi.h:434
struct usbd_lookup_info info
Definition: usbdi.h:426
struct usb_interface * iface
Definition: usbdi.h:431
struct usb_device * device
Definition: usbdi.h:430
uByte data[16]
Definition: usb_cdc.h:160
uByte bNumInterface
Definition: usb.h:389
uint8_t type
Definition: usbdi.h:238
uByte bInterfaceNumber
Definition: usb.h:405
struct usb_interface_descriptor * idesc
Definition: usbdi.h:175
uint8_t bIfaceNum
Definition: usbdi.h:418
uint8_t bIfaceIndex
Definition: usbdi.h:417
uint8_t bDeviceClass
Definition: usbdi.h:411
uint8_t bConfigIndex
Definition: usbdi.h:419
static SYSCTL_NODE(_hw_usb, OID_AUTO, uhso, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "USB uhso")
#define UHSO_IF_MUX
Definition: uhso.c:135
static char * uhso_port_type_sysctl[]
Definition: uhso.c:231
static unsigned char uhso_port_map[]
Definition: uhso.c:191
@ UHSO_BULK_ENDPT_WRITE
Definition: uhso.c:349
@ UHSO_BULK_ENDPT_INTR
Definition: uhso.c:350
@ UHSO_BULK_ENDPT_READ
Definition: uhso.c:348
@ UHSO_BULK_ENDPT_MAX
Definition: uhso.c:351
static char * uhso_port_type[]
Definition: uhso.c:215
static void uhso_if_init(void *)
Definition: uhso.c:1873
static int uhso_probe_iface_auto(struct usb_device *, int)
Definition: uhso.c:779
static const struct usb_config uhso_ifnet_config[UHSO_IFNET_MAX]
Definition: uhso.c:398
static usb_callback_t uhso_mux_read_callback
Definition: uhso.c:355
static void uhso_if_rxflush(void *)
Definition: uhso.c:1664
static char uhso_port_map_max
Definition: uhso.c:205
static int uhso_if_ioctl(struct ifnet *, u_long, caddr_t)
Definition: uhso.c:1841
static usb_callback_t uhso_mux_write_callback
Definition: uhso.c:356
#define UHSO_PORT_TYPE_MODEM
Definition: uhso.c:165
static int uhso_radio_sysctl(SYSCTL_HANDLER_ARGS)
Definition: uhso.c:987
static void uhso_ucom_cfg_set_dtr(struct ucom_softc *, uint8_t)
Definition: uhso.c:1448
static int uhso_driver_loaded(struct module *, int, void *)
Definition: uhso.c:753
@ UHSO_CTRL_READ
Definition: uhso.c:336
@ UHSO_CTRL_WRITE
Definition: uhso.c:337
@ UHSO_CTRL_MAX
Definition: uhso.c:338
static usb_callback_t uhso_mux_intr_callback
Definition: uhso.c:354
static int uhso_attach_ifnet(struct uhso_softc *, struct usb_interface *, int type)
Definition: uhso.c:1554
static int uhso_autoswitch
Definition: uhso.c:293
static eventhandler_tag uhso_etag
Definition: uhso.c:176
static int uhso_attach_muxserial(struct uhso_softc *, struct usb_interface *, int type)
Definition: uhso.c:1038
static void uhso_if_start(struct ifnet *)
Definition: uhso.c:1913
static const struct usb_config uhso_mux_config[UHSO_MUX_ENDPT_MAX]
Definition: uhso.c:386
#define UHSO_PORT_TYPE_APP2
Definition: uhso.c:164
static void uhso_bs_cfg(struct uhso_softc *sc)
Definition: uhso.c:1361
#define UHSO_PORT_TYPE_VOICE
Definition: uhso.c:173
#define UHSO_PORT_TYPE_MSD
Definition: uhso.c:172
static int uhso_radio_ctrl(struct uhso_softc *, int)
Definition: uhso.c:966
#define UHSO_HEXDUMP(_buf, _len)
Definition: uhso.c:327
static usb_callback_t uhso_bs_read_callback
Definition: uhso.c:357
static device_detach_t uhso_detach
Definition: uhso.c:482
#define UHSO_IFACE_SPEC(usb_type, port, port_type)
Definition: uhso.c:124
#define UHSO_PORT_TYPE_UNKNOWN
Definition: uhso.c:161
static void uhso_free(struct ucom_softc *)
Definition: uhso.c:722
static struct ucom_callback uhso_ucom_callback
Definition: uhso.c:505
DRIVER_MODULE(uhso, uhub, uhso_driver, uhso_devclass, uhso_driver_loaded, 0)
#define UHSO_PORT_TYPE_NETWORK
Definition: uhso.c:166
static void uhso_ucom_stop_read(struct ucom_softc *)
Definition: uhso.c:1500
#define UHSO_AUTO_IFACE
Definition: uhso.c:248
static const struct usb_config uhso_ctrl_config[UHSO_CTRL_MAX]
Definition: uhso.c:364
static usb_callback_t uhso_bs_intr_callback
Definition: uhso.c:359
static int uhso_alloc_tty(struct uhso_softc *sc)
Definition: uhso.c:1012
USB_PNP_HOST_INFO(uhso_devs)
#define UHSO_MPORT_TYPE_NOMAX
Definition: uhso.c:154
__FBSDID("$FreeBSD$")
static usb_callback_t uhso_bs_write_callback
Definition: uhso.c:358
static driver_t uhso_driver
Definition: uhso.c:492
static int uhso_if_output(struct ifnet *, struct mbuf *, const struct sockaddr *, struct route *)
Definition: uhso.c:1889
static void uhso_test_autoinst(void *, struct usb_device *, struct usb_attach_arg *)
Definition: uhso.c:728
#define UHSO_PORT_TYPE_DIAG
Definition: uhso.c:167
static usb_callback_t uhso_ifnet_read_callback
Definition: uhso.c:360
static const STRUCT_USB_HOST_ID uhso_devs[]
Definition: uhso.c:253
static const struct usb_config uhso_bs_config[UHSO_BULK_ENDPT_MAX]
Definition: uhso.c:419
#define UHSO_PORT_TYPE_GPSCTL
Definition: uhso.c:170
#define UHSO_STATIC_IFACE
Definition: uhso.c:247
#define UHSO_PORT_NETWORK
Definition: uhso.c:143
static void uhso_if_stop(struct uhso_softc *)
Definition: uhso.c:1930
static void uhso_ucom_start_write(struct ucom_softc *)
Definition: uhso.c:1519
MODULE_VERSION(uhso, 1)
static void uhso_ucom_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *)
Definition: uhso.c:1439
#define UHSO_DPRINTF(n, x,...)
Definition: uhso.c:313
#define UHSO_DEV(v, p, i)
#define UHSO_PORT_TYPE_PCSC
Definition: uhso.c:171
static struct unrhdr * uhso_ifnet_unit
Definition: uhso.c:251
#define UHSO_PORT_TYPE_CTL
Definition: uhso.c:162
static char * uhso_port[]
Definition: uhso.c:179
SYSCTL_INT(_hw_usb_uhso, OID_AUTO, auto_switch, CTLFLAG_RWTUN, &uhso_autoswitch, 0, "Automatically switch to modem mode")
@ UHSO_IFNET_READ
Definition: uhso.c:342
@ UHSO_IFNET_WRITE
Definition: uhso.c:343
@ UHSO_IFNET_MAX
Definition: uhso.c:344
#define UHSO_MAX_MTU
Definition: uhso.c:114
static device_method_t uhso_methods[]
Definition: uhso.c:485
MODULE_DEPEND(uhso, ucom, 1, 1, 1)
#define UHSO_PORT_TYPE_GPS
Definition: uhso.c:169
static void uhso_ucom_cfg_set_rts(struct ucom_softc *, uint8_t)
Definition: uhso.c:1464
#define UHSO_PORT_SERIAL
Definition: uhso.c:142
#define UHSO_IF_NET
Definition: uhso.c:134
#define UHSO_IFACE_USB_TYPE(x)
Definition: uhso.c:127
static int uhso_probe_iface_static(struct usb_device *, int)
Definition: uhso.c:847
static device_probe_t uhso_probe
Definition: uhso.c:480
UCOM_UNLOAD_DRAIN(uhso)
static void uhso_ucom_stop_write(struct ucom_softc *)
Definition: uhso.c:1540
static device_attach_t uhso_attach
Definition: uhso.c:481
static int uhso_attach_bulkserial(struct uhso_softc *, struct usb_interface *, int type)
Definition: uhso.c:1268
#define UHSO_IF_BULK
Definition: uhso.c:136
static void uhso_free_softc(struct uhso_softc *)
Definition: uhso.c:711
#define UHSO_IFACE_PORT_TYPE(x)
Definition: uhso.c:129
static unsigned char uhso_mux_port_map[]
Definition: uhso.c:207
static devclass_t uhso_devclass
Definition: uhso.c:498
#define UHSO_PORT_TYPE_DIAG2
Definition: uhso.c:168
static usb_callback_t uhso_ifnet_write_callback
Definition: uhso.c:361
#define UHSO_IFACE_PORT(x)
Definition: uhso.c:128
static void uhso_ucom_start_read(struct ucom_softc *)
Definition: uhso.c:1480
@ UHSO_MUX_ENDPT_MAX
Definition: uhso.c:332
@ UHSO_MUX_ENDPT_INTR
Definition: uhso.c:331
#define UHSO_PORT_TYPE_APP
Definition: uhso.c:163
static int uhso_probe_iface(struct uhso_softc *, int, int(*probe)(struct usb_device *, int))
Definition: uhso.c:892
#define UE_INTERRUPT
Definition: usb.h:544
#define UE_DIR_ANY
Definition: usb.h:535
#define UE_ADDR_ANY
Definition: usb.h:537
#define UE_BULK
Definition: usb.h:543
#define UT_READ_CLASS_INTERFACE
Definition: usb.h:173
#define UT_VENDOR
Definition: usb.h:160
#define UT_READ_VENDOR_DEVICE
Definition: usb.h:180
#define UE_DIR_IN
Definition: usb.h:531
#define UE_DIR_OUT
Definition: usb.h:532
@ USB_MODE_HOST
Definition: usb.h:778
#define UT_WRITE_CLASS_INTERFACE
Definition: usb.h:177
#define UE_CONTROL
Definition: usb.h:541
#define UICLASS_MASS
Definition: usb.h:467
#define UDESC_CS_INTERFACE
Definition: usb.h:212
void usbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset, struct usb_page_search *res)
Definition: usb_busdma.c:86
void usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset, const void *ptr, usb_frlength_t len)
Definition: usb_busdma.c:166
void usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset, void *ptr, usb_frlength_t len)
Definition: usb_busdma.c:283
#define UCDC_LINE_RTS
Definition: usb_cdc.h:115
#define UCDC_SEND_ENCAPSULATED_COMMAND
Definition: usb_cdc.h:104
#define UCDC_LINE_DTR
Definition: usb_cdc.h:114
#define UCDC_NOTIFICATION_LENGTH
Definition: usb_cdc.h:163
#define UCDC_N_SERIAL_STATE
Definition: usb_cdc.h:153
#define UCDC_N_SERIAL_DCD
Definition: usb_cdc.h:175
#define UCDC_SET_CONTROL_LINE_STATE
Definition: usb_cdc.h:113
#define UCDC_N_SERIAL_DSR
Definition: usb_cdc.h:174
#define UCDC_N_SERIAL_RI
Definition: usb_cdc.h:172
#define UCDC_GET_ENCAPSULATED_RESPONSE
Definition: usb_cdc.h:105
#define UCDC_NOTIFICATION
Definition: usb_cdc.h:147
struct usb_interface_descriptor * usbd_get_interface_descriptor(struct usb_interface *iface)
Definition: usb_device.c:2654
struct usb_config_descriptor * usbd_get_config_descriptor(struct usb_device *udev)
Definition: usb_device.c:2616
void * usbd_find_descriptor(struct usb_device *udev, void *id, uint8_t iface_index, uint8_t type, uint8_t type_mask, uint8_t subtype, uint8_t subtype_mask)
Definition: usb_device.c:2395
const char * usb_get_product(struct usb_device *udev)
Definition: usb_device.c:287
struct usb_interface * usbd_get_iface(struct usb_device *udev, uint8_t iface_index)
Definition: usb_device.c:2370
const char * usb_get_manufacturer(struct usb_device *udev)
Definition: usb_device.c:281
struct usb_endpoint_descriptor desc
Definition: usb_device.h:0
#define USETW(w, v)
Definition: usb_endian.h:77
#define UGETW(w)
Definition: usb_endian.h:53
const char * usbd_errstr(usb_error_t err)
Definition: usb_error.c:93
const void * req
Definition: usb_if.m:51
INTERFACE usb
Definition: usb_if.m:35
int usbd_lookup_id_by_uaa(const struct usb_device_id *id, usb_size_t sizeof_id, struct usb_attach_arg *uaa)
Definition: usb_lookup.c:143
usb_error_t usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
Definition: usb_msctest.c:964
@ MSC_EJECT_REZERO
Definition: usb_msctest.h:34
usb_error_t usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, struct usb_device_request *req, void *data, uint16_t flags, uint16_t *actlen, usb_timeout_t timeout)
Definition: usb_request.c:405
uint8_t ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len, uint32_t *actlen)
Definition: usb_serial.c:1384
void ucom_status_change(struct ucom_softc *sc)
Definition: usb_serial.c:1229
int ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc, int subunits, void *parent, const struct ucom_callback *callback, struct mtx *mtx)
Definition: usb_serial.c:267
int ucom_unref(struct ucom_super_softc *ssc)
Definition: usb_serial.c:1730
void ucom_ref(struct ucom_super_softc *ssc)
Definition: usb_serial.c:1695
void ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev)
Definition: usb_serial.c:549
void ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
Definition: usb_serial.c:336
void ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len)
Definition: usb_serial.c:1462
#define ucom_cfg_do_request(udev, com, req, ptr, flags, timo)
Definition: usb_serial.h:208
void usbd_transfer_submit(struct usb_xfer *xfer)
void usbd_xfer_set_frames(struct usb_xfer *xfer, usb_frcount_t n)
void * usbd_xfer_get_priv(struct usb_xfer *xfer)
void usbd_transfer_unsetup(struct usb_xfer **pxfer, uint16_t n_setup)
void usbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex, usb_frlength_t len)
usb_frlength_t usbd_xfer_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex)
struct usb_page_cache * usbd_xfer_get_frame(struct usb_xfer *xfer, usb_frcount_t frindex)
usb_error_t usbd_transfer_setup(struct usb_device *udev, const uint8_t *ifaces, struct usb_xfer **ppxfer, const struct usb_config *setup_start, uint16_t n_setup, void *priv_sc, struct mtx *xfer_mtx)
Definition: usb_transfer.c:987
void usbd_transfer_start(struct usb_xfer *xfer)
void usbd_xfer_set_priv(struct usb_xfer *xfer, void *ptr)
void * usbd_xfer_softc(struct usb_xfer *xfer)
void usbd_xfer_set_stall(struct usb_xfer *xfer)
void usbd_transfer_stop(struct usb_xfer *xfer)
void usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, int *aframes, int *nframes)
usb_frlength_t usbd_xfer_max_len(struct usb_xfer *xfer)
#define USB_MS_HZ
Definition: usbdi.h:118
#define USB_ST_SETUP
Definition: usbdi.h:502
usb_error_t
Definition: usbdi.h:45
@ USB_ERR_CANCELLED
Definition: usbdi.h:51
#define UAA_DEV_READY
Definition: usbdi.h:435
#define USB_ST_TRANSFERRED
Definition: usbdi.h:503
void usbd_m_copy_in(struct usb_page_cache *cache, usb_frlength_t dst_offset, struct mbuf *m, usb_size_t src_offset, usb_frlength_t src_len)
void() usb_callback_t(struct usb_xfer *, usb_error_t)
Definition: usbdi.h:94
#define STRUCT_USB_HOST_ID
Definition: usbdi.h:258
#define USB_GET_DRIVER_INFO(did)
Definition: usbdi.h:400
#define USB_GET_STATE(xfer)
Definition: usbdi.h:515
#define usbd_do_request(u, m, r, d)
Definition: usbdi.h:596
#define UAA_DEV_EJECTING
Definition: usbdi.h:437