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