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