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