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