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