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