u3g.c revision 1.25.2.3 1 1.25.2.2 tls /* $NetBSD: u3g.c,v 1.25.2.3 2014/08/20 00:03:51 tls Exp $ */
2 1.9 martin
3 1.9 martin /*-
4 1.9 martin * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 1.9 martin * All rights reserved.
6 1.9 martin *
7 1.9 martin * This code is derived from software contributed to The NetBSD Foundation.
8 1.9 martin *
9 1.9 martin * Redistribution and use in source and binary forms, with or without
10 1.9 martin * modification, are permitted provided that the following conditions
11 1.9 martin * are met:
12 1.9 martin * 1. Redistributions of source code must retain the above copyright
13 1.9 martin * notice, this list of conditions and the following disclaimer.
14 1.9 martin * 2. Redistributions in binary form must reproduce the above copyright
15 1.9 martin * notice, this list of conditions and the following disclaimer in the
16 1.9 martin * documentation and/or other materials provided with the distribution.
17 1.9 martin *
18 1.9 martin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 1.9 martin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 1.9 martin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 1.9 martin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 1.9 martin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 1.9 martin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 1.9 martin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 1.9 martin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 1.9 martin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 1.9 martin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 1.9 martin * POSSIBILITY OF SUCH DAMAGE.
29 1.9 martin */
30 1.7 plunky
31 1.1 joerg /*
32 1.1 joerg * Copyright (c) 2008 AnyWi Technologies
33 1.1 joerg * Author: Andrea Guzzo <aguzzo (at) anywi.com>
34 1.1 joerg * * based on uark.c 1.1 2006/08/14 08:30:22 jsg *
35 1.1 joerg * * parts from ubsa.c 183348 2008-09-25 12:00:56Z phk *
36 1.1 joerg *
37 1.1 joerg * Permission to use, copy, modify, and distribute this software for any
38 1.1 joerg * purpose with or without fee is hereby granted, provided that the above
39 1.1 joerg * copyright notice and this permission notice appear in all copies.
40 1.1 joerg *
41 1.1 joerg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
42 1.1 joerg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
43 1.1 joerg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
44 1.1 joerg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
45 1.1 joerg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
46 1.1 joerg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
47 1.1 joerg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
48 1.1 joerg *
49 1.1 joerg * $FreeBSD$
50 1.1 joerg */
51 1.1 joerg
52 1.7 plunky #include <sys/cdefs.h>
53 1.25.2.2 tls __KERNEL_RCSID(0, "$NetBSD: u3g.c,v 1.25.2.3 2014/08/20 00:03:51 tls Exp $");
54 1.7 plunky
55 1.1 joerg #include <sys/param.h>
56 1.1 joerg #include <sys/systm.h>
57 1.1 joerg #include <sys/kernel.h>
58 1.1 joerg #include <sys/malloc.h>
59 1.1 joerg #include <sys/bus.h>
60 1.1 joerg #include <sys/conf.h>
61 1.1 joerg #include <sys/tty.h>
62 1.1 joerg
63 1.1 joerg #include <dev/usb/usb.h>
64 1.1 joerg #include <dev/usb/usbdi.h>
65 1.1 joerg #include <dev/usb/usbdivar.h>
66 1.1 joerg #include <dev/usb/usbdi_util.h>
67 1.1 joerg
68 1.1 joerg #include <dev/usb/ucomvar.h>
69 1.1 joerg
70 1.1 joerg #include "usbdevs.h"
71 1.1 joerg
72 1.9 martin /*
73 1.9 martin * We read/write data from/to the device in 4KB chunks to maximise
74 1.9 martin * performance.
75 1.9 martin */
76 1.9 martin #define U3G_BUFF_SIZE 4096
77 1.9 martin
78 1.9 martin /*
79 1.9 martin * Some 3G devices (the Huawei E160/E220 springs to mind here) buffer up
80 1.9 martin * data internally even when the USB pipes are closed. So on first open,
81 1.9 martin * we can receive a large chunk of stale data.
82 1.9 martin *
83 1.9 martin * This causes a real problem because the default TTYDEF_LFLAG (applied
84 1.9 martin * on first open) has the ECHO flag set, resulting in all the stale data
85 1.9 martin * being echoed straight back to the device by the tty(4) layer. Some
86 1.9 martin * devices (again, the Huawei E160/E220 for example) react to this spew
87 1.9 martin * by going catatonic.
88 1.9 martin *
89 1.9 martin * All this happens before the application gets a chance to disable ECHO.
90 1.9 martin *
91 1.9 martin * We work around this by ignoring all data received from the device for
92 1.9 martin * a period of two seconds, or until the application starts sending data -
93 1.9 martin * whichever comes first.
94 1.9 martin */
95 1.9 martin #define U3G_PURGE_SECS 2
96 1.9 martin
97 1.9 martin /*
98 1.9 martin * Define bits for the virtual modem control pins.
99 1.9 martin * The input pin states are reported via the interrupt pipe on some devices.
100 1.9 martin */
101 1.9 martin #define U3G_OUTPIN_DTR (1u << 0)
102 1.9 martin #define U3G_OUTPIN_RTS (1u << 1)
103 1.9 martin #define U3G_INPIN_DCD (1u << 0)
104 1.9 martin #define U3G_INPIN_DSR (1u << 1)
105 1.9 martin #define U3G_INPIN_RI (1u << 3)
106 1.9 martin
107 1.9 martin /*
108 1.9 martin * USB request to set the output pin status
109 1.9 martin */
110 1.9 martin #define U3G_SET_PIN 0x22
111 1.1 joerg
112 1.1 joerg struct u3g_softc {
113 1.9 martin device_t sc_dev;
114 1.9 martin usbd_device_handle sc_udev;
115 1.9 martin bool sc_dying; /* We're going away */
116 1.9 martin int sc_ifaceno; /* Device interface number */
117 1.9 martin
118 1.25.2.1 tls struct u3g_com {
119 1.25.2.1 tls device_t c_dev; /* Child ucom(4) handle */
120 1.9 martin
121 1.25.2.1 tls bool c_open; /* Device is in use */
122 1.25.2.1 tls bool c_purging; /* Purging stale data */
123 1.25.2.1 tls struct timeval c_purge_start; /* Control duration of purge */
124 1.25.2.1 tls
125 1.25.2.1 tls u_char c_msr; /* Emulated 'msr' */
126 1.25.2.1 tls uint16_t c_outpins; /* Output pin state */
127 1.25.2.1 tls } sc_com[10];
128 1.25.2.1 tls size_t sc_ncom;
129 1.9 martin
130 1.9 martin usbd_pipe_handle sc_intr_pipe; /* Interrupt pipe */
131 1.9 martin u_char *sc_intr_buff; /* Interrupt buffer */
132 1.1 joerg };
133 1.1 joerg
134 1.9 martin /*
135 1.9 martin * The device driver has two personalities. The first uses the 'usbdevif'
136 1.9 martin * interface attribute so that a match will claim the entire USB device
137 1.9 martin * for itself. This is used for when a device needs to be mode-switched
138 1.9 martin * and ensures any other interfaces present cannot be claimed by other
139 1.9 martin * drivers while the mode-switch is in progress.
140 1.9 martin *
141 1.9 martin * The second personality uses the 'usbifif' interface attribute so that
142 1.9 martin * it can claim the 3G modem interfaces for itself, leaving others (such
143 1.9 martin * as the mass storage interfaces on some devices) for other drivers.
144 1.9 martin */
145 1.9 martin static int u3ginit_match(device_t, cfdata_t, void *);
146 1.9 martin static void u3ginit_attach(device_t, device_t, void *);
147 1.9 martin static int u3ginit_detach(device_t, int);
148 1.9 martin
149 1.9 martin CFATTACH_DECL2_NEW(u3ginit, 0, u3ginit_match,
150 1.9 martin u3ginit_attach, u3ginit_detach, NULL, NULL, NULL);
151 1.9 martin
152 1.9 martin
153 1.9 martin static int u3g_match(device_t, cfdata_t, void *);
154 1.9 martin static void u3g_attach(device_t, device_t, void *);
155 1.9 martin static int u3g_detach(device_t, int);
156 1.9 martin static int u3g_activate(device_t, enum devact);
157 1.9 martin static void u3g_childdet(device_t, device_t);
158 1.9 martin
159 1.9 martin CFATTACH_DECL2_NEW(u3g, sizeof(struct u3g_softc), u3g_match,
160 1.9 martin u3g_attach, u3g_detach, u3g_activate, NULL, u3g_childdet);
161 1.9 martin
162 1.9 martin
163 1.9 martin static void u3g_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
164 1.9 martin static void u3g_get_status(void *, int, u_char *, u_char *);
165 1.9 martin static void u3g_set(void *, int, int, int);
166 1.9 martin static int u3g_open(void *, int);
167 1.9 martin static void u3g_close(void *, int);
168 1.9 martin static void u3g_read(void *, int, u_char **, uint32_t *);
169 1.9 martin static void u3g_write(void *, int, u_char *, u_char *, u_int32_t *);
170 1.9 martin
171 1.1 joerg struct ucom_methods u3g_methods = {
172 1.9 martin u3g_get_status,
173 1.9 martin u3g_set,
174 1.1 joerg NULL,
175 1.1 joerg NULL,
176 1.9 martin u3g_open,
177 1.9 martin u3g_close,
178 1.9 martin u3g_read,
179 1.9 martin u3g_write,
180 1.1 joerg };
181 1.1 joerg
182 1.9 martin /*
183 1.9 martin * Allegedly supported devices
184 1.9 martin */
185 1.1 joerg static const struct usb_devno u3g_devs[] = {
186 1.13 riz { USB_VENDOR_DELL, USB_PRODUCT_DELL_W5500 },
187 1.1 joerg /* OEM: Huawei */
188 1.19 veego { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E1750 },
189 1.18 apb { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E1820 },
190 1.1 joerg { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
191 1.25.2.1 tls { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_EM770W },
192 1.11 pooka { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_K3765 },
193 1.13 riz { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },
194 1.25.2.2 tls { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E171 },
195 1.13 riz /* OEM: Merlin */
196 1.13 riz { USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 },
197 1.1 joerg /* OEM: Novatel */
198 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_ES620 },
199 1.22 nonaka { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_EU8X0D },
200 1.1 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D },
201 1.13 riz #if 0
202 1.14 riz /* These are matched in u3ginit_match() */
203 1.13 riz { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D_DRIVER },
204 1.14 riz { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U760_DRIVER },
205 1.13 riz #endif
206 1.13 riz { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINU740 },
207 1.13 riz { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 },
208 1.13 riz { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_S720 },
209 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U720 },
210 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U727 },
211 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U740_2 },
212 1.14 riz { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U760 },
213 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U870 },
214 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_V740 },
215 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_X950D },
216 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_XU870 },
217 1.13 riz /* OEM: Option N.V. */
218 1.13 riz { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_QUADPLUSUMTS },
219 1.13 riz { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_HSDPA },
220 1.13 riz { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GTMAXHSUPA },
221 1.13 riz /* OEM: Qualcomm, Inc. */
222 1.25 nonaka { USB_VENDOR_QUALCOMM, USB_PRODUCT_QUALCOMM_NTT_DOCOMO_L02C_MODEM },
223 1.1 joerg
224 1.3 joerg /* OEM: Sierra Wireless: */
225 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U },
226 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E },
227 1.13 riz { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U },
228 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 },
229 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E },
230 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U },
231 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 },
232 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E },
233 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U },
234 1.13 riz { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 },
235 1.13 riz { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 },
236 1.13 riz { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 },
237 1.13 riz { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 },
238 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 },
239 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 },
240 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 },
241 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 },
242 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 },
243 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 },
244 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 },
245 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 },
246 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 },
247 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 },
248 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 },
249 1.13 riz { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725 },
250 1.12 riz { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_USB305 },
251 1.25.2.1 tls { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_250U },
252 1.17 scw /* Toshiba */
253 1.17 scw { USB_VENDOR_TOSHIBA, USB_PRODUCT_TOSHIBA_HSDPA_MODEM_EU870DT1 },
254 1.20 christos
255 1.25.2.3 tls /* ZTE */
256 1.25.2.3 tls { USB_VENDOR_ZTE, USB_PRODUCT_ZTE_MF622 },
257 1.25.2.3 tls { USB_VENDOR_ZTE, USB_PRODUCT_ZTE_MF626 },
258 1.25.2.3 tls { USB_VENDOR_ZTE, USB_PRODUCT_ZTE_MF628 },
259 1.25.2.3 tls { USB_VENDOR_ZTE, USB_PRODUCT_ZTE_MF820D },
260 1.25.2.3 tls
261 1.20 christos /* 4G Systems */
262 1.20 christos { USB_VENDOR_4GSYSTEMS, USB_PRODUCT_4GSYSTEMS_XSSTICK_P14 },
263 1.25.2.3 tls { USB_VENDOR_4GSYSTEMS, USB_PRODUCT_4GSYSTEMS_XSSTICK_W14 },
264 1.1 joerg };
265 1.1 joerg
266 1.1 joerg static int
267 1.20 christos send_bulkmsg(usbd_device_handle dev, void *cmd, size_t cmdlen)
268 1.2 joerg {
269 1.2 joerg usbd_interface_handle iface;
270 1.2 joerg usb_interface_descriptor_t *id;
271 1.2 joerg usb_endpoint_descriptor_t *ed;
272 1.2 joerg usbd_pipe_handle pipe;
273 1.2 joerg usbd_xfer_handle xfer;
274 1.2 joerg int err, i;
275 1.2 joerg
276 1.2 joerg /* Move the device into the configured state. */
277 1.9 martin err = usbd_set_config_index(dev, 0, 0);
278 1.2 joerg if (err) {
279 1.25.2.3 tls aprint_error("u3ginit: failed to set config index\n");
280 1.2 joerg return UMATCH_NONE;
281 1.2 joerg }
282 1.2 joerg
283 1.9 martin err = usbd_device2interface_handle(dev, 0, &iface);
284 1.2 joerg if (err != 0) {
285 1.11 pooka aprint_error("u3ginit: failed to get interface\n");
286 1.2 joerg return UMATCH_NONE;
287 1.2 joerg }
288 1.2 joerg
289 1.2 joerg id = usbd_get_interface_descriptor(iface);
290 1.2 joerg ed = NULL;
291 1.2 joerg for (i = 0 ; i < id->bNumEndpoints ; i++) {
292 1.2 joerg ed = usbd_interface2endpoint_descriptor(iface, i);
293 1.2 joerg if (ed == NULL)
294 1.2 joerg continue;
295 1.2 joerg if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT)
296 1.2 joerg continue;
297 1.2 joerg if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK)
298 1.2 joerg break;
299 1.2 joerg }
300 1.2 joerg
301 1.2 joerg if (i == id->bNumEndpoints)
302 1.2 joerg return UMATCH_NONE;
303 1.2 joerg
304 1.11 pooka err = usbd_open_pipe(iface, ed->bEndpointAddress,
305 1.11 pooka USBD_EXCLUSIVE_USE, &pipe);
306 1.2 joerg if (err != 0) {
307 1.11 pooka aprint_error("u3ginit: failed to open bulk transfer pipe %d\n",
308 1.2 joerg ed->bEndpointAddress);
309 1.2 joerg return UMATCH_NONE;
310 1.2 joerg }
311 1.2 joerg
312 1.9 martin xfer = usbd_alloc_xfer(dev);
313 1.2 joerg if (xfer != NULL) {
314 1.11 pooka usbd_setup_xfer(xfer, pipe, NULL, cmd, cmdlen,
315 1.2 joerg USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL);
316 1.2 joerg
317 1.2 joerg err = usbd_transfer(xfer);
318 1.11 pooka
319 1.11 pooka #if 0 /* XXXpooka: at least my huawei "fails" this always, but still detaches */
320 1.2 joerg if (err)
321 1.11 pooka aprint_error("u3ginit: transfer failed\n");
322 1.11 pooka #else
323 1.11 pooka err = 0;
324 1.11 pooka #endif
325 1.2 joerg usbd_free_xfer(xfer);
326 1.2 joerg } else {
327 1.11 pooka aprint_error("u3ginit: failed to allocate xfer\n");
328 1.2 joerg err = USBD_NOMEM;
329 1.2 joerg }
330 1.2 joerg
331 1.2 joerg usbd_abort_pipe(pipe);
332 1.2 joerg usbd_close_pipe(pipe);
333 1.2 joerg
334 1.2 joerg return (err == USBD_NORMAL_COMPLETION ? UMATCH_HIGHEST : UMATCH_NONE);
335 1.2 joerg }
336 1.2 joerg
337 1.2 joerg static int
338 1.25.2.3 tls u3g_bulk_scsi_eject(usbd_device_handle dev)
339 1.11 pooka {
340 1.11 pooka unsigned char cmd[31];
341 1.11 pooka
342 1.11 pooka memset(cmd, 0, sizeof(cmd));
343 1.11 pooka /* Byte 0..3: Command Block Wrapper (CBW) signature */
344 1.24 jakllsch cmd[0] = 0x55;
345 1.11 pooka cmd[1] = 0x53;
346 1.11 pooka cmd[2] = 0x42;
347 1.11 pooka cmd[3] = 0x43;
348 1.11 pooka /* 4..7: CBW Tag, has to unique, but only a single transfer used. */
349 1.11 pooka cmd[4] = 0x01;
350 1.11 pooka /* 8..11: CBW Transfer Length, no data here */
351 1.11 pooka /* 12: CBW Flag: output, so 0 */
352 1.11 pooka /* 13: CBW Lun: 0 */
353 1.11 pooka /* 14: CBW Length */
354 1.11 pooka cmd[14] = 0x06;
355 1.25.2.3 tls
356 1.11 pooka /* Rest is the SCSI payload */
357 1.25.2.3 tls
358 1.11 pooka /* 0: SCSI START/STOP opcode */
359 1.11 pooka cmd[15] = 0x1b;
360 1.11 pooka /* 1..3 unused */
361 1.11 pooka /* 4 Load/Eject command */
362 1.11 pooka cmd[19] = 0x02;
363 1.11 pooka /* 5: unused */
364 1.11 pooka
365 1.11 pooka return send_bulkmsg(dev, cmd, sizeof(cmd));
366 1.11 pooka }
367 1.11 pooka
368 1.11 pooka static int
369 1.25.2.3 tls u3g_bulk_ata_eject(usbd_device_handle dev)
370 1.25.2.3 tls {
371 1.25.2.3 tls unsigned char cmd[31];
372 1.25.2.3 tls
373 1.25.2.3 tls memset(cmd, 0, sizeof(cmd));
374 1.25.2.3 tls /* Byte 0..3: Command Block Wrapper (CBW) signature */
375 1.25.2.3 tls cmd[0] = 0x55;
376 1.25.2.3 tls cmd[1] = 0x53;
377 1.25.2.3 tls cmd[2] = 0x42;
378 1.25.2.3 tls cmd[3] = 0x43;
379 1.25.2.3 tls /* 4..7: CBW Tag, has to unique, but only a single transfer used. */
380 1.25.2.3 tls cmd[4] = 0x01;
381 1.25.2.3 tls /* 8..11: CBW Transfer Length, no data here */
382 1.25.2.3 tls /* 12: CBW Flag: output, so 0 */
383 1.25.2.3 tls /* 13: CBW Lun: 0 */
384 1.25.2.3 tls /* 14: CBW Length */
385 1.25.2.3 tls cmd[14] = 0x06;
386 1.25.2.3 tls
387 1.25.2.3 tls /* Rest is the SCSI payload */
388 1.25.2.3 tls
389 1.25.2.3 tls /* 0: ATA pass-through */
390 1.25.2.3 tls cmd[15] = 0x85;
391 1.25.2.3 tls /* 1..3 unused */
392 1.25.2.3 tls /* 4 XXX What is this command? */
393 1.25.2.3 tls cmd[19] = 0x24;
394 1.25.2.3 tls /* 5: unused */
395 1.25.2.3 tls
396 1.25.2.3 tls return send_bulkmsg(dev, cmd, sizeof(cmd));
397 1.25.2.3 tls }
398 1.25.2.3 tls
399 1.25.2.3 tls static int
400 1.1 joerg u3g_huawei_reinit(usbd_device_handle dev)
401 1.1 joerg {
402 1.9 martin /*
403 1.9 martin * The Huawei device presents itself as a umass device with Windows
404 1.1 joerg * drivers on it. After installation of the driver, it reinits into a
405 1.1 joerg * 3G serial device.
406 1.1 joerg */
407 1.1 joerg usb_device_request_t req;
408 1.1 joerg usb_config_descriptor_t *cdesc;
409 1.1 joerg
410 1.1 joerg /* Get the config descriptor */
411 1.1 joerg cdesc = usbd_get_config_descriptor(dev);
412 1.9 martin if (cdesc == NULL) {
413 1.9 martin usb_device_descriptor_t dd;
414 1.9 martin
415 1.9 martin if (usbd_get_device_desc(dev, &dd) != 0)
416 1.9 martin return (UMATCH_NONE);
417 1.9 martin
418 1.9 martin if (dd.bNumConfigurations != 1)
419 1.9 martin return (UMATCH_NONE);
420 1.9 martin
421 1.9 martin if (usbd_set_config_index(dev, 0, 1) != 0)
422 1.9 martin return (UMATCH_NONE);
423 1.9 martin
424 1.9 martin cdesc = usbd_get_config_descriptor(dev);
425 1.9 martin
426 1.9 martin if (cdesc == NULL)
427 1.9 martin return (UMATCH_NONE);
428 1.9 martin }
429 1.1 joerg
430 1.9 martin /*
431 1.9 martin * One iface means umass mode, more than 1 (4 usually) means 3G mode.
432 1.9 martin *
433 1.9 martin * XXX: We should check the first interface's device class just to be
434 1.9 martin * sure. If it's a mass storage device, then we can be fairly certain
435 1.9 martin * it needs a mode-switch.
436 1.9 martin */
437 1.1 joerg if (cdesc->bNumInterface > 1)
438 1.9 martin return (UMATCH_NONE);
439 1.1 joerg
440 1.1 joerg req.bmRequestType = UT_WRITE_DEVICE;
441 1.1 joerg req.bRequest = UR_SET_FEATURE;
442 1.1 joerg USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
443 1.1 joerg USETW(req.wIndex, UHF_PORT_SUSPEND);
444 1.1 joerg USETW(req.wLength, 0);
445 1.1 joerg
446 1.1 joerg (void) usbd_do_request(dev, &req, 0);
447 1.1 joerg
448 1.11 pooka return (UMATCH_HIGHEST); /* Prevent umass from attaching */
449 1.11 pooka }
450 1.11 pooka
451 1.11 pooka static int
452 1.11 pooka u3g_huawei_k3765_reinit(usbd_device_handle dev)
453 1.11 pooka {
454 1.11 pooka unsigned char cmd[31];
455 1.11 pooka
456 1.11 pooka /* magic string adapted from some webpage */
457 1.11 pooka memset(cmd, 0, sizeof(cmd));
458 1.24 jakllsch cmd[0] = 0x55;
459 1.11 pooka cmd[1] = 0x53;
460 1.11 pooka cmd[2] = 0x42;
461 1.11 pooka cmd[3] = 0x43;
462 1.11 pooka cmd[15]= 0x11;
463 1.11 pooka cmd[16]= 0x06;
464 1.11 pooka
465 1.11 pooka return send_bulkmsg(dev, cmd, sizeof(cmd));
466 1.1 joerg }
467 1.1 joerg
468 1.1 joerg static int
469 1.25.2.2 tls u3g_huawei_e171_reinit(usbd_device_handle dev)
470 1.25.2.2 tls {
471 1.25.2.2 tls unsigned char cmd[31];
472 1.25.2.2 tls
473 1.25.2.2 tls /* magic string adapted from some webpage */
474 1.25.2.2 tls memset(cmd, 0, sizeof(cmd));
475 1.25.2.2 tls cmd[0] = 0x55;
476 1.25.2.2 tls cmd[1] = 0x53;
477 1.25.2.2 tls cmd[2] = 0x42;
478 1.25.2.2 tls cmd[3] = 0x43;
479 1.25.2.2 tls cmd[15]= 0x11;
480 1.25.2.2 tls cmd[16]= 0x06;
481 1.25.2.2 tls cmd[17]= 0x20;
482 1.25.2.2 tls cmd[20]= 0x01;
483 1.25.2.2 tls
484 1.25.2.2 tls return send_bulkmsg(dev, cmd, sizeof(cmd));
485 1.25.2.2 tls }
486 1.25.2.2 tls
487 1.25.2.2 tls static int
488 1.4 christos u3g_sierra_reinit(usbd_device_handle dev)
489 1.4 christos {
490 1.4 christos /* Some Sierra devices presents themselves as a umass device with
491 1.4 christos * Windows drivers on it. After installation of the driver, it
492 1.4 christos * reinits into a * 3G serial device.
493 1.4 christos */
494 1.4 christos usb_device_request_t req;
495 1.4 christos
496 1.4 christos req.bmRequestType = UT_VENDOR;
497 1.4 christos req.bRequest = UR_SET_INTERFACE;
498 1.4 christos USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
499 1.4 christos USETW(req.wIndex, UHF_PORT_CONNECTION);
500 1.4 christos USETW(req.wLength, 0);
501 1.4 christos
502 1.4 christos (void) usbd_do_request(dev, &req, 0);
503 1.4 christos
504 1.4 christos return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */
505 1.4 christos }
506 1.4 christos
507 1.20 christos static int
508 1.20 christos u3g_4gsystems_reinit(usbd_device_handle dev)
509 1.20 christos {
510 1.20 christos /* magic string adapted from usb_modeswitch database */
511 1.20 christos static unsigned char cmd[31] = {
512 1.20 christos 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 0x80, 0x00,
513 1.20 christos 0x00, 0x00, 0x80, 0x00, 0x06, 0x06, 0xf5, 0x04, 0x02, 0x52,
514 1.20 christos 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515 1.20 christos 0x00
516 1.20 christos };
517 1.20 christos
518 1.20 christos return send_bulkmsg(dev, cmd, sizeof(cmd));
519 1.20 christos }
520 1.20 christos
521 1.9 martin /*
522 1.9 martin * First personality:
523 1.9 martin *
524 1.9 martin * Claim the entire device if a mode-switch is required.
525 1.9 martin */
526 1.9 martin
527 1.4 christos static int
528 1.9 martin u3ginit_match(device_t parent, cfdata_t match, void *aux)
529 1.1 joerg {
530 1.1 joerg struct usb_attach_arg *uaa = aux;
531 1.1 joerg
532 1.11 pooka /*
533 1.11 pooka * Huawei changes product when it is configured as a modem.
534 1.11 pooka */
535 1.16 christos switch (uaa->vendor) {
536 1.16 christos case USB_VENDOR_HUAWEI:
537 1.11 pooka if (uaa->product == USB_PRODUCT_HUAWEI_K3765)
538 1.11 pooka return UMATCH_NONE;
539 1.11 pooka
540 1.15 kardel switch (uaa->product) {
541 1.15 kardel case USB_PRODUCT_HUAWEI_E1750INIT:
542 1.15 kardel case USB_PRODUCT_HUAWEI_K3765INIT:
543 1.11 pooka return u3g_huawei_k3765_reinit(uaa->device);
544 1.15 kardel break;
545 1.25.2.2 tls case USB_PRODUCT_HUAWEI_E171INIT:
546 1.25.2.2 tls return u3g_huawei_e171_reinit(uaa->device);
547 1.25.2.2 tls break;
548 1.15 kardel default:
549 1.11 pooka return u3g_huawei_reinit(uaa->device);
550 1.15 kardel break;
551 1.15 kardel }
552 1.16 christos break;
553 1.1 joerg
554 1.16 christos case USB_VENDOR_NOVATEL2:
555 1.14 riz switch (uaa->product){
556 1.14 riz case USB_PRODUCT_NOVATEL2_MC950D_DRIVER:
557 1.14 riz case USB_PRODUCT_NOVATEL2_U760_DRIVER:
558 1.25.2.3 tls return u3g_bulk_scsi_eject(uaa->device);
559 1.14 riz break;
560 1.14 riz default:
561 1.14 riz break;
562 1.14 riz }
563 1.16 christos break;
564 1.16 christos
565 1.16 christos case USB_VENDOR_SIERRA:
566 1.16 christos if (uaa->product == USB_PRODUCT_SIERRA_INSTALLER)
567 1.16 christos return u3g_sierra_reinit(uaa->device);
568 1.16 christos break;
569 1.16 christos
570 1.25 nonaka case USB_VENDOR_QUALCOMM:
571 1.25 nonaka if (uaa->product == USB_PRODUCT_QUALCOMM_NTT_DOCOMO_L02C_STORAGE)
572 1.25.2.3 tls return u3g_bulk_scsi_eject(uaa->device);
573 1.25.2.3 tls break;
574 1.25.2.3 tls
575 1.25.2.3 tls case USB_VENDOR_ZTE:
576 1.25.2.3 tls switch (uaa->product){
577 1.25.2.3 tls case USB_PRODUCT_ZTE_INSTALLER:
578 1.25.2.3 tls case USB_PRODUCT_ZTE_MF820D_INSTALLER:
579 1.25.2.3 tls (void)u3g_bulk_ata_eject(uaa->device);
580 1.25.2.3 tls (void)u3g_bulk_scsi_eject(uaa->device);
581 1.25.2.3 tls return UMATCH_HIGHEST;
582 1.25.2.3 tls default:
583 1.25.2.3 tls break;
584 1.25.2.3 tls }
585 1.25 nonaka break;
586 1.25 nonaka
587 1.20 christos case USB_VENDOR_4GSYSTEMS:
588 1.21 christos if (uaa->product == USB_PRODUCT_4GSYSTEMS_XSSTICK_P14_INSTALLER)
589 1.20 christos return u3g_4gsystems_reinit(uaa->device);
590 1.20 christos break;
591 1.20 christos
592 1.16 christos default:
593 1.16 christos break;
594 1.14 riz }
595 1.2 joerg
596 1.1 joerg return UMATCH_NONE;
597 1.1 joerg }
598 1.1 joerg
599 1.1 joerg static void
600 1.9 martin u3ginit_attach(device_t parent, device_t self, void *aux)
601 1.1 joerg {
602 1.1 joerg struct usb_attach_arg *uaa = aux;
603 1.1 joerg
604 1.1 joerg aprint_naive("\n");
605 1.9 martin aprint_normal(": Switching to 3G mode\n");
606 1.1 joerg
607 1.14 riz if (uaa->vendor == USB_VENDOR_NOVATEL2) {
608 1.14 riz switch (uaa->product) {
609 1.14 riz case USB_PRODUCT_NOVATEL2_MC950D_DRIVER:
610 1.14 riz case USB_PRODUCT_NOVATEL2_U760_DRIVER:
611 1.14 riz /* About to disappear... */
612 1.14 riz return;
613 1.14 riz break;
614 1.14 riz default:
615 1.14 riz break;
616 1.14 riz }
617 1.2 joerg }
618 1.2 joerg
619 1.1 joerg /* Move the device into the configured state. */
620 1.9 martin (void) usbd_set_config_index(uaa->device, 0, 1);
621 1.9 martin }
622 1.9 martin
623 1.9 martin static int
624 1.9 martin u3ginit_detach(device_t self, int flags)
625 1.9 martin {
626 1.9 martin
627 1.9 martin return (0);
628 1.9 martin }
629 1.9 martin
630 1.9 martin
631 1.9 martin /*
632 1.9 martin * Second personality:
633 1.9 martin *
634 1.9 martin * Claim only those interfaces required for 3G modem operation.
635 1.9 martin */
636 1.9 martin
637 1.9 martin static int
638 1.9 martin u3g_match(device_t parent, cfdata_t match, void *aux)
639 1.9 martin {
640 1.9 martin struct usbif_attach_arg *uaa = aux;
641 1.9 martin usbd_interface_handle iface;
642 1.9 martin usb_interface_descriptor_t *id;
643 1.9 martin usbd_status error;
644 1.9 martin
645 1.9 martin if (!usb_lookup(u3g_devs, uaa->vendor, uaa->product))
646 1.9 martin return (UMATCH_NONE);
647 1.9 martin
648 1.9 martin error = usbd_device2interface_handle(uaa->device, uaa->ifaceno, &iface);
649 1.1 joerg if (error) {
650 1.9 martin printf("u3g_match: failed to get interface, err=%s\n",
651 1.9 martin usbd_errstr(error));
652 1.9 martin return (UMATCH_NONE);
653 1.9 martin }
654 1.9 martin
655 1.9 martin id = usbd_get_interface_descriptor(iface);
656 1.9 martin if (id == NULL) {
657 1.9 martin printf("u3g_match: failed to get interface descriptor\n");
658 1.9 martin return (UMATCH_NONE);
659 1.1 joerg }
660 1.1 joerg
661 1.9 martin /*
662 1.25.2.3 tls * Huawei modems use the vendor-specific class for all interfaces,
663 1.25.2.3 tls * both tty and CDC NCM, which we should avoid attaching to.
664 1.25.2.3 tls */
665 1.25.2.3 tls if (uaa->vendor == USB_VENDOR_HUAWEI && id->bInterfaceSubClass == 2 &&
666 1.25.2.3 tls (id->bInterfaceProtocol & 0xf) == 6) /* 0x16, 0x46, 0x76 */
667 1.25.2.3 tls return (UMATCH_NONE);
668 1.25.2.3 tls
669 1.25.2.3 tls /*
670 1.9 martin * 3G modems generally report vendor-specific class
671 1.9 martin *
672 1.9 martin * XXX: this may be too generalised.
673 1.9 martin */
674 1.9 martin return ((id->bInterfaceClass == UICLASS_VENDOR) ?
675 1.9 martin UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
676 1.9 martin }
677 1.9 martin
678 1.9 martin static void
679 1.9 martin u3g_attach(device_t parent, device_t self, void *aux)
680 1.9 martin {
681 1.9 martin struct u3g_softc *sc = device_private(self);
682 1.9 martin struct usbif_attach_arg *uaa = aux;
683 1.9 martin usbd_device_handle dev = uaa->device;
684 1.9 martin usbd_interface_handle iface;
685 1.9 martin usb_interface_descriptor_t *id;
686 1.9 martin usb_endpoint_descriptor_t *ed;
687 1.9 martin struct ucom_attach_args uca;
688 1.9 martin usbd_status error;
689 1.24 jakllsch int n, intr_address, intr_size;
690 1.1 joerg
691 1.9 martin aprint_naive("\n");
692 1.9 martin aprint_normal("\n");
693 1.1 joerg
694 1.9 martin sc->sc_dev = self;
695 1.9 martin sc->sc_dying = false;
696 1.9 martin sc->sc_udev = dev;
697 1.2 joerg
698 1.9 martin error = usbd_device2interface_handle(dev, uaa->ifaceno, &iface);
699 1.9 martin if (error) {
700 1.9 martin aprint_error_dev(self, "failed to get interface, err=%s\n",
701 1.9 martin usbd_errstr(error));
702 1.4 christos return;
703 1.4 christos }
704 1.4 christos
705 1.9 martin id = usbd_get_interface_descriptor(iface);
706 1.1 joerg
707 1.9 martin uca.info = "3G Modem";
708 1.9 martin uca.ibufsize = U3G_BUFF_SIZE;
709 1.9 martin uca.obufsize = U3G_BUFF_SIZE;
710 1.9 martin uca.ibufsizepad = U3G_BUFF_SIZE;
711 1.9 martin uca.opkthdrlen = 0;
712 1.9 martin uca.device = dev;
713 1.9 martin uca.iface = iface;
714 1.9 martin uca.methods = &u3g_methods;
715 1.9 martin uca.arg = sc;
716 1.25.2.1 tls uca.portno = -1;
717 1.9 martin uca.bulkin = uca.bulkout = -1;
718 1.9 martin
719 1.9 martin
720 1.25.2.1 tls sc->sc_ifaceno = uaa->ifaceno;
721 1.9 martin intr_address = -1;
722 1.9 martin intr_size = 0;
723 1.9 martin
724 1.9 martin for (n = 0; n < id->bNumEndpoints; n++) {
725 1.9 martin ed = usbd_interface2endpoint_descriptor(iface, n);
726 1.9 martin if (ed == NULL) {
727 1.9 martin aprint_error_dev(self, "no endpoint descriptor "
728 1.9 martin "for %d (interface: %d)\n", n, sc->sc_ifaceno);
729 1.9 martin sc->sc_dying = true;
730 1.1 joerg return;
731 1.1 joerg }
732 1.1 joerg
733 1.9 martin if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
734 1.9 martin UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
735 1.9 martin intr_address = ed->bEndpointAddress;
736 1.9 martin intr_size = UGETW(ed->wMaxPacketSize);
737 1.9 martin } else
738 1.9 martin if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
739 1.9 martin UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
740 1.9 martin uca.bulkin = ed->bEndpointAddress;
741 1.9 martin } else
742 1.9 martin if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
743 1.9 martin UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
744 1.9 martin uca.bulkout = ed->bEndpointAddress;
745 1.1 joerg }
746 1.25.2.1 tls if (uca.bulkin != -1 && uca.bulkout != -1) {
747 1.25.2.1 tls struct u3g_com *com;
748 1.25.2.1 tls if (sc->sc_ncom == __arraycount(sc->sc_com)) {
749 1.25.2.1 tls aprint_error_dev(self, "Need to configure "
750 1.25.2.1 tls "more than %zu ttys", sc->sc_ncom);
751 1.25.2.1 tls continue;
752 1.25.2.1 tls }
753 1.25.2.1 tls uca.portno = sc->sc_ncom++;
754 1.25.2.1 tls com = &sc->sc_com[uca.portno];
755 1.25.2.1 tls com->c_outpins = 0;
756 1.25.2.1 tls com->c_msr = UMSR_DSR | UMSR_CTS | UMSR_DCD;
757 1.25.2.1 tls com->c_open = false;
758 1.25.2.1 tls com->c_purging = false;
759 1.25.2.1 tls com->c_dev = config_found_sm_loc(self, "ucombus",
760 1.25.2.1 tls NULL, &uca, ucomprint, ucomsubmatch);
761 1.25.2.1 tls uca.bulkin = -1;
762 1.25.2.1 tls uca.bulkout = -1;
763 1.25.2.1 tls }
764 1.9 martin }
765 1.9 martin
766 1.25.2.1 tls if (sc->sc_ncom == 0) {
767 1.25.2.1 tls aprint_error_dev(self, "Missing bulk in/out for interface %d\n",
768 1.9 martin sc->sc_ifaceno);
769 1.9 martin sc->sc_dying = true;
770 1.9 martin return;
771 1.1 joerg }
772 1.1 joerg
773 1.9 martin /*
774 1.9 martin * If the interface has an interrupt pipe, open it immediately so
775 1.9 martin * that we can track input pin state changes regardless of whether
776 1.9 martin * the tty(4) device is open or not.
777 1.9 martin */
778 1.9 martin if (intr_address != -1) {
779 1.9 martin sc->sc_intr_buff = malloc(intr_size, M_USBDEV, M_WAITOK);
780 1.9 martin error = usbd_open_pipe_intr(iface, intr_address,
781 1.9 martin USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_intr_buff,
782 1.9 martin intr_size, u3g_intr, 100);
783 1.1 joerg if (error) {
784 1.9 martin aprint_error_dev(self, "cannot open interrupt pipe "
785 1.9 martin "(addr %d)\n", intr_address);
786 1.1 joerg return;
787 1.1 joerg }
788 1.9 martin } else {
789 1.9 martin sc->sc_intr_pipe = NULL;
790 1.9 martin sc->sc_intr_buff = NULL;
791 1.1 joerg }
792 1.1 joerg
793 1.1 joerg if (!pmf_device_register(self, NULL, NULL))
794 1.1 joerg aprint_error_dev(self, "couldn't establish power handler\n");
795 1.1 joerg }
796 1.1 joerg
797 1.1 joerg static int
798 1.1 joerg u3g_detach(device_t self, int flags)
799 1.1 joerg {
800 1.1 joerg struct u3g_softc *sc = device_private(self);
801 1.9 martin int rv;
802 1.1 joerg
803 1.9 martin if (sc->sc_dying)
804 1.2 joerg return 0;
805 1.2 joerg
806 1.1 joerg pmf_device_deregister(self);
807 1.1 joerg
808 1.25.2.1 tls for (size_t i = 0; i < sc->sc_ncom; i++)
809 1.25.2.1 tls if (sc->sc_com[i].c_dev != NULL) {
810 1.25.2.1 tls rv = config_detach(sc->sc_com[i].c_dev, flags);
811 1.25.2.1 tls if (rv != 0) {
812 1.25.2.1 tls aprint_verbose_dev(self, "Can't deallocate "
813 1.25.2.1 tls "port (%d)", rv);
814 1.25.2.1 tls }
815 1.1 joerg }
816 1.1 joerg
817 1.1 joerg if (sc->sc_intr_pipe != NULL) {
818 1.9 martin (void) usbd_abort_pipe(sc->sc_intr_pipe);
819 1.9 martin (void) usbd_close_pipe(sc->sc_intr_pipe);
820 1.1 joerg sc->sc_intr_pipe = NULL;
821 1.1 joerg }
822 1.9 martin if (sc->sc_intr_buff != NULL) {
823 1.9 martin free(sc->sc_intr_buff, M_USBDEV);
824 1.9 martin sc->sc_intr_buff = NULL;
825 1.9 martin }
826 1.1 joerg
827 1.9 martin return (0);
828 1.1 joerg }
829 1.1 joerg
830 1.1 joerg static void
831 1.1 joerg u3g_childdet(device_t self, device_t child)
832 1.1 joerg {
833 1.1 joerg struct u3g_softc *sc = device_private(self);
834 1.9 martin
835 1.25.2.1 tls for (size_t i = 0; i < sc->sc_ncom; i++)
836 1.25.2.1 tls if (sc->sc_com[i].c_dev == child)
837 1.25.2.1 tls sc->sc_com[i].c_dev = NULL;
838 1.9 martin }
839 1.9 martin
840 1.9 martin static int
841 1.9 martin u3g_activate(device_t self, enum devact act)
842 1.9 martin {
843 1.9 martin struct u3g_softc *sc = device_private(self);
844 1.25.2.1 tls int rv = 0;
845 1.9 martin
846 1.9 martin switch (act) {
847 1.9 martin case DVACT_DEACTIVATE:
848 1.25.2.1 tls for (size_t i = 0; i < sc->sc_ncom; i++)
849 1.25.2.1 tls if (sc->sc_com[i].c_dev != NULL &&
850 1.25.2.1 tls config_deactivate(sc->sc_com[i].c_dev) && rv == 0)
851 1.9 martin rv = -1;
852 1.9 martin else
853 1.9 martin rv = 0;
854 1.9 martin break;
855 1.9 martin
856 1.9 martin default:
857 1.9 martin break;
858 1.9 martin }
859 1.9 martin
860 1.25.2.1 tls return rv;
861 1.9 martin }
862 1.9 martin
863 1.9 martin static void
864 1.9 martin u3g_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
865 1.9 martin {
866 1.9 martin struct u3g_softc *sc = (struct u3g_softc *)priv;
867 1.9 martin u_char *buf;
868 1.25.2.1 tls int portno = 0; /* XXX */
869 1.25.2.1 tls struct u3g_com *com = &sc->sc_com[portno];
870 1.9 martin
871 1.9 martin if (sc->sc_dying)
872 1.9 martin return;
873 1.9 martin
874 1.9 martin if (status != USBD_NORMAL_COMPLETION) {
875 1.9 martin if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
876 1.9 martin return;
877 1.9 martin usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
878 1.9 martin return;
879 1.9 martin }
880 1.9 martin
881 1.9 martin buf = sc->sc_intr_buff;
882 1.9 martin if (buf[0] == 0xa1 && buf[1] == 0x20) {
883 1.9 martin u_char msr;
884 1.9 martin
885 1.25.2.1 tls msr = com->c_msr & ~(UMSR_DCD | UMSR_DSR | UMSR_RI);
886 1.9 martin
887 1.9 martin if (buf[8] & U3G_INPIN_DCD)
888 1.9 martin msr |= UMSR_DCD;
889 1.9 martin
890 1.9 martin if (buf[8] & U3G_INPIN_DSR)
891 1.9 martin msr |= UMSR_DSR;
892 1.9 martin
893 1.9 martin if (buf[8] & U3G_INPIN_RI)
894 1.9 martin msr |= UMSR_RI;
895 1.9 martin
896 1.25.2.1 tls if (msr != com->c_msr) {
897 1.25.2.1 tls com->c_msr = msr;
898 1.25.2.1 tls if (com->c_open)
899 1.25.2.1 tls ucom_status_change(device_private(com->c_dev));
900 1.9 martin }
901 1.9 martin }
902 1.9 martin }
903 1.9 martin
904 1.9 martin /*ARGSUSED*/
905 1.9 martin static void
906 1.9 martin u3g_get_status(void *arg, int portno, u_char *lsr, u_char *msr)
907 1.9 martin {
908 1.9 martin struct u3g_softc *sc = arg;
909 1.9 martin
910 1.9 martin if (lsr != NULL)
911 1.9 martin *lsr = 0; /* LSR isn't supported */
912 1.9 martin if (msr != NULL)
913 1.25.2.1 tls *msr = sc->sc_com[portno].c_msr;
914 1.9 martin }
915 1.9 martin
916 1.9 martin /*ARGSUSED*/
917 1.9 martin static void
918 1.9 martin u3g_set(void *arg, int portno, int reg, int onoff)
919 1.9 martin {
920 1.9 martin struct u3g_softc *sc = arg;
921 1.9 martin usb_device_request_t req;
922 1.9 martin uint16_t mask, new_state;
923 1.9 martin usbd_status err;
924 1.25.2.1 tls struct u3g_com *com = &sc->sc_com[portno];
925 1.9 martin
926 1.9 martin if (sc->sc_dying)
927 1.9 martin return;
928 1.9 martin
929 1.9 martin switch (reg) {
930 1.9 martin case UCOM_SET_DTR:
931 1.9 martin mask = U3G_OUTPIN_DTR;
932 1.9 martin break;
933 1.9 martin case UCOM_SET_RTS:
934 1.9 martin mask = U3G_OUTPIN_RTS;
935 1.9 martin break;
936 1.9 martin default:
937 1.9 martin return;
938 1.9 martin }
939 1.9 martin
940 1.25.2.1 tls new_state = com->c_outpins & ~mask;
941 1.9 martin if (onoff)
942 1.9 martin new_state |= mask;
943 1.9 martin
944 1.25.2.1 tls if (new_state == com->c_outpins)
945 1.9 martin return;
946 1.9 martin
947 1.25.2.1 tls com->c_outpins = new_state;
948 1.9 martin
949 1.9 martin req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
950 1.9 martin req.bRequest = U3G_SET_PIN;
951 1.9 martin USETW(req.wValue, new_state);
952 1.9 martin USETW(req.wIndex, sc->sc_ifaceno);
953 1.9 martin USETW(req.wLength, 0);
954 1.9 martin
955 1.9 martin err = usbd_do_request(sc->sc_udev, &req, 0);
956 1.9 martin if (err == USBD_STALLED)
957 1.9 martin usbd_clear_endpoint_stall(sc->sc_udev->default_pipe);
958 1.9 martin }
959 1.9 martin
960 1.9 martin /*ARGSUSED*/
961 1.24 jakllsch static int
962 1.9 martin u3g_open(void *arg, int portno)
963 1.9 martin {
964 1.9 martin struct u3g_softc *sc = arg;
965 1.9 martin usb_device_request_t req;
966 1.9 martin usb_endpoint_descriptor_t *ed;
967 1.9 martin usb_interface_descriptor_t *id;
968 1.9 martin usbd_interface_handle ih;
969 1.9 martin usbd_status err;
970 1.25.2.1 tls struct u3g_com *com = &sc->sc_com[portno];
971 1.25.2.1 tls int i, nin;
972 1.1 joerg
973 1.9 martin if (sc->sc_dying)
974 1.9 martin return (0);
975 1.9 martin
976 1.25.2.1 tls err = usbd_device2interface_handle(sc->sc_udev, sc->sc_ifaceno, &ih);
977 1.9 martin if (err)
978 1.9 martin return (EIO);
979 1.9 martin
980 1.9 martin id = usbd_get_interface_descriptor(ih);
981 1.9 martin
982 1.25.2.1 tls for (nin = i = 0; i < id->bNumEndpoints; i++) {
983 1.9 martin ed = usbd_interface2endpoint_descriptor(ih, i);
984 1.24 jakllsch if (ed == NULL)
985 1.9 martin return (EIO);
986 1.9 martin
987 1.25.2.1 tls if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
988 1.25.2.1 tls UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK &&
989 1.25.2.1 tls nin++ == portno) {
990 1.9 martin /* Issue ENDPOINT_HALT request */
991 1.9 martin req.bmRequestType = UT_WRITE_ENDPOINT;
992 1.9 martin req.bRequest = UR_CLEAR_FEATURE;
993 1.9 martin USETW(req.wValue, UF_ENDPOINT_HALT);
994 1.9 martin USETW(req.wIndex, ed->bEndpointAddress);
995 1.9 martin USETW(req.wLength, 0);
996 1.9 martin err = usbd_do_request(sc->sc_udev, &req, 0);
997 1.9 martin if (err)
998 1.9 martin return (EIO);
999 1.9 martin }
1000 1.1 joerg }
1001 1.9 martin
1002 1.25.2.1 tls com->c_open = true;
1003 1.25.2.1 tls com->c_purging = true;
1004 1.25.2.1 tls getmicrotime(&com->c_purge_start);
1005 1.9 martin
1006 1.9 martin return (0);
1007 1.1 joerg }
1008 1.1 joerg
1009 1.9 martin /*ARGSUSED*/
1010 1.24 jakllsch static void
1011 1.9 martin u3g_close(void *arg, int portno)
1012 1.9 martin {
1013 1.9 martin struct u3g_softc *sc = arg;
1014 1.25.2.1 tls struct u3g_com *com = &sc->sc_com[portno];
1015 1.9 martin
1016 1.25.2.1 tls com->c_open = false;
1017 1.9 martin }
1018 1.9 martin
1019 1.9 martin /*ARGSUSED*/
1020 1.9 martin static void
1021 1.9 martin u3g_read(void *arg, int portno, u_char **cpp, uint32_t *ccp)
1022 1.9 martin {
1023 1.9 martin struct u3g_softc *sc = arg;
1024 1.9 martin struct timeval curr_tv, diff_tv;
1025 1.25.2.1 tls struct u3g_com *com = &sc->sc_com[portno];
1026 1.9 martin
1027 1.9 martin /*
1028 1.9 martin * If we're not purging input data following first open, do nothing.
1029 1.9 martin */
1030 1.25.2.1 tls if (com->c_purging == false)
1031 1.9 martin return;
1032 1.9 martin
1033 1.9 martin /*
1034 1.9 martin * Otherwise check if the purge timeout has expired
1035 1.9 martin */
1036 1.9 martin getmicrotime(&curr_tv);
1037 1.25.2.1 tls timersub(&curr_tv, &com->c_purge_start, &diff_tv);
1038 1.9 martin
1039 1.9 martin if (diff_tv.tv_sec >= U3G_PURGE_SECS) {
1040 1.9 martin /* Timeout expired. */
1041 1.25.2.1 tls com->c_purging = false;
1042 1.9 martin } else {
1043 1.9 martin /* Still purging. Adjust the caller's byte count. */
1044 1.9 martin *ccp = 0;
1045 1.9 martin }
1046 1.9 martin }
1047 1.9 martin
1048 1.9 martin /*ARGSUSED*/
1049 1.9 martin static void
1050 1.9 martin u3g_write(void *arg, int portno, u_char *to, u_char *from, u_int32_t *count)
1051 1.9 martin {
1052 1.9 martin struct u3g_softc *sc = arg;
1053 1.25.2.1 tls struct u3g_com *com = &sc->sc_com[portno];
1054 1.9 martin
1055 1.9 martin /*
1056 1.9 martin * Stop purging as soon as the first data is written to the device.
1057 1.9 martin */
1058 1.25.2.1 tls com->c_purging = false;
1059 1.9 martin memcpy(to, from, *count);
1060 1.9 martin }
1061