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