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