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