u3g.c revision 1.6.6.4 1 /* $NetBSD: u3g.c,v 1.6.6.4 2010/03/11 15:04:05 yamt 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.6.6.4 2010/03/11 15:04:05 yamt 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 /* OEM: Option N.V. */
184 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_QUADPLUSUMTS },
185 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_HSDPA },
186 { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GTMAXHSUPA },
187 /* OEM: Qualcomm, Inc. */
188 { USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM },
189 { USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_ZTE_MF626 },
190 /* OEM: Huawei */
191 { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },
192 { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
193 { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_K3765 },
194 /* OEM: Novatel */
195 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 },
196 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_ES620 },
197 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D },
198 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U720 },
199 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U727 },
200 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINU740 },
201 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U740_2 },
202 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U870 },
203 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 },
204 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_S720 },
205 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_V740 },
206 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_X950D },
207 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_XU870 },
208 { USB_VENDOR_DELL, USB_PRODUCT_DELL_W5500 },
209 #if 0
210 { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D_DRIVER },
211 #endif
212 /* OEM: Merlin */
213 { USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 },
214
215 /* OEM: Sierra Wireless: */
216 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 },
217 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 },
218 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U },
219 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E },
220 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 },
221 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 },
222 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E },
223 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U },
224 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 },
225 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E },
226 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U },
227 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 },
228 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 },
229 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 },
230 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 },
231 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725 },
232 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 },
233 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 },
234 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 },
235 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 },
236 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 },
237 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U },
238 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 },
239 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 },
240 { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 },
241 };
242
243 static int
244 send_bulkmsg(usbd_device_handle dev, char *cmd, size_t cmdlen)
245 {
246 usbd_interface_handle iface;
247 usb_interface_descriptor_t *id;
248 usb_endpoint_descriptor_t *ed;
249 usbd_pipe_handle pipe;
250 usbd_xfer_handle xfer;
251 int err, i;
252
253 /* Move the device into the configured state. */
254 err = usbd_set_config_index(dev, 0, 0);
255 if (err) {
256 aprint_error("u3g: failed to set configuration index\n");
257 return UMATCH_NONE;
258 }
259
260 err = usbd_device2interface_handle(dev, 0, &iface);
261 if (err != 0) {
262 aprint_error("u3ginit: failed to get interface\n");
263 return UMATCH_NONE;
264 }
265
266 id = usbd_get_interface_descriptor(iface);
267 ed = NULL;
268 for (i = 0 ; i < id->bNumEndpoints ; i++) {
269 ed = usbd_interface2endpoint_descriptor(iface, i);
270 if (ed == NULL)
271 continue;
272 if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT)
273 continue;
274 if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK)
275 break;
276 }
277
278 if (i == id->bNumEndpoints)
279 return UMATCH_NONE;
280
281 err = usbd_open_pipe(iface, ed->bEndpointAddress,
282 USBD_EXCLUSIVE_USE, &pipe);
283 if (err != 0) {
284 aprint_error("u3ginit: failed to open bulk transfer pipe %d\n",
285 ed->bEndpointAddress);
286 return UMATCH_NONE;
287 }
288
289 xfer = usbd_alloc_xfer(dev);
290 if (xfer != NULL) {
291 usbd_setup_xfer(xfer, pipe, NULL, cmd, cmdlen,
292 USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL);
293
294 err = usbd_transfer(xfer);
295
296 #if 0 /* XXXpooka: at least my huawei "fails" this always, but still detaches */
297 if (err)
298 aprint_error("u3ginit: transfer failed\n");
299 #else
300 err = 0;
301 #endif
302 usbd_free_xfer(xfer);
303 } else {
304 aprint_error("u3ginit: failed to allocate xfer\n");
305 err = USBD_NOMEM;
306 }
307
308 usbd_abort_pipe(pipe);
309 usbd_close_pipe(pipe);
310
311 return (err == USBD_NORMAL_COMPLETION ? UMATCH_HIGHEST : UMATCH_NONE);
312 }
313
314 static int
315 u3g_novatel_reinit(usbd_device_handle dev)
316 {
317 unsigned char cmd[31];
318
319 memset(cmd, 0, sizeof(cmd));
320 /* Byte 0..3: Command Block Wrapper (CBW) signature */
321 cmd[0] = 0x55;
322 cmd[1] = 0x53;
323 cmd[2] = 0x42;
324 cmd[3] = 0x43;
325 /* 4..7: CBW Tag, has to unique, but only a single transfer used. */
326 cmd[4] = 0x01;
327 /* 8..11: CBW Transfer Length, no data here */
328 /* 12: CBW Flag: output, so 0 */
329 /* 13: CBW Lun: 0 */
330 /* 14: CBW Length */
331 cmd[14] = 0x06;
332 /* Rest is the SCSI payload */
333 /* 0: SCSI START/STOP opcode */
334 cmd[15] = 0x1b;
335 /* 1..3 unused */
336 /* 4 Load/Eject command */
337 cmd[19] = 0x02;
338 /* 5: unused */
339
340 return send_bulkmsg(dev, cmd, sizeof(cmd));
341 }
342
343 static int
344 u3g_huawei_reinit(usbd_device_handle dev)
345 {
346 /*
347 * The Huawei device presents itself as a umass device with Windows
348 * drivers on it. After installation of the driver, it reinits into a
349 * 3G serial device.
350 */
351 usb_device_request_t req;
352 usb_config_descriptor_t *cdesc;
353
354 /* Get the config descriptor */
355 cdesc = usbd_get_config_descriptor(dev);
356 if (cdesc == NULL) {
357 usb_device_descriptor_t dd;
358
359 if (usbd_get_device_desc(dev, &dd) != 0)
360 return (UMATCH_NONE);
361
362 if (dd.bNumConfigurations != 1)
363 return (UMATCH_NONE);
364
365 if (usbd_set_config_index(dev, 0, 1) != 0)
366 return (UMATCH_NONE);
367
368 cdesc = usbd_get_config_descriptor(dev);
369
370 if (cdesc == NULL)
371 return (UMATCH_NONE);
372 }
373
374 /*
375 * One iface means umass mode, more than 1 (4 usually) means 3G mode.
376 *
377 * XXX: We should check the first interface's device class just to be
378 * sure. If it's a mass storage device, then we can be fairly certain
379 * it needs a mode-switch.
380 */
381 if (cdesc->bNumInterface > 1)
382 return (UMATCH_NONE);
383
384 req.bmRequestType = UT_WRITE_DEVICE;
385 req.bRequest = UR_SET_FEATURE;
386 USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
387 USETW(req.wIndex, UHF_PORT_SUSPEND);
388 USETW(req.wLength, 0);
389
390 (void) usbd_do_request(dev, &req, 0);
391
392 return (UMATCH_HIGHEST); /* Prevent umass from attaching */
393 }
394
395 static int
396 u3g_huawei_k3765_reinit(usbd_device_handle dev)
397 {
398 unsigned char cmd[31];
399
400 /* magic string adapted from some webpage */
401 memset(cmd, 0, sizeof(cmd));
402 cmd[0] = 0x55;
403 cmd[1] = 0x53;
404 cmd[2] = 0x42;
405 cmd[3] = 0x43;
406 cmd[15]= 0x11;
407 cmd[16]= 0x06;
408
409 return send_bulkmsg(dev, cmd, sizeof(cmd));
410 }
411
412 static int
413 u3g_sierra_reinit(usbd_device_handle dev)
414 {
415 /* Some Sierra devices presents themselves as a umass device with
416 * Windows drivers on it. After installation of the driver, it
417 * reinits into a * 3G serial device.
418 */
419 usb_device_request_t req;
420
421 req.bmRequestType = UT_VENDOR;
422 req.bRequest = UR_SET_INTERFACE;
423 USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
424 USETW(req.wIndex, UHF_PORT_CONNECTION);
425 USETW(req.wLength, 0);
426
427 (void) usbd_do_request(dev, &req, 0);
428
429 return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */
430 }
431
432 /*
433 * First personality:
434 *
435 * Claim the entire device if a mode-switch is required.
436 */
437
438 static int
439 u3ginit_match(device_t parent, cfdata_t match, void *aux)
440 {
441 struct usb_attach_arg *uaa = aux;
442
443 /*
444 * Huawei changes product when it is configured as a modem.
445 */
446 if (uaa->vendor == USB_VENDOR_HUAWEI) {
447 if (uaa->product == USB_PRODUCT_HUAWEI_K3765)
448 return UMATCH_NONE;
449
450 if (uaa->product == USB_PRODUCT_HUAWEI_K3765INIT)
451 return u3g_huawei_k3765_reinit(uaa->device);
452 else
453 return u3g_huawei_reinit(uaa->device);
454 }
455
456 if (uaa->vendor == USB_VENDOR_NOVATEL2 &&
457 uaa->product == USB_PRODUCT_NOVATEL2_MC950D_DRIVER)
458 return u3g_novatel_reinit(uaa->device);
459
460 if (uaa->vendor == USB_VENDOR_SIERRA &&
461 uaa->product == USB_PRODUCT_SIERRA_INSTALLER)
462 return u3g_sierra_reinit(uaa->device);
463
464 return UMATCH_NONE;
465 }
466
467 static void
468 u3ginit_attach(device_t parent, device_t self, void *aux)
469 {
470 struct usb_attach_arg *uaa = aux;
471
472 aprint_naive("\n");
473 aprint_normal(": Switching to 3G mode\n");
474
475 if (uaa->vendor == USB_VENDOR_NOVATEL2 &&
476 uaa->product == USB_PRODUCT_NOVATEL2_MC950D_DRIVER) {
477 /* About to disappear... */
478 return;
479 }
480
481 /* Move the device into the configured state. */
482 (void) usbd_set_config_index(uaa->device, 0, 1);
483 }
484
485 static int
486 u3ginit_detach(device_t self, int flags)
487 {
488
489 return (0);
490 }
491
492
493 /*
494 * Second personality:
495 *
496 * Claim only those interfaces required for 3G modem operation.
497 */
498
499 static int
500 u3g_match(device_t parent, cfdata_t match, void *aux)
501 {
502 struct usbif_attach_arg *uaa = aux;
503 usbd_interface_handle iface;
504 usb_interface_descriptor_t *id;
505 usbd_status error;
506
507 if (!usb_lookup(u3g_devs, uaa->vendor, uaa->product))
508 return (UMATCH_NONE);
509
510 error = usbd_device2interface_handle(uaa->device, uaa->ifaceno, &iface);
511 if (error) {
512 printf("u3g_match: failed to get interface, err=%s\n",
513 usbd_errstr(error));
514 return (UMATCH_NONE);
515 }
516
517 id = usbd_get_interface_descriptor(iface);
518 if (id == NULL) {
519 printf("u3g_match: failed to get interface descriptor\n");
520 return (UMATCH_NONE);
521 }
522
523 /*
524 * 3G modems generally report vendor-specific class
525 *
526 * XXX: this may be too generalised.
527 */
528 return ((id->bInterfaceClass == UICLASS_VENDOR) ?
529 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
530 }
531
532 static void
533 u3g_attach(device_t parent, device_t self, void *aux)
534 {
535 struct u3g_softc *sc = device_private(self);
536 struct usbif_attach_arg *uaa = aux;
537 usbd_device_handle dev = uaa->device;
538 usbd_interface_handle iface;
539 usb_interface_descriptor_t *id;
540 usb_endpoint_descriptor_t *ed;
541 struct ucom_attach_args uca;
542 usbd_status error;
543 int n, intr_address, intr_size;
544
545 aprint_naive("\n");
546 aprint_normal("\n");
547
548 sc->sc_dev = self;
549 sc->sc_dying = false;
550 sc->sc_udev = dev;
551
552 error = usbd_device2interface_handle(dev, uaa->ifaceno, &iface);
553 if (error) {
554 aprint_error_dev(self, "failed to get interface, err=%s\n",
555 usbd_errstr(error));
556 return;
557 }
558
559 id = usbd_get_interface_descriptor(iface);
560
561 uca.info = "3G Modem";
562 uca.ibufsize = U3G_BUFF_SIZE;
563 uca.obufsize = U3G_BUFF_SIZE;
564 uca.ibufsizepad = U3G_BUFF_SIZE;
565 uca.portno = uaa->ifaceno;
566 uca.opkthdrlen = 0;
567 uca.device = dev;
568 uca.iface = iface;
569 uca.methods = &u3g_methods;
570 uca.arg = sc;
571 uca.bulkin = uca.bulkout = -1;
572
573 sc->sc_outpins = 0;
574 sc->sc_msr = UMSR_DSR | UMSR_CTS | UMSR_DCD;
575 sc->sc_ifaceno = uaa->ifaceno;
576 sc->sc_open = false;
577 sc->sc_purging = false;
578
579 intr_address = -1;
580 intr_size = 0;
581
582 for (n = 0; n < id->bNumEndpoints; n++) {
583 ed = usbd_interface2endpoint_descriptor(iface, n);
584 if (ed == NULL) {
585 aprint_error_dev(self, "no endpoint descriptor "
586 "for %d (interface: %d)\n", n, sc->sc_ifaceno);
587 sc->sc_dying = true;
588 return;
589 }
590
591 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
592 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
593 intr_address = ed->bEndpointAddress;
594 intr_size = UGETW(ed->wMaxPacketSize);
595 } else
596 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
597 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
598 uca.bulkin = ed->bEndpointAddress;
599 } else
600 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
601 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
602 uca.bulkout = ed->bEndpointAddress;
603 }
604 }
605
606 if (uca.bulkin == -1) {
607 aprint_error_dev(self, "Missing bulk in for interface %d\n",
608 sc->sc_ifaceno);
609 sc->sc_dying = true;
610 return;
611 }
612
613 if (uca.bulkout == -1) {
614 aprint_error_dev(self, "Missing bulk out for interface %d\n",
615 sc->sc_ifaceno);
616 sc->sc_dying = true;
617 return;
618 }
619
620 sc->sc_ucom = config_found_sm_loc(self, "ucombus",
621 NULL, &uca, ucomprint, ucomsubmatch);
622
623 /*
624 * If the interface has an interrupt pipe, open it immediately so
625 * that we can track input pin state changes regardless of whether
626 * the tty(4) device is open or not.
627 */
628 if (intr_address != -1) {
629 sc->sc_intr_buff = malloc(intr_size, M_USBDEV, M_WAITOK);
630 error = usbd_open_pipe_intr(iface, intr_address,
631 USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_intr_buff,
632 intr_size, u3g_intr, 100);
633 if (error) {
634 aprint_error_dev(self, "cannot open interrupt pipe "
635 "(addr %d)\n", intr_address);
636 return;
637 }
638 } else {
639 sc->sc_intr_pipe = NULL;
640 sc->sc_intr_buff = NULL;
641 }
642
643 if (!pmf_device_register(self, NULL, NULL))
644 aprint_error_dev(self, "couldn't establish power handler\n");
645 }
646
647 static int
648 u3g_detach(device_t self, int flags)
649 {
650 struct u3g_softc *sc = device_private(self);
651 int rv;
652
653 if (sc->sc_dying)
654 return 0;
655
656 pmf_device_deregister(self);
657
658 if (sc->sc_ucom != NULL) {
659 rv = config_detach(sc->sc_ucom, flags);
660 if (rv != 0) {
661 aprint_verbose_dev(self, "Can't deallocate "
662 "port (%d)", rv);
663 }
664 }
665
666 if (sc->sc_intr_pipe != NULL) {
667 (void) usbd_abort_pipe(sc->sc_intr_pipe);
668 (void) usbd_close_pipe(sc->sc_intr_pipe);
669 sc->sc_intr_pipe = NULL;
670 }
671 if (sc->sc_intr_buff != NULL) {
672 free(sc->sc_intr_buff, M_USBDEV);
673 sc->sc_intr_buff = NULL;
674 }
675
676 return (0);
677 }
678
679 static void
680 u3g_childdet(device_t self, device_t child)
681 {
682 struct u3g_softc *sc = device_private(self);
683
684 if (sc->sc_ucom == child)
685 sc->sc_ucom = NULL;
686 }
687
688 static int
689 u3g_activate(device_t self, enum devact act)
690 {
691 struct u3g_softc *sc = device_private(self);
692 int rv;
693
694 switch (act) {
695 case DVACT_DEACTIVATE:
696 if (sc->sc_ucom != NULL && config_deactivate(sc->sc_ucom))
697 rv = -1;
698 else
699 rv = 0;
700 break;
701
702 default:
703 rv = 0;
704 break;
705 }
706
707 return (rv);
708 }
709
710 static void
711 u3g_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
712 {
713 struct u3g_softc *sc = (struct u3g_softc *)priv;
714 u_char *buf;
715
716 if (sc->sc_dying)
717 return;
718
719 if (status != USBD_NORMAL_COMPLETION) {
720 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
721 return;
722 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
723 return;
724 }
725
726 buf = sc->sc_intr_buff;
727 if (buf[0] == 0xa1 && buf[1] == 0x20) {
728 u_char msr;
729
730 msr = sc->sc_msr & ~(UMSR_DCD | UMSR_DSR | UMSR_RI);
731
732 if (buf[8] & U3G_INPIN_DCD)
733 msr |= UMSR_DCD;
734
735 if (buf[8] & U3G_INPIN_DSR)
736 msr |= UMSR_DSR;
737
738 if (buf[8] & U3G_INPIN_RI)
739 msr |= UMSR_RI;
740
741 if (msr != sc->sc_msr) {
742 sc->sc_msr = msr;
743 if (sc->sc_open)
744 ucom_status_change(device_private(sc->sc_ucom));
745 }
746 }
747 }
748
749 /*ARGSUSED*/
750 static void
751 u3g_get_status(void *arg, int portno, u_char *lsr, u_char *msr)
752 {
753 struct u3g_softc *sc = arg;
754
755 if (lsr != NULL)
756 *lsr = 0; /* LSR isn't supported */
757 if (msr != NULL)
758 *msr = sc->sc_msr;
759 }
760
761 /*ARGSUSED*/
762 static void
763 u3g_set(void *arg, int portno, int reg, int onoff)
764 {
765 struct u3g_softc *sc = arg;
766 usb_device_request_t req;
767 uint16_t mask, new_state;
768 usbd_status err;
769
770 if (sc->sc_dying)
771 return;
772
773 switch (reg) {
774 case UCOM_SET_DTR:
775 mask = U3G_OUTPIN_DTR;
776 break;
777 case UCOM_SET_RTS:
778 mask = U3G_OUTPIN_RTS;
779 break;
780 default:
781 return;
782 }
783
784 new_state = sc->sc_outpins & ~mask;
785 if (onoff)
786 new_state |= mask;
787
788 if (new_state == sc->sc_outpins)
789 return;
790
791 sc->sc_outpins = new_state;
792
793 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
794 req.bRequest = U3G_SET_PIN;
795 USETW(req.wValue, new_state);
796 USETW(req.wIndex, sc->sc_ifaceno);
797 USETW(req.wLength, 0);
798
799 err = usbd_do_request(sc->sc_udev, &req, 0);
800 if (err == USBD_STALLED)
801 usbd_clear_endpoint_stall(sc->sc_udev->default_pipe);
802 }
803
804 /*ARGSUSED*/
805 static int
806 u3g_open(void *arg, int portno)
807 {
808 struct u3g_softc *sc = arg;
809 usb_device_request_t req;
810 usb_endpoint_descriptor_t *ed;
811 usb_interface_descriptor_t *id;
812 usbd_interface_handle ih;
813 usbd_status err;
814 int i;
815
816 if (sc->sc_dying)
817 return (0);
818
819 err = usbd_device2interface_handle(sc->sc_udev, portno, &ih);
820 if (err)
821 return (EIO);
822
823 id = usbd_get_interface_descriptor(ih);
824
825 for (i = 0; i < id->bNumEndpoints; i++) {
826 ed = usbd_interface2endpoint_descriptor(ih, i);
827 if (ed == NULL)
828 return (EIO);
829
830 if (UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
831 /* Issue ENDPOINT_HALT request */
832 req.bmRequestType = UT_WRITE_ENDPOINT;
833 req.bRequest = UR_CLEAR_FEATURE;
834 USETW(req.wValue, UF_ENDPOINT_HALT);
835 USETW(req.wIndex, ed->bEndpointAddress);
836 USETW(req.wLength, 0);
837 err = usbd_do_request(sc->sc_udev, &req, 0);
838 if (err)
839 return (EIO);
840 }
841 }
842
843 sc->sc_open = true;
844 sc->sc_purging = true;
845 getmicrotime(&sc->sc_purge_start);
846
847 return (0);
848 }
849
850 /*ARGSUSED*/
851 static void
852 u3g_close(void *arg, int portno)
853 {
854 struct u3g_softc *sc = arg;
855
856 sc->sc_open = false;
857 }
858
859 /*ARGSUSED*/
860 static void
861 u3g_read(void *arg, int portno, u_char **cpp, uint32_t *ccp)
862 {
863 struct u3g_softc *sc = arg;
864 struct timeval curr_tv, diff_tv;
865
866 /*
867 * If we're not purging input data following first open, do nothing.
868 */
869 if (sc->sc_purging == false)
870 return;
871
872 /*
873 * Otherwise check if the purge timeout has expired
874 */
875 getmicrotime(&curr_tv);
876 timersub(&curr_tv, &sc->sc_purge_start, &diff_tv);
877
878 if (diff_tv.tv_sec >= U3G_PURGE_SECS) {
879 /* Timeout expired. */
880 sc->sc_purging = false;
881 } else {
882 /* Still purging. Adjust the caller's byte count. */
883 *ccp = 0;
884 }
885 }
886
887 /*ARGSUSED*/
888 static void
889 u3g_write(void *arg, int portno, u_char *to, u_char *from, u_int32_t *count)
890 {
891 struct u3g_softc *sc = arg;
892
893 /*
894 * Stop purging as soon as the first data is written to the device.
895 */
896 sc->sc_purging = false;
897 memcpy(to, from, *count);
898 }
899