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