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