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