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