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