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