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