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