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