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